diff --git a/CHANGELOG.md b/CHANGELOG.md index aa6c85844..35f22385a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -175,6 +175,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Agents/Antigravity: preserve unsigned Claude thinking blocks as plain text instead of dropping them during transcript sanitization, preventing reasoning context loss while avoiding `thinking.signature` request rejections. - Agents/Google: clean tool JSON Schemas for `google-antigravity` the same as `google-gemini-cli` before Cloud Code Assist requests, preventing Claude tool calls from failing with `patternProperties` 400 errors. (#19860) - Tests/Telegram: add regression coverage for command-menu sync that asserts all `setMyCommands` entries are Telegram-safe and hyphen-normalized across native/custom/plugin command sources. (#19703) Thanks @obviyus. - Agents/Image: collapse resize diagnostics to one line per image and include visible pixel/byte size details in the log message for faster triage. diff --git a/src/agents/pi-embedded-runner.google-sanitize-thinking.e2e.test.ts b/src/agents/pi-embedded-runner.google-sanitize-thinking.e2e.test.ts index 0e44cf3c3..f716ff32a 100644 --- a/src/agents/pi-embedded-runner.google-sanitize-thinking.e2e.test.ts +++ b/src/agents/pi-embedded-runner.google-sanitize-thinking.e2e.test.ts @@ -91,7 +91,7 @@ describe("sanitizeSessionHistory (google thinking)", () => { expect(assistant.content?.[0]?.thinking).toBe("reasoning"); }); - it("drops unsigned thinking blocks for Antigravity Claude", async () => { + it("converts unsigned thinking blocks to text for Antigravity Claude", async () => { const out = await sanitizeSimpleSession({ modelApi: "google-antigravity", modelId: "anthropic/claude-3.5-sonnet", @@ -99,8 +99,10 @@ describe("sanitizeSessionHistory (google thinking)", () => { content: [{ type: "thinking", thinking: "reasoning" }], }); - const assistant = out.find((msg) => (msg as { role?: string }).role === "assistant"); - expect(assistant).toBeUndefined(); + const assistant = out.find((msg) => (msg as { role?: string }).role === "assistant") as { + content?: Array<{ type?: string; text?: string }>; + }; + expect(assistant.content).toEqual([{ type: "text", text: "reasoning" }]); }); it("maps base64 signatures to thinkingSignature for Antigravity Claude", async () => { diff --git a/src/agents/pi-embedded-runner/google.ts b/src/agents/pi-embedded-runner/google.ts index 7a6a0bf76..9a0263a2d 100644 --- a/src/agents/pi-embedded-runner/google.ts +++ b/src/agents/pi-embedded-runner/google.ts @@ -101,6 +101,12 @@ export function sanitizeAntigravityThinkingBlocks(messages: AgentMessage[]): Age const candidate = rec.thinkingSignature ?? rec.signature ?? rec.thought_signature ?? rec.thoughtSignature; if (!isValidAntigravitySignature(candidate)) { + // Preserve reasoning content as plain text when signatures are invalid/missing. + // Antigravity Claude rejects unsigned thinking blocks, but dropping them loses context. + const thinkingText = (block as { thinking?: unknown }).thinking; + if (typeof thinkingText === "string" && thinkingText.trim()) { + nextContent.push({ type: "text", text: thinkingText } as AssistantContentBlock); + } contentChanged = true; continue; }