@tangle-network/ui 7.0.0 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 8.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 79b55f5: Converge the two transcripts on one collapsible run. New `AssistantRunShell` primitive (the header · summary · status pill · chevron · Radix collapse extracted from `RunGroup`) is now used by both `RunGroup` and `AgentTimeline`, so there is one implementation of "an assistant run" instead of two divergent ones. `AgentTimeline` folds consecutive tool / tool-group items into that shell (`collapsibleToolRuns`, default on; `defaultToolRunsOpen`, default open) so a burst of tool activity reads as one toggleable step on the timeline spine instead of a long ladder of rows — matching `RunGroup`. Additive: `AgentTimeline`'s `items[]` API is unchanged and folding happens internally; consumers building their own item arrays keep working.
8
+
9
+ ## 8.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - 831e935: One composer, no zombie API. `ChatInput` is deleted — the canonical composer is `AgentComposer` in `@tangle-network/sandbox-ui`, composed below the transcript by the app. `ChatContainer` is now transcript-only: the input props (`onSend`, `onCancel`, `placeholder`, `hideInput`, `modelLabel`, `onModelClick`, `pendingFiles`, `onRemoveFile`, `onAttach`, `disabled`) and the `PendingFile` type are removed. `ChatMessage` drops the no-op `avatar`/`hideAvatar` props. `ToolCallStep`/`ToolCallGroup` are no longer exported (internal adapters over `InlineToolItem`); the `ToolCallType`/`ToolCallStatus` types stay public via `ToolCallData`, and `ToolCallFeed` is unchanged.
14
+
3
15
  ## 7.0.0
4
16
 
5
17
  ### Minor Changes
package/dist/chat.d.ts CHANGED
@@ -7,83 +7,23 @@ import { AgentBranding } from './types.js';
7
7
  import { C as CustomToolRenderer } from './tool-display-z4JcDmMQ.js';
8
8
  import { R as Run, G as GroupedMessage } from './run-PfLmDAox.js';
9
9
  import { OpenUIAction } from './openui.js';
10
- import { T as ToolCallData } from './tool-call-feed-Bs3MyQMT.js';
10
+ import { T as ToolCallData } from './tool-call-feed-D9iofJgW.js';
11
11
 
12
12
  /**
13
- * ChatInput message input bar with file attach, drag-and-drop, send/cancel.
14
- *
15
- * - Auto-resizing textarea (up to max height)
16
- * - Enter to send, Shift+Enter for newline
17
- * - Drag-and-drop files onto the input with styled overlay
18
- * - File attachment button (files) + folder attachment button
19
- * - Pending file/folder chips
20
- * - Cancel button when streaming
21
- * - Optional model selector pill
13
+ * Transcript-only container: message list + auto-scroll. Composers are
14
+ * composed BELOW this by the app (the canonical one is `AgentComposer` in
15
+ * `@tangle-network/sandbox-ui`) this component never renders an input.
22
16
  */
