[eric] chat: superseded questions collapse to a quiet row, docked minis center in an invisible slot and can't be resize-yanked out

This commit is contained in:
ciregenz
2026-08-04 10:20:02 -07:00
parent 9cd83b7fd9
commit e958842b9c
2 changed files with 22 additions and 9 deletions
+17 -4
View File
@@ -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<AgentChatProps> = ({ 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<AgentChatProps> = ({ 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 (
<Box key={item.id} data-window-item-id={item.id} ref={isLastVisibleItem ? lastVisibleItemRef : undefined}>
<ToolCallBubble call={item.call} result={item.result} isPending={false} sessionId={session.id} suppressReveal />
{compactionChip}
</Box>
);
}
return (
<Box key={item.id} data-window-item-id={item.id} ref={isLastVisibleItem ? lastVisibleItemRef : undefined}>
<AskUiBubble pair={item} sessionId={session.id} isPending={isPending} suppressReveal={item.call.id === justStreamedId} />
@@ -2417,9 +2431,8 @@ const AgentChat: React.FC<AgentChatProps> = ({ 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.
}}
/>
)}
@@ -1095,11 +1095,11 @@ const BrowserCard: React.FC<Props> = ({
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<Props> = ({
)}
</Box>
{/* 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 }) => (
<Box
key={dir}
className="resize-handle"