From 1cfe409a09f3836b39bfbc4a9b3f94f16892f0a2 Mon Sep 17 00:00:00 2001 From: Muhammed Mukhthar CM Date: Fri, 9 Jan 2026 09:07:05 +0000 Subject: [PATCH 1/3] fix: filter empty error messages to prevent session corruption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When 429/500 errors occur during tool execution, empty assistant messages with stopReason='error' and content=[] get persisted to the session file. These break the tool_use -> tool_result chain that Claude/Gemini require: - Claude expects every tool_use block to have a matching tool_result - Empty error messages inserted mid-sequence violate this invariant - Results in: 'tool_use ids were found without tool_result blocks' This patch filters out empty error messages when building session context, allowing sessions to recover gracefully from transient API errors. Evidence from production: - 113 of 170 sessions had empty error messages - Session 30764430 demonstrated recovery: 429 at 14:30:11 IST, resumed successfully at 14:30:22, completed at 14:30:34 Sorry Peter, one more patch! 🙈 --- package.json | 3 ++- patches/@mariozechner__pi-coding-agent.patch | 20 ++++++++++++++++++++ pnpm-lock.yaml | 7 +++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 3f8e729fe..04283a3a7 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,8 @@ "@sinclair/typebox": "0.34.47" }, "patchedDependencies": { - "@mariozechner/pi-agent-core": "patches/@mariozechner__pi-agent-core.patch" + "@mariozechner/pi-agent-core": "patches/@mariozechner__pi-agent-core.patch", + "@mariozechner/pi-coding-agent": "patches/@mariozechner__pi-coding-agent.patch" } }, "vitest": { diff --git a/patches/@mariozechner__pi-coding-agent.patch b/patches/@mariozechner__pi-coding-agent.patch index 08270770e..ba46e77fa 100644 --- a/patches/@mariozechner__pi-coding-agent.patch +++ b/patches/@mariozechner__pi-coding-agent.patch @@ -26,3 +26,23 @@ index 0000000..1111111 100644 } /** Result from createAgentSession */ export interface CreateAgentSessionResult { +diff --git a/dist/core/session-manager.js b/dist/core/session-manager.js +index b2aba5280d002253b0938b75aedbb9e6e6c4dcf8..67464efff535dbd7a8e6ed825aab2b305ca2aee2 100644 +--- a/dist/core/session-manager.js ++++ b/dist/core/session-manager.js +@@ -161,6 +161,15 @@ export function buildSessionContext(entries, leafId, byId) { + const messages = []; + const appendMessage = (entry) => { + if (entry.type === "message") { ++ // PATCH: Filter out empty error assistant messages to prevent session corruption ++ // When 429/500 errors occur during tool execution, empty error messages get persisted ++ // to the session file. These break the tool_use -> tool_result chain for Claude/Gemini. ++ const msg = entry.message; ++ if (msg.role === "assistant" && ++ msg.stopReason === "error" && ++ (!msg.content || msg.content.length === 0)) { ++ return; // Skip empty error messages ++ } + messages.push(entry.message); + } + else if (entry.type === "custom_message") { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c8ac64885..e6852d628 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ patchedDependencies: '@mariozechner/pi-agent-core': hash: 01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4 path: patches/@mariozechner__pi-agent-core.patch + '@mariozechner/pi-coding-agent': + hash: 58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e + path: patches/@mariozechner__pi-coding-agent.patch importers: @@ -39,7 +42,7 @@ importers: version: 0.41.0(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-coding-agent': specifier: ^0.41.0 - version: 0.41.0(ws@8.19.0)(zod@4.3.5) + version: 0.41.0(patch_hash=58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-tui': specifier: ^0.41.0 version: 0.41.0 @@ -3807,7 +3810,7 @@ snapshots: - ws - zod - '@mariozechner/pi-coding-agent@0.41.0(ws@8.19.0)(zod@4.3.5)': + '@mariozechner/pi-coding-agent@0.41.0(patch_hash=58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e)(ws@8.19.0)(zod@4.3.5)': dependencies: '@mariozechner/clipboard': 0.3.0 '@mariozechner/pi-agent-core': 0.41.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) From d0450bb42578d02398372c9d00523a2315a49bbf Mon Sep 17 00:00:00 2001 From: Muhammed Mukhthar CM Date: Fri, 9 Jan 2026 15:51:19 +0000 Subject: [PATCH 2/3] fix(antigravity): add fail-fast on 429 rate limit When Antigravity returns 429, throw immediately instead of waiting for the server-provided retry delay (which can be 10+ minutes). This lets clawdbot quickly rotate to another account. This patch was previously in PR #454 but was accidentally removed in 0dbb569 when bumping to pi-ai 0.40.0. The upstream release did NOT include this fix. Context: Antigravity rate limits cause pi-ai to sleep for the full retry delay inside the request, blocking the thread. Clawdbot's timeout would eventually fire, but waiting 10+ minutes is unacceptable UX. Bundled with the empty error message filter since both handle 429 recovery. --- package.json | 4 +++- patches/@mariozechner__pi-ai.patch | 18 ++++++++++++++++++ pnpm-lock.yaml | 11 +++++++---- 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 patches/@mariozechner__pi-ai.patch diff --git a/package.json b/package.json index 04283a3a7..593b0d2da 100644 --- a/package.json +++ b/package.json @@ -171,7 +171,8 @@ }, "patchedDependencies": { "@mariozechner/pi-agent-core": "patches/@mariozechner__pi-agent-core.patch", - "@mariozechner/pi-coding-agent": "patches/@mariozechner__pi-coding-agent.patch" + "@mariozechner/pi-coding-agent": "patches/@mariozechner__pi-coding-agent.patch", + "@mariozechner/pi-ai": "patches/@mariozechner__pi-ai.patch" } }, "vitest": { @@ -209,6 +210,7 @@ "patchedDependencies": { "@mariozechner/pi-agent-core": "patches/@mariozechner__pi-agent-core.patch", "@mariozechner/pi-coding-agent": "patches/@mariozechner__pi-coding-agent.patch", + "@mariozechner/pi-ai": "patches/@mariozechner__pi-ai.patch", "qrcode-terminal": "patches/qrcode-terminal.patch", "playwright-core@1.57.0": "patches/playwright-core@1.57.0.patch" } diff --git a/patches/@mariozechner__pi-ai.patch b/patches/@mariozechner__pi-ai.patch new file mode 100644 index 000000000..92a7b9087 --- /dev/null +++ b/patches/@mariozechner__pi-ai.patch @@ -0,0 +1,18 @@ +diff --git a/dist/providers/google-gemini-cli.js b/dist/providers/google-gemini-cli.js +index 0000000..1111111 100644 +--- a/dist/providers/google-gemini-cli.js ++++ b/dist/providers/google-gemini-cli.js +@@ -248,6 +248,13 @@ async function* streamGeminiCli(model, context, credentials, options) { + break; // Success, exit retry loop + } + const errorText = await response.text(); ++ // PATCH: Fail immediately on 429 to let caller rotate accounts ++ // Antigravity rate limits can have very long retry delays (10+ minutes). ++ // Instead of waiting, throw immediately so clawdbot can rotate to another account. ++ if (response.status === 429) { ++ console.log(`[pi-ai] 429 rate limit - failing fast to rotate account`); ++ throw new Error(`Cloud Code Assist API error (${response.status}): ${errorText}`); ++ } + // Check if retryable + if (attempt < MAX_RETRIES && isRetryableError(response.status, errorText)) { + // Use server-provided delay or exponential backoff diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e6852d628..361e2b677 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ patchedDependencies: '@mariozechner/pi-agent-core': hash: 01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4 path: patches/@mariozechner__pi-agent-core.patch + '@mariozechner/pi-ai': + hash: a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811 + path: patches/@mariozechner__pi-ai.patch '@mariozechner/pi-coding-agent': hash: 58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e path: patches/@mariozechner__pi-coding-agent.patch @@ -39,7 +42,7 @@ importers: version: 0.41.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-ai': specifier: ^0.41.0 - version: 0.41.0(ws@8.19.0)(zod@4.3.5) + version: 0.41.0(patch_hash=a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-coding-agent': specifier: ^0.41.0 version: 0.41.0(patch_hash=58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e)(ws@8.19.0)(zod@4.3.5) @@ -3780,7 +3783,7 @@ snapshots: '@mariozechner/pi-agent-core@0.41.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5)': dependencies: - '@mariozechner/pi-ai': 0.41.0(ws@8.19.0)(zod@4.3.5) + '@mariozechner/pi-ai': 0.41.0(patch_hash=a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-tui': 0.41.0 transitivePeerDependencies: - '@modelcontextprotocol/sdk' @@ -3790,7 +3793,7 @@ snapshots: - ws - zod - '@mariozechner/pi-ai@0.41.0(ws@8.19.0)(zod@4.3.5)': + '@mariozechner/pi-ai@0.41.0(patch_hash=a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811)(ws@8.19.0)(zod@4.3.5)': dependencies: '@anthropic-ai/sdk': 0.71.2(zod@4.3.5) '@google/genai': 1.34.0 @@ -3814,7 +3817,7 @@ snapshots: dependencies: '@mariozechner/clipboard': 0.3.0 '@mariozechner/pi-agent-core': 0.41.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) - '@mariozechner/pi-ai': 0.41.0(ws@8.19.0)(zod@4.3.5) + '@mariozechner/pi-ai': 0.41.0(patch_hash=a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-tui': 0.41.0 chalk: 5.6.2 cli-highlight: 2.1.11 From 6156402c1ac5a52a1d30681982a9053e32904cd7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 9 Jan 2026 18:13:47 +0100 Subject: [PATCH 3/3] fix: scope 429 fast-fail to antigravity (#561) (thanks @mukhtharcm) --- CHANGELOG.md | 1 + package.json | 2 +- patches/@mariozechner__pi-ai.patch | 7 +++---- pnpm-lock.yaml | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 723771cf6..9c201c0a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - WhatsApp: route queued replies to the original sender instead of the bot's own number. (#534) — thanks @mcinteerj - Models: add OAuth expiry checks in doctor, expanded `models status` auth output (missing auth + `--check` exit codes). (#538) — thanks @latitudeki5223 - Deps: bump Pi to 0.40.0 and drop pi-ai patch (upstream 429 fix). (#543) — thanks @mcinteerj +- Agent: skip empty error assistant messages when rebuilding session context to avoid tool-chain corruption. (#561) — thanks @mukhtharcm - Security: per-agent mention patterns and group elevated directives now require explicit mention to avoid cross-agent toggles. - Config: support inline env vars in config (`env.*` / `env.vars`) and document env precedence. - Agent: enable adaptive context pruning by default for tool-result trimming. diff --git a/package.json b/package.json index 593b0d2da..671bd5228 100644 --- a/package.json +++ b/package.json @@ -210,7 +210,7 @@ "patchedDependencies": { "@mariozechner/pi-agent-core": "patches/@mariozechner__pi-agent-core.patch", "@mariozechner/pi-coding-agent": "patches/@mariozechner__pi-coding-agent.patch", - "@mariozechner/pi-ai": "patches/@mariozechner__pi-ai.patch", + "@mariozechner/pi-ai": "patches/@mariozechner__pi-ai.patch", "qrcode-terminal": "patches/qrcode-terminal.patch", "playwright-core@1.57.0": "patches/playwright-core@1.57.0.patch" } diff --git a/patches/@mariozechner__pi-ai.patch b/patches/@mariozechner__pi-ai.patch index 92a7b9087..65b206c74 100644 --- a/patches/@mariozechner__pi-ai.patch +++ b/patches/@mariozechner__pi-ai.patch @@ -2,14 +2,13 @@ diff --git a/dist/providers/google-gemini-cli.js b/dist/providers/google-gemini- index 0000000..1111111 100644 --- a/dist/providers/google-gemini-cli.js +++ b/dist/providers/google-gemini-cli.js -@@ -248,6 +248,13 @@ async function* streamGeminiCli(model, context, credentials, options) { +@@ -248,6 +248,12 @@ async function* streamGeminiCli(model, context, credentials, options) { break; // Success, exit retry loop } const errorText = await response.text(); -+ // PATCH: Fail immediately on 429 to let caller rotate accounts ++ // PATCH: Fail immediately on 429 for Antigravity to let caller rotate accounts. + // Antigravity rate limits can have very long retry delays (10+ minutes). -+ // Instead of waiting, throw immediately so clawdbot can rotate to another account. -+ if (response.status === 429) { ++ if (isAntigravity && response.status === 429) { + console.log(`[pi-ai] 429 rate limit - failing fast to rotate account`); + throw new Error(`Cloud Code Assist API error (${response.status}): ${errorText}`); + } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 361e2b677..ff1f71889 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,7 +12,7 @@ patchedDependencies: hash: 01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4 path: patches/@mariozechner__pi-agent-core.patch '@mariozechner/pi-ai': - hash: a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811 + hash: 3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c path: patches/@mariozechner__pi-ai.patch '@mariozechner/pi-coding-agent': hash: 58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e @@ -42,7 +42,7 @@ importers: version: 0.41.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-ai': specifier: ^0.41.0 - version: 0.41.0(patch_hash=a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811)(ws@8.19.0)(zod@4.3.5) + version: 0.41.0(patch_hash=3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-coding-agent': specifier: ^0.41.0 version: 0.41.0(patch_hash=58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e)(ws@8.19.0)(zod@4.3.5) @@ -3783,7 +3783,7 @@ snapshots: '@mariozechner/pi-agent-core@0.41.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5)': dependencies: - '@mariozechner/pi-ai': 0.41.0(patch_hash=a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811)(ws@8.19.0)(zod@4.3.5) + '@mariozechner/pi-ai': 0.41.0(patch_hash=3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-tui': 0.41.0 transitivePeerDependencies: - '@modelcontextprotocol/sdk' @@ -3793,7 +3793,7 @@ snapshots: - ws - zod - '@mariozechner/pi-ai@0.41.0(patch_hash=a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811)(ws@8.19.0)(zod@4.3.5)': + '@mariozechner/pi-ai@0.41.0(patch_hash=3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c)(ws@8.19.0)(zod@4.3.5)': dependencies: '@anthropic-ai/sdk': 0.71.2(zod@4.3.5) '@google/genai': 1.34.0 @@ -3817,7 +3817,7 @@ snapshots: dependencies: '@mariozechner/clipboard': 0.3.0 '@mariozechner/pi-agent-core': 0.41.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) - '@mariozechner/pi-ai': 0.41.0(patch_hash=a64d167efc76cfc0504fa6ce9e9643276ee41020f9c82e7ed0c763c4af290811)(ws@8.19.0)(zod@4.3.5) + '@mariozechner/pi-ai': 0.41.0(patch_hash=3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-tui': 0.41.0 chalk: 5.6.2 cli-highlight: 2.1.11