You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
StructuredOutput drops additionalProperties (map) fields on Gemini; Ajv accepts the lossy {} #139
In aictrl prod on 2026-10-10, all 5 PR Explanation runs on Gemini 3.8 Flash (Vertex) stored diagrams[*].elements as {}. In each run the model had written and linted a result file with populated elements ("lint: zero errors" right before the StructuredOutput call). GLM 5.2 runs were unaffected.
Root cause
@ai-sdk/google 2.0.54 convertJSONSchemaToOpenAPISchema keeps only type, description, required, properties, items, allOf/anyOf/oneOf, format, const, minLength and enum. It drops additionalProperties, so a map-typed field (elements: {type: object, additionalProperties: {...}}) reaches Gemini as a bare {type: object}, and constrained decoding emits {}. The CLI's Ajv check then accepts {} (valid against the original schema), and --output-result writes the lossy copy.
Expected
Map-typed fields survive the provider schema conversion, or the CLI fails fast when a schema uses a construct the provider path can't express. It must never silently empty a field.
Acceptance Criteria
A test with a schema containing additionalProperties (object map) round-trips non-empty data on the Google provider path, or the run fails with a clear config error.
Options to weigh: pass the full JSON Schema via Gemini's parametersJsonSchema / responseJsonSchema; or skip provider-side schema constraints for StructuredOutput and rely on Ajv plus the corrective turn.
Result:ws/result.json is identical to expected.json (all 6 keys), but out.json has "elements": {} and the exit code is 0.
On the wire (a pass-through proxy logged the Vertex request): the StructuredOutput function declaration carries "elements":{"type":"object"} with toolConfig.functionCallingConfig.mode: ANY. Both additionalProperties and minProperties are gone. Offline, @ai-sdk/google 2.0.54's convertJSONSchemaToOpenAPISchema on the same schema gives:
Upstream status: fixed in @ai-sdk/google 4.0.70 (vercel/ai#20757), which preserves the JSON Schema via parametersJsonSchema/responseJsonSchema. That is the AI SDK v7 line only; the v6 line (google 3.0.131) still converts, and upstream OpenCode dev (ai 6.0.168, google 3.0.73) has this bug too. Decision: fix via the SDK migration, tracked in #141.
Blocked by #141 (AI SDK v7 migration). Keep this open until #141 merges and the reproduction above passes on Gemini (5/5, all keys published). #140 (publish the validated file) would stop PR Explanations from hitting this, but any inline map-typed --output-schema stays affected until #141.
Update: on AI SDK v7 (probe in #141), the map field is no longer emptied, but Gemini rewrites non-identifier keys in its function-call response (queued->running→queued__running, 1→_1, TASKS.org_id→TASKS_org_id), and that still passes Ajv silently. So the acceptance criterion "all 6 keys published" fails on v7 alone. #140 (path form) avoids it for file-based results; for inline schema results, map keys with non-identifier characters are unsafe on Gemini.
Resolved for StructuredOutput by #142 (0.4.8): in schema mode the tool's only argument is {path}, so no map-typed result schema reaches the Google converter. Verified in prod on 2026-10-10: Talentrix (Gemini) PR Explanations store all diagram elements. The underlying converter limitation in @ai-sdk/google 2.x/3.x still applies to any other map-typed tool schema sent to Gemini (e.g. an MCP tool). If that shows up, reopen this together with #141.
Activity
byapparov commentedon Oct 10, 2026
Reproduction on
aictrl run0.4.7 (the prod executor pin), 2026-10-10Confirmed: the map-typed field reaches Gemini without
additionalProperties, and Gemini returns{}.Files. Put
expected.jsonin an empty git dirws/.schema-nomin.json{ "type": "object", "required": [ "title", "elements" ], "properties": { "title": { "type": "string" }, "elements": { "type": "object", "additionalProperties": { "type": "object", "required": [ "label" ], "properties": { "label": { "type": "string" }, "lines": { "type": "array", "items": { "type": "integer" } } } } } } }expected.json{ "title": "Task lifecycle", "elements": { "queued->running": { "label": "dispatch", "lines": [12, 40] }, "[*]->queued": { "label": "create", "lines": [3] }, "TASKS.org_id": { "label": "org_id uuid FK", "lines": [88, 89, 90] }, "1": { "label": "first step", "lines": [] }, "A": { "label": "Actor A", "lines": [7] }, "done->[*]": { "label": "finish", "lines": [101] } } }prompt.txtCommand
Result:
ws/result.jsonis identical toexpected.json(all 6 keys), butout.jsonhas"elements": {}and the exit code is 0.On the wire (a pass-through proxy logged the Vertex request): the StructuredOutput function declaration carries
"elements":{"type":"object"}withtoolConfig.functionCallingConfig.mode: ANY. BothadditionalPropertiesandminPropertiesare gone. Offline,@ai-sdk/google2.0.54'sconvertJSONSchemaToOpenAPISchemaon the same schema gives:{"required":["title","elements"],"type":"object","properties":{"title":{"type":"string"},"elements":{"type":"object"}}}The 0.4.7 bundle contains two copies of that converter, and neither handles
additionalProperties.Matrix
elements{}2/2{}minProperties: 1{}5/5zai-coding-plan/glm-5.2), mapelementsas an array of{id,label,lines}In every run the file the model wrote matched
expected.jsonexactly. The loss is only in the schema-constrained StructuredOutput call.Workaround evidence: array-shaped collections survive the converter (full
itemskept; onlyminItemsis dropped).byapparov commentedon Oct 10, 2026
Upstream status: fixed in
@ai-sdk/google4.0.70 (vercel/ai#20757), which preserves the JSON Schema viaparametersJsonSchema/responseJsonSchema. That is the AI SDK v7 line only; the v6 line (google 3.0.131) still converts, and upstream OpenCodedev(ai 6.0.168, google 3.0.73) has this bug too. Decision: fix via the SDK migration, tracked in #141.byapparov commentedon Oct 10, 2026
Blocked by #141 (AI SDK v7 migration). Keep this open until #141 merges and the reproduction above passes on Gemini (5/5, all keys published). #140 (publish the validated file) would stop PR Explanations from hitting this, but any inline map-typed
--output-schemastays affected until #141.byapparov commentedon Oct 10, 2026
Update: on AI SDK v7 (probe in #141), the map field is no longer emptied, but Gemini rewrites non-identifier keys in its function-call response (
queued->running→queued__running,1→_1,TASKS.org_id→TASKS_org_id), and that still passes Ajv silently. So the acceptance criterion "all 6 keys published" fails on v7 alone. #140 (path form) avoids it for file-based results; for inline schema results, map keys with non-identifier characters are unsafe on Gemini.byapparov commentedon Oct 11, 2026
Resolved for StructuredOutput by #142 (0.4.8): in schema mode the tool's only argument is
{path}, so no map-typed result schema reaches the Google converter. Verified in prod on 2026-10-10: Talentrix (Gemini) PR Explanations store all diagram elements. The underlying converter limitation in @ai-sdk/google 2.x/3.x still applies to any other map-typed tool schema sent to Gemini (e.g. an MCP tool). If that shows up, reopen this together with #141.