@surf-kit/agent 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +19 -1
  2. package/dist/agent-BNSmiexZ.d.cts +44 -0
  3. package/dist/agent-BNSmiexZ.d.ts +44 -0
  4. package/dist/agent-identity/index.cjs +157 -0
  5. package/dist/agent-identity/index.cjs.map +1 -0
  6. package/dist/agent-identity/index.d.cts +35 -0
  7. package/dist/agent-identity/index.d.ts +35 -0
  8. package/dist/agent-identity/index.js +127 -0
  9. package/dist/agent-identity/index.js.map +1 -0
  10. package/dist/chat/index.cjs +1281 -0
  11. package/dist/chat/index.cjs.map +1 -0
  12. package/dist/chat/index.d.cts +72 -0
  13. package/dist/chat/index.d.ts +72 -0
  14. package/dist/chat/index.js +1239 -0
  15. package/dist/chat/index.js.map +1 -0
  16. package/dist/chat--OifhIRe.d.ts +24 -0
  17. package/dist/chat-ChYl2XjV.d.cts +24 -0
  18. package/dist/confidence/index.cjs +253 -0
  19. package/dist/confidence/index.cjs.map +1 -0
  20. package/dist/confidence/index.d.cts +40 -0
  21. package/dist/confidence/index.d.ts +40 -0
  22. package/dist/confidence/index.js +222 -0
  23. package/dist/confidence/index.js.map +1 -0
  24. package/dist/feedback/index.cjs +186 -0
  25. package/dist/feedback/index.cjs.map +1 -0
  26. package/dist/feedback/index.d.cts +27 -0
  27. package/dist/feedback/index.d.ts +27 -0
  28. package/dist/feedback/index.js +157 -0
  29. package/dist/feedback/index.js.map +1 -0
  30. package/dist/{hooks-B8CSeOsn.d.cts → hooks-BGs8-4GK.d.ts} +4 -99
  31. package/dist/{hooks-B8CSeOsn.d.ts → hooks-DLfF18IU.d.cts} +4 -99
  32. package/dist/hooks.d.cts +4 -1
  33. package/dist/hooks.d.ts +4 -1
  34. package/dist/index-BazLnae1.d.cts +67 -0
  35. package/dist/index-BazLnae1.d.ts +67 -0
  36. package/dist/index.cjs +889 -144
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +15 -321
  39. package/dist/index.d.ts +15 -321
  40. package/dist/index.js +879 -142
  41. package/dist/index.js.map +1 -1
  42. package/dist/layouts/index.cjs +1588 -0
  43. package/dist/layouts/index.cjs.map +1 -0
  44. package/dist/layouts/index.d.cts +46 -0
  45. package/dist/layouts/index.d.ts +46 -0
  46. package/dist/layouts/index.js +1548 -0
  47. package/dist/layouts/index.js.map +1 -0
  48. package/dist/mcp/index.cjs +522 -0
  49. package/dist/mcp/index.cjs.map +1 -0
  50. package/dist/mcp/index.d.cts +2 -0
  51. package/dist/mcp/index.d.ts +2 -0
  52. package/dist/mcp/index.js +492 -0
  53. package/dist/mcp/index.js.map +1 -0
  54. package/dist/response/index.cjs +519 -0
  55. package/dist/response/index.cjs.map +1 -0
  56. package/dist/response/index.d.cts +44 -0
  57. package/dist/response/index.d.ts +44 -0
  58. package/dist/response/index.js +478 -0
  59. package/dist/response/index.js.map +1 -0
  60. package/dist/sources/index.cjs +243 -0
  61. package/dist/sources/index.cjs.map +1 -0
  62. package/dist/sources/index.d.cts +44 -0
  63. package/dist/sources/index.d.ts +44 -0
  64. package/dist/sources/index.js +212 -0
  65. package/dist/sources/index.js.map +1 -0
  66. package/dist/streaming/index.cjs +531 -0
  67. package/dist/streaming/index.cjs.map +1 -0
  68. package/dist/streaming/index.d.cts +81 -0
  69. package/dist/streaming/index.d.ts +81 -0
  70. package/dist/streaming/index.js +495 -0
  71. package/dist/streaming/index.js.map +1 -0
  72. package/dist/streaming-DbQxScpi.d.ts +39 -0
  73. package/dist/streaming-DfT22A0z.d.cts +39 -0
  74. package/package.json +62 -17
