mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
fix(vertex_ai): rewrap claude-agent-sdk bare-field tool schemas
The Anthropic /v1/messages tool input_schema spec is a JSON Schema
object with type/properties/required. Some SDKs (notably
claude-agent-sdk's @tool decorator) emit a non-conformant shape
that puts field definitions at the top level with per-field
required:true flags:
{"to": {"type":"string","required":true}, "amount": {...}}
Anthropic's own API tolerates this. Vertex/Gemini's strict Schema
validator does not — filter_schema_fields strips the schema down
to {"type":"object"} (empty), and the model then hallucinates
field names from the tool description (e.g. dst_address, coin).
Add _rewrap_bare_field_schema() that detects the bare-field shape
and rewraps to standard JSON Schema before _build_vertex_schema
processes it. Already-conformant schemas pass through unchanged.
Test plan:
- Locally exercised the helper against the bare-field shape, an
already-conformant schema, empty {}, non-dict values, and dicts
without type field — all behave correctly.
- End-to-end: replayed a wallet adversarial-suite prompt through
the LiteLLM gateway (Anthropic /v1/messages format with 61 tools
in the claude-agent-sdk shape). Before patch: Gemini emitted
tool_use(transfer, {dst_address: ...}). After patch: Gemini
emitted tool_use(transfer, {to: ...}) matching MiniMax-via-gateway
byte-for-byte on the same payload.
This commit is contained in:
parent
10bd7406e0
commit
30c5d43b5b
1 changed files with 39 additions and 0 deletions
|
|
@ -535,6 +535,42 @@ def _fix_enum_types(schema, depth=0):
|
|||
_fix_enum_types(item, depth=depth + 1)
|
||||
|
||||
|
||||
def _rewrap_bare_field_schema(parameters: dict) -> dict:
|
||||
"""Rewrap claude-agent-sdk style "bare field" tool schemas in place.
|
||||
|
||||
The Anthropic Messages API tool ``input_schema`` is documented as a JSON
|
||||
Schema object with ``type``, ``properties``, ``required``. Some SDKs
|
||||
(notably ``claude-agent-sdk``'s ``@tool`` decorator) emit a non-conformant
|
||||
convenience shape that puts field definitions at the top level with
|
||||
per-field ``required: true`` flags::
|
||||
|
||||
{"to": {"type": "string", "required": true}, "amount": {...}}
|
||||
|
||||
Anthropic's own API tolerates this. Gemini's strict Schema validator
|
||||
does not — without rewrapping, the downstream ``filter_schema_fields``
|
||||
call below strips the whole schema down to ``{"type": "object"}``,
|
||||
causing the model to hallucinate field names when calling the tool.
|
||||
"""
|
||||
if not isinstance(parameters, dict) or not parameters:
|
||||
return parameters
|
||||
if parameters.get("type") == "object" and "properties" in parameters:
|
||||
return parameters
|
||||
# Detect the bare-field shape: every value is a dict with a "type" key.
|
||||
if not all(isinstance(v, dict) and "type" in v for v in parameters.values()):
|
||||
return parameters
|
||||
properties: dict = {}
|
||||
required: list = []
|
||||
for field, defn in parameters.items():
|
||||
defn_copy = {k: v for k, v in defn.items() if k != "required"}
|
||||
if defn.get("required") is True:
|
||||
required.append(field)
|
||||
properties[field] = defn_copy
|
||||
out: dict = {"type": "object", "properties": properties}
|
||||
if required:
|
||||
out["required"] = required
|
||||
return out
|
||||
|
||||
|
||||
def _build_vertex_schema(parameters: dict, add_property_ordering: bool = False):
|
||||
"""
|
||||
This is a modified version of https://github.com/google-gemini/generative-ai-python/blob/8f77cc6ac99937cd3a81299ecf79608b91b06bbb/google/generativeai/types/content_types.py#L419
|
||||
|
|
@ -548,6 +584,9 @@ def _build_vertex_schema(parameters: dict, add_property_ordering: bool = False):
|
|||
Returns:
|
||||
parameters: dict - the input parameters, modified in place
|
||||
"""
|
||||
# Pre-rewrap claude-agent-sdk bare-field schemas before strict filtering.
|
||||
parameters = _rewrap_bare_field_schema(parameters)
|
||||
|
||||
# Get valid fields from Schema TypedDict
|
||||
valid_schema_fields = set(get_type_hints(Schema).keys())
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue