Skip to content

fix(core): normalize JSON Schema nullable type arrays in toGeminiSchema - #45

Closed
mv2sa wants to merge 5 commits into
cortexkit:mainfrom
mv2sa:fix/gemini-nullable-type-array
Closed

mv2sa wants to merge 5 commits into
cortexkit:mainfrom
mv2sa:fix/gemini-nullable-type-array

Conversation

@mv2sa

@mv2sa mv2sa commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Fixes #44

Summary

toGeminiSchema already normalizes anyOf / oneOf null unions into { type, nullable: true }, but JSON Schema nullable type arrays (type: ["string", "null"]) reached typeof inputSchema.type === 'string' as an array and had their type dropped. Tools that declare nullable arguments via type arrays (such as OpenCode 2.x tools with type: ["string", "null"]) then failed on Gemini models with HTTP 400.

Changes

  • Add normalizeNullableTypeArray in packages/core/src/transform/gemini.ts after mergeSchemaAllOf to normalize:
    • 2-element nullable type arrays (["string", "null"], ["null", "integer"], etc., case-insensitive and deduplicated) to { type: "<type>", nullable: true }
    • 1-element arrays (["string"] -> type: "string", ["null"] -> type: "null")
    • Nested object properties, array items, and allOf-merged schemas
  • Leave genuine multi-type arrays (["string", "number"]) and unknown type entries untouched so existing provider validation handles them without misclassifying schema errors.
  • Add unit coverage in packages/core/src/transform/gemini.test.ts.

Verification

  • bun test --isolate packages/core/src/transform/gemini.test.ts (166 pass, 0 fail)
  • bun run --cwd packages/core typecheck (0 errors)
  • bun x @biomejs/biome check packages/core/src/transform/gemini.ts packages/core/src/transform/gemini.test.ts
  • Live tool-call round-trips with explicit null arguments on antigravity-gemini-3.8-flash and antigravity-gemini-4-argon.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files

Reply to a comment to ask cubic a question or push back. It learns from your replies.

View guided diff | Re-trigger cubic

Comment thread packages/core/src/transform/gemini.ts Resolved
@agauth-alfonso

Copy link
Copy Markdown

Thanks for the fix and the thorough tests. We checked it against our current integration branch: it merges cleanly, the transform, Pi and OpenCode request-helper suites pass, and the new tests fail without the change, which is what we want. The type + nullable: true output is the right Gemini form, and it works well with the existing items/properties filtering and with the GPT-OSS constraint handling.

A few changes before we merge:

  1. allOf and nullable. allOf: [{ type: ['object', 'null'], properties: { a } }, { type: 'object', properties: { b } }] now produces nullable: true. An intersection with a non-nullable object can't be null, so please keep nullable on the merged schema only when every branch is nullable, and add a test for the mixed case.
  2. Multi-type arrays. We agree that narrowing ["string", "number"] to one type isn't right. But the test does not narrow genuine multi-type arrays… asserts that the lowercase array is the expected output, and that output still fails on the wire. Please drop that assertion or rename the test so it doesn't present this as desired behaviour. Converting multi-type arrays to anyOf would also be welcome, but it's fine to leave it for a follow-up.
  3. Please move the set of allowed type names to a module-level constant instead of rebuilding it on each call.
  4. Please reduce the captured knowledge-tool fixture to the fields that exercise nullable handling, and leave out the third-party product name. Also, the invalid-array it.each rows are spread into arguments, so their titles render as %j, null, "bogus" and "string". Wrapping each row in an outer array would fix the titles.

Happy to help with any of these if you'd prefer.

@mv2sa

mv2sa commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Addressed all 4 items in 5752fcf:

  1. mergeSchemaAllOf now keeps nullable: true on the merged object schema only when every contributing branch is nullable, with unit coverage for both mixed and all-nullable allOf intersections.
  2. Renamed the multi-type array test and updated its assertion so it only verifies non-narrowing rather than asserting a lowercase array wire shape.
  3. Moved ALLOWED_JSON_SCHEMA_TYPES to a module-level constant.
  4. Reduced the knowledge-tool fixture to the fields exercising nullable handling (with third-party naming removed) and wrapped the invalid-array it.each rows in outer arrays so test titles render cleanly.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread packages/core/src/transform/gemini.ts Resolved
@agauth-alfonso

Copy link
Copy Markdown

Thanks — verified on a trial merge onto our current release: the transform
suite (333 pass), the Pi convert and OpenCode request-helper suites
(191 pass), and the core typecheck all pass, and the new tests fail with the
fix reverted, which is what we want. All four points from the last round are
addressed, including the allOf mixed-nullability case and the reduced
fixture. Approving; we will run the formatter over the test file on merge
(one tools: array it wants to collapse — CI's format:check would flag
it), with no content changes.

@agauth-alfonso

Copy link
Copy Markdown

Thank you for this fix and for working through the review. It shipped in 3.0.14 (https://github.com/cortexkit/antigravity-auth/releases/tag/v3.0.14), squashed into our release branch with you credited as co-author (Co-authored-by), which is why this PR shows as closed rather than merged.

@agauth-alfonso agauth-alfonso Bot closed this Oct 27, 2026
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.

toGeminiSchema drops type on JSON Schema nullable type arrays (type: ["string", "null"]), causing 400 on Gemini tool calls

1 participant