Claude Code marks its system prompt with cache_control
{type:"ephemeral", ttl:"1h", scope:"global"}. When pxpipe relocates
that marker onto a rendered image, the new position is never a valid
global prefix (slab pages 1..N-1 and other injected blocks carry no
marker), so Anthropic rejects the whole request with 400
invalid_request_error — making pxpipe unusable in front of Claude Code.
Demote relocated markers to plain ephemeral by stripping the scope key
(type/ttl preserved) at all four relocation sites: the slab->history
anchor move, the static-system marker, and the reminder / tool_result
image renders. Markers without scope pass through untouched, so
byte-stability of existing traffic is unaffected. pxpipe still never
adds markers of its own.
Closes#95
Collapse old conversation history into rendered PNG sections so the model
reads a compact image instead of re-billed text, while preserving prompt
caching and tool-call behavior. Measures real vs compressed token/cost.
Core:
- GPT history collapse (openai-history.ts): append-only, o200k token-length
sectioning. Sections seal only at a tool-closed boundary (open call-id set
empty), so a function_call and its function_call_output never split across
the collapse cut. Fixes the OpenAI 400 "No tool call found for function
call output with call_id ..." that hit long Responses-API sessions.
- Anthropic cache contract (history.ts): append-only per-chunk rendering;
cache_control markers are preserved/moved, never added; chunk boundaries
align with caller marker seams for byte-stable prefix caching.
- GPT image budget (openai.ts): detail:'original' for gpt-5.x, flagship
vision-multiplier fix, patch cap; schema-strip preserves real descriptions.
- Savings accounting (openai-savings.ts): cached_tokens + vision-token basis.
Model scope (applicability.ts):
- Default imaged scope = claude-fable-5 + gpt-5.6.
- gpt-5.5 and claude-opus-4-8 stay opt-in: same pipeline, but they degrade
reading dense imaged history (gist drift), so silently imaging them by
default is wrong. Promotion is gated on an OCR/recall threshold.
Dashboard: GPT + Anthropic rendering, per-family model toggles, persisted
metrics, thumbnail-expired session UI, reflow/newline handling.
Tests: cache-alignment (GPT + Anthropic), history sectioning + tool-boundary
invariants, savings, dashboard, sessions/restart-restore. 452 passing.