Repository navigation
[Feature]: Let agents ask the user via the t3-code MCP server (t3_pending_request_create) #13853
Replies: 8 comments
|
One invariant I'd add before implementing this is idempotent request creation.
I'd also bind the request to the originating provider session / turn generation. If that generation has been replaced before the answer arrives, the answer should become stale-but-visible rather than silently steering the newer turn. That would make the non-blocking approach safe across the restart/reconnect failures it's intended to survive. |
|
A use case beyond Pi. We have Claude agents end their turn with
A question with |
|
Another use case, for orchestrator threads. A Claude orchestrator delegates work with
|
|
Follow-up with a working prototype for the orchestrator case. I built What it does
Input
Three optional additions, shown in the screenshots
[screenshot: card 2 of 3, a plan with two questions] Tested so far Claude Sonnet 5.5 posted three cards and ended its turn. I answered one by choosing options and one by typing my own answer; both arrived as messages after the turn had ended, and the thread showed Input in the sidebar while cards waited. Focused tests cover create, retry, multi-select answers, Stop, and the input checks. Mobile: cards work in the mobile app too. An agent's card shows up there and answering it sends the reply back as the next message, with no mobile changes needed. The pager, links and badge are web-only so far; mobile shows the oldest waiting card. Would you accept a PR for the tool? And should the three additions be separate PRs, or left out? |
|
Another data point from Pi: In RPC mode it falls back to
As a local workaround I made the extension use only
It works, but it is clearly a stopgap: one card per toggle, no per-option descriptions, the title shown twice. With |
|
Another orchestrator case, from a Claude-only multi-agent setup on the 0.1.3 nightly. Claude's
#22803 would clean up the dead card. #21158 would make every agent message to a running Claude turn wait in the queue, so the second case becomes the default. Neither lets a Claude thread keep working while its question waits. Claude Opus 5.5 via T3 Code |
|
We have this implemented, scoped to reuse what
The branch is apophisnow/t3code |
|
+1 to apophisnow's proposal. I think it should land as is, offered to every provider and model. The agent can then choose how to ask each question. If a wrong answer would be expensive to undo, it uses a blocking question and waits. If changing course later is cheap, it uses In the second case, the user must be able to see which questions the agent asked and which recommendations it assumed. The open card could show this by marking the assumed option, so the user can correct it later. On my machine, I chose the recommended option in 46 of 67 questions. That's often enough to proceed on when a mistake is cheap, but not often enough to hide the assumption. Maintainers, can this land? The branch is stacked on #26868, which closed without merging. |


Uh oh!
There was an error while loading. Please reload this page.
Problem
Agents without a native ask-the-user tool can't reach T3's structured question card.
Claude Code gets it via
AskUserQuestion(claudeUserInputQuestionsinClaudeAdapterV2), Codex viarequestUserInputand async questions, OpenCode via itsquestiontool, and ACP agents via form elicitation (AcpAdapterV2). Pi has no native equivalent. The only path a Pi extension has into T3 isextension_ui_request, andPiAdapterV2maps everyselect/input/editordialog to exactly one question:Pi's RPC dialog carries only
title,options: string[], andtimeout, so an extension can't express several questions, per-option descriptions, or multi-select. As far as I can tell,CursorAdapterV2has no user-input path either.What already exists
t3_pending_request_list/_read/_respond, which let an agent see and answer pending user questions. Nothing lets an agent create one.CodexAdapterV2emits async questions as auser_input_requestwithresponseCapability: { type: "message" }, andOrchestratordelivers the answers as the next user message (async-answer:<requestId>), steering a running turn or resuming an idle session.McpInvocationScopealready carriesthreadId,providerSessionId, andcapabilities, so a tool call knows where to show the card and can be gated per provider.t3_thread_update([Feature]: Let the agent update its thread title once the work is actually decided #7333) is on the V2 branch.Proposal
Add
t3_pending_request_createto the t3-code MCP server:OrchestrationV2UserInputQuestion(id,header,question,options[{ label, description }],multiSelect,allowCustomAnswer,required).user_input_requestin the calling thread withresponseCapability: { type: "message" }and return immediately, telling the agent to end its turn. The answers then arrive through the same async-answer path Codex already uses.Why non-blocking
A tool that blocks until the user answers doesn't fit the Pi bridge.
piT3McpExtensionSourcesendstools/callas a plainfetchwith only the turn's abort signal, and Node's built-in fetch (undici) defaults to 300 s header and body timeouts, so a question left unanswered for more than five minutes would fail. Blocking also wouldn't survive a server restart. The message capability avoids both, lets the user answer later from mobile, and matches thet3_thread_waitpattern of not holding calls open.Alternatives considered
PiAdapterV2already special-cases thesubagenttool by name. A similar convention for questions would help only Pi and would still need a way to wait for the answer.Current workaround
A Pi extension asks each question in turn with
ctx.ui.selectoutside the TUI. It prefixes the title with[1/2 · Label]and puts option descriptions into the option strings. It works, but each question is a separate card, the title shows twice (the card header and body both come fromtitle), and there's no multi-select.Environment
T3 Code
0.0.43-preview.20260925.2234(V2 preview), Pi0.87.1, Node 22 (undici 6.24), server on Linux (WSL2), clients on web and desktop.All reactions