| author | |
| committer | |
| log | 3f62e6fa65c2a2a91a367be4ee95da1b50007bde |
| tree | 7324e9dfd92c915133c35d1d2104c15a0d3dbfd3 |
| parent | 9842518c9a0af14fb3a3e90993692a6e34032682 |
| signature | Signed by PGP key B5690EEEBB952194 |
4 files changed, 6 insertions(+), 36 deletions(-)
apps/web/src/components/ChatView.tsx-16| ... | @@ -2435,21 +2435,6 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -2435,21 +2435,6 @@ function ChatViewContent(props: ChatViewProps) { |
| 2435 | () => deriveActivePlanState(threadActivities, activeLatestTurn?.turnId ?? undefined), | 2435 | () => deriveActivePlanState(threadActivities, activeLatestTurn?.turnId ?? undefined), |
| 2436 | [activeLatestTurn?.turnId, threadActivities], | 2436 | [activeLatestTurn?.turnId, threadActivities], |
| 2437 | ); | 2437 | ); |
| 2438 | // Current step for the in-chat working row: only for the running turn's own | ||
| 2439 | // plan (deriveActivePlanState falls back to older turns' plans, which must | ||
| 2440 | // not label fresh work). Falls back to the first pending step so an | ||
| 2441 | // all-pending freshly written plan labels the row, matching the composer and | ||
| 2442 | // the server's planProgress. | ||
| 2443 | const workingStepLabel = useMemo(() => { | ||
| 2444 | if (!activePlan || activePlan.turnId !== (activeLatestTurn?.turnId ?? null)) { | ||
| 2445 | return null; | ||
| 2446 | } | ||
| 2447 | return ( | ||
| 2448 | activePlan.steps.find((step) => step.status === "inProgress")?.step ?? | ||
| 2449 | activePlan.steps.find((step) => step.status === "pending")?.step ?? | ||
| 2450 | null | ||
| 2451 | ); | ||
| 2452 | }, [activeLatestTurn?.turnId, activePlan]); | ||
| 2453 | const showPlanFollowUpPrompt = shouldShowPlanFollowUpPrompt({ | 2438 | const showPlanFollowUpPrompt = shouldShowPlanFollowUpPrompt({ |
| 2454 | pendingUserInputCount: pendingUserInputs.length, | 2439 | pendingUserInputCount: pendingUserInputs.length, |
| 2455 | interactionMode, | 2440 | interactionMode, |
| ... | @@ -7240,7 +7225,6 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -7240,7 +7225,6 @@ function ChatViewContent(props: ChatViewProps) { |
| 7240 | onOpenAgents={addAgentsSurface} | 7225 | onOpenAgents={addAgentsSurface} |
| 7241 | key={activeThread.id} | 7226 | key={activeThread.id} |
| 7242 | isWorking={isWorking} | 7227 | isWorking={isWorking} |
| 7243 | workingStepLabel={workingStepLabel} | ||
| 7244 | activeTurnStartedAt={activeWorkStartedAt} | 7228 | activeTurnStartedAt={activeWorkStartedAt} |
| 7245 | listRef={legendListRef} | 7229 | listRef={legendListRef} |
| 7246 | timelineEntries={timelineEntries} | 7230 | timelineEntries={timelineEntries} |
apps/web/src/components/chat/ChatComposer.tsx+1-8| ... | @@ -3439,14 +3439,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) | ... | @@ -3439,14 +3439,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) |
| 3439 | /> | 3439 | /> |
| 3440 | {!activityStackItem && (props.threadSyncPhase || inlineTasksBadge) ? ( | 3440 | {!activityStackItem && (props.threadSyncPhase || inlineTasksBadge) ? ( |
| 3441 | <ComposerBanner.Attachment> | 3441 | <ComposerBanner.Attachment> |
| 3442 | <ComposerBanner.Root | 3442 | <ComposerBanner.Root data-chat-composer-activity-strip="true"> |
| 3443 | width={ | ||
| 3444 | props.threadSyncPhase && !showComposerTopDrawer && !isComposerCollapsedMobile | ||
| 3445 | ? "content" | ||
| 3446 | : "fill" | ||
| 3447 | } | ||
| 3448 | data-chat-composer-activity-strip="true" | ||
| 3449 | > | ||
| 3450 | {props.threadSyncPhase ? ( | 3443 | {props.threadSyncPhase ? ( |
| 3451 | <ComposerActivityRow phase={props.threadSyncPhase} /> | 3444 | <ComposerActivityRow phase={props.threadSyncPhase} /> |
| 3452 | ) : ( | 3445 | ) : ( |
apps/web/src/components/chat/MessagesTimeline.tsx+1-12| ... | @@ -171,8 +171,6 @@ interface TimelineRowActivityState { | ... | @@ -171,8 +171,6 @@ interface TimelineRowActivityState { |
| 171 | isWorking: boolean; | 171 | isWorking: boolean; |
| 172 | isRevertingCheckpoint: boolean; | 172 | isRevertingCheckpoint: boolean; |
| 173 | latestTurnId: TurnId | null; | 173 | latestTurnId: TurnId | null; |
| 174 | /** Current plan step label for the working row, when the turn has a plan. */ | ||
| 175 | workingStepLabel: string | null; | ||
| 176 | } | 174 | } |
| 177 | 175 | ||
| 178 | const TimelineRowCtx = createContext<TimelineRowSharedState>(null!); | 176 | const TimelineRowCtx = createContext<TimelineRowSharedState>(null!); |
| ... | @@ -227,7 +225,6 @@ interface MessagesTimelineProps { | ... | @@ -227,7 +225,6 @@ interface MessagesTimelineProps { |
| 227 | agentPanelModel?: AgentPanelModel; | 225 | agentPanelModel?: AgentPanelModel; |
| 228 | onOpenAgents?: () => void; | 226 | onOpenAgents?: () => void; |
| 229 | isWorking: boolean; | 227 | isWorking: boolean; |
| 230 | workingStepLabel?: string | null; | ||
| 231 | activeTurnStartedAt: string | null; | 228 | activeTurnStartedAt: string | null; |
| 232 | listRef: React.RefObject<LegendListRef | null>; | 229 | listRef: React.RefObject<LegendListRef | null>; |
| 233 | timelineEntries: ReturnType<typeof deriveTimelineEntries>; | 230 | timelineEntries: ReturnType<typeof deriveTimelineEntries>; |
| ... | @@ -273,7 +270,6 @@ interface MessagesTimelineProps { | ... | @@ -273,7 +270,6 @@ interface MessagesTimelineProps { |
| 273 | 270 | ||
| 274 | export const MessagesTimeline = memo(function MessagesTimeline({ | 271 | export const MessagesTimeline = memo(function MessagesTimeline({ |
| 275 | isWorking, | 272 | isWorking, |
| 276 | workingStepLabel = null, | ||
| 277 | activeTurnStartedAt, | 273 | activeTurnStartedAt, |
| 278 | agentPanelModel = EMPTY_AGENT_PANEL_MODEL, | 274 | agentPanelModel = EMPTY_AGENT_PANEL_MODEL, |
| 279 | onOpenAgents = NOOP_OPEN_AGENTS, | 275 | onOpenAgents = NOOP_OPEN_AGENTS, |
| ... | @@ -583,9 +579,8 @@ export const MessagesTimeline = memo(function MessagesTimeline({ | ... | @@ -583,9 +579,8 @@ export const MessagesTimeline = memo(function MessagesTimeline({ |
| 583 | isWorking, | 579 | isWorking, |
| 584 | isRevertingCheckpoint, | 580 | isRevertingCheckpoint, |
| 585 | latestTurnId: latestTurn?.turnId ?? null, | 581 | latestTurnId: latestTurn?.turnId ?? null, |
| 586 | workingStepLabel, | ||
| 587 | }), | 582 | }), |
| 588 | [isRevertingCheckpoint, isWorking, latestTurn?.turnId, workingStepLabel], | 583 | [isRevertingCheckpoint, isWorking, latestTurn?.turnId], |
| 589 | ); | 584 | ); |
| 590 | 585 | ||
| 591 | // Stable renderItem — no closure deps. Row components read shared state | 586 | // Stable renderItem — no closure deps. Row components read shared state |
| ... | @@ -1323,7 +1318,6 @@ function ProposedPlanTimelineRow({ | ... | @@ -1323,7 +1318,6 @@ function ProposedPlanTimelineRow({ |
| 1323 | } | 1318 | } |
| 1324 | 1319 | ||
| 1325 | function WorkingTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "working" }> }) { | 1320 | function WorkingTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "working" }> }) { |
| 1326 | const { workingStepLabel } = use(TimelineRowActivityCtx); | ||
| 1327 | return ( | 1321 | return ( |
| 1328 | <div> | 1322 | <div> |
| 1329 | <div className="border-b border-border/60 pb-2 pt-1"> | 1323 | <div className="border-b border-border/60 pb-2 pt-1"> |
| ... | @@ -1337,11 +1331,6 @@ function WorkingTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "workin | ... | @@ -1337,11 +1331,6 @@ function WorkingTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "workin |
| 1337 | "Working..." | 1331 | "Working..." |
| 1338 | )} | 1332 | )} |
| 1339 | </span> | 1333 | </span> |
| 1340 | {workingStepLabel ? ( | ||
| 1341 | <span className="ml-2 min-w-0 truncate text-muted-foreground/55"> | ||
| 1342 | · {workingStepLabel} | ||
| 1343 | </span> | ||
| 1344 | ) : null} | ||
| 1345 | </div> | 1334 | </div> |
| 1346 | </div> | 1335 | </div> |
| 1347 | {row.showThinking ? ( | 1336 | {row.showThinking ? ( |
docs/user/composer.md+4| ... | @@ -37,6 +37,10 @@ when starting a thread or changing an existing thread's model. | ... | @@ -37,6 +37,10 @@ when starting a thread or changing an existing thread's model. |
| 37 | 37 | ||
| 38 | ## Notices above the composer | 38 | ## Notices above the composer |
| 39 | 39 | ||
| 40 | On web and desktop, loading and syncing statuses fill the available banner width beside the | ||
| 41 | stash tab. Task progress appears above the composer, while the timeline's working timer shows | ||
| 42 | only elapsed time. | ||
| 43 | |||
| 40 | On web and desktop, additional notices peek out above the attached banner. Hover over the peek | 44 | On web and desktop, additional notices peek out above the attached banner. Hover over the peek |
| 41 | to reveal them, or focus **Show other notices** with `Tab` and press `Enter` or `Space`. Press | 45 | to reveal them, or focus **Show other notices** with `Tab` and press `Enter` or `Space`. Press |
| 42 | `Escape` to close the stack and return focus to that control. On a touchscreen, tap the peek to | 46 | `Escape` to close the stack and return focus to that control. On a touchscreen, tap the peek to |