-
Notifications
You must be signed in to change notification settings - Fork 30
🤖 feat: add ask_user_question interactive plan-mode tool #1121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+1,306
−67
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50e17c1 to
9647779
Compare
Member
Author
|
@codex review |
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
Change-Id: I84e7c504ff312915a9e0fdeae4e6d4e30e1d9aa1 Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I89e5cf1a21b7fd491b7f821870ddeada88be9f39 Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I9aa88d6979c49c8e68926f85e7bc82421d67dca9 Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I89dc9db6cfc514869bcb6587c1b80e3511b72bf7 Signed-off-by: Thomas Kosiewski <tk@coder.com>
…dicators - Add Summary tab showing all Q&A with status, allowing partial submissions - Stop sidebar shimmer/pulse when awaiting user input - Show "Mux has a few questions" prominent indicator in sidebar - Update bottom bar to show "Awaiting your input..." instead of streaming - Improve tab contrast: green tint for answered questions - Add Next button to navigate between questions - Display completed answers vertically with bullet points _Generated with `mux`_ Change-Id: I8142e99ba39d3237ce5dc5e5d86675c240f8a2cf Signed-off-by: Thomas Kosiewski <tk@coder.com>
The 30-minute timeout was too aggressive - users may step away and come back later. The tool now waits indefinitely for user input. It can still be canceled via: - User typing a chat message - Stream interruption (abort signal) - Workspace cleanup Signed-off-by: Thomas Kosiewski <tk@coder.com> --- _Generated with `mux`_ Change-Id: I3e5e5e9f697cc07ad8fb1cc854562d2e4b1111bf
Add optional mode parameter to getAvailableTools so ask_user_question is only advertised in plan mode, matching the runtime registration. Fixes P1 review feedback: models would otherwise invoke unavailable tool in exec mode and cause failures. Signed-off-by: Thomas Kosiewski <tk@coder.com> --- _Generated with `mux`_ Change-Id: I1e2c792bee3b0606ec0c10a18a19443d990f2091
36760d8 to
2ea7e0f
Compare
The ask_user_question tool was not being advertised to the model in plan mode because readToolInstructions wasn't passing the mode parameter. Now the mode flows through the call chain so ask_user_question appears in the tool list for plan sessions. Signed-off-by: Thomas Kosiewski <tk@coder.com> --- _Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_ Change-Id: I09b446ee61d090d0979ce5010928e457efbde657
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Adds a new interactive plan-mode tool
ask_user_question(inspired by Claude Code'sAskUserQuestion) and a corresponding inline UI for answering multiple-choice questions.Key behaviors:
tool-error) and the message is sent as a real user message.Validation:
make static-check📋 Implementation Plan
🤖 Plan: Add an
AskUserQuestion-style tool to Mux (Plan Mode UX)Goal
Implement a tool compatible with Claude Code’s
AskUserQuestionsemantics (percc-plan-mode.md) so that, while staying in plan mode, the assistant can ask the user 1–4 multiple-choice questions and receive structured answers.Key UX requirement: the question UI should be non-invasive and optional—the user is encouraged to answer via the form, but they should also be able to just type a normal chat reply without having to explicitly “close/deny” the UI.
Source-of-truth behavior to mirror (from
cc-plan-mode.md)We should match the Claude Code behavior + schema as closely as practical, while using Mux’s snake_case naming convention:
AskUserQuestionask_user_question{ questions: Question[], answers?: Record<string,string> }{ questions: Question[], answers: Record<string,string> }optionsinput)What already exists in Mux (relevant implementation hooks)
src/browser/components/Messages/ToolMessage.tsx, which routes known tools to custom React components; otherwise it falls back toGenericToolCall.src/browser/components/tools/shared/ToolPrimitives.tsx+toolUtils.tsx.src/browser/components/ui/toggle-group.tsx(Radix ToggleGroup; supportstype="single"|"multiple")src/browser/components/ui/checkbox.tsxsrc/browser/components/ui/input.tsxsrc/browser/components/ui/button.tsxsrc/common/utils/tools/toolDefinitions.ts(Zod schema + description); backend tools reference this.src/node/services/tools/*and are registered throughsrc/common/utils/tools/tools.ts(getToolsForModel).dynamic-toolparts; while a tool is running it’sstate: "input-available"and UI status becomes"executing".Recommended approach (single approach; net new product LoC ~500–900)
Summary
Add a new interactive tool
ask_user_question(CC-compatibleAskUserQuestion) that:Backend design
1) Tool definition (shared)
ask_user_questiontoTOOL_DEFINITIONSwith a Zod schema matchingcc-plan-mode.md:AskUserQuestionOptionSchema,AskUserQuestionQuestionSchema) so the result schema + UI types can reuse them.Option:{ label: string; description: string }Question:{ question: string; header: string; options: Option[]; multiSelect: boolean }{ questions: Question[]; answers?: Record<string,string> }+ refine uniqueness{ questions: Question[]; answers: Record<string,string> }TypeScript types: infer from Zod (avoid handwritten interfaces) to prevent drift.
export type AskUserQuestionToolArgs = z.infer<typeof TOOL_DEFINITIONS.ask_user_question.schema>;AskUserQuestionToolResultSchema(Zod) alongside the input schema (reusing the sameQuestion/Optionschemas), then:export type AskUserQuestionToolResult = z.infer<typeof AskUserQuestionToolResultSchema>;AskUserQuestionQuestion/AskUserQuestionOptionviaz.infer<...>for the UI reducer.2) Pending-question manager (new node service)
Create an in-memory manager owned by the backend process (NOT persisted):
AskUserQuestionManagerregisterPending(workspaceId, toolCallId, questions): Promise<Record<string,string>>answer(workspaceId, toolCallId, answers): voidcancel(workspaceId, toolCallId, reason): voidgetLatestPending(workspaceId): { toolCallId, questions } | nullImportant defensive behavior:
3) Tool implementation (
src/node/services/tools/ask_user_question.ts)Implement
createAskUserQuestionTool(config)usingtool()fromai.Execution flow:
workspaceIdfromconfig.workspaceId(assert present).toolCallIdfromToolCallOptions.toolCallId.AskUserQuestionManagerand await answers.{ questions, answers }(matching Claude Code’s output schema).Abort/cancel handling:
tool-errorpart (Mux will record this as a failed tool result).Model-context parity (optional but recommended):
applyToolOutputRedaction(...)to replace the provider-facing output forask_user_questionwith a short string summary like:User has answered your questions: "<Q>"="<A>", ... You can now continue with the user's answers in mind.{ questions, answers }persisted for UI.4) ORPC endpoint to submit answers
Add a workspace-scoped ORPC endpoint:
workspace.answerAskUserQuestion{ workspaceId: string; toolCallId: string; answers: Record<string,string> }Result<void, string>Implementation:
WorkspaceService→AskUserQuestionManager.answer(...).5) “Chat message instead of clicking” behavior (non-invasive requirement)
Requirement (confirmed): if the user just types a normal chat reply while
ask_user_questionis pending, we should not treat it as tool input. Instead we should:Implementation sketch:
AskUserQuestionManager.getLatestPending(workspaceId)(orgetPendingByToolCallId) that returns the active pending prompt.WorkspaceService.sendMessage()behavior:aiService.isStreaming(workspaceId)and a pendingask_user_questionexists:AskUserQuestionManager.cancel(workspaceId, toolCallId, "User responded in chat; questions canceled")session.queueMessage(message, options))Ok()Effect:
tool-error→ Mux records a failed tool result.Frontend design
1) Add a custom tool renderer
Add
AskUserQuestionToolCall.tsxundersrc/browser/components/tools/and route it inToolMessage.tsxsimilarly toProposePlanToolCall.Props needed:
args,result,status,workspaceId2) UI behavior (inline form)
Render as an inline tool card, expanded by default while awaiting answers:
ask_user_question+ statusheader, with a checkmark for answered.ToggleGroup type="single"Checkboxlist orToggleGroup type="multiple"Inputfor custom textSubmit answersbutton → callsapi.workspace.answerAskUserQuestion({ workspaceId, toolCallId, answers })State management:
currentQuestionIndex,answers,questionStates,isInTextInput).Accessibility/keyboard (follow-up, but planned):
3) Display after completion
When
resultis present:4) Non-invasive encouragement
While the tool is pending:
(We can later refine this into a better “waiting for input” streaming banner, but it’s not required for v1.)
Testing / validation (net new test LoC ~250–450)
AskUserQuestionManager:ask_user_questiontool callAlternatives considered
A) Non-blocking “suggestion card” tool (net new product LoC ~300–600)
Have
ask_user_questionreturn immediately and not pause the stream; user answers later and the answer is posted as a normal user message.Downside: this diverges from Claude Code semantics and won’t behave like the tool LLMs were trained on (tool answers won’t be available in the same turn).
Decisions / requirements confirmed
ask_user_questionis pending:ask_user_question(snake_case).Availability / gating
ask_user_questiononly whenSendMessageOptions.mode === "plan"(so it is available by default in plan mode, and not callable in exec mode).AIService.streamMessage()passesmodeinto the earlygetToolsForModel(...)call used for the mode-transition “Available tools: …” sentinel. Otherwise plan mode would omitask_user_questionfrom the advertised tool list even though it’s registered.ask_user_questiontool parts (no toggle).Net new product code estimate (recommended approach): ~500–900 LoC
Generated with
mux• Model:anthropic:claude-opus-4-5• Thinking:high