feat: wire-level stripHistoricalImages for historical image payloads - #215
Conversation
Image bytes ride along verbatim on every request even after compression folds the surrounding text (codecs move images out of CoreMessage.text into sidecars), so a host that wants to shed the payload of aged-out turns had no shared primitive. Add one to the wire layer so "which field carries an image" lives in a single place across hosts. - src/wire/strip-images.ts: stripHistoricalImages(body, protocol, keepRecent) drops image parts from every message older than the most recent keepRecent across anthropic/openai/responses. Image-only content collapses to an "[image]" text placeholder (input_text for responses) so message count/role stay stable; mixed content keeps its non-image parts; returns the input reference unchanged when nothing changed. Detection is type-based, so remote-URL images are dropped too (not just data URLs). - Exposed through the acp-kernel/wire barrel (src/wire/index.ts). - tests/wire-strip-images.test.ts: 10 cases covering all three protocols, recent-N preservation, no-op identity, remote-URL stripping, field preservation. Pre-flight: typecheck clean, full suite 592 pass, build ok.
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)In your adapter project: npm install acp-kernel@pr-215Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf acp-kernel-pr215.tgz
npm install ./packageThis comment is automatically updated on each push. |
[bot] 🏷 Review of #215 — reviewer 1/2; a second independent agent review also completed and both converge. Pre-flight (re-run on branch Verdict: Approve-with-nitsNo correctness defects in any shape the codecs model. Mechanism/policy split and placement are right. One documentation nit worth fixing before merge. Correctness — clean. Per-protocol part types + placeholder types match the codecs: openai Architecture fit — good. Pure fn, zero imports/deps, no Top nit (fix before merge): the header comment overstates id stability
Low severity in practice (needs repeated near-identical image-only turns; distinct real images rarely collide), but the comment will mislead future maintainers into believing the impact is trivially bounded. Suggest rewriting lines 9-10 to state: anthropic/mixed are id-stable; image-only openai/responses birth-or-shift; cluster renumbering can exceed one shift per message; the collision hazard is the pre-existing documented one. Secondary nits (optional, non-blocking — fine as follow-ups)
Recommendation: the implementation is correct and correctly placed — approve the code. Fix the header comment (top nit, doc-only, ~5 min) before merge, since acp-kernel treats comments as load-bearing; ship the rest as a small follow-up. Merge stays human-only per AGENTS.md — I won't merge. |
Adds a protocol-aware primitive to the wire layer for dropping historical image payloads from a request body before the wire rebuild.
What
stripHistoricalImages(body, protocol, keepRecent)removes image parts from every message older than the most recentkeepRecent, across all three codecs (anthropic/openai/responses). An image-only message collapses to an"[image]"text placeholder (input_textfor Responses) so message count and role ordering stay stable; mixed content keeps its non-image parts; the input reference is returned unchanged when nothing changed. Detection is type-based, so remote-URL images are dropped too — not just data URLs.Why
Image bytes ride along verbatim on every request even after compression folds the surrounding text — the codecs move images out of
CoreMessage.textinto sidecars, so the raw payload is forwarded regardless of what got summarized. A host wanting to shed the payload of aged-out turns previously had no shared place to do it. Putting this in the wire layer means "which field carries an image per protocol" has one home, reusable by every host (proxy + in-process adapters) instead of each re-implementing the traversal.Design split: this is the mechanism only. Whether to strip, how many recent messages to keep, and any overflow interplay remain host policy.
keepRecentis a required parameter; no default is baked in here.Cross-reference
Requested by ranxianglei/billion-context#617 (opt-in strip of historical image payloads during compression). billion-context will call this export once it lands and ships a version; its own PR (#618) currently carries an equivalent in-repo implementation and will be re-pointed at this export after the kernel release.
Pre-flight
npm run typecheck— cleannpm test— 592 pass, 0 failnpm run build— ok (dist/wire/index.js+.d.tsemitted; barrel re-export confirmed reachable via the/wiresubpath)Ready for review (≥2 agents) ahead of merge. No version bump on this branch — the release flow handles that separately.