23
- interface PendingFile {
24
- id: string;
25
- name: string;
26
- size: number;
27
- type: "file" | "folder";
28
- /** Number of files inside (for folders) */
29
- fileCount?: number;
30
- status: "pending" | "uploading" | "ready" | "error";
31
- }
32
- interface ChatInputProps {
33
- onSend: (message: string, files?: File[]) => void;
34
- onCancel?: () => void;
35
- isStreaming?: boolean;
36
- disabled?: boolean;
37
- placeholder?: string;
38
- /** Currently selected model label */
39
- modelLabel?: string;
40
- onModelClick?: () => void;
41
- /** Pending uploaded files */
42
- pendingFiles?: PendingFile[];
43
- onRemoveFile?: (id: string) => void;
44
- /** Called when files are attached (via button or drag-and-drop) */
45
- onAttach?: (files: FileList) => void;
46
- /** Called when a folder is selected via the folder button */
47
- onAttachFolder?: (files: FileList) => void;
48
- /** Accepted file types for the file input (e.g. ".pdf,.csv") */
49
- accept?: string;
50
- /** Drop zone overlay title */
51
- dropTitle?: string;
52
- /** Drop zone overlay description */
53
- dropDescription?: string;
54
- className?: string;
55
- /** Label above the input. Set to null to hide. Default: "Agent Command Deck" */
56
- inputLabel?: string | null;
57
- /** Status text shown when idle. Set to null to hide. Default: "Ready for next instruction" */
58
- idleStatus?: string | null;
59
- /** Status text shown when streaming. Set to null to hide. Default: "Streaming response" */
60
- streamingStatus?: string | null;
61
- /** Hide the Cmd+L focus shortcut hint */
62
- hideShortcutHint?: boolean;
63
- }
64
- declare function ChatInput({ onSend, onCancel, isStreaming, disabled, placeholder, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, onAttachFolder, accept, dropTitle, dropDescription, className, inputLabel, idleStatus, streamingStatus, hideShortcutHint, }: ChatInputProps): react_jsx_runtime.JSX.Element;
65
-
66
17
  interface ChatContainerProps {
67
18
  messages: SessionMessage[];
68
19
  partMap: Record<string, SessionPart[]>;
69
20
  isStreaming: boolean;
70
- onSend?: (text: string) => void;
71
- onCancel?: () => void;
72
21
  branding?: AgentBranding;
73
- placeholder?: string;
74
22
  className?: string;
75
- /** Hide the input area (useful for read-only views). */
76
- hideInput?: boolean;
77
23
  /** Custom renderer for tool details. Return ReactNode to override, null to use default. */
78
24
  renderToolDetail?: CustomToolRenderer;
79
25
  /** Presentation mode for the session view. */
80
26
  presentation?: "runs" | "timeline";
81
- modelLabel?: string;
82
- onModelClick?: () => void;
83
- pendingFiles?: PendingFile[];
84
- onRemoveFile?: (id: string) => void;
85
- onAttach?: (files: FileList) => void;
86
- disabled?: boolean;
87
27
  /** Callback when an OpenUI action button is pressed within inline OpenUI blocks. */
88
28
  onOpenUIAction?: (action: OpenUIAction) => void;
89
29
  /** Enable rendering OpenUI schemas inline in the chat timeline. Defaults to true. */
@@ -100,10 +40,10 @@ interface ChatContainerProps {
100
40
  }) => ReactNode;
101
41
  }
102
42
  /**
103
- * Full chat container: message list + auto-scroll + input area.
43
+ * Chat transcript container: message list + auto-scroll.
104
44
  * Orchestrates useRunGroups, useRunCollapseState, and useAutoScroll.
105
45
  */
106
- declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, onSend, onCancel, branding, placeholder, className, hideInput, renderToolDetail, presentation, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, disabled, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
46
+ declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, branding, className, renderToolDetail, presentation, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
107
47
 
108
48
  interface MessageListProps {
109
49
  groups: GroupedMessage[];
@@ -158,10 +98,6 @@ interface ChatMessageProps {
158
98
  assistantLabel?: string;
159
99
  /** Hide the role label row entirely */
160
100
  hideRoleLabel?: boolean;
161
- /** @deprecated Avatars were removed from the bubble design; this prop is ignored. */
162
- hideAvatar?: boolean;
163
- /** @deprecated Avatars were removed from the bubble design; this prop is ignored. */
164
- avatar?: ReactNode;
165
101
  }
166
102
  declare function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, className, userLabel, assistantLabel, hideRoleLabel, }: ChatMessageProps): react_jsx_runtime.JSX.Element;
167
103
 
