@tangle-network/ui 11.10.0 → 11.11.1
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 +14 -0
- package/README.md +4 -1
- package/dist/active-sessions-store-Gt1R0rFG.js +262 -0
- package/dist/{active-sessions-store-CeOmXgv5.d.ts → active-sessions-store-nl70ZnMC.d.ts} +40 -41
- package/dist/artifact-pane-BL_DFWNl.d.ts +32 -0
- package/dist/artifact-pane-DMXT9a8U.js +70 -0
- package/dist/auth-DOETfnd9.js +154 -0
- package/dist/auth.d.ts +2 -74
- package/dist/auth.js +2 -16
- package/dist/branding-26d5ARIr.d.ts +14 -0
- package/dist/button-C87nEe2R.js +78 -0
- package/dist/button-yoIv77e2.d.ts +16 -0
- package/dist/chat-D4jAfEmj.js +667 -0
- package/dist/chat.d.ts +2 -201
- package/dist/chat.js +2 -31
- package/dist/code-block-B36KVUSN.js +165 -0
- package/dist/code-block-B9miUPht.d.ts +23 -0
- package/dist/diff-preview-BcK3nRXb.js +533 -0
- package/dist/document-editor-pane-BcoABlhn.d.ts +131 -0
- package/dist/document-editor-pane-BxlPjaTP.js +1287 -0
- package/dist/dropdown-menu-BpcLa5vF.js +101 -0
- package/dist/editor.d.ts +76 -78
- package/dist/editor.js +2 -34
- package/dist/file-format-BgXbr-Ib.js +160 -0
- package/dist/files-Bug33qCl.js +743 -0
- package/dist/files.d.ts +2 -243
- package/dist/files.js +3 -41
- package/dist/focus-BcE_SHqz.js +57 -0
- package/dist/format-DfcLWqMa.js +54 -0
- package/dist/hooks.d.ts +30 -37
- package/dist/hooks.js +111 -46
- package/dist/index-2UntyjBb.d.ts +52 -0
- package/dist/index-BgUHilZm.d.ts +108 -0
- package/dist/index-COgqsFAQ.d.ts +42 -0
- package/dist/index-CPDET_s1.d.ts +549 -0
- package/dist/index-CUhfHT_V.d.ts +204 -0
- package/dist/index-Cg6gYAqh.d.ts +73 -0
- package/dist/index-Cq-EJzqW.d.ts +16 -0
- package/dist/index-DhYmSaLF.d.ts +245 -0
- package/dist/index-DjKxO357.d.ts +128 -0
- package/dist/index.d.ts +26 -43
- package/dist/index.js +35 -472
- package/dist/markdown-BGqicV82.js +45 -0
- package/dist/markdown.d.ts +3 -18
- package/dist/markdown.js +3 -15
- package/dist/message-vhUI0c5G.d.ts +16 -0
- package/dist/nav.d.ts +6 -8
- package/dist/nav.js +29 -11
- package/dist/openui-artifact-renderer-D3E5bIAI.d.ts +114 -0
- package/dist/openui-artifact-renderer-DrU1AdVk.js +266 -0
- package/dist/openui.d.ts +2 -115
- package/dist/openui.js +2 -13
- package/dist/parts-5mhy9yJ3.d.ts +37 -0
- package/dist/primitives-Cb8GGVKr.js +1239 -0
- package/dist/primitives.d.ts +5 -525
- package/dist/primitives.js +9 -212
- package/dist/redaction-CGGB2ENG.js +74 -0
- package/dist/redaction.d.ts +2 -42
- package/dist/redaction.js +2 -7
- package/dist/run-OyWmIDqu.d.ts +41 -0
- package/dist/run-ZsIKPA6J.js +17 -0
- package/dist/run-group-BACLbCFl.js +410 -0
- package/dist/run.d.ts +3 -126
- package/dist/run.js +5 -40
- package/dist/sdk-hooks.d.ts +2 -285
- package/dist/sdk-hooks.js +3 -36
- package/dist/stores.d.ts +13 -14
- package/dist/stores.js +34 -76
- package/dist/table-Bss73DhB.js +146 -0
- package/dist/tabs-BVHR6NkO.js +40 -0
- package/dist/text-shimmer-BUUo6I-g.js +64 -0
- package/dist/tool-call-feed-BeB1_4pX.d.ts +47 -0
- package/dist/tool-call-feed-Djt2q11V.js +109 -0
- package/dist/tool-call-step-DNebqhmX.js +434 -0
- package/dist/tool-display-BAuAVa43.js +158 -0
- package/dist/{tool-display-z4JcDmMQ.d.ts → tool-display-DgmL5rIU.d.ts} +16 -16
- package/dist/tool-previews.d.ts +2 -48
- package/dist/tool-previews.js +2 -23
- package/dist/types.d.ts +6 -19
- package/dist/types.js +0 -1
- package/dist/use-auto-scroll-C5Pjeqon.js +153 -0
- package/dist/use-sse-stream-BVgO1QBN.js +884 -0
- package/dist/use-sse-stream-Dm6R5YWz.d.ts +282 -0
- package/dist/utils-Bl_CZ0Qp.js +37 -0
- package/dist/{chunk-RQHJBTEU.js → utils-C_uf36nf.js} +4 -6
- package/dist/utils.d.ts +2 -104
- package/dist/utils.js +6 -44
- package/package.json +39 -41
- package/src/lib/focus.ts +2 -1
- package/dist/artifact-pane-DpuWcAiF.d.ts +0 -33
- package/dist/button-CMQuQEW_.d.ts +0 -17
- package/dist/chunk-34A66VBG.js +0 -214
- package/dist/chunk-3OI2QKFD.js +0 -0
- package/dist/chunk-3XXBZL53.js +0 -174
- package/dist/chunk-42PAH5D2.js +0 -112
- package/dist/chunk-4CLN43XT.js +0 -45
- package/dist/chunk-55WHV7SS.js +0 -1604
- package/dist/chunk-565EATZZ.js +0 -156
- package/dist/chunk-5Z5ZYMOJ.js +0 -0
- package/dist/chunk-6BGQA4BQ.js +0 -0
- package/dist/chunk-BEBXZPHW.js +0 -299
- package/dist/chunk-C5WF4WMV.js +0 -734
- package/dist/chunk-HFL6R6IF.js +0 -37
- package/dist/chunk-HGML45QH.js +0 -104
- package/dist/chunk-HMAPIH7L.js +0 -595
- package/dist/chunk-K5XFRUS4.js +0 -1401
- package/dist/chunk-KFQGHD73.js +0 -198
- package/dist/chunk-L57WRIND.js +0 -59
- package/dist/chunk-LTEKI7YJ.js +0 -59
- package/dist/chunk-M3QZK62R.js +0 -233
- package/dist/chunk-ND3ZFXQK.js +0 -179
- package/dist/chunk-OEX7NZE3.js +0 -321
- package/dist/chunk-OL5GYLHV.js +0 -60
- package/dist/chunk-QGFYBNSO.js +0 -133
- package/dist/chunk-R7B3UWPF.js +0 -550
- package/dist/chunk-R7SUY4E3.js +0 -65
- package/dist/chunk-REJESC5U.js +0 -117
- package/dist/chunk-RQGKSCEZ.js +0 -0
- package/dist/chunk-SNLR2AEA.js +0 -40
- package/dist/chunk-WKWBTL2V.js +0 -15
- package/dist/chunk-X7CU776B.js +0 -1048
- package/dist/chunk-XU3HB5QL.js +0 -127
- package/dist/chunk-YTO5V6QS.js +0 -19
- package/dist/chunk-YU4E5J2N.js +0 -437
- package/dist/chunk-YZ6AK25N.js +0 -886
- package/dist/code-block-0kSpWMnf.d.ts +0 -25
- package/dist/document-editor-pane-IAEQn_Dl.d.ts +0 -128
- package/dist/document-editor-pane-QHDOBA43.js +0 -13
- package/dist/message-BHWbxBtT.d.ts +0 -15
- package/dist/parts-dj7AcUg0.d.ts +0 -36
- package/dist/run-PfLmDAox.d.ts +0 -41
- package/dist/tool-call-feed-D9iofJgW.d.ts +0 -46
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
import { i as focusRing } from "./focus-BcE_SHqz.js";
|
|
2
|
+
import { t as cn } from "./utils-C_uf36nf.js";
|
|
3
|
+
import { r as getToolDisplayMetadata } from "./tool-display-BAuAVa43.js";
|
|
4
|
+
import { n as useRunCollapseState, r as useRunGroups, t as useAutoScroll } from "./use-auto-scroll-C5Pjeqon.js";
|
|
5
|
+
import { n as ToolCallStep, t as ToolCallGroup } from "./tool-call-step-DNebqhmX.js";
|
|
6
|
+
import { t as Markdown } from "./markdown-BGqicV82.js";
|
|
7
|
+
import { n as InlineThinkingItem, t as RunGroup } from "./run-group-BACLbCFl.js";
|
|
8
|
+
import { t as OpenUIArtifactRenderer } from "./openui-artifact-renderer-DrU1AdVk.js";
|
|
9
|
+
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { AlertTriangle, ArrowDown, CheckCircle2, CircleDot, FileText, Info } from "lucide-react";
|
|
12
|
+
//#region src/chat/user-message.tsx
|
|
13
|
+
function formatTime$1(date) {
|
|
14
|
+
return date.toLocaleTimeString(void 0, {
|
|
15
|
+
hour: "numeric",
|
|
16
|
+
minute: "2-digit"
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The single user message bubble — a quiet, right-aligned fill on the muted
|
|
21
|
+
* surface (no border, no loud fill, no uppercase label). The timestamp sits
|
|
22
|
+
* beside the bubble and appears on hover, so it costs no height. Used by both
|
|
23
|
+
* the run/message list (session-model `parts`) and AgentTimeline (direct
|
|
24
|
+
* `content`/`timestamp`).
|
|
25
|
+
*/
|
|
26
|
+
const UserMessage = memo(({ message: _message, parts, content, timestamp, actions }) => {
|
|
27
|
+
const text = content ?? (parts ?? []).filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
28
|
+
if (!text.trim()) return null;
|
|
29
|
+
return /* @__PURE__ */ jsx("div", {
|
|
30
|
+
className: "flex justify-end",
|
|
31
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
32
|
+
className: "group flex max-w-[78%] flex-col items-end gap-2",
|
|
33
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
34
|
+
className: "relative w-full rounded-2xl bg-muted/50 px-4 py-3",
|
|
35
|
+
children: [timestamp ? /* @__PURE__ */ jsx("span", {
|
|
36
|
+
"data-user-message-time": "",
|
|
37
|
+
className: "pointer-events-none absolute right-full top-1/2 mr-3 -translate-y-1/2 whitespace-nowrap text-[var(--font-size-xs)] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
|
|
38
|
+
children: formatTime$1(timestamp)
|
|
39
|
+
}) : null, /* @__PURE__ */ jsx("div", {
|
|
40
|
+
className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[1.5] text-foreground",
|
|
41
|
+
children: text
|
|
42
|
+
})]
|
|
43
|
+
}), actions ? /* @__PURE__ */ jsx("div", {
|
|
44
|
+
className: "flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground",
|
|
45
|
+
children: actions
|
|
46
|
+
}) : null]
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
UserMessage.displayName = "UserMessage";
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/chat/message-list.tsx
|
|
53
|
+
/**
|
|
54
|
+
* Maps GroupedMessage[] to UserMessage and RunGroup components.
|
|
55
|
+
* This is the main render list for the chat view.
|
|
56
|
+
*/
|
|
57
|
+
const MessageList = memo(({ groups, partMap, isCollapsed, onToggleCollapse, branding, renderToolDetail, renderRunActions, renderUserMessageActions, renderToolActions }) => {
|
|
58
|
+
return /* @__PURE__ */ jsx("div", {
|
|
59
|
+
className: "space-y-4",
|
|
60
|
+
children: groups.map((group) => {
|
|
61
|
+
if (group.type === "user") {
|
|
62
|
+
const messageParts = partMap[group.message.id] ?? [];
|
|
63
|
+
return /* @__PURE__ */ jsx(UserMessage, {
|
|
64
|
+
message: group.message,
|
|
65
|
+
parts: messageParts,
|
|
66
|
+
actions: renderUserMessageActions?.(group.message, messageParts)
|
|
67
|
+
}, group.message.id);
|
|
68
|
+
}
|
|
69
|
+
return /* @__PURE__ */ jsx(RunGroup, {
|
|
70
|
+
run: group.run,
|
|
71
|
+
partMap,
|
|
72
|
+
collapsed: isCollapsed(group.run.id),
|
|
73
|
+
onToggle: () => onToggleCollapse(group.run.id),
|
|
74
|
+
branding,
|
|
75
|
+
renderToolDetail,
|
|
76
|
+
headerActions: renderRunActions?.(group.run),
|
|
77
|
+
renderToolActions
|
|
78
|
+
}, group.run.id);
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
MessageList.displayName = "MessageList";
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/chat/thinking-indicator.tsx
|
|
85
|
+
function ThinkingIndicator({ className }) {
|
|
86
|
+
const [elapsed, setElapsed] = useState(0);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
const interval = window.setInterval(() => setElapsed((current) => current + 1), 1e3);
|
|
89
|
+
return () => window.clearInterval(interval);
|
|
90
|
+
}, []);
|
|
91
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
92
|
+
role: "status",
|
|
93
|
+
"aria-label": "Agent is thinking",
|
|
94
|
+
className: cn("flex items-center gap-2 px-3 py-1.5", className),
|
|
95
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
96
|
+
className: "flex gap-[3px]",
|
|
97
|
+
children: [
|
|
98
|
+
/* @__PURE__ */ jsx("span", {
|
|
99
|
+
className: "h-[var(--indicator-dot-size)] w-[var(--indicator-dot-size)] animate-bounce rounded-full bg-[var(--brand-glow)]",
|
|
100
|
+
style: { animationDelay: "0ms" }
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ jsx("span", {
|
|
103
|
+
className: "h-[var(--indicator-dot-size)] w-[var(--indicator-dot-size)] animate-bounce rounded-full bg-[var(--brand-glow)]",
|
|
104
|
+
style: { animationDelay: "150ms" }
|
|
105
|
+
}),
|
|
106
|
+
/* @__PURE__ */ jsx("span", {
|
|
107
|
+
className: "h-[var(--indicator-dot-size)] w-[var(--indicator-dot-size)] animate-bounce rounded-full bg-[var(--brand-glow)]",
|
|
108
|
+
style: { animationDelay: "300ms" }
|
|
109
|
+
})
|
|
110
|
+
]
|
|
111
|
+
}), elapsed > 3 && /* @__PURE__ */ jsxs("span", {
|
|
112
|
+
className: "text-[var(--font-size-xs)] tabular-nums text-muted-foreground",
|
|
113
|
+
children: [elapsed, "s"]
|
|
114
|
+
})]
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/chat/agent-timeline.tsx
|
|
119
|
+
const TONE_STYLES = {
|
|
120
|
+
default: {
|
|
121
|
+
card: "border-border bg-card",
|
|
122
|
+
text: "text-foreground",
|
|
123
|
+
icon: CircleDot
|
|
124
|
+
},
|
|
125
|
+
info: {
|
|
126
|
+
card: "border-[var(--surface-info-border)] bg-[var(--surface-info-bg)]",
|
|
127
|
+
text: "text-[var(--surface-info-text)]",
|
|
128
|
+
icon: Info
|
|
129
|
+
},
|
|
130
|
+
success: {
|
|
131
|
+
card: "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]",
|
|
132
|
+
text: "text-[var(--surface-success-text)]",
|
|
133
|
+
icon: CheckCircle2
|
|
134
|
+
},
|
|
135
|
+
warning: {
|
|
136
|
+
card: "border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)]",
|
|
137
|
+
text: "text-[var(--surface-warning-text)]",
|
|
138
|
+
icon: AlertTriangle
|
|
139
|
+
},
|
|
140
|
+
error: {
|
|
141
|
+
card: "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)]",
|
|
142
|
+
text: "text-[var(--surface-danger-text)]",
|
|
143
|
+
icon: AlertTriangle
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
function stepKind(item) {
|
|
147
|
+
if (item.kind === "message") return item.role === "user" ? "user" : "prose";
|
|
148
|
+
if (item.kind === "status" || item.kind === "artifact") return "card";
|
|
149
|
+
return "tool";
|
|
150
|
+
}
|
|
151
|
+
function spacingBefore(prev, next) {
|
|
152
|
+
if (prev === void 0) return "";
|
|
153
|
+
if (prev === "user" || next === "user") return "mt-4";
|
|
154
|
+
if (prev === "card" || next === "card") return "mt-2";
|
|
155
|
+
if (prev === "tool" || next === "tool") return "mt-1";
|
|
156
|
+
return "mt-3";
|
|
157
|
+
}
|
|
158
|
+
const ROW_BLEED = "-mx-3";
|
|
159
|
+
function AssistantMessage({ item }) {
|
|
160
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
161
|
+
item.content && /* @__PURE__ */ jsx(Markdown, {
|
|
162
|
+
className: "tangle-prose text-[var(--font-size-base)] leading-[1.5]",
|
|
163
|
+
children: item.content
|
|
164
|
+
}),
|
|
165
|
+
item.isStreaming && /* @__PURE__ */ jsx("span", {
|
|
166
|
+
"aria-hidden": true,
|
|
167
|
+
"data-streaming-caret": "",
|
|
168
|
+
className: "ml-0.5 inline-block h-[1em] w-0.5 animate-pulse rounded-full bg-muted-foreground align-text-bottom"
|
|
169
|
+
}),
|
|
170
|
+
item.toolCalls && /* @__PURE__ */ jsx("div", {
|
|
171
|
+
className: "mt-1",
|
|
172
|
+
children: item.toolCalls
|
|
173
|
+
}),
|
|
174
|
+
item.after && /* @__PURE__ */ jsx("div", {
|
|
175
|
+
className: "mt-3 border-t border-border pt-3",
|
|
176
|
+
children: item.after
|
|
177
|
+
})
|
|
178
|
+
] });
|
|
179
|
+
}
|
|
180
|
+
function StatusCard({ item }) {
|
|
181
|
+
const tone = TONE_STYLES[item.tone ?? "default"];
|
|
182
|
+
const Icon = tone.icon;
|
|
183
|
+
return /* @__PURE__ */ jsx("div", {
|
|
184
|
+
className: cn("rounded-[var(--radius-lg)] border px-4 py-3", tone.card),
|
|
185
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
186
|
+
className: "flex items-start gap-3",
|
|
187
|
+
children: [/* @__PURE__ */ jsx(Icon, { className: cn("mt-0.5 h-4 w-4 shrink-0", tone.text) }), /* @__PURE__ */ jsxs("div", {
|
|
188
|
+
className: "min-w-0",
|
|
189
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
190
|
+
className: cn("text-sm font-medium", tone.text),
|
|
191
|
+
children: item.label
|
|
192
|
+
}), item.detail && /* @__PURE__ */ jsx("div", {
|
|
193
|
+
className: "mt-0.5 text-sm text-muted-foreground",
|
|
194
|
+
children: item.detail
|
|
195
|
+
})]
|
|
196
|
+
})]
|
|
197
|
+
})
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
function ArtifactCard({ item }) {
|
|
201
|
+
const tone = TONE_STYLES[item.tone ?? "default"];
|
|
202
|
+
const content = /* @__PURE__ */ jsx("div", {
|
|
203
|
+
className: cn("rounded-[var(--radius-lg)] border px-4 py-3", tone.card),
|
|
204
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
205
|
+
className: "flex items-start gap-3",
|
|
206
|
+
children: [
|
|
207
|
+
/* @__PURE__ */ jsx("div", {
|
|
208
|
+
className: "mt-0.5 flex h-[var(--avatar-size)] w-[var(--avatar-size)] shrink-0 items-center justify-center rounded-[var(--radius-md)] bg-muted/50 text-foreground",
|
|
209
|
+
children: item.icon ?? /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4" })
|
|
210
|
+
}),
|
|
211
|
+
/* @__PURE__ */ jsxs("div", {
|
|
212
|
+
className: "min-w-0 flex-1",
|
|
213
|
+
children: [
|
|
214
|
+
/* @__PURE__ */ jsx("div", {
|
|
215
|
+
className: "text-sm font-medium text-foreground",
|
|
216
|
+
children: item.title
|
|
217
|
+
}),
|
|
218
|
+
item.description && /* @__PURE__ */ jsx("div", {
|
|
219
|
+
className: "mt-1 text-sm text-muted-foreground",
|
|
220
|
+
children: item.description
|
|
221
|
+
}),
|
|
222
|
+
item.meta && /* @__PURE__ */ jsx("div", {
|
|
223
|
+
className: "mt-2 flex flex-wrap items-center gap-2 text-xs text-muted-foreground",
|
|
224
|
+
children: item.meta
|
|
225
|
+
})
|
|
226
|
+
]
|
|
227
|
+
}),
|
|
228
|
+
item.action && /* @__PURE__ */ jsx("div", {
|
|
229
|
+
className: "shrink-0",
|
|
230
|
+
children: item.action
|
|
231
|
+
})
|
|
232
|
+
]
|
|
233
|
+
})
|
|
234
|
+
});
|
|
235
|
+
if (!item.onClick) return content;
|
|
236
|
+
return /* @__PURE__ */ jsx("div", {
|
|
237
|
+
role: "button",
|
|
238
|
+
tabIndex: 0,
|
|
239
|
+
onClick: item.onClick,
|
|
240
|
+
onKeyDown: (event) => {
|
|
241
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
242
|
+
event.preventDefault();
|
|
243
|
+
item.onClick?.();
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
className: cn("block w-full rounded-[var(--radius-lg)] text-left transition-transform hover:-translate-y-0.5", focusRing),
|
|
247
|
+
children: content
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* AgentTimeline — unified mixed-content transcript for agent-backed sandbox
|
|
252
|
+
* sessions. Renders messages, tool rows, status cards, and artifact handoffs
|
|
253
|
+
* as one plain column: prose at the reading size, tool calls as quiet
|
|
254
|
+
* one-liners between the paragraphs, no connector chrome.
|
|
255
|
+
*/
|
|
256
|
+
function AgentTimeline({ items, isThinking, emptyState, className, renderToolActions, collapseAfter }) {
|
|
257
|
+
const [expanded, setExpanded] = useState(false);
|
|
258
|
+
if (items.length === 0 && !isThinking) return emptyState ? /* @__PURE__ */ jsx("div", {
|
|
259
|
+
className: cn("flex h-full items-center justify-center p-4", className),
|
|
260
|
+
children: emptyState
|
|
261
|
+
}) : null;
|
|
262
|
+
const renderedItems = isThinking ? [...items, {
|
|
263
|
+
id: "__thinking__",
|
|
264
|
+
kind: "custom",
|
|
265
|
+
content: /* @__PURE__ */ jsx(ThinkingIndicator, {})
|
|
266
|
+
}] : items;
|
|
267
|
+
const isUserMessage = (item) => item.kind === "message" && item.role === "user";
|
|
268
|
+
const stepItems = renderedItems.filter((item) => !isUserMessage(item));
|
|
269
|
+
const limit = collapseAfter ?? Infinity;
|
|
270
|
+
const collapsible = stepItems.length > limit;
|
|
271
|
+
const collapsed = collapsible && !expanded;
|
|
272
|
+
let renderList = renderedItems;
|
|
273
|
+
let hiddenCount = 0;
|
|
274
|
+
if (collapsed) {
|
|
275
|
+
const visible = [];
|
|
276
|
+
let stepCount = 0;
|
|
277
|
+
for (const item of renderedItems) {
|
|
278
|
+
if (stepCount >= limit) break;
|
|
279
|
+
visible.push(item);
|
|
280
|
+
if (!isUserMessage(item)) stepCount += 1;
|
|
281
|
+
}
|
|
282
|
+
renderList = visible;
|
|
283
|
+
hiddenCount = stepItems.length - limit;
|
|
284
|
+
}
|
|
285
|
+
const renderItem = (item) => {
|
|
286
|
+
if (item.kind === "message") return item.role === "user" ? /* @__PURE__ */ jsx(UserMessage, {
|
|
287
|
+
content: item.content,
|
|
288
|
+
timestamp: item.timestamp
|
|
289
|
+
}) : /* @__PURE__ */ jsx(AssistantMessage, { item });
|
|
290
|
+
if (item.kind === "tool") return /* @__PURE__ */ jsx(ToolCallStep, {
|
|
291
|
+
type: item.call.type,
|
|
292
|
+
label: item.call.label,
|
|
293
|
+
status: item.call.status,
|
|
294
|
+
detail: item.call.detail,
|
|
295
|
+
output: item.call.output,
|
|
296
|
+
duration: item.call.duration,
|
|
297
|
+
part: item.part,
|
|
298
|
+
actions: item.part ? renderToolActions?.(item.part) : void 0
|
|
299
|
+
});
|
|
300
|
+
if (item.kind === "tool_group") return /* @__PURE__ */ jsx(ToolCallGroup, {
|
|
301
|
+
title: item.title,
|
|
302
|
+
children: item.calls.map((call, callIndex) => {
|
|
303
|
+
const part = item.parts?.[callIndex];
|
|
304
|
+
return /* @__PURE__ */ jsx(ToolCallStep, {
|
|
305
|
+
type: call.type,
|
|
306
|
+
label: call.label,
|
|
307
|
+
status: call.status,
|
|
308
|
+
detail: call.detail,
|
|
309
|
+
output: call.output,
|
|
310
|
+
duration: call.duration,
|
|
311
|
+
part,
|
|
312
|
+
actions: part ? renderToolActions?.(part) : void 0
|
|
313
|
+
}, call.id);
|
|
314
|
+
})
|
|
315
|
+
});
|
|
316
|
+
if (item.kind === "status") return /* @__PURE__ */ jsx(StatusCard, { item });
|
|
317
|
+
if (item.kind === "artifact") return /* @__PURE__ */ jsx(ArtifactCard, { item });
|
|
318
|
+
return item.content;
|
|
319
|
+
};
|
|
320
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
321
|
+
className: cn("mx-auto flex w-full max-w-5xl flex-col px-4 py-4", className),
|
|
322
|
+
children: [renderList.map((item, index) => {
|
|
323
|
+
const kind = stepKind(item);
|
|
324
|
+
const prev = index > 0 ? stepKind(renderList[index - 1]) : void 0;
|
|
325
|
+
return /* @__PURE__ */ jsx("div", {
|
|
326
|
+
"data-timeline-step": kind,
|
|
327
|
+
className: cn(spacingBefore(prev, kind), kind === "tool" && ROW_BLEED),
|
|
328
|
+
children: renderItem(item)
|
|
329
|
+
}, item.id);
|
|
330
|
+
}), collapsible ? /* @__PURE__ */ jsx("button", {
|
|
331
|
+
type: "button",
|
|
332
|
+
onClick: () => setExpanded((value) => !value),
|
|
333
|
+
className: "mt-2 self-start text-xs font-medium text-muted-foreground transition-colors hover:text-foreground",
|
|
334
|
+
children: collapsed ? `Show ${hiddenCount} more step${hiddenCount === 1 ? "" : "s"}` : "Show less"
|
|
335
|
+
}) : null]
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
//#endregion
|
|
339
|
+
//#region src/chat/chat-container.tsx
|
|
340
|
+
const OPENUI_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
341
|
+
"heading",
|
|
342
|
+
"text",
|
|
343
|
+
"badge",
|
|
344
|
+
"stat",
|
|
345
|
+
"key_value",
|
|
346
|
+
"code",
|
|
347
|
+
"markdown",
|
|
348
|
+
"table",
|
|
349
|
+
"actions",
|
|
350
|
+
"separator",
|
|
351
|
+
"stack",
|
|
352
|
+
"grid",
|
|
353
|
+
"card"
|
|
354
|
+
]);
|
|
355
|
+
function isOpenUINode(value) {
|
|
356
|
+
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string" && OPENUI_NODE_TYPES.has(value.type);
|
|
357
|
+
}
|
|
358
|
+
function extractOpenUISchema(output) {
|
|
359
|
+
if (output == null) return null;
|
|
360
|
+
if (isOpenUINode(output)) return [output];
|
|
361
|
+
if (Array.isArray(output) && output.length > 0 && output.every(isOpenUINode)) return output;
|
|
362
|
+
if (typeof output === "object" && !Array.isArray(output)) {
|
|
363
|
+
const obj = output;
|
|
364
|
+
for (const key of [
|
|
365
|
+
"openui",
|
|
366
|
+
"schema",
|
|
367
|
+
"ui"
|
|
368
|
+
]) if (obj[key]) {
|
|
369
|
+
const inner = obj[key];
|
|
370
|
+
if (isOpenUINode(inner)) return [inner];
|
|
371
|
+
if (Array.isArray(inner) && inner.length > 0 && inner.every(isOpenUINode)) return inner;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (typeof output === "string") try {
|
|
375
|
+
return extractOpenUISchema(JSON.parse(output));
|
|
376
|
+
} catch {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
function formatUnknown(value) {
|
|
382
|
+
if (value == null) return void 0;
|
|
383
|
+
if (typeof value === "string") return value;
|
|
384
|
+
try {
|
|
385
|
+
return JSON.stringify(value, null, 2);
|
|
386
|
+
} catch {
|
|
387
|
+
return String(value);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function createdAtFromMessage(message) {
|
|
391
|
+
return message.time?.created ? new Date(message.time.created) : void 0;
|
|
392
|
+
}
|
|
393
|
+
function mapToolPartToTimelineType(part) {
|
|
394
|
+
switch (part.tool.toLowerCase().replace(/^tool:/, "")) {
|
|
395
|
+
case "bash":
|
|
396
|
+
case "shell":
|
|
397
|
+
case "command":
|
|
398
|
+
case "execute": return "bash";
|
|
399
|
+
case "write":
|
|
400
|
+
case "write_file":
|
|
401
|
+
case "create_file": return "write";
|
|
402
|
+
case "read":
|
|
403
|
+
case "read_file":
|
|
404
|
+
case "cat": return "read";
|
|
405
|
+
case "edit":
|
|
406
|
+
case "patch":
|
|
407
|
+
case "sed": return "edit";
|
|
408
|
+
case "glob":
|
|
409
|
+
case "find": return "glob";
|
|
410
|
+
case "ls": return "list";
|
|
411
|
+
case "grep":
|
|
412
|
+
case "search":
|
|
413
|
+
case "rg": return "grep";
|
|
414
|
+
case "inspect": return "inspect";
|
|
415
|
+
default: return "unknown";
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI = true) {
|
|
419
|
+
const items = [];
|
|
420
|
+
let latestUserIndex = -1;
|
|
421
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) if (messages[index].role === "user") {
|
|
422
|
+
latestUserIndex = index;
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
const lastAssistantMessage = [...latestUserIndex >= 0 ? messages.slice(latestUserIndex + 1) : messages].reverse().find((message) => message.role === "assistant");
|
|
426
|
+
const toToolCall = (part) => {
|
|
427
|
+
const meta = getToolDisplayMetadata(part);
|
|
428
|
+
const start = part.state.time?.start;
|
|
429
|
+
const end = part.state.time?.end;
|
|
430
|
+
return {
|
|
431
|
+
id: part.id,
|
|
432
|
+
type: mapToolPartToTimelineType(part),
|
|
433
|
+
label: meta.title,
|
|
434
|
+
status: part.state.status === "completed" ? "success" : part.state.status === "error" ? "error" : "running",
|
|
435
|
+
detail: meta.commandSnippet ?? meta.targetPath ?? meta.description,
|
|
436
|
+
output: formatUnknown(part.state.output),
|
|
437
|
+
duration: start && end ? end - start : void 0
|
|
438
|
+
};
|
|
439
|
+
};
|
|
440
|
+
for (const message of messages) {
|
|
441
|
+
const parts = partMap[message.id] ?? [];
|
|
442
|
+
if (message.role === "user") {
|
|
443
|
+
const content = parts.filter((part) => part.type === "text").map((part) => part.text).join("\n").trim();
|
|
444
|
+
if (!content) continue;
|
|
445
|
+
items.push({
|
|
446
|
+
id: message.id,
|
|
447
|
+
kind: "message",
|
|
448
|
+
role: "user",
|
|
449
|
+
content,
|
|
450
|
+
timestamp: createdAtFromMessage(message)
|
|
451
|
+
});
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
const toolBuffer = [];
|
|
455
|
+
const flushToolBuffer = (index) => {
|
|
456
|
+
if (toolBuffer.length === 0) return;
|
|
457
|
+
if (toolBuffer.length === 1) items.push({
|
|
458
|
+
id: `${message.id}-tool-${toolBuffer[0].id}`,
|
|
459
|
+
kind: "tool",
|
|
460
|
+
call: toToolCall(toolBuffer[0]),
|
|
461
|
+
part: toolBuffer[0]
|
|
462
|
+
});
|
|
463
|
+
else items.push({
|
|
464
|
+
id: `${message.id}-tool-group-${index}`,
|
|
465
|
+
kind: "tool_group",
|
|
466
|
+
title: "Tool activity",
|
|
467
|
+
parts: [...toolBuffer],
|
|
468
|
+
calls: toolBuffer.map((part) => toToolCall(part))
|
|
469
|
+
});
|
|
470
|
+
if (enableOpenUI) for (const part of toolBuffer) {
|
|
471
|
+
if (part.state.status !== "completed" || !part.state.output) continue;
|
|
472
|
+
const schema = extractOpenUISchema(part.state.output);
|
|
473
|
+
if (!schema) continue;
|
|
474
|
+
items.push({
|
|
475
|
+
id: `${message.id}-openui-${part.id}`,
|
|
476
|
+
kind: "custom",
|
|
477
|
+
content: /* @__PURE__ */ jsx("div", {
|
|
478
|
+
className: "my-2 rounded-[var(--radius-lg)] border border-border bg-card p-4 shadow-[var(--shadow-card)]",
|
|
479
|
+
children: /* @__PURE__ */ jsx(OpenUIArtifactRenderer, {
|
|
480
|
+
schema,
|
|
481
|
+
onAction: onOpenUIAction
|
|
482
|
+
})
|
|
483
|
+
})
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
toolBuffer.length = 0;
|
|
487
|
+
};
|
|
488
|
+
parts.forEach((part, index) => {
|
|
489
|
+
const itemId = `${message.id}-${index}`;
|
|
490
|
+
if (part.type === "tool") {
|
|
491
|
+
toolBuffer.push(part);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
flushToolBuffer(index);
|
|
495
|
+
if (part.type === "text" && !part.synthetic && part.text.trim()) {
|
|
496
|
+
if (enableOpenUI) {
|
|
497
|
+
const jsonMatch = part.text.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
|
|
498
|
+
if (jsonMatch) {
|
|
499
|
+
const schema = extractOpenUISchema(jsonMatch[1]);
|
|
500
|
+
if (schema) {
|
|
501
|
+
const beforeJson = part.text.slice(0, part.text.indexOf("```")).trim();
|
|
502
|
+
if (beforeJson) items.push({
|
|
503
|
+
id: `${itemId}-text`,
|
|
504
|
+
kind: "message",
|
|
505
|
+
role: "assistant",
|
|
506
|
+
content: beforeJson,
|
|
507
|
+
timestamp: createdAtFromMessage(message)
|
|
508
|
+
});
|
|
509
|
+
items.push({
|
|
510
|
+
id: `${itemId}-openui`,
|
|
511
|
+
kind: "custom",
|
|
512
|
+
content: /* @__PURE__ */ jsx("div", {
|
|
513
|
+
className: "my-2 rounded-[var(--radius-lg)] border border-border bg-card p-4 shadow-[var(--shadow-card)]",
|
|
514
|
+
children: /* @__PURE__ */ jsx(OpenUIArtifactRenderer, {
|
|
515
|
+
schema,
|
|
516
|
+
onAction: onOpenUIAction
|
|
517
|
+
})
|
|
518
|
+
})
|
|
519
|
+
});
|
|
520
|
+
const afterJson = part.text.slice(part.text.lastIndexOf("```") + 3).trim();
|
|
521
|
+
if (afterJson) items.push({
|
|
522
|
+
id: `${itemId}-after`,
|
|
523
|
+
kind: "message",
|
|
524
|
+
role: "assistant",
|
|
525
|
+
content: afterJson,
|
|
526
|
+
timestamp: createdAtFromMessage(message)
|
|
527
|
+
});
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
items.push({
|
|
533
|
+
id: itemId,
|
|
534
|
+
kind: "message",
|
|
535
|
+
role: "assistant",
|
|
536
|
+
content: part.text,
|
|
537
|
+
timestamp: createdAtFromMessage(message),
|
|
538
|
+
isStreaming: isStreaming && lastAssistantMessage?.id === message.id && index === parts.length - 1
|
|
539
|
+
});
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
if (part.type === "reasoning") {
|
|
543
|
+
items.push({
|
|
544
|
+
id: itemId,
|
|
545
|
+
kind: "custom",
|
|
546
|
+
content: /* @__PURE__ */ jsx(InlineThinkingItem, {
|
|
547
|
+
part,
|
|
548
|
+
defaultOpen: isStreaming && lastAssistantMessage?.id === message.id
|
|
549
|
+
})
|
|
550
|
+
});
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
flushToolBuffer(parts.length);
|
|
555
|
+
}
|
|
556
|
+
return {
|
|
557
|
+
items,
|
|
558
|
+
showThinking: isStreaming && latestUserIndex >= 0 && (lastAssistantMessage == null || !items.some((item) => item.kind === "message" && item.role === "assistant" && item.id.startsWith(lastAssistantMessage.id)))
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Chat transcript container: message list + auto-scroll.
|
|
563
|
+
* Orchestrates useRunGroups, useRunCollapseState, and useAutoScroll.
|
|
564
|
+
*/
|
|
565
|
+
const ChatContainer = memo(({ messages, partMap, isStreaming, branding, className, renderToolDetail, presentation = "runs", onOpenUIAction, enableOpenUI = true, renderRunActions, renderUserMessageActions, renderToolActions, renderTimelineToolActions, collapseTimelineAfter }) => {
|
|
566
|
+
const scrollRef = useRef(null);
|
|
567
|
+
const groups = useRunGroups({
|
|
568
|
+
messages,
|
|
569
|
+
partMap,
|
|
570
|
+
isStreaming
|
|
571
|
+
});
|
|
572
|
+
const runs = groups.filter((g) => g.type === "run").map((g) => g.run);
|
|
573
|
+
const { isCollapsed, toggleCollapse } = useRunCollapseState(runs);
|
|
574
|
+
const { isAtBottom, scrollToBottom } = useAutoScroll(scrollRef, [
|
|
575
|
+
messages,
|
|
576
|
+
partMap,
|
|
577
|
+
isStreaming
|
|
578
|
+
]);
|
|
579
|
+
const timeline = useMemo(() => buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI), [
|
|
580
|
+
messages,
|
|
581
|
+
partMap,
|
|
582
|
+
isStreaming,
|
|
583
|
+
onOpenUIAction,
|
|
584
|
+
enableOpenUI
|
|
585
|
+
]);
|
|
586
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
587
|
+
className: cn("flex h-full flex-col", className),
|
|
588
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
589
|
+
ref: scrollRef,
|
|
590
|
+
className: "flex-1 overflow-y-auto [scrollbar-gutter:stable]",
|
|
591
|
+
children: messages.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
592
|
+
className: "flex h-full items-center justify-center",
|
|
593
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
594
|
+
className: "max-w-md text-center",
|
|
595
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
596
|
+
className: "text-sm font-medium text-muted-foreground",
|
|
597
|
+
children: "Start a conversation."
|
|
598
|
+
})
|
|
599
|
+
})
|
|
600
|
+
}) : presentation === "timeline" ? /* @__PURE__ */ jsx("div", {
|
|
601
|
+
className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end",
|
|
602
|
+
children: /* @__PURE__ */ jsx(AgentTimeline, {
|
|
603
|
+
items: timeline.items,
|
|
604
|
+
isThinking: timeline.showThinking,
|
|
605
|
+
renderToolActions: renderTimelineToolActions,
|
|
606
|
+
collapseAfter: collapseTimelineAfter
|
|
607
|
+
})
|
|
608
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
609
|
+
className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end",
|
|
610
|
+
children: /* @__PURE__ */ jsx(MessageList, {
|
|
611
|
+
groups,
|
|
612
|
+
partMap,
|
|
613
|
+
isCollapsed,
|
|
614
|
+
onToggleCollapse: toggleCollapse,
|
|
615
|
+
branding,
|
|
616
|
+
renderToolDetail,
|
|
617
|
+
renderRunActions,
|
|
618
|
+
renderUserMessageActions,
|
|
619
|
+
renderToolActions
|
|
620
|
+
})
|
|
621
|
+
})
|
|
622
|
+
}), !isAtBottom && /* @__PURE__ */ jsx("div", {
|
|
623
|
+
className: "relative z-10 -mt-10 flex justify-center",
|
|
624
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
625
|
+
onClick: scrollToBottom,
|
|
626
|
+
className: cn("flex items-center gap-1.5 px-3 py-1.5 rounded-full", "border border-border bg-card shadow-[0_6px_16px_rgba(15,23,42,0.08)]", "text-xs text-foreground transition-colors hover:bg-accent", focusRing),
|
|
627
|
+
children: [/* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }), "Scroll to bottom"]
|
|
628
|
+
})
|
|
629
|
+
})]
|
|
630
|
+
});
|
|
631
|
+
});
|
|
632
|
+
ChatContainer.displayName = "ChatContainer";
|
|
633
|
+
//#endregion
|
|
634
|
+
//#region src/chat/chat-message.tsx
|
|
635
|
+
function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, className, userLabel = "You", assistantLabel = "Agent", hideRoleLabel }) {
|
|
636
|
+
const isUser = role === "user";
|
|
637
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
638
|
+
className: cn("flex flex-col gap-1", isUser ? "items-end" : "items-start", className),
|
|
639
|
+
children: [!hideRoleLabel && /* @__PURE__ */ jsxs("div", {
|
|
640
|
+
className: cn("flex items-center gap-2 px-1", isUser && "flex-row-reverse"),
|
|
641
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
642
|
+
className: "font-medium text-foreground text-xs",
|
|
643
|
+
children: isUser ? userLabel : assistantLabel
|
|
644
|
+
}), timestamp && /* @__PURE__ */ jsx("span", {
|
|
645
|
+
className: "text-muted-foreground text-xs",
|
|
646
|
+
children: formatTime(timestamp)
|
|
647
|
+
})]
|
|
648
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
649
|
+
className: cn("min-w-0 max-w-[85%] space-y-1 rounded-[var(--radius-lg)] border", "px-[var(--chat-message-px)] py-[var(--chat-message-py)]", isUser ? "border-border bg-muted/50" : "border-border bg-card"),
|
|
650
|
+
children: [isUser ? /* @__PURE__ */ jsx("div", {
|
|
651
|
+
className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground",
|
|
652
|
+
children: content
|
|
653
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [content && /* @__PURE__ */ jsx(Markdown, {
|
|
654
|
+
className: "tangle-prose text-[var(--font-size-base)] leading-[var(--line-height-base)]",
|
|
655
|
+
children: content
|
|
656
|
+
}), isStreaming && /* @__PURE__ */ jsx("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse rounded-sm bg-[var(--brand-cool)] align-text-bottom" })] }), toolCalls]
|
|
657
|
+
})]
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
function formatTime(date) {
|
|
661
|
+
return date.toLocaleTimeString(void 0, {
|
|
662
|
+
hour: "numeric",
|
|
663
|
+
minute: "2-digit"
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
//#endregion
|
|
667
|
+
export { MessageList as a, ThinkingIndicator as i, ChatContainer as n, UserMessage as o, AgentTimeline as r, ChatMessage as t };
|