Repository navigation
Description
Description *
Same post-fold Google 400 as #5252, reproduced on Antigravity (agy) rather than DSH/Vertex.
After one successful compress, every later request of the session is rejected by Google until the lane is taken out of bili. The session cannot be repaired in place: thoughtSignature is gone from remaining functionCall parts, and it cannot be invented.
This client has no plugin seam and does not rewrite conversation history around the fold splice (docs/clients.md: Antigravity is launcher-only, closed Go language_server). That makes a pure “client resent unsigned parts” explanation (#5277) incomplete for this lane.
Repro
- Route Antigravity through bili by setting
CLOUD_CODE_URL/AGY_ACP_CCPA_BASE_URLto
http://127.0.0.1:8787/bili/https://daily-cloudcode-pa.googleapis.com. - Use
gemini-4-argon-mediumwith tools (default_api:run_command). - Let the session grow until T1 injects
compress. - Fold applies (
outcomeapplied, ~46k tokens saved). - Immediate re-request 400s. Every retry 400s.
What we expected
A remaining functionCall part after fold either:
- keeps its original
thoughtSignatureverbatim, or - is folded away entirely (no bare
functionCallleft on the wire), or - is dropped with an explicit local warn instead of forwarding a body Google will 400.
Observed
- Fold
m00001–m00049on session94fa0cbc-6e4c-4568-a975-b6d71296ee15. 67 msgs → 24 msgs, shrink ~70% (~46059/66022).- Next
processTurnis immediately followed by:
Function call is missing a thought_signature in functionCall parts/default_api:run_command/ position 18. - Retry ~12 min later: same 400, position 2.
invariant-judgeon the 400 request:clean fold verdict: matched 2/2, exempt carrier=1.- Not overflow: last settled input ~55294 vs window 1048576. bili’s overflow self-heal cannot engage (
#4452log). - Earlier session
2c3dcaa6-d3ae-406e-ba55-b425d84cfc76hit the same 400 on this lane.
Related: #5252 (same 400 after fold, DSH + Vertex), #5277 (audit/warn only, no wire change), #3158 (standalone SSE signature parts — different stage).
Local workaround we applied: stop sending this host through bili (CLOUD_CODE_URL back to https://daily-cloudcode-pa.googleapis.com, plus per-route passthrough). Grok/other lanes stay compressed.
摘要
Google 车道(Antigravity / daily-cloudcode-pa.googleapis.com)一次正常折叠后,保留下来的 functionCall 丢了 thoughtSignature,下一轮起每请求都 400,会话无法继续。Antigravity 没有插件缝、不会在 fold splice 后改写历史,所以不能只归因于客户端重放丢签名。#5252 的同族问题;#5277 目前只打日志。
bili version *
0.1.213
Usage mode *
Proxy mode (client manually points its base URL at bili)
OpenBot custom Antigravity wrapper rewrote CLOUD_CODE_URL / AGY_ACP_CCPA_BASE_URL to /bili/https://daily-cloudcode-pa.googleapis.com. Not bili antigravity launcher, same URL rewrite.
Client and version *
Antigravity (agy) 1.4.5 (agy_acp_server.par, darwin-arm64). No native bili plugin.
Operating system *
macOS (darwin-arm64)
Upstream and model *
https://daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent · gemini-4-argon-medium · declared window 1048576
Compression-related config (optional)
Default compress. No per-provider override at the time of the 400 (empty providers block). Later we set:
{
"providers": {
"https://daily-cloudcode-pa.googleapis.com": { "passthrough": true }
}
}Log excerpt
Times are UTC from ~/.local/state/billion-context/bili.log. Secrets stripped.
2026-11-10T10:41:53.183 processTurn: 67 msgs, renderTags=text-only, 7 text tagged, 1 tool tagged
2026-11-10T10:41:53.184 nudge INJECT T1: usage=9% (97349/1048576), growth=54647/22500, pendingT1=50785/50000 model=gemini-4-argon-medium
2026-11-10T10:41:53.188 forward POST → https://daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent
2026-11-10T10:42:21.017 [acp-usage] round 1 input=101353 cached=17807 (cache hit 18%)
2026-11-10T10:42:21.040 [acp-proxy: compress requested 1 range(s): m00001–m00049]
2026-11-10T10:42:21.045 [acp-compress-obs] shrink 70% this-fold (~46059/66022 tok) · postCtx≈19878
2026-11-10T10:42:21.049 [Compressed m00001–m00049 → 1 block(s), ~46059 tokens saved.]
2026-11-10T10:42:21.051 [acp-loop] round 1: re-request view refreshed to post-compress fold
2026-11-10T10:42:21.656 processTurn: 24 msgs, renderTags=text-only, 5 text tagged, 0 tool tagged
2026-11-10T10:42:21.660 request: inbound=380.7KiB, outbound=272.6KiB
2026-11-10T10:42:21.669 [invariant-judge/main] clean fold verdict: matched 2/2, exempt carrier=1 reasoning=0 crush=0 ccr=0 truncate=0
2026-11-10T10:42:22.777 ← upstream 400: Function call is missing a thought_signature in functionCall parts. … function call `default_api:run_command` , position 18.
2026-11-10T10:54:53.620 processTurn: 25 msgs …
2026-11-10T10:54:53.640 [invariant-judge/main] clean fold verdict: matched 2/2, exempt carrier=1
2026-11-10T10:54:54.816 ← upstream 400: … function call `default_api:run_command` , position 2.
Can provide inbound/outbound dumps for this session if needed (ACP_DUMP_BODY / BILI_DUMP_4XX).
Activity
ranxianglei commentedon Nov 10, 2026
(ai: vllm-qwen/qwen3.8-27b)
查重结论:不重复,且已有在途修复 PR,我未另开并行 PR。
functionCall丢失thoughtSignature→ 之后每轮 sticky 400(Function call is missing a thought_signature in functionCall parts)。[Bug] Google 车道折叠后保留的 functionCall 丢 thoughtSignature,下一轮必 400(gemini-4-argon / Vertex) #5252 是更早的报告(DSH Desktop + Vertex,gemini-4-argon,点名herdr_pane_read);本 thread 是 Antigravity + Vertex(gemini-4-argon-medium,点名default_api:run_command)。同一缺陷家族。src/server/google-sig-audit.ts),其审计看到 part 从客户端进来时就已经无签名——这正好是本 bug 的下游痕迹,不是修复本身。Fixes #6079+Fixes #5252)。按「一个 thread 一个修复 PR」规则,我没有另开并行 PR,而是对 [PR] fix(google): promote stripped proxy call thoughtSignature onto surviving sibling functionCall (#6079, #5252) #6103 做了独立审核。下面是对它的核验结论。根因(我独立读旧代码验证过,成立):
旧
filterRealCallChunk(src/loop/adapter-google.ts)用parts.filter((_,i)=>keep[i])逐字丢弃 proxy part、原样保留 real part。Gemini 只对一轮里第一个functionCallpart 盖thoughtSignature;当那个带签名的第一个调用恰好是会被服务端执行并剥离的 proxy 工具(compress),它就丢了,而幸存的首个真实调用没有签名 → 被原样转发给客户端 → 客户端把它记成「无签名的 leading functionCall」→ 下一轮回放 → Gemini 400。这条因果链精确解释了报告者的证据:折叠前一直 200(还没出现过「[带签名的 proxy + 真实]」并行轮),一次 compress 后每轮必 400,且点名的
run_command正是与触发折叠那次 compress 并行的真实工具调用;会话无法就地恢复(签名已被客户端记成缺失,无法凭空补回)。(说明:我最初在 kernel 的折叠重建路径上做的探针复现不出来,正是因为 bug 不在
processTurn/coreToGoogle折叠重建层,而在流式剥离/结算这一层——#6103 修对了地方。)修复评估(#6103,三处出站面,都在源头防中毒):
src/loop/adapter-google.ts:settleToolCalls计算出promoteSig(首个真实调用无签名 && 被剥离的 proxy 带签名时),filterRealCallChunk把该签名提升到对应 part 上(仅当目标本就无签名,绝不覆盖)。无 proxy、无提升时仍返回"keep"(逐字节原样,保前缀缓存锚点)。src/stream-google.ts:非流式 JSON 路径同样捕获被剥离 proxy 的签名并挂到首个幸存真实 fc;纯 proxy 轮则挂到合成 note 文本 part。src/loop/core.ts:runCompressLoop把本轮 proxy 签名传播给缺签名的并列 proxy tc 记录(仅 google)。PROXY_TOOL_SET扩充:+acp_cache/acp_retrieve/acp_rule/acp_read_original_image。其中acp_read_original_image是干净收益(isProxyToolFor恒真,此前在 Google 车道会泄漏给客户端,Egress image downscale: shrink big images before sending to the model, originals stay local and self-readable | 重做图片降采样(简化版):发模型前压大图、原图留本地不动、模型被告知尺寸后可自读原图 #3400 本意就是别转发)。测试: 6 个新用例、双向断言(符合 Gate Discipline #3617),含负向控制(真实调用自带签名绝不被覆盖)和最关键的一条回归锚点——
runCompressLoop+ 下一轮googleToCore→coreToGoogle回放后断言 survivingwrite_file仍带签名(正是能钉住本 bug 的那条)。测试有牙。CI(镜像缓存,实时): 30 项,failed 0;static-gates/gate/mysql-contract 绿,test 分片在跑,e2e 待 gate。目前无失败。
我提的风险点(建议合并前确认第 1 条,其余非阻塞):
stream-google.ts的 notePart 分支:纯 proxy 轮(模型只发 compress、没有真实工具/文本——很常见)时,把被剥离 compress 的thoughtSignature注入到合成的普通文本 note part 上。「真实 Gemini 是否接受非 reasoning 的普通 model 文本 part 携带thoughtSignature」在本环境无法实测(单测走 mock)。若被拒,纯折叠轮可能新增 400,影响面大。建议:对真实端点快速确认一次,或收窄该分支(只在有真实 fc 幸存时提升签名,去掉对文本 part 的注入)。PROXY_TOOL_SET与isProxyToolFor条件不一致:acp_retrieve/acp_rule现在被硬编码进 adapter-google 的PROXY_TOOL_SET(无条件当 proxy 剥离),但isProxyToolFor(src/absorb.ts:49)只在 CCR/rules 开启时才把它们当 proxy。特性关闭 + 模型幻觉调用 → 结算层剥离、执行层不执行 → 静默丢弃(旧行为是泄漏给客户端)。仅幻觉可达,低风险;更干净的做法是让两处条件对齐。core.ts把同一个签名复制到多个并列 proxy tc 记录——语义上最不确定,但防御性 + 仅 google,且有测试fix: post-merge review fixes + per-route context window + XDG config #6 兜底。判定:根因成立、修法在正确层次(源头防中毒)、测试扎实、CI 未见失败 → 建议可合并,合并前请确认风险点 1。我不合并(人工权限)。
注意:该修复防止的是新会话中毒;报告者当前已中毒的会话仍然坏着,需重启/摘出该 host(与 #5252 一致,无法就地恢复)。
结构化八问
functionCall丢失thoughtSignature,导致之后每一轮请求都 400,会话彻底不可用直到重启。functionCall盖签名;当那个带签名的首个调用是被服务端执行并剥离的 bili proxy 工具(compress),剥离后幸存的首个真实调用没有签名,还被原样转发给客户端记进历史 → 下一轮回放必 400。根在流式剥离/结算层,不在折叠重建层。thoughtSignature,提升到该轮首个原本无签名的真实functionCall上(绝不覆盖已有签名),覆盖流式结算、非流式 JSON、re-request 循环重建三处出站面,避免客户端把无签名调用记进历史。keep逐字节不变(保持);真实调用自带签名不被兄弟 proxy 覆盖(负向控制钉住,保持);全 proxy 轮整块丢弃行为不变(保持);插件模式因提升逻辑自门控(仅在实际发生剥离时触发)不受影响。潜在漂移两处:①notePart 向普通文本 part 注签名(风险点1,可能改变既有出站字节/新增 400);②PROXY_TOOL_SET扩大使四个 ACP 工具在 Google 结算层被当 proxy 处理(风险点2,低危)。filterRealCallChunk仍返回"keep"(逐字节原样,前缀缓存锚点不动);只有真正需要剥离/提升时才重写。唯一额外改字节的点是 notePart 注签名(见风险点1)。fix(google): promote stripped proxy call thoughtSignature onto surviv…
fix(google): promote stripped proxy call thoughtSignature onto surviv…