Problem
Today, once a turn begins (model is streaming tokens or executing tool calls), the input is effectively frozen. Any message typed by the user is either:
- Queued silently and delivered as a new turn after the current one finishes
- Discarded in some UI states
- Never acknowledged — the user has no feedback about what will happen to it
This creates several painful failure modes:
- The agent is mid-stream realizing the wrong approach, user can't correct it
- The agent has started a 15-tool refactor in the wrong directory — no way to redirect without full cancel
- The user wants to give additional context that changes the trajectory ("actually use the v2 API not v1") but must wait for the entire turn to finish
- Cancel (Escape/Ctrl+C) is the only option — a blunt instrument that loses all progress
This is distinct from #17691 which proposes a /btw slash command specifically to inject context between tool calls. This issue is about a first-class mid-turn messaging system at the protocol level — covering all phases of a turn.
Desired Behavior
The user's input should always be live. Messages sent during an active turn should be handled in one of three modes (configurable per user / per session):
Mode 1: Queue + Inject at next tool boundary
Message is held and injected into the agent's context at the next natural breakpoint (between tool calls). The current tool finishes. No interruption.
Mode 2: Preempt — pause streaming, inject, resume
The model stream is paused mid-generation. The message is prepended to the pending assistant context and the turn resumes with the new context. Requires SSE stream cancellation + context splicing.
Mode 3: Hard interrupt with context carry-forward
The current turn is cancelled (existing behavior), but the accumulated partial tool results + the new user message are forwarded into a new turn automatically. The user doesn't lose the work done so far.
Proposed UX
┌─────────────────────────────────────────────────────┐
│ Agent is running... [Cancel ✕] [Inject ↩] │
│ │
│ > _______________________________________________ │
│ Send mid-turn (injects at next tool boundary) │
└─────────────────────────────────────────────────────┘
- Input remains enabled during agent turns (not grayed out)
- A visual indicator shows the message will be injected, not queued for next turn
- Optional: show the queued message in the turn timeline as a "pending injection"
Technical Sketch
TUI path:
- Keep input active at all times
- On Enter during active turn: push to
mid_turn_queue: Message[] on the session
- Before each tool dispatch in
runTurn(), drain mid_turn_queue → append as user messages to the message array
- Surface queue state in the turn event stream:
{ type: \"mid_turn_message_queued\", content }
Web path:
- Same session-level queue, surfaced via SSE event
- Input stays active, send button changes to "Queue for injection" label during active turn
API path:
POST /session/{id}/message
{
\"content\": \"actually use the v2 API\",
\"delivery\": \"inject\" | \"queue\" | \"interrupt\"
}
inject: deliver at next tool boundary in current turn
queue: deliver as new turn after current completes (existing behavior)
interrupt: cancel current turn and start new one with carry-forward context
Why This Matters
This is one of the highest-leverage UX improvements for agentic workflows:
- Long tasks become steerable instead of all-or-nothing
- Reduces wasted compute — no more watching a wrong refactor complete before you can correct it
- Enables collaborative human-in-the-loop workflows where the human and agent work together within a single turn
- Naturally extends automode — external scripts can inject context mid-loop without cancelling
Related Issues
Problem
Today, once a turn begins (model is streaming tokens or executing tool calls), the input is effectively frozen. Any message typed by the user is either:
This creates several painful failure modes:
This is distinct from #17691 which proposes a
/btwslash command specifically to inject context between tool calls. This issue is about a first-class mid-turn messaging system at the protocol level — covering all phases of a turn.Desired Behavior
The user's input should always be live. Messages sent during an active turn should be handled in one of three modes (configurable per user / per session):
Mode 1: Queue + Inject at next tool boundary
Message is held and injected into the agent's context at the next natural breakpoint (between tool calls). The current tool finishes. No interruption.
Mode 2: Preempt — pause streaming, inject, resume
The model stream is paused mid-generation. The message is prepended to the pending assistant context and the turn resumes with the new context. Requires SSE stream cancellation + context splicing.
Mode 3: Hard interrupt with context carry-forward
The current turn is cancelled (existing behavior), but the accumulated partial tool results + the new user message are forwarded into a new turn automatically. The user doesn't lose the work done so far.
Proposed UX
Technical Sketch
TUI path:
mid_turn_queue: Message[]on the sessionrunTurn(), drainmid_turn_queue→ append asusermessages to the message array{ type: \"mid_turn_message_queued\", content }Web path:
API path:
inject: deliver at next tool boundary in current turnqueue: deliver as new turn after current completes (existing behavior)interrupt: cancel current turn and start new one with carry-forward contextWhy This Matters
This is one of the highest-leverage UX improvements for agentic workflows:
Related Issues
/btwcommand (subset of this: inject between tool calls only)