@tangle-network/sandbox-ui 0.13.0 → 0.15.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 (106) hide show
  1. package/dist/auth.d.ts +1 -74
  2. package/dist/auth.js +1 -4
  3. package/dist/chat.d.ts +1 -136
  4. package/dist/chat.js +2 -15
  5. package/dist/chunk-2BUPSB7O.js +0 -0
  6. package/dist/chunk-3J6FG3FJ.js +18 -0
  7. package/dist/chunk-76IQLPW2.js +206 -0
  8. package/dist/chunk-7ZA5SEK3.js +239 -0
  9. package/dist/{chunk-ESVYBDGA.js → chunk-AG7QDC2Q.js} +182 -2
  10. package/dist/chunk-AHBZCBDO.js +2960 -0
  11. package/dist/chunk-AZ3AWMTM.js +8 -0
  12. package/dist/chunk-CMY7W45U.js +380 -0
  13. package/dist/{chunk-QMU2PWOU.js → chunk-DNZ4DTNA.js} +71 -17
  14. package/dist/chunk-EI44GEQ5.js +6 -0
  15. package/dist/{chunk-5OQ27N57.js → chunk-GPT7VKK6.js} +34 -38
  16. package/dist/chunk-JBGKGLD7.js +16 -0
  17. package/dist/chunk-NJNME4J4.js +14 -0
  18. package/dist/chunk-QPAJR74X.js +20 -0
  19. package/dist/chunk-TK46XFLM.js +28 -0
  20. package/dist/chunk-WID73FPH.js +89 -0
  21. package/dist/chunk-YVXK4XRO.js +30 -0
  22. package/dist/dashboard.d.ts +538 -4
  23. package/dist/dashboard.js +15 -886
  24. package/dist/editor.d.ts +1 -120
  25. package/dist/editor.js +1 -5
  26. package/dist/files.d.ts +1 -129
  27. package/dist/files.js +2 -7
  28. package/dist/globals.css +5 -1265
  29. package/dist/hooks.d.ts +114 -11
  30. package/dist/hooks.js +17 -88
  31. package/dist/index.d.ts +24 -99
  32. package/dist/index.js +247 -252
  33. package/dist/markdown.d.ts +1 -29
  34. package/dist/markdown.js +2 -2
  35. package/dist/openui.d.ts +8 -115
  36. package/dist/openui.js +1 -6
  37. package/dist/pages.d.ts +1 -2
  38. package/dist/pages.js +68 -66
  39. package/dist/primitives.d.ts +14 -49
  40. package/dist/primitives.js +69 -77
  41. package/dist/run.d.ts +1 -14
  42. package/dist/run.js +2 -22
  43. package/dist/sdk-hooks.d.ts +3 -283
  44. package/dist/sdk-hooks.js +10 -14
  45. package/dist/stores.d.ts +2 -14
  46. package/dist/stores.js +11 -39
  47. package/dist/styles.css +5 -1265
  48. package/dist/{usage-chart-CPTcNlGs.d.ts → template-card-UhV3pmRC.d.ts} +16 -1
  49. package/dist/terminal.js +39 -2
  50. package/dist/types.d.ts +11 -8
  51. package/dist/types.js +1 -0
  52. package/dist/utils.d.ts +1 -44
  53. package/dist/utils.js +6 -12
  54. package/dist/workspace.d.ts +5 -10
  55. package/dist/workspace.js +3 -19
  56. package/package.json +23 -54
  57. package/dist/active-sessions-store-CeOmXgv5.d.ts +0 -85
  58. package/dist/artifact-pane-Bh45Ssco.d.ts +0 -24
  59. package/dist/branding-DCi5VEik.d.ts +0 -13
  60. package/dist/button-CMQuQEW_.d.ts +0 -17
  61. package/dist/chat-container-f4yEs6KN.d.ts +0 -106
  62. package/dist/chunk-34A66VBG.js +0 -214
  63. package/dist/chunk-34I7UFSX.js +0 -92
  64. package/dist/chunk-36QY2W5G.js +0 -802
  65. package/dist/chunk-4CLN43XT.js +0 -45
  66. package/dist/chunk-54SQQMMM.js +0 -156
  67. package/dist/chunk-66EZOYZR.js +0 -102
  68. package/dist/chunk-BX6AQMUS.js +0 -183
  69. package/dist/chunk-DI3NZ5ZX.js +0 -192
  70. package/dist/chunk-DPGIXDAI.js +0 -220
  71. package/dist/chunk-DXMIEK4K.js +0 -1426
  72. package/dist/chunk-GSZA3TSY.js +0 -79
  73. package/dist/chunk-HB5Y37YU.js +0 -54
  74. package/dist/chunk-LQNEZDRM.js +0 -109
  75. package/dist/chunk-MA7YKRUP.js +0 -131
  76. package/dist/chunk-MKTSMWVD.js +0 -109
  77. package/dist/chunk-MQXABZTB.js +0 -1348
  78. package/dist/chunk-MT5FJ3ZT.js +0 -186
  79. package/dist/chunk-NKUPJC34.js +0 -2070
  80. package/dist/chunk-OEX7NZE3.js +0 -321
  81. package/dist/chunk-OKLQVY3Y.js +0 -139
  82. package/dist/chunk-Q56BYXQF.js +0 -61
  83. package/dist/chunk-QD4QE5P5.js +0 -40
  84. package/dist/chunk-QDH5GEGY.js +0 -630
  85. package/dist/chunk-QID2OOMG.js +0 -133
  86. package/dist/chunk-RQHJBTEU.js +0 -10
  87. package/dist/chunk-T7HMZEVO.js +0 -216
  88. package/dist/chunk-U6QTHMY6.js +0 -1290
  89. package/dist/chunk-US6JKJKH.js +0 -124
  90. package/dist/chunk-VX3XOUEB.js +0 -63
  91. package/dist/chunk-XLG757B6.js +0 -933
  92. package/dist/chunk-ZMNSRDMH.js +0 -127
  93. package/dist/chunk-ZNCEM5CD.js +0 -316
  94. package/dist/document-editor-pane-A70-EhdQ.d.ts +0 -124
  95. package/dist/document-editor-pane-TLPVRBBU.js +0 -11
  96. package/dist/expanded-tool-detail-Dh99mcbY.d.ts +0 -63
  97. package/dist/file-tabs-BLfxfmAH.d.ts +0 -51
  98. package/dist/parts-CyGkM6Fp.d.ts +0 -50
  99. package/dist/run-CtFZ6s-D.d.ts +0 -41
  100. package/dist/sidebar-drop-zone-tDBsuOH5.d.ts +0 -301
  101. package/dist/sidecar-CFU2W9j1.d.ts +0 -8
  102. package/dist/template-card-BAtvcAkU.d.ts +0 -18
  103. package/dist/tool-call-feed-Bs3MyQMT.d.ts +0 -68
  104. package/dist/tool-display-Ct9nFAzJ.d.ts +0 -32
  105. package/dist/use-sandbox-metrics-B64diPqN.d.ts +0 -141
  106. package/dist/variant-list-BrHYcBCk.d.ts +0 -540