@@ -221,12 +157,21 @@ interface AgentTimelineProps {
221
157
  isThinking?: boolean;
222
158
  emptyState?: ReactNode;
223
159
  className?: string;
160
+ /**
161
+ * Fold consecutive tool / tool-group items into one collapsible run shell
162
+ * (the same `AssistantRunShell` `RunGroup` uses), so a burst of tool activity
163
+ * reads as a single toggleable step instead of a long ladder of rows.
164
+ * Default true; pass false for the flat one-row-per-tool timeline.
165
+ */
166
+ collapsibleToolRuns?: boolean;
167
+ /** Start collapsed tool runs open (true) or collapsed (false). Default open. */
168
+ defaultToolRunsOpen?: boolean;
224
169
  }
225
170
  /**
226
171
  * AgentTimeline — unified mixed-content timeline for agent-backed sandbox
227
172
  * sessions. Renders messages, tool steps, status cards, and artifact handoffs in
228
173
  * a single execution narrative.
229
174
  */
230
- declare function AgentTimeline({ items, isThinking, emptyState, className, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
175
+ declare function AgentTimeline({ items, isThinking, emptyState, className, collapsibleToolRuns, defaultToolRunsOpen, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
231
176
 
232
- export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ChatContainer, type ChatContainerProps, ChatInput, type ChatInputProps, ChatMessage, type ChatMessageProps, MessageList, type MessageListProps, type MessageRole, type PendingFile, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps };
177
+ export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, MessageList, type MessageListProps, type MessageRole, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps };
package/dist/chat.js CHANGED
@@ -1,14 +1,13 @@
1
1
  import {
2
2
  AgentTimeline,
3
3
  ChatContainer,
4
- ChatInput,
5
4
  ChatMessage,
6
5
  MessageList,
7
6
  ThinkingIndicator,
8
7
  UserMessage
9
- } from "./chunk-5CS3I7Y3.js";
8
+ } from "./chunk-QUAU6ZNC.js";
10
9
  import "./chunk-AZWDI2JG.js";
11
- import "./chunk-QIRVZMQY.js";
10
+ import "./chunk-C3BIVG72.js";
12
11
  import "./chunk-RKQDBRTC.js";
13
12
  import "./chunk-ULDNFLIM.js";
14
13
  import "./chunk-AAUNOHVL.js";
@@ -22,7 +21,6 @@ import "./chunk-RQHJBTEU.js";
22
21
  export {
23
22
  AgentTimeline,
24
23
  ChatContainer,
25
- ChatInput,
26
24
  ChatMessage,
27
25
  MessageList,
28
26
  ThinkingIndicator,
@@ -108,14 +108,68 @@ var InlineThinkingItem = memo(
108
108
  );
109
109
  InlineThinkingItem.displayName = "InlineThinkingItem";
110
110
 
111
+ // src/run/assistant-run-shell.tsx
112
+ import * as Collapsible2 from "@radix-ui/react-collapsible";
113
+ import { ChevronDown, ChevronRight as ChevronRight2, Loader2, Sparkles } from "lucide-react";
114
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
115
+ function AssistantRunShell({
116
+ label,
117
+ summary,
118
+ collapsedPreview,
119
+ badges,
120
+ isStreaming,
121
+ collapsed,
122
+ onToggle,
123
+ headerActions,
124
+ children,
125
+ className
126
+ }) {
127
+ return /* @__PURE__ */ jsx2(Collapsible2.Root, { open: !collapsed, onOpenChange: () => onToggle(), children: /* @__PURE__ */ jsxs2(
128
+ "div",
129
+ {
130
+ className: cn(
131
+ "rounded-[28px] border border-[var(--border-subtle)] bg-[var(--bg-card)] shadow-none",
132
+ className
133
+ ),
134
+ children: [
135
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-3 px-3 py-2.5", children: [
136
+ /* @__PURE__ */ jsx2(Collapsible2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx2(
137
+ "button",
138
+ {
139
+ type: "button",
140
+ className: "w-full rounded-[20px] bg-transparent px-0 py-0 text-left transition-colors hover:bg-transparent",
141
+ children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
142
+ /* @__PURE__ */ jsx2("span", { className: "font-semibold text-foreground text-sm", children: label }),
143
+ summary ? /* @__PURE__ */ jsx2("span", { className: "text-[11px] text-muted-foreground", children: summary }) : null,
144
+ collapsed && collapsedPreview ? /* @__PURE__ */ jsx2("span", { className: "min-w-0 truncate text-[11px] text-foreground/70", children: collapsedPreview }) : null,
145
+ /* @__PURE__ */ jsxs2("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
146
+ badges,
147
+ isStreaming ? /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-1 rounded-full border border-[var(--border-accent)] bg-[var(--accent-surface-soft)] px-2 py-px text-[10px] font-semibold uppercase text-[var(--accent-text)]", children: [
148
+ /* @__PURE__ */ jsx2(Loader2, { className: "h-2.5 w-2.5 animate-spin" }),
149
+ "Running"
150
+ ] }) : /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-1 rounded-full border border-border px-2 py-px text-[10px] font-semibold uppercase text-muted-foreground", children: [
151
+ /* @__PURE__ */ jsx2(Sparkles, { className: "h-2.5 w-2.5" }),
152
+ "Done"
153
+ ] }),
154
+ collapsed ? /* @__PURE__ */ jsx2(ChevronRight2, { className: "h-3.5 w-3.5 text-muted-foreground" }) : /* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
155
+ ] })
156
+ ] })
157
+ }
158
+ ) }),
159
+ headerActions ? /* @__PURE__ */ jsx2("div", { className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1", children: headerActions }) : null
160
+ ] }),
161
+ collapsed && collapsedPreview ? /* @__PURE__ */ jsx2("div", { className: "line-clamp-2 px-4 pb-4 text-sm leading-6 text-muted-foreground", children: collapsedPreview }) : null,
162
+ /* @__PURE__ */ jsx2(Collapsible2.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx2("div", { className: "border-t border-[var(--border-subtle)] px-4 pb-4 pt-3", children }) })
163
+ ]
164
+ }
165
+ ) });
166
+ }
167
+
111
168
  // src/run/run-group.tsx
