You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
stripHistoricalImages (src/wire/strip-images.ts) only removes image parts at the top level of each message. Images inside tool results are never removed:
In the affected session, historical images were nested in tool results (screenshots, file reads), so enabling stripImages did not remove them and the request body kept growing.
Repro (minimal)
stripHistoricalImages({messages: [{role: "user",content: [{type: "tool_result",tool_use_id: "t1",content: [{type: "image",source: {type: "base64",media_type: "image/png",data: "AAAA"}}]}]},{role: "assistant",content: [{type: "text",text: "ok"}]},]},"anthropic",1)// → { removed: 0 }, the image is still there
Impact
Real pi session (billion-context-pi 0.1.77, Anthropic, 1701 messages, keepRecent: 3): replaying its request body locally through stripHistoricalImages gives 56.5 MB with removed: 0. Anthropic rejected it with 413 request_too_large (~32 MB limit) at only 22% of the token window, and every later request failed the same way.
Since #367, Anthropic tool-result images are protected from folding, so the opt-in strip needs to handle them explicitly.
Suggested fix
Strip images one level down inside tool-result parts (tool_result.content, functionResponse.parts), and walk Responses tool outputs through output instead of content. Emptied containers get the existing [image] placeholder, except Gemini functionResponse.parts, which only accepts media parts, so the key is dropped instead. Within Gemini functionResponse.parts, only explicit image/* MIME types are stripped; documents and parts without a MIME type are retained. These parts are left unchanged when response contains a $ref, to avoid dangling references. Top-level Gemini behaviour is unchanged. I have a PR ready.
Implementation matches your suggested fix point-for-point (one nesting level per dialect; Responses via output; Gemini nested = image/* MIME only with emptied parts key dropped; $ref skip; top-level Gemini unchanged).
Regression audit clean: top-level semantics, same-ref no-op contract, keepRecent cutoff, and tool-pair atomicity all preserved (verified against googleToCore — it never reads functionResponse.parts).
9 new tests have teeth (structure deep-equals, reference-identity pins, real anthropicToCore pairing check). Local on head: typecheck ✅ · 1131/1131 tests ✅ · build ✅.
The only red CI item (build-artifact) is a CI-permission defect affecting external fork PRs, unrelated to this code — filed as #440.
Per repo rules the merge itself is human-side; the PR meets the §7.4 auto-merge gate, so it's ready whenever you are. Follow-up reminder from the PR body: after release, bump the acp-kernel pin in billion-context-pi so the real 1701-message session actually gets the nested strip.
Activity
ranxianglei commentedon Sep 25, 2026
[bot] 🏷 已确认问题属实:
stripHistoricalImages(src/wire/strip-images.ts)确实只处理每条消息的顶层 image part——anthropictool_result.content、Responsesfunction_call_output/custom_tool_call_output的.output、GeminifunctionResponse.parts里的图片全部漏掉。你提到的 PR #437 我已看到,正在做正式 review(代码 + 回归 + 测试有效性),结论稍后贴在这里和 PR 上。ranxianglei commentedon Sep 25, 2026
[bot] 🏷 Conclusion — bug confirmed (reproduced your minimal case on master:
removed: 0, image intact), and the fix is reviewed: PR #437 is mergeable.Full review posted on #437; highlights:
output; Gemini nested =image/*MIME only with emptiedpartskey dropped;$refskip; top-level Gemini unchanged).googleToCore— it never readsfunctionResponse.parts).anthropicToCorepairing check). Local on head: typecheck ✅ · 1131/1131 tests ✅ · build ✅.build-artifact) is a CI-permission defect affecting external fork PRs, unrelated to this code — filed as #440.Per repo rules the merge itself is human-side; the PR meets the §7.4 auto-merge gate, so it's ready whenever you are. Follow-up reminder from the PR body: after release, bump the
acp-kernelpin in billion-context-pi so the real 1701-message session actually gets the nested strip.