Repository navigation
Conversation
…de Assist TypeBox serializes Type.Union([Type.Literal(...)]) tool parameters as anyOf branches carrying "const". Cloud Code Assist validates function declarations against OpenAPI 3.0, which has no "const", so every request from a session with such a tool 400s with "Unknown name \"const\" at ...parameters.properties[N].value.any_of[M]" (e.g. subagent_check.evidence since openpi-dev#652; setup's role/browser unions are affected too). enum-carrying parameters in the same payload pass, so rewrite const to a single-value enum in sanitizeSchemaForCca instead of dropping the constraint. Verified live: pi -ne -a -e ai-providers -e subagents against google-antigravity/gemini-3.8-flash-high 400s before, replies after the rewrite; broader load with workflows+setup passes as well. Unit tests cover anyOf-branch literals, enum merging, and a property named const.
Align sanitizeSchemaForCca with oh-my-pi's current schema pipeline (packages/ai/src/utils/schema, MIT) for the same wire path: - Collapse all-literal combinators (anyOf/oneOf/allOf where every variant carries const, e.g. TypeBox Type.Union([Type.Literal(...)])) into a flat enum with a single inferred type, instead of anyOf-of-singleton-enums. - Infer the type of a bare const node from its value. - Sync nine missing Google-dialect denylist entries from omp fields.ts: $id, $anchor, contains, minContains, maxContains, additionalItems, contentEncoding, contentMediaType, contentSchema. - Add a final allowlist pass: only keys CCA's parameters dialect has accepted in practice (type/description/enum/items/properties/required/ anyOf/oneOf/allOf) reach the wire; type arrays are scalarized. A novel schema keyword now degrades the advertised schema (fail-soft) instead of 400ing every request, mirroring omp's validateAndFallback. Verified live against google-antigravity/gemini-3.8-flash-high with subagents + workflows + setup loaded: plain reply OK, wide smoke OK, and a real subagent_check tool round-trip through the collapsed enum. Unit tests 68/68.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #905 — the first commit of this branch is that PR's; only
7e18c1f9is new here. If #905 merges first, this PR's diff collapses to the hardening commit.Problem
sanitizeSchemaForCcais a denylist snapshot of oh-my-pi's olderfields.ts. Two gaps remain after the const fix (#905): (1) nine Google-dialect rejected keywords are missing from the denylist ($id,$anchor,contains,minContains,maxContains,additionalItems,contentEncoding,contentMediaType,contentSchema), so tools carrying them still 400; (2) the denylist shape fails hard — any keyword outside the list reaches the wire, and one rejection kills every request in the session. That failure class has now recurred twice on this sanitizer (#465, #905); out-of-tree schemas (MCP tools, third-party extensions) make recurrence a matter of time, not chance.Value
Aligns the sanitizer with the reference implementation for the same endpoint (oh-my-pi
packages/ai/src/utils/schema, MIT — shipped and exercised daily against Cloud Code Assist) and converts the boundary from fail-hard to fail-soft: a novel schema keyword now degrades the advertised schema instead of 400ing the session.Approach
Four changes to
sanitizeSchemaForCca, ported from omp's current pipeline where noted (hand-ported into our single-file sanitizer — no omp dependency, and none of omp's fork-level machinery):anyOf/oneOf/allOfwhere every variant carriesconst, e.g. TypeBoxType.Union([Type.Literal(...)])) into a flatenumwith a single type, instead ofanyOfof singleton enums (ompnormalize.ts"allHaveConst"). ForallOfthe collapse widens an intersection to a union, which only broadens what the model may pick — sound for an advertised schema.constnode'stypefrom its value (string/number/boolean).fields.ts(mechanism unchanged: liftable constraints still spill intodescription).type,title,description,enum,items,properties,required,anyOf,oneOf,allOf);typearrays are scalarized (a null-only array yields no type). Anything else is dropped — fail-soft, mirroring omp'svalidateAndFallbackintent.Intentionally not ported: omp's
$ref/$defsdereferencing, 2020-12 dialect upgrade, nullable extraction, property ordering, and the whole-profile machinery (~2.5k lines); also omp'sparametersJsonSchemaroute for Gemini models — both routes here stay onparameters, verified live.Validation
node --test --experimental-strip-types tests/extensions/ai-providers/antigravity.test.ts: 68 pass, covering combinator collapse (anyOf/oneOf/allOf, with and without explicit types), mixed-type unions staying unions, bare-const inference, the synced denylist entries, the gate (dropsif/then/nullable, keepstitleper omp parity), type-array scalarization, and properties namedconst/anyOf; plus abuildRequestBodyend-to-end assertion that a literal union reaches the wire as a flat enum.google-antigravity/gemini-3.8-flash-highwith subagents+workflows+setup loaded: reply OK; a model-drivensubagent_checkround-trip succeeds through the collapsed enum.bun run check: clean (biome format/lint, tsc --noEmit).node scripts/run-tests.mjs): the same 2 pre-existingtests/extensions/code-mode/index.test.tsfailures as clean main.Impact
enum(same value set, fewer tokens).if/then/else/not,nullable, customx-*) are now dropped from the advertised schema instead of being sent; previously they were sent and 400ed whenever a tool actually carried them. In-tree tools use none of these today (verified by grep), so there is no in-tree regression.