Removes JSON Schema keywords that Google's Gemini APIs reject.
Google's function declarations and response schemas accept a
select subset of an OpenAPI 3.0
schema object rather than full JSON Schema. The Schema type is a protobuf
message, so a keyword it has no field for is rejected by the parser before
any semantic validation runs:
Invalid JSON payload received. Unknown name "additionalProperties" at
'tools[0].function_declarations[0].parameters': Cannot find field.That fails the entire request, not the single tool, and the message names a field path rather than the tool, so the cause is not obvious.
additionalProperties is the keyword that matters most in practice, because
LangChain.FunctionParam.to_parameters_schema/1 adds it to every schema it
generates. Without this sanitizing step, any tool declared the ordinary way —
with a parameters: list of LangChain.FunctionParam structs — is rejected
by Gemini.
Semantic loss
One removal changes what the API enforces. Dropping additionalProperties: false means Gemini does not reject unexpected properties, so a tool call's
arguments may contain fields the schema did not declare. Where that matters,
validate the arguments inside the tool's own function.
Schemas built around $ref are also flattened, since neither $ref nor
$defs has a Google equivalent. Inline such schemas before sending them.
Summary
Functions
Return true when the schema describes an object with no properties.
Remove the schema keywords Google does not support, recursing through nested schemas.
Functions
Return true when the schema describes an object with no properties.
Google rejects such a schema with "should be non-empty for OBJECT type", so a function declaration that produces one has to omit its parameters entirely rather than send an empty object.
Example
iex> LangChain.Utils.GoogleSchema.empty_object?(%{"type" => "object", "properties" => %{}})
true
iex> LangChain.Utils.GoogleSchema.empty_object?(%{"type" => "object", "properties" => %{"a" => %{}}})
false
Remove the schema keywords Google does not support, recursing through nested schemas.
Non-map input is returned unchanged, so this is safe to apply to a nil
response schema or a schema fragment that is a bare boolean.
Example
iex> LangChain.Utils.GoogleSchema.sanitize(%{
...> "type" => "object",
...> "additionalProperties" => false,
...> "properties" => %{"city" => %{"type" => "string"}}
...> })
%{"type" => "object", "properties" => %{"city" => %{"type" => "string"}}}