Selecting google/gemini-3.8-flash in pi fails every request with a 400 from Vertex, while Claude/GLM/GPT models work in the same session with the same tools. Vertex returns:
... functionDeclaration parameters.min_confidence schema specified other fields alongside any_of. When using any_of, it must be the only field set.
What reaches the gateway is a JSON Schema whose optional fields use type arrays, like "type": ["number", "null"]. MCP servers emit this shape all the time for Option-style parameters, and the provider's own makeNullable in src/json-schema.ts produces it too. For Gemini 3 the gateway converts each union into any_of with the sibling fields still sitting next to it, and Vertex validates function declarations strictly on Gemini 3, so it refuses the request. One bad declaration is enough to kill the whole model call.
The local conversion paths handle unions fine (pi-ai plus @google/genai turn them into nullable plus a single type), so this looks specific to the gateway translation.
Two possible fixes: collapse type unions to the single non-null type for google/* models before sending input_schema (the parameters are optional anyway), or normalize on the gateway side. Happy to test a patch.
Repro: register any tool whose schema has a nullable parameter (ai-memory's memory_auto_improve.min_confidence is one), pick a gemini-3.x model, send a prompt.
Selecting
google/gemini-3.8-flashin pi fails every request with a 400 from Vertex, while Claude/GLM/GPT models work in the same session with the same tools. Vertex returns:What reaches the gateway is a JSON Schema whose optional fields use type arrays, like
"type": ["number", "null"]. MCP servers emit this shape all the time for Option-style parameters, and the provider's ownmakeNullableinsrc/json-schema.tsproduces it too. For Gemini 3 the gateway converts each union intoany_ofwith the sibling fields still sitting next to it, and Vertex validates function declarations strictly on Gemini 3, so it refuses the request. One bad declaration is enough to kill the whole model call.The local conversion paths handle unions fine (pi-ai plus
@google/genaiturn them intonullableplus a single type), so this looks specific to the gateway translation.Two possible fixes: collapse type unions to the single non-null type for
google/*models before sendinginput_schema(the parameters are optional anyway), or normalize on the gateway side. Happy to test a patch.Repro: register any tool whose schema has a nullable parameter (ai-memory's
memory_auto_improve.min_confidenceis one), pick agemini-3.xmodel, send a prompt.