pingdotgg / pingdotgg/t3code

Queue dispatches follow-ups as mid-turn steers after each tool call

Open
#12,100 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

accepted bug via-triage
Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

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.completed activity 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:

https://github.com/pingdotgg/t3code/pull/11673

PR #11964 added the Queue/Steer preference without changing provider or server dispatch behavior:

https://github.com/pingdotgg/t3code/pull/11964

This conflicts with the intended distinction described in the feature requests:

  • #1462 defines Queue as holding a message until the current turn completes.
  • #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
  1. Open T3 Code desktop.
  2. Set Settings → General → Follow-up behavior to Queue.
  3. Start a task that performs several sequential tool calls.
  4. While a tool call is running, submit two follow-up messages intended for after the task finishes.
  5. 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

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with apps/web/src/queuedMessageStore.ts and apps/web/src/components/ChatView.tsx, then reproduce the Queue behavior while a task performs multiple tool calls. Trace when queued messages become due and how they are dispatched. Done means queued messages remain pending until the active turn reaches a terminal state, with the oldest message starting the next turn while Steer remains mid-turn guidance.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
desktop, frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.