Skip to content

fix(genai): preserve format/example fields and support integer enums in schema conversion - #1949

Open
Alon Nahmias (alonahmias) wants to merge 1 commit into
langchain-ai:mainfrom
alonahmias:fix/genai-schema-example-and-int-enum
Open

fix(genai): preserve format/example fields and support integer enums in schema conversion#1949
Alon Nahmias (alonahmias) wants to merge 1 commit into
langchain-ai:mainfrom
alonahmias:fix/genai-schema-example-and-int-enum

Conversation

@alonahmias

Copy link
Copy Markdown

Problem

While debugging why a Gemini agent kept sending a bare date ("2026-08-17") instead of the RFC 3339 datetime declared in a tool's OpenAPI schema (format: "date-time", with a matching example), I traced the root cause to langchain_google_genai/_function_utils.py's schema conversion path (_dict_to_genai_schema / _get_properties_from_schema):

  1. format is silently dropped for every property. _dict_to_genai_schema builds schema_dict from formatted_schema, but never copies formatted_schema["format"] into it — even though "format" is in _ALLOWED_SCHEMA_FIELDS and reaches _format_json_schema_to_gapic untouched. So a property declared with format: "date-time" never actually reaches the Gemini API call.
  2. example/examples are dropped entirely. They aren't in _ALLOWED_SCHEMA_FIELDS at all, even though google.genai.types.Schema has a native example: Optional[Any] field:
    example: Optional[Any] = Field(
        default=None,
        description="Optional. Example of the object. Will only populated when the object is the root.",
    )
  3. Integer/number/boolean enums are silently invalid. Schema.enum's own docstring documents the expected shape for non-string enums:
    2. We can define apartment number as: {type:INTEGER, format:"enum", enum:["101", "201", "301"]}
    
    i.e. format: "enum" must be set and enum values must be strings even when type is INTEGER/NUMBER/BOOLEAN. The current conversion just copies the raw (integer-typed) enum list and never sets format, so e.g. Literal[100, 110, 120] produces an enum Gemini doesn't recognize correctly.

Also found and removed a redundant duplicate if "enum" in schema: items["enum"] = schema["enum"] in _get_items_from_schema — harmless before this change, but it would have clobbered the new stringified array-item enum with the raw values.

Fix

  • _dict_to_genai_schema: copy format and example from formatted_schema into schema_dict.
  • _ALLOWED_SCHEMA_FIELDS: add "example"/"examples"; _format_json_schema_to_gapic collapses plural JSON Schema examples to the singular Schema.example.
  • _get_properties_from_schema / _get_items_from_schema: propagate format generally, and for INTEGER/NUMBER/BOOLEAN types with an enum, stringify the enum values and set format: "enum", matching Gemini's documented requirement.

Testing

  • Added test_tool_field_format_is_preserved, test_tool_field_example_is_preserved, test_tool_field_integer_enum to tests/unit_tests/test_function_utils.py.
  • uv run pytest tests/unit_tests — 385 passed (was 382 before, +3 new tests).
  • uv run mypy langchain_google_genai/ — no issues.
  • uv run ruff format / ruff check — clean.

No existing tests changed behavior; this only adds previously-dropped fields and fixes previously-invalid enum output.

…in schema conversion

- _dict_to_genai_schema never copied 'format' from the intermediate dict
  into the final schema_dict, so format: date-time, format: enum, etc. were
  silently dropped for every property.
- 'example'/'examples' were missing from _ALLOWED_SCHEMA_FIELDS entirely,
  even though google.genai.types.Schema natively supports an 'example' field.
  JSON Schema's plural 'examples' is collapsed to its first element to match
  Schema.example (singular).
- Gemini's Schema.enum only accepts string values, even when the underlying
  type is INTEGER/NUMBER/BOOLEAN; format: "enum" is required for the API to
  treat these as enum constraints (see Schema.enum docstring examples). Enum
  values are now stringified and format is set accordingly, for both object
  properties and array items.
- Removed a redundant duplicate 'enum' assignment in _get_items_from_schema
  that would have clobbered the new stringified enum with the raw values.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant