Repository navigation
fix(artifact-store): keep recovery hints identical across requests so the prompt cache holds - #90
Merged
trancefornow merged 2 commits intoSep 29, 2026
Conversation
…hints stay stable buildArchiveLocation named every archive `<Date.now()>-<segment>.json`. Adapters re-run reduction over the whole history on every request, so the same tool output got a new `Archive:` path in its recovery hint each time: the text sent to the model changed on every request (prompt-cache miss from the first trimmed result onward), a new archive file was written each time, and tool_payload_trim (which builds the hint's path separately from the write) could name a file other than the one it wrote. When the caller passes `originalText`, the name is now `<segment>-<sha256(sessionId + text)[:16]>.json`: the same content in the same session always maps to the same path. archiveContent already passes the text, so exec_output_truncation, read_state_compaction, eviction and the adapters' own archive calls pick this up unchanged; tool_payload_trim now passes it too. Callers that pass no text keep the timestamped name. Tests: artifact-store A1-A5, reduction T1-T4. A1, A2, A5, T1 and T4 fail with timestamped names; T1 and T2 fail if the trim pass does not pass the text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6it2Si8k8XNGMF8RdyMQz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When an adapter shortens a large tool output, it saves the original to an archive file and adds a recovery hint with an
Archive: <path>line. That file name contained the current time (Date.now()).The adapters re-shorten the whole conversation on every request, so the same tool output got a different
Archive:line each time. Any change there breaks the provider's prompt cache from that point onwards, on every request.This PR names archive files after their content instead of the time. The same output now produces exactly the same text on every request.
What was going wrong
I ran each adapter's real per-request code twice on the same conversation, 10 ms apart:
…/1790620061951-message-2-block-0.jsonvs…/1790620061974-……/1790620208729-input-2-output.jsonvs…/1790620208758-……/1790620175400-proxy-2-output.jsonvs…/1790620175445-…Two side effects of the timestamped name are fixed too:
tool_payload_trimbuilds the hint's path and the path it writes with two separateDate.now()calls. When the clock ticked in between, the hint named a file that doesn't exist. Recovery still worked, because it looks archives up bydataKey, but the path shown to the model was wrong.The fix
artifact-store:buildArchiveLocationtakes an optionaloriginalText.<segment>-<sha256(sessionId + text)[:16]>.json, so the same content in the same session always maps to the same path.reduction:tool_payload_trimnow passes the text when building the hint's path.archiveContent, which passes the text, so they pick this up with no changes.Recovery is unaffected: archives are still found by
dataKey.Tests
artifact-store, new filetests/archive-location-stability.test.ts:reduction, new filetests/archive-path-stability.test.ts:tool_payload_trimoutput is byte-identical across requests.exec_output_truncation.tool_payload_trimchange makes T1 and T2 fail.pnpm build,pnpm typecheckandcheck:boundariespass, and every suite CI runs passes (openclaw, claude-code, codex, host-adapter, history, preset, runtime-core, product-surface, eviction, deepseek-harness, mcp, cli, artifact-store, reduction).Prepared with help from Claude Code; the commit is marked
Co-Authored-By: Claude.