@arbidocs/blocks 0.4.2 → 0.4.4

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 (156) hide show
  1. package/README.md +42 -0
  2. package/dist/agents/definitions/AgentCreator.d.ts +11 -2
  3. package/dist/agents/definitions/index.d.ts +1 -0
  4. package/dist/agents/definitions/persona.d.ts +16 -0
  5. package/dist/agents/index.cjs +199 -146
  6. package/dist/agents/index.js +3 -2
  7. package/dist/agents/tasks/TaskRunsDialog.d.ts +15 -3
  8. package/dist/agents/tasks/index.d.ts +1 -0
  9. package/dist/agents/tasks/taskRequest.d.ts +61 -0
  10. package/dist/chat/AssistantDock.d.ts +39 -0
  11. package/dist/chat/ChatDocuments.d.ts +17 -0
  12. package/dist/chat/ChatPage.d.ts +16 -0
  13. package/dist/chat/ChatThreads.d.ts +28 -0
  14. package/dist/chat/chat-page-types.d.ts +121 -0
  15. package/dist/chat/chat-surface.d.ts +9 -0
  16. package/dist/chat/index.cjs +247 -205
  17. package/dist/chat/index.d.ts +6 -0
  18. package/dist/chat/index.js +4 -2
  19. package/dist/{chunk-OBLSURHV.js → chunk-2NNTQLBY.js} +3 -3
  20. package/dist/{chunk-OBLSURHV.js.map → chunk-2NNTQLBY.js.map} +1 -1
  21. package/dist/chunk-2VBJ763Y.js +296 -0
  22. package/dist/chunk-2VBJ763Y.js.map +1 -0
  23. package/dist/{chunk-2ORA62OF.js → chunk-67MKU5U7.js} +3 -3
  24. package/dist/{chunk-2ORA62OF.js.map → chunk-67MKU5U7.js.map} +1 -1
  25. package/dist/{chunk-AE5FHFZ5.cjs → chunk-6CHMNKXC.cjs} +6 -6
  26. package/dist/{chunk-AE5FHFZ5.cjs.map → chunk-6CHMNKXC.cjs.map} +1 -1
  27. package/dist/{chunk-TYZUCAT7.js → chunk-7YADKWZT.js} +43 -6
  28. package/dist/chunk-7YADKWZT.js.map +1 -0
  29. package/dist/chunk-ATXPAD6S.cjs +1952 -0
  30. package/dist/chunk-ATXPAD6S.cjs.map +1 -0
  31. package/dist/{chunk-YBXCZEWS.js → chunk-B673CCW5.js} +29 -6
  32. package/dist/chunk-B673CCW5.js.map +1 -0
  33. package/dist/{chunk-ITGHMJOM.js → chunk-BBEMPS6C.js} +169 -26
  34. package/dist/chunk-BBEMPS6C.js.map +1 -0
  35. package/dist/{chunk-XNBAXRY7.cjs → chunk-DGVKBOY5.cjs} +188 -32
  36. package/dist/chunk-DGVKBOY5.cjs.map +1 -0
  37. package/dist/{chunk-2K33YGM6.cjs → chunk-DN3NFNIA.cjs} +63 -294
  38. package/dist/chunk-DN3NFNIA.cjs.map +1 -0
  39. package/dist/{chunk-XQ7PKKDY.cjs → chunk-G4YOH5DU.cjs} +3 -3
  40. package/dist/{chunk-XQ7PKKDY.cjs.map → chunk-G4YOH5DU.cjs.map} +1 -1
  41. package/dist/{chunk-AXIZ2MDV.js → chunk-HER7MTRR.js} +3 -3
  42. package/dist/{chunk-AXIZ2MDV.js.map → chunk-HER7MTRR.js.map} +1 -1
  43. package/dist/{chunk-SYDHKKRZ.cjs → chunk-IZHWP6WQ.cjs} +47 -5
  44. package/dist/chunk-IZHWP6WQ.cjs.map +1 -0
  45. package/dist/chunk-JPO3F4J7.js +1899 -0
  46. package/dist/chunk-JPO3F4J7.js.map +1 -0
  47. package/dist/{chunk-WJMEXTVD.cjs → chunk-KDG6FER6.cjs} +28 -2
  48. package/dist/chunk-KDG6FER6.cjs.map +1 -0
  49. package/dist/chunk-KHX2BX3S.cjs +307 -0
  50. package/dist/chunk-KHX2BX3S.cjs.map +1 -0
  51. package/dist/{chunk-WTNMWEBC.js → chunk-NJL4LIXX.js} +4 -3
  52. package/dist/chunk-NJL4LIXX.js.map +1 -0
  53. package/dist/{chunk-J2BGSWXM.cjs → chunk-O637DUKS.cjs} +27 -27
  54. package/dist/{chunk-J2BGSWXM.cjs.map → chunk-O637DUKS.cjs.map} +1 -1
  55. package/dist/{chunk-WW6EOVZA.js → chunk-OXF2IFXG.js} +26 -3
  56. package/dist/chunk-OXF2IFXG.js.map +1 -0
  57. package/dist/{chunk-6HIPFEID.cjs → chunk-PBS5MFIY.cjs} +4 -4
  58. package/dist/{chunk-6HIPFEID.cjs.map → chunk-PBS5MFIY.cjs.map} +1 -1
  59. package/dist/{chunk-AZQDNYH4.js → chunk-RCP6THBS.js} +9 -1249
  60. package/dist/chunk-RCP6THBS.js.map +1 -0
  61. package/dist/{chunk-GDFWJ73C.cjs → chunk-RIL7G7AS.cjs} +4 -1286
  62. package/dist/chunk-RIL7G7AS.cjs.map +1 -0
  63. package/dist/{chunk-DREI7EQ2.cjs → chunk-SS23F63U.cjs} +9 -9
  64. package/dist/{chunk-DREI7EQ2.cjs.map → chunk-SS23F63U.cjs.map} +1 -1
  65. package/dist/{chunk-7PEELPMA.js → chunk-TI4UTYRL.js} +62 -285
  66. package/dist/chunk-TI4UTYRL.js.map +1 -0
  67. package/dist/{chunk-6P6AEQJB.js → chunk-WJZBJUPX.js} +4 -4
  68. package/dist/{chunk-6P6AEQJB.js.map → chunk-WJZBJUPX.js.map} +1 -1
  69. package/dist/{chunk-UFHMLHIR.cjs → chunk-XAJIKT6Y.cjs} +32 -11
  70. package/dist/chunk-XAJIKT6Y.cjs.map +1 -0
  71. package/dist/{chunk-G3G7LZPM.cjs → chunk-XKKGGUU2.cjs} +29 -3
  72. package/dist/chunk-XKKGGUU2.cjs.map +1 -0
  73. package/dist/{chunk-UWGIB3VQ.js → chunk-XNOASBGW.js} +33 -12
  74. package/dist/chunk-XNOASBGW.js.map +1 -0
  75. package/dist/{chunk-CTZ5745I.js → chunk-XQKGYGCJ.js} +3 -3
  76. package/dist/{chunk-CTZ5745I.js.map → chunk-XQKGYGCJ.js.map} +1 -1
  77. package/dist/{chunk-54Q3RNJU.cjs → chunk-ZVPTFTGV.cjs} +4 -3
  78. package/dist/chunk-ZVPTFTGV.cjs.map +1 -0
  79. package/dist/citations/index.cjs +11 -11
  80. package/dist/citations/index.js +2 -2
  81. package/dist/collaboration/contacts/AddContactsParts.d.ts +9 -4
  82. package/dist/collaboration/contacts/index.d.ts +1 -0
  83. package/dist/collaboration/contacts/parseEmails.d.ts +26 -0
  84. package/dist/collaboration/index.cjs +51 -31
  85. package/dist/collaboration/index.js +1 -1
  86. package/dist/components/MemberAvatarStack.d.ts +7 -2
  87. package/dist/connect/index.cjs +41 -12
  88. package/dist/connect/index.cjs.map +1 -1
  89. package/dist/connect/index.d.ts +3 -2
  90. package/dist/connect/index.js +20 -4
  91. package/dist/connect/index.js.map +1 -1
  92. package/dist/connection/ConnectionProvider.d.ts +2 -0
  93. package/dist/connection/ai.d.ts +13 -1
  94. package/dist/connection/useConnectedShellWorkspaces.d.ts +15 -0
  95. package/dist/facts/index.cjs +3 -3
  96. package/dist/facts/index.cjs.map +1 -1
  97. package/dist/facts/index.js +2 -2
  98. package/dist/facts/index.js.map +1 -1
  99. package/dist/files/index.cjs +4 -3
  100. package/dist/files/index.cjs.map +1 -1
  101. package/dist/files/index.js +4 -3
  102. package/dist/files/index.js.map +1 -1
  103. package/dist/home/index.cjs +18 -17
  104. package/dist/home/index.cjs.map +1 -1
  105. package/dist/home/index.js +3 -2
  106. package/dist/home/index.js.map +1 -1
  107. package/dist/index.cjs +824 -695
  108. package/dist/index.cjs.map +1 -1
  109. package/dist/index.d.ts +1 -1
  110. package/dist/index.js +16 -15
  111. package/dist/index.js.map +1 -1
  112. package/dist/lib/format.d.ts +31 -0
  113. package/dist/retrieval/index.cjs +36 -36
  114. package/dist/retrieval/index.js +1 -1
  115. package/dist/settings/index.cjs +13 -11
  116. package/dist/settings/index.cjs.map +1 -1
  117. package/dist/settings/index.js +13 -11
  118. package/dist/settings/index.js.map +1 -1
  119. package/dist/shell/SplitLayout.d.ts +32 -0
  120. package/dist/shell/index.cjs +72 -68
  121. package/dist/shell/index.d.ts +1 -0
  122. package/dist/shell/index.js +2 -2
  123. package/dist/site/index.cjs +71 -71
  124. package/dist/site/index.js +3 -3
  125. package/dist/studio/index.cjs +79 -76
  126. package/dist/studio/index.cjs.map +1 -1
  127. package/dist/studio/index.js +9 -6
  128. package/dist/studio/index.js.map +1 -1
  129. package/dist/workspaces/WorkspaceGallery.d.ts +42 -0
  130. package/dist/workspaces/index.cjs +74 -7
  131. package/dist/workspaces/index.cjs.map +1 -1
  132. package/dist/workspaces/index.d.ts +2 -0
  133. package/dist/workspaces/index.js +73 -7
  134. package/dist/workspaces/index.js.map +1 -1
  135. package/package.json +3 -3
  136. package/src/blocks.css +10 -13
  137. package/dist/chunk-2K33YGM6.cjs.map +0 -1
  138. package/dist/chunk-54Q3RNJU.cjs.map +0 -1
  139. package/dist/chunk-7PEELPMA.js.map +0 -1
  140. package/dist/chunk-AZQDNYH4.js.map +0 -1
  141. package/dist/chunk-G3G7LZPM.cjs.map +0 -1
  142. package/dist/chunk-GDFWJ73C.cjs.map +0 -1
  143. package/dist/chunk-ITGHMJOM.js.map +0 -1
  144. package/dist/chunk-SCFYPAG6.cjs +0 -18
  145. package/dist/chunk-SCFYPAG6.cjs.map +0 -1
  146. package/dist/chunk-SYDHKKRZ.cjs.map +0 -1
  147. package/dist/chunk-TYZUCAT7.js.map +0 -1
  148. package/dist/chunk-UFHMLHIR.cjs.map +0 -1
  149. package/dist/chunk-UWGIB3VQ.js.map +0 -1
  150. package/dist/chunk-WJMEXTVD.cjs.map +0 -1
  151. package/dist/chunk-WTNMWEBC.js.map +0 -1
  152. package/dist/chunk-WW6EOVZA.js.map +0 -1
  153. package/dist/chunk-XNBAXRY7.cjs.map +0 -1
  154. package/dist/chunk-YBXCZEWS.js.map +0 -1
  155. package/dist/chunk-YDHO4AVL.js +0 -16
  156. package/dist/chunk-YDHO4AVL.js.map +0 -1
