Repository navigation
fix(kosong): strip JSON Schema metadata from Google GenAI tool parameters - #739
xiaoju111a wants to merge 2 commits into
Conversation
…ters Google GenAI SDK's Pydantic model has extra='forbid', which rejects JSON Schema metadata fields like $schema, $id, and $comment. This causes validation errors when using MCP tools that include standard JSON Schema metadata in their inputSchema. Fixes MoonshotAI#734
| parameters = { | ||
| k: v | ||
| for k, v in tool.parameters.items() | ||
| if k not in ("$schema", "$id", "$comment", "examples") | ||
| } |
There was a problem hiding this comment.
🟡 JSON Schema metadata stripping only applied at top level, not recursively into nested schemas
The new filtering at packages/kosong/src/kosong/contrib/chat_provider/google_genai.py:360-364 only strips metadata fields ($schema, $id, $comment, examples) from the top-level keys of tool.parameters. However, these fields—especially examples—can appear at any depth in a JSON Schema (e.g., inside properties entries when Pydantic's Field(examples=[...]) is used). Since the google-genai SDK uses extra='forbid' (as noted in the comment on line 358), it will recursively validate nested schema dicts and reject any that contain these forbidden keys. A tool whose parameter field uses Field(examples=["foo"]) would produce a schema like {"properties": {"name": {"type": "string", "examples": ["foo"]}}}, and the nested examples would still cause the SDK to raise a validation error.
Prompt for agents
In packages/kosong/src/kosong/contrib/chat_provider/google_genai.py, the tool_to_google_genai function at lines 360-364 needs to recursively strip the metadata fields from the entire JSON Schema tree, not just the top-level dict. Replace the top-level dict comprehension with a recursive helper function that walks the schema dict (and any nested dicts/lists) and removes keys in the forbidden set ("$schema", "$id", "$comment", "examples") at every level. For example:
def _strip_schema_metadata(schema: dict) -> dict:
FORBIDDEN = {"$schema", "$id", "$comment", "examples"}
result = {}
for k, v in schema.items():
if k in FORBIDDEN:
continue
if isinstance(v, dict):
result[k] = _strip_schema_metadata(v)
elif isinstance(v, list):
result[k] = [_strip_schema_metadata(item) if isinstance(item, dict) else item for item in v]
else:
result[k] = v
return result
Then use parameters = _strip_schema_metadata(tool.parameters) in tool_to_google_genai().
Was this helpful? React with 👍 or 👎 to provide feedback.
|
There is a one-line version of this that removes the whole class of failure instead of the four keys, and I think it's worth considering before this lands: pass the schema to
RAW = {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object",
"properties": {"a": {"type": ["string", "null"]},
"c": {"type": "integer", "exclusiveMinimum": 0},
"d": {"type": "array", "prefixItems": [{"type": "integer"}]}}}
FunctionDeclaration(name="t", parameters=RAW) # 6 validation errors
FunctionDeclaration(name="t", parameters_json_schema=RAW) # accepted, byte-identicalThis isn't an obscure corner — it's what the JS client already does for you. Two things about the current patch that I'd want on the record either way, both measured against the diff as written: 1. The strip is top-level only. 2. Even a recursive strip leaves about a dozen more, and most of them have no plus array-form The two that matter most can't be fixed by stripping at all, because deleting them destroys the parameter rather than sanitising it:
So if the strip approach is preferred over the field switch, it needs to be a recursive rewrite, not a recursive delete. Last thing, and it makes any of these testable: (One surface caveat if this pattern gets reused elsewhere: the same SDK does inline |
Related Issue
Resolves #734
Description
This PR fixes a compatibility issue between Google GenAI provider and MCP tools that include standard JSON Schema metadata fields.
Problem
When using MCP tools (like Exa MCP) with Google GenAI provider, the following validation error occurs:
Root cause:
inputSchemaincludes standard JSON Schema metadata fieldsextra='forbid', which rejects these additional fieldsSolution
Strip JSON Schema metadata fields in
tool_to_google_genai()function before passing to Google GenAI SDK. We filter 4 fields that are rejected by the SDK:$schema,$id,$comment- JSON Schema metadataexamples- Example values (not part of validation schema)Note:
$defsanddefinitionsare already removed by kosong'sderef_json_schema()function, so we don't need to filter them here.Impact
Testing
Manually verified the 4 rejected fields with Google GenAI SDK:
Checklist
make gen-changelogto update the changelog.make gen-docsto update the user documentation.