112
169
  import { memo as memo2, useMemo } from "react";
113
- import * as Collapsible2 from "@radix-ui/react-collapsible";
114
170
  import {
115
171
  Bot,
116
- Loader2,
117
- ChevronDown,
118
- ChevronRight as ChevronRight2,
172
+ Loader2 as Loader22,
119
173
  Terminal,
120
174
  FileEdit,
121
175
  FileSearch,
@@ -123,10 +177,9 @@ import {
123
177
  PencilLine,
124
178
  Globe,
125
179
  ClipboardList,
126
- Settings,
127
- Sparkles
180
+ Settings
128
181
  } from "lucide-react";
129
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
182
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
130
183
  var DEFAULT_BRANDING = {
131
184
  label: "Agent",
132
185
  accentClass: "text-primary",
@@ -142,15 +195,15 @@ function AssistantShell({
142
195
  isStreaming,
143
196
  children
144
197
  }) {
145
- return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-1", children: [
146
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-1 font-medium text-muted-foreground text-xs", children: [
147
- /* @__PURE__ */ jsx2("span", { children: branding.label }),
148
- isStreaming ? /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-1.5", children: [
149
- /* @__PURE__ */ jsx2(Loader2, { className: "h-3 w-3 animate-spin" }),
198
+ return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-1", children: [
199
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-1 font-medium text-muted-foreground text-xs", children: [
200
+ /* @__PURE__ */ jsx3("span", { children: branding.label }),
201
+ isStreaming ? /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1.5", children: [
202
+ /* @__PURE__ */ jsx3(Loader22, { className: "h-3 w-3 animate-spin" }),
150
203
  "Thinking"
151
204
  ] }) : null
152
205
  ] }),
153
- /* @__PURE__ */ jsx2("div", { className: ASSISTANT_SHELL, children })
206
+ /* @__PURE__ */ jsx3("div", { className: ASSISTANT_SHELL, children })
154
207
  ] });
