Mid-stream message aborts the in-flight turn and resends #43

Open
opened 2026-07-06 01:39:43 +08:00 by weiwen · 0 comments
Owner

What to build

When the user sends a plain text/attachment message while a response is still streaming, abort the in-flight turn and answer the new message instead — with correct Telegram ordering.

Rationale (decided during grilling): pi's native steer never interrupts the current generation and would render the continuation above the new user message in the timeline. Telegram can't reorder messages, so the only way to place the answer below the steering message is to abort the old turn, delete its answer, and send a fresh one below. Hence abort-and-resend rather than steer.

Builds on the cancel primitive from the blocking issue.

End-to-end behavior:

  • A plain text/attachment message arriving while a turn is in-flight for that chat cancels it (via the cancel primitive), deletes the in-flight answer message(s), then runs the new message as a normal prompt — new placeholder appears below the new user message and streams the fresh answer.
  • Last-writer-wins for rapid fire: a third message aborts the second's turn, and so on. Only the final message drives the visible answer.
  • The aborted partial answer stays in pi's session history (its default on stopReason: "aborted"), so the new prompt runs with prior context; no history surgery.
  • Atomic in-flight guard: the "is a turn live? → abort+await : start" decision is serialized per-chat so two near-simultaneous fresh messages can't both start a turn on the one pi process.
  • Commands are control, not conversation: only plain text/attachments trigger this flow (/clear handling comes from the blocking issue; /help//start are untouched).
  • HTTP interface is unaffected (no streaming, no placeholder, no ordering problem).

Also update the docs that currently claim message queuing is "delegated to pi via streamingBehavior: followUp" — that path is no longer exercised, since evie now ensures pi is idle (abort → drain) before every new prompt. Affected: DESIGN.md, CONTEXT.md, docs/adr/0001-rust-telegram-pi-rpc-stack.md.

Acceptance criteria

  • Sending a plain message mid-stream deletes the in-flight answer (all pages) and answers the new message in a new message below the new user message
  • Rapid consecutive messages resolve last-writer-wins — only the final message's answer is shown
  • The new prompt runs with prior context including the aborted partial (no session reset)
  • Two near-simultaneous fresh messages never both start a turn (guarded transition)
  • A message arriving after the turn has already finished is handled as a normal new message (no abort)
  • Attachments/images in the mid-stream message are handled the same as normal messages
  • Docs no longer claim queuing is delegated to pi; they describe evie's abort-and-resend
  • Tests cover the mid-stream abort-and-resend path and the last-writer-wins race

Blocked by

## What to build When the user sends a plain text/attachment message while a response is still streaming, abort the in-flight turn and answer the new message instead — with correct Telegram ordering. Rationale (decided during grilling): `pi`'s native `steer` never interrupts the current generation and would render the continuation *above* the new user message in the timeline. Telegram can't reorder messages, so the only way to place the answer below the steering message is to abort the old turn, delete its answer, and send a fresh one below. Hence abort-and-resend rather than steer. Builds on the cancel primitive from the blocking issue. End-to-end behavior: - A plain text/attachment message arriving while a turn is in-flight for that chat cancels it (via the cancel primitive), deletes the in-flight answer message(s), then runs the new message as a normal prompt — new placeholder appears below the new user message and streams the fresh answer. - **Last-writer-wins** for rapid fire: a third message aborts the second's turn, and so on. Only the final message drives the visible answer. - The aborted partial answer stays in `pi`'s session history (its default on `stopReason: "aborted"`), so the new prompt runs with prior context; no history surgery. - **Atomic in-flight guard:** the "is a turn live? → abort+await : start" decision is serialized per-chat so two near-simultaneous fresh messages can't both start a turn on the one `pi` process. - Commands are control, not conversation: only plain text/attachments trigger this flow (`/clear` handling comes from the blocking issue; `/help`/`/start` are untouched). - HTTP interface is unaffected (no streaming, no placeholder, no ordering problem). Also update the docs that currently claim message queuing is "delegated to `pi` via `streamingBehavior: followUp`" — that path is no longer exercised, since evie now ensures `pi` is idle (abort → drain) before every new prompt. Affected: `DESIGN.md`, `CONTEXT.md`, `docs/adr/0001-rust-telegram-pi-rpc-stack.md`. ## Acceptance criteria - [ ] Sending a plain message mid-stream deletes the in-flight answer (all pages) and answers the new message in a new message below the new user message - [ ] Rapid consecutive messages resolve last-writer-wins — only the final message's answer is shown - [ ] The new prompt runs with prior context including the aborted partial (no session reset) - [ ] Two near-simultaneous fresh messages never both start a turn (guarded transition) - [ ] A message arriving after the turn has already finished is handled as a normal new message (no abort) - [ ] Attachments/images in the mid-stream message are handled the same as normal messages - [ ] Docs no longer claim queuing is delegated to `pi`; they describe evie's abort-and-resend - [ ] Tests cover the mid-stream abort-and-resend path and the last-writer-wins race ## Blocked by - #42
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
weiwen/evie#43
No description provided.