Skip to content

conversation cache: a shared prefix is copied out of a parked conversation instead of taking it over, so the parked one keeps its history - #1164

Closed
BlueKingMuch wants to merge 4 commits into
Niko1221:mainfrom
BlueKingMuch:cache-borrow
Closed

BlueKingMuch wants to merge 4 commits into
Niko1221:mainfrom
BlueKingMuch:cache-borrow

Conversation

@BlueKingMuch

Copy link
Copy Markdown
Contributor

Builds on #1163 (the first commit); this PR is the second.

An agent harness that runs subagents sends several conversations that start with the same system prompt and tool list. The conversation cache checkpoints that prefix, and when a new conversation finds it only inside a parked one (because another conversation is in the session at that moment), it moves that whole parked conversation into the session and overwrites it after the checkpoint. The parked conversation is gone, and its next turn reads its history again.

With this, the new conversation borrows: only the K/V up to the checkpoint and the checkpoint itself come over (conversation_snapshot_restore_prefix), and the parked conversation stays where it is. A match on a parked conversation's live state or its newest checkpoint is that conversation going on, and it is moved into the session as before (ConversationCache::borrows). While the outgoing conversation is parked, the one borrowed from is pinned, so parking cannot evict it; if the outgoing conversation fits only in its room, it is moved in as before and the outgoing one keeps its place. The engine log says "borrowed".

#1090 (prefix snapshots on disk) changes the same decision: a saved prefix wins over a parked conversation that matches no further, so that conversation is not taken out. With this PR it is not taken out either, and nothing is read from disk.

Measured

Same setup as #1163, also on 0.1.40.1 against v0.1.40.1 (a layer split never borrows - its stages restore whole images only - a borrow clears a batch slot as a source, as a taken conversation does, and without --mtp it takes no draft K/V, as parking saves none): RTX 4080 SUPER 32 GB, Ryzen 7 5800X3D, 96 GB, Windows 11, IQ3_S, 262K context, --conversation-cache-mib 2816 --conversation-cache-slots 3, a fixed expert placement (--adapt-every 1000000 --expert-cache 8031), greedy, 64-token answers. A main agent P (30,000 tokens) and two subagents S1 and S2 with the same system prompt (15,000 each) take turns for two rounds, every return +2,300 tokens: P1 S1 P2 S2 S1b S2b P3 S1c S2c P4. Prompt tokens read, time to first token:

v0.1.40.1 #1163 #1163 + this PR
S2, new subagent while P is in the session moves S1 in, S1 is overwritten the same borrows from S1 (32 ms), S1 stays parked
S1b, subagent 1 goes on 14,878, 4.8 s 14,878, 4.8 s 2,369, 2.9 s
S2c, subagent 2 in the second round 17,242, 5.4 s 2,369, 2.9 s 2,369, 2.9 s
all ten requests 116,147 read, 49.9 s 86,332 read, 44.6 s 73,892 read, 42.9 s
evicted 3 1 2

With both, every return resumes its conversation (2.8 to 3.0 s). The second eviction is S1 at P4, by 5 MB: three conversations of 0.8 to 1.1 GiB and the one being switched in fill 2816 MiB.

Why it builds on #1163: borrowing keeps one more conversation in the cache, and with the reserve unbounded that pushed the main agent out - this PR alone on v0.1.40.1, same run: P3 read 34,728 tokens again (12.1 s instead of 2.9 s), all ten requests 54.5 s instead of 42.9 s.

The answers: with the fixed placement all ten equal #1163 alone (S2 borrowed gives the same tokens as S2 moved in the old way), and the main agent's four answers equal a run without subagents.

