Port visible-KV checkpoint fixes for tool turns (fixes token-mismatch reprocesses on agentic workloads) - #789
Port visible-KV checkpoint fixes for tool turns (fixes token-mismatch reprocesses on agentic workloads)#789fradav wants to merge 2 commits into
Conversation
Three fork commits (b1e3287, 47ee3ce, ac98ff4) backported onto the slot-threaded upstream structure, so agentic workloads stop paying a full 140k+ token reprocess on every cache invalidation: - Chat/Anthropic tool-call turns now remember a visible live checkpoint (prompt_text + canonical suffix) keyed to the live KV frontier, so the next request continues in memory instead of an evict-store + disk-restore round trip. Hits are labeled tool-visible. - Tool-context conversations (has_tools / tool-using history) also remember a visible checkpoint for turns that finish without calling a tool: the chat template keeps reasoning in future renders, so the generated text is exactly what the next request renders. - Responses/Anthropic/chat live state is preserved even on streaming errors: the tool calls were generated and KV rows written; only HTTP delivery failed. The !response_ok path keeps job_mark_cancelled() and the error accounting but deliberately drops request_live_state_clear() so the freshly recorded frontier survives a retry ("send now"). - KV waypoints are stored through tool calls too, so a stream death mid-tool-call leaves recent restart points instead of forcing a near-total reprocess. - Add should_remember_tool_context_checkpoint() gate plus a unit test. Server-only change: Metal, SSD streaming and distributed paths untouched.
There was a problem hiding this comment.
Pull request overview
This PR ports “visible-KV checkpoint” behavior to chat/completions and Anthropic tool-turns so retries/continuations can bind to an in-memory KV frontier using a predictable visible transcript key, avoiding full-context re-prefills triggered by token mismatches in agentic/tool-heavy workloads.
Changes:
- Adds a “tool-visible” live checkpoint path for chat/completions + Anthropic tool-call turns (and a companion checkpoint for tool-context turns that didn’t call a tool).
- Preserves live continuation state across streaming delivery failures (so retries can continue from the just-generated frontier).
- Enables continued KV waypoint snapshotting during tool calls to improve restart points for long tool-call spans.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Nice — this is broader than #709 (adds Anthropic, waypoints through tool-call turns, and disconnect/error preservation). Flagging where the two meet, since they collide on merge and, more usefully, cover opposite halves of the same axis. Both remember
Opposite client modes — and on current The clean unification is to pick the reasoning by the flag rather than hardcoding it — roughly (Heads-up: #714 also changes |
Zed and other Responses API clients send reasoning items with encrypted_content (opaque base64) instead of plain summary/content when replaying history in stateless mode. DS4 cannot decrypt this, but must preserve it verbatim in the rendered prompt so the token stream matches the original generation for KV cache reuse. Without this fix, encrypted_content was silently dropped by the JSON parser, causing the rendered prompt to omit thinking tags entirely and triggering full cache invalidation on the next request. Changes: - Add encrypted_content field to chat_msg struct - Parse encrypted_content in parse_responses_input JSON loop - Attach encrypted_content to assistant messages alongside reasoning - Render encrypted_content in thinking tags when reasoning is empty (both DeepSeek and GLM prompt templates) - Add test_responses_encrypted_reasoning_preserved unit test
Problem
On agentic workloads (tool-calling, thinking, steering interrupts, "send now" with a new message, or even a mid-thinking stream death),
ds4-serverfrequently logslive kv cache miss ... reason=token-mismatchand then re-prefills the entire context — routinely 140k+ tokens. This happens on every failed tool, every steering interrupt that appends a new user message, and sometimes in the middle of a thinking run with no interruption at all.Root cause: chat/completions and Anthropic tool-call turns had no live binding to the next request. The sampled tail (hidden reasoning, exact DSML spelling, BPE drift) never token-matches the client's replay, and the byte-exact memory-text path rarely matches either — so every agent turn paid an evict-store (~650 MiB) plus disk-snapshot restore and tail re-prefill.
The Responses API already solves this with a predicted visible-transcript key. This PR reuses that mechanism for chat/Anthropic.
Changes (all in
ds4_server.c, server-only)Visible checkpoint for chat/Anthropic tool-call turns — after
finish=tool_calls, rememberprompt_text+ the same canonical suffixcanonicalize_tool_checkpoint()builds (byte-equality with the next rendered prompt is already covered bytest_tool_checkpoint_suffix_is_future_prompt_canonical). The next request continues from live KV, tokenizing only the new tool results. Hits are labeledtool-visiblein logs.Visible checkpoint for tool-context turns that don't call a tool — when the conversation has tools (or tool-using history), the chat template preserves reasoning verbatim in future renders, so a plain turn that finished without calling a tool still renders byte-for-byte into the next request. Previously such turns had no visible checkpoint at all and fell through to raw token matching. New gate
should_remember_tool_context_checkpoint()+ unit test.Preserve the live frontier on streaming errors — the tool calls were generated and the KV rows written; only HTTP delivery failed. The
!response_okpath keepsjob_mark_cancelled()and the error accounting but deliberately dropsrequest_live_state_clear()so the freshly recorded frontier survives a retry ("send now").Store KV waypoints through tool calls too — waypoint snapshots are stored on disk in full (compressed KV, indexer, compressor frontiers included), so a snapshot taken mid-tool-call is as safe as any other. Previously waypoints were suppressed for the whole tool-call duration; long agentic turns left no recent restart point, forcing a near-total reprocess when the client stream died mid-tool-call.
Validation
make ds4_testclean./ds4_test --server→server: OKtest_tool_context_checkpoint_remember_gatepassesThese are backported from the fork's
b1e3287,47ee3ce, andac98ff4, adapted to the slot-threaded upstream structure.