@tangle-network/ui 11.0.0 → 11.2.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 +30 -0
- package/dist/{artifact-pane-DvJyPWV4.d.ts → artifact-pane-DpuWcAiF.d.ts} +10 -1
- package/dist/chat.d.ts +8 -2
- package/dist/chat.js +5 -5
- package/dist/{chunk-52Y3FMFI.js → chunk-3M7BPSSW.js} +1 -1
- package/dist/chunk-4ORVXSMU.js +507 -0
- package/dist/{chunk-LELGOLFV.js → chunk-GGDYWMFF.js} +15 -7
- package/dist/{chunk-CCM2KRQH.js → chunk-HW4ROISY.js} +1 -1
- package/dist/{chunk-KBOD47AW.js → chunk-J3YZIQNI.js} +2 -2
- package/dist/{chunk-CSAIKY36.js → chunk-LTEKI7YJ.js} +12 -7
- package/dist/{chunk-KHO7DYXH.js → chunk-OTZWQJ5W.js} +107 -72
- package/dist/{chunk-FJBTCTZM.js → chunk-P5F43A65.js} +1 -1
- package/dist/{chunk-SZ44QDA6.js → chunk-RADUPP44.js} +12 -5
- package/dist/{chunk-HHYUPAOJ.js → chunk-SRAKCVPO.js} +49 -81
- package/dist/{document-editor-pane-DyDEX_Zm.d.ts → document-editor-pane-C3cYEDWZ.d.ts} +2 -2
- package/dist/{document-editor-pane-WCTA3ZOE.js → document-editor-pane-OQNGM4RJ.js} +3 -3
- package/dist/editor.d.ts +3 -3
- package/dist/editor.js +3 -3
- package/dist/files.d.ts +5 -3
- package/dist/files.js +3 -3
- package/dist/hooks.js +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9 -9
- package/dist/markdown.js +1 -1
- package/dist/openui.js +2 -2
- package/dist/primitives.d.ts +1 -1
- package/dist/primitives.js +1 -1
- package/dist/run.d.ts +4 -3
- package/dist/run.js +5 -5
- package/dist/sdk-hooks.js +4 -4
- package/package.json +1 -1
- package/src/chat/agent-timeline.stories.tsx +11 -0
- package/src/chat/agent-timeline.test.tsx +34 -0
- package/src/chat/agent-timeline.tsx +65 -12
- package/src/chat/chat-container.tsx +5 -0
- package/src/editor/document-editor-pane.stories.tsx +74 -0
- package/src/editor/document-editor-pane.tsx +10 -3
- package/src/files/file-artifact-pane.tsx +14 -2
- package/src/files/file-preview.stories.tsx +22 -1
- package/src/files/file-preview.tsx +2 -2
- package/src/markdown/markdown.stories.tsx +55 -1
- package/src/markdown/markdown.test.tsx +23 -0
- package/src/markdown/markdown.tsx +1 -1
- package/src/primitives/artifact-pane.tsx +52 -26
- package/src/run/expandable-content.test.tsx +52 -0
- package/src/run/expandable-content.tsx +73 -0
- package/src/run/expanded-tool-detail.tsx +17 -12
- package/src/run/inline-thinking-item.stories.tsx +30 -1
- package/src/run/inline-thinking-item.tsx +34 -70
- package/src/run/inline-tool-item.tsx +30 -116
- package/src/run/run-row-shell.test.tsx +38 -0
- package/src/run/run-row-shell.tsx +191 -0
- package/dist/chunk-INMWNFAS.js +0 -369
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { useState, type ReactNode } from "react";
|
|
2
|
+
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
3
|
+
import { Loader2, ChevronRight } from "lucide-react";
|
|
4
|
+
import { cn } from "../lib/utils";
|
|
5
|
+
import { formatDuration } from "../utils/format";
|
|
6
|
+
import { LiveDuration } from "./run-item-primitives";
|
|
7
|
+
|
|
8
|
+
export type RunRowStatus = "running" | "success" | "error" | "idle";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Trailing status indicator shared by every run row: a spinner while running,
|
|
12
|
+
* a green/red dot on terminal states, nothing when idle. Status is shown here
|
|
13
|
+
* — it never replaces the row's semantic lead icon.
|
|
14
|
+
*/
|
|
15
|
+
export function RunRowStatusDot({ status }: { status: RunRowStatus }) {
|
|
16
|
+
if (status === "running") {
|
|
17
|
+
return <Loader2 className="h-3 w-3 shrink-0 animate-spin text-[var(--accent-text)]" />;
|
|
18
|
+
}
|
|
19
|
+
if (status === "success") {
|
|
20
|
+
return (
|
|
21
|
+
<span className="h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-success-text)]" />
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
if (status === "error") {
|
|
25
|
+
return (
|
|
26
|
+
<span className="h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-danger-text)]" />
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface RunRowShellProps {
|
|
33
|
+
/** Semantic lead glyph — always visible; never replaced by status. */
|
|
34
|
+
icon: ReactNode;
|
|
35
|
+
title: string;
|
|
36
|
+
/** Secondary inline text (tool path/command, or a reasoning preview). */
|
|
37
|
+
description?: string;
|
|
38
|
+
/** Render the description in mono (tools) vs prose (reasoning). */
|
|
39
|
+
descriptionMono?: boolean;
|
|
40
|
+
status?: RunRowStatus;
|
|
41
|
+
/** Live-ticks a duration while running. */
|
|
42
|
+
startTime?: number;
|
|
43
|
+
/** Static duration shown once the row is no longer running. */
|
|
44
|
+
durationMs?: number;
|
|
45
|
+
/** Radius shaping when rows are stacked into a group. */
|
|
46
|
+
groupPosition?: "single" | "first" | "middle" | "last";
|
|
47
|
+
/** Message shown below the header while collapsed (tool errors). */
|
|
48
|
+
collapsedError?: string;
|
|
49
|
+
actions?: ReactNode;
|
|
50
|
+
/** Controlled open state. Omit for internal (uncontrolled) state. */
|
|
51
|
+
open?: boolean;
|
|
52
|
+
onOpenChange?: (open: boolean) => void;
|
|
53
|
+
defaultOpen?: boolean;
|
|
54
|
+
className?: string;
|
|
55
|
+
contentClassName?: string;
|
|
56
|
+
/** Expanded body. When absent the row is not expandable. */
|
|
57
|
+
children?: ReactNode;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const SHAPE_CLASS: Record<
|
|
61
|
+
NonNullable<RunRowShellProps["groupPosition"]>,
|
|
62
|
+
string
|
|
63
|
+
> = {
|
|
64
|
+
single: "rounded-[var(--radius-lg)]",
|
|
65
|
+
first: "rounded-t-[var(--radius-lg)] rounded-b-[var(--radius-sm)]",
|
|
66
|
+
middle: "rounded-[var(--radius-sm)]",
|
|
67
|
+
last: "rounded-t-[var(--radius-sm)] rounded-b-[var(--radius-lg)]",
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Shared shell for the agent activity rows (reasoning + tool). Owns the
|
|
72
|
+
* bordered container, the lead icon badge, title/description, the trailing
|
|
73
|
+
* meta cluster (duration + status + chevron) and the collapsible body, so
|
|
74
|
+
* both row kinds read as one family instead of two bespoke layouts.
|
|
75
|
+
*/
|
|
76
|
+
export function RunRowShell({
|
|
77
|
+
icon,
|
|
78
|
+
title,
|
|
79
|
+
description,
|
|
80
|
+
descriptionMono = false,
|
|
81
|
+
status = "idle",
|
|
82
|
+
startTime,
|
|
83
|
+
durationMs,
|
|
84
|
+
groupPosition = "single",
|
|
85
|
+
collapsedError,
|
|
86
|
+
actions,
|
|
87
|
+
open: openProp,
|
|
88
|
+
onOpenChange,
|
|
89
|
+
defaultOpen = false,
|
|
90
|
+
className,
|
|
91
|
+
contentClassName,
|
|
92
|
+
children,
|
|
93
|
+
}: RunRowShellProps) {
|
|
94
|
+
const [openState, setOpenState] = useState(defaultOpen);
|
|
95
|
+
const isControlled = openProp !== undefined;
|
|
96
|
+
const open = isControlled ? openProp : openState;
|
|
97
|
+
const setOpen = (next: boolean) => {
|
|
98
|
+
if (!isControlled) setOpenState(next);
|
|
99
|
+
onOpenChange?.(next);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const isRunning = status === "running";
|
|
103
|
+
const expandable = children != null;
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<Collapsible.Root open={open} onOpenChange={setOpen}>
|
|
107
|
+
<div className="flex items-start gap-2">
|
|
108
|
+
<div
|
|
109
|
+
className={cn(
|
|
110
|
+
"min-w-0 flex-1 overflow-hidden border transition-colors",
|
|
111
|
+
"border-[var(--border-subtle)] bg-[var(--md3-surface-container)]",
|
|
112
|
+
expandable && "hover:border-border",
|
|
113
|
+
open && "border-border",
|
|
114
|
+
SHAPE_CLASS[groupPosition],
|
|
115
|
+
className,
|
|
116
|
+
)}
|
|
117
|
+
>
|
|
118
|
+
<Collapsible.Trigger asChild disabled={!expandable}>
|
|
119
|
+
<button
|
|
120
|
+
type="button"
|
|
121
|
+
className={cn(
|
|
122
|
+
"flex w-full items-center gap-2.5 px-3 py-2 text-left",
|
|
123
|
+
expandable ? "cursor-pointer" : "cursor-default",
|
|
124
|
+
)}
|
|
125
|
+
>
|
|
126
|
+
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-border bg-muted text-muted-foreground">
|
|
127
|
+
{icon}
|
|
128
|
+
</span>
|
|
129
|
+
|
|
130
|
+
<span className="shrink-0 whitespace-nowrap text-xs font-medium text-foreground">
|
|
131
|
+
{title}
|
|
132
|
+
</span>
|
|
133
|
+
{description ? (
|
|
134
|
+
<span
|
|
135
|
+
className={cn(
|
|
136
|
+
"hidden min-w-0 flex-1 truncate text-xs text-muted-foreground sm:inline",
|
|
137
|
+
descriptionMono && "font-mono",
|
|
138
|
+
)}
|
|
139
|
+
>
|
|
140
|
+
{description}
|
|
141
|
+
</span>
|
|
142
|
+
) : null}
|
|
143
|
+
|
|
144
|
+
<div className="ml-auto flex shrink-0 items-center gap-1.5">
|
|
145
|
+
{isRunning && startTime != null ? (
|
|
146
|
+
<LiveDuration startTime={startTime} />
|
|
147
|
+
) : durationMs != null ? (
|
|
148
|
+
<span className="text-[10px] font-mono tabular-nums text-muted-foreground">
|
|
149
|
+
{formatDuration(durationMs)}
|
|
150
|
+
</span>
|
|
151
|
+
) : null}
|
|
152
|
+
<RunRowStatusDot status={status} />
|
|
153
|
+
{expandable ? (
|
|
154
|
+
<ChevronRight
|
|
155
|
+
className={cn(
|
|
156
|
+
"h-3 w-3 shrink-0 text-muted-foreground transition-transform",
|
|
157
|
+
open && "rotate-90",
|
|
158
|
+
)}
|
|
159
|
+
/>
|
|
160
|
+
) : null}
|
|
161
|
+
</div>
|
|
162
|
+
</button>
|
|
163
|
+
</Collapsible.Trigger>
|
|
164
|
+
|
|
165
|
+
{collapsedError && !open ? (
|
|
166
|
+
<div className="border-t border-border px-3 py-2 text-xs text-[var(--surface-danger-text)]">
|
|
167
|
+
{collapsedError}
|
|
168
|
+
</div>
|
|
169
|
+
) : null}
|
|
170
|
+
|
|
171
|
+
{expandable ? (
|
|
172
|
+
<Collapsible.Content className="overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp">
|
|
173
|
+
<div className={cn("border-t border-border", contentClassName)}>
|
|
174
|
+
{children}
|
|
175
|
+
</div>
|
|
176
|
+
</Collapsible.Content>
|
|
177
|
+
) : null}
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
{actions ? (
|
|
181
|
+
<div
|
|
182
|
+
className="flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1"
|
|
183
|
+
onClick={(event) => event.stopPropagation()}
|
|
184
|
+
>
|
|
185
|
+
{actions}
|
|
186
|
+
</div>
|
|
187
|
+
) : null}
|
|
188
|
+
</div>
|
|
189
|
+
</Collapsible.Root>
|
|
190
|
+
);
|
|
191
|
+
}
|
package/dist/chunk-INMWNFAS.js
DELETED
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
formatDuration,
|
|
3
|
-
getToolCategory,
|
|
4
|
-
getToolDisplayMetadata,
|
|
5
|
-
getToolErrorText
|
|
6
|
-
} from "./chunk-ULDNFLIM.js";
|
|
7
|
-
import {
|
|
8
|
-
CommandPreview,
|
|
9
|
-
DiffPreview,
|
|
10
|
-
GlobResultsPreview,
|
|
11
|
-
GrepResultsPreview,
|
|
12
|
-
QuestionPreview,
|
|
13
|
-
WebSearchPreview,
|
|
14
|
-
WriteFilePreview
|
|
15
|
-
} from "./chunk-AAUNOHVL.js";
|
|
16
|
-
import {
|
|
17
|
-
CodeBlock
|
|
18
|
-
} from "./chunk-WUQDUBJG.js";
|
|
19
|
-
import {
|
|
20
|
-
cn
|
|
21
|
-
} from "./chunk-RQHJBTEU.js";
|
|
22
|
-
|
|
23
|
-
// src/run/expanded-tool-detail.tsx
|
|
24
|
-
import { memo } from "react";
|
|
25
|
-
import {
|
|
26
|
-
ArrowRight,
|
|
27
|
-
ArrowLeft,
|
|
28
|
-
AlertCircle,
|
|
29
|
-
Loader2,
|
|
30
|
-
FileText
|
|
31
|
-
} from "lucide-react";
|
|
32
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
33
|
-
var EXT_LANG = {
|
|
34
|
-
ts: "typescript",
|
|
35
|
-
tsx: "tsx",
|
|
36
|
-
js: "javascript",
|
|
37
|
-
jsx: "jsx",
|
|
38
|
-
rs: "rust",
|
|
39
|
-
py: "python",
|
|
40
|
-
go: "go",
|
|
41
|
-
rb: "ruby",
|
|
42
|
-
json: "json",
|
|
43
|
-
yaml: "yaml",
|
|
44
|
-
yml: "yaml",
|
|
45
|
-
toml: "toml",
|
|
46
|
-
md: "markdown",
|
|
47
|
-
css: "css",
|
|
48
|
-
scss: "scss",
|
|
49
|
-
html: "html",
|
|
50
|
-
sh: "bash",
|
|
51
|
-
bash: "bash",
|
|
52
|
-
zsh: "bash",
|
|
53
|
-
sql: "sql",
|
|
54
|
-
sol: "solidity",
|
|
55
|
-
proto: "protobuf"
|
|
56
|
-
};
|
|
57
|
-
function langFromPath(path) {
|
|
58
|
-
if (!path) return void 0;
|
|
59
|
-
const ext = path.split(".").pop()?.toLowerCase();
|
|
60
|
-
return ext ? EXT_LANG[ext] : void 0;
|
|
61
|
-
}
|
|
62
|
-
function formatOutput(value) {
|
|
63
|
-
if (value == null) return "";
|
|
64
|
-
if (typeof value === "string") return value;
|
|
65
|
-
try {
|
|
66
|
-
return JSON.stringify(value, null, 2);
|
|
67
|
-
} catch {
|
|
68
|
-
return String(value);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
var ExpandedToolDetail = memo(({ part }) => {
|
|
72
|
-
const meta = getToolDisplayMetadata(part);
|
|
73
|
-
const { status, input, output, error } = part.state;
|
|
74
|
-
if (meta.displayVariant === "command") {
|
|
75
|
-
return /* @__PURE__ */ jsx(CommandPreview, { part });
|
|
76
|
-
}
|
|
77
|
-
if (meta.displayVariant === "write-file") {
|
|
78
|
-
return /* @__PURE__ */ jsx(WriteFilePreview, { part });
|
|
79
|
-
}
|
|
80
|
-
if (meta.displayVariant === "grep") {
|
|
81
|
-
return /* @__PURE__ */ jsx(GrepResultsPreview, { part });
|
|
82
|
-
}
|
|
83
|
-
if (meta.displayVariant === "glob") {
|
|
84
|
-
return /* @__PURE__ */ jsx(GlobResultsPreview, { part });
|
|
85
|
-
}
|
|
86
|
-
if (meta.displayVariant === "web-search") {
|
|
87
|
-
return /* @__PURE__ */ jsx(WebSearchPreview, { part });
|
|
88
|
-
}
|
|
89
|
-
if (meta.displayVariant === "question") {
|
|
90
|
-
return /* @__PURE__ */ jsx(QuestionPreview, { part });
|
|
91
|
-
}
|
|
92
|
-
if (meta.displayVariant === "diff") {
|
|
93
|
-
return /* @__PURE__ */ jsx(DiffPreview, { part });
|
|
94
|
-
}
|
|
95
|
-
if (meta.displayVariant === "read-file") {
|
|
96
|
-
return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card shadow-[var(--shadow-card)]", children: [
|
|
97
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 border-b border-border bg-card px-3 py-2", children: [
|
|
98
|
-
/* @__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" }) }),
|
|
99
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex items-center gap-2", children: [
|
|
100
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-foreground", children: "Read file" }),
|
|
101
|
-
meta.targetPath ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs font-mono text-muted-foreground", children: meta.targetPath }) : null
|
|
102
|
-
] })
|
|
103
|
-
] }),
|
|
104
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2 px-3 py-2.5", children: [
|
|
105
|
-
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." }),
|
|
106
|
-
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
|
|
107
|
-
] })
|
|
108
|
-
] });
|
|
109
|
-
}
|
|
110
|
-
const inputStr = formatOutput(input);
|
|
111
|
-
const outputStr = formatOutput(output);
|
|
112
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
113
|
-
inputStr && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card", children: [
|
|
114
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2", children: [
|
|
115
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "h-3 w-3 text-primary" }),
|
|
116
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground", children: "Input" })
|
|
117
|
-
] }),
|
|
118
|
-
/* @__PURE__ */ jsx(CodeBlock, { code: inputStr, language: "json", className: "rounded-none border-0" })
|
|
119
|
-
] }),
|
|
120
|
-
status === "completed" && outputStr && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card", children: [
|
|
121
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2", children: [
|
|
122
|
-
/* @__PURE__ */ jsx(ArrowLeft, { className: "h-3 w-3 text-primary" }),
|
|
123
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground", children: "Output" })
|
|
124
|
-
] }),
|
|
125
|
-
/* @__PURE__ */ jsx(
|
|
126
|
-
CodeBlock,
|
|
127
|
-
{
|
|
128
|
-
code: outputStr.length > 2e3 ? outputStr.slice(0, 2e3) + "\n...(truncated)" : outputStr,
|
|
129
|
-
language: "json",
|
|
130
|
-
className: "rounded-none border-0"
|
|
131
|
-
}
|
|
132
|
-
)
|
|
133
|
-
] }),
|
|
134
|
-
error && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-[var(--surface-danger-border)]", children: [
|
|
135
|
-
/* @__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: [
|
|
136
|
-
/* @__PURE__ */ jsx(AlertCircle, { className: "h-3 w-3 text-[var(--surface-danger-text)]" }),
|
|
137
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-[var(--surface-danger-text)]", children: "Error" })
|
|
138
|
-
] }),
|
|
139
|
-
/* @__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 })
|
|
140
|
-
] }),
|
|
141
|
-
(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: [
|
|
142
|
-
/* @__PURE__ */ jsx(Loader2, { className: cn("h-3 w-3 animate-spin text-primary") }),
|
|
143
|
-
"Running\u2026"
|
|
144
|
-
] })
|
|
145
|
-
] });
|
|
146
|
-
});
|
|
147
|
-
ExpandedToolDetail.displayName = "ExpandedToolDetail";
|
|
148
|
-
|
|
149
|
-
// src/run/run-item-primitives.tsx
|
|
150
|
-
import { useEffect, useState } from "react";
|
|
151
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
152
|
-
function LiveDuration({ startTime }) {
|
|
153
|
-
const [elapsed, setElapsed] = useState(Date.now() - startTime);
|
|
154
|
-
useEffect(() => {
|
|
155
|
-
const id = setInterval(() => setElapsed(Date.now() - startTime), 100);
|
|
156
|
-
return () => clearInterval(id);
|
|
157
|
-
}, [startTime]);
|
|
158
|
-
return /* @__PURE__ */ jsx2("span", { className: "text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums", children: formatDuration(elapsed) });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// src/run/inline-tool-item.tsx
|
|
162
|
-
import { memo as memo2, useState as useState2 } from "react";
|
|
163
|
-
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
164
|
-
import {
|
|
165
|
-
Loader2 as Loader22,
|
|
166
|
-
CheckCircle2,
|
|
167
|
-
AlertCircle as AlertCircle2,
|
|
168
|
-
ChevronDown,
|
|
169
|
-
ChevronRight,
|
|
170
|
-
Terminal,
|
|
171
|
-
FileEdit,
|
|
172
|
-
FileSearch,
|
|
173
|
-
Search,
|
|
174
|
-
PencilLine,
|
|
175
|
-
Bot,
|
|
176
|
-
Globe,
|
|
177
|
-
ClipboardList,
|
|
178
|
-
Settings
|
|
179
|
-
} from "lucide-react";
|
|
180
|
-
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
181
|
-
var TOOL_CATEGORY_ICON_MAP = {
|
|
182
|
-
command: Terminal,
|
|
183
|
-
write: FileEdit,
|
|
184
|
-
read: FileSearch,
|
|
185
|
-
search: Search,
|
|
186
|
-
edit: PencilLine,
|
|
187
|
-
task: Bot,
|
|
188
|
-
web: Globe,
|
|
189
|
-
todo: ClipboardList,
|
|
190
|
-
other: Settings
|
|
191
|
-
};
|
|
192
|
-
var InlineToolItem = memo2(
|
|
193
|
-
({
|
|
194
|
-
part,
|
|
195
|
-
renderToolDetail,
|
|
196
|
-
groupPosition = "single",
|
|
197
|
-
className,
|
|
198
|
-
contentClassName,
|
|
199
|
-
actions,
|
|
200
|
-
title: titleOverride,
|
|
201
|
-
description: descriptionOverride
|
|
202
|
-
}) => {
|
|
203
|
-
const [open, setOpen] = useState2(false);
|
|
204
|
-
const meta = getToolDisplayMetadata(part);
|
|
205
|
-
const title = titleOverride ?? meta.title;
|
|
206
|
-
const description = descriptionOverride ?? meta.description;
|
|
207
|
-
const { status } = part.state;
|
|
208
|
-
const errorText = getToolErrorText(part);
|
|
209
|
-
const isRunning = status === "pending" || status === "running";
|
|
210
|
-
const isError = status === "error";
|
|
211
|
-
const isComplete = status === "completed";
|
|
212
|
-
const startTime = part.state.time?.start;
|
|
213
|
-
const endTime = part.state.time?.end;
|
|
214
|
-
const durationMs = startTime && endTime ? endTime - startTime : void 0;
|
|
215
|
-
const category = getToolCategory(part.tool);
|
|
216
|
-
const DefaultIcon = TOOL_CATEGORY_ICON_MAP[category] ?? Settings;
|
|
217
|
-
const shapeClass = {
|
|
218
|
-
single: "rounded-[var(--radius-lg)]",
|
|
219
|
-
first: "rounded-t-[var(--radius-lg)] rounded-b-[var(--radius-sm)]",
|
|
220
|
-
middle: "rounded-[var(--radius-sm)]",
|
|
221
|
-
last: "rounded-t-[var(--radius-sm)] rounded-b-[var(--radius-lg)]"
|
|
222
|
-
}[groupPosition];
|
|
223
|
-
return /* @__PURE__ */ jsxs2(Collapsible.Root, { open, onOpenChange: setOpen, children: [
|
|
224
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-2", children: [
|
|
225
|
-
/* @__PURE__ */ jsx3(Collapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
|
|
226
|
-
"button",
|
|
227
|
-
{
|
|
228
|
-
className: cn(
|
|
229
|
-
"w-full border text-left transition-colors",
|
|
230
|
-
"border-[var(--border-subtle)] bg-[var(--md3-surface-container)] hover:border-border hover:bg-[var(--md3-surface-container-high)]",
|
|
231
|
-
open && "border-border bg-[var(--md3-surface-container-high)]",
|
|
232
|
-
shapeClass,
|
|
233
|
-
className
|
|
234
|
-
),
|
|
235
|
-
children: [
|
|
236
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2.5 px-3 py-2.5", children: [
|
|
237
|
-
/* @__PURE__ */ jsx3("div", { className: cn(
|
|
238
|
-
"shrink-0",
|
|
239
|
-
isRunning && "text-[var(--accent-text)]",
|
|
240
|
-
isComplete && "text-[var(--surface-success-text)]",
|
|
241
|
-
isError && "text-[var(--surface-danger-text)]",
|
|
242
|
-
!isRunning && !isComplete && !isError && "text-muted-foreground"
|
|
243
|
-
), 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" }) }),
|
|
244
|
-
/* @__PURE__ */ jsx3("span", { className: "truncate text-xs font-medium text-foreground", children: title }),
|
|
245
|
-
description ? /* @__PURE__ */ jsx3("span", { className: "hidden truncate text-xs font-mono text-muted-foreground sm:inline", children: description }) : null,
|
|
246
|
-
/* @__PURE__ */ jsxs2("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
|
|
247
|
-
isRunning && startTime ? /* @__PURE__ */ jsx3(LiveDuration, { startTime }) : null,
|
|
248
|
-
!isRunning && durationMs != null ? /* @__PURE__ */ jsx3("span", { className: "text-[10px] font-mono tabular-nums text-muted-foreground", children: formatDuration(durationMs) }) : null,
|
|
249
|
-
isError ? /* @__PURE__ */ jsx3("span", { className: "text-[10px] font-medium text-[var(--surface-danger-text)]", children: "failed" }) : null,
|
|
250
|
-
isRunning ? /* @__PURE__ */ jsx3("span", { className: "text-[10px] font-medium text-[var(--accent-text)]", children: "running" }) : null,
|
|
251
|
-
open ? /* @__PURE__ */ jsx3(ChevronDown, { className: "h-3 w-3 text-muted-foreground" }) : /* @__PURE__ */ jsx3(ChevronRight, { className: "h-3 w-3 text-muted-foreground" })
|
|
252
|
-
] })
|
|
253
|
-
] }),
|
|
254
|
-
errorText && !open ? /* @__PURE__ */ jsx3("div", { className: "border-t border-border px-3 py-2 text-xs text-red-200", children: errorText }) : null
|
|
255
|
-
]
|
|
256
|
-
}
|
|
257
|
-
) }),
|
|
258
|
-
actions ? /* @__PURE__ */ jsx3(
|
|
259
|
-
"div",
|
|
260
|
-
{
|
|
261
|
-
className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1",
|
|
262
|
-
onClick: (event) => event.stopPropagation(),
|
|
263
|
-
children: actions
|
|
264
|
-
}
|
|
265
|
-
) : null
|
|
266
|
-
] }),
|
|
267
|
-
/* @__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 }) }) })
|
|
268
|
-
] });
|
|
269
|
-
}
|
|
270
|
-
);
|
|
271
|
-
InlineToolItem.displayName = "InlineToolItem";
|
|
272
|
-
|
|
273
|
-
// src/run/tool-call-step.tsx
|
|
274
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
275
|
-
var EXT_LANGUAGE = {
|
|
276
|
-
ts: "typescript",
|
|
277
|
-
tsx: "typescript",
|
|
278
|
-
js: "javascript",
|
|
279
|
-
jsx: "javascript",
|
|
280
|
-
mjs: "javascript",
|
|
281
|
-
cjs: "javascript",
|
|
282
|
-
css: "css",
|
|
283
|
-
scss: "scss",
|
|
284
|
-
json: "json",
|
|
285
|
-
jsonc: "json",
|
|
286
|
-
md: "markdown",
|
|
287
|
-
mdx: "markdown",
|
|
288
|
-
py: "python",
|
|
289
|
-
sh: "bash",
|
|
290
|
-
bash: "bash",
|
|
291
|
-
zsh: "bash",
|
|
292
|
-
html: "html",
|
|
293
|
-
htm: "html",
|
|
294
|
-
yaml: "yaml",
|
|
295
|
-
yml: "yaml",
|
|
296
|
-
toml: "toml",
|
|
297
|
-
rs: "rust",
|
|
298
|
-
go: "go",
|
|
299
|
-
sql: "sql",
|
|
300
|
-
xml: "xml"
|
|
301
|
-
};
|
|
302
|
-
function inferLanguage(detail, language) {
|
|
303
|
-
if (language) return language;
|
|
304
|
-
if (!detail) return void 0;
|
|
305
|
-
const ext = detail.split(".").pop()?.toLowerCase();
|
|
306
|
-
return ext ? EXT_LANGUAGE[ext] : void 0;
|
|
307
|
-
}
|
|
308
|
-
var STATUS_MAP = {
|
|
309
|
-
running: "running",
|
|
310
|
-
success: "completed",
|
|
311
|
-
error: "error"
|
|
312
|
-
};
|
|
313
|
-
function ToolCallStep({
|
|
314
|
-
type,
|
|
315
|
-
label,
|
|
316
|
-
status,
|
|
317
|
-
detail,
|
|
318
|
-
output,
|
|
319
|
-
language,
|
|
320
|
-
duration,
|
|
321
|
-
className,
|
|
322
|
-
actions,
|
|
323
|
-
part
|
|
324
|
-
}) {
|
|
325
|
-
const resolvedPart = part ?? {
|
|
326
|
-
type: "tool",
|
|
327
|
-
id: `${type}:${label}`,
|
|
328
|
-
tool: type,
|
|
329
|
-
state: {
|
|
330
|
-
status: STATUS_MAP[status],
|
|
331
|
-
input: detail ? { detail } : void 0,
|
|
332
|
-
output,
|
|
333
|
-
time: duration != null ? { start: 0, end: duration } : void 0
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
const lang = inferLanguage(detail, language);
|
|
337
|
-
return /* @__PURE__ */ jsx4(
|
|
338
|
-
InlineToolItem,
|
|
339
|
-
{
|
|
340
|
-
part: resolvedPart,
|
|
341
|
-
title: label,
|
|
342
|
-
description: detail,
|
|
343
|
-
className,
|
|
344
|
-
actions,
|
|
345
|
-
renderToolDetail: part ? void 0 : output ? () => /* @__PURE__ */ jsx4(
|
|
346
|
-
CodeBlock,
|
|
347
|
-
{
|
|
348
|
-
code: output,
|
|
349
|
-
language: lang,
|
|
350
|
-
className: "max-h-72 overflow-auto text-xs"
|
|
351
|
-
}
|
|
352
|
-
) : () => null
|
|
353
|
-
}
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
function ToolCallGroup({ title, children, className }) {
|
|
357
|
-
return /* @__PURE__ */ jsxs3("div", { className: ["my-2 space-y-2", className].filter(Boolean).join(" "), children: [
|
|
358
|
-
title && /* @__PURE__ */ jsx4("div", { className: "mb-1 px-1 text-xs font-medium uppercase tracking-wider text-muted-foreground", children: title }),
|
|
359
|
-
children
|
|
360
|
-
] });
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
export {
|
|
364
|
-
ExpandedToolDetail,
|
|
365
|
-
LiveDuration,
|
|
366
|
-
InlineToolItem,
|
|
367
|
-
ToolCallStep,
|
|
368
|
-
ToolCallGroup
|
|
369
|
-
};
|