Two overstated evidence claims, reworded to the precise fact: - prune-dead-core-spine-surface: runLoop has no importer OUTSIDE the package (its own agent.ts drives the loop with it); the dead surface is the public re-export, not the function. - generic-long-running-tool-runtime census: BashTask.done has no consumer through the public seam, but is production-load-bearing inside dsh-bash-local (disposal awaits it); only the public completion surface is single-consumer. Also fold the reviewer-located doc sites into the removal sets so the implementing PRs need no re-discovery: the llm/pi-ai/compact-basic README rows and the adding-an-llm-adapter cookbook line (prefill/image), the content-block-vocabulary RFC's has-a-home consequence lines (cache/prefill/image), the tools.md paste + type-equiv manifest row + tools README row (callId), and the session-surface RFC's full-rebuild-after-replacement sentence (invalidate).
3.9 KiB
RFC: Drop the image content block until a path can honor it
Status: proposed
Problem
ImageBlock (packages/llm/llm/src/types.ts) has no production producer, and every consumer on every path DROPS it: the deepseek adapter's serializer skips image blocks (a documented MVP limitation), the pi-ai converter skips them as unrepresentable, the ACP codec neither advertises image prompt capability nor forwards image blocks outbound and REJECTS image prompt content inbound, and the compaction estimator charges a flat token constant and renders [image]. An ImageBlock constructed today would silently vanish from the wire — the vocabulary advertises a capability no path honors, which is the silent-data-loss shape AGENTS.md's defensive patterns warn against. The only constructors anywhere are tests pinning the skip/drop/estimate branches.
Proposal
Remove ImageBlock, its ContentBlockMap entry, and the explicit skip/estimate branches in the deepseek serializer, the pi-ai converter, the ACP codec's outbound mapping, and compact-basic — the default arms those switches already carry for plugin-added block types absorb the cases. Update the vocabulary line in architecture.md, the block list in packages/llm/llm/README.md, the pi-ai README's images-not-representable row, the compact-basic README's image-estimation row, the pastes in core.md and llm-streaming.md, and the type-equiv manifest; amend the content-block vocabulary RFC's block list and multimodal-home consequence per implemented/AGENTS.md; drop or retarget the tests that construct image blocks to exercise the removed branches. The ACP codec's inbound rejection of image PROMPT content is unaffected — that guard is about protocol content a client can send regardless of our vocabulary, and it stays.
Why not keep it?
This is the most contested cut in the batch. Multimodal input (screenshots) is a plausible near-term coding-agent feature, and the content-block vocabulary RFC reserved the slot deliberately. Two responses. First, ContentBlockMap is merge-extensible by design: a real multimodal feature reintroduces image in core in the same coordinated change that maps it in the adapters, advertises and renders it in ACP, and prices it in compaction — the producer and its consumers arrive together, which is how the map is meant to grow. Second, the middle option — keep the type but make adapters throw UNSUPPORTED instead of silently dropping — converts this into exactly the shape the request-knobs RFC argues against: surface whose only implementation is rejection. Absence (a compile error at the would-be producer) is strictly clearer than either silent loss or universal throw.
If review lands on keeping the slot, the fallback this RFC records is: keep ImageBlock but replace every silent skip with a loud rejection, and document that policy in the vocabulary — the current silent drop is the one state with no defender.
Acceptance criteria
- No
ImageBlock/ harnesstype: 'image'block construction outside this RFC; the codec's inbound ACP-image rejection still passes its tests. - Adapter/codec/compaction switches handle the case through their unknown-block default arms (pinned by the existing plugin-added-block tests where present).
- Doc pastes, the manifest, and the architecture vocabulary list updated;
pnpm run doc-syncgreen.
Risks
Re-adding a core vocabulary type later touches several packages at once — but that coordinated change is the shape a real multimodal feature needs anyway (adapter mapping, ACP advertisement, compaction pricing), and none of it exists today to preserve.