Repository navigation
[Bug]: google-antigravity tool continuation 400s once the in-process thought-signature replay cache misses #1429
Description
Client or integration
Direct HTTP/API client
Area
Provider adapter
Summary
Opening this per @Wibias's request on #1254, which was closed as fixed by #1266 (Vertex). This is the google-antigravity side, and it is a different failure than the one #1266 addressed.
A tool-call continuation on google-antigravity fails with HTTP 400 whenever the in-process reasoning-replay cache does not hold the signature:
Provider error 400: Antigravity invalid request: Function call is missing a thought_signature
in functionCall parts. This is required for tools to work correctly, and missing
thought_signature may lead to degraded model performance.
The cache in src/adapters/google-antigravity-replay.ts is process-local, with REPLAY_TTL_MS = 1h, ANTIGRAVITY_REPLAY_MAX_ENTRIES = 10_240, and batch eviction. So the signature is lost on a proxy restart, after an hour, or under eviction pressure.
What makes it unrecoverable rather than merely inconvenient is the client surface. On /v1/chat/completions there is no field where a caller can carry a thought signature back: the OpenAI tool-call schema has no equivalent of thoughtSignature. messagesToGeminiFormat will attach one from tc.thoughtSignature when present, but an OpenAI-format client has no way to populate it. When the cache misses, the conversation is simply stuck — every continuation of that tool call 400s, and re-sending the same history cannot help.
The Codex /v1/responses path is not affected in the same way, since the signature travels in the payload there.
Expected: a tool-call continuation on google-antigravity should keep working across a proxy restart, or, if that cannot be guaranteed, fail in a way the caller can act on rather than a provider 400 the client has no means to satisfy.
Not claiming which fix is right — persisting the cache, exposing the signature through an extension field on the OpenAI surface, and re-deriving the turn are all plausible and have different costs. Reporting the gap and the repro.
Reproduction
Deterministic on 2.12.0. The proxy restart between the two turns is the whole point — it empties the replay cache.
- Configure a
google-antigravityprovider (adapter: google,googleMode: cloud-code-assist,authMode: oauth). - Turn 1 — force a tool call and keep the response:
curl -s -X POST http://127.0.0.1:10100/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "google-antigravity/gemini-3.6-flash",
"messages": [{"role":"user","content":"What is the weather in Lisbon? Use the tool."}],
"tools": [{"type":"function","function":{"name":"get_weather","description":"Get the current weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}],
"tool_choice": "auto", "stream": false, "max_tokens": 512
}'Returns 200 with tool_calls: [get_weather({"city":"Lisbon"})].
- Restart the proxy —
ocx service stop && ocx service start. This clears the in-process replay cache. A one-hour wait or enough eviction pressure reproduces the same state without a restart. - Turn 2 — send the history back with the assistant tool call and the tool result:
curl -s -X POST http://127.0.0.1:10100/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "google-antigravity/gemini-3.6-flash",
"messages": [
{"role":"user","content":"What is the weather in Lisbon? Use the tool."},
{"role":"assistant","content":null,"tool_calls":[{"id":"<id from turn 1>","type":"function","function":{"name":"get_weather","arguments":"{\"city\":\"Lisbon\"}"}}]},
{"role":"tool","tool_call_id":"<id from turn 1>","content":"{\"tempC\": 19, \"sky\": \"clear\"}"}
],
"tools": [{"type":"function","function":{"name":"get_weather","description":"Get the current weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}],
"stream": false, "max_tokens": 512
}'Observed: HTTP 400 with the missing a thought_signature error above.
Control, to show the failure is the cache and not the request shape: run turns 1 and 2 back to back without restarting. It returns 200 and completes normally — the replay cache supplies the signature. I ran that four times across gemini-3.6-flash and claude-opus-4-6-thinking; all succeeded.
One incidental finding from the same measurements, in case it saves someone else the detour: the endpoint accepts the camelCase thoughtSignature key. google-antigravity-replay.ts injects only that form and those requests are accepted, so emitting a snake_case thought_signature alongside it is not needed. I had been carrying a local patch that did exactly that, on the assumption it was required; it was not, and I have dropped it.
Version
2.12.0
Operating system
Windows 11 Home Single Language 26H2 (build 10.0.26200)
Provider and model
google-antigravity / gemini-3.6-flash (also reproduced on claude-opus-4-6-thinking)
Logs or error output
# turn 2, after a proxy restart
status: 400
{"error":{"message":"Provider error 400: Antigravity invalid request: Function call is missing a
thought_signature in functionCall parts. This is required for tools to work correctly, and missing
thought_signature may lead to degraded model performance. Additional data, function call
`default_api:get_weather` , position 2. Please refer to
https://ai.google.dev/gemini-api/docs/thought-signatures for more details.",
"type":"invalid_request_error","param":null,"code":"invalid_request_error"}}
# same two turns without the restart
status: 200
finish_reason: stop
content: "The current weather in Lisbon is clear with a temperature of 19°C."Relevant constants in src/adapters/google-antigravity-replay.ts (v2.12.0):
REPLAY_TTL_MS = 60 * 60 * 1000 // 1h
ANTIGRAVITY_REPLAY_MAX_ENTRIES = 10_240
REPLAY_EVICT_BATCH = 128
Screenshots and supporting files
Not attached — the reproduction above is self-contained.
Redacted configuration
{
"providers": {
"google-antigravity": {
"adapter": "google",
"baseUrl": "https://daily-cloudcode-pa.googleapis.com",
"authMode": "oauth",
"googleMode": "cloud-code-assist",
"defaultModel": "gemini-3.6-flash"
}
}
}Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
brunoflma commentedon Aug 10, 2026
Scoping detail I did not have when I filed: this is Gemini-only, and the code says so —
shouldReplayreturns!/claude/i.test(model)(google-antigravity-replay.ts:362), so Claude-on-Antigravity takes the inline-sanitization path instead of the replay cache.Measured the pair on 2.12.0, same procedure both times (turn 1, restart the proxy, turn 2):
gemini-3.6-flashFunction call is missing a thought_signature in functionCall partsclaude-opus-4-6-thinkingSo the blast radius is the Gemini family on
google-antigravity, not the provider as a whole. If a fix targets the replay cache specifically, that is the right scope.Also confirmed the underlying file is untouched between v2.11.0 and v2.12.0, so nothing about this changed in the release I filed against.
Ingwannu commentedon Aug 11, 2026
Confirmed against current
dev: this is a real Gemini-on-Antigravity continuation bug, and the reporter's narrowed scope is correct. The OpenAI Chat surface cannot carrythoughtSignature, while the current replay state is process-local, so a restart/expiry/eviction turns an otherwise valid tool continuation into an unrecoverable upstream 400. Claude-on-Antigravity uses the separate inline path and is not affected by this cache boundary.PR #1434 is the active fix and its durable-cache direction is appropriate; I am not creating a duplicate patch. I requested two remaining changes on its current head: enforce the snapshot cap against the complete serialized document (not only entry payloads), and make bounded flush non-convergence fail explicitly instead of silently reporting shutdown success with a newer mutation still unpersisted. The branch also needs a refresh onto current
devand exact-head full CI.Keeping this issue open until the corrected PR is independently reviewed and integrated into
dev.docs(devlog): plan the seven paired bug-fix landings
fix(google-antigravity): reject an unconverged replay flush and cap t…
lidge-jun commentedon Aug 11, 2026
Fixed on
dev(via #1434).The thought-signature replay cache is no longer process-local: it persists to a snapshot with atomic writes and restricted permissions, load-time validation and trimming, activity-ordered eviction, and a flush on shutdown. A restart no longer loses the signatures, so a tool-call continuation on
google-antigravitystops failing withFunction call is missing a thought_signature.Two durability corrections on top of the original work: flush budget exhaustion now rejects rather than silently resolving — shutdown was otherwise reporting a durability it could not demonstrate — and the snapshot byte cap now accounts for the document framing and separators, not just the entries, so the written file actually honors the configured limit.
Verified: 55 pass / 0 fail on the replay suite, 17 pass / 0 fail on shutdown drain.
Thanks for opening this as a separate issue from the Vertex case in #1254 — they really were different failures.
docs(devlog): plan the seven paired bug-fix landings
fix(google-antigravity): reject an unconverged replay flush and cap t…