diff --git a/src/server/turn.rs b/src/server/turn.rs index ab67bf8..d9084b8 100644 --- a/src/server/turn.rs +++ b/src/server/turn.rs @@ -473,17 +473,21 @@ pub(crate) async fn run_turn( send_res = tx.send(Ok(BackendEvent::Token(s.clone()))) => { if send_res.is_err() { // The SSE receiver is gone (the surface - // disconnected mid-reply). Do NOT return early: - // that would skip the session commit below and - // orphan this turn, leaving a user→user gap so - // the next turn cannot link to the past — the - // model reads the follow-up with no preceding - // reply and answers as if from nowhere. Commit - // the partial text like an interrupt instead, so - // the conversation thread stays intact even when - // the surface vanishes. + // disconnected mid-stream). The model's reply is + // already complete in `final_content` — only the + // paced live-stream was cut, so do NOT truncate + // to `streamed`. Stop streaming to the dead + // receiver and let the turn commit the FULL + // reply below; treating it as an interrupt also + // skips the now-pointless N+1 pass and lands a + // small marker so the next turn knows the live + // tail was missed. Returning early here used to + // orphan the turn entirely — no commit — leaving + // a user→user gap so the next turn could not link + // to the past, and the model answered as if from + // nowhere ("whatever it was…"). The surface + // recovers the whole reply on its next resume. interrupted = true; - final_content = streamed; break; } dispatcher.emit_segment(&s);