@tangle-network/ui 5.1.0 → 6.0.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.
@@ -1,735 +0,0 @@
1
- import {
2
- formatDuration,
3
- truncateText
4
- } from "./chunk-4CLN43XT.js";
5
- import {
6
- getToolCategory,
7
- getToolDisplayMetadata,
8
- getToolErrorText
9
- } from "./chunk-BX6AQMUS.js";
10
- import {
11
- CommandPreview,
12
- DiffPreview,
13
- GlobResultsPreview,
14
- GrepResultsPreview,
15
- QuestionPreview,
16
- WebSearchPreview,
17
- WriteFilePreview
18
- } from "./chunk-AAUNOHVL.js";
19
- import {
20
- OpenUIArtifactRenderer
21
- } from "./chunk-52Y3FMFI.js";
22
- import {
23
- Markdown
24
- } from "./chunk-FJBTCTZM.js";
25
- import {
26
- CodeBlock
27
- } from "./chunk-WUQDUBJG.js";
28
- import {
29
- cn
30
- } from "./chunk-RQHJBTEU.js";
31
-
32
- // src/run/expanded-tool-detail.tsx
33
- import { memo } from "react";
34
- import {
35
- ArrowRight,
36
- ArrowLeft,
37
- AlertCircle,
38
- Loader2,
39
- FileText
40
- } from "lucide-react";
41
- import { jsx, jsxs } from "react/jsx-runtime";
42
- var EXT_LANG = {
43
- ts: "typescript",
44
- tsx: "tsx",
45
- js: "javascript",
46
- jsx: "jsx",
47
- rs: "rust",
48
- py: "python",
49
- go: "go",
50
- rb: "ruby",
51
- json: "json",
52
- yaml: "yaml",
53
- yml: "yaml",
54
- toml: "toml",
55
- md: "markdown",
56
- css: "css",
57
- scss: "scss",
58
- html: "html",
59
- sh: "bash",
60
- bash: "bash",
61
- zsh: "bash",
62
- sql: "sql",
63
- sol: "solidity",
64
- proto: "protobuf"
65
- };
66
- function langFromPath(path) {
67
- if (!path) return void 0;
68
- const ext = path.split(".").pop()?.toLowerCase();
69
- return ext ? EXT_LANG[ext] : void 0;
70
- }
71
- function formatOutput(value) {
72
- if (value == null) return "";
73
- if (typeof value === "string") return value;
74
- try {
75
- return JSON.stringify(value, null, 2);
76
- } catch {
77
- return String(value);
78
- }
79
- }
80
- var ExpandedToolDetail = memo(({ part }) => {
81
- const meta = getToolDisplayMetadata(part);
82
- const { status, input, output, error } = part.state;
83
- if (meta.displayVariant === "command") {
84
- return /* @__PURE__ */ jsx(CommandPreview, { part });
85
- }
86
- if (meta.displayVariant === "write-file") {
87
- return /* @__PURE__ */ jsx(WriteFilePreview, { part });
88
- }
89
- if (meta.displayVariant === "grep") {
90
- return /* @__PURE__ */ jsx(GrepResultsPreview, { part });
91
- }
92
- if (meta.displayVariant === "glob") {
93
- return /* @__PURE__ */ jsx(GlobResultsPreview, { part });
94
- }
95
- if (meta.displayVariant === "web-search") {
96
- return /* @__PURE__ */ jsx(WebSearchPreview, { part });
97
- }
98
- if (meta.displayVariant === "question") {
99
- return /* @__PURE__ */ jsx(QuestionPreview, { part });
100
- }
101
- if (meta.displayVariant === "diff") {
102
- return /* @__PURE__ */ jsx(DiffPreview, { part });
103
- }
104
- if (meta.displayVariant === "read-file") {
105
- return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card shadow-[var(--shadow-card)]", children: [
106
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 border-b border-border bg-card px-3 py-2", children: [
107
- /* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-[var(--border-accent)] bg-muted text-primary", children: /* @__PURE__ */ jsx(FileText, { className: "h-3.5 w-3.5" }) }),
108
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex items-center gap-2", children: [
109
- /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-foreground", children: "Read file" }),
110
- meta.targetPath ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs font-mono text-muted-foreground", children: meta.targetPath }) : null
111
- ] })
112
- ] }),
113
- /* @__PURE__ */ jsxs("div", { className: "space-y-2 px-3 py-2.5", children: [
114
- typeof output === "string" ? /* @__PURE__ */ jsx(CodeBlock, { code: output, language: langFromPath(meta.targetPath) ?? "text", className: "rounded-[var(--radius-md)]" }) : /* @__PURE__ */ jsx("div", { className: "rounded-[var(--radius-md)] border border-dashed border-border bg-muted px-3 py-4 text-sm text-muted-foreground", children: "No readable file content was returned." }),
115
- error ? /* @__PURE__ */ jsx("div", { className: "rounded-[var(--radius-md)] border border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-3 py-3 text-sm text-[var(--surface-danger-text)]", children: error }) : null
116
- ] })
117
- ] });
118
- }
119
- const inputStr = formatOutput(input);
120
- const outputStr = formatOutput(output);
121
- return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
122
- inputStr && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card", children: [
123
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2", children: [
124
- /* @__PURE__ */ jsx(ArrowRight, { className: "h-3 w-3 text-primary" }),
125
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground", children: "Input" })
126
- ] }),
127
- /* @__PURE__ */ jsx(CodeBlock, { code: inputStr, language: "json", className: "rounded-none border-0" })
128
- ] }),
129
- status === "completed" && outputStr && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card", children: [
130
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2", children: [
131
- /* @__PURE__ */ jsx(ArrowLeft, { className: "h-3 w-3 text-primary" }),
132
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground", children: "Output" })
133
- ] }),
134
- /* @__PURE__ */ jsx(
135
- CodeBlock,
136
- {
137
- code: outputStr.length > 2e3 ? outputStr.slice(0, 2e3) + "\n...(truncated)" : outputStr,
138
- language: "json",
139
- className: "rounded-none border-0"
140
- }
141
- )
142
- ] }),
143
- error && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-[var(--surface-danger-border)]", children: [
144
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-3 py-2", children: [
145
- /* @__PURE__ */ jsx(AlertCircle, { className: "h-3 w-3 text-[var(--surface-danger-text)]" }),
146
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-[var(--surface-danger-text)]", children: "Error" })
147
- ] }),
148
- /* @__PURE__ */ jsx("pre", { className: "bg-[var(--surface-danger-bg)] p-3 text-xs font-mono whitespace-pre-wrap break-all text-[var(--surface-danger-text)]", children: error })
149
- ] }),
150
- (status === "pending" || status === "running") && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-[var(--radius-md)] border border-border bg-muted px-3 py-3 text-xs text-muted-foreground", children: [
151
- /* @__PURE__ */ jsx(Loader2, { className: cn("h-3 w-3 animate-spin text-primary") }),
152
- "Running\u2026"
153
- ] })
154
- ] });
155
- });
156
- ExpandedToolDetail.displayName = "ExpandedToolDetail";
157
-
158
- // src/run/run-item-primitives.tsx
159
- import { useEffect, useState } from "react";
160
- import { jsx as jsx2 } from "react/jsx-runtime";
161
- function LiveDuration({ startTime }) {
162
- const [elapsed, setElapsed] = useState(Date.now() - startTime);
163
- useEffect(() => {
164
- const id = setInterval(() => setElapsed(Date.now() - startTime), 100);
165
- return () => clearInterval(id);
166
- }, [startTime]);
167
- return /* @__PURE__ */ jsx2("span", { className: "text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums", children: formatDuration(elapsed) });
168
- }
169
-
170
- // src/run/inline-tool-item.tsx
171
- import { memo as memo2, useState as useState2 } from "react";
172
- import * as Collapsible from "@radix-ui/react-collapsible";
173
- import {
174
- Loader2 as Loader22,
175
- CheckCircle2,
176
- AlertCircle as AlertCircle2,
177
- ChevronDown,
178
- ChevronRight,
179
- Terminal,
180
- FileEdit,
181
- FileSearch,
182
- Search,
183
- PencilLine,
184
- Bot,
185
- Globe,
186
- ClipboardList,
187
- Settings
188
- } from "lucide-react";
189
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
190
- var TOOL_CATEGORY_ICON_MAP = {
191
- command: Terminal,
192
- write: FileEdit,
193
- read: FileSearch,
194
- search: Search,
195
- edit: PencilLine,
196
- task: Bot,
197
- web: Globe,
198
- todo: ClipboardList,
199
- other: Settings
200
- };
201
- var InlineToolItem = memo2(
202
- ({
203
- part,
204
- renderToolDetail,
205
- groupPosition = "single",
206
- className,
207
- contentClassName,
208
- actions
209
- }) => {
210
- const [open, setOpen] = useState2(false);
211
- const meta = getToolDisplayMetadata(part);
212
- const { status } = part.state;
213
- const errorText = getToolErrorText(part);
214
- const isRunning = status === "pending" || status === "running";
215
- const isError = status === "error";
216
- const isComplete = status === "completed";
217
- const startTime = part.state.time?.start;
218
- const endTime = part.state.time?.end;
219
- const durationMs = startTime && endTime ? endTime - startTime : void 0;
220
- const category = getToolCategory(part.tool);
221
- const DefaultIcon = TOOL_CATEGORY_ICON_MAP[category] ?? Settings;
222
- const shapeClass = {
223
- single: "rounded-[var(--radius-lg)]",
224
- first: "rounded-t-[var(--radius-lg)] rounded-b-[var(--radius-sm)]",
225
- middle: "rounded-[var(--radius-sm)]",
226
- last: "rounded-t-[var(--radius-sm)] rounded-b-[var(--radius-lg)]"
227
- }[groupPosition];
228
- return /* @__PURE__ */ jsxs2(Collapsible.Root, { open, onOpenChange: setOpen, children: [
229
- /* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-2", children: [
230
- /* @__PURE__ */ jsx3(Collapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
231
- "button",
232
- {
233
- className: cn(
234
- "w-full border text-left transition-colors",
235
- "border-[var(--border-subtle)] bg-card/40 hover:border-border hover:bg-accent/25",
236
- open && "border-border bg-accent/20",
237
- shapeClass,
238
- className
239
- ),
240
- children: [
241
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-2.5 py-1.5", children: [
242
- /* @__PURE__ */ jsx3("div", { className: cn(
243
- "shrink-0",
244
- isRunning && "text-primary",
245
- isComplete && "text-[var(--surface-success-text)]",
246
- isError && "text-[var(--surface-danger-text)]",
247
- !isRunning && !isComplete && !isError && "text-muted-foreground"
248
- ), children: isRunning ? /* @__PURE__ */ jsx3(Loader22, { className: "h-3.5 w-3.5 animate-spin" }) : isComplete ? /* @__PURE__ */ jsx3(CheckCircle2, { className: "h-3.5 w-3.5" }) : isError ? /* @__PURE__ */ jsx3(AlertCircle2, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx3(DefaultIcon, { className: "h-3.5 w-3.5" }) }),
249
- /* @__PURE__ */ jsx3("span", { className: "truncate text-xs font-medium text-foreground", children: meta.title }),
250
- meta.description ? /* @__PURE__ */ jsx3("span", { className: "hidden truncate text-xs font-mono text-muted-foreground sm:inline", children: meta.description }) : null,
251
- /* @__PURE__ */ jsxs2("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
252
- isRunning && startTime ? /* @__PURE__ */ jsx3(LiveDuration, { startTime }) : null,
253
- !isRunning && durationMs != null ? /* @__PURE__ */ jsx3("span", { className: "text-[10px] font-mono tabular-nums text-muted-foreground", children: formatDuration(durationMs) }) : null,
254
- isError ? /* @__PURE__ */ jsx3("span", { className: "rounded-full border border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-1.5 py-px text-[10px] font-semibold uppercase text-[var(--surface-danger-text)]", children: "Failed" }) : null,
255
- isRunning ? /* @__PURE__ */ jsx3("span", { className: "rounded-full border border-[var(--border-accent)] bg-primary/10 px-1.5 py-px text-[10px] font-semibold uppercase text-primary", children: "Running" }) : null,
256
- open ? /* @__PURE__ */ jsx3(ChevronDown, { className: "h-3 w-3 text-muted-foreground" }) : /* @__PURE__ */ jsx3(ChevronRight, { className: "h-3 w-3 text-muted-foreground" })
257
- ] })
258
- ] }),
259
- errorText && !open ? /* @__PURE__ */ jsx3("div", { className: "border-t border-border px-3 py-2 text-xs text-red-200", children: errorText }) : null
260
- ]
261
- }
262
- ) }),
263
- actions ? /* @__PURE__ */ jsx3(
264
- "div",
265
- {
266
- className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1",
267
- onClick: (event) => event.stopPropagation(),
268
- children: actions
269
- }
270
- ) : null
271
- ] }),
272
- /* @__PURE__ */ jsx3(Collapsible.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx3("div", { className: cn("mt-1.5 ml-2.5 border-l-2 border-primary/15 pl-3.5", contentClassName), children: renderToolDetail?.(part) ?? /* @__PURE__ */ jsx3(ExpandedToolDetail, { part }) }) })
273
- ] });
274
- }
275
- );
276
- InlineToolItem.displayName = "InlineToolItem";
277
-
278
- // src/run/inline-thinking-item.tsx
279
- import { memo as memo3, useEffect as useEffect2, useRef, useState as useState3 } from "react";
280
- import * as Collapsible2 from "@radix-ui/react-collapsible";
281
- import { Brain, ChevronRight as ChevronRight2 } from "lucide-react";
282
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
283
- var InlineThinkingItem = memo3(
284
- ({
285
- part,
286
- defaultOpen = false,
287
- autoCollapse = true,
288
- className,
289
- contentClassName
290
- }) => {
291
- const [open, setOpen] = useState3(defaultOpen);
292
- const autoCollapsedRef = useRef(false);
293
- const startTime = part.time?.start;
294
- const endTime = part.time?.end;
295
- const durationMs = startTime && endTime ? endTime - startTime : void 0;
296
- const isActive = startTime != null && endTime == null;
297
- const preview = part.text ? truncateText(part.text, 120) : void 0;
298
- useEffect2(() => {
299
- if (isActive) {
300
- autoCollapsedRef.current = false;
301
- setOpen(true);
302
- return;
303
- }
304
- if (autoCollapse && !autoCollapsedRef.current && durationMs != null) {
305
- const timer = window.setTimeout(() => {
306
- setOpen(false);
307
- autoCollapsedRef.current = true;
308
- }, 900);
309
- return () => window.clearTimeout(timer);
310
- }
311
- }, [autoCollapse, durationMs, isActive]);
312
- return /* @__PURE__ */ jsx4(Collapsible2.Root, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs3(
313
- "div",
314
- {
315
- className: cn(
316
- "overflow-hidden rounded-[var(--radius-lg)] border bg-card transition-colors",
317
- isActive ? "border-[var(--border-accent)]" : "border-border hover:border-[var(--border-accent)]",
318
- className
319
- ),
320
- children: [
321
- /* @__PURE__ */ jsx4(Collapsible2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
322
- "button",
323
- {
324
- className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm cursor-pointer",
325
- children: [
326
- /* @__PURE__ */ jsx4(
327
- "div",
328
- {
329
- className: cn(
330
- "flex h-6 w-6 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border",
331
- isActive ? "border-[var(--border-accent)] bg-[var(--accent-surface-soft)] text-primary" : "border-border bg-muted text-muted-foreground"
332
- ),
333
- children: /* @__PURE__ */ jsx4(Brain, { className: cn("h-3 w-3 shrink-0", isActive && "animate-pulse") })
334
- }
335
- ),
336
- /* @__PURE__ */ jsx4("p", { className: "min-w-0 flex-1 truncate font-[var(--font-sans)] text-muted-foreground", children: preview ?? (isActive ? "Thinking\u2026" : "Reasoning") }),
337
- /* @__PURE__ */ jsxs3("div", { className: "flex shrink-0 items-center gap-2", children: [
338
- isActive && startTime ? /* @__PURE__ */ jsx4(LiveDuration, { startTime }) : null,
339
- !isActive && durationMs != null ? /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: formatDuration(durationMs) }) : null,
340
- /* @__PURE__ */ jsx4(
341
- ChevronRight2,
342
- {
343
- className: cn(
344
- "h-3 w-3 text-muted-foreground transition-transform shrink-0",
345
- open && "rotate-90"
346
- )
347
- }
348
- )
349
- ] })
350
- ]
351
- }
352
- ) }),
353
- /* @__PURE__ */ jsx4(Collapsible2.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: part.text ? /* @__PURE__ */ jsx4(
354
- "div",
355
- {
356
- className: cn(
357
- "max-h-60 overflow-y-auto border-t border-border bg-muted px-3 py-3 text-sm leading-relaxed text-muted-foreground",
358
- contentClassName
359
- ),
360
- children: /* @__PURE__ */ jsx4(Markdown, { children: part.text })
361
- }
362
- ) : /* @__PURE__ */ jsx4("div", { className: "border-t border-border bg-muted px-3 py-2.5 text-xs text-muted-foreground", children: "No reasoning text provided." }) })
363
- ]
364
- }
365
- ) });
366
- }
367
- );
368
- InlineThinkingItem.displayName = "InlineThinkingItem";
369
-
370
- // src/run/run-group.tsx
371
- import { memo as memo4, useMemo } from "react";
372
- import * as Collapsible3 from "@radix-ui/react-collapsible";
373
- import {
374
- Bot as Bot2,
375
- Loader2 as Loader23,
376
- ChevronDown as ChevronDown2,
377
- ChevronRight as ChevronRight3,
378
- Terminal as Terminal2,
379
- FileEdit as FileEdit2,
380
- FileSearch as FileSearch2,
381
- Search as Search2,
382
- PencilLine as PencilLine2,
383
- Globe as Globe2,
384
- ClipboardList as ClipboardList2,
385
- Settings as Settings2,
386
- Sparkles
387
- } from "lucide-react";
388
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
389
- var DEFAULT_BRANDING = {
390
- label: "Agent",
391
- accentClass: "text-primary",
392
- bgClass: "bg-[var(--accent-surface-soft)]",
393
- containerBgClass: "bg-muted",
394
- borderClass: "border-border",
395
- iconClass: "",
396
- textClass: "text-primary"
397
- };
398
- var ASSISTANT_SHELL = "min-w-0 flex-1 space-y-3 rounded-[26px] border border-[var(--border-subtle)] bg-[color:color-mix(in_srgb,var(--bg-card)_94%,transparent)] px-5 py-4 shadow-[0_1px_2px_rgba(15,23,42,0.04)]";
399
- function AssistantShell({
400
- branding,
401
- isStreaming,
402
- children
403
- }) {
404
- return /* @__PURE__ */ jsxs4("div", { className: "flex gap-2.5", children: [
405
- /* @__PURE__ */ jsx5("div", { className: "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-[var(--brand-primary)] text-white", children: /* @__PURE__ */ jsx5(Bot2, { className: "h-3.5 w-3.5" }) }),
406
- /* @__PURE__ */ jsxs4("div", { className: ASSISTANT_SHELL, children: [
407
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 text-[11px] font-semibold uppercase tracking-[0.14em] text-[var(--text-muted)]", children: [
408
- /* @__PURE__ */ jsx5("span", { children: branding.label }),
409
- isStreaming ? /* @__PURE__ */ jsxs4("span", { className: "inline-flex items-center gap-1.5 text-[var(--text-muted)]", children: [
410
- /* @__PURE__ */ jsx5(Loader23, { className: "h-3 w-3 animate-spin" }),
411
- "Thinking"
412
- ] }) : null
413
- ] }),
414
- children
415
- ] })
416
- ] });
417
- }
418
- var CATEGORY_ICON_MAP = {
419
- command: Terminal2,
420
- write: FileEdit2,
421
- read: FileSearch2,
422
- search: Search2,
423
- edit: PencilLine2,
424
- task: Bot2,
425
- web: Globe2,
426
- todo: ClipboardList2,
427
- other: Settings2
428
- };
429
- var CATEGORY_ORDER = [
430
- "command",
431
- "write",
432
- "edit",
433
- "read",
434
- "search",
435
- "web",
436
- "task",
437
- "todo",
438
- "other"
439
- ];
440
- var OPENUI_NODE_TYPES = /* @__PURE__ */ new Set([
441
- "heading",
442
- "text",
443
- "badge",
444
- "stat",
445
- "key_value",
446
- "code",
447
- "markdown",
448
- "table",
449
- "actions",
450
- "separator",
451
- "stack",
452
- "grid",
453
- "card"
454
- ]);
455
- function isOpenUINode(value) {
456
- return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string" && OPENUI_NODE_TYPES.has(value.type);
457
- }
458
- function extractOpenUISchema(output) {
459
- if (output == null) return null;
460
- if (isOpenUINode(output)) return [output];
461
- if (Array.isArray(output) && output.length > 0 && output.every(isOpenUINode)) {
462
- return output;
463
- }
464
- if (typeof output === "object" && !Array.isArray(output)) {
465
- const obj = output;
466
- for (const key of ["openui", "schema", "ui"]) {
467
- if (obj[key] == null) continue;
468
- const inner = obj[key];
469
- if (typeof inner === "string") {
470
- try {
471
- const parsed = JSON.parse(inner);
472
- return extractOpenUISchema(parsed);
473
- } catch {
474
- continue;
475
- }
476
- }
477
- const nested = extractOpenUISchema(inner);
478
- if (nested) return nested;
479
- }
480
- }
481
- if (typeof output === "string") {
482
- try {
483
- return extractOpenUISchema(JSON.parse(output));
484
- } catch {
485
- return null;
486
- }
487
- }
488
- return null;
489
- }
490
- function getOpenUISummary(output) {
491
- if (!output || typeof output !== "object" || Array.isArray(output)) {
492
- return null;
493
- }
494
- const summary = output.summary;
495
- return typeof summary === "string" && summary.trim() ? summary.trim() : null;
496
- }
497
- function isOpenUITool(part) {
498
- const normalized = part.tool.toLowerCase().replace(/^tool:/, "");
499
- return normalized.includes("openui");
500
- }
501
- function CategoryBadges({ categories }) {
502
- const sorted = useMemo(
503
- () => CATEGORY_ORDER.filter((category) => categories.has(category)),
504
- [categories]
505
- );
506
- if (sorted.length === 0) return null;
507
- return /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-1", children: sorted.map((cat) => {
508
- const Icon = CATEGORY_ICON_MAP[cat] ?? Settings2;
509
- return /* @__PURE__ */ jsx5(
510
- "span",
511
- {
512
- title: cat,
513
- className: "flex h-5 w-5 items-center justify-center rounded border border-border text-muted-foreground",
514
- children: /* @__PURE__ */ jsx5(Icon, { className: "h-3 w-3" })
515
- },
516
- cat
517
- );
518
- }) });
519
- }
520
- function renderSummary(run) {
521
- const parts = [];
522
- if (run.stats.toolCount > 0) {
523
- parts.push(`${run.stats.toolCount} tool${run.stats.toolCount === 1 ? "" : "s"}`);
524
- }
525
- if (run.stats.textPartCount > 0) {
526
- parts.push(`${run.stats.textPartCount} response${run.stats.textPartCount === 1 ? "" : "s"}`);
527
- }
528
- if (run.stats.thinkingDurationMs > 0) {
529
- parts.push(`${formatDuration(run.stats.thinkingDurationMs)} thinking`);
530
- }
531
- return parts.join(", ");
532
- }
533
- function getToolGroupPosition(currentIndex, parts) {
534
- const previous = parts[currentIndex - 1]?.part;
535
- const next = parts[currentIndex + 1]?.part;
536
- const previousIsTool = previous?.type === "tool";
537
- const nextIsTool = next?.type === "tool";
538
- if (previousIsTool && nextIsTool) return "middle";
539
- if (previousIsTool) return "last";
540
- if (nextIsTool) return "first";
541
- return "single";
542
- }
543
- var RunGroup = memo4(
544
- ({
545
- run,
546
- partMap,
547
- collapsed,
548
- onToggle,
549
- branding = DEFAULT_BRANDING,
550
- renderToolDetail,
551
- headerActions,
552
- renderToolActions
553
- }) => {
554
- const allParts = useMemo(() => {
555
- const parts = [];
556
- for (const msg of run.messages) {
557
- const msgParts = partMap[msg.id] ?? [];
558
- msgParts.forEach((part, index) => {
559
- parts.push({ part, msgId: msg.id, index });
560
- });
561
- }
562
- return parts;
563
- }, [run.messages, partMap]);
564
- const { stats, isStreaming } = run;
565
- const hasRenderableParts = allParts.some(({ part }) => {
566
- if (part.type === "tool" || part.type === "reasoning") {
567
- return true;
568
- }
569
- return part.type === "text" && !part.synthetic && part.text.trim().length > 0;
570
- });
571
- if (!hasRenderableParts) {
572
- if (!isStreaming) {
573
- return null;
574
- }
575
- return /* @__PURE__ */ jsx5(AssistantShell, { branding, isStreaming: true, children: /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2 px-0.5 py-0.5 text-sm text-[var(--text-muted)]", children: /* @__PURE__ */ jsxs4("span", { className: "flex gap-[5px]", children: [
576
- /* @__PURE__ */ jsx5("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "0ms" } }),
577
- /* @__PURE__ */ jsx5("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "150ms" } }),
578
- /* @__PURE__ */ jsx5("span", { className: "h-2 w-2 animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "300ms" } })
579
- ] }) }) });
580
- }
581
- const showTraceChrome = allParts.some(({ part }) => {
582
- if (part.type === "reasoning") {
583
- return true;
584
- }
585
- if (part.type === "tool") {
586
- return !isOpenUITool(part);
587
- }
588
- return false;
589
- });
590
- if (!showTraceChrome) {
591
- return /* @__PURE__ */ jsx5(AssistantShell, { branding, isStreaming, children: allParts.map(({ part, msgId, index }) => {
592
- const key = `${msgId}-${index}`;
593
- if (part.type === "tool" && isOpenUITool(part)) {
594
- const toolPart = part;
595
- const schema = extractOpenUISchema(toolPart.state.output);
596
- const summary = getOpenUISummary(toolPart.state.output);
597
- if (toolPart.state.status === "completed" && schema) {
598
- return /* @__PURE__ */ jsxs4(
599
- "div",
600
- {
601
- className: "overflow-hidden rounded-[22px] border border-[var(--border-subtle)] bg-[var(--bg-root)]",
602
- children: [
603
- summary ? /* @__PURE__ */ jsx5("div", { className: "border-b border-[var(--border-subtle)] px-4 py-3 text-sm leading-6 text-foreground", children: summary }) : null,
604
- /* @__PURE__ */ jsx5("div", { className: "p-4", children: /* @__PURE__ */ jsx5(OpenUIArtifactRenderer, { schema }) })
605
- ]
606
- },
607
- key
608
- );
609
- }
610
- if (toolPart.state.status === "running") {
611
- return /* @__PURE__ */ jsxs4(
612
- "div",
613
- {
614
- 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",
615
- children: [
616
- /* @__PURE__ */ jsx5(Loader23, { className: "h-4 w-4 animate-spin text-primary" }),
617
- "Building view\u2026"
618
- ]
619
- },
620
- key
621
- );
622
- }
623
- }
624
- if (part.type === "text" && !part.synthetic && part.text.trim()) {
625
- return /* @__PURE__ */ jsx5("div", { className: "px-0.5", children: /* @__PURE__ */ jsx5(Markdown, { className: "tangle-prose text-[15px] leading-7 text-[var(--text-primary)]", children: part.text }) }, key);
626
- }
627
- return null;
628
- }) });
629
- }
630
- return /* @__PURE__ */ jsx5(Collapsible3.Root, { open: !collapsed, onOpenChange: () => onToggle(), children: /* @__PURE__ */ jsxs4("div", { className: "rounded-[28px] border border-[var(--border-subtle)] bg-[var(--bg-card)] shadow-none", children: [
631
- /* @__PURE__ */ jsxs4("div", { className: "flex items-start gap-3 px-3 py-2.5", children: [
632
- /* @__PURE__ */ jsx5(Collapsible3.Trigger, { asChild: true, children: /* @__PURE__ */ jsx5(
633
- "button",
634
- {
635
- className: cn(
636
- "w-full rounded-[20px] px-0 py-0 text-left transition-colors",
637
- "bg-transparent hover:bg-transparent"
638
- ),
639
- children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
640
- /* @__PURE__ */ jsx5(
641
- "div",
642
- {
643
- className: cn(
644
- "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-[var(--brand-primary)] text-white"
645
- ),
646
- children: /* @__PURE__ */ jsx5(Bot2, { className: "h-3.5 w-3.5" })
647
- }
648
- ),
649
- /* @__PURE__ */ jsx5("span", { className: cn("text-sm font-semibold", branding.textClass), children: branding.label }),
650
- renderSummary(run) ? /* @__PURE__ */ jsx5("span", { className: "text-[11px] text-muted-foreground", children: renderSummary(run) }) : null,
651
- collapsed && run.summaryText ? /* @__PURE__ */ jsx5("span", { className: "min-w-0 truncate text-[11px] text-foreground/70", children: run.summaryText }) : null,
652
- /* @__PURE__ */ jsxs4("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
653
- /* @__PURE__ */ jsx5(CategoryBadges, { categories: stats.toolCategories }),
654
- isStreaming ? /* @__PURE__ */ jsxs4("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: [
655
- /* @__PURE__ */ jsx5(Loader23, { className: "h-2.5 w-2.5 animate-spin" }),
656
- "Running"
657
- ] }) : /* @__PURE__ */ jsxs4("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: [
658
- /* @__PURE__ */ jsx5(Sparkles, { className: "h-2.5 w-2.5" }),
659
- "Done"
660
- ] }),
661
- !collapsed ? /* @__PURE__ */ jsx5(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" }) : /* @__PURE__ */ jsx5(ChevronRight3, { className: "h-3.5 w-3.5 text-muted-foreground" })
662
- ] })
663
- ] })
664
- }
665
- ) }),
666
- headerActions ? /* @__PURE__ */ jsx5("div", { className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1", children: headerActions }) : null
667
- ] }),
668
- collapsed && run.summaryText && /* @__PURE__ */ jsx5("div", { className: "px-4 pb-4 text-sm leading-6 text-muted-foreground line-clamp-2", children: run.summaryText }),
669
- /* @__PURE__ */ jsx5(Collapsible3.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx5("div", { className: cn("border-t border-[var(--border-subtle)] px-4 pb-4 pt-3"), children: allParts.map(({ part, msgId, index }, partIndex) => {
670
- const key = `${msgId}-${index}`;
671
- const prev = allParts[partIndex - 1]?.part;
672
- const connectedTool = part.type === "tool" && prev?.type === "tool" && !isOpenUITool(part) && !isOpenUITool(prev);
673
- const gapClass = partIndex === 0 ? "" : connectedTool ? "mt-px" : "mt-3";
674
- let node = null;
675
- if (part.type === "tool") {
676
- if (isOpenUITool(part)) {
677
- const toolPart = part;
678
- const schema = extractOpenUISchema(toolPart.state.output);
679
- const summary = getOpenUISummary(toolPart.state.output);
680
- if (toolPart.state.status === "completed" && schema) {
681
- node = /* @__PURE__ */ jsxs4("div", { className: "overflow-hidden rounded-[24px] border border-[var(--border-subtle)] bg-[var(--bg-card)]", children: [
682
- summary ? /* @__PURE__ */ jsxs4("div", { className: "border-b border-[var(--border-subtle)] px-4 py-3", children: [
683
- /* @__PURE__ */ jsx5("div", { className: "text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "View" }),
684
- /* @__PURE__ */ jsx5("div", { className: "mt-1 text-sm leading-6 text-foreground", children: summary })
685
- ] }) : null,
686
- /* @__PURE__ */ jsx5("div", { className: "p-4", children: /* @__PURE__ */ jsx5(OpenUIArtifactRenderer, { schema }) })
687
- ] });
688
- } else if (toolPart.state.status === "running") {
689
- node = /* @__PURE__ */ jsxs4("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: [
690
- /* @__PURE__ */ jsx5(Loader23, { className: "h-4 w-4 animate-spin text-primary" }),
691
- "Building view\u2026"
692
- ] });
693
- }
694
- }
695
- if (node === null) {
696
- node = /* @__PURE__ */ jsx5(
697
- InlineToolItem,
698
- {
699
- part,
700
- renderToolDetail,
701
- groupPosition: getToolGroupPosition(partIndex, allParts),
702
- actions: renderToolActions?.(part, {
703
- run,
704
- messageId: msgId,
705
- partIndex: index
706
- })
707
- }
708
- );
709
- }
710
- } else if (part.type === "reasoning") {
711
- node = /* @__PURE__ */ jsx5(
712
- InlineThinkingItem,
713
- {
714
- part,
715
- defaultOpen: isStreaming
716
- }
717
- );
718
- } else if (part.type === "text" && !part.synthetic && part.text.trim()) {
719
- node = /* @__PURE__ */ jsx5("div", { className: "px-1 py-1", children: /* @__PURE__ */ jsx5(Markdown, { className: "tangle-prose text-[15px] leading-7", children: part.text }) });
720
- }
721
- if (!node) return null;
722
- return /* @__PURE__ */ jsx5("div", { className: gapClass, children: node }, key);
723
- }) }) })
724
- ] }) });
725
- }
726
- );
727
- RunGroup.displayName = "RunGroup";
728
-
729
- export {
730
- ExpandedToolDetail,
731
- LiveDuration,
732
- InlineToolItem,
733
- InlineThinkingItem,
734
- RunGroup
735
- };