Skip to content

[Bug]: google-antigravity tool continuation 400s once the in-process thought-signature replay cache misses #1429

Description

@brunoflma

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.

  1. Configure a google-antigravity provider (adapter: google, googleMode: cloud-code-assist, authMode: oauth).
  2. 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"})].

  1. Restart the proxyocx 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.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't workingproviderProvider adapters, OpenAI-compat presets, upstream API quirksserviceService lifecycle (WinSW/launchd/scheduler)toolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions