From e958842b9c30e37216b2dec7f4912cf78e092249 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Tue, 4 Aug 2026 10:20:02 -0700 Subject: [PATCH] [eric] chat: superseded questions collapse to a quiet row, docked minis center in an invisible slot and can't be resize-yanked out --- .../src/app/pages/AgentChat/AgentChat.tsx | 21 +++++++++++++++---- .../app/pages/Dashboard/cards/BrowserCard.tsx | 10 ++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/pages/AgentChat/AgentChat.tsx b/frontend/src/app/pages/AgentChat/AgentChat.tsx index 45d5ded4..ccf3b407 100644 --- a/frontend/src/app/pages/AgentChat/AgentChat.tsx +++ b/frontend/src/app/pages/AgentChat/AgentChat.tsx @@ -63,7 +63,7 @@ import ToolCallBubble, { ToolPair } from './tool-bubbles/ToolCallBubble'; import ToolGroupBubble, { RenderItem, ToolGroup, ToolGroupEntry, isToolGroup, isToolPair } from './tool-bubbles/ToolGroupBubble'; import ToolUiBubble from './tool-ui/ToolUiBubble'; import AskUiBubble from './tool-ui/AskUiBubble'; -import { isShowUiPair, isAskUiPair } from './tool-ui/showUiPayload'; +import { isShowUiPair, isAskUiPair, extractPendingAskUi } from './tool-ui/showUiPayload'; import ApprovalBar, { BatchApprovalBar } from './shell/ApprovalBar'; import ForceStopAgentBar from './ForceStopAgentBar'; import { RateLimitPill } from './shell/RateLimitPill'; @@ -1062,6 +1062,10 @@ const AgentChat: React.FC = ({ sessionId: sessionIdProp, onClose }, [activeBranchMessages, session?.system_prompt, session?.tokens?.input, session?.context_window, streamingMessageId, model, modelsByProvider]); const sessionRunning = session?.status === 'running' || session?.status === 'waiting_approval'; + const lastPendingAskCallId = useMemo( + () => extractPendingAskUi(session?.messages || [])?.call.id ?? null, + [session?.messages], + ); const renderItems: RenderItem[] = useMemo(() => { const items: RenderItem[] = []; @@ -1717,6 +1721,16 @@ const AgentChat: React.FC = ({ sessionId: sessionIdProp, onClose if (isToolPair(item)) { const isPending = item.result === null && sessionRunning; if (isAskUiPair(item)) { + // Only the LATEST unanswered question is live (the backend parks one component); an + // older pending ask renders as a quiet row instead of a second clickable form. + if (item.result === null && lastPendingAskCallId !== null && item.call.id !== lastPendingAskCallId) { + return ( + + + {compactionChip} + + ); + } return ( @@ -2417,9 +2431,8 @@ const AgentChat: React.FC = ({ sessionId: sessionIdProp, onClose minHeight: 180, mx: 1.5, mb: 1, - borderRadius: '10px', - border: `1px dashed ${c.border.medium}`, - background: c.bg.secondary, + // Pure geometry: the docked mini overlays this rect, so any visible chrome here + // (the old dashed outline) just framed the letterbox margins as an ugly gap. }} /> )} diff --git a/frontend/src/app/pages/Dashboard/cards/BrowserCard.tsx b/frontend/src/app/pages/Dashboard/cards/BrowserCard.tsx index f4040a77..473b3a48 100644 --- a/frontend/src/app/pages/Dashboard/cards/BrowserCard.tsx +++ b/frontend/src/app/pages/Dashboard/cards/BrowserCard.tsx @@ -1095,11 +1095,11 @@ const BrowserCard: React.FC = ({ contain: 'layout style', // Own compositor layer so hover/paint invalidations stay contained to this card. See AgentCard for full rationale. willChange: 'transform', - left: keepAliveHidden || isMinimized || dockParked ? -100000 : (dockActive ? dockRect!.x : (dragging ? cardX : displayX)), - top: dockActive ? dockRect!.y : (dragging ? cardY : displayY), // Docked = a TRUE miniature: the card keeps its full-size layout and shrinks by uniform - // transform, so the page never reflows and the agent's position-based clicks stay valid. + // transform (centered in the slot), so the page never reflows and agent clicks stay valid. // Resizing the webview to the slot re-rendered the page as a narrow window, which is wrong. + left: keepAliveHidden || isMinimized || dockParked ? -100000 : (dockActive ? dockRect!.x + (dockRect!.w - displayW * Math.min(dockRect!.w / displayW, dockRect!.h / displayH)) / 2 : (dragging ? cardX : displayX)), + top: dockActive ? dockRect!.y + (dockRect!.h - displayH * Math.min(dockRect!.w / displayW, dockRect!.h / displayH)) / 2 : (dragging ? cardY : displayY), transform: tiledSize ? undefined : (dragging ? `translate3d(${dragTx}px, ${dragTy}px, 0)` : dockActive ? `scale(${Math.min(dockRect!.w / displayW, dockRect!.h / displayH)})` : undefined), transformOrigin: tiledSize || dockActive ? '0 0' : undefined, width: tiledSize ? tiledSize.width : displayW, @@ -1834,8 +1834,8 @@ const BrowserCard: React.FC = ({ )} - {/* Resize handles */} - {HANDLE_DEFS.map(({ dir, sx }) => ( + {/* Resize handles; a docked mini's size follows the slot, so grabbing an edge used to pop it out of the chat mid-gesture. */} + {!dockActive && HANDLE_DEFS.map(({ dir, sx }) => (