Skip to content

server: restore the prompt frontier after cancelled generation - #960

Open
JordiPosthumus wants to merge 1 commit into
antirez:mainfrom
JordiPosthumus:codex/fix-cancelled-request-frontier
Open

server: restore the prompt frontier after cancelled generation#960
JordiPosthumus wants to merge 1 commit into
antirez:mainfrom
JordiPosthumus:codex/fix-cancelled-request-frontier

Conversation

@JordiPosthumus

@JordiPosthumus JordiPosthumus commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Preserve the synchronized prompt when a client cancels generation, and retain
an exact OpenAI retry binding when visible replay differs from sampled tokens.

Why

Generation mutates more than a token count: raw KV is a ring and compressor/
indexer accumulators change in place. Truncating the token list cannot recover
the prompt after those values have been overwritten. The request checkpoint
copies the mutable frontier; compressed history remains in place and is bounded
again by its saved counters. A checkpoint belongs to one session and is retired
before destructive history reconstruction.

Restoring KV is also insufficient if the client omits prior hidden reasoning.
The retry binding ties the original parsed messages and rendered tokens to the
complete restored frontier. Execution rechecks tokens and image identity, and
dispatch selects the unique owner. It does not re-append consumed tool results.
Failed restoration clears the binding. Successful response delivery is not
undone by a late client FIN.

After rollback, a continued-save counter beyond the restored prompt is capped
at that prompt; lower counters are left alone. Otherwise a checkpoint written
by the discarded tail can suppress a new retry-tail checkpoint. This uses the
existing slot counter and does not delete the old disk file or depend on #903.

Compatibility

Tensor rollback is limited to local DeepSeek Metal sessions. Unsupported or
invalidated rollback uses conservative invalidation; an untouched valid prompt
can be preserved without a snapshot. No model math, sampling, cache format or
arbitrary rewind change. The new binding is exact, resident-only, and uses the
existing slot state/locks; it is not general history matching.

Validation — 2026-09-03

Amended head acb51c4f9a06d7b27188482a919a8d283962d4c0, directly on
main b0a147a7fba6d1a104d047d5a140e9bb4bfc13cd. Clean default/CPU builds,
focused server/agent tests and C ASan+UBSan server/agent tests pass. Sanitizers
link the ordinary Metal object with leak detection disabled: not GPU sanitizer
coverage. CPU validation is compile/link only.

make -j2
make -j2 ds4_test ds4_agent_test
./ds4_test --server
./ds4_agent_test
make -j2 cpu  # build only; no CPU model execution

On M3 Ultra/Metal with the Vision-Exp mixed quant below:

  • DS4_TEST_MODEL="$MODEL" ./ds4_test --cancel-checkpoint overwrote the raw
    ring and reproduced all 607 full-logit vectors after restoration; a foreign
    session rejected the checkpoint.
  • Standalone text/image abort-retry checks reused 4,010/2,107 tokens.
  • Save-counter tests fail 15 assertions without the amendment and pass with it.
    Cases include lower/equal counters, multiple intervals, repeated cancellation,
    untouched prompts and injected restore/validation failures. These are the
    direct boundary regression; model runs do not generate a 16,384-token tail.
  • A separate local integration with vision/OpenAI continuation patches restored
    and reused all 1,272 tokens after image/tool cancellation and retained the
    first of ten conversations. This is not standalone server: restore the prompt frontier after cancelled generation #960 evidence or a forced
    publication-race test. The exact retry binding remains resident-only.

Snapshot capture at allocated context 262,144 and prompt 8,193 averaged
2.3048 ms over 20 captures (2.216–2.625 ms), with 22.39 MiB incremental tracked
GPU memory released after free. This is request-boundary capture cost, not
per-token overhead. No full aggregate model suite is claimed.

Matched engine speed

Matched M3 Ultra (512 GiB), Metal, DeepSeek-V4-Flash-Vision-Exp
MXFP4Experts/F16HC/F16Compressor/F16Indexer/Q8Attn/Q8Shared/Q8Out comparison:
two runs per build in mirrored order, 2,048/16,384-token text frontiers,
262,144 allocated context, 4,096 prefill, 64 greedy output tokens, warmed
weights, no MTP. Mean tokens/s:

Frontier Main prefill PR prefill Main generation PR generation
2,048 630.45 629.62 42.800 43.000
16,384 573.94 573.57 37.430 37.525

Frontier-logit dumps were byte-identical. Differences were below 0.5%; these
short engine runs are not a server-scheduling, image-throughput or long-context
production guarantee. Spotlight indexing was active; swap did not grow.
ds4-bench does not exercise server request-boundary capture; its separate cost
is reported above.

./ds4-bench --model "$MODEL" --metal \
  --prompt-file speed-bench/promessi_sposi.txt \
  --ctx-start 2048 --ctx-max 16384 --step-incr 14336 \
  --ctx-alloc 262144 --prefill-chunk 4096 --gen-tokens 64 \
  --warm-weights --csv "$CSV" --dump-frontier-logits-dir "$LOGITS"

This restores a saved request prompt, unlike bounded live-prefix rewind #710;
socket-disconnect detection #785 is also separate. #927 overlaps the reuse
dispatch: after either lands, preserve exact cancelled-retry priority and use
exact image matching for protocol reconstruction when refreshing the other.

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