Skip to content

Commit 50e17c1

Browse files
committed
🤖 feat: improve ask_user_question UX with summary page and sidebar indicators
- 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>
1 parent 0ce51fe commit 50e17c1

File tree

8 files changed

+313
-177
lines changed

8 files changed

+313
-177
lines changed

src/browser/components/AIView.tsx

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ const AIViewInner: React.FC<AIViewProps> = ({
160160
useEffect(() => {
161161
workspaceStateRef.current = workspaceState;
162162
}, [workspaceState]);
163-
const { messages, canInterrupt, isCompacting, loading, currentModel } = workspaceState;
163+
const { messages, canInterrupt, isCompacting, awaitingUserQuestion, loading, currentModel } =
164+
workspaceState;
164165

165166
// Apply message transformations:
166167
// 1. Merge consecutive identical stream errors
@@ -670,24 +671,34 @@ const AIViewInner: React.FC<AIViewProps> = ({
670671
{canInterrupt && (
671672
<StreamingBarrier
672673
statusText={
673-
isCompacting
674-
? currentModel
675-
? `${getModelName(currentModel)} compacting...`
676-
: "compacting..."
677-
: currentModel
678-
? `${getModelName(currentModel)} streaming...`
679-
: "streaming..."
674+
awaitingUserQuestion
675+
? "Awaiting your input..."
676+
: isCompacting
677+
? currentModel
678+
? `${getModelName(currentModel)} compacting...`
679+
: "compacting..."
680+
: currentModel
681+
? `${getModelName(currentModel)} streaming...`
682+
: "streaming..."
683+
}
684+
cancelText={
685+
awaitingUserQuestion
686+
? "type a message to respond"
687+
: `hit ${formatKeybind(vimEnabled ? KEYBINDS.INTERRUPT_STREAM_VIM : KEYBINDS.INTERRUPT_STREAM_NORMAL)} to cancel`
680688
}
681-
cancelText={`hit ${formatKeybind(vimEnabled ? KEYBINDS.INTERRUPT_STREAM_VIM : KEYBINDS.INTERRUPT_STREAM_NORMAL)} to cancel`}
682689
tokenCount={
683-
activeStreamMessageId
684-
? aggregator?.getStreamingTokenCount(activeStreamMessageId)
685-
: undefined
690+
awaitingUserQuestion
691+
? undefined
692+
: activeStreamMessageId
693+
? aggregator?.getStreamingTokenCount(activeStreamMessageId)
694+
: undefined
686695
}
687696
tps={
688-
activeStreamMessageId
689-
? aggregator?.getStreamingTPS(activeStreamMessageId)
690-
: undefined
697+
awaitingUserQuestion
698+
? undefined
699+
: activeStreamMessageId
700+
? aggregator?.getStreamingTPS(activeStreamMessageId)
701+
: undefined
691702
}
692703
/>
693704
)}

src/browser/components/WorkspaceListItem.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ const WorkspaceListItemInner: React.FC<WorkspaceListItemProps> = ({
9999
}
100100
};
101101

102-
const { canInterrupt } = useWorkspaceSidebarState(workspaceId);
102+
const { canInterrupt, awaitingUserQuestion } = useWorkspaceSidebarState(workspaceId);
103+
const isWorking = canInterrupt && !awaitingUserQuestion;
103104

104105
return (
105106
<React.Fragment>
@@ -167,7 +168,7 @@ const WorkspaceListItemInner: React.FC<WorkspaceListItemProps> = ({
167168
<TooltipContent align="start">Remove workspace</TooltipContent>
168169
</Tooltip>
169170
)}
170-
<RuntimeBadge runtimeConfig={metadata.runtimeConfig} isWorking={canInterrupt} />
171+
<RuntimeBadge runtimeConfig={metadata.runtimeConfig} isWorking={isWorking} />
171172
{isEditing ? (
172173
<input
173174
className="bg-input-bg text-input-text border-input-border font-inherit focus:border-input-border-focus col-span-2 min-w-0 flex-1 rounded-sm border px-1 text-left text-[13px] outline-none"
@@ -195,7 +196,7 @@ const WorkspaceListItemInner: React.FC<WorkspaceListItemProps> = ({
195196
}}
196197
title={isDisabled ? undefined : "Double-click to edit title"}
197198
>
198-
{canInterrupt || isCreating ? (
199+
{isWorking || isCreating ? (
199200
<Shimmer className="w-full truncate" colorClass="var(--color-foreground)">
200201
{displayTitle}
201202
</Shimmer>
@@ -213,7 +214,7 @@ const WorkspaceListItemInner: React.FC<WorkspaceListItemProps> = ({
213214
gitStatus={gitStatus}
214215
workspaceId={workspaceId}
215216
tooltipPosition="right"
216-
isWorking={canInterrupt}
217+
isWorking={isWorking}
217218
/>
218219
)}
219220
</div>

src/browser/components/WorkspaceStatusDot.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ export const WorkspaceStatusDot = memo<{
1111
size?: number;
1212
}>(
1313
({ workspaceId, lastReadTimestamp, onClick, size = 8 }) => {
14-
const { canInterrupt, currentModel, agentStatus, recencyTimestamp } =
14+
const { canInterrupt, awaitingUserQuestion, currentModel, agentStatus, recencyTimestamp } =
1515
useWorkspaceSidebarState(workspaceId);
1616

17-
const streaming = canInterrupt;
17+
const streaming = canInterrupt && !awaitingUserQuestion;
1818

1919
// Compute unread status if lastReadTimestamp provided (sidebar only)
2020
const unread = useMemo(() => {
@@ -27,12 +27,13 @@ export const WorkspaceStatusDot = memo<{
2727
() =>
2828
getStatusTooltip({
2929
isStreaming: streaming,
30+
isAwaitingInput: awaitingUserQuestion,
3031
streamingModel: currentModel,
3132
agentStatus,
3233
isUnread: unread,
3334
recencyTimestamp,
3435
}),
35-
[streaming, currentModel, agentStatus, unread, recencyTimestamp]
36+
[streaming, awaitingUserQuestion, currentModel, agentStatus, unread, recencyTimestamp]
3637
);
3738

3839
const bgColor = canInterrupt ? "bg-blue-400" : unread ? "bg-gray-300" : "bg-muted-dark";

src/browser/components/WorkspaceStatusIndicator.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@ import { Tooltip, TooltipTrigger, TooltipContent } from "./ui/tooltip";
55
import { Button } from "./ui/button";
66

77
export const WorkspaceStatusIndicator = memo<{ workspaceId: string }>(({ workspaceId }) => {
8-
const { agentStatus } = useWorkspaceSidebarState(workspaceId);
8+
const { agentStatus, awaitingUserQuestion } = useWorkspaceSidebarState(workspaceId);
9+
10+
// Show prompt when ask_user_question is pending - make it prominent
11+
if (awaitingUserQuestion) {
12+
return (
13+
<div className="flex min-w-0 items-center gap-1.5 rounded bg-yellow-500/20 px-1.5 py-0.5 text-xs text-yellow-400">
14+
<span className="-mt-0.5 shrink-0 text-[10px]"></span>
15+
<span className="min-w-0 truncate font-medium">Mux has a few questions</span>
16+
</div>
17+
);
18+
}
919

1020
if (!agentStatus) {
1121
return null;

0 commit comments

Comments
 (0)