@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.
Files changed (132) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +4 -1
  3. package/dist/active-sessions-store-Gt1R0rFG.js +262 -0
  4. package/dist/{active-sessions-store-CeOmXgv5.d.ts → active-sessions-store-nl70ZnMC.d.ts} +40 -41
  5. package/dist/artifact-pane-BL_DFWNl.d.ts +32 -0
  6. package/dist/artifact-pane-DMXT9a8U.js +70 -0
  7. package/dist/auth-DOETfnd9.js +154 -0
  8. package/dist/auth.d.ts +2 -74
  9. package/dist/auth.js +2 -16
  10. package/dist/branding-26d5ARIr.d.ts +14 -0
  11. package/dist/button-C87nEe2R.js +78 -0
  12. package/dist/button-yoIv77e2.d.ts +16 -0
  13. package/dist/chat-D4jAfEmj.js +667 -0
  14. package/dist/chat.d.ts +2 -201
  15. package/dist/chat.js +2 -31
  16. package/dist/code-block-B36KVUSN.js +165 -0
  17. package/dist/code-block-B9miUPht.d.ts +23 -0
  18. package/dist/diff-preview-BcK3nRXb.js +533 -0
  19. package/dist/document-editor-pane-BcoABlhn.d.ts +131 -0
  20. package/dist/document-editor-pane-BxlPjaTP.js +1287 -0
  21. package/dist/dropdown-menu-BpcLa5vF.js +101 -0
  22. package/dist/editor.d.ts +76 -78
  23. package/dist/editor.js +2 -34
  24. package/dist/file-format-BgXbr-Ib.js +160 -0
  25. package/dist/files-Bug33qCl.js +743 -0
  26. package/dist/files.d.ts +2 -243
  27. package/dist/files.js +3 -41
  28. package/dist/focus-BcE_SHqz.js +57 -0
  29. package/dist/format-DfcLWqMa.js +54 -0
  30. package/dist/hooks.d.ts +30 -37
  31. package/dist/hooks.js +111 -46
  32. package/dist/index-2UntyjBb.d.ts +52 -0
  33. package/dist/index-BgUHilZm.d.ts +108 -0
  34. package/dist/index-COgqsFAQ.d.ts +42 -0
  35. package/dist/index-CPDET_s1.d.ts +549 -0
  36. package/dist/index-CUhfHT_V.d.ts +204 -0
  37. package/dist/index-Cg6gYAqh.d.ts +73 -0
  38. package/dist/index-Cq-EJzqW.d.ts +16 -0
  39. package/dist/index-DhYmSaLF.d.ts +245 -0
  40. package/dist/index-DjKxO357.d.ts +128 -0
  41. package/dist/index.d.ts +26 -43
  42. package/dist/index.js +35 -472
  43. package/dist/markdown-BGqicV82.js +45 -0
  44. package/dist/markdown.d.ts +3 -18
  45. package/dist/markdown.js +3 -15
  46. package/dist/message-vhUI0c5G.d.ts +16 -0
  47. package/dist/nav.d.ts +6 -8
  48. package/dist/nav.js +29 -11
  49. package/dist/openui-artifact-renderer-D3E5bIAI.d.ts +114 -0
  50. package/dist/openui-artifact-renderer-DrU1AdVk.js +266 -0
  51. package/dist/openui.d.ts +2 -115
  52. package/dist/openui.js +2 -13
  53. package/dist/parts-5mhy9yJ3.d.ts +37 -0
  54. package/dist/primitives-Cb8GGVKr.js +1239 -0
  55. package/dist/primitives.d.ts +5 -525
  56. package/dist/primitives.js +9 -212
  57. package/dist/redaction-CGGB2ENG.js +74 -0
  58. package/dist/redaction.d.ts +2 -42
  59. package/dist/redaction.js +2 -7
  60. package/dist/run-OyWmIDqu.d.ts +41 -0
  61. package/dist/run-ZsIKPA6J.js +17 -0
  62. package/dist/run-group-BACLbCFl.js +410 -0
  63. package/dist/run.d.ts +3 -126
  64. package/dist/run.js +5 -40
  65. package/dist/sdk-hooks.d.ts +2 -285
  66. package/dist/sdk-hooks.js +3 -36
  67. package/dist/stores.d.ts +13 -14
  68. package/dist/stores.js +34 -76
  69. package/dist/table-Bss73DhB.js +146 -0
  70. package/dist/tabs-BVHR6NkO.js +40 -0
  71. package/dist/text-shimmer-BUUo6I-g.js +64 -0
  72. package/dist/tool-call-feed-BeB1_4pX.d.ts +47 -0
  73. package/dist/tool-call-feed-Djt2q11V.js +109 -0
  74. package/dist/tool-call-step-DNebqhmX.js +434 -0
  75. package/dist/tool-display-BAuAVa43.js +158 -0
  76. package/dist/{tool-display-z4JcDmMQ.d.ts → tool-display-DgmL5rIU.d.ts} +16 -16
  77. package/dist/tool-previews.d.ts +2 -48
  78. package/dist/tool-previews.js +2 -23
  79. package/dist/types.d.ts +6 -19
  80. package/dist/types.js +0 -1
  81. package/dist/use-auto-scroll-C5Pjeqon.js +153 -0
  82. package/dist/use-sse-stream-BVgO1QBN.js +884 -0
  83. package/dist/use-sse-stream-Dm6R5YWz.d.ts +282 -0
  84. package/dist/utils-Bl_CZ0Qp.js +37 -0
  85. package/dist/{chunk-RQHJBTEU.js → utils-C_uf36nf.js} +4 -6
  86. package/dist/utils.d.ts +2 -104
  87. package/dist/utils.js +6 -44
  88. package/package.json +39 -41
  89. package/src/lib/focus.ts +2 -1
  90. package/dist/artifact-pane-DpuWcAiF.d.ts +0 -33
  91. package/dist/button-CMQuQEW_.d.ts +0 -17
  92. package/dist/chunk-34A66VBG.js +0 -214
  93. package/dist/chunk-3OI2QKFD.js +0 -0
  94. package/dist/chunk-3XXBZL53.js +0 -174
  95. package/dist/chunk-42PAH5D2.js +0 -112
  96. package/dist/chunk-4CLN43XT.js +0 -45
  97. package/dist/chunk-55WHV7SS.js +0 -1604
  98. package/dist/chunk-565EATZZ.js +0 -156
  99. package/dist/chunk-5Z5ZYMOJ.js +0 -0
  100. package/dist/chunk-6BGQA4BQ.js +0 -0
  101. package/dist/chunk-BEBXZPHW.js +0 -299
  102. package/dist/chunk-C5WF4WMV.js +0 -734
  103. package/dist/chunk-HFL6R6IF.js +0 -37
  104. package/dist/chunk-HGML45QH.js +0 -104
  105. package/dist/chunk-HMAPIH7L.js +0 -595
  106. package/dist/chunk-K5XFRUS4.js +0 -1401
  107. package/dist/chunk-KFQGHD73.js +0 -198
  108. package/dist/chunk-L57WRIND.js +0 -59
  109. package/dist/chunk-LTEKI7YJ.js +0 -59
  110. package/dist/chunk-M3QZK62R.js +0 -233
  111. package/dist/chunk-ND3ZFXQK.js +0 -179
  112. package/dist/chunk-OEX7NZE3.js +0 -321
  113. package/dist/chunk-OL5GYLHV.js +0 -60
  114. package/dist/chunk-QGFYBNSO.js +0 -133
  115. package/dist/chunk-R7B3UWPF.js +0 -550
  116. package/dist/chunk-R7SUY4E3.js +0 -65
  117. package/dist/chunk-REJESC5U.js +0 -117
  118. package/dist/chunk-RQGKSCEZ.js +0 -0
  119. package/dist/chunk-SNLR2AEA.js +0 -40
  120. package/dist/chunk-WKWBTL2V.js +0 -15
  121. package/dist/chunk-X7CU776B.js +0 -1048
  122. package/dist/chunk-XU3HB5QL.js +0 -127
  123. package/dist/chunk-YTO5V6QS.js +0 -19
  124. package/dist/chunk-YU4E5J2N.js +0 -437
  125. package/dist/chunk-YZ6AK25N.js +0 -886
  126. package/dist/code-block-0kSpWMnf.d.ts +0 -25
  127. package/dist/document-editor-pane-IAEQn_Dl.d.ts +0 -128
  128. package/dist/document-editor-pane-QHDOBA43.js +0 -13
  129. package/dist/message-BHWbxBtT.d.ts +0 -15
  130. package/dist/parts-dj7AcUg0.d.ts +0 -36
  131. package/dist/run-PfLmDAox.d.ts +0 -41
  132. 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 };