@@ -1,933 +0,0 @@
1
- import {
2
- useAutoScroll,
3
- useRunCollapseState,
4
- useRunGroups
5
- } from "./chunk-54SQQMMM.js";
6
- import {
7
- InlineThinkingItem,
8
- RunGroup
9
- } from "./chunk-MQXABZTB.js";
10
- import {
11
- ToolCallGroup,
12
- ToolCallStep
13
- } from "./chunk-MT5FJ3ZT.js";
14
- import {
15
- getToolDisplayMetadata
16
- } from "./chunk-BX6AQMUS.js";
17
- import {
18
- OpenUIArtifactRenderer
19
- } from "./chunk-ZNCEM5CD.js";
20
- import {
21
- Markdown
22
- } from "./chunk-T7HMZEVO.js";
23
- import {
24
- cn
25
- } from "./chunk-RQHJBTEU.js";
26
-
27
- // src/chat/user-message.tsx
28
- import { memo } from "react";
29
- import { jsx, jsxs } from "react/jsx-runtime";
30
- var UserMessage = memo(({ message, parts, actions }) => {
31
- const textContent = parts.filter((p) => p.type === "text").map((p) => p.text).join("\n");
32
- if (!textContent.trim()) return null;
33
- return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: "flex max-w-[78%] flex-col items-end gap-2", children: [
34
- /* @__PURE__ */ jsxs("div", { className: "w-full rounded-[26px] rounded-br-[12px] bg-[var(--brand-primary)] px-4 py-3 text-white shadow-[0_8px_20px_rgba(15,23,42,0.12)]", children: [
35
- /* @__PURE__ */ jsx("div", { className: "mb-1 text-[10px] font-semibold uppercase tracking-[0.14em] text-white/60", children: "You" }),
36
- /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap text-[15px] leading-6.5 text-white", children: textContent })
37
- ] }),
38
- actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground", children: actions }) : null
39
- ] }) });
40
- });
41
- UserMessage.displayName = "UserMessage";
42
-
43
- // src/chat/message-list.tsx
44
- import { memo as memo2 } from "react";
45
- import { jsx as jsx2 } from "react/jsx-runtime";
46
- var MessageList = memo2(
47
- ({
48
- groups,
49
- partMap,
50
- isCollapsed,
51
- onToggleCollapse,
52
- branding,
53
- renderToolDetail,
54
- renderRunActions,
55
- renderUserMessageActions,
56
- renderToolActions
57
- }) => {
58
- return /* @__PURE__ */ jsx2("div", { className: "space-y-4", children: groups.map((group) => {
59
- if (group.type === "user") {
60
- const messageParts = partMap[group.message.id] ?? [];
61
- return /* @__PURE__ */ jsx2(
62
- UserMessage,
63
- {
64
- message: group.message,
65
- parts: messageParts,
66
- actions: renderUserMessageActions?.(group.message, messageParts)
67
- },
68
- group.message.id
69
- );
70
- }
71
- return /* @__PURE__ */ jsx2(
72
- RunGroup,
73
- {
74
- run: group.run,
75
- partMap,
76
- collapsed: isCollapsed(group.run.id),
77
- onToggle: () => onToggleCollapse(group.run.id),
78
- branding,
79
- renderToolDetail,
80
- headerActions: renderRunActions?.(group.run),
81
- renderToolActions
82
- },
83
- group.run.id
84
- );
85
- }) });
86
- }
87
- );
88
- MessageList.displayName = "MessageList";
89
-
90
- // src/chat/thinking-indicator.tsx
91
- import { useEffect, useState } from "react";
92
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
93
- function ThinkingIndicator({ className }) {
94
- const [elapsed, setElapsed] = useState(0);
95
- useEffect(() => {
96
- const interval = window.setInterval(() => setElapsed((current) => current + 1), 1e3);
97
- return () => window.clearInterval(interval);
98
- }, []);
99
- return /* @__PURE__ */ jsxs2("div", { className: cn("flex items-center gap-2 px-3 py-1.5", className), children: [
100
- /* @__PURE__ */ jsxs2("div", { className: "flex gap-[3px]", children: [
101
- /* @__PURE__ */ jsx3("span", { className: "h-[var(--indicator-dot-size)] w-[var(--indicator-dot-size)] animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "0ms" } }),
102
- /* @__PURE__ */ jsx3("span", { className: "h-[var(--indicator-dot-size)] w-[var(--indicator-dot-size)] animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "150ms" } }),
103
- /* @__PURE__ */ jsx3("span", { className: "h-[var(--indicator-dot-size)] w-[var(--indicator-dot-size)] animate-bounce rounded-full bg-[var(--brand-glow)]", style: { animationDelay: "300ms" } })
104
- ] }),
105
- elapsed > 3 && /* @__PURE__ */ jsxs2("span", { className: "text-[var(--font-size-xs)] tabular-nums text-[var(--text-dim)]", children: [
106
- elapsed,
107
- "s"
108
- ] })
109
- ] });
110
- }
111
-
112
- // src/chat/agent-timeline.tsx
113
- import {
114
- AlertTriangle,
115
- CheckCircle2,
116
- CircleDot,
117
- FileText,
118
- Info
119
- } from "lucide-react";
120
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
121
- var TONE_STYLES = {
122
- default: {
123
- dot: "bg-[var(--border-hover)]",
124
- card: "border-border bg-card",
125
- text: "text-foreground",
126
- icon: CircleDot
127
- },
128
- info: {
129
- dot: "bg-[var(--surface-info-text)]",
130
- card: "border-[var(--surface-info-border)] bg-[var(--surface-info-bg)]",
131
- text: "text-[var(--surface-info-text)]",
132
- icon: Info
133
- },
134
- success: {
135
- dot: "bg-[var(--surface-success-text)]",
136
- card: "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]",
137
- text: "text-[var(--surface-success-text)]",
138
- icon: CheckCircle2
139
- },
140
- warning: {
141
- dot: "bg-[var(--surface-warning-text)]",
142
- card: "border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)]",
143
- text: "text-[var(--surface-warning-text)]",
144
- icon: AlertTriangle
145
- },
146
- error: {
147
- dot: "bg-[var(--surface-danger-text)]",
148
- card: "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)]",
149
- text: "text-[var(--surface-danger-text)]",
150
- icon: AlertTriangle
151
- }
152
- };
153
- function formatTime(date) {
154
- return date.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
155
- }
156
- function AgentTimelineRow({ isLast, accentClassName, children }) {
157
- return /* @__PURE__ */ jsxs3("div", { className: "grid grid-cols-[1.25rem_minmax(0,1fr)] gap-x-4", children: [
158
- /* @__PURE__ */ jsxs3("div", { className: "relative flex justify-center", children: [
159
- !isLast && /* @__PURE__ */ jsx4("span", { className: "absolute top-4 bottom-[-0.75rem] left-1/2 w-px -translate-x-1/2 bg-border" }),
160
- /* @__PURE__ */ jsx4("span", { className: cn("relative mt-2 h-[var(--timeline-dot-size)] w-[var(--timeline-dot-size)] rounded-full ring-4 ring-[var(--bg-root)]", accentClassName) })
161
- ] }),
162
- /* @__PURE__ */ jsx4("div", { className: "min-w-0 pb-3", children })
163
- ] });
164
- }
165
- function UserMessage2({ item }) {
166
- return /* @__PURE__ */ jsx4("div", { className: "mb-3 flex justify-end", children: /* @__PURE__ */ jsx4("div", { className: "max-w-[72%]", children: /* @__PURE__ */ jsxs3("div", { className: "rounded-2xl border border-border bg-muted/50 px-4 py-3", children: [
167
- item.timestamp && /* @__PURE__ */ jsx4("div", { className: "mb-1.5 text-right text-[var(--font-size-xs)] text-muted-foreground", children: formatTime(item.timestamp) }),
168
- /* @__PURE__ */ jsx4("div", { className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground", children: item.content })
169
- ] }) }) });
170
- }
171
- function AssistantMessage({ item }) {
172
- return /* @__PURE__ */ jsxs3("div", { className: "-mt-0.5", children: [
173
- item.timestamp && /* @__PURE__ */ jsx4("div", { className: "mb-2 text-[var(--font-size-xs)] text-muted-foreground", children: formatTime(item.timestamp) }),
174
- item.content && /* @__PURE__ */ jsx4(Markdown, { className: "tangle-prose text-[var(--font-size-base)] leading-[var(--line-height-base)]", children: item.content }),
175
- item.isStreaming && /* @__PURE__ */ jsx4("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse rounded-sm bg-primary align-text-bottom" }),
176
- item.toolCalls && /* @__PURE__ */ jsx4("div", { className: "mt-3", children: item.toolCalls }),
177
- item.after && /* @__PURE__ */ jsx4("div", { className: "mt-3 border-t border-border pt-3", children: item.after })
178
- ] });
179
- }
180
- function StatusCard({ item }) {
181
- const tone = TONE_STYLES[item.tone ?? "default"];
182
- const Icon = tone.icon;
183
- return /* @__PURE__ */ jsx4("div", { className: cn("rounded-[var(--radius-lg)] border px-4 py-3", tone.card), children: /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-3", children: [
184
- /* @__PURE__ */ jsx4(Icon, { className: cn("mt-0.5 h-4 w-4 shrink-0", tone.text) }),
185
- /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
186
- /* @__PURE__ */ jsx4("div", { className: cn("text-sm font-medium", tone.text), children: item.label }),
187
- item.detail && /* @__PURE__ */ jsx4("div", { className: "mt-0.5 text-sm text-muted-foreground", children: item.detail })
188
- ] })
189
- ] }) });
190
- }
191
- function ArtifactCard({ item }) {
192
- const tone = TONE_STYLES[item.tone ?? "default"];
193
- const content = /* @__PURE__ */ jsx4("div", { className: cn("rounded-[var(--radius-lg)] border px-4 py-3", tone.card), children: /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-3", children: [
194
- /* @__PURE__ */ jsx4("div", { 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", children: item.icon ?? /* @__PURE__ */ jsx4(FileText, { className: "h-4 w-4" }) }),
195
- /* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
196
- /* @__PURE__ */ jsx4("div", { className: "text-sm font-medium text-foreground", children: item.title }),
197
- item.description && /* @__PURE__ */ jsx4("div", { className: "mt-1 text-sm text-muted-foreground", children: item.description }),
198
- item.meta && /* @__PURE__ */ jsx4("div", { className: "mt-2 flex flex-wrap items-center gap-2 text-xs text-muted-foreground", children: item.meta })
199
- ] }),
200
- item.action && /* @__PURE__ */ jsx4("div", { className: "shrink-0", children: item.action })
201
- ] }) });
202
- if (!item.onClick) return content;
203
- return /* @__PURE__ */ jsx4(
204
- "div",
205
- {
206
- role: "button",
207
- tabIndex: 0,
208
- onClick: item.onClick,
209
- onKeyDown: (event) => {
210
- if (event.key === "Enter" || event.key === " ") {
211
- event.preventDefault();
212
- item.onClick?.();
213
- }
214
- },
215
- className: "block w-full text-left transition-transform hover:-translate-y-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
216
- children: content
217
- }
218
- );
219
- }
220
- function AgentTimeline({
221
- items,
222
- isThinking,
223
- emptyState,
224
- className
225
- }) {
226
- if (items.length === 0 && !isThinking) {
227
- return emptyState ? /* @__PURE__ */ jsx4("div", { className: cn("flex h-full items-center justify-center p-4", className), children: emptyState }) : null;
228
- }
229
- const renderedItems = isThinking ? [...items, { id: "__thinking__", kind: "custom", content: /* @__PURE__ */ jsx4(ThinkingIndicator, {}) }] : items;
230
- const timelineItems = renderedItems.filter((item) => !(item.kind === "message" && item.role === "user"));
231
- return /* @__PURE__ */ jsx4("div", { className: cn("mx-auto w-full max-w-5xl px-4 py-4", className), children: renderedItems.map((item, index) => {
232
- if (item.kind === "message" && item.role === "user") {
233
- return /* @__PURE__ */ jsx4(UserMessage2, { item }, item.id);
234
- }
235
- const timelineIndex = timelineItems.indexOf(item);
236
- const isLast = timelineIndex === timelineItems.length - 1;
237
- if (item.kind === "message") {
238
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--brand-glow)]", children: /* @__PURE__ */ jsx4(AssistantMessage, { item }) }, item.id);
239
- }
240
- if (item.kind === "tool") {
241
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: /* @__PURE__ */ jsx4(
242
- ToolCallStep,
243
- {
244
- type: item.call.type,
245
- label: item.call.label,
246
- status: item.call.status,
247
- detail: item.call.detail,
248
- output: item.call.output,
249
- duration: item.call.duration
250
- }
251
- ) }, item.id);
252
- }
253
- if (item.kind === "tool_group") {
254
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: /* @__PURE__ */ jsx4(ToolCallGroup, { title: item.title, children: item.calls.map((call) => /* @__PURE__ */ jsx4(
255
- ToolCallStep,
256
- {
257
- type: call.type,
258
- label: call.label,
259
- status: call.status,
260
- detail: call.detail,
261
- output: call.output,
262
- duration: call.duration
263
- },
264
- call.id
265
- )) }) }, item.id);
266
- }
267
- if (item.kind === "status") {
268
- return /* @__PURE__ */ jsx4(
269
- AgentTimelineRow,
270
- {
271
- isLast,
272
- accentClassName: TONE_STYLES[item.tone ?? "default"].dot,
273
- children: /* @__PURE__ */ jsx4(StatusCard, { item })
274
- },
275
- item.id
276
- );
277
- }
278
- if (item.kind === "artifact") {
279
- return /* @__PURE__ */ jsx4(
280
- AgentTimelineRow,
281
- {
282
- isLast,
283
- accentClassName: TONE_STYLES[item.tone ?? "default"].dot,
284
- children: /* @__PURE__ */ jsx4(ArtifactCard, { item })
285
- },
286
- item.id
287
- );
288
- }
289
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: item.content }, item.id);
290
- }) });
291
- }
292
-
293
- // src/chat/chat-input.tsx
294
- import { useState as useState2, useRef, useCallback } from "react";
295
- import { Send, Square, Paperclip, FolderUp, X, Upload } from "lucide-react";
296
- import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
297
- function ChatInput({
298
- onSend,
299
- onCancel,
300
- isStreaming,
301
- disabled,
302
- placeholder = "Ask the agent to inspect files, run commands, or explain results\u2026",
303
- modelLabel,
304
- onModelClick,
305
- pendingFiles = [],
306
- onRemoveFile,
307
- onAttach,
308
- onAttachFolder,
309
- accept,
310
- dropTitle = "Drop files to add context",
311
- dropDescription = "Files will be attached to your next message.",
312
- className,
313
- inputLabel = "Agent Command Deck",
314
- idleStatus = "Ready for next instruction",
315
- streamingStatus = "Streaming response",
316
- hideShortcutHint
317
- }) {
318
- const [value, setValue] = useState2("");
319
- const [dragOver, setDragOver] = useState2(false);
320
- const dragCounter = useRef(0);
321
- const textareaRef = useRef(null);
322
- const fileInputRef = useRef(null);
323
- const folderInputRef = useRef(null);
324
- const handleSend = useCallback(() => {
325
- const trimmed = value.trim();
326
- if (!trimmed || isStreaming || disabled) return;
327
- onSend(trimmed);
328
- setValue("");
329
- if (textareaRef.current) {
330
- textareaRef.current.style.height = "auto";
331
- }
332
- }, [value, isStreaming, disabled, onSend]);
333
- const handleKeyDown = (e) => {
334
- if (e.key === "Enter" && !e.shiftKey) {
335
- e.preventDefault();
336
- handleSend();
337
- }
338
- };
339
- const handleChange = (e) => {
340
- setValue(e.target.value);
341
- const el = e.target;
342
- el.style.height = "auto";
343
- el.style.height = `${Math.min(el.scrollHeight, 160)}px`;
344
- };
345
- const handleAttachClick = () => {
346
- fileInputRef.current?.click();
347
- };
348
- const handleFolderClick = () => {
349
- folderInputRef.current?.click();
350
- };
351
- const handleFileChange = (e) => {
352
- if (e.target.files?.length) {
353
- onAttach?.(e.target.files);
354
- e.target.value = "";
355
- }
356
- };
357
- const handleFolderChange = (e) => {
358
- if (e.target.files?.length) {
359
- (onAttachFolder ?? onAttach)?.(e.target.files);
360
- e.target.value = "";
361
- }
362
- };
363
- const handleDragEnter = useCallback((e) => {
364
- e.preventDefault();
365
- e.stopPropagation();
366
- dragCounter.current++;
367
- if (e.dataTransfer?.types.includes("Files")) {
368
- setDragOver(true);
369
- }
370
- }, []);
371
- const handleDragLeave = useCallback((e) => {
372
- e.preventDefault();
373
- e.stopPropagation();
374
- dragCounter.current--;
375
- if (dragCounter.current === 0) {
376
- setDragOver(false);
377
- }
378
- }, []);
379
- const handleDragOver = useCallback((e) => {
380
- e.preventDefault();
381
- e.stopPropagation();
382
- e.dataTransfer.dropEffect = "copy";
383
- }, []);
384
- const handleDrop = useCallback((e) => {
385
- e.preventDefault();
386
- e.stopPropagation();
387
- dragCounter.current = 0;
388
- setDragOver(false);
389
- const files = e.dataTransfer?.files;
390
- if (files?.length && onAttach) {
391
- onAttach(files);
392
- }
393
- }, [onAttach]);
394
- const fileChips = pendingFiles.filter((f) => f.type === "file" || !f.type);
395
- const folderChips = pendingFiles.filter((f) => f.type === "folder");
396
- return /* @__PURE__ */ jsxs4(
397
- "div",
398
- {
399
- className: cn("relative", className),
400
- onDragEnter: onAttach ? handleDragEnter : void 0,
401
- onDragLeave: onAttach ? handleDragLeave : void 0,
402
- onDragOver: onAttach ? handleDragOver : void 0,
403
- onDrop: onAttach ? handleDrop : void 0,
404
- children: [
405
- dragOver && /* @__PURE__ */ jsx5("div", { className: "absolute inset-0 z-10 flex items-center justify-center rounded-[var(--radius-xl)] border-2 border-dashed border-border bg-card pointer-events-none", children: /* @__PURE__ */ jsxs4("div", { className: "text-center", children: [
406
- /* @__PURE__ */ jsx5("div", { className: "mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-xl bg-[var(--accent-surface-soft)]", children: /* @__PURE__ */ jsx5(Upload, { className: "h-6 w-6 text-primary" }) }),
407
- /* @__PURE__ */ jsx5("p", { className: "text-sm font-semibold text-foreground", children: dropTitle }),
408
- /* @__PURE__ */ jsx5("p", { className: "mt-1 text-xs text-muted-foreground", children: dropDescription })
409
- ] }) }),
410
- pendingFiles.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "mb-3 flex flex-wrap gap-2", children: [
411
- folderChips.map((f) => /* @__PURE__ */ jsxs4(
412
- "span",
413
- {
414
- className: cn(
415
- "inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border px-3 py-1.5 text-xs",
416
- "border-border bg-muted/50",
417
- f.status === "error" && "border-[var(--code-error)]/30 text-[var(--code-error)]",
418
- f.status !== "error" && "text-foreground"
419
- ),
420
- children: [
421
- /* @__PURE__ */ jsx5(FolderUp, { className: "h-3 w-3 shrink-0" }),
422
- /* @__PURE__ */ jsx5("span", { className: "truncate max-w-[150px]", children: f.name }),
423
- f.fileCount !== void 0 && /* @__PURE__ */ jsxs4("span", { className: "text-muted-foreground", children: [
424
- "(",
425
- f.fileCount,
426
- ")"
427
- ] }),
428
- f.status === "uploading" && /* @__PURE__ */ jsx5("span", { className: "w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin" }),
429
- onRemoveFile && /* @__PURE__ */ jsx5(
430
- "button",
431
- {
432
- type: "button",
433
- "aria-label": `Remove ${f.name}`,
434
- onClick: () => onRemoveFile(f.id),
435
- className: "rounded p-0.5 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
436
- children: /* @__PURE__ */ jsx5(X, { className: "h-3 w-3" })
437
- }
438
- )
439
- ]
440
- },
441
- f.id
442
- )),
443
- fileChips.map((f) => /* @__PURE__ */ jsxs4(
444
- "span",
445
- {
446
- className: cn(
447
- "inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border px-3 py-1.5 text-xs",
448
- "border-border bg-muted/50",
449
- f.status === "error" && "border-[var(--code-error)]/30 text-[var(--code-error)]",
450
- f.status !== "error" && "text-foreground"
451
- ),
452
- children: [
453
- /* @__PURE__ */ jsx5(Paperclip, { className: "h-3 w-3 shrink-0" }),
454
- /* @__PURE__ */ jsx5("span", { className: "truncate max-w-[150px]", children: f.name }),
455
- f.status === "uploading" && /* @__PURE__ */ jsx5("span", { className: "w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin" }),
456
- onRemoveFile && /* @__PURE__ */ jsx5(
457
- "button",
458
- {
459
- type: "button",
460
- "aria-label": `Remove ${f.name}`,
461
- onClick: () => onRemoveFile(f.id),
462
- className: "rounded p-0.5 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
463
- children: /* @__PURE__ */ jsx5(X, { className: "h-3 w-3" })
464
- }
465
- )
466
- ]
467
- },
468
- f.id
469
- ))
470
- ] }),
471
- /* @__PURE__ */ jsx5("div", { className: "rounded-[24px] border border-[var(--chat-input-border,var(--border-default))] [background:var(--chat-input-bg,var(--bg-card))] shadow-[var(--chat-input-shadow,0_1px_2px_rgba(15,23,42,0.05))] transition-all focus-within:border-[var(--chat-input-focus-border,var(--border-accent))] focus-within:shadow-[var(--chat-input-focus-shadow,0_10px_30px_rgba(15,23,42,0.08))]", children: /* @__PURE__ */ jsxs4("div", { className: "rounded-[24px] px-4 py-[var(--chat-input-py)]", children: [
472
- (inputLabel !== null || idleStatus !== null || streamingStatus !== null) && /* @__PURE__ */ jsxs4("div", { className: "mb-1.5 flex items-center justify-between gap-3 px-1", children: [
473
- inputLabel !== null && /* @__PURE__ */ jsx5("div", { className: "text-[var(--chat-label-size,11px)] font-[var(--chat-label-weight,600)] uppercase tracking-[var(--chat-label-tracking,0.16em)] text-[var(--text-muted)]", children: inputLabel }),
474
- (idleStatus !== null || streamingStatus !== null) && /* @__PURE__ */ jsx5("div", { className: "text-[var(--chat-label-size,11px)] text-[var(--text-muted)]", children: isStreaming ? streamingStatus ?? "" : idleStatus ?? "" })
475
- ] }),
476
- /* @__PURE__ */ jsxs4("div", { className: "flex items-end gap-2.5", children: [
477
- onAttach && /* @__PURE__ */ jsxs4(Fragment, { children: [
478
- /* @__PURE__ */ jsx5(
479
- "button",
480
- {
481
- type: "button",
482
- onClick: handleAttachClick,
483
- disabled: isStreaming,
484
- "aria-label": "Attach files",
485
- title: "Attach files",
486
- className: "mb-0.5 shrink-0 rounded-[var(--radius-md)] border border-transparent p-2 text-muted-foreground transition-colors hover:border-border hover:bg-accent hover:text-foreground disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
487
- children: /* @__PURE__ */ jsx5(Paperclip, { className: "h-4 w-4" })
488
- }
489
- ),
490
- /* @__PURE__ */ jsx5(
491
- "input",
492
- {
493
- ref: fileInputRef,
494
- type: "file",
495
- multiple: true,
496
- className: "hidden",
497
- onChange: handleFileChange,
498
- accept: accept ?? ".pdf,.csv,.xlsx,.xls,.jpg,.jpeg,.png,.gif,.txt,.json,.yaml,.yml"
499
- }
500
- )
501
- ] }),
502
- (onAttachFolder ?? onAttach) && /* @__PURE__ */ jsxs4(Fragment, { children: [
503
- /* @__PURE__ */ jsx5(
504
- "button",
505
- {
506
- type: "button",
507
- onClick: handleFolderClick,
508
- disabled: isStreaming,
509
- "aria-label": "Attach folder",
510
- title: "Attach folder",
511
- className: "mb-0.5 shrink-0 rounded-[var(--radius-md)] border border-transparent p-2 text-muted-foreground transition-colors hover:border-border hover:bg-accent hover:text-foreground disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
512
- children: /* @__PURE__ */ jsx5(FolderUp, { className: "h-4 w-4" })
513
- }
514
- ),
515
- /* @__PURE__ */ jsx5(
516
- "input",
517
- {
518
- ref: folderInputRef,
519
- type: "file",
520
- multiple: true,
521
- className: "hidden",
522
- onChange: handleFolderChange,
523
- webkitdirectory: ""
524
- }
525
- )
526
- ] }),
527
- /* @__PURE__ */ jsx5(
528
- "textarea",
529
- {
530
- ref: textareaRef,
531
- value,
532
- onChange: handleChange,
533
- onKeyDown: handleKeyDown,
534
- placeholder,
535
- disabled: isStreaming || disabled,
536
- rows: 1,
537
- "aria-label": "Message input",
538
- className: "min-h-[42px] max-h-[160px] flex-1 resize-none bg-transparent py-2 text-[15px] leading-6 text-foreground placeholder:text-muted-foreground disabled:opacity-50 focus-visible:outline-none"
539
- }
540
- ),
541
- isStreaming ? /* @__PURE__ */ jsx5(
542
- "button",
543
- {
544
- type: "button",
545
- onClick: onCancel,
546
- "aria-label": "Stop response",
547
- className: "mb-0.5 shrink-0 rounded-[var(--radius-lg)] border border-[var(--code-error)]/20 bg-[var(--code-error)]/14 p-2.5 text-[var(--code-error)] transition-colors hover:bg-[var(--code-error)]/24 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--code-error)]/50",
548
- children: /* @__PURE__ */ jsx5(Square, { className: "h-4 w-4" })
549
- }
550
- ) : /* @__PURE__ */ jsxs4(
551
- "button",
552
- {
553
- type: "button",
554
- onClick: handleSend,
555
- disabled: !value.trim() || disabled,
556
- "aria-label": "Send message",
557
- className: "mb-0.5 inline-flex shrink-0 items-center gap-1.5 rounded-full border border-[var(--chat-send-border,var(--border-accent))] [background:var(--chat-send-bg,var(--brand-primary))] px-3.5 py-2.5 text-sm font-medium text-[var(--chat-send-color,white)] shadow-[var(--chat-send-shadow,0_6px_16px_rgba(15,23,42,0.12))] transition-all hover:translate-y-[-1px] hover:[background:var(--chat-send-hover-bg,var(--brand-strong))] disabled:opacity-30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--chat-send-ring,var(--border-accent))]",
558
- children: [
559
- /* @__PURE__ */ jsx5(Send, { className: "h-4 w-4" }),
560
- /* @__PURE__ */ jsx5("span", { children: "Send" })
561
- ]
562
- }
563
- )
564
- ] })
565
- ] }) }),
566
- (modelLabel || !hideShortcutHint) && /* @__PURE__ */ jsxs4("div", { className: "mt-2 flex items-center justify-between px-1", children: [
567
- /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2", children: modelLabel && /* @__PURE__ */ jsxs4(
568
- "button",
569
- {
570
- type: "button",
571
- onClick: onModelClick,
572
- "aria-label": `Select model, current model ${modelLabel}`,
573
- className: "inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border border-border bg-[linear-gradient(180deg,rgba(255,255,255,0.04),transparent)] px-2.5 py-1 text-xs text-muted-foreground transition-colors hover:border-primary/20 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
574
- children: [
575
- /* @__PURE__ */ jsx5("span", { className: "w-1.5 h-1.5 rounded-full bg-[var(--code-success)]" }),
576
- modelLabel
577
- ]
578
- }
579
- ) }),
580
- !hideShortcutHint && /* @__PURE__ */ jsxs4("span", { className: "text-xs text-muted-foreground", children: [
581
- /* @__PURE__ */ jsx5("kbd", { className: "px-1 py-0.5 bg-background rounded border border-border text-[10px]", children: "Cmd" }),
582
- /* @__PURE__ */ jsx5("kbd", { className: "px-1 py-0.5 bg-background rounded border border-border text-[10px] ml-0.5", children: "L" }),
583
- /* @__PURE__ */ jsx5("span", { className: "ml-1", children: "to focus" })
584
- ] })
585
- ] })
586
- ]
587
- }
588
- );
589
- }
590
-
591
- // src/chat/chat-container.tsx
592
- import {
593
- memo as memo3,
594
- useCallback as useCallback2,
595
- useMemo,
596
- useRef as useRef2
597
- } from "react";
598
- import { ArrowDown } from "lucide-react";
599
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
600
- var OPENUI_NODE_TYPES = /* @__PURE__ */ new Set([
601
- "heading",
602
- "text",
603
- "badge",
604
- "stat",
605
- "key_value",
606
- "code",
607
- "markdown",
608
- "table",
609
- "actions",
610
- "separator",
611
- "stack",
612
- "grid",
613
- "card"
614
- ]);
615
- function isOpenUINode(value) {
616
- return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string" && OPENUI_NODE_TYPES.has(value.type);
617
- }
618
- function extractOpenUISchema(output) {
619
- if (output == null) return null;
620
- if (isOpenUINode(output)) return [output];
621
- if (Array.isArray(output) && output.length > 0 && output.every(isOpenUINode)) {
622
- return output;
623
- }
624
- if (typeof output === "object" && !Array.isArray(output)) {
625
- const obj = output;
626
- for (const key of ["openui", "schema", "ui"]) {
627
- if (obj[key]) {
628
- const inner = obj[key];
629
- if (isOpenUINode(inner)) return [inner];
630
- if (Array.isArray(inner) && inner.length > 0 && inner.every(isOpenUINode)) {
631
- return inner;
632
- }
633
- }
634
- }
635
- }
636
- if (typeof output === "string") {
637
- try {
638
- const parsed = JSON.parse(output);
639
- return extractOpenUISchema(parsed);
640
- } catch {
641
- return null;
642
- }
643
- }
644
- return null;
645
- }
646
- function formatUnknown(value) {
647
- if (value == null) return void 0;
648
- if (typeof value === "string") return value;
649
- try {
650
- return JSON.stringify(value, null, 2);
651
- } catch {
652
- return String(value);
653
- }
654
- }
655
- function createdAtFromMessage(message) {
656
- return message.time?.created ? new Date(message.time.created) : void 0;
657
- }
658
- function mapToolPartToTimelineType(part) {
659
- const name = part.tool.toLowerCase().replace(/^tool:/, "");
660
- switch (name) {
661
- case "bash":
662
- case "shell":
663
- case "command":
664
- case "execute":
665
- return "bash";
666
- case "write":
667
- case "write_file":
668
- case "create_file":
669
- return "write";
670
- case "read":
671
- case "read_file":
672
- case "cat":
673
- return "read";
674
- case "edit":
675
- case "patch":
676
- case "sed":
677
- return "edit";
678
- case "glob":
679
- case "find":
680
- return "glob";
681
- case "ls":
682
- return "list";
683
- case "grep":
684
- case "search":
685
- case "rg":
686
- return "grep";
687
- case "inspect":
688
- return "inspect";
689
- default:
690
- return "unknown";
691
- }
692
- }
693
- function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI = true) {
694
- const items = [];
695
- const lastAssistantMessage = [...messages].reverse().find((message) => message.role === "assistant");
696
- const toToolCall = (part) => {
697
- const meta = getToolDisplayMetadata(part);
698
- const start = part.state.time?.start;
699
- const end = part.state.time?.end;
700
- return {
701
- id: part.id,
702
- type: mapToolPartToTimelineType(part),
703
- label: meta.description ? `${meta.title}: ${meta.description}` : meta.title,
704
- status: part.state.status === "completed" ? "success" : part.state.status === "error" ? "error" : "running",
705
- detail: formatUnknown(part.state.input),
706
- output: formatUnknown(part.state.output),
707
- duration: start && end ? end - start : void 0
708
- };
709
- };
710
- for (const message of messages) {
711
- const parts = partMap[message.id] ?? [];
712
- if (message.role === "user") {
713
- const content = parts.filter((part) => part.type === "text").map((part) => part.text).join("\n").trim();
714
- if (!content) continue;
715
- items.push({
716
- id: message.id,
717
- kind: "message",
718
- role: "user",
719
- content,
720
- timestamp: createdAtFromMessage(message)
721
- });
722
- continue;
723
- }
724
- const toolBuffer = [];
725
- const flushToolBuffer = (index) => {
726
- if (toolBuffer.length === 0) return;
727
- if (toolBuffer.length === 1) {
728
- items.push({
729
- id: `${message.id}-tool-${toolBuffer[0].id}`,
730
- kind: "tool",
731
- call: toToolCall(toolBuffer[0])
732
- });
733
- } else {
734
- items.push({
735
- id: `${message.id}-tool-group-${index}`,
736
- kind: "tool_group",
737
- title: "Tool activity",
738
- calls: toolBuffer.map((part) => toToolCall(part))
739
- });
740
- }
741
- if (enableOpenUI) {
742
- for (const part of toolBuffer) {
743
- if (part.state.status !== "completed" || !part.state.output) continue;
744
- const schema = extractOpenUISchema(part.state.output);
745
- if (!schema) continue;
746
- items.push({
747
- id: `${message.id}-openui-${part.id}`,
748
- kind: "custom",
749
- content: /* @__PURE__ */ jsx6("div", { className: "my-2 rounded-[var(--radius-lg)] border border-border bg-card p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx6(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
750
- });
751
- }
752
- }
753
- toolBuffer.length = 0;
754
- };
755
- parts.forEach((part, index) => {
756
- const itemId = `${message.id}-${index}`;
757
- if (part.type === "tool") {
758
- toolBuffer.push(part);
759
- return;
760
- }
761
- flushToolBuffer(index);
762
- if (part.type === "text" && !part.synthetic && part.text.trim()) {
763
- if (enableOpenUI) {
764
- const jsonMatch = part.text.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
765
- if (jsonMatch) {
766
- const schema = extractOpenUISchema(jsonMatch[1]);
767
- if (schema) {
768
- const beforeJson = part.text.slice(0, part.text.indexOf("```")).trim();
769
- if (beforeJson) {
770
- items.push({
771
- id: `${itemId}-text`,
772
- kind: "message",
773
- role: "assistant",
774
- content: beforeJson,
775
- timestamp: createdAtFromMessage(message)
776
- });
777
- }
778
- items.push({
779
- id: `${itemId}-openui`,
780
- kind: "custom",
781
- content: /* @__PURE__ */ jsx6("div", { className: "my-2 rounded-[var(--radius-lg)] border border-border bg-card p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx6(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
782
- });
783
- const afterJson = part.text.slice(part.text.lastIndexOf("```") + 3).trim();
784
- if (afterJson) {
785
- items.push({
786
- id: `${itemId}-after`,
787
- kind: "message",
788
- role: "assistant",
789
- content: afterJson,
790
- timestamp: createdAtFromMessage(message)
791
- });
792
- }
793
- return;
794
- }
795
- }
796
- }
797
- items.push({
798
- id: itemId,
799
- kind: "message",
800
- role: "assistant",
801
- content: part.text,
802
- timestamp: createdAtFromMessage(message),
803
- isStreaming: isStreaming && lastAssistantMessage?.id === message.id && index === parts.length - 1
804
- });
805
- return;
806
- }
807
- if (part.type === "reasoning") {
808
- items.push({
809
- id: itemId,
810
- kind: "custom",
811
- content: /* @__PURE__ */ jsx6(InlineThinkingItem, { part, defaultOpen: isStreaming && lastAssistantMessage?.id === message.id })
812
- });
813
- return;
814
- }
815
- });
816
- flushToolBuffer(parts.length);
817
- }
818
- const showThinking = isStreaming && lastAssistantMessage != null && !items.some(
819
- (item) => item.kind === "message" && item.role === "assistant" && item.id.startsWith(lastAssistantMessage.id)
820
- );
821
- return { items, showThinking };
822
- }
823
- var ChatContainer = memo3(
824
- ({
825
- messages,
826
- partMap,
827
- isStreaming,
828
- onSend,
829
- onCancel,
830
- branding,
831
- placeholder = "Type a message...",
832
- className,
833
- hideInput = false,
834
- renderToolDetail,
835
- presentation = "runs",
836
- modelLabel,
837
- onModelClick,
838
- pendingFiles,
839
- onRemoveFile,
840
- onAttach,
841
- disabled = false,
842
- onOpenUIAction,
843
- enableOpenUI = true,
844
- renderRunActions,
845
- renderUserMessageActions,
846
- renderToolActions
847
- }) => {
848
- const scrollRef = useRef2(null);
849
- const groups = useRunGroups({ messages, partMap, isStreaming });
850
- const runs = groups.filter((g) => g.type === "run").map((g) => g.run);
851
- const { isCollapsed, toggleCollapse } = useRunCollapseState(runs);
852
- const { isAtBottom, scrollToBottom } = useAutoScroll(scrollRef, [
853
- messages,
854
- partMap,
855
- isStreaming
856
- ]);
857
- const timeline = useMemo(
858
- () => buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI),
859
- [messages, partMap, isStreaming, onOpenUIAction, enableOpenUI]
860
- );
861
- const handleSend = useCallback2(
862
- (text) => {
863
- onSend?.(text);
864
- },
865
- [onSend]
866
- );
867
- return /* @__PURE__ */ jsxs5("div", { className: cn("flex h-full flex-col", className), children: [
868
- /* @__PURE__ */ jsx6(
869
- "div",
870
- {
871
- ref: scrollRef,
872
- className: "flex-1 overflow-y-auto [scrollbar-gutter:stable]",
873
- children: messages.length === 0 ? /* @__PURE__ */ jsx6("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx6("div", { className: "max-w-md text-center", children: /* @__PURE__ */ jsx6("div", { className: "text-sm font-medium text-muted-foreground", children: "Start a conversation." }) }) }) : presentation === "timeline" ? /* @__PURE__ */ jsx6("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx6(AgentTimeline, { items: timeline.items, isThinking: timeline.showThinking }) }) : /* @__PURE__ */ jsx6("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx6(
874
- MessageList,
875
- {
876
- groups,
877
- partMap,
878
- isCollapsed,
879
- onToggleCollapse: toggleCollapse,
880
- branding,
881
- renderToolDetail,
882
- renderRunActions,
883
- renderUserMessageActions,
884
- renderToolActions
885
- }
886
- ) })
887
- }
888
- ),
889
- !isAtBottom && /* @__PURE__ */ jsx6("div", { className: "relative z-10 -mt-10 flex justify-center", children: /* @__PURE__ */ jsxs5(
890
- "button",
891
- {
892
- onClick: scrollToBottom,
893
- className: cn(
894
- "flex items-center gap-1.5 px-3 py-1.5 rounded-full",
895
- "border border-border bg-card shadow-[0_6px_16px_rgba(15,23,42,0.08)]",
896
- "text-xs text-foreground transition-colors hover:bg-accent",
897
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60"
898
- ),
899
- children: [
900
- /* @__PURE__ */ jsx6(ArrowDown, { className: "w-3 h-3" }),
901
- "Scroll to bottom"
902
- ]
903
- }
904
- ) }),
905
- !hideInput && onSend && /* @__PURE__ */ jsx6(
906
- ChatInput,
907
- {
908
- onSend: handleSend,
909
- onCancel,
910
- isStreaming,
911
- placeholder,
912
- modelLabel,
913
- onModelClick,
914
- pendingFiles,
915
- onRemoveFile,
916
- onAttach,
917
- disabled,
918
- className: "shrink-0 border-t border-border bg-background"
919
- }
920
- )
921
- ] });
922
- }
923
- );
924
- ChatContainer.displayName = "ChatContainer";
925
-
926
- export {
927
- UserMessage,
928
- MessageList,
929
- ThinkingIndicator,
930
- AgentTimeline,
931
- ChatInput,
932
- ChatContainer
933
- };