155
208
  }
156
209
  var CATEGORY_ICON_MAP = {
@@ -242,14 +295,14 @@ function CategoryBadges({ categories }) {
242
295
  [categories]
243
296
  );
244
297
  if (sorted.length === 0) return null;
245
- return /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-1", children: sorted.map((cat) => {
298
+ return /* @__PURE__ */ jsx3("div", { className: "flex items-center gap-1", children: sorted.map((cat) => {
246
299
  const Icon = CATEGORY_ICON_MAP[cat] ?? Settings;
247
- return /* @__PURE__ */ jsx2(
300
+ return /* @__PURE__ */ jsx3(
248
301
  "span",
249
302
  {
250
303
  title: cat,
251
304
  className: "flex h-5 w-5 items-center justify-center rounded border border-border text-muted-foreground",
252
- children: /* @__PURE__ */ jsx2(Icon, { className: "h-3 w-3" })
305
+ children: /* @__PURE__ */ jsx3(Icon, { className: "h-3 w-3" })
253
306
  },
254
307
  cat
255
308
  );
@@ -310,10 +363,10 @@ var RunGroup = memo2(
310
363
  if (!isStreaming) {
311
364
  return null;
312
365
  }
313
- return /* @__PURE__ */ jsx2(AssistantShell, { branding, isStreaming: true, children: /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-2 px-0.5 py-0.5 text-sm text-[var(--text-muted)]", children: /* @__PURE__ */ jsxs2("span", { className: "flex gap-[5px]", children: [
314
- /* @__PURE__ */ jsx2("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "0ms" } }),
315
- /* @__PURE__ */ jsx2("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "150ms" } }),
316
- /* @__PURE__ */ jsx2("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "300ms" } })
366
+ return /* @__PURE__ */ jsx3(AssistantShell, { branding, isStreaming: true, children: /* @__PURE__ */ jsx3("div", { className: "flex items-center gap-2 px-0.5 py-0.5 text-sm text-[var(--text-muted)]", children: /* @__PURE__ */ jsxs3("span", { className: "flex gap-[5px]", children: [
367
+ /* @__PURE__ */ jsx3("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "0ms" } }),
368
+ /* @__PURE__ */ jsx3("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "150ms" } }),
369
+ /* @__PURE__ */ jsx3("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "300ms" } })
317
370
  ] }) }) });
318
371
  }
319
372
  const showTraceChrome = allParts.some(({ part }) => {
@@ -326,32 +379,32 @@ var RunGroup = memo2(
326
379
  return false;
327
380
  });
328
381
  if (!showTraceChrome) {
329
- return /* @__PURE__ */ jsx2(AssistantShell, { branding, isStreaming, children: allParts.map(({ part, msgId, index }) => {
382
+ return /* @__PURE__ */ jsx3(AssistantShell, { branding, isStreaming, children: allParts.map(({ part, msgId, index }) => {
330
383
  const key = `${msgId}-${index}`;
331
384
  if (part.type === "tool" && isOpenUITool(part)) {
332
385
  const toolPart = part;
333
386
  const schema = extractOpenUISchema(toolPart.state.output);
334
387
  const summary = getOpenUISummary(toolPart.state.output);
335
388
  if (toolPart.state.status === "completed" && schema) {
336
- return /* @__PURE__ */ jsxs2(
389
+ return /* @__PURE__ */ jsxs3(
337
390
  "div",
338
391
  {
339
392
  className: "overflow-hidden rounded-[22px] border border-[var(--border-subtle)] bg-[var(--bg-root)]",
340
393
  children: [
341
- summary ? /* @__PURE__ */ jsx2("div", { className: "border-b border-[var(--border-subtle)] px-4 py-3 text-sm leading-6 text-foreground", children: summary }) : null,
342
- /* @__PURE__ */ jsx2("div", { className: "p-4", children: /* @__PURE__ */ jsx2(OpenUIArtifactRenderer, { schema }) })
394
+ summary ? /* @__PURE__ */ jsx3("div", { className: "border-b border-[var(--border-subtle)] px-4 py-3 text-sm leading-6 text-foreground", children: summary }) : null,
395
+ /* @__PURE__ */ jsx3("div", { className: "p-4", children: /* @__PURE__ */ jsx3(OpenUIArtifactRenderer, { schema }) })
343
396
  ]
344
397
  },
345
398
  key
346
399
  );
347
400
  }
348
401
  if (toolPart.state.status === "running") {
349
- return /* @__PURE__ */ jsxs2(
402
+ return /* @__PURE__ */ jsxs3(
350
403
  "div",
351
404
  {
352
405
  className: "flex items-center gap-2 rounded-[18px] border border-[var(--border-subtle)] bg-[var(--bg-root)] px-4 py-3 text-sm text-muted-foreground",
353
406
  children: [
354
- /* @__PURE__ */ jsx2(Loader2, { className: "h-4 w-4 animate-spin text-primary" }),
407
+ /* @__PURE__ */ jsx3(Loader22, { className: "h-4 w-4 animate-spin text-primary" }),
355
408
  "Building view\u2026"
356
409
  ]
357
410
  },
@@ -360,102 +413,85 @@ var RunGroup = memo2(
360
413
  }
361
414
  }
362
415
  if (part.type === "text" && !part.synthetic && part.text.trim()) {
363
- return /* @__PURE__ */ jsx2("div", { className: "px-0.5", children: /* @__PURE__ */ jsx2(Markdown, { className: "tangle-prose text-[15px] leading-7 text-[var(--text-primary)]", children: part.text }) }, key);
416
+ return /* @__PURE__ */ jsx3("div", { className: "px-0.5", children: /* @__PURE__ */ jsx3(Markdown, { className: "tangle-prose text-[15px] leading-7 text-[var(--text-primary)]", children: part.text }) }, key);
364
417
  }
365
418
  return null;
366
419
  }) });
367
420
  }
368
- return /* @__PURE__ */ jsx2(Collapsible2.Root, { open: !collapsed, onOpenChange: () => onToggle(), children: /* @__PURE__ */ jsxs2("div", { className: "rounded-[28px] border border-[var(--border-subtle)] bg-[var(--bg-card)] shadow-none", children: [
369
- /* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-3 px-3 py-2.5", children: [
370
- /* @__PURE__ */ jsx2(Collapsible2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx2(
371
- "button",
372
- {
373
- className: cn(
374
- "w-full rounded-[20px] px-0 py-0 text-left transition-colors",
375
- "bg-transparent hover:bg-transparent"
376
- ),
377
- children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
378
- /* @__PURE__ */ jsx2("span", { className: cn("font-semibold text-sm", branding.textClass), children: branding.label }),
379
- renderSummary(run) ? /* @__PURE__ */ jsx2("span", { className: "text-[11px] text-muted-foreground", children: renderSummary(run) }) : null,
380
- collapsed && run.summaryText ? /* @__PURE__ */ jsx2("span", { className: "min-w-0 truncate text-[11px] text-foreground/70", children: run.summaryText }) : null,
381
- /* @__PURE__ */ jsxs2("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
382
- /* @__PURE__ */ jsx2(CategoryBadges, { categories: stats.toolCategories }),
383
- isStreaming ? /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-1 rounded-full border border-[var(--border-accent)] bg-[var(--accent-surface-soft)] px-2 py-px text-[10px] font-semibold uppercase text-[var(--accent-text)]", children: [
384
- /* @__PURE__ */ jsx2(Loader2, { className: "h-2.5 w-2.5 animate-spin" }),
385
- "Running"
386
- ] }) : /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-1 rounded-full border border-border px-2 py-px text-[10px] font-semibold uppercase text-muted-foreground", children: [
387
- /* @__PURE__ */ jsx2(Sparkles, { className: "h-2.5 w-2.5" }),
388
- "Done"
389
- ] }),
390
- !collapsed ? /* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" }) : /* @__PURE__ */ jsx2(ChevronRight2, { className: "h-3.5 w-3.5 text-muted-foreground" })
391
- ] })
392
- ] })
393
- }
394
- ) }),
395
- headerActions ? /* @__PURE__ */ jsx2("div", { className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1", children: headerActions }) : null
396
- ] }),
397
- collapsed && run.summaryText && /* @__PURE__ */ jsx2("div", { className: "px-4 pb-4 text-sm leading-6 text-muted-foreground line-clamp-2", children: run.summaryText }),
398
- /* @__PURE__ */ jsx2(Collapsible2.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx2("div", { className: cn("border-t border-[var(--border-subtle)] px-4 pb-4 pt-3"), children: allParts.map(({ part, msgId, index }, partIndex) => {
399
- const key = `${msgId}-${index}`;
400
- const prev = allParts[partIndex - 1]?.part;
401
- const connectedTool = part.type === "tool" && prev?.type === "tool" && !isOpenUITool(part) && !isOpenUITool(prev);
402
- const gapClass = partIndex === 0 ? "" : connectedTool ? "mt-px" : "mt-3";
403
- let node = null;
404
- if (part.type === "tool") {
405
- if (isOpenUITool(part)) {
406
- const toolPart = part;
407
- const schema = extractOpenUISchema(toolPart.state.output);
408
- const summary = getOpenUISummary(toolPart.state.output);
409
- if (toolPart.state.status === "completed" && schema) {
410
- node = /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-[24px] border border-[var(--border-subtle)] bg-[var(--bg-card)]", children: [
411
- summary ? /* @__PURE__ */ jsxs2("div", { className: "border-b border-[var(--border-subtle)] px-4 py-3", children: [
412
- /* @__PURE__ */ jsx2("div", { className: "text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "View" }),
413
- /* @__PURE__ */ jsx2("div", { className: "mt-1 text-sm leading-6 text-foreground", children: summary })
414
- ] }) : null,
415
- /* @__PURE__ */ jsx2("div", { className: "p-4", children: /* @__PURE__ */ jsx2(OpenUIArtifactRenderer, { schema }) })
416
- ] });
417
- } else if (toolPart.state.status === "running") {
418
- node = /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 rounded-[20px] border border-[var(--border-subtle)] bg-[var(--bg-card)] px-4 py-3 text-sm text-muted-foreground", children: [
419
- /* @__PURE__ */ jsx2(Loader2, { className: "h-4 w-4 animate-spin text-primary" }),
420
- "Building view\u2026"
421
- ] });
421
+ return /* @__PURE__ */ jsx3(
422
+ AssistantRunShell,
423
+ {
424
+ label: branding.label,
425
+ summary: renderSummary(run) || void 0,
426
+ collapsedPreview: run.summaryText ?? void 0,
427
+ badges: /* @__PURE__ */ jsx3(CategoryBadges, { categories: stats.toolCategories }),
428
+ isStreaming,
429
+ collapsed,
430
+ onToggle,
431
+ headerActions,
432
+ children: allParts.map(({ part, msgId, index }, partIndex) => {
433
+ const key = `${msgId}-${index}`;
434
+ const prev = allParts[partIndex - 1]?.part;
435
+ const connectedTool = part.type === "tool" && prev?.type === "tool" && !isOpenUITool(part) && !isOpenUITool(prev);
436
+ const gapClass = partIndex === 0 ? "" : connectedTool ? "mt-px" : "mt-3";
437
+ let node = null;
438
+ if (part.type === "tool") {
439
+ if (isOpenUITool(part)) {
440
+ const toolPart = part;
441
+ const schema = extractOpenUISchema(toolPart.state.output);
442
+ const summary = getOpenUISummary(toolPart.state.output);
443
+ if (toolPart.state.status === "completed" && schema) {
444
+ node = /* @__PURE__ */ jsxs3("div", { className: "overflow-hidden rounded-[24px] border border-[var(--border-subtle)] bg-[var(--bg-card)]", children: [
445
+ summary ? /* @__PURE__ */ jsxs3("div", { className: "border-b border-[var(--border-subtle)] px-4 py-3", children: [
446
+ /* @__PURE__ */ jsx3("div", { className: "text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "View" }),
447
+ /* @__PURE__ */ jsx3("div", { className: "mt-1 text-sm leading-6 text-foreground", children: summary })
448
+ ] }) : null,
449
+ /* @__PURE__ */ jsx3("div", { className: "p-4", children: /* @__PURE__ */ jsx3(OpenUIArtifactRenderer, { schema }) })
450
+ ] });
451
+ } else if (toolPart.state.status === "running") {
452
+ node = /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 rounded-[20px] border border-[var(--border-subtle)] bg-[var(--bg-card)] px-4 py-3 text-sm text-muted-foreground", children: [
453
+ /* @__PURE__ */ jsx3(Loader22, { className: "h-4 w-4 animate-spin text-primary" }),
454
+ "Building view\u2026"
455
+ ] });
456
+ }
422
457
  }
423
- }
424
- if (node === null) {
425
- node = /* @__PURE__ */ jsx2(
426
- InlineToolItem,
458
+ if (node === null) {
459
+ node = /* @__PURE__ */ jsx3(
460
+ InlineToolItem,
461
+ {
462
+ part,
463
+ renderToolDetail,
464
+ groupPosition: getToolGroupPosition(partIndex, allParts),
465
+ actions: renderToolActions?.(part, {
466
+ run,
467
+ messageId: msgId,
468
+ partIndex: index
469
+ })
470
+ }
471
+ );
472
+ }
473
+ } else if (part.type === "reasoning") {
474
+ node = /* @__PURE__ */ jsx3(
475
+ InlineThinkingItem,
427
476
  {
428
477
  part,
429
- renderToolDetail,
430
- groupPosition: getToolGroupPosition(partIndex, allParts),
431
- actions: renderToolActions?.(part, {
432
- run,
433
- messageId: msgId,
434
- partIndex: index
435
- })
478
+ defaultOpen: isStreaming
436
479
  }
437
480
  );
481
+ } else if (part.type === "text" && !part.synthetic && part.text.trim()) {
482
+ node = /* @__PURE__ */ jsx3("div", { className: "px-1 py-1", children: /* @__PURE__ */ jsx3(Markdown, { className: "tangle-prose text-[15px] leading-7", children: part.text }) });
438
483
  }
439
- } else if (part.type === "reasoning") {
440
- node = /* @__PURE__ */ jsx2(
441
- InlineThinkingItem,
442
- {
443
- part,
444
- defaultOpen: isStreaming
445
- }
446
- );
447
- } else if (part.type === "text" && !part.synthetic && part.text.trim()) {
448
- node = /* @__PURE__ */ jsx2("div", { className: "px-1 py-1", children: /* @__PURE__ */ jsx2(Markdown, { className: "tangle-prose text-[15px] leading-7", children: part.text }) });
449
- }
450
- if (!node) return null;
451
- return /* @__PURE__ */ jsx2("div", { className: gapClass, children: node }, key);
452
- }) }) })
453
- ] }) });
484
+ if (!node) return null;
485
+ return /* @__PURE__ */ jsx3("div", { className: gapClass, children: node }, key);
486
+ })
487
+ }
488
+ );
454
489
  }
455
490
  );
456
491
  RunGroup.displayName = "RunGroup";
457
492
 
458
493
  export {
459
494
  InlineThinkingItem,
495
+ AssistantRunShell,
460
496
  RunGroup
461
497
  };