Repository navigation
Open
Labels
bugSomething isn't workingSomething isn't working
Description
问题
Antigravity 的工具 schema 转换会静默删除本地 $ref 指向的完整结果合同。引用字段最后可能变成 {},模型看不到原 schema 要求的嵌套字段、类型和枚举。
Direct Subagent 的 output_schema 和 Workflow 的 structured output 接受 JSON Schema。相同合同在本地参数校验和模型收到的工具声明之间发生语义漂移。
价值
让模型看到能够满足的结果合同,减少因隐藏要求而产生的校验失败和纠错回合。对于 provider 无法表达的 schema,调用前明确报错比悄悄删空约束更容易定位和修复。
审计边界
- 检查日期:2026-09-08。
- 固定源码:ed9dbc1018f890fd54375f5371990ddfee8af5df。
- 已验证:实际仓库本地
convertTools(..., true)→sanitizeSchemaForCca完整纯转换链。 - 验证使用本地 converter 与从同一固定源码提取的 sanitizer;没有只凭 sanitizer 单点输出来推断上游转换结果。
- 未验证:Antigravity 线上请求、HTTP 响应、真实模型任务或 provider 内部处理;不声称已经观察到 HTTP 400、重试次数或成功率变化。
触发条件
- 通过 Antigravity route 使用具有本地
$ref的工具参数 schema,例如 Direct/Workflow 的结构化结果。 - 被引用的定义承载模型必须满足的结构或约束。
- 出站工具转换先删除定义,再删除引用;该字段变成无结构说明的空 schema。
最小输入
{
"type": "object",
"properties": {
"answer": { "$ref": "#/$defs/Answer" }
},
"required": ["answer"],
"$defs": {
"Answer": {
"type": "object",
"properties": {
"verdict": { "type": "string", "enum": ["pass", "fail"] }
},
"required": ["verdict"]
}
}
}将该 schema 作为一个工具的 parameters,依照 buildTools 的顺序执行:
const declarations = convertTools([{
name: "structured_output",
description: "Return the final result",
parameters: schema,
}], true);
const converted = declarations[0].functionDeclarations[0].parameters;
const wire = sanitizeSchemaForCca(converted);已验证的完整链输出为:
{
"converted": {
"type": "object",
"properties": { "answer": { "$ref": "#/$defs/Answer" } },
"required": ["answer"]
},
"wire": {
"type": "object",
"properties": { "answer": {} },
"required": ["answer"]
}
}verdict、它的类型、枚举和嵌套 required 已全部不在出站工具声明中。这里的 wire 指客户端转换后的声明,不是线上 provider 接收回执。
源码证据
subagents/src/prompt.ts:197-204:output_schema接受带任意属性的对象。shared/structured-output.ts:32-68:检查 JSON 形状、深度和节点边界后,Type.Unsafe(schema)保留调用方 schema,没有禁止本地引用。antigravity/google-conversion.ts:26-35与397-429:本地convertTools的sanitizeForOpenApi删除$defs/definitions,没有展开$ref。antigravity/provider.ts:81-84与157-166:第二步直接删除$ref,也没有把引用内容转成 description。antigravity/provider.ts:272-290:所有相关工具声明依次经过这两步转换。
已有保护与建议范围
结构化工具仍保留原 schema 供 Pi 参数校验使用,因此本问题不等于“错误 JSON 会被当作有效结果”。当前代码也会把部分不支持的长度/数值约束写入 description;这些保护不能恢复已删除的引用结构。
建议转换前有界展开能够表达的本地引用;递归引用、外部引用或超出边界的展开明确拒绝并说明原因。实现选择应保持 provider 适配边界,不复制一套子任务执行或校验 Runtime。
验收
- 同一 fixture 同时验证原始 schema、完整出站转换链和参数校验,至少覆盖上面的嵌套对象、required、enum。
- 可表达的本地引用在最终声明中保留结构含义,不能静默变成
{}。 - 递归引用、外部引用、过深或过大的展开在发起模型请求前明确失败,且转换成本有界。
- 普通无引用 schema 和已有 description spill 行为保持兼容。
- 验证记录区分纯 schema 转换、Pi 参数校验和真实 provider 验收;未运行的层次明确列出。
Related: #234 Antigravity/Cursor provider、#155 Direct Subagent 结构化结果合同。本 Issue 跟踪两者交界处的具体 schema 转换缺陷。
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity
testikun commentedon Sep 8, 2026
我来认领 Antigravity 工具 schema
$ref约束丢失切片。技术方案:在 provider-specific sanitize 边界增加有界 local
$refresolver,仅解析同一 schema document 内的 JSON Pointer;设置 depth/node/byte/cycle 上限,无法表达的外部或循环引用显式返回可诊断转换错误,不再把约束静默替换成{}。保留无$refschema 与已有 provider 兼容行为,补充 nested definitions、数组/枚举、循环引用、超限和 Direct/Workflow structured output 的转换回归测试。testikun commentedon Sep 8, 2026
开始处理,基线 upstream/main a3edee2。先固定 provider 出站转换链,方案拟采用同 document 内 JSON Pointer 的有界展开;外部/循环/超限引用在发请求前显式失败,保留普通 schema 兼容行为。
testikun commentedon Sep 8, 2026
实现已完成并提交 PR #488:provider 转换先展开有界同文档 JSON Pointer,再执行现有 CCA sanitizer;外部/未解析/循环/超限引用 fail-closed。专项 39/39,bun run check 通过。