anomalyco / anomalyco/opencode
[FEATURE] /undo during active generation: cancel the queued messages, keep the in-flight stream
@kitlangton is already working on this.
Since Aug 22, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Summary
Proposed semantics for /undo while a generation is active: cancel the queued messages and leave the in-flight stream alone, applying the revert once the active response completes.
Today the behavior is either a Session is busy failure (#38476) or — in the pre-beta behavior #38476 asks to restore — aborting the active generation. Both miss the common case.
The common case
A run is active and I realize the follow-up message I just queued is wrong (typo, wrong file, changed my mind). I reach for /undo. What I want reverted is the queued message — the part that has not been consumed yet. What I do not want is to kill the active generation:
- On paid providers, aborting mid-stream throws away committed tokens.
- On large local models (e.g. long-context local seats), prefill + decode can represent minutes of compute that must then be redone from scratch.
Esc/ctrl+c already exists as the explicit "kill the active generation" affordance. /undo does not need to be a second one.
Proposed behavior
| Session state | /undo behavior |
|---|---|
| Active stream + queued messages | Drop the queued messages; keep the active stream; apply the revert after it completes |
| Active stream, empty queue | Friendly no-op with a hint ("nothing queued — press Esc to abort") instead of a busy error |
| Idle | Current behavior (revert last message) |
| Esc / interrupt | Unchanged force-abort |
This also gives a natural answer to the promotion race in #39736: a queued-but-not-yet-promoted message becomes an explicit "cancelled before promotion" outcome rather than an undo boundary the revert planner cannot find.
Why not simply restore abort+undo (the ask in #38476)
It works, but it conflates two operations and pays for both: the active generation is destroyed and the message is reverted. With queue-first semantics, #38476's reproduction (start response → /undo → error) resolves without any abort when the intent was fixing the queue, and Esc remains available when the intent really is killing the run.
Environment
- opencode 1.18.15, macOS TUI (arm64), Homebrew
- Abort path observed in local logs as
message=cancelfollowed bymessage=process ... error=Aborted
Refs: #38476 (busy failure; asks for abort+undo), #39736 (admitted-message undo race after interrupt), #14014 (historical: session.undo aborted ongoing work)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.