Skip to content

Cache-stable requests, step 3: frozen run context - #134

Merged
ayman3000 merged 7 commits into
mainfrom
cache-stable-step3
Oct 9, 2026
Merged

ayman3000 merged 7 commits into
mainfrom
cache-stable-step3

Conversation

@ayman3000

Copy link
Copy Markdown
Owner

Step 3 of Naseem's cache-stable requests design.

  • AgentConfig.freezeRunContext (default false): the memory block, the app's per-run context block and the skill index are built on a run's first request and kept byte-for-byte for every later run. FrozenRunContext (Codable) can be read and restored, so an app can persist it with a chat and reuse it after a relaunch; a restored context from a different base prompt or tool set is rejected by digest and rebuilt. invalidateRunContext() marks it stale; a generation counter makes an invalidation that lands mid-build win.
  • Sub-agents always read current memory and never freeze.
  • Deterministic artifact ids for evicted tool results (derived from the call id and output) and idempotent saves in both built-in stores, so a relaunch neither rewrites receipts nor duplicates artifacts.
  • Regression test: two runs with a fact filed between them, through an eviction batch and a simulated relaunch, byte-identical prefixes on the real OpenAI wire (streaming and not); the filed fact appears only after invalidation. One known issue kept on purpose: the evicted set is rebuilt after a relaunch (accepted: one miss per relaunch).

Requires LLMProviderKit 0.1.0-alpha.42 (Anthropic's fourth cache breakpoint on the previous turn).

Tests: 659 pass (1 known issue), XCTest 182 (7 skipped).

🤖 Generated with Claude Code

ayman3000 and others added 7 commits October 9, 2026 11:12
…lt once

Opt-in (default off). The system prompt's dynamic parts are built at the
first run and kept as a Codable FrozenRunContext, reused while the engine's
own base (configured prompt, tool line, group index) has the same digest.
invalidateRunContext() and a compaction clear it; restoreRunContext(_:)
installs a saved one. The prompt is assembled exactly as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Review found that invalidateRunContext() during runContextParts' awaits
(memory store, run-context provider, skill index) was silently overwritten
by the stale build. Add a generation counter, bumped by invalidate,
restore and compaction, captured before the first await; the build only
freezes its result if the generation is unchanged, otherwise the stale
parts still serve the in-flight run but the next run rebuilds.

Also make restoreRunContext a no-op when freezeRunContext is off (nothing
ever reads the stored value in that mode), and add tests pinning the
FrozenRunContext Codable wire keys and the load_tools-mid-chat invariant.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… a relaunch

Two frozen runs with a fact filed between them and one ContextSift batch,
then a relaunch from the JSON-saved FrozenRunContext, on the OpenAI wire
(streaming and not): one system text, one batch, identical tool
definitions; the fact reaches the prompt only after invalidateRunContext().

Known issue pinned with withKnownIssue: after a relaunch the messages are
append-only only up to the first evicted step. Receipts are rebuilt with
new random artifact ids and the evicted set is recomputed (one more step).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ing them again

An artifact saved for a tool call now gets its id from the call id and the
output (artifact- + 12 hex of an unseeded FNV-1a digest), and both built-in
stores return the existing artifact for that id instead of storing it again.
After a relaunch, ContextSift's empty receipt cache no longer writes a
duplicate artifact per evicted output to the FileArtifactStore, and every
receipt is the same bytes as before. The output is part of the key so a
provider that reuses call ids across runs never gets a stale artifact; with
no call id the id stays random.

The relaunch regression test now shares a FileArtifactStore folder and checks
receipts and the prefix through every receipt; its known issue is narrowed to
the one remaining cause, the evicted set rebuilt from scratch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…int)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rth cache breakpoint (LLMProviderKit alpha.42)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ayman3000
ayman3000 merged commit b92ab52 into main Oct 9, 2026
1 check passed
@ayman3000
ayman3000 deleted the cache-stable-step3 branch October 9, 2026 08:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant