diff --git a/tools/server/server-context.cpp b/tools/server/server-context.cpp index 01e7eaa35..c2f29094e 100644 --- a/tools/server/server-context.cpp +++ b/tools/server/server-context.cpp @@ -321,6 +321,9 @@ struct server_slot { return; } SLT_WRN(*this, "dropping an unfinished splice at %d tokens\n", prompt.n_tokens()); + if (!common_speculative_flush(spec, id)) { + SLT_ERR(*this, "%s", "failed to flush the draft context before aborting SCR\n"); + } scr.reset(); llama_scr_set_spliced(ctx_tgt, id, false); if (ctx_dft) { @@ -2869,7 +2872,13 @@ private: // the prefill of a splicing slot has reached its next run: the run's tokens are already in the cache. after the // last run the recurrent state continues from the pre-edit snapshot, and the splice is done - void scr_take_run(server_slot & slot) { + bool scr_take_run(server_slot & slot) { + // Short edited gaps can leave MTP catch-up rows pending below the relocated KV. + // Decode them while the splice guard is still active, before skipping this run. + if (!common_speculative_flush(spec.get(), slot.id)) { + return false; + } + auto & s = *slot.scr; const auto & tokens = slot.task->tokens; @@ -2897,6 +2906,7 @@ private: } llama_scr_recr_set_pos(ctx_tgt, slot.id, slot.prompt.tokens.pos_next() - 1); + return true; } // n_tokens_cur: the number of tokens added to the batch for the current slot @@ -4397,7 +4407,11 @@ private: if (batch.size() > n_tokens_prev) { break; } - scr_take_run(slot); + if (!scr_take_run(slot)) { + send_error(slot, "failed to flush the draft context before an SCR run", ERROR_TYPE_SERVER); + slot.release(); + return; + } continue; }