Tests: conversation_cache_test (which matches borrow and which do not, pinning against slot and byte eviction and the drop of superseded copies, the refusal when the outgoing conversation fits only in the donor's room) and conversation_file_test on Windows; conversation_snapshot_test (on the GPU: the borrowed prefix and its checkpoint give the same bytes as restoring the whole conversation and rewinding to the checkpoint, and the parked image stays unchanged) on Windows with CUDA. The same run without --mtp borrows the same way.

BlueKingMuch and others added 2 commits October 6, 2026 12:36
…th of each K/V buffer in reserve (was up to 16 MiB per buffer, 0.4-0.5 GB per conversation)

A conversation that was restored and is parked again keeps its unchanged K/V
pages and appends the new ones (92a3d5f). The appended segment reserved room
for later turns, growing geometrically up to 16 MiB - per buffer, and a parked
image has one per K/V layer and part (k, v, their scales, the indexer rows, the
draft layer). With Qwen3.8-Flash-Next (IQ3_S, int8 K/V) a 32K-token main agent
parked again took 1.49 GB instead of 0.97 GB, a 17K-token subagent 1.16 GB
instead of 0.74 GB. The cache counts that capacity against its budget, so with
2816 MiB the reserve decides which conversations are evicted.

The reserve is now at most an eighth of what the buffer held before the append
(at least 64 KiB, and at most 16 MiB as before). Small turns still fill the
reserve instead of adding a transfer each: the 4096-append test keeps its
segment bound, and 256 turns of 1 MiB onto a 16 MiB buffer take 28 segments
(17 before).

The docs said parking falls back to a full capture when the reserve would evict
another conversation; that check went in 6cd29d9. With the reserve bounded the
two captures differ by at most an eighth of the K/V, and the docs now say what
the reserve is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKZxC8sUotEzdWXws2FTUC
…ne borrows it, the parked conversation stays (sibling subagents no longer cost each other their history)

A request whose best match was a checkpoint inside a parked conversation took that whole conversation into the
session and overwrote everything after the checkpoint. With subagents that share a system prompt and tool list, a
new sibling arriving while another conversation was live (the parent, or a subagent of another kind) therefore
destroyed a running sibling's cache: its next turn read its history again from the end of the system prompt.

Now such a checkpoint is borrowed: the K/V of the first tokens (main layers and draft layer) comes from the parked
image (conversation_snapshot_restore_prefix), the checkpoint is copied and mounted as for any checkpoint resume, and
the parked conversation keeps its place. Parking the outgoing conversation pins it; when the outgoing image fits
only in its room, the outgoing one keeps that room and the parked one is taken whole as before. A match on a parked
conversation's live state or its deepest checkpoint (the same conversation going on, its last reply re-rendered) is
taken as before.

conversation_cache_test: the borrow/take decision, pinning against slot and byte eviction and Niko1221#342's superseded
drop, the refusal before evicting anything. conversation_snapshot_test: a borrowed prefix gives the same K/V bytes
and running state as a whole restore rewound to that checkpoint and leaves the image unchanged (needs a GPU).

On 0.1.40.1: the draft layer is a pointer in the snapshot functions (a layer split's stages have none, and without
--mtp no image has one); the borrowed prefix takes it the same way. A layer split never borrows (its stages restore
whole images only), a borrow clears a batch slot as a source like a taken conversation does, and the outgoing
conversation is parked for a batch slot's restore as before. With --kv-grow the K/V has grown to this prompt before
the borrow, and the borrowed prefix is never longer than the prompt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKZxC8sUotEzdWXws2FTUC
fragtion added a commit to fragtion/StrataPool that referenced this pull request Oct 6, 2026
…upstream PR Niko1221#1164), also in a pool

From upstream PR Niko1221#1164 (BlueKingMuch, open): a request whose best match is a checkpoint inside another
parked conversation borrows its K/V up to there and a copy of the checkpoint; the parked conversation
stays (sibling subagents no longer cost each other their history).
POOL: CONV_BORROW (id, n) - every worker takes the same prefix from its part of the image, which
stays; the mounted checkpoint's CKPT_RESTORE gives them its running state.  A worker that cannot
borrow makes the prompt read from the start.  pool_link_test covers it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157fjixQD2nRxvCvtXq66DD
fragtion added a commit to fragtion/StrataPool that referenced this pull request Oct 7, 2026
Upstream now carries our picks of Niko1221#851 (AVX2 Q8_K quantizer), Niko1221#789 (expert uploads beside the shared expert),
Niko1221#813 (--ple-io ram on Windows), Niko1221#1185 (window graphs free older batch layouts), Niko1221#1201/Niko1221#1118 (doorbell per
window), Niko1221#1101/Niko1221#1057 (Stager sleep: now the default on Linux only, STRATA_STAGER_SLEEP=1 forces it) and Niko1221#1063
(the shared draft head's type); their versions are kept.

Conflicts resolved:
- prefill: upstream's own CPU share (STRATA_PREFILL_CPU_SHARE, opt-in) sits beside CPU assist.  Its setter is
  set_cpu_share_pool; when it is asked for, it replaces CPU assist for the chunks it covers, otherwise CPU
  assist runs as before (on by default).  The debug NaN check skips both kinds of CPU rows.
- conversation cache: a pool-borrowed entry and upstream's pinned shared prefix (pin=N) are both kept from
  eviction; the borrow (Niko1221#1164) and pin=N's sibling path do not park at once.
- generate: pool batch groups launch only up to their last active slot (Niko1221#1249's G.S), also on the workers;
  --adapt-async's poll between verdicts runs beside the pool's verified-path-first loop.
- server: upstream's chunked bodies (Niko1221#893) and the pool's read-once body are one helper; do_POST's BadBody
  wrapper around the pool's routed-request check.
- native dense: the pool's served_bytes beside upstream's weight_bytes_for (Niko1221#1238).
- expert source: the commit-limit retry (Niko1221#1064) beside upstream's paced page-locking (Niko1221#1250).
- setup: no ready-made engine (StrataPool compiles its own); REPO names StrataPool for the SHA-256 lookup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157fjixQD2nRxvCvtXq66DD
@midhatn

midhatn commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Tested a local port of this + #1163 onto v0.1.40.2 on Windows, Ryzen 9 7940HS / RTX 4070 Laptop 8 GB / 64 GB RAM, IQ3_S, 64K context. Both builds used the same toolchain, 36 GiB resident expert budget, two conversation slots and a 2 GiB cache.

Ten turns switched between a parent and two workers with deliberately different inventory answers (422 vs 1422). Every answer was correct:

Across the ten turns Unchanged source build #1163 + #1164 port
Newly read prompt tokens 29,176 21,323
Prompt processing 103.77 s 79.09 s
Total request wall time 137.28 s 116.49 s
Generated tokens 675 731

The final return to worker B read 8,082 tokens on the control versus 28 on the patched build. This is one complete sequence per build, with sampled high-reasoning output; the generated histories differ, so the 15% wall-time reduction is workload evidence rather than a deterministic speed guarantee. Separate pinned-document queries also passed.

One integration detail for the rebase: v0.1.40.2 now has permanently pinned prefixes. I preserved both entry.pinned() and the borrowed donor's serial in victim selection. A new three-entry test (pinned document A, borrowed donor B, ordinary C, then insert D) confirms only C is evicted. All six conversation tests passed on MSVC/CUDA. This looks useful for single-model agent switching.

Follow-up with a larger shared system prefix: the earlier 100-record fixture did not reach the default 2,048-token root threshold, so it tested storage/eviction behavior rather than borrowing. I repeated the ten-turn schedule with a 2,833-token common root and checked the engine's actual borrowed event.

Both arms reused that root on B's first turn. On returning to A and B later, the control read 6,203 and 6,523 tokens, while the #1163 + #1164 port read only 26 and 27. All distinct-answer checks passed. Across the sequence, newly read tokens fell from 33,731 to 21,058, and prompt processing from 116.85 to 75.36 s. The candidate logged the borrowed restore; the control did not.

This is still one sampled sequence per arm and a combined port, not an isolated attribution to #1164. Output totals differed (1,235 vs 725), so the 174.05 vs 108.67 s total wall times also include generation differences. The specific improvement supported by the cache trace is avoiding the two history rereads after borrowing the common root.

BlueKingMuch and others added 2 commits October 7, 2026 19:14
conversation_cache.hpp: make_room evicts neither a conversation that holds a pinned shared prefix (pin=N, new in
0.1.40.2) nor the parked conversation a borrow restores from. generate.cpp: the pin=N sibling check and the borrow's
parking stand side by side; a borrow parks the outgoing conversation as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKZxC8sUotEzdWXws2FTUC
…ead of borrowed

0.1.40.2 added pinned shared prefixes (pin=N): a parked conversation that holds one is never evicted, and N queries
keep one conversation holding the pin. A borrow copies the donor's checkpoints up to the match, so a match that
reached a pinned prefix gave the borrower the pin as well: once parked, a second conversation held it and was never
evicted either. Such a match now takes the conversation, as before the borrow.

The refusal before evicting anything counts the conversations that hold a pinned prefix along with the donor. When
they filled the slots between them, the outgoing conversation found nothing to evict and was not parked; now the
donor is taken whole as before and the outgoing conversation keeps its place.

The borrow's guard is guard()/unguard()/guard_blocked() instead of pin()/unpin()/pin_blocked(), since "pinned" now
means pin=N. conversation_cache_test: a pinned prefix, the donor and an ordinary conversation (only the ordinary one
is evicted), the refusal with both in every slot, and matches on and past a pinned prefix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKZxC8sUotEzdWXws2FTUC
@BlueKingMuch

Copy link
Copy Markdown
Contributor Author

Thanks @midhatn for porting and testing this, and for repeating it with a root above the 2,048-token threshold: the returns to A and B (26 and 27 tokens read instead of 6,203 and 6,523) are the case #1164 is for.

I've updated this PR for 0.1.40.3: a merge of v0.1.40.3 and one commit on top. Your integration point is what the merge does too: parking the outgoing conversation evicts neither a conversation that holds a pinned prefix (pin=N, since 0.1.40.2) nor the conversation a borrow comes from. The commit adds two details:

  • A match that reaches the pinned prefix takes the conversation instead of borrowing from it. A borrow copies the donor's checkpoints up to the match, so the borrower would carry the pin as well; once parked, a second conversation would hold it and never be evicted.
  • The refusal before evicting anything counts the conversations that hold a pinned prefix along with the donor. When they fill the slots or the budget between them, the outgoing conversation would otherwise find nothing to evict and not be parked; now the donor is taken whole as before.

The borrow's guard is now guard()/unguard() instead of pin()/unpin(), since "pinned" means pin=N.

Measured on 0.1.40.3, this against #1163 on 0.1.40.3, with the setup from the description (RTX 4080 SUPER 32 GB, Windows 11, IQ3_S, 262K context, --conversation-cache-mib 2816 --conversation-cache-slots 3, --adapt-every 1000000 --expert-cache 8031, greedy; P1 S1 P2 S2 S1b S2b P3 S1c S2c P4). Prompt tokens read, time to first token:

#1163 #1163 + this PR
S2, new subagent while P is in the session moves S1 in, S1 is overwritten borrows 2,486 tokens from S1 (29 ms), S1 stays parked
S1b, subagent 1 goes on 14,878, 4.9 s 2,369, 2.9 s
all ten requests 86,332 read, 45.1 s 73,892 read, 43.2 s
evicted 1 2

With this PR every return resumes its conversation (2.8 to 3.0 s), and all ten answers are the same in both runs.

With a pinned prefix (a 20,014-token document sent with pin=N, five questions on it, and between them four subagents with a shared 6,018-token system prompt), each request reads as much as on #1163 alone and gives the same answer. The subagents borrow the system prompt from their parked sibling, where #1163 alone takes the sibling whole; the questions never borrow, they resume at the pinned prefix (29 tokens read, 0.4 s). At the end three conversations are parked instead of two, after two evictions (none on #1163 alone); the document was never among them (every later question still resumed at it).

Tests on Windows with CUDA: conversation_cache_test (4,744 checks, now with your case of a pinned prefix, the donor and an ordinary conversation, only the ordinary one evicted; the refusal with both in every slot; matches on and past a pinned prefix), conversation_snapshot_test (4,041), conversation_file_test (169).

@midhatn

midhatn commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Thanks for incorporating the pinned-document/donor/ordinary-entry case. I reviewed cf7f3e8: keeping guard() separate from the persistent pin, and taking a match that reaches the pin rather than copying that pin into another parked conversation, address two distinct eviction problems.

For clarity, my measurements above are from the earlier local port. I have not rerun your new head, so they should not be counted as validation of the added pin-duplication and full-slot refusal cases. The source and test additions look aligned with those cases; no additional change requested from this review.

@edt-xx

edt-xx commented Oct 9, 2026 •

Copy link
Copy Markdown

I run an agentic workload with prompts from about 70K to 105K. With #1164 + #1163 (and stats from #1114) installed I am seeing

Last request 84,024 of 84,075 prompt tokens reused
Reused since start 28,115,329 tokens (92% of all prompt tokens)

without this the reuse percentage is in the low 80s.

Niko1221 added a commit that referenced this pull request Oct 17, 2026
…ne borrows it, the parked conversation stays (#1164)

Sibling subagents with the same system prompt and tools no longer cost each other their history: only the K/V up to the checkpoint and the checkpoint itself are copied into the session (conversation_snapshot_restore_prefix); the parked conversation stays where it is and is pinned while the outgoing one parks. A match on a parked conversation's live state or newest checkpoint is that conversation going on and is taken as before.

Rebased onto 0.1.44.1 by hand: the pinned shared prefix (#879) and evict_oldest() now also skip the borrowed donor, serials follow every erase, and park-gain (#2265) and the pin= sibling rule gate the outgoing park.

Co-authored-by: BlueKingMuch <53972523+BlueKingMuch@users.noreply.github.com>
Niko1221 added a commit that referenced this pull request Oct 17, 2026
…ead of borrowed (#1164)

A borrow copies the donor's checkpoints up to the match, so a match that reached a pinned shared prefix gave the borrower the pin too. Such a match now takes the conversation as before. The borrow's guard is guard()/unguard()/guard_blocked(), and the refusal before evicting counts the pinned conversations along with the donor.

Rebased by hand onto 0.1.44.1 (evict_oldest() honours the guarded donor).

Co-authored-by: BlueKingMuch <53972523+BlueKingMuch@users.noreply.github.com>
@Niko1221

Copy link
Copy Markdown
Owner

Thank you, this is in for 0.1.45, co-authored with you. It needed a hand rebase because 0.1.42 added pinned shared prefixes with their own eviction rule. On our RTX 3060 (IQ3_XXS) the sibling pattern A, B1, A, B2, A went from 13.35 s to 0.80 s on A's last turn (5 of 5 pairs), same greedy output; the sibling's own turn costs about 0.2 s more.

xrip added a commit to xrip/Strata that referenced this pull request Oct 17, 2026
Conflicts: upstream took the Turing kernels this fork had cherry-picked (Niko1221#1821 Niko1221#1825 Niko1221#2069-Niko1221#2072 Niko1221#2081 Niko1221#2091 Niko1221#2093),
now opt-in with STRATA_SM75_PERF=1: their versions kept (native_mmvq, qsa_select, qsa_prompt_attn, prefill, gemm,
kernels). Upstream's sm_75 table replaces ours (STRATA_SM75_TABLE gone; STRATA_MMVQ_IL_ROWS can set rows).
conversation_cache.hpp: the disk tier's on_evict on upstream's serial-aware evict_oldest. generate.cpp: the disk
tier's read-back before Niko1221#1164's borrow (a disk restore never borrows), --conversation-cache-park-gain beside the
disk options. CMakeLists: prefill_mmq_bench kept beside upstream's new tests. Tokenizer: our long-text cache beside
max_special_len.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fragtion added a commit to fragtion/StrataPool that referenced this pull request Oct 17, 2026
Upstream 0.1.45 took in ten of the PRs we carried: Niko1221#567 (prompt encoder), Niko1221#1164 (sibling
borrow), Niko1221#1166, Niko1221#1368, Niko1221#1367, Niko1221#1120 (split overlap), Niko1221#1912, Niko1221#1888, Niko1221#1949, Niko1221#1305.  Their
versions are kept and our copies dropped: verify.cpp's duplicate prelaunch/handoff block,
verify_kernels.hpp, the qsa prompt kernels, gr_upmix_parity, the tokenizer and its tests
(tools/test_strata_tokenizer_upstream.py is gone: upstream's test file is the one now),
the second quantize_scatter declaration.  README credits updated.

Pool parts kept on top:
- conversation cache: upstream renamed the borrow guard (pin -> guard); clear() resets it.
- prefill: the remote_next hand-off beside upstream's hand-off pieces/worker (a pool stage
  has no pieces: the whole chunk goes to the workers).
- generate.cpp: --pool-affinity measure over a node's own layers; the node's dense-range
  load beside STRATA_HC_REQ8; the carve on primary_device over the pool range; checkpoints
  keep pool_id (STRATA_CKPT_POOL/THREADS' parallel save is skipped on a pool PC); the
  workers' retain after eviction and after a resume; the borrow/restore of parked
  conversations on the workers with upstream's --conversation-cache-park-gain; Niko1221#652's
  emit count in upstream's merged windows.
- expert_source: our budget retry beside upstream's lend budget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157fjixQD2nRxvCvtXq66DD
MistVVK added a commit to MistVVK/XeStrata that referenced this pull request Oct 18, 2026
…tream c9e571e・2b296987)

同じシステムプロンプトと道具で始まるサブエージェントは、置いた会話を丸ごと取って後ろを上書き
していたので、その会話の次のターンは履歴を読み直していた。そこまでの K/V とチェックポイントだけ
を写し(conversation_snapshot_restore_prefix)、置いた会話はそのまま残す。最新の状態や最も深い
チェックポイント、固定した前置き(pin=N)との一致はその会話の続きなので、これまでどおり取る。
XeStrata ではファイルからの読み(--conversation-save)を先に見て、層の分割では借りない。
B70・IQ3_XXS: 4K の会話 A の 3 ターン目は、間に A の前置きで始まる B を挟んでも 3,690 トークンを
使い直す(前は 3,555 で 170 を読み直した)。
@Niko1221

Copy link
Copy Markdown
Owner

Thanks for the pull request.

Your change is already in main for 0.2.0-beta, with your credit, so there is nothing left for you to do here. We're closing it because we're resetting the tracker for 0.2.0-beta: there are more than 1,300 open issues and pull requests, and we're closing everything that isn't being worked on right now.

If part of your work did not make it in and you want it considered, open a new pull request on top of main that follows CONTRIBUTING.md, or comment /reopen after fixing the title area prefix and the template.

@Niko1221 Niko1221 closed this Oct 19, 2026
DarthCY-K pushed a commit to DarthCY-K/Strata that referenced this pull request Oct 20, 2026
…est resumes from its own checkpoint

With the conversation cache on, every next turn of a chat whose client sends
the last reply back without its thinking parked the whole live conversation
(1.4-1.6 GB, 280-370 ms on a 52K-token conversation) and dropped that copy as
superseded one request later. Opt-in STRATA_PARK_REWIND_MAX=N skips the park
when the request resumes from a checkpoint of the session's own conversation
and leaves N tokens or fewer behind. Unset, the path is unchanged.

Xiaomi2008 8e4ccbe (fork Xiaomi2008/Strata, not an upstream PR), measured there on an RTX 5090: twelve appended
turns on a 52K conversation 10.4 s -> 6.3 s of prompt reading. Ported onto 0.1.43.1 with Niko1221#1164's borrow: a borrow
never counts as the session's own rewind (it parks the outgoing conversation as Niko1221#1164 does).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZy1yKaDDiA8a7svdwaHio
DarthCY-K pushed a commit to DarthCY-K/Strata that referenced this pull request Oct 20, 2026
…h "parallel", the fork's changes and the measured costs

docs/BATCHING.md "This fork" and docs/NVFP4.md "Several dialogs at once": the switch cost of dialogs that take turns
without and with --conversation-cache-mib (8K / 32K / 100K), why "parallel" was unusable on the 262K config (14.6 GiB
of slots), --batch-max-context in the options table, the control-vector window fix, the conversation-cache PRs taken
(Niko1221#1503, Niko1221#1163, Niko1221#1164, Niko1221#1959, Xiaomi2008's STRATA_PARK_REWIND_MAX), the checks, one dialog's decode per config, and
the recommended setting (the conversation cache; "parallel": 2 with 64K slots when requests really overlap).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZy1yKaDDiA8a7svdwaHio
DarthCY-K pushed a commit to DarthCY-K/Strata that referenced this pull request Oct 20, 2026
…gs, the rope warning, the final build's checks (81049f34)

What's new and "Upstream 0.1.43.1" add the EOS-literal fix ("stop_token_text"), the parallel-dialog fixes (upstream
PRs Niko1221#1503 Niko1221#1163 Niko1221#1164 Niko1221#1959; link to "Several dialogs at once") and the --max-context warning; the checks name the
release build 81049f34: 2K / 32K logits and tokens = 0.1.42-nvfp4.2's engine, the serve KL texts byte-identical,
ctest 116/119, serve 849, tools 821.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZy1yKaDDiA8a7svdwaHio
DarthCY-K pushed a commit to DarthCY-K/Strata that referenced this pull request Oct 20, 2026
…ds, supersede, an index hash, a writer gate, UTF-8 paths

The tray stops an engine with taskkill /F /T, so xrip's QUIT-time save (--conversation-disk-persist)
never runs there and every parked conversation and the live one died with the process.

- --conversation-disk-sync-s N (with --conversation-disk-persist; default 60, 0 = QUIT only): after N s
  without a request the engine writes every parked conversation that has no copy on the disk (from its
  RAM image) and the live one (streamed from the device, as SAVE: one GPU, no --batch), on the serving
  thread, given up within one 16 MiB block when a command arrives (SessionWriteOptions::cancel).
  A RAM image written this way carries its disk entry (SavedConversation::disk_id): its eviction drops
  the RAM copy without a second write.  QUIT runs the same save, then xrip's park-and-spill for what it
  could not stream.
- take(..., keep): with persist (and for a checkpoint match, Niko1221#1164's borrow) the entry stays on the disk
  after a read, as the most recently used: it is the copy that survives a crash until a newer one exists.
- Supersede: a newly written entry removes the older copies of the same conversation (the RAM cache's
  Niko1221#342 rule on the keys), only after it is complete; the budget then takes the least recently used,
  never an entry being read.
- An entry with the same keys is not written twice.
- The index (format 2) ends with a hash: a torn or edited index is refused at start like a damaged one;
  file names in it must be bare names of this tier.
- The background writer starts a job only while the engine is idle (set_busy), unless RAM or the entry
  is waited for (wait_idle, take): spills no longer write during a prompt read or decode.  Windows:
  THREAD_PRIORITY_BELOW_NORMAL.
- Paths: UTF-8 through std::u8string (std::filesystem reads a std::string in the ANSI code page on
  Windows).
conversation_disk_test: 118 checks (keep, write_now, cancel, supersede, the gate, the index hash, disk_id).

Measured (RTX 5090, Windows, NVFP4 GPTQ pack): a 16K sub-agent back from the disk in 0.41 s against
1.75 s read; idle save of 2 conversations 0.5 s; after taskkill /F /T and a restart all 3 dialogs back
from the disk in 0.32-0.49 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZy1yKaDDiA8a7svdwaHio
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.

4 participants