mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-09 19:27:45 +02:00
[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:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user