Skip to content

fix(antigravity): preserve local schema refs - #488

Open
testikun wants to merge 3 commits into
openpi-dev:mainfrom
testikun:codex/issue-465-ref-safety
Open

fix(antigravity): preserve local schema refs#488
testikun wants to merge 3 commits into
openpi-dev:mainfrom
testikun:codex/issue-465-ref-safety

Conversation

@testikun

@testikun testikun commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Problem

Closes #465. Antigravity removed $defs during tool conversion and $ref during provider sanitization, leaving referenced result-contract properties as {} in the outbound schema.

Value

Direct Subagent and Workflow structured-output contracts remain visible to the model while unsupported Cloud Code Assist keywords are still removed.

Approach

  • Expand same-document JSON Pointer references before the existing CCA sanitizer.
  • Reject external, unresolved, recursive, too-deep, too-large, or over-node-limit references before sending a request.
  • Preserve sibling keywords and existing no-reference behavior.
  • Add provider-chain regression tests and a design/ablation record.

Validation

  • node --test --experimental-strip-types tests/extensions/ai-providers/antigravity.test.ts passed: 39/39.
  • bun run check passed: config contract, discipline ledger, Web build/typecheck, format, lint, and TypeScript typecheck.
  • Ablation: without expansion the issue fixture produces an empty referenced property; without bounds expansion could be unbounded.
  • Real provider/model smoke: not run; tests use the existing local conversion and mocked transport boundaries.

Impact

  • User-visible behavior: Antigravity model tool declarations retain expressible local result constraints.
  • Model-visible context/tools: structured schemas sent to Antigravity are more faithful.
  • Runtime/lifecycle: request preparation now fails closed for unsupported references.
  • Persisted config/data: none.
  • Compatibility/risk: schemas without references retain existing behavior; expansion is bounded.

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 8, 2026
@JS-banana

JS-banana commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

hi,Preserving structured output contracts in CCA tool declarations is a valuable fix.

Sharing two observations regarding traversal overhead and node/byte accounting in expandLocalSchemaRefs:

1. Repeated subtree serialization in visit

In visit:

bytes += Buffer.byteLength(JSON.stringify(value) ?? "");
  • Because JSON.stringify(value) is executed at every node during the recursive walk, every subtree is serialized repeatedly down to the leaf nodes. For a schema with depth $D$ and node count $N$, this produces $O(N \times D)$ serialization overhead.
  • bytes accumulates the sum of every serialized intermediate subtree rather than the byte length of the schema itself (for instance, a schema of ~4 KB can accumulate >20 KB in bytes).
  • This traversal runs in convertTools for all registered tools on each turn, regardless of whether a schema contains $ref.

2. Double traversal of target and MAX_SCHEMA_REF_NODES (512)

In $ref expansion:

const target = visit(pointer(ref), depth + 1, ref) as Record<string, unknown>;
active.delete(ref);
const siblings = Object.fromEntries(
  Object.entries(object).filter(([key]) => key !== "$ref"),
);
return visit({ ...target, ...siblings }, depth + 1, path);
  • target is fully traversed and counted by visit(pointer(ref)).
  • Passing { ...target, ...siblings } into return visit(...) traverses the entire target subtree a second time, incrementing nodes and bytes again for every field.
  • Along with the initial traversal of $defs from the root, the effective node count for referenced types is multiplied. In practice, a schema with ~50–60 fields and 1–2 $ref usages can exceed MAX_SCHEMA_REF_NODES (512) due to the repeated counting and fail closed before sending the request.

@testikun

testikun commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

已推送修复提交 9322d4f(同步最新 main,快进更新源分支)。针对 schema $ref 展开评审意见:移除每个节点的重复 JSON 序列化;展开引用目标后不再二次遍历;保留最终展开 schema 的 256 KiB 上限,并用 60 字段/双引用和超大 schema 回归锁定节点与字节边界。验证:bun run check 通过;完整测试 Node 1469 passed / 1 skipped,Vitest 130 passed;Antigravity 41/41 passed。

@tt-a1i tt-a1i left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at exact head 9322d4f.

Standards

[P1] The 256 KiB bound is checked only after the full expanded graph has been materialized and JSON-stringified. Many references to one large subtree can amplify a small input dramatically before rejection, allowing excessive allocation or OOM during request preparation. Account for emitted expansion bytes before cloning/materialization.

[P2] The resolver applies depth 16 / node 512 limits to every schema, including schemas with no $ref, while the canonical structured-output boundary accepts depth 24 / 10,000 nodes. This regresses previously valid Antigravity tools. Fast-path no-ref schemas or align the limits with the authoritative boundary.

Spec

[P1] $ref siblings shallow-overwrite referenced keywords. A target containing properties / required combined with sibling constraints loses the referenced constraints instead of preserving conjunction.

[P1] A valid boolean-schema target false is object-spread into {}, reversing “reject everything” into unconstrained acceptance.

[P2] JSON Pointer traversal uses inherited property lookup, so #/$defs/toString can resolve Object.prototype.toString instead of failing closed. Use own-property traversal only.

Please add regressions for sibling collisions, boolean targets, inherited/unresolved pointers, and ordinary no-ref compatibility before merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(antigravity): 工具 Schema 转换静默删除 $ref 结果约束

3 participants