fix: drop empty-string enum values from Gemini tool schemas

Merged
AN
2d ago
+144-1

Issue for this PR

Closes #1531

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Why: Gemini models (google/*, google-vertex/*) currently fail every analyst-agent request with a 400 before the model runs:

GenerateContentRequest.tools[0].function_declarations[44].parameters.properties[unresolved].any_of[1].enum[0]: cannot be empty

Root cause: answer_commit's optional() helper unions z.literal(""), so that strict-schema providers' blank fillers count as absent. That literal is emitted as const: "", and the Gemini API rejects empty-string enum/const values. The Gemini branch of ProviderTransform.schema stringified enum values but never dropped empty ones.

What changed: the Gemini sanitizer in provider/transform.ts now drops const: "", skips enums whose values are all empty, and filters empty strings out of mixed enums. The branch keeps its type. This only changes the provider-facing schema: Zod still validates the arguments the model actually sends, so "" is still accepted as "absent" at runtime. Other providers' schema paths are untouched.

  • Before: Gemini request with the analyst tool set → 400, no model call.
  • After: the declaration has no empty enum/const; {type:"string", const:""} becomes {type:"string"}, and enum:["", "a"] becomes enum:["a"].

Tenant/user impact: anyone using a Gemini model with the analyst agent, which is currently fully broken. No change for other providers.

Deployment readiness: self-contained.

How did you verify your code works?

  • Unit/integration: the new test/altimate/tools/tool-schema-gemini.test.ts runs every registered analyst/builder tool through the Google and Vertex transforms and asserts that no empty enum/const remains. It also has a sanitizer unit case. On unfixed main it fails, listing 10+ answer_commit const: "" locations; on this branch it passes.

  • test/provider/transform.test.ts, tool-schema-anthropic.test.ts, answer-commit.test.ts and the new test: 553 pass, 0 fail. bun run typecheck is clean.

  • Live provider: a build of this branch is being exercised against Vertex gemini-4-argon. Its startup probe makes a real tool-bearing request, which is what returned the 400 above on main.

  • Review: an independent review by a Sonnet agent at f9dd333568 (Codex CLI is out of quota) found no P0/P1. Its two P2 notes are fixed in e4a56e59: an untyped empty const/enum now keeps type: "string" instead of becoming {}, and an empty enum: [] is left untouched.

  • Local Codex review at e4a56e59: no P0/P1. One P2 not addressed: a typeless mixed enum ({enum: ["", "a"]}) keeps no type after filtering; no current tool emits that shape.

Screenshots / recordings

Not applicable. There are no UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code


[!NOTE]
Low Risk
Scoped to Gemini/Google schema sanitization before API calls; runtime validation is unchanged and other providers are untouched.

Overview
Fixes Gemini / Vertex tool requests that returned 400 because function-declaration schemas included empty-string const or enum values (e.g. from answer_commit’s optional() z.literal("")), which the API rejects with “cannot be empty”.

The Gemini branch of ProviderTransform.schema (sanitizeGemini) now strips const: "", omits enums that are only empty strings, and filters "" out of mixed enums while keeping the branch’s type. If dropping an empty literal would leave an untyped node as {}, it is coerced to type: "string". This only changes the provider-facing JSON Schema; Zod still validates tool args at runtime.

Adds tool-schema-gemini.test.ts: integration checks over registered analyst/builder tools for Google and Vertex, plus focused unit cases for the sanitizer.

Reviewed by Cursor Bugbot for commit e4a56e59b4b8328c1b9a7f66f44b3f4dcc78c236. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fixes Gemini tool schemas failing validation with a 400 because they contained empty-string enum or const values, which the Gemini API rejects. Before, every analyst-agent request using a google/* or google-vertex/* model failed before the model ran; after, the sanitizer in ProviderTransform.schema drops const: "", filters empty strings out of mixed enums, and keeps a node type: "string" when an untyped empty literal is dropped. Zod still validates tool arguments at runtime, so "" remains accepted as "absent". Other providers are unaffected.

  • Added tool-schema-gemini.test.ts, which runs all registered analyst and builder tools through the Google and Vertex transforms and asserts no empty enum or const remains, plus sanitizer unit cases for untyped, nullable, and empty enum nodes.

Closes #1531.

Summary by CodeRabbit

  • Bug Fixes
    • Improved compatibility for Gemini-powered tools by excluding empty-string values from schema constraints while preserving valid options. Schema fields remain correctly typed when empty constraints are removed, and nullable string handling is preserved.
  • Tests
    • Added coverage for schema transformations and tool availability across Google and Google Vertex providers, including checks for empty and valid enum values.