@@ -0,0 +1,1548 @@
1
+ // src/layouts/AgentFullPage/AgentFullPage.tsx
2
+ import { twMerge as twMerge10 } from "tailwind-merge";
3
+ import { useState as useState4, useCallback as useCallback3 } from "react";
4
+
5
+ // src/chat/AgentChat/AgentChat.tsx
6
+ import { twMerge as twMerge8 } from "tailwind-merge";
7
+
8
+ // src/hooks/useAgentChat.ts
9
+ import { useReducer, useCallback, useRef } from "react";
10
+ var initialState = {
11
+ messages: [],
12
+ conversationId: null,
13
+ isLoading: false,
14
+ error: null,
15
+ inputValue: "",
16
+ streamPhase: "idle",
17
+ streamingContent: ""
18
+ };
19
+ function reducer(state, action) {
20
+ switch (action.type) {
21
+ case "SET_INPUT":
22
+ return { ...state, inputValue: action.value };
23
+ case "SEND_START":
24
+ return {
25
+ ...state,
26
+ messages: [...state.messages, action.message],
27
+ isLoading: true,
28
+ error: null,
29
+ inputValue: "",
30
+ streamPhase: "thinking",
31
+ streamingContent: ""
32
+ };
33
+ case "STREAM_PHASE":
34
+ return { ...state, streamPhase: action.phase };
35
+ case "STREAM_CONTENT":
36
+ return { ...state, streamingContent: state.streamingContent + action.content };
37
+ case "SEND_SUCCESS":
38
+ return {
39
+ ...state,
40
+ messages: [...state.messages, action.message],
41
+ conversationId: action.conversationId ?? state.conversationId,
42
+ isLoading: false,
43
+ streamPhase: "idle",
44
+ streamingContent: ""
45
+ };
46
+ case "SEND_ERROR":
47
+ return {
48
+ ...state,
49
+ isLoading: false,
50
+ error: action.error,
51
+ streamPhase: "idle",
52
+ streamingContent: ""
53
+ };
54
+ case "LOAD_CONVERSATION":
55
+ return {
56
+ ...state,
57
+ conversationId: action.conversationId,
58
+ messages: action.messages,
59
+ error: null
60
+ };
61
+ case "RESET":
62
+ return { ...initialState };
63
+ case "CLEAR_ERROR":
64
+ return { ...state, error: null };
65
+ default:
66
+ return state;
67
+ }
68
+ }
69
+ var msgIdCounter = 0;
70
+ function generateMessageId() {
71
+ return `msg-${Date.now()}-${++msgIdCounter}`;
72
+ }
73
+ function useAgentChat(config) {
74
+ const [state, dispatch] = useReducer(reducer, initialState);
75
+ const configRef = useRef(config);
76
+ configRef.current = config;
77
+ const lastUserMessageRef = useRef(null);
78
+ const sendMessage = useCallback(
79
+ async (content) => {
80
+ const { apiUrl, streamPath = "/chat/stream", headers = {}, timeout = 3e4 } = configRef.current;
81
+ lastUserMessageRef.current = content;
82
+ const userMessage = {
83
+ id: generateMessageId(),
84
+ role: "user",
85
+ content,
86
+ timestamp: /* @__PURE__ */ new Date()
87
+ };
88
+ dispatch({ type: "SEND_START", message: userMessage });
89
+ const controller = new AbortController();
90
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
91
+ try {
92
+ const response = await fetch(`${apiUrl}${streamPath}`, {
93
+ method: "POST",
94
+ headers: {
95
+ "Content-Type": "application/json",
96
+ Accept: "text/event-stream",
97
+ ...headers
98
+ },
99
+ body: JSON.stringify({
100
+ message: content,
101
+ conversation_id: state.conversationId
102
+ }),
103
+ signal: controller.signal
104
+ });
105
+ clearTimeout(timeoutId);
106
+ if (!response.ok) {
107
+ dispatch({
108
+ type: "SEND_ERROR",
109
+ error: {
110
+ code: "API_ERROR",
111
+ message: `HTTP ${response.status}: ${response.statusText}`,
112
+ retryable: response.status >= 500
113
+ }
114
+ });
115
+ return;
116
+ }
117
+ const reader = response.body?.getReader();
118
+ if (!reader) {
119
+ dispatch({
120
+ type: "SEND_ERROR",
121
+ error: { code: "STREAM_ERROR", message: "No response body", retryable: true }
122
+ });
123
+ return;
124
+ }
125
+ const decoder = new TextDecoder();
126
+ let buffer = "";
127
+ let accumulatedContent = "";
128
+ let agentResponse = null;
129
+ let capturedAgent = null;
130
+ let capturedConversationId = null;
131
+ while (true) {
132
+ const { done, value } = await reader.read();
133
+ if (done) break;
134
+ buffer += decoder.decode(value, { stream: true });
135
+ const lines = buffer.split("\n");
136
+ buffer = lines.pop() ?? "";
137
+ for (const line of lines) {
138
+ if (!line.startsWith("data: ")) continue;
139
+ const data = line.slice(6).trim();
140
+ if (data === "[DONE]") continue;
141
+ try {
142
+ const event = JSON.parse(data);
143
+ switch (event.type) {
144
+ case "agent":
145
+ capturedAgent = event.agent;
146
+ break;
147
+ case "phase":
148
+ dispatch({ type: "STREAM_PHASE", phase: event.phase });
149
+ break;
150
+ case "delta":
151
+ accumulatedContent += event.content;
152
+ dispatch({ type: "STREAM_CONTENT", content: event.content });
153
+ break;
154
+ case "done":
155
+ agentResponse = event.response;
156
+ capturedConversationId = event.conversation_id ?? null;
157
+ break;
158
+ case "error":
159
+ dispatch({ type: "SEND_ERROR", error: event.error });
160
+ return;
161
+ }
162
+ } catch {
163
+ }
164
+ }
165
+ }
166
+ const assistantMessage = {
167
+ id: generateMessageId(),
168
+ role: "assistant",
169
+ content: agentResponse?.message ?? accumulatedContent,
170
+ response: agentResponse ?? void 0,
171
+ agent: capturedAgent ?? void 0,
172
+ timestamp: /* @__PURE__ */ new Date()
173
+ };
174
+ dispatch({
175
+ type: "SEND_SUCCESS",
176
+ message: assistantMessage,
177
+ streamingContent: accumulatedContent,
178
+ conversationId: capturedConversationId
179
+ });
180
+ } catch (err) {
181
+ clearTimeout(timeoutId);
182
+ if (err.name === "AbortError") {
183
+ dispatch({
184
+ type: "SEND_ERROR",
185
+ error: { code: "TIMEOUT", message: "Request timed out", retryable: true }
186
+ });
187
+ } else {
188
+ dispatch({
189
+ type: "SEND_ERROR",
190
+ error: {
191
+ code: "NETWORK_ERROR",
192
+ message: err.message ?? "Network error",
193
+ retryable: true
194
+ }
195
+ });
196
+ }
197
+ }
198
+ },
199
+ [state.conversationId]
200
+ );
201
+ const setInputValue = useCallback((value) => {
202
+ dispatch({ type: "SET_INPUT", value });
203
+ }, []);
204
+ const loadConversation = useCallback((conversationId, messages) => {
205
+ dispatch({ type: "LOAD_CONVERSATION", conversationId, messages });
206
+ }, []);
207
+ const submitFeedback = useCallback(
208
+ async (messageId, rating, comment) => {
209
+ const { apiUrl, feedbackPath = "/feedback", headers = {} } = configRef.current;
210
+ await fetch(`${apiUrl}${feedbackPath}`, {
211
+ method: "POST",
212
+ headers: { "Content-Type": "application/json", ...headers },
213
+ body: JSON.stringify({ messageId, rating, comment })
214
+ });
215
+ },
216
+ []
217
+ );
218
+ const retry = useCallback(async () => {
219
+ if (lastUserMessageRef.current) {
220
+ await sendMessage(lastUserMessageRef.current);
221
+ }
222
+ }, [sendMessage]);
223
+ const reset = useCallback(() => {
224
+ dispatch({ type: "RESET" });
225
+ lastUserMessageRef.current = null;
226
+ }, []);
227
+ const actions = {
228
+ sendMessage,
229
+ setInputValue,
230
+ loadConversation,
231
+ submitFeedback,
232
+ retry,
233
+ reset
234
+ };
235
+ return { state, actions };
236
+ }
237
+
238
+ // src/chat/MessageThread/MessageThread.tsx
239
+ import { twMerge as twMerge5 } from "tailwind-merge";
240
+ import { useEffect, useRef as useRef2 } from "react";
241
+
242
+ // src/chat/MessageBubble/MessageBubble.tsx
243
+ import { twMerge as twMerge4 } from "tailwind-merge";
244
+
245
+ // src/response/AgentResponse/AgentResponse.tsx
246
+ import { Badge as Badge2 } from "@surf-kit/core";
247
+
248
+ // src/response/ResponseMessage/ResponseMessage.tsx
249
+ import ReactMarkdown from "react-markdown";
250
+ import rehypeSanitize from "rehype-sanitize";
251
+ import { twMerge } from "tailwind-merge";
252
+ import { jsx } from "react/jsx-runtime";
253
+ function normalizeMarkdownLists(content) {
254
+ return content.replace(/:\s+-\s+/g, ":\n\n- ");
255
+ }
256
+ function ResponseMessage({ content, className }) {
257
+ return /* @__PURE__ */ jsx(
258
+ "div",
259
+ {
260
+ className: twMerge(
261
+ "text-sm leading-relaxed text-text-primary",
262
+ "[&_p]:my-2",
263
+ "[&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-6",
264
+ "[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-6",
265
+ "[&_li]:my-1",
266
+ "[&_strong]:text-text-primary [&_strong]:font-semibold",
267
+ "[&_em]:text-text-secondary",
268
+ "[&_h1]:text-lg [&_h1]:font-semibold [&_h1]:text-text-primary [&_h1]:mt-4 [&_h1]:mb-2",
269
+ "[&_h2]:text-base [&_h2]:font-semibold [&_h2]:text-text-primary [&_h2]:mt-3 [&_h2]:mb-1.5",
270
+ "[&_h3]:text-sm [&_h3]:font-semibold [&_h3]:text-accent [&_h3]:mt-2 [&_h3]:mb-1",
271
+ "[&_code]:bg-surface-raised [&_code]:text-accent [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono",
272
+ "[&_pre]:bg-surface-raised [&_pre]:border [&_pre]:border-border [&_pre]:rounded-xl [&_pre]:p-4 [&_pre]:overflow-x-auto",
273
+ "[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-4 [&_blockquote]:text-text-secondary",
274
+ "[&_a]:text-accent [&_a]:underline-offset-2 [&_a]:hover:text-accent/80",
275
+ className
276
+ ),
277
+ "data-testid": "response-message",
278
+ children: /* @__PURE__ */ jsx(
279
+ ReactMarkdown,
280
+ {
281
+ rehypePlugins: [rehypeSanitize],
282
+ components: {
283
+ script: () => null,
284
+ iframe: () => null,
285
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "my-2", children }),
286
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "my-2 list-disc pl-6", children }),
287
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "my-2 list-decimal pl-6", children }),
288
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "my-1", children }),
289
+ strong: ({ children }) => /* @__PURE__ */ jsx("strong", { className: "font-semibold", children }),
290
+ h1: ({ children }) => /* @__PURE__ */ jsx("h1", { className: "text-base font-bold mt-4 mb-2", children }),
291
+ h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "text-sm font-bold mt-3 mb-1", children }),
292
+ h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold mt-2 mb-1", children }),
293
+ code: ({ children }) => /* @__PURE__ */ jsx("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children })
294
+ },
295
+ children: normalizeMarkdownLists(content)
296
+ }
297
+ )
298
+ }
299
+ );
300
+ }
301
+
302
+ // src/response/StructuredResponse/StructuredResponse.tsx
303
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
304
+ function tryParse(value) {
305
+ if (value === void 0 || value === null) return null;
306
+ if (typeof value === "string") {
307
+ try {
308
+ return JSON.parse(value);
309
+ } catch {
310
+ return null;
311
+ }
312
+ }
313
+ return value;
314
+ }
315
+ function renderSteps(data) {
316
+ const steps = tryParse(data.steps);
317
+ if (!steps || !Array.isArray(steps)) return null;
318
+ return /* @__PURE__ */ jsx2("ol", { className: "flex flex-col gap-2", "data-testid": "structured-steps", children: steps.map((step, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3", children: [
319
+ /* @__PURE__ */ jsx2(
320
+ "span",
321
+ {
322
+ className: "mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-accent text-[11px] font-semibold text-white",
323
+ "aria-hidden": "true",
324
+ children: i + 1
325
+ }
326
+ ),
327
+ /* @__PURE__ */ jsx2("span", { className: "text-sm text-text-primary leading-relaxed", children: step })
328
+ ] }, i)) });
329
+ }
330
+ function renderTable(data) {
331
+ const columns = tryParse(data.columns);
332
+ const rawRows = tryParse(data.rows);
333
+ if (columns && rawRows && Array.isArray(columns) && Array.isArray(rawRows)) {
334
+ return /* @__PURE__ */ jsx2("div", { className: "overflow-x-auto rounded-lg border border-border", "data-testid": "structured-table", children: /* @__PURE__ */ jsxs("table", { role: "table", className: "w-full border-collapse text-sm", children: [
335
+ /* @__PURE__ */ jsx2("thead", { className: "bg-surface-raised", children: /* @__PURE__ */ jsx2("tr", { children: columns.map((col) => /* @__PURE__ */ jsx2(
336
+ "th",
337
+ {
338
+ className: "text-left px-4 py-2.5 font-semibold text-text-primary border-b border-border",
339
+ children: col
340
+ },
341
+ col
342
+ )) }) }),
343
+ /* @__PURE__ */ jsx2("tbody", { children: rawRows.map((row, i) => {
344
+ const cells = Array.isArray(row) ? row : columns.map((col) => row[col]);
345
+ return /* @__PURE__ */ jsx2("tr", { className: "even:bg-surface-raised/40", children: cells.map((cell, j) => /* @__PURE__ */ jsx2("td", { className: "px-4 py-2 text-text-secondary border-b border-border", children: String(cell ?? "") }, j)) }, i);
346
+ }) })
347
+ ] }) });
348
+ }
349
+ const entries = Object.entries(data);
350
+ return /* @__PURE__ */ jsx2("div", { className: "overflow-x-auto rounded-lg border border-border", "data-testid": "structured-table", children: /* @__PURE__ */ jsx2("table", { role: "table", className: "w-full border-collapse text-sm", children: /* @__PURE__ */ jsx2("tbody", { children: entries.map(([key, value]) => /* @__PURE__ */ jsxs("tr", { className: "even:bg-surface-raised/40", children: [
351
+ /* @__PURE__ */ jsx2("td", { className: "px-4 py-2 text-text-primary font-medium border-b border-border w-1/3", children: key }),
352
+ /* @__PURE__ */ jsx2("td", { className: "px-4 py-2 text-text-secondary border-b border-border", children: typeof value === "object" ? JSON.stringify(value) : String(value ?? "") })
353
+ ] }, key)) }) }) });
354
+ }
355
+ function renderCard(data) {
356
+ const title = typeof data.title === "string" ? data.title : null;
357
+ const body = typeof data.body === "string" ? data.body : null;
358
+ const link = typeof data.link === "string" ? data.link : null;
359
+ const linkLabel = typeof data.link_label === "string" ? data.link_label : "Learn more";
360
+ return /* @__PURE__ */ jsxs(
361
+ "div",
362
+ {
363
+ className: "rounded-xl border border-border bg-surface-raised p-4 flex flex-col gap-2",
364
+ "data-testid": "structured-card",
365
+ children: [
366
+ title && /* @__PURE__ */ jsx2("p", { className: "text-sm font-semibold text-text-primary", children: title }),
367
+ body && /* @__PURE__ */ jsx2("p", { className: "text-sm text-text-secondary leading-relaxed", children: body }),
368
+ link && /* @__PURE__ */ jsxs(
369
+ "a",
370
+ {
371
+ href: link,
372
+ target: "_blank",
373
+ rel: "noopener noreferrer",
374
+ className: "mt-1 inline-flex items-center gap-1 text-xs font-medium text-accent hover:text-accent/80 underline-offset-2 hover:underline transition-colors",
375
+ children: [
376
+ linkLabel,
377
+ /* @__PURE__ */ jsx2("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
378
+ ]
379
+ }
380
+ )
381
+ ]
382
+ }
383
+ );
384
+ }
385
+ function renderList(data) {
386
+ const items = tryParse(data.items);
387
+ const title = typeof data.title === "string" ? data.title : null;
388
+ if (!items || !Array.isArray(items)) return null;
389
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", "data-testid": "structured-list", children: [
390
+ title && /* @__PURE__ */ jsx2("p", { className: "text-xs font-semibold uppercase tracking-wider text-text-secondary mb-1", children: title }),
391
+ /* @__PURE__ */ jsx2("ul", { className: "flex flex-col gap-1.5", children: items.map((item, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2.5", children: [
392
+ /* @__PURE__ */ jsx2("span", { className: "mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-accent", "aria-hidden": "true" }),
393
+ /* @__PURE__ */ jsx2("span", { className: "text-sm text-text-primary leading-relaxed", children: item })
394
+ ] }, i)) })
395
+ ] });
396
+ }
397
+ function renderWarning(data) {
398
+ const severity = typeof data.severity === "string" ? data.severity : "medium";
399
+ const action = typeof data.action === "string" ? data.action : null;
400
+ const details = typeof data.details === "string" ? data.details : null;
401
+ const isHigh = severity === "high";
402
+ return /* @__PURE__ */ jsxs(
403
+ "div",
404
+ {
405
+ role: "alert",
406
+ className: `rounded-xl border p-4 flex gap-3 ${isHigh ? "border-red-200 bg-red-50 dark:border-red-900/50 dark:bg-red-950/30" : "border-amber-200 bg-amber-50 dark:border-amber-900/50 dark:bg-amber-950/30"}`,
407
+ "data-testid": "structured-warning",
408
+ children: [
409
+ /* @__PURE__ */ jsx2(
410
+ "svg",
411
+ {
412
+ className: `mt-0.5 h-5 w-5 shrink-0 ${isHigh ? "text-red-500" : "text-amber-500"}`,
413
+ fill: "none",
414
+ viewBox: "0 0 24 24",
415
+ stroke: "currentColor",
416
+ strokeWidth: 2,
417
+ children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" })
418
+ }
419
+ ),
420
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
421
+ action && /* @__PURE__ */ jsx2("p", { className: `text-sm font-semibold ${isHigh ? "text-red-700 dark:text-red-300" : "text-amber-700 dark:text-amber-300"}`, children: action }),
422
+ details && /* @__PURE__ */ jsx2("p", { className: `text-sm ${isHigh ? "text-red-600 dark:text-red-400" : "text-amber-600 dark:text-amber-400"}`, children: details })
423
+ ] })
424
+ ]
425
+ }
426
+ );
427
+ }
428
+ function StructuredResponse({ uiHint, data, className }) {
429
+ if (!data) return null;
430
+ let content;
431
+ switch (uiHint) {
432
+ case "steps":
433
+ content = renderSteps(data);
434
+ break;
435
+ case "table":
436
+ content = renderTable(data);
437
+ break;
438
+ case "card":
439
+ content = renderCard(data);
440
+ break;
441
+ case "list":
442
+ content = renderList(data);
443
+ break;
444
+ case "warning":
445
+ content = renderWarning(data);
446
+ break;
447
+ case "text":
448
+ content = typeof data.text === "string" ? /* @__PURE__ */ jsx2("p", { "data-testid": "structured-text", children: data.text }) : null;
449
+ break;
450
+ default:
451
+ content = null;
452
+ }
453
+ if (!content) return null;
454
+ return /* @__PURE__ */ jsx2("div", { className, "data-testid": "structured-response", children: content });
455
+ }
456
+
457
+ // src/sources/SourceList/SourceList.tsx
458
+ import { useState } from "react";
459
+
460
+ // src/sources/SourceCard/SourceCard.tsx
461
+ import { Badge } from "@surf-kit/core";
462
+ import { twMerge as twMerge2 } from "tailwind-merge";
463
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
464
+ function getConfidenceIntent(confidence) {
465
+ if (confidence >= 0.8) return "success";
466
+ if (confidence >= 0.5) return "warning";
467
+ return "error";
468
+ }
469
+ function getConfidenceLabel(confidence) {
470
+ if (confidence >= 0.8) return "High";
471
+ if (confidence >= 0.5) return "Medium";
472
+ return "Low";
473
+ }
474
+ function SourceCard({ source, variant = "compact", onNavigate, className }) {
475
+ const handleClick = () => {
476
+ if (onNavigate) {
477
+ onNavigate(source);
478
+ }
479
+ };
480
+ const isCompact = variant === "compact";
481
+ return /* @__PURE__ */ jsx3(
482
+ "div",
483
+ {
484
+ className: twMerge2(
485
+ "rounded-xl border transition-all duration-200",
486
+ "bg-surface border-border",
487
+ onNavigate && "cursor-pointer hover:border-border-strong",
488
+ className
489
+ ),
490
+ "data-document-id": source.document_id,
491
+ "data-testid": "source-card",
492
+ children: /* @__PURE__ */ jsxs2(
493
+ "div",
494
+ {
495
+ className: isCompact ? "px-4 py-3" : "px-6 py-4",
496
+ onClick: handleClick,
497
+ role: onNavigate ? "button" : void 0,
498
+ tabIndex: onNavigate ? 0 : void 0,
499
+ onKeyDown: onNavigate ? (e) => {
500
+ if (e.key === "Enter" || e.key === " ") {
501
+ e.preventDefault();
502
+ handleClick();
503
+ }
504
+ } : void 0,
505
+ children: [
506
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-2", children: [
507
+ /* @__PURE__ */ jsxs2("div", { className: "flex-1 min-w-0", children: [
508
+ /* @__PURE__ */ jsx3("p", { className: "text-sm font-medium text-text-primary truncate", children: source.title }),
509
+ source.section && /* @__PURE__ */ jsx3("p", { className: "text-[11px] font-semibold uppercase tracking-wider text-text-secondary truncate mt-0.5", children: source.section })
510
+ ] }),
511
+ /* @__PURE__ */ jsx3(
512
+ Badge,
513
+ {
514
+ intent: getConfidenceIntent(source.confidence),
515
+ size: "sm",
516
+ children: getConfidenceLabel(source.confidence)
517
+ }
518
+ )
519
+ ] }),
520
+ !isCompact && /* @__PURE__ */ jsx3("p", { className: "text-xs text-text-secondary mt-2 line-clamp-3 leading-relaxed", children: source.snippet })
521
+ ]
522
+ }
523
+ )
524
+ }
525
+ );
526
+ }
527
+
528
+ // src/sources/SourceList/SourceList.tsx
529
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
530
+ function SourceList({
531
+ sources,
532
+ variant = "compact",
533
+ collapsible = false,
534
+ defaultExpanded = true,
535
+ onNavigate,
536
+ className
537
+ }) {
538
+ const [isExpanded, setIsExpanded] = useState(defaultExpanded);
539
+ if (sources.length === 0) return null;
540
+ const content = /* @__PURE__ */ jsx4("div", { className: "flex flex-col gap-1.5", "data-testid": "source-list-items", children: sources.map((source) => /* @__PURE__ */ jsx4(
541
+ SourceCard,
542
+ {
543
+ source,
544
+ variant,
545
+ onNavigate
546
+ },
547
+ source.document_id
548
+ )) });
549
+ if (!collapsible) {
550
+ return /* @__PURE__ */ jsx4("div", { className, "data-testid": "source-list", children: content });
551
+ }
552
+ return /* @__PURE__ */ jsxs3("div", { className, "data-testid": "source-list", children: [
553
+ /* @__PURE__ */ jsxs3(
554
+ "button",
555
+ {
556
+ type: "button",
557
+ onClick: () => setIsExpanded((prev) => !prev),
558
+ "aria-expanded": isExpanded,
559
+ className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-secondary hover:text-accent mb-2 transition-colors duration-200",
560
+ children: [
561
+ /* @__PURE__ */ jsx4(
562
+ "svg",
563
+ {
564
+ className: `w-4 h-4 transition-transform ${isExpanded ? "rotate-180" : ""}`,
565
+ fill: "none",
566
+ viewBox: "0 0 24 24",
567
+ stroke: "currentColor",
568
+ strokeWidth: 2,
569
+ children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
570
+ }
571
+ ),
572
+ "Sources (",
573
+ sources.length,
574
+ ")"
575
+ ]
576
+ }
577
+ ),
578
+ isExpanded && content
579
+ ] });
580
+ }
581
+
582
+ // src/response/FollowUpChips/FollowUpChips.tsx
583
+ import { twMerge as twMerge3 } from "tailwind-merge";
584
+ import { jsx as jsx5 } from "react/jsx-runtime";
585
+ function FollowUpChips({ suggestions, onSelect, className }) {
586
+ if (suggestions.length === 0) return null;
587
+ return /* @__PURE__ */ jsx5(
588
+ "div",
589
+ {
590
+ className: twMerge3("flex flex-wrap gap-2 py-1", className),
591
+ role: "group",
592
+ "aria-label": "Follow-up suggestions",
593
+ "data-testid": "follow-up-chips",
594
+ children: suggestions.map((suggestion) => /* @__PURE__ */ jsx5(
595
+ "button",
596
+ {
597
+ type: "button",
598
+ onClick: () => onSelect(suggestion),
599
+ className: twMerge3(
600
+ "px-4 py-1.5 rounded-full text-sm whitespace-nowrap",
601
+ "border border-border bg-transparent text-text-secondary",
602
+ "hover:bg-accent/10 hover:border-interactive hover:text-text-primary",
603
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
604
+ "transition-all duration-200"
605
+ ),
606
+ children: suggestion
607
+ },
608
+ suggestion
609
+ ))
610
+ }
611
+ );
612
+ }
613
+
614
+ // src/response/AgentResponse/AgentResponse.tsx
615
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
616
+ function getConfidenceIntent2(overall) {
617
+ if (overall === "high") return "success";
618
+ if (overall === "medium") return "warning";
619
+ return "error";
620
+ }
621
+ function getVerificationIntent(status) {
622
+ if (status === "passed") return "success";
623
+ if (status === "flagged") return "warning";
624
+ return "error";
625
+ }
626
+ function getVerificationLabel(status) {
627
+ if (status === "passed") return "Verified";
628
+ if (status === "flagged") return "Flagged";
629
+ return "Failed";
630
+ }
631
+ function AgentResponse({
632
+ response,
633
+ showSources = true,
634
+ showConfidence = false,
635
+ showVerification = false,
636
+ onFollowUp,
637
+ onNavigateSource,
638
+ className
639
+ }) {
640
+ return /* @__PURE__ */ jsxs4("div", { className: `flex flex-col gap-4 ${className ?? ""}`, "data-testid": "agent-response", children: [
641
+ /* @__PURE__ */ jsx6(ResponseMessage, { content: response.message }),
642
+ response.ui_hint !== "text" && response.structured_data && /* @__PURE__ */ jsx6(
643
+ StructuredResponse,
644
+ {
645
+ uiHint: response.ui_hint,
646
+ data: response.structured_data
647
+ }
648
+ ),
649
+ (showConfidence || showVerification) && /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-2 mt-1", "data-testid": "response-meta", children: [
650
+ showConfidence && /* @__PURE__ */ jsxs4(
651
+ Badge2,
652
+ {
653
+ intent: getConfidenceIntent2(response.confidence.overall),
654
+ size: "sm",
655
+ children: [
656
+ response.confidence.overall,
657
+ " confidence"
658
+ ]
659
+ }
660
+ ),
661
+ showVerification && /* @__PURE__ */ jsxs4(
662
+ Badge2,
663
+ {
664
+ intent: getVerificationIntent(response.verification.status),
665
+ size: "sm",
666
+ children: [
667
+ getVerificationLabel(response.verification.status),
668
+ " (",
669
+ response.verification.claims_verified,
670
+ "/",
671
+ response.verification.claims_checked,
672
+ ")"
673
+ ]
674
+ }
675
+ )
676
+ ] }),
677
+ showSources && response.sources.length > 0 && /* @__PURE__ */ jsx6(
678
+ SourceList,
679
+ {
680
+ sources: response.sources,
681
+ variant: "compact",
682
+ collapsible: true,
683
+ defaultExpanded: false,
684
+ onNavigate: onNavigateSource
685
+ }
686
+ ),
687
+ response.follow_up_suggestions.length > 0 && onFollowUp && /* @__PURE__ */ jsx6(
688
+ FollowUpChips,
689
+ {
690
+ suggestions: response.follow_up_suggestions,
691
+ onSelect: onFollowUp
692
+ }
693
+ )
694
+ ] });
695
+ }
696
+
697
+ // src/chat/MessageBubble/MessageBubble.tsx
698
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
699
+ function MessageBubble({
700
+ message,
701
+ showAgent,
702
+ showSources = true,
703
+ showConfidence = true,
704
+ showVerification = true,
705
+ animated = true,
706
+ className
707
+ }) {
708
+ const isUser = message.role === "user";
709
+ if (isUser) {
710
+ return /* @__PURE__ */ jsx7(
711
+ "div",
712
+ {
713
+ "data-message-id": message.id,
714
+ className: twMerge4("flex w-full justify-end", className),
715
+ children: /* @__PURE__ */ jsx7(
716
+ "div",
717
+ {
718
+ className: twMerge4(
719
+ "max-w-[70%] rounded-[18px] rounded-br-[4px] px-4 py-2.5 bg-accent text-brand-cream break-words whitespace-pre-wrap text-sm leading-relaxed",
720
+ animated && "motion-safe:animate-slideFromRight"
721
+ ),
722
+ children: message.content
723
+ }
724
+ )
725
+ }
726
+ );
727
+ }
728
+ return /* @__PURE__ */ jsxs5(
729
+ "div",
730
+ {
731
+ "data-message-id": message.id,
732
+ className: twMerge4("flex w-full flex-col items-start gap-1.5", className),
733
+ children: [
734
+ showAgent && message.agent && /* @__PURE__ */ jsx7("div", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-text-muted px-1", children: message.agent.replace("_agent", "").replace("_", " ") }),
735
+ /* @__PURE__ */ jsx7(
736
+ "div",
737
+ {
738
+ className: twMerge4(
739
+ "max-w-[88%] rounded-[18px] rounded-tl-[4px] px-4 py-3 bg-surface border border-border",
740
+ animated && "motion-safe:animate-springFromLeft"
741
+ ),
742
+ children: message.response ? /* @__PURE__ */ jsx7(
743
+ AgentResponse,
744
+ {
745
+ response: message.response,
746
+ showSources,
747
+ showConfidence,
748
+ showVerification
749
+ }
750
+ ) : /* @__PURE__ */ jsx7(ResponseMessage, { content: message.content })
751
+ }
752
+ )
753
+ ]
754
+ }
755
+ );
756
+ }
757
+
758
+ // src/chat/MessageThread/MessageThread.tsx
759
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
760
+ function MessageThread({ messages, streamingSlot, showSources, showConfidence, showVerification, className }) {
761
+ const bottomRef = useRef2(null);
762
+ useEffect(() => {
763
+ bottomRef.current?.scrollIntoView?.({ behavior: "smooth" });
764
+ }, [messages.length, streamingSlot]);
765
+ return /* @__PURE__ */ jsxs6(
766
+ "div",
767
+ {
768
+ role: "log",
769
+ "aria-live": "polite",
770
+ "aria-label": "Message thread",
771
+ className: twMerge5(
772
+ "flex flex-col gap-4 overflow-y-auto flex-1 px-4 py-6",
773
+ className
774
+ ),
775
+ children: [
776
+ messages.map((message) => /* @__PURE__ */ jsx8(
777
+ MessageBubble,
778
+ {
779
+ message,
780
+ showSources,
781
+ showConfidence,
782
+ showVerification
783
+ },
784
+ message.id
785
+ )),
786
+ streamingSlot,
787
+ /* @__PURE__ */ jsx8("div", { ref: bottomRef })
788
+ ]
789
+ }
790
+ );
791
+ }
792
+
793
+ // src/chat/MessageComposer/MessageComposer.tsx
794
+ import { twMerge as twMerge6 } from "tailwind-merge";
795
+ import { useState as useState2, useRef as useRef3, useCallback as useCallback2 } from "react";
796
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
797
+ function MessageComposer({
798
+ onSend,
799
+ isLoading = false,
800
+ placeholder = "Type a message...",
801
+ className
802
+ }) {
803
+ const [value, setValue] = useState2("");
804
+ const textareaRef = useRef3(null);
805
+ const canSend = value.trim().length > 0 && !isLoading;
806
+ const resetHeight = useCallback2(() => {
807
+ const el = textareaRef.current;
808
+ if (el) {
809
+ el.style.height = "auto";
810
+ el.style.overflowY = "hidden";
811
+ }
812
+ }, []);
813
+ const handleSend = useCallback2(() => {
814
+ if (!canSend) return;
815
+ onSend(value.trim());
816
+ setValue("");
817
+ resetHeight();
818
+ textareaRef.current?.focus();
819
+ }, [canSend, onSend, value, resetHeight]);
820
+ const handleKeyDown = useCallback2(
821
+ (e) => {
822
+ if (e.key === "Enter" && !e.shiftKey) {
823
+ e.preventDefault();
824
+ handleSend();
825
+ }
826
+ },
827
+ [handleSend]
828
+ );
829
+ const handleChange = useCallback2(
830
+ (e) => {
831
+ setValue(e.target.value);
832
+ const el = e.target;
833
+ el.style.height = "auto";
834
+ const capped = Math.min(el.scrollHeight, 128);
835
+ el.style.height = `${capped}px`;
836
+ el.style.overflowY = el.scrollHeight > 128 ? "auto" : "hidden";
837
+ },
838
+ []
839
+ );
840
+ return /* @__PURE__ */ jsxs7(
841
+ "div",
842
+ {
843
+ className: twMerge6(
844
+ "flex items-end gap-3 shrink-0 border-t border-border px-4 py-3",
845
+ className
846
+ ),
847
+ children: [
848
+ /* @__PURE__ */ jsx9(
849
+ "textarea",
850
+ {
851
+ ref: textareaRef,
852
+ value,
853
+ onChange: handleChange,
854
+ onKeyDown: handleKeyDown,
855
+ placeholder,
856
+ rows: 1,
857
+ disabled: isLoading,
858
+ className: twMerge6(
859
+ "flex-1 resize-none rounded-xl border border-border bg-surface/80",
860
+ "px-4 py-2.5 text-sm text-text-primary placeholder:text-text-muted",
861
+ "focus:border-transparent focus:ring-2 focus:ring-accent/40 focus:outline-none",
862
+ "disabled:opacity-50 disabled:cursor-not-allowed",
863
+ "overflow-hidden",
864
+ "transition-all duration-200"
865
+ ),
866
+ style: { colorScheme: "dark" },
867
+ "aria-label": "Message input"
868
+ }
869
+ ),
870
+ /* @__PURE__ */ jsx9(
871
+ "button",
872
+ {
873
+ type: "button",
874
+ onClick: handleSend,
875
+ disabled: !value.trim() || isLoading,
876
+ "aria-label": "Send message",
877
+ className: twMerge6(
878
+ "inline-flex items-center justify-center rounded-xl px-5 py-2.5",
879
+ "text-sm font-semibold text-white shrink-0",
880
+ "transition-all duration-200",
881
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
882
+ value.trim() && !isLoading ? "bg-accent hover:bg-accent-hover hover:scale-[1.02] hover:shadow-glow-cyan active:scale-[0.98]" : "bg-accent/30 text-text-muted cursor-not-allowed"
883
+ ),
884
+ children: "Send"
885
+ }
886
+ )
887
+ ]
888
+ }
889
+ );
890
+ }
891
+
892
+ // src/chat/WelcomeScreen/WelcomeScreen.tsx
893
+ import { twMerge as twMerge7 } from "tailwind-merge";
894
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
895
+ function WelcomeScreen({
896
+ title = "Welcome",
897
+ message = "How can I help you today?",
898
+ icon,
899
+ suggestedQuestions = [],
900
+ onQuestionSelect,
901
+ className
902
+ }) {
903
+ return /* @__PURE__ */ jsxs8(
904
+ "div",
905
+ {
906
+ className: twMerge7(
907
+ "flex flex-1 flex-col items-center justify-center gap-8 p-8 text-center motion-safe:animate-fadeUp",
908
+ className
909
+ ),
910
+ children: [
911
+ /* @__PURE__ */ jsx10(
912
+ "div",
913
+ {
914
+ className: "w-14 h-14 rounded-2xl bg-accent/10 border border-border flex items-center justify-center pulse-glow",
915
+ "aria-hidden": "true",
916
+ children: icon ?? /* @__PURE__ */ jsx10("span", { className: "text-2xl", children: "\u2726" })
917
+ }
918
+ ),
919
+ /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
920
+ title && /* @__PURE__ */ jsx10("h2", { className: "text-3xl font-bold text-text-primary", children: title }),
921
+ /* @__PURE__ */ jsx10("p", { className: "text-text-secondary text-base leading-relaxed max-w-md", children: message })
922
+ ] }),
923
+ suggestedQuestions.length > 0 && /* @__PURE__ */ jsx10(
924
+ "div",
925
+ {
926
+ className: "flex flex-wrap justify-center gap-2 max-w-md",
927
+ role: "group",
928
+ "aria-label": "Suggested questions",
929
+ children: suggestedQuestions.map((question) => /* @__PURE__ */ jsx10(
930
+ "button",
931
+ {
932
+ type: "button",
933
+ onClick: () => onQuestionSelect?.(question),
934
+ className: twMerge7(
935
+ "px-4 py-2 rounded-full text-sm",
936
+ "border border-border bg-transparent text-text-secondary",
937
+ "hover:bg-accent/10 hover:border-interactive hover:text-text-primary",
938
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
939
+ "transition-colors duration-200"
940
+ ),
941
+ children: question
942
+ },
943
+ question
944
+ ))
945
+ }
946
+ )
947
+ ]
948
+ }
949
+ );
950
+ }
951
+
952
+ // src/streaming/StreamingMessage/StreamingMessage.tsx
953
+ import { useEffect as useEffect3, useRef as useRef5 } from "react";
954
+ import { Spinner } from "@surf-kit/core";
955
+
956
+ // src/hooks/useCharacterDrain.ts
957
+ import { useState as useState3, useRef as useRef4, useEffect as useEffect2 } from "react";
958
+ function useCharacterDrain(target, msPerChar = 15) {
959
+ const [displayed, setDisplayed] = useState3("");
960
+ const indexRef = useRef4(0);
961
+ const lastTimeRef = useRef4(0);
962
+ const rafRef = useRef4(null);
963
+ const drainTargetRef = useRef4("");
964
+ const msPerCharRef = useRef4(msPerChar);
965
+ msPerCharRef.current = msPerChar;
966
+ if (target !== "") {
967
+ drainTargetRef.current = target;
968
+ }
969
+ const drainTarget = drainTargetRef.current;
970
+ const isDraining = displayed.length < drainTarget.length;
971
+ const tickRef = useRef4(() => {
972
+ });
973
+ tickRef.current = (now) => {
974
+ const currentTarget = drainTargetRef.current;
975
+ if (currentTarget === "") {
976
+ rafRef.current = null;
977
+ return;
978
+ }
979
+ if (lastTimeRef.current === 0) lastTimeRef.current = now;
980
+ const elapsed = now - lastTimeRef.current;
981
+ const charsToAdvance = Math.floor(elapsed / msPerCharRef.current);
982
+ if (charsToAdvance > 0 && indexRef.current < currentTarget.length) {
983
+ const nextIndex = Math.min(indexRef.current + charsToAdvance, currentTarget.length);
984
+ indexRef.current = nextIndex;
985
+ lastTimeRef.current = now;
986
+ setDisplayed(currentTarget.slice(0, nextIndex));
987
+ }
988
+ if (indexRef.current < currentTarget.length) {
989
+ rafRef.current = requestAnimationFrame((t) => tickRef.current(t));
990
+ } else {
991
+ rafRef.current = null;
992
+ }
993
+ };
994
+ useEffect2(() => {
995
+ if (drainTargetRef.current !== "" && indexRef.current < drainTargetRef.current.length && rafRef.current === null) {
996
+ rafRef.current = requestAnimationFrame((t) => tickRef.current(t));
997
+ }
998
+ }, [drainTarget]);
999
+ useEffect2(() => {
1000
+ if (target === "" && !isDraining && displayed !== "") {
1001
+ indexRef.current = 0;
1002
+ lastTimeRef.current = 0;
1003
+ drainTargetRef.current = "";
1004
+ setDisplayed("");
1005
+ }
1006
+ }, [target, isDraining, displayed]);
1007
+ useEffect2(() => {
1008
+ return () => {
1009
+ if (rafRef.current !== null) {
1010
+ cancelAnimationFrame(rafRef.current);
1011
+ rafRef.current = null;
1012
+ }
1013
+ };
1014
+ }, []);
1015
+ return { displayed, isDraining };
1016
+ }
1017
+
1018
+ // src/streaming/StreamingMessage/StreamingMessage.tsx
1019
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1020
+ var phaseLabels = {
1021
+ idle: "",
1022
+ waiting: "Waiting...",
1023
+ thinking: "Thinking...",
1024
+ retrieving: "Searching...",
1025
+ generating: "Writing...",
1026
+ verifying: "Verifying..."
1027
+ };
1028
+ function StreamingMessage({
1029
+ stream,
1030
+ onComplete,
1031
+ showPhases = true,
1032
+ className
1033
+ }) {
1034
+ const onCompleteRef = useRef5(onComplete);
1035
+ onCompleteRef.current = onComplete;
1036
+ const wasActiveRef = useRef5(stream.active);
1037
+ useEffect3(() => {
1038
+ if (wasActiveRef.current && !stream.active) {
1039
+ onCompleteRef.current?.();
1040
+ }
1041
+ wasActiveRef.current = stream.active;
1042
+ }, [stream.active]);
1043
+ const phaseLabel = phaseLabels[stream.phase];
1044
+ const { displayed: displayedContent } = useCharacterDrain(stream.content);
1045
+ return /* @__PURE__ */ jsxs9("div", { className, "data-testid": "streaming-message", children: [
1046
+ /* @__PURE__ */ jsxs9("div", { "aria-live": "assertive", className: "sr-only", children: [
1047
+ stream.active && stream.phase !== "idle" && "Response started",
1048
+ !stream.active && stream.content && "Response complete"
1049
+ ] }),
1050
+ /* @__PURE__ */ jsxs9("div", { className: "max-w-[88%] px-4 py-3 rounded-[18px] rounded-tl-[4px] bg-surface border border-border motion-safe:animate-springFromLeft", children: [
1051
+ showPhases && stream.active && stream.phase !== "idle" && /* @__PURE__ */ jsxs9(
1052
+ "div",
1053
+ {
1054
+ className: "flex items-center gap-2 mb-2 text-sm text-text-secondary",
1055
+ "data-testid": "phase-indicator",
1056
+ children: [
1057
+ /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx11(Spinner, { size: "sm" }) }),
1058
+ /* @__PURE__ */ jsx11("span", { children: phaseLabel })
1059
+ ]
1060
+ }
1061
+ ),
1062
+ /* @__PURE__ */ jsxs9("div", { className: "text-sm leading-relaxed text-text-primary whitespace-pre-wrap", children: [
1063
+ displayedContent,
1064
+ stream.active && /* @__PURE__ */ jsx11(
1065
+ "span",
1066
+ {
1067
+ className: "inline-block w-0.5 h-4 bg-accent align-text-bottom animate-pulse ml-0.5",
1068
+ "aria-hidden": "true",
1069
+ "data-testid": "streaming-cursor"
1070
+ }
1071
+ )
1072
+ ] })
1073
+ ] })
1074
+ ] });
1075
+ }
1076
+
1077
+ // src/chat/AgentChat/AgentChat.tsx
1078
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1079
+ function AgentChat({
1080
+ endpoint,
1081
+ title = "Chat",
1082
+ welcomeTitle,
1083
+ welcomeMessage = "How can I help you today?",
1084
+ suggestedQuestions = [],
1085
+ showHeader = true,
1086
+ showWelcomeTitle = true,
1087
+ showSources,
1088
+ showConfidence,
1089
+ showVerification,
1090
+ className
1091
+ }) {
1092
+ const { state, actions } = useAgentChat({ apiUrl: endpoint });
1093
+ const hasMessages = state.messages.length > 0;
1094
+ const handleSend = (content) => {
1095
+ void actions.sendMessage(content);
1096
+ };
1097
+ const handleQuestionSelect = (question) => {
1098
+ void actions.sendMessage(question);
1099
+ };
1100
+ return /* @__PURE__ */ jsxs10(
1101
+ "div",
1102
+ {
1103
+ className: twMerge8(
1104
+ "flex flex-col h-full bg-canvas border border-border rounded-xl overflow-hidden",
1105
+ className
1106
+ ),
1107
+ children: [
1108
+ showHeader && /* @__PURE__ */ jsx12("div", { className: "flex items-center justify-between border-b border-border px-4 py-3 bg-surface-raised shrink-0", children: /* @__PURE__ */ jsx12("h1", { className: "text-base font-semibold text-text-primary", children: title }) }),
1109
+ hasMessages ? /* @__PURE__ */ jsx12(
1110
+ MessageThread,
1111
+ {
1112
+ messages: state.messages,
1113
+ streamingSlot: state.isLoading ? /* @__PURE__ */ jsx12(
1114
+ StreamingMessage,
1115
+ {
1116
+ stream: {
1117
+ active: state.isLoading,
1118
+ phase: state.streamPhase,
1119
+ content: state.streamingContent,
1120
+ sources: [],
1121
+ agent: null,
1122
+ agentLabel: null
1123
+ }
1124
+ }
1125
+ ) : void 0,
1126
+ showSources,
1127
+ showConfidence,
1128
+ showVerification
1129
+ }
1130
+ ) : /* @__PURE__ */ jsx12(
1131
+ WelcomeScreen,
1132
+ {
1133
+ title: showWelcomeTitle ? welcomeTitle ?? title : "",
1134
+ message: welcomeMessage,
1135
+ suggestedQuestions,
1136
+ onQuestionSelect: handleQuestionSelect
1137
+ }
1138
+ ),
1139
+ /* @__PURE__ */ jsx12(MessageComposer, { onSend: handleSend, isLoading: state.isLoading })
1140
+ ]
1141
+ }
1142
+ );
1143
+ }
1144
+
1145
+ // src/chat/ConversationList/ConversationList.tsx
1146
+ import { twMerge as twMerge9 } from "tailwind-merge";
1147
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1148
+ function ConversationList({
1149
+ conversations,
1150
+ activeId,
1151
+ onSelect,
1152
+ onDelete,
1153
+ onNew,
1154
+ className
1155
+ }) {
1156
+ return /* @__PURE__ */ jsxs11(
1157
+ "nav",
1158
+ {
1159
+ "aria-label": "Conversation list",
1160
+ className: twMerge9("flex flex-col h-full bg-canvas", className),
1161
+ children: [
1162
+ onNew && /* @__PURE__ */ jsx13("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsx13(
1163
+ "button",
1164
+ {
1165
+ type: "button",
1166
+ onClick: onNew,
1167
+ className: "w-full px-4 py-2.5 rounded-xl text-sm font-semibold bg-accent text-white hover:bg-accent-hover transition-all duration-200",
1168
+ children: "New conversation"
1169
+ }
1170
+ ) }),
1171
+ /* @__PURE__ */ jsxs11("ul", { role: "list", className: "flex-1 overflow-y-auto", children: [
1172
+ conversations.map((conversation) => {
1173
+ const isActive = conversation.id === activeId;
1174
+ return /* @__PURE__ */ jsxs11(
1175
+ "li",
1176
+ {
1177
+ className: twMerge9(
1178
+ "flex items-start border-b border-border transition-colors duration-200",
1179
+ "hover:bg-surface",
1180
+ isActive && "bg-surface-raised border-l-2 border-l-accent"
1181
+ ),
1182
+ children: [
1183
+ /* @__PURE__ */ jsxs11(
1184
+ "button",
1185
+ {
1186
+ type: "button",
1187
+ onClick: () => onSelect(conversation.id),
1188
+ "aria-current": isActive ? "true" : void 0,
1189
+ className: "flex-1 min-w-0 text-left px-4 py-3",
1190
+ children: [
1191
+ /* @__PURE__ */ jsx13("div", { className: "text-sm font-medium text-brand-cream truncate", children: conversation.title }),
1192
+ /* @__PURE__ */ jsx13("div", { className: "text-xs text-brand-cream/40 truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
1193
+ ]
1194
+ }
1195
+ ),
1196
+ onDelete && /* @__PURE__ */ jsx13(
1197
+ "button",
1198
+ {
1199
+ type: "button",
1200
+ onClick: () => onDelete(conversation.id),
1201
+ "aria-label": `Delete ${conversation.title}`,
1202
+ className: "shrink-0 p-1.5 m-2 rounded-lg text-brand-cream/25 hover:text-brand-watermelon hover:bg-brand-watermelon/10 transition-colors duration-200",
1203
+ children: /* @__PURE__ */ jsxs11(
1204
+ "svg",
1205
+ {
1206
+ xmlns: "http://www.w3.org/2000/svg",
1207
+ width: "14",
1208
+ height: "14",
1209
+ viewBox: "0 0 24 24",
1210
+ fill: "none",
1211
+ stroke: "currentColor",
1212
+ strokeWidth: "2",
1213
+ strokeLinecap: "round",
1214
+ strokeLinejoin: "round",
1215
+ "aria-hidden": "true",
1216
+ children: [
1217
+ /* @__PURE__ */ jsx13("polyline", { points: "3 6 5 6 21 6" }),
1218
+ /* @__PURE__ */ jsx13("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
1219
+ ]
1220
+ }
1221
+ )
1222
+ }
1223
+ )
1224
+ ]
1225
+ },
1226
+ conversation.id
1227
+ );
1228
+ }),
1229
+ conversations.length === 0 && /* @__PURE__ */ jsx13("li", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ jsx13("span", { className: "text-sm text-brand-cream/30 font-body", children: "No conversations yet" }) })
1230
+ ] })
1231
+ ]
1232
+ }
1233
+ );
1234
+ }
1235
+
1236
+ // src/layouts/AgentFullPage/AgentFullPage.tsx
1237
+ import { Fragment, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1238
+ function AgentFullPage({
1239
+ endpoint,
1240
+ title = "Chat",
1241
+ showConversationList = false,
1242
+ conversations = [],
1243
+ activeConversationId,
1244
+ onConversationSelect,
1245
+ onConversationDelete,
1246
+ onNewConversation,
1247
+ className
1248
+ }) {
1249
+ const [sidebarOpen, setSidebarOpen] = useState4(false);
1250
+ const handleSelect = useCallback3(
1251
+ (id) => {
1252
+ onConversationSelect?.(id);
1253
+ setSidebarOpen(false);
1254
+ },
1255
+ [onConversationSelect]
1256
+ );
1257
+ return /* @__PURE__ */ jsxs12(
1258
+ "div",
1259
+ {
1260
+ className: twMerge10("flex h-screen w-full overflow-hidden bg-brand-dark", className),
1261
+ "data-testid": "agent-full-page",
1262
+ children: [
1263
+ showConversationList && /* @__PURE__ */ jsxs12(Fragment, { children: [
1264
+ sidebarOpen && /* @__PURE__ */ jsx14(
1265
+ "div",
1266
+ {
1267
+ className: "fixed inset-0 bg-brand-dark/80 backdrop-blur-sm z-30 md:hidden",
1268
+ onClick: () => setSidebarOpen(false),
1269
+ "data-testid": "sidebar-overlay"
1270
+ }
1271
+ ),
1272
+ /* @__PURE__ */ jsx14(
1273
+ "aside",
1274
+ {
1275
+ className: twMerge10(
1276
+ "bg-brand-dark border-r border-brand-gold/15 w-72 shrink-0 flex-col z-40",
1277
+ // Desktop: always visible
1278
+ "hidden md:flex",
1279
+ // Mobile: overlay when open
1280
+ sidebarOpen && "fixed inset-y-0 left-0 flex md:relative"
1281
+ ),
1282
+ "aria-label": "Conversations sidebar",
1283
+ children: /* @__PURE__ */ jsx14(
1284
+ ConversationList,
1285
+ {
1286
+ conversations,
1287
+ activeId: activeConversationId,
1288
+ onSelect: handleSelect,
1289
+ onDelete: onConversationDelete,
1290
+ onNew: onNewConversation
1291
+ }
1292
+ )
1293
+ }
1294
+ )
1295
+ ] }),
1296
+ /* @__PURE__ */ jsxs12("div", { className: "flex-1 flex flex-col min-w-0 bg-brand-dark", children: [
1297
+ showConversationList && /* @__PURE__ */ jsx14("div", { className: "md:hidden flex items-center border-b border-brand-gold/15 px-3 py-2 bg-brand-dark-panel/60 backdrop-blur-sm", children: /* @__PURE__ */ jsx14(
1298
+ "button",
1299
+ {
1300
+ type: "button",
1301
+ onClick: () => setSidebarOpen(true),
1302
+ "aria-label": "Open conversations sidebar",
1303
+ className: "p-2 rounded-xl text-brand-cream/60 hover:text-brand-cream hover:bg-brand-dark-panel transition-colors duration-200",
1304
+ children: /* @__PURE__ */ jsxs12(
1305
+ "svg",
1306
+ {
1307
+ xmlns: "http://www.w3.org/2000/svg",
1308
+ width: "20",
1309
+ height: "20",
1310
+ viewBox: "0 0 24 24",
1311
+ fill: "none",
1312
+ stroke: "currentColor",
1313
+ strokeWidth: "2",
1314
+ strokeLinecap: "round",
1315
+ strokeLinejoin: "round",
1316
+ "aria-hidden": "true",
1317
+ children: [
1318
+ /* @__PURE__ */ jsx14("line", { x1: "3", y1: "12", x2: "21", y2: "12" }),
1319
+ /* @__PURE__ */ jsx14("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
1320
+ /* @__PURE__ */ jsx14("line", { x1: "3", y1: "18", x2: "21", y2: "18" })
1321
+ ]
1322
+ }
1323
+ )
1324
+ }
1325
+ ) }),
1326
+ /* @__PURE__ */ jsx14(
1327
+ AgentChat,
1328
+ {
1329
+ endpoint,
1330
+ title,
1331
+ className: "flex-1 rounded-none border-0"
1332
+ }
1333
+ )
1334
+ ] })
1335
+ ]
1336
+ }
1337
+ );
1338
+ }
1339
+
1340
+ // src/layouts/AgentPanel/AgentPanel.tsx
1341
+ import { twMerge as twMerge11 } from "tailwind-merge";
1342
+ import { useRef as useRef6, useEffect as useEffect4 } from "react";
1343
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
1344
+ function AgentPanel({
1345
+ endpoint,
1346
+ isOpen,
1347
+ onClose,
1348
+ side = "right",
1349
+ width = 400,
1350
+ title = "Chat",
1351
+ className
1352
+ }) {
1353
+ const panelRef = useRef6(null);
1354
+ useEffect4(() => {
1355
+ if (!isOpen) return;
1356
+ const handleKeyDown = (e) => {
1357
+ if (e.key === "Escape") onClose();
1358
+ };
1359
+ document.addEventListener("keydown", handleKeyDown);
1360
+ return () => document.removeEventListener("keydown", handleKeyDown);
1361
+ }, [isOpen, onClose]);
1362
+ const widthStyle = typeof width === "number" ? `${width}px` : width;
1363
+ return /* @__PURE__ */ jsxs13(
1364
+ "div",
1365
+ {
1366
+ className: twMerge11("fixed inset-0 z-50", !isOpen && "pointer-events-none"),
1367
+ "aria-hidden": !isOpen,
1368
+ children: [
1369
+ /* @__PURE__ */ jsx15(
1370
+ "div",
1371
+ {
1372
+ className: twMerge11(
1373
+ "fixed inset-0 transition-opacity duration-300",
1374
+ isOpen ? "opacity-100 bg-brand-dark/70 backdrop-blur-sm pointer-events-auto" : "opacity-0 pointer-events-none"
1375
+ ),
1376
+ onClick: isOpen ? onClose : void 0,
1377
+ "data-testid": "panel-backdrop"
1378
+ }
1379
+ ),
1380
+ /* @__PURE__ */ jsxs13(
1381
+ "div",
1382
+ {
1383
+ ref: panelRef,
1384
+ role: "dialog",
1385
+ "aria-label": title,
1386
+ "aria-modal": isOpen ? "true" : void 0,
1387
+ style: { width: widthStyle, maxWidth: "100vw" },
1388
+ className: twMerge11(
1389
+ "fixed top-0 h-full flex flex-col z-50 bg-brand-dark shadow-card",
1390
+ "transition-transform duration-300 ease-in-out",
1391
+ side === "left" ? `left-0 border-r border-brand-gold/15 ${isOpen ? "translate-x-0" : "-translate-x-full"}` : `right-0 border-l border-brand-gold/15 ${isOpen ? "translate-x-0" : "translate-x-full"}`,
1392
+ className
1393
+ ),
1394
+ children: [
1395
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between border-b border-brand-gold/15 px-5 py-3.5 bg-brand-dark-panel/60 backdrop-blur-sm shrink-0", children: [
1396
+ /* @__PURE__ */ jsx15("h2", { className: "text-base font-display font-semibold text-brand-cream", children: title }),
1397
+ /* @__PURE__ */ jsx15(
1398
+ "button",
1399
+ {
1400
+ type: "button",
1401
+ onClick: onClose,
1402
+ "aria-label": "Close panel",
1403
+ className: "rounded-xl p-2 text-brand-cream/40 hover:text-brand-cream/80 hover:bg-brand-cream/5 transition-colors duration-200",
1404
+ children: /* @__PURE__ */ jsxs13("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1405
+ /* @__PURE__ */ jsx15("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1406
+ /* @__PURE__ */ jsx15("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1407
+ ] })
1408
+ }
1409
+ )
1410
+ ] }),
1411
+ /* @__PURE__ */ jsx15(
1412
+ AgentChat,
1413
+ {
1414
+ endpoint,
1415
+ title,
1416
+ showHeader: false,
1417
+ showWelcomeTitle: false,
1418
+ className: "flex-1 rounded-none border-0"
1419
+ }
1420
+ )
1421
+ ]
1422
+ }
1423
+ )
1424
+ ]
1425
+ }
1426
+ );
1427
+ }
1428
+
1429
+ // src/layouts/AgentWidget/AgentWidget.tsx
1430
+ import { twMerge as twMerge12 } from "tailwind-merge";
1431
+ import { useState as useState5, useCallback as useCallback4 } from "react";
1432
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
1433
+ function AgentWidget({
1434
+ endpoint,
1435
+ position = "bottom-right",
1436
+ triggerLabel = "Chat",
1437
+ title = "Chat",
1438
+ className
1439
+ }) {
1440
+ const [isOpen, setIsOpen] = useState5(false);
1441
+ const toggle = useCallback4(() => {
1442
+ setIsOpen((prev) => !prev);
1443
+ }, []);
1444
+ const positionClasses = position === "bottom-left" ? "left-4 bottom-4" : "right-4 bottom-4";
1445
+ const popoverPositionClasses = position === "bottom-left" ? "left-4 bottom-20" : "right-4 bottom-20";
1446
+ const popoverOrigin = position === "bottom-left" ? "origin-bottom-left" : "origin-bottom-right";
1447
+ return /* @__PURE__ */ jsxs14("div", { className, children: [
1448
+ /* @__PURE__ */ jsxs14(
1449
+ "div",
1450
+ {
1451
+ role: "dialog",
1452
+ "aria-label": title,
1453
+ "aria-hidden": !isOpen,
1454
+ className: twMerge12(
1455
+ "fixed z-50 flex flex-col",
1456
+ "w-[min(400px,calc(100vw-2rem))] h-[min(600px,calc(100vh-6rem))]",
1457
+ "rounded-2xl overflow-hidden border border-brand-gold/15",
1458
+ "bg-brand-dark/95 backdrop-blur-[12px] shadow-card",
1459
+ popoverPositionClasses,
1460
+ popoverOrigin,
1461
+ "transition-all duration-200 ease-out",
1462
+ isOpen ? "opacity-100 scale-100 pointer-events-auto translate-y-0" : "opacity-0 scale-95 pointer-events-none translate-y-2"
1463
+ ),
1464
+ children: [
1465
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between px-4 py-2.5 bg-brand-dark-panel/80 border-b border-brand-gold/15 shrink-0", children: [
1466
+ /* @__PURE__ */ jsx16("h2", { className: "text-sm font-display font-semibold text-brand-cream", children: title }),
1467
+ /* @__PURE__ */ jsx16(
1468
+ "button",
1469
+ {
1470
+ type: "button",
1471
+ onClick: () => setIsOpen(false),
1472
+ "aria-label": "Minimize chat",
1473
+ className: "rounded-lg p-1.5 text-brand-cream/40 hover:text-brand-cream/70 transition-colors duration-200",
1474
+ children: /* @__PURE__ */ jsxs14("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1475
+ /* @__PURE__ */ jsx16("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1476
+ /* @__PURE__ */ jsx16("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1477
+ ] })
1478
+ }
1479
+ )
1480
+ ] }),
1481
+ /* @__PURE__ */ jsx16(
1482
+ AgentChat,
1483
+ {
1484
+ endpoint,
1485
+ title,
1486
+ showHeader: false,
1487
+ showWelcomeTitle: false,
1488
+ className: "flex-1 rounded-none border-0 min-h-0"
1489
+ }
1490
+ )
1491
+ ]
1492
+ }
1493
+ ),
1494
+ /* @__PURE__ */ jsx16(
1495
+ "button",
1496
+ {
1497
+ type: "button",
1498
+ onClick: toggle,
1499
+ "aria-label": isOpen ? "Close chat" : triggerLabel,
1500
+ "aria-expanded": isOpen,
1501
+ className: twMerge12(
1502
+ "fixed z-50 flex items-center justify-center w-14 h-14 rounded-full",
1503
+ "bg-brand-blue text-brand-cream shadow-glow-cyan",
1504
+ "hover:bg-brand-cyan hover:shadow-glow-cyan hover:scale-105",
1505
+ "active:scale-95",
1506
+ "transition-all duration-200",
1507
+ positionClasses
1508
+ ),
1509
+ children: isOpen ? /* @__PURE__ */ jsxs14("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1510
+ /* @__PURE__ */ jsx16("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1511
+ /* @__PURE__ */ jsx16("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1512
+ ] }) : /* @__PURE__ */ jsx16("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx16("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })
1513
+ }
1514
+ )
1515
+ ] });
1516
+ }
1517
+
1518
+ // src/layouts/AgentEmbed/AgentEmbed.tsx
1519
+ import { twMerge as twMerge13 } from "tailwind-merge";
1520
+ import { jsx as jsx17 } from "react/jsx-runtime";
1521
+ function AgentEmbed({
1522
+ endpoint,
1523
+ title = "Chat",
1524
+ className
1525
+ }) {
1526
+ return /* @__PURE__ */ jsx17(
1527
+ "div",
1528
+ {
1529
+ className: twMerge13("w-full h-full min-h-0", className),
1530
+ "data-testid": "agent-embed",
1531
+ children: /* @__PURE__ */ jsx17(
1532
+ AgentChat,
1533
+ {
1534
+ endpoint,
1535
+ title,
1536
+ className: "h-full rounded-none border-0"
1537
+ }
1538
+ )
1539
+ }
1540
+ );
1541
+ }
1542
+ export {
1543
+ AgentEmbed,
1544
+ AgentFullPage,
1545
+ AgentPanel,
1546
+ AgentWidget
1547
+ };
1548
+ //# sourceMappingURL=index.js.map