Repository navigation
Queue dispatches follow-ups as mid-turn steers after each tool call #12100
Description
What happened
With Settings → General → Follow-up behavior set to Queue, queued messages are released after individual tool calls while the original agent turn is still running.
This makes Queue behave like delayed Steer. A message intended as the next task can alter work that is still underway. When several messages are queued, releasing exactly one after each tool call also spreads related guidance across multiple stages of the active turn for no clear semantic reason.
The behavior occurs in the desktop app across all tested providers.
Diagnosis
T3 Code v0.0.42 intentionally implements Queue as a client-side delay until the next tool boundary:
- A message records the latest completed tool activity when queued.
- During a running turn, it becomes due when a different
tool.completedactivity appears. - After dispatch, the remaining messages are re-anchored so one message leaves at each subsequent tool boundary.
- Providers interpret these mid-turn sends as steering input for the active turn.
PR #11673 introduced these semantics and states that a queued message leaves after the next tool call or when the turn ends:
PR #11964 added the Queue/Steer preference without changing provider or server dispatch behavior:
This conflicts with the intended distinction described in the feature requests:
- [Feature]: Add configurable follow-up behavior while a turn is running #1462 defines Queue as holding a message until the current turn completes.
- feat: add Steer and Queue follow-up modes alongside Chat/Plan #231 defines Queue as saving a follow-up until the current work settles.
Both requests are closed, but the completed implementation does not provide those Queue semantics.
Current Steer and Queue behavior differs primarily in client-side dispatch timing:
- Steer sends each submitted message immediately to the active provider turn.
- Queue sends the oldest message to that same active turn after the next tool completion, then waits for another tool completion before sending the next message.
At the harness layer, immediate steering may already be deferred until the current tool call finishes and the agent can safely consume new input. If so, submitting several messages during one tool call may cause the harness to consume all of them at the next boundary. This needs confirmation for each provider, but it would mean T3 Code's client-side Queue adds little beyond delaying dispatch—and its one-message-per-tool-boundary policy may be less useful than forwarding all accumulated steering input at the next safe boundary.
The same tool-boundary implementation remains on main, so no newer stable release or current upstream change fixes this.
Expected semantic separation:
- Steer: inject guidance into the active turn at the next safe opportunity.
- Queue: wait until the active turn fully settles, then start a new turn.
- Stop: abort the active turn.
Steps to reproduce
- Open T3 Code desktop.
- Set Settings → General → Follow-up behavior to Queue.
- Start a task that performs several sequential tool calls.
- While a tool call is running, submit two follow-up messages intended for after the task finishes.
- Observe the conversation after each tool call completes.
Expected:
- Both messages remain visibly queued until the original turn fully completes.
- After completion, the oldest queued message starts a new turn.
- Remaining messages stay queued for subsequent turns.
Actual:
- The first queued message dispatches after the next completed tool call.
- The original turn is still active.
- The provider consumes the message as steering input for that turn.
- Additional queued messages dispatch one at a time at subsequent tool boundaries.
Version
0.0.42 (719a76ca1dbf5490f1aa33ffb9966301e02be9a9)
Environment
Linux x64, Fedora 44 kernel 7.0.10-200.fc44.x86_64, Node.js 26.8.2, T3 Code desktop, all tested providers
Evidence
apps/web/src/queuedMessageStore.ts:
"A queued message is due mid-turn once a tool call finished after it was
queued, and as soon as the turn is over otherwise."
if (input.phase !== "running") return true;
return input.latestToolActivityId !== input.message.queuedAfterToolActivityId;
apps/web/src/components/ChatView.tsx:
"Sends the oldest queued message once it is due: a tool call finished
after it was queued, or the turn ended. Only one leaves per boundary."
PR #11673:
"It goes out on its own when the agent finishes its next tool call, or when
the turn ends."
"The provider side already treats a mid-turn send as a steer of the active
turn for every adapter, so the queue only decides when to dispatch. Only one
message leaves per tool boundary."Related issues
- [Feature]: Add configurable follow-up behavior while a turn is running #1462 — specifies that Queue should wait until the current turn completes; closed.
- feat: add Steer and Queue follow-up modes alongside Chat/Plan #231 — requests distinct Queue and Steer semantics; closed.
- Message sent while a turn is running stays pending forever after the turn ends #9672 — related pending-turn problem, but not a duplicate; that issue concerns a queued server turn that never starts.
This report concerns client-side Queue intentionally releasing messages into an active turn.
Fix applied or workaround
No fix was applied.
Current workaround: wait until the active turn finishes before submitting the follow-up. This defeats the purpose of Queue.
A fix should release one queued message only after the active provider turn reaches a terminal state. Explicit Steer should remain available for mid-turn guidance.
As an additional design option, T3 Code could support a batched boundary steer: collect all messages submitted before the next safe tool boundary and deliver them together at that boundary. This appears consistent with the reporter's experience of steering in the native Claude and Codex harnesses, although that comparison and the exact harness-level delivery timing need confirmation. If multiple follow-ups are intended to steer the active turn, batching them is more coherent than releasing one message after each successive tool call. This could be a separate behavior or an adjustment to Steer, while Queue retains true next-turn semantics.
Filed by
Codex (GPT-5) via T3 Code triage.
Activity
juliusmarminge commentedon Sep 16, 2026
Triage
Confirmed on current
mainand shipping0.0.42. This is a real bug in the shipped Queue setting, not a reporter misread. Desktop and web share the same client dispatch. Not already fixed, and not a duplicate of #9672. No later commit onmainchanges the due rule.What you reported. With Settings → General → Follow-up behavior set to Queue, a follow-up leaves after the next
tool.completed, while the original turn is still running. Providers treat that send as a steer. Several queued messages then drip out one per later tool call. Expected: they stay queued until the active turn is terminal, then the oldest starts a new turn.That matches the code. Default
followUpBehavioris already"queue", so this is the default send-while-running path.What the code does. Queue is a client-side delay until the next tool boundary. It is not a next-turn hold.
isQueuedMessageDue(apps/web/src/queuedMessageStore.ts) returns true whilephase === "running"as soon aslatestToolActivityId !== queuedAfterToolActivityId. Tests lock that in: a message anchored ata2becomes due ona4mid-run.ChatView).onSend.docs/user/composer.mdstill documents the tool-boundary rule.That is not the Queue contract from the closed requests (#1462 / #231): hold until the current turn completes / work settles. Steer vs Queue today is only when the same mid-turn
sendTurnfires (now vs next tool). There is no next-turn path except waiting until the turn is already over.Your extra idea — batch every steer at the next safe harness boundary — is plausible and unconfirmed here. Do not treat harness batching as the close for this issue.
Related, not duplicates
pendingturn that never starts (opposite failure mode).isQueuedMessageDue.Suggested fix
Keep Steer as immediate mid-turn
sendTurn. Make Queue wait for a terminal / non-running phase, then start a new turn. Keep Send now /thread.steerQueuedMessageas the one-off promote.isQueuedMessageDue, ifphase === "running", returnfalse. Leaveconnectingblocked.phase !== "running"already drains after settle.docs/user/composer.mdand the settings row copy (both currently describe delayed steer).a4while running; add a ChatView case with two Queue submits during a multi-tool turn.Workaround
Wait until the turn is idle, then send — the only true next-turn path today. Send now on a dashed row is Steer. Switching the setting to Steer only removes the delay.
piotrnowakowski commentedon Sep 23, 2026
Still happening for me on the desktop app with both the Codex and Claude harnesses. With Follow-up behavior set to Queue, a queued message is sent right after the next tool/task completes (Claude log:
task.completedat 18:41:14.448, thensendTurnat 18:41:14.760 with noturn.completedin between), so it lands mid-turn as a steer. Looking forward to #12119 landing.dimasmufid commentedon Sep 30, 2026
Is it bug or it is by design, that
queueis become laggingsteer(steer it after tool calling completed)mejtyas commentedon Sep 30, 2026
Any update on #12119? Queue still injects my next prompt immediately after a tool call, before the current task finishes. This changes ongoing work when I explicitly selected Queue.
This breaks the main reason to use the feature. Is there a blocker preventing the fix from being merged, or an ETA?
infinit7even commentedon Oct 2, 2026
Same problem