LangChain.Utils.GoogleSchema (LangChain v0.9.5)

Copy Markdown View Source

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

empty_object?(arg1)

@spec empty_object?(any()) :: boolean()

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

sanitize(schema)

@spec sanitize(map()) :: map()
@spec sanitize(any()) :: any()

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"}}}