mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-07-09 17:08:29 +00:00
Normalize Responses tool schemas
Ensure function parameter schemas include an explicit properties object before Responses requests are dispatched through LiteLLM. Keep prompt/MCP permissive schemas compatible with stricter OpenAI-compatible chat validators and cover chat, legacy function, and native Responses tool inputs with regressions.
This commit is contained in:
parent
a4b2848172
commit
272a0d8dfa
6 changed files with 139 additions and 11 deletions
|
|
@ -640,13 +640,11 @@ class ResponsesTransport:
|
|||
response_builtin_tools: Any = None,
|
||||
) -> list[Any]:
|
||||
merged: list[Any] = []
|
||||
if isinstance(tools, list):
|
||||
merged.extend(tools)
|
||||
elif tools:
|
||||
merged.append(tools)
|
||||
|
||||
for source in (response_function_tools, response_builtin_tools):
|
||||
for tool in _as_list(source):
|
||||
for source in (tools, response_function_tools, response_builtin_tools):
|
||||
source_tools = (
|
||||
source if isinstance(source, list) else [source] if source else []
|
||||
)
|
||||
for tool in source_tools:
|
||||
normalized = cls.normalize_response_tool(tool)
|
||||
if normalized:
|
||||
merged.append(normalized)
|
||||
|
|
@ -658,7 +656,12 @@ class ResponsesTransport:
|
|||
tool = {"type": tool}
|
||||
if not isinstance(tool, dict):
|
||||
return None
|
||||
return dict(tool)
|
||||
normalized = dict(tool)
|
||||
if normalized.get("type") == "function":
|
||||
normalized["parameters"] = _normalize_function_parameters(
|
||||
normalized.get("parameters")
|
||||
)
|
||||
return normalized
|
||||
|
||||
@staticmethod
|
||||
def prepare_prompt_caching(
|
||||
|
|
@ -800,7 +803,9 @@ class ResponsesTransport:
|
|||
"type": "function",
|
||||
"name": function.get("name", ""),
|
||||
"description": function.get("description", ""),
|
||||
"parameters": function.get("parameters", {}),
|
||||
"parameters": _normalize_function_parameters(
|
||||
function.get("parameters")
|
||||
),
|
||||
}
|
||||
if "strict" in function:
|
||||
response_tool["strict"] = function["strict"]
|
||||
|
|
@ -1206,6 +1211,23 @@ def _response_tool_type(tool: Any) -> str:
|
|||
return ""
|
||||
|
||||
|
||||
def _normalize_function_parameters(parameters: Any) -> dict[str, Any]:
|
||||
if not isinstance(parameters, dict):
|
||||
return _permissive_function_parameters()
|
||||
|
||||
normalized = dict(parameters)
|
||||
normalized.setdefault("type", "object")
|
||||
if normalized.get("type") == "object" and not isinstance(
|
||||
normalized.get("properties"), dict
|
||||
):
|
||||
normalized["properties"] = {}
|
||||
return normalized or _permissive_function_parameters()
|
||||
|
||||
|
||||
def _permissive_function_parameters() -> dict[str, Any]:
|
||||
return {"type": "object", "properties": {}, "additionalProperties": True}
|
||||
|
||||
|
||||
def apply_chat_prompt_cache_markers(
|
||||
messages: list[dict[str, Any]],
|
||||
*,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
- Keep provider selection and provider-specific defaults outside this helper; callers pass a resolved LiteLLM model name and kwargs.
|
||||
- Strip Agent Zero internal kwargs before sending requests to LiteLLM.
|
||||
- Do not send orphan tool controls when no tools are present; strict OpenAI-compatible servers can reject empty `tools` arrays.
|
||||
- Normalize function tool parameter schemas with an explicit object `properties` field before Responses requests so OpenAI-compatible chat backends reached through LiteLLM can validate them.
|
||||
- Prefer Responses API when configured, but fallback to Chat Completions when the provider does not support Responses.
|
||||
- Fall back to Chat Completions when a Responses request is rejected before any output by an endpoint-specific or shape-specific Bad Request indicating the provider cannot parse Responses payloads.
|
||||
- Preserve provider-state metadata when Responses API calls succeed, and fall back to local replay when provider state is unsupported.
|
||||
|
|
|
|||
|
|
@ -217,13 +217,17 @@ def _schema_from_any(schema: Any) -> dict[str, Any]:
|
|||
if isinstance(schema, dict):
|
||||
normalized = dict(schema)
|
||||
normalized.setdefault("type", "object")
|
||||
if normalized.get("type") == "object" and not isinstance(
|
||||
normalized.get("properties"), dict
|
||||
):
|
||||
normalized["properties"] = {}
|
||||
normalized.setdefault("additionalProperties", True)
|
||||
return normalized
|
||||
return _permissive_schema()
|
||||
|
||||
|
||||
def _permissive_schema() -> dict[str, Any]:
|
||||
return {"type": "object", "additionalProperties": True}
|
||||
return {"type": "object", "properties": {}, "additionalProperties": True}
|
||||
|
||||
|
||||
def _balanced_json_object(text: str) -> str:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
- Build local function tools from enabled `agent.system.tool.*.md` prompt files.
|
||||
- Local prompt-derived function names prefer explicit `"tool_name"` examples, then the first prompt heading, and only fall back to the prompt filename when the prompt declares no callable name.
|
||||
- Function parameter schemas are object schemas with an explicit `properties` object so OpenAI-compatible servers that validate chat-style tool payloads accept permissive tools.
|
||||
- Preserve original Agent Zero tool names through the native Responses name map.
|
||||
- Keep MCP tool schemas merged after local prompt-derived tools.
|
||||
- Connector remote tools are advertised only when `_a0_connector` runtime metadata says the matching connected CLI capability is currently available.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue