← Back to PRs

#15379: fix(antigravity): strip unsigned thinking blocks in agent loop via transformContext

by jg-noncelogic open 2026-02-13 11:02 View on GitHub →
agents size: S
## Summary Fixes #13826 Google Antigravity returns Claude thinking blocks without `signature` fields. The existing `sanitizeAntigravityThinkingBlocks` in `sanitizeSessionHistory` only runs once per user turn (at session load), but within the same turn, pi-ai's `agent-loop.js` accumulates assistant responses—with unsigned thinking blocks—in `context.messages` and replays them on subsequent API calls during tool-call iterations. This causes: ``` LLM request rejected: messages.N.content.0.thinking.signature: Field required ``` ### Fix Use the `Agent.transformContext` hook (called by the agent loop before every API call) to run `sanitizeAntigravityThinkingBlocks`, stripping unsigned thinking blocks both at session replay **and** between tool-call iterations within a single turn. The hook is only set when `transcriptPolicy.normalizeAntigravityThinkingBlocks` is true (i.e., Antigravity providers), so non-Antigravity providers are unaffected. ### Code flow (before fix) ``` agent-loop.js: streamAssistantResponse() → API returns assistant with thinking block (no signature) → stored in context.messages agent-loop.js: tool execution → next streamAssistantResponse() → context.messages still has unsigned thinking blocks → API rejects: "thinking.signature: Field required" ``` ### Code flow (after fix) ``` agent-loop.js: streamAssistantResponse() → config.transformContext(messages) ← strips unsigned thinking blocks → clean messages sent to API ``` ## Test plan - [x] All 81 `pi-embedded-runner` tests pass - [x] `pnpm build && pnpm check` clean - [x] Verified on live Antigravity deployment with tool-calling conversations 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> Fixes a runtime error (`thinking.signature: Field required`) that occurs during multi-step tool-calling conversations with Google Antigravity Claude models. The root cause: unsigned thinking blocks accumulate in `context.messages` between tool-call iterations within the agent loop, and the existing `sanitizeSessionHistory` only runs once at session load. The fix hooks `sanitizeAntigravityThinkingBlocks` into the agent's `transformContext` callback (called before every API request), ensuring unsigned thinking blocks are stripped both at session replay and between tool-call iterations. - Hooks `sanitizeAntigravityThinkingBlocks` via `Agent.transformContext` in `attempt.ts`, gated behind `transcriptPolicy.normalizeAntigravityThinkingBlocks` (only active for Antigravity Claude models) - Includes a runtime reference-comparison guard to detect if the `transformContext` property assignment fails (e.g., due to `Object.freeze` or a read-only setter) - Adds comprehensive unit tests for `sanitizeAntigravityThinkingBlocks` covering the `transformContext` code path (stripping unsigned blocks, preserving signed blocks, normalizing signature variants, dropping empty messages, reference identity) - Adds transcript policy tests verifying `normalizeAntigravityThinkingBlocks` is enabled only for Antigravity Claude and not Gemini-via-Antigravity or direct Anthropic API <h3>Confidence Score: 4/5</h3> - This PR is safe to merge — it's a targeted fix for a specific runtime error with good test coverage and minimal risk to non-Antigravity code paths. - Score of 4 reflects a well-scoped fix with comprehensive tests and clear documentation. The only caveat is the reliance on an undocumented `transformContext` hook via type casting, but this is mitigated by the runtime guard and clear comments explaining the trade-off. The change is gated behind `normalizeAntigravityThinkingBlocks` so non-Antigravity providers are completely unaffected. - `src/agents/pi-embedded-runner/run/attempt.ts` — the `transformContext` hook assignment relies on an undocumented upstream API; worth monitoring on pi-agent-core upgrades. <sub>Last reviewed commit: a3a1680</sub> <!-- greptile_other_comments_section --> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) - Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13)) <!-- /greptile_comment -->

Most Similar PRs