Summary
Registering any tool whose JSON schema has enum on a non-string property (e.g. {\"type\": \"integer\", \"enum\": [4, 6, 8]}) against Gemini's function-calling API fails with a 400. Celeste-AI passes the schema to the legacy functionDeclarations[].parameters field, which only permits enum on TYPE_STRING properties per Google's documented rule. This breaks tool-calling for every model whose parameter_constraints carry a non-string Choice.
Reproduction
Calling any Gemini text model with a tool fleet that includes one of these constraints fails:
Choice(options=[4, 6, 8]) — duration on all four Veo models
src/celeste/modalities/videos/providers/google/models.py:26 (veo-3.0-generate-001)
src/celeste/modalities/videos/providers/google/models.py:40 (veo-3.0-fast-generate-001)
src/celeste/modalities/videos/providers/google/models.py:54 (veo-3.1-generate-preview)
src/celeste/modalities/videos/providers/google/models.py:75 (veo-3.1-fast-generate-preview)
Choice(options=[768, 1536, 3072]) — dimensions on both Google embedding models
src/celeste/modalities/embeddings/providers/google/models.py:21 (gemini-embedding-001)
src/celeste/modalities/embeddings/providers/google/models.py:30 (gemini-embedding-2-preview)
Error
```
HTTPStatusError: google API error: Invalid value at
'tools[0].function_declarations[N].parameters.properties[M].value.enum[0]'
(TYPE_STRING), 4
```
Root cause
src/celeste/providers/google/generate_content/parameters.py:222 assigns the raw JSON schema to the legacy parameters field:
```python
result["parameters"] = schema
```
parameters is a narrow OpenAPI-2 subset where enum is valid only on TYPE_STRING properties (see https://ai.google.dev/api/caching#Schema: "Possible values of the element of Type.STRING with enum format"). _remove_titles is the only existing sanitization step; no coercion of non-string enums, no translation of composition keywords, no handling of $defs/$ref.
Proposed fix
Switch to the parametersJsonSchema field introduced in Gemini's November 2025 structured-outputs update (https://blog.google/technology/developers/gemini-api-structured-outputs/: "added support for JSON Schema to all actively supported Gemini models"). That field accepts native JSON Schema — integer enums, \$defs, \$ref, anyOf, oneOf, additionalProperties — with no sanitization.
```python
src/celeste/providers/google/generate_content/parameters.py:222
result["parametersJsonSchema"] = schema
```
parameters and parametersJsonSchema are mutually exclusive per Gemini's API reference (https://ai.google.dev/api/caching) — send one, not both.
Ecosystem precedent
- pydantic-ai already uses
parametersJsonSchema unconditionally in its Gemini provider: https://github.com/pydantic/pydantic-ai/blob/main/pydantic_ai_slim/pydantic_ai/models/google.py
- Google's
google-genai SDK Schema.from_json_schema(...) (the legacy-shape sanitizer) now emits deprecation warnings steering callers toward parametersJsonSchema.
- LiteLLM still on legacy and silently drops integer enums. LangChain (
langchain-google-genai) still on legacy and has the same bug (langchain-google/issues/409). Both are trailing indicators; celeste has no reason to follow.
Model compatibility
Every Gemini model currently registered in src/celeste/modalities/text/providers/google/models.py is 2.5+ or 3.x — all within Google's November 2025 "all actively supported Gemini models" set. No 1.0/1.5/2.0 entries to worry about.
Tests
- New regression in
tests/unit_tests/ (or the Google provider tests directory): build a tool with an integer Choice constraint, map it through ToolsMapper._map_user_tool, assert the emitted dict has parametersJsonSchema with the integer enum preserved (not coerced, not dropped).
- Existing integration tests in
tests/integration_tests/text/test_tools.py continue to pass — string-enum schemas flow through unchanged.
Scope
Single-line behavioral change + one new unit test. No API surface change for celeste-ai callers.
Summary
Registering any tool whose JSON schema has
enumon a non-string property (e.g.{\"type\": \"integer\", \"enum\": [4, 6, 8]}) against Gemini's function-calling API fails with a 400. Celeste-AI passes the schema to the legacyfunctionDeclarations[].parametersfield, which only permitsenumonTYPE_STRINGproperties per Google's documented rule. This breaks tool-calling for every model whoseparameter_constraintscarry a non-stringChoice.Reproduction
Calling any Gemini text model with a tool fleet that includes one of these constraints fails:
Choice(options=[4, 6, 8])—durationon all four Veo modelssrc/celeste/modalities/videos/providers/google/models.py:26(veo-3.0-generate-001)src/celeste/modalities/videos/providers/google/models.py:40(veo-3.0-fast-generate-001)src/celeste/modalities/videos/providers/google/models.py:54(veo-3.1-generate-preview)src/celeste/modalities/videos/providers/google/models.py:75(veo-3.1-fast-generate-preview)Choice(options=[768, 1536, 3072])—dimensionson both Google embedding modelssrc/celeste/modalities/embeddings/providers/google/models.py:21(gemini-embedding-001)src/celeste/modalities/embeddings/providers/google/models.py:30(gemini-embedding-2-preview)Error
```
HTTPStatusError: google API error: Invalid value at
'tools[0].function_declarations[N].parameters.properties[M].value.enum[0]'
(TYPE_STRING), 4
```
Root cause
src/celeste/providers/google/generate_content/parameters.py:222assigns the raw JSON schema to the legacyparametersfield:```python
result["parameters"] = schema
```
parametersis a narrow OpenAPI-2 subset whereenumis valid only onTYPE_STRINGproperties (see https://ai.google.dev/api/caching#Schema: "Possible values of the element of Type.STRING with enum format")._remove_titlesis the only existing sanitization step; no coercion of non-string enums, no translation of composition keywords, no handling of$defs/$ref.Proposed fix
Switch to the
parametersJsonSchemafield introduced in Gemini's November 2025 structured-outputs update (https://blog.google/technology/developers/gemini-api-structured-outputs/: "added support for JSON Schema to all actively supported Gemini models"). That field accepts native JSON Schema — integer enums,\$defs,\$ref,anyOf,oneOf,additionalProperties— with no sanitization.```python
src/celeste/providers/google/generate_content/parameters.py:222
result["parametersJsonSchema"] = schema
```
parametersandparametersJsonSchemaare mutually exclusive per Gemini's API reference (https://ai.google.dev/api/caching) — send one, not both.Ecosystem precedent
parametersJsonSchemaunconditionally in its Gemini provider: https://github.com/pydantic/pydantic-ai/blob/main/pydantic_ai_slim/pydantic_ai/models/google.pygoogle-genaiSDKSchema.from_json_schema(...)(the legacy-shape sanitizer) now emits deprecation warnings steering callers towardparametersJsonSchema.langchain-google-genai) still on legacy and has the same bug (langchain-google/issues/409). Both are trailing indicators; celeste has no reason to follow.Model compatibility
Every Gemini model currently registered in
src/celeste/modalities/text/providers/google/models.pyis 2.5+ or 3.x — all within Google's November 2025 "all actively supported Gemini models" set. No 1.0/1.5/2.0 entries to worry about.Tests
tests/unit_tests/(or the Google provider tests directory): build a tool with an integerChoiceconstraint, map it throughToolsMapper._map_user_tool, assert the emitted dict hasparametersJsonSchemawith the integer enum preserved (not coerced, not dropped).tests/integration_tests/text/test_tools.pycontinue to pass — string-enum schemas flow through unchanged.Scope
Single-line behavioral change + one new unit test. No API surface change for celeste-ai callers.