@@ -0,0 +1,1952 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkKHX2BX3S_cjs = require('./chunk-KHX2BX3S.cjs');
5
+ var chunkKDG6FER6_cjs = require('./chunk-KDG6FER6.cjs');
6
+ var chunkMHVNT4J3_cjs = require('./chunk-MHVNT4J3.cjs');
7
+ var react = require('react');
8
+ var lucideReact = require('lucide-react');
9
+ var ui = require('@arbidocs/react/ui');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+
12
+ var DEFAULT_MESSAGE_LABELS = {
13
+ subagentBadge: "sub-agent",
14
+ hideSteps: "Hide steps",
15
+ showSteps: "Show steps",
16
+ stepCount: (count) => chunkKDG6FER6_cjs.formatCount(count, { one: "step", other: "steps" }),
17
+ openSource: (num, title) => `Open source ${num}: ${title}`,
18
+ openSourceAria: (num, title, page) => `Open source ${num}: ${title}${page != null ? `, page ${page}` : ""}`,
19
+ page: (page) => `p. ${page}`,
20
+ pages: (pages) => `pp. ${pages.join(", ")}`,
21
+ moreActionsTitle: "More actions",
22
+ moreActionsAria: "More message actions"
23
+ };
24
+ function MessageRoot({
25
+ role,
26
+ messageId,
27
+ tone = "default",
28
+ testId = `message-${messageId}`,
29
+ className,
30
+ children,
31
+ ...rest
32
+ }) {
33
+ return /* @__PURE__ */ jsxRuntime.jsx(
34
+ "div",
35
+ {
36
+ "data-slot": "message",
37
+ "data-testid": testId,
38
+ "data-message-role": role,
39
+ className: ui.cn(
40
+ "group mx-auto mb-1 flex w-full max-w-[46rem] justify-center",
41
+ tone === "error" ? "rounded-lg bg-red-bg" : tone === "subagent" ? "rounded-lg bg-muted/40" : "bg-background",
42
+ className
43
+ ),
44
+ ...rest,
45
+ children
46
+ }
47
+ );
48
+ }
49
+ function MessageContent({
50
+ role,
51
+ messageId,
52
+ testId = `message-content-${messageId}`,
53
+ className,
54
+ children,
55
+ ...rest
56
+ }) {
57
+ return /* @__PURE__ */ jsxRuntime.jsx(
58
+ "div",
59
+ {
60
+ "data-slot": "message-content",
61
+ "data-testid": testId,
62
+ className: ui.cn(
63
+ "w-full max-w-full overflow-hidden text-chat",
64
+ role === "user" && "flex flex-col items-end",
65
+ className
66
+ ),
67
+ ...rest,
68
+ children
69
+ }
70
+ );
71
+ }
72
+ var MessageBubble = react.forwardRef(function MessageBubble2({ role, messageId, isEditing, isQueued, testId, className, children, ...rest }, ref) {
73
+ const isUser = role === "user";
74
+ return /* @__PURE__ */ jsxRuntime.jsx(
75
+ "div",
76
+ {
77
+ ref,
78
+ "data-slot": "message-bubble",
79
+ "data-testid": testId ?? (isUser ? `user-message-${messageId}` : `assistant-message-${messageId}`),
80
+ className: ui.cn(
81
+ "overflow-hidden transition-colors",
82
+ isUser && "max-w-[80%] rounded-lg bg-muted",
83
+ isEditing && "ring-2 ring-inset ring-primary/30",
84
+ className
85
+ ),
86
+ ...rest,
87
+ children: /* @__PURE__ */ jsxRuntime.jsx(
88
+ "div",
89
+ {
90
+ className: ui.cn(
91
+ isUser ? "px-4 py-2.5" : "px-4 py-3 sm:pl-9 sm:pr-0",
92
+ isQueued && "opacity-70"
93
+ ),
94
+ children
95
+ }
96
+ )
97
+ }
98
+ );
99
+ });
100
+ function MessageByline({
101
+ messageId,
102
+ identity,
103
+ timeLabel,
104
+ isSettled,
105
+ isFailed,
106
+ statusLabel,
107
+ className,
108
+ testId = `assistant-byline-${messageId}`,
109
+ statusTestId
110
+ }) {
111
+ return /* @__PURE__ */ jsxRuntime.jsxs(
112
+ "div",
113
+ {
114
+ "data-slot": "message-byline",
115
+ "data-testid": testId,
116
+ className: ui.cn("mb-2 flex min-w-0 items-center gap-2 text-sm sm:-ml-9", className),
117
+ children: [
118
+ /* @__PURE__ */ jsxRuntime.jsx(
119
+ "span",
120
+ {
121
+ className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-ai-soft text-ai-ink",
122
+ "aria-hidden": "true",
123
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { size: 14 })
124
+ }
125
+ ),
126
+ identity,
127
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-muted-foreground", children: timeLabel }),
128
+ isSettled && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", "aria-hidden": "true", children: "\xB7" }),
129
+ isSettled && /* @__PURE__ */ jsxRuntime.jsx(
130
+ "span",
131
+ {
132
+ className: ui.cn(
133
+ "shrink-0 text-xs",
134
+ isFailed ? "font-medium text-red-text" : "text-muted-foreground"
135
+ ),
136
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(statusTestId, { testId: "assistant-status" }),
137
+ children: statusLabel
138
+ }
139
+ )
140
+ ]
141
+ }
142
+ );
143
+ }
144
+ function MessageSubagentBadge({
145
+ messageId,
146
+ children,
147
+ labels,
148
+ className,
149
+ testId = `subagent-task-badge-${messageId}`
150
+ }) {
151
+ const l = { ...DEFAULT_MESSAGE_LABELS, ...labels };
152
+ return /* @__PURE__ */ jsxRuntime.jsx(
153
+ "span",
154
+ {
155
+ "data-slot": "message-subagent-badge",
156
+ className: ui.cn(
157
+ "mb-2 inline-block rounded bg-muted px-1 py-0.5 text-xs font-semibold uppercase leading-none tracking-wide text-muted-foreground",
158
+ className
159
+ ),
160
+ "data-testid": testId,
161
+ children: children ?? l.subagentBadge
162
+ }
163
+ );
164
+ }
165
+ function MessageBody({
166
+ messageId,
167
+ className,
168
+ children,
169
+ testId = `message-body-${messageId}`
170
+ }) {
171
+ return /* @__PURE__ */ jsxRuntime.jsx(
172
+ "div",
173
+ {
174
+ "data-slot": "message-body",
175
+ className: ui.cn("markdown-content m-0 p-0 text-base leading-relaxed", className),
176
+ "data-testid": testId,
177
+ children
178
+ }
179
+ );
180
+ }
181
+ function MessageNarration({
182
+ messageId,
183
+ children,
184
+ className,
185
+ testId = `message-narration-${messageId}`
186
+ }) {
187
+ return /* @__PURE__ */ jsxRuntime.jsx(
188
+ "div",
189
+ {
190
+ "data-slot": "message-narration",
191
+ className: ui.cn("opacity-50 transition-opacity duration-300", className),
192
+ "data-provisional": "true",
193
+ "data-testid": testId,
194
+ children
195
+ }
196
+ );
197
+ }
198
+ function SourceChip({
199
+ num,
200
+ title,
201
+ page,
202
+ pages,
203
+ onOpen,
204
+ className,
205
+ labels,
206
+ testId = `source-chip-${num}`
207
+ }) {
208
+ const l = { ...DEFAULT_MESSAGE_LABELS, ...labels };
209
+ const pageText = pages && pages.length > 1 ? l.pages(pages) : page != null ? l.page(page) : null;
210
+ return /* @__PURE__ */ jsxRuntime.jsxs(
211
+ "button",
212
+ {
213
+ type: "button",
214
+ "data-slot": "source-chip",
215
+ onClick: onOpen,
216
+ className: ui.cn(
217
+ "inline-flex min-h-8 max-w-full items-center gap-2 rounded-md bg-muted px-2 py-1 text-sm text-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
218
+ className
219
+ ),
220
+ title: l.openSource(num, title),
221
+ "aria-label": l.openSourceAria(num, title, page),
222
+ "data-testid": testId,
223
+ children: [
224
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex h-5 min-w-5 items-center justify-center rounded-sm bg-ai-soft px-1 text-xs font-semibold text-ai-ink", children: num }),
225
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: title }),
226
+ pageText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: pageText })
227
+ ]
228
+ }
229
+ );
230
+ }
231
+ function mergeSourcesByFile(sources) {
232
+ const byTitle = /* @__PURE__ */ new Map();
233
+ for (const s of sources) {
234
+ const group = byTitle.get(s.title) ?? { nums: [], title: s.title, pages: [] };
235
+ group.nums.push(s.num);
236
+ if (s.page != null && !group.pages.includes(s.page)) group.pages.push(s.page);
237
+ byTitle.set(s.title, group);
238
+ }
239
+ return [...byTitle.values()];
240
+ }
241
+ function MessageSources({
242
+ messageId,
243
+ sources,
244
+ onOpenSource,
245
+ className,
246
+ labels,
247
+ testId = `source-chips-${messageId}`
248
+ }) {
249
+ if (sources.length === 0) return null;
250
+ return /* @__PURE__ */ jsxRuntime.jsx(
251
+ "div",
252
+ {
253
+ "data-slot": "message-sources",
254
+ className: ui.cn("mt-3 flex flex-wrap gap-2", className),
255
+ "data-testid": testId,
256
+ children: mergeSourcesByFile(sources).map((g) => /* @__PURE__ */ jsxRuntime.jsx(
257
+ SourceChip,
258
+ {
259
+ num: g.nums.join(", "),
260
+ testId: `source-chip-${g.nums[0]}`,
261
+ title: g.title,
262
+ page: g.pages[0],
263
+ pages: g.pages,
264
+ onOpen: () => onOpenSource(g.nums[0]),
265
+ labels
266
+ },
267
+ g.nums[0]
268
+ ))
269
+ }
270
+ );
271
+ }
272
+ function MessageFooter({
273
+ role,
274
+ leading,
275
+ actions,
276
+ steps,
277
+ className,
278
+ labels,
279
+ stepsToggleTestId
280
+ }) {
281
+ const l = { ...DEFAULT_MESSAGE_LABELS, ...labels };
282
+ const isUser = role === "user";
283
+ const showSteps = !isUser && !!steps && steps.count > 0;
284
+ const row = /* @__PURE__ */ jsxRuntime.jsxs(
285
+ "div",
286
+ {
287
+ className: ui.cn(
288
+ "flex items-center text-sm",
289
+ isUser ? "justify-end gap-2 text-xs" : "justify-between"
290
+ ),
291
+ children: [
292
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
293
+ leading,
294
+ showSteps && /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
295
+ "button",
296
+ {
297
+ type: "button",
298
+ className: "flex items-center gap-1 text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
299
+ "aria-expanded": steps.open,
300
+ "aria-label": steps.open ? l.hideSteps : l.showSteps,
301
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(stepsToggleTestId, { testId: "steps-toggle" }),
302
+ children: [
303
+ steps.open ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { size: 14 }),
304
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: l.stepCount(steps.count) })
305
+ ]
306
+ }
307
+ ) })
308
+ ] }),
309
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: actions })
310
+ ]
311
+ }
312
+ );
313
+ return /* @__PURE__ */ jsxRuntime.jsx(
314
+ "div",
315
+ {
316
+ "data-slot": "message-footer",
317
+ className: ui.cn(
318
+ "text-muted-foreground",
319
+ isUser ? "mt-1 max-w-full self-end" : "mt-3",
320
+ className
321
+ ),
322
+ children: steps ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { open: steps.open, onOpenChange: steps.onOpenChange, children: [
323
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverAnchor, { asChild: true, children: row }),
324
+ !isUser && steps.count > 0 && /* @__PURE__ */ jsxRuntime.jsx(
325
+ ui.PopoverContent,
326
+ {
327
+ side: "top",
328
+ align: "start",
329
+ sideOffset: 8,
330
+ className: "max-h-[min(60vh,32rem)] w-[var(--radix-popover-trigger-width)] overflow-y-auto rounded-lg border border-border bg-popover p-0 shadow-lg",
331
+ children: steps.panel
332
+ }
333
+ )
334
+ ] }) : row
335
+ }
336
+ );
337
+ }
338
+ var MessageActionButton = react.forwardRef(
339
+ function MessageActionButton2({ isDone, className, type = "button", ...rest }, ref) {
340
+ return /* @__PURE__ */ jsxRuntime.jsx(
341
+ "button",
342
+ {
343
+ ref,
344
+ type,
345
+ "data-slot": "message-action",
346
+ className: ui.cn(
347
+ "inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 pointer-coarse:h-11 pointer-coarse:w-11",
348
+ isDone && "text-green-text",
349
+ className
350
+ ),
351
+ ...rest
352
+ }
353
+ );
354
+ }
355
+ );
356
+ function MessageActionMenu({
357
+ items,
358
+ testId,
359
+ label,
360
+ labels,
361
+ className
362
+ }) {
363
+ const l = { ...DEFAULT_MESSAGE_LABELS, ...labels };
364
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
365
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
366
+ MessageActionButton,
367
+ {
368
+ onClick: (e) => e.stopPropagation(),
369
+ className,
370
+ title: l.moreActionsTitle,
371
+ "aria-label": label ?? l.moreActionsAria,
372
+ "data-testid": testId,
373
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { size: 16 })
374
+ }
375
+ ) }),
376
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "end", children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
377
+ ui.DropdownMenuItem,
378
+ {
379
+ onClick: (e) => {
380
+ e.stopPropagation();
381
+ item.onSelect();
382
+ },
383
+ className: item.tone === "danger" ? "text-red-text focus:text-red-text" : void 0,
384
+ "data-testid": item.testId,
385
+ children: [
386
+ item.icon,
387
+ item.label
388
+ ]
389
+ },
390
+ item.id
391
+ )) })
392
+ ] });
393
+ }
394
+ var Message = {
395
+ Root: MessageRoot,
396
+ Content: MessageContent,
397
+ Bubble: MessageBubble,
398
+ Byline: MessageByline,
399
+ SubagentBadge: MessageSubagentBadge,
400
+ Body: MessageBody,
401
+ Narration: MessageNarration,
402
+ Sources: MessageSources,
403
+ Footer: MessageFooter,
404
+ ActionButton: MessageActionButton,
405
+ ActionMenu: MessageActionMenu
406
+ };
407
+ var DEFAULT_MESSAGE_ALERT_LABELS = {
408
+ retrying: "Retrying...",
409
+ retry: "Retry"
410
+ };
411
+ function MessageAlert({
412
+ title,
413
+ description,
414
+ isBusy = false,
415
+ busyTitle,
416
+ labels,
417
+ onActivate,
418
+ actions,
419
+ className,
420
+ testId = "message-alert"
421
+ }) {
422
+ const l = { ...DEFAULT_MESSAGE_ALERT_LABELS, ...labels };
423
+ return /* @__PURE__ */ jsxRuntime.jsx(
424
+ "div",
425
+ {
426
+ "data-slot": "message-alert",
427
+ role: isBusy ? "status" : "alert",
428
+ "aria-busy": isBusy,
429
+ className: ui.cn(
430
+ "mb-3 rounded-lg border border-red-border bg-red-bg px-4 py-2 transition-colors",
431
+ className
432
+ ),
433
+ "data-testid": testId,
434
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
435
+ isBusy ? /* @__PURE__ */ jsxRuntime.jsx(
436
+ lucideReact.RotateCw,
437
+ {
438
+ "aria-hidden": "true",
439
+ className: "mt-0.5 h-5 w-5 shrink-0 animate-spin text-red-text motion-reduce:animate-none"
440
+ }
441
+ ) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { "aria-hidden": "true", className: "mt-0.5 h-5 w-5 shrink-0 text-red-text" }),
442
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
443
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1 text-base font-medium text-red-text", children: isBusy ? busyTitle ?? l.retrying : title }),
444
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1 text-sm text-muted-foreground", children: description }),
445
+ (actions || onActivate) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap gap-2", children: [
446
+ actions,
447
+ onActivate && /* @__PURE__ */ jsxRuntime.jsxs(
448
+ ui.Button,
449
+ {
450
+ type: "button",
451
+ size: "sm",
452
+ variant: "outline",
453
+ className: "pointer-coarse:min-h-11",
454
+ disabled: isBusy,
455
+ onClick: onActivate,
456
+ "data-testid": `${testId}-retry`,
457
+ children: [
458
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { "aria-hidden": "true", className: "mr-2 h-4 w-4" }),
459
+ l.retry
460
+ ]
461
+ }
462
+ )
463
+ ] })
464
+ ] })
465
+ ] })
466
+ }
467
+ );
468
+ }
469
+ var DEFAULT_MESSAGE_LIST_LABELS = {
470
+ messageList: "Message list",
471
+ startConversation: "Start a new conversation",
472
+ backToConversation: "Back to conversation \u2014 this is a sub-agent's delegated thread",
473
+ conversationMessages: "Conversation messages",
474
+ responding: "Assistant is responding",
475
+ responseComplete: (text) => text ? `Response complete: ${text}` : "Response complete"
476
+ };
477
+ function MessageListRoot({
478
+ className,
479
+ children,
480
+ isBusy = false,
481
+ labels,
482
+ testId = "message-list",
483
+ ...rest
484
+ }) {
485
+ const l = { ...DEFAULT_MESSAGE_LIST_LABELS, ...labels };
486
+ return /* @__PURE__ */ jsxRuntime.jsx(
487
+ "div",
488
+ {
489
+ "data-slot": "message-list",
490
+ style: { containerType: "inline-size" },
491
+ "data-testid": testId,
492
+ role: "log",
493
+ "aria-live": "off",
494
+ "aria-busy": isBusy,
495
+ "aria-label": l.messageList,
496
+ className,
497
+ ...rest,
498
+ children
499
+ }
500
+ );
501
+ }
502
+ function MessageListStatus({
503
+ message,
504
+ testId = "message-list-status"
505
+ }) {
506
+ return /* @__PURE__ */ jsxRuntime.jsx(
507
+ "div",
508
+ {
509
+ "data-slot": "message-list-status",
510
+ role: "status",
511
+ "aria-live": "polite",
512
+ "aria-atomic": "true",
513
+ className: "sr-only",
514
+ "data-testid": testId,
515
+ children: message
516
+ }
517
+ );
518
+ }
519
+ function MessageListEmpty({
520
+ children,
521
+ labels,
522
+ className,
523
+ testId = "message-list-empty"
524
+ }) {
525
+ const l = { ...DEFAULT_MESSAGE_LIST_LABELS, ...labels };
526
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cn("flex h-64 items-center justify-center", className), "data-testid": testId, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: children ?? l.startConversation }) });
527
+ }
528
+ function MessageListBanner({
529
+ onBack,
530
+ children,
531
+ labels,
532
+ className,
533
+ testId = "back-to-conversation-button"
534
+ }) {
535
+ const l = { ...DEFAULT_MESSAGE_LIST_LABELS, ...labels };
536
+ return /* @__PURE__ */ jsxRuntime.jsx(
537
+ "div",
538
+ {
539
+ "data-slot": "message-list-banner",
540
+ className: ui.cn(
541
+ "sticky top-0 z-10 border-b border-border/40 bg-background px-3 py-2 sm:px-6",
542
+ className
543
+ ),
544
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
545
+ "button",
546
+ {
547
+ type: "button",
548
+ onClick: onBack,
549
+ className: "flex items-center gap-1.5 rounded-md px-2 py-1 text-sm font-medium text-primary transition-colors hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
550
+ "data-testid": testId,
551
+ children: [
552
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { size: 14 }),
553
+ children ?? l.backToConversation
554
+ ]
555
+ }
556
+ )
557
+ }
558
+ );
559
+ }
560
+ function MessageListRows({
561
+ totalSize,
562
+ className,
563
+ children,
564
+ labels,
565
+ ...rest
566
+ }) {
567
+ const l = { ...DEFAULT_MESSAGE_LIST_LABELS, ...labels };
568
+ return /* @__PURE__ */ jsxRuntime.jsx(
569
+ "div",
570
+ {
571
+ "data-slot": "message-list-rows",
572
+ style: { height: totalSize, position: "relative" },
573
+ role: "list",
574
+ "aria-label": l.conversationMessages,
575
+ className,
576
+ ...rest,
577
+ children
578
+ }
579
+ );
580
+ }
581
+ var MessageListRow = react.forwardRef(
582
+ function MessageListRow2({ index, start, messageId, setSize, className, children, ...rest }, ref) {
583
+ const style = {
584
+ position: "absolute",
585
+ top: 0,
586
+ left: 0,
587
+ width: "100%",
588
+ transform: `translateY(${start}px)`
589
+ };
590
+ return /* @__PURE__ */ jsxRuntime.jsx(
591
+ "div",
592
+ {
593
+ ref,
594
+ "data-slot": "message-list-row",
595
+ "data-index": index,
596
+ "data-message-id": messageId,
597
+ role: "listitem",
598
+ "aria-posinset": setSize === void 0 ? void 0 : index + 1,
599
+ "aria-setsize": setSize,
600
+ style,
601
+ className,
602
+ ...rest,
603
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cn("w-full px-3 sm:px-6"), children })
604
+ }
605
+ );
606
+ }
607
+ );
608
+ function MessageListTail() {
609
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-12 sm:h-32", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none h-8 bg-gradient-to-b from-background to-transparent sm:h-20" }) });
610
+ }
611
+ var MessageList = {
612
+ Root: MessageListRoot,
613
+ Empty: MessageListEmpty,
614
+ Banner: MessageListBanner,
615
+ Status: MessageListStatus,
616
+ Rows: MessageListRows,
617
+ Row: MessageListRow,
618
+ Tail: MessageListTail
619
+ };
620
+ function toSpeakableText(markdown, maxLength = 600) {
621
+ const flat = markdown.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[*_`#>~|]/g, "").replace(/\s+/g, " ").trim();
622
+ if (flat.length <= maxLength) return flat;
623
+ const cut = flat.slice(0, maxLength);
624
+ const lastSpace = cut.lastIndexOf(" ");
625
+ return `${(lastSpace > maxLength / 2 ? cut.slice(0, lastSpace) : cut).trimEnd()}\u2026`;
626
+ }
627
+ function useStreamAnnouncement({
628
+ isStreaming,
629
+ text,
630
+ resetKey,
631
+ maxLength,
632
+ labels
633
+ }) {
634
+ const l = { ...DEFAULT_MESSAGE_LIST_LABELS, ...labels };
635
+ const [message, setMessage] = react.useState("");
636
+ const wasStreaming = react.useRef(isStreaming);
637
+ const textRef = react.useRef(text);
638
+ textRef.current = text;
639
+ const lastKey = react.useRef(resetKey);
640
+ react.useEffect(() => {
641
+ if (lastKey.current !== resetKey) {
642
+ lastKey.current = resetKey;
643
+ wasStreaming.current = isStreaming;
644
+ setMessage("");
645
+ return;
646
+ }
647
+ if (isStreaming === wasStreaming.current) return;
648
+ wasStreaming.current = isStreaming;
649
+ setMessage(
650
+ isStreaming ? l.responding : l.responseComplete(toSpeakableText(textRef.current, maxLength))
651
+ );
652
+ }, [isStreaming, resetKey]);
653
+ return message;
654
+ }
655
+ var DEFAULT_COMPOSER_LABELS = {
656
+ branchingNotice: "Editing message. Submit to send, or cancel to go back.",
657
+ cancel: "Cancel",
658
+ inputAriaLabel: "Write your prompt here",
659
+ pastedText: "Pasted text",
660
+ pasteSummary: (lines, characters) => `${lines} lines \xB7 ${characters} characters`,
661
+ expand: "Expand",
662
+ retryMessage: "Retry message",
663
+ sendMessage: "Send message",
664
+ voiceButton: "Press and hold to speak",
665
+ jumpToBottom: "Jump to bottom"
666
+ };
667
+ function ComposerRoot({
668
+ onSubmit,
669
+ notice,
670
+ isBranching,
671
+ formRef,
672
+ testId = "message-input",
673
+ formTestId,
674
+ className,
675
+ children,
676
+ ...rest
677
+ }) {
678
+ return /* @__PURE__ */ jsxRuntime.jsxs(
679
+ "div",
680
+ {
681
+ "data-slot": "composer",
682
+ className: ui.cn("relative z-[20] shrink-0", isBranching && "bg-muted/30"),
683
+ "data-testid": testId,
684
+ children: [
685
+ notice,
686
+ /* @__PURE__ */ jsxRuntime.jsx(
687
+ "form",
688
+ {
689
+ ref: formRef,
690
+ onSubmit,
691
+ ...rest,
692
+ className: ui.cn("relative w-full", className),
693
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(formTestId, { testId: "message-input-form" }),
694
+ children
695
+ }
696
+ )
697
+ ]
698
+ }
699
+ );
700
+ }
701
+ function ComposerBranchingNotice({
702
+ onCancel,
703
+ children,
704
+ labels,
705
+ testId = "message-input-branching-indicator",
706
+ cancelTestId,
707
+ className,
708
+ ...rest
709
+ }) {
710
+ const l = { ...DEFAULT_COMPOSER_LABELS, ...labels };
711
+ return /* @__PURE__ */ jsxRuntime.jsxs(
712
+ "div",
713
+ {
714
+ ...rest,
715
+ "data-slot": "composer-notice",
716
+ className: ui.cn("mb-2 flex items-center rounded-md bg-muted px-3 py-1.5 text-sm", className),
717
+ "data-testid": testId,
718
+ children: [
719
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit3, { size: 16, className: "mr-2 text-muted-foreground" }),
720
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-muted-foreground", children: children ?? l.branchingNotice }),
721
+ onCancel && /* @__PURE__ */ jsxRuntime.jsx(
722
+ ui.Button,
723
+ {
724
+ type: "button",
725
+ variant: "outline",
726
+ size: "sm",
727
+ className: "ml-2",
728
+ onClick: onCancel,
729
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(cancelTestId, { testId: "cancel-branching-button" }),
730
+ children: l.cancel
731
+ }
732
+ )
733
+ ]
734
+ }
735
+ );
736
+ }
737
+ var INTERACTIVE = 'button, a, input, textarea, select, [role="button"], [contenteditable="true"]';
738
+ function ComposerFrame({ className, children, ...rest }) {
739
+ return /* @__PURE__ */ jsxRuntime.jsx(
740
+ "div",
741
+ {
742
+ "data-slot": "composer-frame",
743
+ className: ui.cn(
744
+ "relative flex w-full flex-col rounded-lg border border-border bg-background px-4 py-3 shadow-lg transition-shadow focus-within:shadow-xl",
745
+ className
746
+ ),
747
+ onMouseDown: (e) => {
748
+ const target = e.target;
749
+ if (target.closest(INTERACTIVE)) return;
750
+ e.preventDefault();
751
+ e.currentTarget.querySelector("textarea")?.focus();
752
+ },
753
+ ...rest,
754
+ children
755
+ }
756
+ );
757
+ }
758
+ function scrollToLastContentLine(textarea) {
759
+ if (!textarea) return;
760
+ const text = textarea.value;
761
+ const lines = text.split("\n");
762
+ const trimmedLines = text.trimEnd().split("\n");
763
+ if (lines.length - trimmedLines.length > 0 && trimmedLines.length > 0) {
764
+ const lineHeight = parseFloat(getComputedStyle(textarea).lineHeight) || 24;
765
+ textarea.scrollTop = (trimmedLines.length - 1) * lineHeight;
766
+ } else {
767
+ textarea.scrollTop = textarea.scrollHeight;
768
+ }
769
+ }
770
+ var ComposerInput = react.forwardRef(
771
+ function ComposerInput2({
772
+ value,
773
+ onValueChange,
774
+ onKeyDown,
775
+ submitOnEnter = true,
776
+ onPaste,
777
+ placeholder,
778
+ textareaRef,
779
+ isSuggestion,
780
+ isRoomy,
781
+ isPasteCollapsed,
782
+ onExpandPaste,
783
+ ariaLabel,
784
+ textareaProps,
785
+ className,
786
+ labels,
787
+ testId = "message-input-textarea",
788
+ pasteChipTestId
789
+ }, forwardedRef) {
790
+ const l = { ...DEFAULT_COMPOSER_LABELS, ...labels };
791
+ const [isFocused, setIsFocused] = react.useState(false);
792
+ const [isHovered, setIsHovered] = react.useState(false);
793
+ const innerRef = react.useRef(null);
794
+ const setRefs = (node) => {
795
+ innerRef.current = node;
796
+ for (const ref of [forwardedRef, textareaRef]) {
797
+ if (typeof ref === "function") ref(node);
798
+ else if (ref) ref.current = node;
799
+ }
800
+ };
801
+ const handleKeyDown = (event) => {
802
+ onKeyDown?.(event);
803
+ if (event.defaultPrevented || !submitOnEnter) return;
804
+ if (event.key !== "Enter" || event.shiftKey || event.altKey) return;
805
+ if (event.nativeEvent.isComposing || event.keyCode === 229) return;
806
+ event.preventDefault();
807
+ event.currentTarget.form?.requestSubmit();
808
+ };
809
+ if (isPasteCollapsed) {
810
+ const lineCount = value.split("\n").length;
811
+ return /* @__PURE__ */ jsxRuntime.jsxs(
812
+ "button",
813
+ {
814
+ type: "button",
815
+ "data-slot": "composer-paste-chip",
816
+ onClick: onExpandPaste,
817
+ className: "flex w-full items-center gap-2 rounded-md bg-muted/50 px-3 py-2 text-left transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40",
818
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(pasteChipTestId, { testId: "long-paste-placeholder" }),
819
+ "data-full-length": value.length,
820
+ children: [
821
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
822
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
823
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-sm font-medium text-foreground", children: l.pastedText }),
824
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs text-muted-foreground", children: l.pasteSummary(lineCount, value.length.toLocaleString()) })
825
+ ] }),
826
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-1 text-xs font-medium text-muted-foreground", children: [
827
+ l.expand,
828
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
829
+ ] })
830
+ ]
831
+ }
832
+ );
833
+ }
834
+ return /* @__PURE__ */ jsxRuntime.jsx(
835
+ ui.Textarea,
836
+ {
837
+ ...textareaProps,
838
+ "aria-label": ariaLabel ?? l.inputAriaLabel,
839
+ placeholder,
840
+ "data-suggested-query": isSuggestion ? "true" : void 0,
841
+ rows: 1,
842
+ ref: setRefs,
843
+ value,
844
+ onChange: (event) => onValueChange(event.target.value),
845
+ onPaste,
846
+ onKeyDown: handleKeyDown,
847
+ disabled: false,
848
+ className: ui.cn(
849
+ "scrollbar-subtle !min-h-0 pointer-coarse:!min-h-11 pointer-coarse:py-2.5 w-full resize-none border-0 bg-transparent p-0 !text-base leading-relaxed text-foreground shadow-none placeholder:text-muted-foreground/50 focus-visible:ring-0 focus-visible:ring-offset-0 md:!text-base",
850
+ className
851
+ ),
852
+ style: {
853
+ fieldSizing: "content",
854
+ maxHeight: isFocused || isHovered ? "40vh" : value ? "6.5em" : isRoomy ? "4em" : "1.7em",
855
+ overflowY: value ? "auto" : "hidden",
856
+ scrollbarGutter: "stable"
857
+ },
858
+ onFocus: () => {
859
+ setIsFocused(true);
860
+ requestAnimationFrame(() => {
861
+ const ta = innerRef.current;
862
+ if (ta) {
863
+ ta.setSelectionRange(ta.value.length, ta.value.length);
864
+ ta.scrollTop = ta.scrollHeight;
865
+ }
866
+ });
867
+ },
868
+ onBlur: () => {
869
+ setIsFocused(false);
870
+ if (!isHovered) requestAnimationFrame(() => scrollToLastContentLine(innerRef.current));
871
+ },
872
+ onMouseEnter: () => setIsHovered(true),
873
+ onMouseLeave: () => {
874
+ setIsHovered(false);
875
+ if (!isFocused) requestAnimationFrame(() => scrollToLastContentLine(innerRef.current));
876
+ },
877
+ "data-testid": testId
878
+ }
879
+ );
880
+ }
881
+ );
882
+ function ComposerToolbar({ leading, trailing, className }) {
883
+ return /* @__PURE__ */ jsxRuntime.jsxs(
884
+ "div",
885
+ {
886
+ "data-slot": "composer-toolbar",
887
+ className: ui.cn(
888
+ "mt-2 flex flex-wrap items-center justify-between gap-x-1 gap-y-0.5",
889
+ className
890
+ ),
891
+ children: [
892
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-1", children: leading }),
893
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex min-w-0 items-center justify-end gap-1", children: trailing })
894
+ ]
895
+ }
896
+ );
897
+ }
898
+ function ComposerSend({
899
+ onSend,
900
+ disabled,
901
+ isRetry,
902
+ labels,
903
+ className,
904
+ testIds
905
+ }) {
906
+ const l = { ...DEFAULT_COMPOSER_LABELS, ...labels };
907
+ const sendTestId = chunkMHVNT4J3_cjs.testIdOr(testIds?.send, { testId: "send-message-button" });
908
+ const retryTestId = chunkMHVNT4J3_cjs.testIdOr(testIds?.retry, { testId: "retry-button" });
909
+ return /* @__PURE__ */ jsxRuntime.jsx(
910
+ ui.Button,
911
+ {
912
+ type: "button",
913
+ size: "icon",
914
+ className: ui.cn(
915
+ "h-9 w-9 shrink-0 pointer-coarse:h-11 pointer-coarse:w-11",
916
+ // A faded primary is unreadable; a flat muted chip reads as "not available yet" at 4.5:1.
917
+ "disabled:bg-muted disabled:text-muted-foreground disabled:opacity-100",
918
+ className
919
+ ),
920
+ "aria-label": isRetry ? l.retryMessage : l.sendMessage,
921
+ disabled,
922
+ onClick: onSend,
923
+ "data-testid": isRetry ? retryTestId : sendTestId,
924
+ children: isRetry ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-3.5 w-3.5" })
925
+ }
926
+ );
927
+ }
928
+ function ComposerVoiceButton({
929
+ isRecording,
930
+ isBusy,
931
+ onPressStart,
932
+ onPressEnd,
933
+ label,
934
+ labels,
935
+ className,
936
+ testIds
937
+ }) {
938
+ const text = label ?? { ...DEFAULT_COMPOSER_LABELS, ...labels }.voiceButton;
939
+ const startTestId = chunkMHVNT4J3_cjs.testIdOr(testIds?.start, { testId: "start-recording-button" });
940
+ const recordingTestId = chunkMHVNT4J3_cjs.testIdOr(testIds?.recording, { testId: "recording-mic-button" });
941
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
942
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
943
+ ui.Button,
944
+ {
945
+ type: "button",
946
+ variant: "ghost",
947
+ size: "sm",
948
+ "aria-label": text,
949
+ onPointerDown: (e) => {
950
+ e.preventDefault();
951
+ onPressStart();
952
+ },
953
+ onPointerUp: onPressEnd,
954
+ onPointerLeave: onPressEnd,
955
+ onPointerCancel: onPressEnd,
956
+ disabled: isBusy,
957
+ className: ui.cn(
958
+ "h-8 w-8 shrink-0 p-0 hover:bg-muted pointer-coarse:h-11 pointer-coarse:w-11",
959
+ isRecording && "bg-red-bg",
960
+ className
961
+ ),
962
+ "data-testid": isRecording ? recordingTestId : startTestId,
963
+ children: isBusy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 animate-spin text-muted-foreground" }) : isRecording ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "h-3 w-3 fill-red-text text-red-text" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "h-4 w-4 text-muted-foreground" })
964
+ }
965
+ ) }),
966
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { side: "top", children: text })
967
+ ] });
968
+ }
969
+ function ComposerContainer({
970
+ className,
971
+ children,
972
+ testId = "message-input-container",
973
+ ...rest
974
+ }) {
975
+ return /* @__PURE__ */ jsxRuntime.jsx(
976
+ "div",
977
+ {
978
+ ...rest,
979
+ "data-slot": "composer-container",
980
+ className: ui.cn("w-full bg-background py-1", className),
981
+ "data-testid": testId,
982
+ children
983
+ }
984
+ );
985
+ }
986
+ function ComposerDock({ children, floating }) {
987
+ return /* @__PURE__ */ jsxRuntime.jsxs(
988
+ "div",
989
+ {
990
+ "data-slot": "composer-dock",
991
+ className: "sticky bottom-0 z-40 w-full pb-4 sm:pb-[max(1rem,env(safe-area-inset-bottom))]",
992
+ children: [
993
+ /* @__PURE__ */ jsxRuntime.jsx(
994
+ "div",
995
+ {
996
+ className: "pointer-events-none absolute bottom-full left-0 right-0 h-16 bg-gradient-to-b from-transparent to-background/70",
997
+ "aria-hidden": "true"
998
+ }
999
+ ),
1000
+ /* @__PURE__ */ jsxRuntime.jsx(
1001
+ "div",
1002
+ {
1003
+ className: "pointer-events-none absolute bottom-0 left-0 right-0 h-4 bg-gradient-to-b from-transparent to-background/60 backdrop-blur-sm",
1004
+ "aria-hidden": "true"
1005
+ }
1006
+ ),
1007
+ floating,
1008
+ children
1009
+ ]
1010
+ }
1011
+ );
1012
+ }
1013
+ function ScrollToBottom({
1014
+ show,
1015
+ onClick,
1016
+ label,
1017
+ labels,
1018
+ className,
1019
+ testId = "scroll-to-bottom-button"
1020
+ }) {
1021
+ if (!show) return null;
1022
+ const text = label ?? { ...DEFAULT_COMPOSER_LABELS, ...labels }.jumpToBottom;
1023
+ return /* @__PURE__ */ jsxRuntime.jsx(
1024
+ ui.Button,
1025
+ {
1026
+ onClick,
1027
+ variant: "outline",
1028
+ size: "icon",
1029
+ className: ui.cn(
1030
+ "absolute -top-12 left-1/2 z-[15] h-10 w-10 -translate-x-1/2 shadow-lg pointer-coarse:h-11 pointer-coarse:w-11",
1031
+ className
1032
+ ),
1033
+ title: text,
1034
+ "aria-label": text,
1035
+ "data-testid": testId,
1036
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { size: 20 })
1037
+ }
1038
+ );
1039
+ }
1040
+ var Composer = {
1041
+ Root: ComposerRoot,
1042
+ Notice: ComposerBranchingNotice,
1043
+ Frame: ComposerFrame,
1044
+ Input: ComposerInput,
1045
+ Toolbar: ComposerToolbar,
1046
+ Send: ComposerSend,
1047
+ VoiceButton: ComposerVoiceButton,
1048
+ Container: ComposerContainer,
1049
+ Dock: ComposerDock
1050
+ };
1051
+ var DEFAULT_CONVERSATION_EMPTY_LABELS = {
1052
+ title: "Ask ARBI about your documents",
1053
+ description: "Ask a question and verify every answer against the source.",
1054
+ dropDocuments: "Drop documents here to add them"
1055
+ };
1056
+ function AddDocumentsArea({
1057
+ onAddDocuments,
1058
+ label,
1059
+ testId
1060
+ }) {
1061
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1062
+ "button",
1063
+ {
1064
+ type: "button",
1065
+ onClick: () => onAddDocuments(),
1066
+ onDragOver: (e) => {
1067
+ if (e.dataTransfer.types.includes("Files")) {
1068
+ e.preventDefault();
1069
+ e.dataTransfer.dropEffect = "copy";
1070
+ }
1071
+ },
1072
+ onDrop: (e) => {
1073
+ const files = Array.from(e.dataTransfer.files ?? []);
1074
+ if (files.length > 0) {
1075
+ e.preventDefault();
1076
+ onAddDocuments(files);
1077
+ }
1078
+ },
1079
+ "data-testid": testId,
1080
+ className: "mx-auto flex w-full max-w-sm items-center justify-center gap-2 rounded-lg bg-muted px-3 py-2.5 text-sm text-muted-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
1081
+ children: [
1082
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileUp, { className: "h-4 w-4 shrink-0" }),
1083
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
1084
+ ]
1085
+ }
1086
+ );
1087
+ }
1088
+ var BELOW = "mx-auto w-full max-w-4xl text-left";
1089
+ var CHIP = "group inline-flex items-center rounded-full bg-muted px-3.5 py-2 text-left text-sm text-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11";
1090
+ function ConversationEmpty({
1091
+ hasDocuments,
1092
+ prompts,
1093
+ shortcut,
1094
+ onUsePrompt,
1095
+ onAddDocuments,
1096
+ noDocuments,
1097
+ below,
1098
+ title,
1099
+ description,
1100
+ className,
1101
+ labels,
1102
+ testIds
1103
+ }) {
1104
+ const l = { ...DEFAULT_CONVERSATION_EMPTY_LABELS, ...labels };
1105
+ const rootTestId = chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "conversation-empty-state" });
1106
+ const uploadTestId = chunkMHVNT4J3_cjs.testIdOr(testIds?.upload, { testId: "conversation-empty-upload" });
1107
+ const shortcutTestId = chunkMHVNT4J3_cjs.testIdOr(testIds?.shortcut, {
1108
+ testId: "conversation-shortcut-main-events"
1109
+ });
1110
+ const promptTestId = chunkMHVNT4J3_cjs.testIdOr(testIds?.prompt, { testId: "conversation-example-prompt" });
1111
+ if (!hasDocuments) {
1112
+ return /* @__PURE__ */ jsxRuntime.jsx(
1113
+ "div",
1114
+ {
1115
+ "data-slot": "conversation-empty",
1116
+ className: ui.cn(
1117
+ "absolute inset-0 flex flex-col items-center overflow-y-auto px-6 py-8 pb-28",
1118
+ className
1119
+ ),
1120
+ "data-testid": rootTestId,
1121
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-auto flex w-full flex-col items-center gap-8", children: [
1122
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full max-w-xl flex-col items-center gap-3", children: noDocuments }),
1123
+ below && /* @__PURE__ */ jsxRuntime.jsx("div", { className: BELOW, children: below })
1124
+ ] })
1125
+ }
1126
+ );
1127
+ }
1128
+ return /* @__PURE__ */ jsxRuntime.jsx(
1129
+ "div",
1130
+ {
1131
+ "data-slot": "conversation-empty",
1132
+ className: ui.cn("absolute inset-0 flex overflow-y-auto p-6 pb-28", className),
1133
+ "data-testid": rootTestId,
1134
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "m-auto flex w-full flex-col", children: [
1135
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto w-full max-w-xl text-center", children: [
1136
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-ai-soft text-ai-ink", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "h-6 w-6" }) }),
1137
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-foreground", children: title ?? l.title }),
1138
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-sm text-muted-foreground", children: description ?? l.description })
1139
+ ] }),
1140
+ below && /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cn(BELOW, "mt-6"), children: below }),
1141
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto w-full max-w-xl text-center", children: [
1142
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-wrap justify-center gap-2", below ? "mt-8" : "mt-5"), children: [
1143
+ shortcut && /* @__PURE__ */ jsxRuntime.jsxs(
1144
+ "button",
1145
+ {
1146
+ type: "button",
1147
+ onClick: () => onUsePrompt(shortcut.prompt),
1148
+ title: shortcut.prompt,
1149
+ className: ui.cn(CHIP, "gap-2 font-medium"),
1150
+ "data-testid": shortcutTestId,
1151
+ children: [
1152
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GanttChartSquare, { className: "h-4 w-4 shrink-0 text-ai-ink" }),
1153
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: shortcut.label }),
1154
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" })
1155
+ ]
1156
+ }
1157
+ ),
1158
+ prompts.map((prompt) => /* @__PURE__ */ jsxRuntime.jsxs(
1159
+ "button",
1160
+ {
1161
+ type: "button",
1162
+ onClick: () => onUsePrompt(prompt),
1163
+ className: ui.cn(CHIP, "gap-1.5"),
1164
+ "data-testid": promptTestId,
1165
+ children: [
1166
+ prompt,
1167
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { className: "h-3.5 w-3.5 text-muted-foreground" })
1168
+ ]
1169
+ },
1170
+ prompt
1171
+ ))
1172
+ ] }),
1173
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-5", children: /* @__PURE__ */ jsxRuntime.jsx(
1174
+ AddDocumentsArea,
1175
+ {
1176
+ onAddDocuments,
1177
+ label: l.dropDocuments,
1178
+ testId: uploadTestId
1179
+ }
1180
+ ) })
1181
+ ] })
1182
+ ] })
1183
+ }
1184
+ );
1185
+ }
1186
+ function canHover() {
1187
+ return typeof window !== "undefined" && !!window.matchMedia?.("(hover: hover)").matches;
1188
+ }
1189
+ function isFocusVisible(el) {
1190
+ try {
1191
+ return el.matches(":focus-visible");
1192
+ } catch {
1193
+ return true;
1194
+ }
1195
+ }
1196
+ var ContextChip = react.forwardRef(function ContextChip2({
1197
+ count,
1198
+ label,
1199
+ isOpen: isOpen2 = false,
1200
+ children,
1201
+ className,
1202
+ onMouseEnter,
1203
+ onMouseLeave,
1204
+ onFocus,
1205
+ onBlur,
1206
+ ...props
1207
+ }, ref) {
1208
+ const [isHovered, setIsHovered] = react.useState(false);
1209
+ const [isFocused, setIsFocused] = react.useState(false);
1210
+ const isEditing = isHovered || isFocused || isOpen2;
1211
+ const Icon = isEditing ? lucideReact.Pencil : lucideReact.FileText;
1212
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1213
+ ui.Button,
1214
+ {
1215
+ ref,
1216
+ type: "button",
1217
+ variant: "outline",
1218
+ "aria-label": label,
1219
+ "aria-haspopup": "dialog",
1220
+ "aria-expanded": isOpen2,
1221
+ "data-slot": "context-chip",
1222
+ "data-icon": isEditing ? "edit" : "document",
1223
+ className: ui.cn(
1224
+ "flex h-8 min-w-0 max-w-[280px] flex-shrink-0 items-center gap-1.5 rounded-md px-2.5",
1225
+ className
1226
+ ),
1227
+ ...props,
1228
+ onMouseEnter: (e) => {
1229
+ onMouseEnter?.(e);
1230
+ if (canHover()) setIsHovered(true);
1231
+ },
1232
+ onMouseLeave: (e) => {
1233
+ onMouseLeave?.(e);
1234
+ setIsHovered(false);
1235
+ },
1236
+ onFocus: (e) => {
1237
+ onFocus?.(e);
1238
+ setIsFocused(isFocusVisible(e.currentTarget));
1239
+ },
1240
+ onBlur: (e) => {
1241
+ onBlur?.(e);
1242
+ setIsFocused(false);
1243
+ },
1244
+ children: [
1245
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5 flex-shrink-0", "aria-hidden": "true" }),
1246
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-sm font-medium", "data-testid": "context-chip-count", children: count >= 1e3 ? "999+" : count }),
1247
+ children
1248
+ ]
1249
+ }
1250
+ );
1251
+ });
1252
+ function ChatDocuments({ chat, labels, onPickFiles, testIds }) {
1253
+ const [isOpen2, setIsOpen] = react.useState(false);
1254
+ const selected = chat.documents.filter((d) => d.isSelected).length;
1255
+ const total = chat.documents.length;
1256
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { open: isOpen2, onOpenChange: setIsOpen, children: [
1257
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
1258
+ ContextChip,
1259
+ {
1260
+ count: selected,
1261
+ label: labels.documentsInChat(selected, total),
1262
+ isOpen: isOpen2,
1263
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.documents, { testId: "chat-documents" }),
1264
+ className: "pointer-coarse:h-11"
1265
+ }
1266
+ ) }),
1267
+ /* @__PURE__ */ jsxRuntime.jsxs(
1268
+ ui.PopoverContent,
1269
+ {
1270
+ align: "start",
1271
+ className: "w-80 p-3",
1272
+ "aria-label": labels.documentsHeading,
1273
+ "data-testid": "chat-documents-panel",
1274
+ children: [
1275
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
1276
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-medium text-foreground", children: labels.documentsHeading }),
1277
+ total > 0 && selected < total && /* @__PURE__ */ jsxRuntime.jsx(
1278
+ ui.Button,
1279
+ {
1280
+ type: "button",
1281
+ variant: "ghost",
1282
+ size: "sm",
1283
+ className: "pointer-coarse:min-h-11",
1284
+ onClick: chat.selectAllDocuments,
1285
+ children: labels.selectAllDocuments
1286
+ }
1287
+ )
1288
+ ] }),
1289
+ total === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-2 text-sm text-muted-foreground", children: labels.noDocuments }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "max-h-60 overflow-y-auto", children: chat.documents.map((doc) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex cursor-pointer items-center gap-2 rounded-md px-1 py-1.5 text-sm hover:bg-muted pointer-coarse:min-h-11", children: [
1290
+ /* @__PURE__ */ jsxRuntime.jsx(
1291
+ "input",
1292
+ {
1293
+ type: "checkbox",
1294
+ checked: doc.isSelected,
1295
+ onChange: () => chat.toggleDocument(doc.id),
1296
+ className: "size-4 shrink-0 accent-[hsl(var(--primary))]"
1297
+ }
1298
+ ),
1299
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", title: doc.name, children: doc.name })
1300
+ ] }) }, doc.id)) }),
1301
+ /* @__PURE__ */ jsxRuntime.jsxs(
1302
+ ui.Button,
1303
+ {
1304
+ type: "button",
1305
+ variant: "outline",
1306
+ size: "sm",
1307
+ className: "mt-2 w-full gap-2 pointer-coarse:min-h-11",
1308
+ disabled: chat.isUploading,
1309
+ onClick: onPickFiles,
1310
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.upload, { testId: "chat-upload" }),
1311
+ children: [
1312
+ chat.isUploading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "size-4", "aria-hidden": "true" }),
1313
+ chat.isUploading ? labels.uploading : labels.uploadDocuments
1314
+ ]
1315
+ }
1316
+ )
1317
+ ]
1318
+ }
1319
+ )
1320
+ ] });
1321
+ }
1322
+ function ChatThreadList({
1323
+ threads,
1324
+ activeId,
1325
+ labels,
1326
+ onSelect,
1327
+ onNew,
1328
+ onDelete,
1329
+ testIds
1330
+ }) {
1331
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1332
+ "nav",
1333
+ {
1334
+ "aria-label": labels.conversations,
1335
+ "data-slot": "chat-thread-list",
1336
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.list, { testId: "chat-thread-list" }),
1337
+ className: "flex min-h-0 flex-1 flex-col gap-2 p-3",
1338
+ children: [
1339
+ /* @__PURE__ */ jsxRuntime.jsxs(
1340
+ ui.Button,
1341
+ {
1342
+ type: "button",
1343
+ variant: "outline",
1344
+ className: "w-full justify-start gap-2 pointer-coarse:min-h-11",
1345
+ onClick: onNew,
1346
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.new, { testId: "chat-new" }),
1347
+ children: [
1348
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquarePlus, { className: "size-4", "aria-hidden": "true" }),
1349
+ labels.newChat
1350
+ ]
1351
+ }
1352
+ ),
1353
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto", children: threads.map((thread) => {
1354
+ const isActive = thread.id === activeId;
1355
+ const title = thread.title || labels.untitled;
1356
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "group relative", children: [
1357
+ /* @__PURE__ */ jsxRuntime.jsx(
1358
+ "button",
1359
+ {
1360
+ type: "button",
1361
+ onClick: () => onSelect(thread.id),
1362
+ "aria-current": isActive ? "true" : void 0,
1363
+ title,
1364
+ "data-testid": `${chunkMHVNT4J3_cjs.testIdOr(testIds?.row, { testId: "chat-conversation" })}-${thread.id}`,
1365
+ className: ui.cn(
1366
+ "flex w-full items-center rounded-md px-3 py-2 pr-10 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
1367
+ isActive ? "bg-muted font-medium text-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground"
1368
+ ),
1369
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: title })
1370
+ }
1371
+ ),
1372
+ onDelete && /* @__PURE__ */ jsxRuntime.jsx(
1373
+ "button",
1374
+ {
1375
+ type: "button",
1376
+ onClick: () => onDelete(thread.id),
1377
+ "aria-label": labels.deleteConversation(title),
1378
+ "data-testid": `${chunkMHVNT4J3_cjs.testIdOr(testIds?.delete, { testId: "chat-delete" })}-${thread.id}`,
1379
+ className: "absolute right-1 top-1/2 flex size-8 -translate-y-1/2 items-center justify-center rounded-md text-muted-foreground opacity-100 hover:bg-background hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-fine:opacity-0 pointer-fine:group-hover:opacity-100 pointer-coarse:size-11",
1380
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4", "aria-hidden": "true" })
1381
+ }
1382
+ )
1383
+ ] }, thread.id);
1384
+ }) })
1385
+ ]
1386
+ }
1387
+ );
1388
+ }
1389
+ function ChatThreadSelect({
1390
+ threads,
1391
+ activeId,
1392
+ labels,
1393
+ onSelect,
1394
+ testIds
1395
+ }) {
1396
+ return /* @__PURE__ */ jsxRuntime.jsx(
1397
+ "select",
1398
+ {
1399
+ "aria-label": labels.conversations,
1400
+ value: activeId,
1401
+ onChange: (e) => onSelect(e.target.value),
1402
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.select, { testId: "chat-conversation-select" }),
1403
+ className: "h-9 min-w-0 flex-1 truncate rounded-md border border-input bg-background px-2 text-sm font-medium text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:h-11 pointer-coarse:text-base",
1404
+ children: threads.map((thread) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: thread.id, children: thread.title || labels.untitled }, thread.id))
1405
+ }
1406
+ );
1407
+ }
1408
+ var embeddedCount = 0;
1409
+ var listeners = /* @__PURE__ */ new Set();
1410
+ function subscribe(listener) {
1411
+ listeners.add(listener);
1412
+ return () => listeners.delete(listener);
1413
+ }
1414
+ function emit() {
1415
+ listeners.forEach((l) => l());
1416
+ }
1417
+ function useRegisterEmbeddedChat(enabled = true) {
1418
+ react.useEffect(() => {
1419
+ if (!enabled) return;
1420
+ embeddedCount += 1;
1421
+ emit();
1422
+ return () => {
1423
+ embeddedCount -= 1;
1424
+ emit();
1425
+ };
1426
+ }, [enabled]);
1427
+ }
1428
+ function useChatSurface() {
1429
+ const count = react.useSyncExternalStore(
1430
+ subscribe,
1431
+ () => embeddedCount,
1432
+ () => 0
1433
+ );
1434
+ return { hasEmbeddedChat: count > 0, isDockAvailable: count === 0 };
1435
+ }
1436
+
1437
+ // src/chat/chat-page-types.ts
1438
+ var DEFAULT_CHAT_PAGE_LABELS = {
1439
+ chat: "Assistant chat",
1440
+ conversations: "Conversations",
1441
+ newChat: "New chat",
1442
+ untitled: "New chat",
1443
+ deleteConversation: (title) => `Delete conversation ${title}`,
1444
+ assistant: "Assistant",
1445
+ thinking: "Thinking\u2026",
1446
+ steps: (count) => count === 1 ? "1 step" : `${count} steps`,
1447
+ responseFailed: "Response failed",
1448
+ answerFailedTitle: "The answer could not be completed",
1449
+ uploadFailedTitle: "The upload failed",
1450
+ placeholder: "Ask about your documents",
1451
+ composerAriaLabel: "Message the assistant",
1452
+ documentsInChat: (selected, total) => `${selected} of ${total} documents in this chat`,
1453
+ documentsHeading: "Documents in this chat",
1454
+ selectAllDocuments: "Select all",
1455
+ noDocuments: "No documents yet",
1456
+ uploadDocuments: "Upload documents",
1457
+ uploading: "Uploading\u2026",
1458
+ emptyTitle: "Ask about your documents",
1459
+ emptyDescription: "Every answer is grounded in the selected documents and cites its sources.",
1460
+ emptyUploadTitle: "Add a document to start",
1461
+ emptyUploadDescription: "Upload the documents you want to ask about.",
1462
+ workflows: "Workflows",
1463
+ loadingDocuments: "Loading documents\u2026"
1464
+ };
1465
+ var USER_BUBBLE = "bg-[color:hsl(var(--chat-user-bubble,var(--muted)))] text-[color:hsl(var(--chat-user-bubble-foreground,var(--foreground)))]";
1466
+ var NEAR_BOTTOM_PX = 96;
1467
+ function MessageRow({ message, identity, renderContent, labels }) {
1468
+ if (message.role === "user") {
1469
+ return /* @__PURE__ */ jsxRuntime.jsx(Message.Root, { role: "user", messageId: message.id, children: /* @__PURE__ */ jsxRuntime.jsx(Message.Content, { role: "user", messageId: message.id, children: /* @__PURE__ */ jsxRuntime.jsx(
1470
+ Message.Bubble,
1471
+ {
1472
+ role: "user",
1473
+ messageId: message.id,
1474
+ className: USER_BUBBLE,
1475
+ testId: "chat-message-user",
1476
+ children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-0 whitespace-pre-wrap break-words text-base leading-relaxed", children: message.content })
1477
+ }
1478
+ ) }) });
1479
+ }
1480
+ const isStreaming = message.status === "streaming";
1481
+ const isFailed = message.status === "error";
1482
+ const hasText = message.content.trim() !== "";
1483
+ return /* @__PURE__ */ jsxRuntime.jsx(Message.Root, { role: "assistant", messageId: message.id, tone: isFailed ? "error" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Message.Content, { role: "assistant", messageId: message.id, children: /* @__PURE__ */ jsxRuntime.jsxs(Message.Bubble, { role: "assistant", messageId: message.id, testId: "chat-message-assistant", children: [
1484
+ /* @__PURE__ */ jsxRuntime.jsx(
1485
+ Message.Byline,
1486
+ {
1487
+ messageId: message.id,
1488
+ identity: identity ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: labels.assistant }),
1489
+ timeLabel: message.stepCount ? labels.steps(message.stepCount) : "",
1490
+ isSettled: !isStreaming,
1491
+ isFailed,
1492
+ statusLabel: isFailed ? labels.responseFailed : ""
1493
+ }
1494
+ ),
1495
+ hasText && (renderContent?.(message) ?? /* @__PURE__ */ jsxRuntime.jsx(ui.MarkdownRenderer, { isStreaming, children: message.content })),
1496
+ isStreaming && !hasText && /* @__PURE__ */ jsxRuntime.jsxs(
1497
+ "span",
1498
+ {
1499
+ className: "flex items-center gap-2 text-muted-foreground",
1500
+ "data-testid": "chat-streaming",
1501
+ children: [
1502
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin motion-reduce:animate-none", "aria-hidden": true }),
1503
+ labels.thinking
1504
+ ]
1505
+ }
1506
+ )
1507
+ ] }) }) });
1508
+ }
1509
+ function ChatPage({
1510
+ chat,
1511
+ surface = "page",
1512
+ header,
1513
+ headerActions,
1514
+ aside,
1515
+ prompts = [],
1516
+ emptyTitle,
1517
+ emptyDescription,
1518
+ identity,
1519
+ renderContent,
1520
+ accept,
1521
+ labels,
1522
+ className,
1523
+ testIds
1524
+ }) {
1525
+ const l = { ...DEFAULT_CHAT_PAGE_LABELS, ...labels };
1526
+ useRegisterEmbeddedChat(surface === "page");
1527
+ const [draft, setDraft] = react.useState("");
1528
+ const [isAsideOpen, setIsAsideOpen] = react.useState(false);
1529
+ const [isAway, setIsAway] = react.useState(false);
1530
+ const scrollRef = react.useRef(null);
1531
+ const fileRef = react.useRef(null);
1532
+ const textareaRef = react.useRef(null);
1533
+ const last = chat.messages[chat.messages.length - 1];
1534
+ const announcement = useStreamAnnouncement({
1535
+ isStreaming: chat.isRunning,
1536
+ text: last?.role === "assistant" ? last.content : "",
1537
+ resetKey: chat.activeThreadId
1538
+ });
1539
+ const scrollToEnd = react.useCallback(() => {
1540
+ const el = scrollRef.current;
1541
+ if (el) el.scrollTop = el.scrollHeight;
1542
+ }, []);
1543
+ react.useEffect(() => {
1544
+ if (!isAway) scrollToEnd();
1545
+ }, [chat.messages, isAway, scrollToEnd]);
1546
+ react.useEffect(() => {
1547
+ setIsAway(false);
1548
+ }, [chat.activeThreadId]);
1549
+ const onScroll = () => {
1550
+ const el = scrollRef.current;
1551
+ if (el) setIsAway(el.scrollHeight - el.scrollTop - el.clientHeight > NEAR_BOTTOM_PX);
1552
+ };
1553
+ const submit = (e) => {
1554
+ e?.preventDefault();
1555
+ const text = draft.trim();
1556
+ if (!text || chat.isRunning) return;
1557
+ setDraft("");
1558
+ setIsAway(false);
1559
+ void chat.send(text);
1560
+ };
1561
+ const pickFiles = () => fileRef.current?.click();
1562
+ const onFiles = (files) => {
1563
+ if (files.length > 0) void chat.upload(files);
1564
+ };
1565
+ const activeThread = chat.threads.find((t) => t.id === chat.activeThreadId);
1566
+ const hasDocuments = chat.documents.length > 0;
1567
+ const isEmpty = chat.messages.length === 0;
1568
+ const heading = header ?? /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "min-w-0 truncate text-sm font-semibold text-foreground", children: activeThread?.title || l.untitled });
1569
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1570
+ "section",
1571
+ {
1572
+ "aria-label": l.chat,
1573
+ "data-slot": "chat-page",
1574
+ "data-surface": surface,
1575
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "chat-page" }),
1576
+ className: ui.cn(
1577
+ "@container/chat flex h-full min-h-0 w-full overflow-hidden bg-background text-foreground",
1578
+ className
1579
+ ),
1580
+ children: [
1581
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden w-64 shrink-0 flex-col border-r border-border @3xl/chat:flex", children: /* @__PURE__ */ jsxRuntime.jsx(
1582
+ ChatThreadList,
1583
+ {
1584
+ threads: chat.threads,
1585
+ activeId: chat.activeThreadId,
1586
+ labels: l,
1587
+ onSelect: chat.selectThread,
1588
+ onNew: chat.newThread,
1589
+ onDelete: chat.deleteThread
1590
+ }
1591
+ ) }),
1592
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
1593
+ /* @__PURE__ */ jsxRuntime.jsxs(
1594
+ "div",
1595
+ {
1596
+ "data-slot": "chat-page-header",
1597
+ className: "flex min-h-12 shrink-0 items-center gap-2 border-b border-border px-3 py-1.5",
1598
+ children: [
1599
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
1600
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden min-w-0 flex-1 @3xl/chat:block", children: heading }),
1601
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2 @3xl/chat:hidden", children: [
1602
+ header ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 shrink", children: header }) : null,
1603
+ /* @__PURE__ */ jsxRuntime.jsx(
1604
+ ChatThreadSelect,
1605
+ {
1606
+ threads: chat.threads,
1607
+ activeId: chat.activeThreadId,
1608
+ labels: l,
1609
+ onSelect: chat.selectThread
1610
+ }
1611
+ ),
1612
+ /* @__PURE__ */ jsxRuntime.jsx(
1613
+ ui.Button,
1614
+ {
1615
+ type: "button",
1616
+ variant: "ghost",
1617
+ size: "icon",
1618
+ className: "size-9 shrink-0 pointer-coarse:size-11",
1619
+ "aria-label": l.newChat,
1620
+ onClick: chat.newThread,
1621
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquarePlus, { className: "size-4", "aria-hidden": "true" })
1622
+ }
1623
+ )
1624
+ ] })
1625
+ ] }),
1626
+ aside && /* @__PURE__ */ jsxRuntime.jsxs(
1627
+ ui.Button,
1628
+ {
1629
+ type: "button",
1630
+ variant: "outline",
1631
+ size: "sm",
1632
+ className: "shrink-0 gap-1.5 pointer-coarse:min-h-11 @6xl/chat:hidden",
1633
+ "aria-expanded": isAsideOpen,
1634
+ "aria-controls": "chat-page-aside-panel",
1635
+ onClick: () => setIsAsideOpen((v) => !v),
1636
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.asideToggle, { testId: "chat-aside-toggle" }),
1637
+ children: [
1638
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRight, { className: "size-4", "aria-hidden": "true" }),
1639
+ l.workflows
1640
+ ]
1641
+ }
1642
+ ),
1643
+ headerActions
1644
+ ]
1645
+ }
1646
+ ),
1647
+ aside && isAsideOpen && /* @__PURE__ */ jsxRuntime.jsx(
1648
+ "div",
1649
+ {
1650
+ id: "chat-page-aside-panel",
1651
+ "data-slot": "chat-page-aside-panel",
1652
+ className: "max-h-[45%] shrink-0 overflow-y-auto border-b border-border p-3 @6xl/chat:hidden",
1653
+ children: aside
1654
+ }
1655
+ ),
1656
+ /* @__PURE__ */ jsxRuntime.jsxs(
1657
+ MessageList.Root,
1658
+ {
1659
+ isBusy: chat.isRunning,
1660
+ testId: chunkMHVNT4J3_cjs.testIdOr(testIds?.transcript, { testId: "chat-messages" }),
1661
+ className: "relative flex min-h-0 flex-1 flex-col",
1662
+ children: [
1663
+ /* @__PURE__ */ jsxRuntime.jsx(MessageList.Status, { message: announcement }),
1664
+ /* @__PURE__ */ jsxRuntime.jsx(
1665
+ "div",
1666
+ {
1667
+ ref: scrollRef,
1668
+ onScroll,
1669
+ "data-slot": "chat-page-scroll",
1670
+ className: "relative min-h-0 flex-1 overflow-y-auto overscroll-contain",
1671
+ children: isEmpty ? chat.isLoadingDocuments ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-sm text-muted-foreground", children: l.loadingDocuments }) : /* @__PURE__ */ jsxRuntime.jsx(
1672
+ ConversationEmpty,
1673
+ {
1674
+ hasDocuments,
1675
+ prompts,
1676
+ onUsePrompt: (text) => {
1677
+ setDraft(text);
1678
+ textareaRef.current?.focus();
1679
+ },
1680
+ onAddDocuments: (files) => files ? onFiles(files) : pickFiles(),
1681
+ title: emptyTitle ?? l.emptyTitle,
1682
+ description: emptyDescription ?? l.emptyDescription,
1683
+ className: "pb-6",
1684
+ noDocuments: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1685
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
1686
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold", children: l.emptyUploadTitle }),
1687
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: l.emptyUploadDescription })
1688
+ ] }),
1689
+ /* @__PURE__ */ jsxRuntime.jsxs(
1690
+ ui.Button,
1691
+ {
1692
+ type: "button",
1693
+ className: "gap-2 pointer-coarse:min-h-11",
1694
+ onClick: pickFiles,
1695
+ disabled: chat.isUploading,
1696
+ children: [
1697
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "size-4", "aria-hidden": "true" }),
1698
+ chat.isUploading ? l.uploading : l.uploadDocuments
1699
+ ]
1700
+ }
1701
+ )
1702
+ ] })
1703
+ }
1704
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1705
+ "div",
1706
+ {
1707
+ role: "list",
1708
+ "aria-label": "Conversation messages",
1709
+ className: "mx-auto flex w-full max-w-3xl flex-col gap-5 px-3 py-5 @lg/chat:px-6",
1710
+ children: chat.messages.map((message) => /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listitem", "data-message-id": message.id, children: /* @__PURE__ */ jsxRuntime.jsx(
1711
+ MessageRow,
1712
+ {
1713
+ message,
1714
+ identity,
1715
+ renderContent,
1716
+ labels: l
1717
+ }
1718
+ ) }, message.id))
1719
+ }
1720
+ )
1721
+ }
1722
+ ),
1723
+ /* @__PURE__ */ jsxRuntime.jsx(
1724
+ ScrollToBottom,
1725
+ {
1726
+ className: "bottom-3 top-auto",
1727
+ show: isAway && !isEmpty,
1728
+ onClick: () => {
1729
+ setIsAway(false);
1730
+ scrollToEnd();
1731
+ }
1732
+ }
1733
+ )
1734
+ ]
1735
+ }
1736
+ ),
1737
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-t border-border/60 bg-background px-3 pb-3 pt-2 @lg/chat:px-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto w-full max-w-3xl", children: [
1738
+ chat.error && /* @__PURE__ */ jsxRuntime.jsx(
1739
+ MessageAlert,
1740
+ {
1741
+ title: l.answerFailedTitle,
1742
+ description: chat.error,
1743
+ isBusy: chat.isRunning,
1744
+ onActivate: () => void chat.retry(),
1745
+ testId: chunkMHVNT4J3_cjs.testIdOr(testIds?.alert, { testId: "chat-alert" })
1746
+ }
1747
+ ),
1748
+ chat.uploadError && /* @__PURE__ */ jsxRuntime.jsx(
1749
+ MessageAlert,
1750
+ {
1751
+ title: l.uploadFailedTitle,
1752
+ description: chat.uploadError,
1753
+ testId: "chat-upload-alert"
1754
+ }
1755
+ ),
1756
+ /* @__PURE__ */ jsxRuntime.jsx(Composer.Root, { onSubmit: submit, testId: "chat-composer", children: /* @__PURE__ */ jsxRuntime.jsxs(Composer.Frame, { className: "px-3 py-2 shadow-sm", children: [
1757
+ /* @__PURE__ */ jsxRuntime.jsx(
1758
+ Composer.Input,
1759
+ {
1760
+ value: draft,
1761
+ onValueChange: setDraft,
1762
+ placeholder: l.placeholder,
1763
+ ariaLabel: l.composerAriaLabel,
1764
+ textareaRef,
1765
+ testId: chunkMHVNT4J3_cjs.testIdOr(testIds?.input, { testId: "chat-input" })
1766
+ }
1767
+ ),
1768
+ /* @__PURE__ */ jsxRuntime.jsx(
1769
+ Composer.Toolbar,
1770
+ {
1771
+ leading: /* @__PURE__ */ jsxRuntime.jsx(
1772
+ ChatDocuments,
1773
+ {
1774
+ chat,
1775
+ labels: l,
1776
+ onPickFiles: pickFiles,
1777
+ testIds: { documents: testIds?.documents, upload: testIds?.upload }
1778
+ }
1779
+ ),
1780
+ trailing: /* @__PURE__ */ jsxRuntime.jsx(
1781
+ Composer.Send,
1782
+ {
1783
+ onSend: () => submit(),
1784
+ disabled: chat.isRunning || draft.trim() === "",
1785
+ testIds: { send: chunkMHVNT4J3_cjs.testIdOr(testIds?.send, { testId: "chat-send" }) }
1786
+ }
1787
+ )
1788
+ }
1789
+ )
1790
+ ] }) })
1791
+ ] }) })
1792
+ ] }),
1793
+ aside && /* @__PURE__ */ jsxRuntime.jsx(
1794
+ "aside",
1795
+ {
1796
+ "aria-label": l.workflows,
1797
+ "data-slot": "chat-page-aside",
1798
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.aside, { testId: "chat-aside" }),
1799
+ className: "hidden w-80 shrink-0 overflow-y-auto border-l border-border p-4 @6xl/chat:block",
1800
+ children: aside
1801
+ }
1802
+ ),
1803
+ /* @__PURE__ */ jsxRuntime.jsx(
1804
+ "input",
1805
+ {
1806
+ ref: fileRef,
1807
+ type: "file",
1808
+ multiple: true,
1809
+ accept,
1810
+ className: "sr-only",
1811
+ tabIndex: -1,
1812
+ "aria-hidden": "true",
1813
+ "data-testid": "chat-file-input",
1814
+ onChange: (e) => {
1815
+ onFiles(Array.from(e.target.files ?? []));
1816
+ e.target.value = "";
1817
+ }
1818
+ }
1819
+ )
1820
+ ]
1821
+ }
1822
+ );
1823
+ }
1824
+ var isOpen = false;
1825
+ var listeners2 = /* @__PURE__ */ new Set();
1826
+ var subscribe2 = (l) => {
1827
+ listeners2.add(l);
1828
+ return () => listeners2.delete(l);
1829
+ };
1830
+ function set(next) {
1831
+ if (next === isOpen) return;
1832
+ isOpen = next;
1833
+ listeners2.forEach((l) => l());
1834
+ }
1835
+ function useAssistantDock() {
1836
+ const open = react.useSyncExternalStore(
1837
+ subscribe2,
1838
+ () => isOpen,
1839
+ () => false
1840
+ );
1841
+ return { isOpen: open, setOpen: set, toggle: () => set(!isOpen) };
1842
+ }
1843
+ function AssistantDockToggle({
1844
+ label = "Assistant chat",
1845
+ testId = "chat-dock-toggle"
1846
+ }) {
1847
+ const { isDockAvailable } = useChatSurface();
1848
+ const dock = useAssistantDock();
1849
+ if (!isDockAvailable) return null;
1850
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkKHX2BX3S_cjs.ToolButton, { onClick: dock.toggle, label, active: dock.isOpen, "data-testid": testId, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "size-4", "aria-hidden": "true" }) });
1851
+ }
1852
+ function AssistantDock({
1853
+ chat,
1854
+ isMobile = false,
1855
+ width = 380,
1856
+ label = "Assistant chat",
1857
+ closeLabel = "Close chat",
1858
+ headerActions,
1859
+ ...pageProps
1860
+ }) {
1861
+ const { isDockAvailable } = useChatSurface();
1862
+ const dock = useAssistantDock();
1863
+ if (!isDockAvailable) return null;
1864
+ return /* @__PURE__ */ jsxRuntime.jsx(
1865
+ chunkKHX2BX3S_cjs.Shell.Dock,
1866
+ {
1867
+ isOpen: dock.isOpen,
1868
+ onOpenChange: dock.setOpen,
1869
+ isMobile,
1870
+ width,
1871
+ label,
1872
+ closeLabel,
1873
+ "data-testid": "chat-dock",
1874
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1875
+ ChatPage,
1876
+ {
1877
+ ...pageProps,
1878
+ chat,
1879
+ surface: "dock",
1880
+ className: "min-h-0 flex-1",
1881
+ headerActions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1882
+ headerActions,
1883
+ !isMobile && /* @__PURE__ */ jsxRuntime.jsx(
1884
+ chunkKHX2BX3S_cjs.ToolButton,
1885
+ {
1886
+ onClick: () => dock.setOpen(false),
1887
+ label: closeLabel,
1888
+ "data-testid": "chat-close",
1889
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4", "aria-hidden": "true" })
1890
+ }
1891
+ )
1892
+ ] })
1893
+ }
1894
+ )
1895
+ }
1896
+ );
1897
+ }
1898
+
1899
+ exports.AssistantDock = AssistantDock;
1900
+ exports.AssistantDockToggle = AssistantDockToggle;
1901
+ exports.ChatDocuments = ChatDocuments;
1902
+ exports.ChatPage = ChatPage;
1903
+ exports.ChatThreadList = ChatThreadList;
1904
+ exports.ChatThreadSelect = ChatThreadSelect;
1905
+ exports.Composer = Composer;
1906
+ exports.ComposerBranchingNotice = ComposerBranchingNotice;
1907
+ exports.ComposerContainer = ComposerContainer;
1908
+ exports.ComposerDock = ComposerDock;
1909
+ exports.ComposerFrame = ComposerFrame;
1910
+ exports.ComposerInput = ComposerInput;
1911
+ exports.ComposerRoot = ComposerRoot;
1912
+ exports.ComposerSend = ComposerSend;
1913
+ exports.ComposerToolbar = ComposerToolbar;
1914
+ exports.ComposerVoiceButton = ComposerVoiceButton;
1915
+ exports.ContextChip = ContextChip;
1916
+ exports.ConversationEmpty = ConversationEmpty;
1917
+ exports.DEFAULT_CHAT_PAGE_LABELS = DEFAULT_CHAT_PAGE_LABELS;
1918
+ exports.DEFAULT_COMPOSER_LABELS = DEFAULT_COMPOSER_LABELS;
1919
+ exports.DEFAULT_CONVERSATION_EMPTY_LABELS = DEFAULT_CONVERSATION_EMPTY_LABELS;
1920
+ exports.DEFAULT_MESSAGE_ALERT_LABELS = DEFAULT_MESSAGE_ALERT_LABELS;
1921
+ exports.DEFAULT_MESSAGE_LABELS = DEFAULT_MESSAGE_LABELS;
1922
+ exports.DEFAULT_MESSAGE_LIST_LABELS = DEFAULT_MESSAGE_LIST_LABELS;
1923
+ exports.Message = Message;
1924
+ exports.MessageActionButton = MessageActionButton;
1925
+ exports.MessageActionMenu = MessageActionMenu;
1926
+ exports.MessageAlert = MessageAlert;
1927
+ exports.MessageBody = MessageBody;
1928
+ exports.MessageBubble = MessageBubble;
1929
+ exports.MessageByline = MessageByline;
1930
+ exports.MessageContent = MessageContent;
1931
+ exports.MessageFooter = MessageFooter;
1932
+ exports.MessageList = MessageList;
1933
+ exports.MessageListBanner = MessageListBanner;
1934
+ exports.MessageListEmpty = MessageListEmpty;
1935
+ exports.MessageListRoot = MessageListRoot;
1936
+ exports.MessageListRow = MessageListRow;
1937
+ exports.MessageListRows = MessageListRows;
1938
+ exports.MessageListStatus = MessageListStatus;
1939
+ exports.MessageListTail = MessageListTail;
1940
+ exports.MessageNarration = MessageNarration;
1941
+ exports.MessageRoot = MessageRoot;
1942
+ exports.MessageSources = MessageSources;
1943
+ exports.MessageSubagentBadge = MessageSubagentBadge;
1944
+ exports.ScrollToBottom = ScrollToBottom;
1945
+ exports.SourceChip = SourceChip;
1946
+ exports.toSpeakableText = toSpeakableText;
1947
+ exports.useAssistantDock = useAssistantDock;
1948
+ exports.useChatSurface = useChatSurface;
1949
+ exports.useRegisterEmbeddedChat = useRegisterEmbeddedChat;
1950
+ exports.useStreamAnnouncement = useStreamAnnouncement;
1951
+ //# sourceMappingURL=chunk-ATXPAD6S.cjs.map
1952
+ //# sourceMappingURL=chunk-ATXPAD6S.cjs.map