@surf-kit/agent 0.2.2 → 0.4.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 (51) hide show
  1. package/dist/chat/index.cjs +733 -222
  2. package/dist/chat/index.cjs.map +1 -1
  3. package/dist/chat/index.d.cts +13 -7
  4. package/dist/chat/index.d.ts +13 -7
  5. package/dist/chat/index.js +715 -204
  6. package/dist/chat/index.js.map +1 -1
  7. package/dist/{chat-ChYl2XjV.d.cts → chat-BRY3xGg_.d.cts} +11 -2
  8. package/dist/{chat--OifhIRe.d.ts → chat-CcKc6OAR.d.ts} +11 -2
  9. package/dist/{hooks-BGs8-4GK.d.ts → hooks-BLeiVk-x.d.ts} +22 -5
  10. package/dist/{hooks-DLfF18IU.d.cts → hooks-CSGGLd7j.d.cts} +22 -5
  11. package/dist/hooks.cjs +160 -85
  12. package/dist/hooks.cjs.map +1 -1
  13. package/dist/hooks.d.cts +3 -3
  14. package/dist/hooks.d.ts +3 -3
  15. package/dist/hooks.js +160 -85
  16. package/dist/hooks.js.map +1 -1
  17. package/dist/index.cjs +794 -283
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +3 -3
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +758 -247
  22. package/dist/index.js.map +1 -1
  23. package/dist/layouts/index.cjs +754 -243
  24. package/dist/layouts/index.cjs.map +1 -1
  25. package/dist/layouts/index.d.cts +1 -1
  26. package/dist/layouts/index.d.ts +1 -1
  27. package/dist/layouts/index.js +733 -222
  28. package/dist/layouts/index.js.map +1 -1
  29. package/dist/mcp/index.cjs +1 -1
  30. package/dist/mcp/index.cjs.map +1 -1
  31. package/dist/mcp/index.js +2 -2
  32. package/dist/mcp/index.js.map +1 -1
  33. package/dist/response/index.cjs +100 -15
  34. package/dist/response/index.cjs.map +1 -1
  35. package/dist/response/index.d.cts +2 -2
  36. package/dist/response/index.d.ts +2 -2
  37. package/dist/response/index.js +99 -14
  38. package/dist/response/index.js.map +1 -1
  39. package/dist/sources/index.cjs +30 -1
  40. package/dist/sources/index.cjs.map +1 -1
  41. package/dist/sources/index.js +30 -1
  42. package/dist/sources/index.js.map +1 -1
  43. package/dist/streaming/index.cjs +213 -93
  44. package/dist/streaming/index.cjs.map +1 -1
  45. package/dist/streaming/index.d.cts +4 -3
  46. package/dist/streaming/index.d.ts +4 -3
  47. package/dist/streaming/index.js +183 -73
  48. package/dist/streaming/index.js.map +1 -1
  49. package/dist/{streaming-DfT22A0z.d.cts → streaming-BHPXnwwo.d.cts} +3 -1
  50. package/dist/{streaming-DbQxScpi.d.ts → streaming-C6mbU7My.d.ts} +3 -1
  51. package/package.json +17 -5
@@ -2,7 +2,8 @@
2
2
 
3
3
  // src/streaming/StreamingMessage/StreamingMessage.tsx
4
4
  import { useEffect as useEffect2, useRef as useRef2 } from "react";
5
- import { Spinner } from "@surf-kit/core";
5
+ import { twMerge as twMerge2 } from "tailwind-merge";
6
+ import { WaveLoader } from "@surf-kit/core";
6
7
 
7
8
  // src/hooks/useCharacterDrain.ts
8
9
  import { useState, useRef, useEffect } from "react";
@@ -31,7 +32,10 @@ function useCharacterDrain(target, msPerChar = 15) {
31
32
  const elapsed = now - lastTimeRef.current;
32
33
  const charsToAdvance = Math.floor(elapsed / msPerCharRef.current);
33
34
  if (charsToAdvance > 0 && indexRef.current < currentTarget.length) {
34
- const nextIndex = Math.min(indexRef.current + charsToAdvance, currentTarget.length);
35
+ let nextIndex = Math.min(indexRef.current + charsToAdvance, currentTarget.length);
36
+ while (nextIndex < currentTarget.length && currentTarget[nextIndex - 1].trim() === "") {
37
+ nextIndex++;
38
+ }
35
39
  indexRef.current = nextIndex;
36
40
  lastTimeRef.current = now;
37
41
  setDisplayed(currentTarget.slice(0, nextIndex));
@@ -66,8 +70,87 @@ function useCharacterDrain(target, msPerChar = 15) {
66
70
  return { displayed, isDraining };
67
71
  }
68
72
 
73
+ // src/response/ResponseMessage/ResponseMessage.tsx
74
+ import React from "react";
75
+ import ReactMarkdown from "react-markdown";
76
+ import rehypeSanitize from "rehype-sanitize";
77
+ import remarkGfm from "remark-gfm";
78
+ import { twMerge } from "tailwind-merge";
79
+ import { jsx } from "react/jsx-runtime";
80
+ function normalizeMarkdownLists(content) {
81
+ return content.replace(/:\s+-\s+/g, ":\n\n- ");
82
+ }
83
+ function ResponseMessage({ content, className }) {
84
+ return /* @__PURE__ */ jsx(
85
+ "div",
86
+ {
87
+ className: twMerge(
88
+ "text-sm leading-relaxed text-text-primary",
89
+ "[&_p]:my-2",
90
+ "[&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-6",
91
+ "[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-6",
92
+ "[&_li]:my-1",
93
+ "[&_strong]:text-text-primary [&_strong]:font-semibold",
94
+ "[&_em]:text-text-secondary",
95
+ "[&_h1]:text-lg [&_h1]:font-semibold [&_h1]:text-text-primary [&_h1]:mt-4 [&_h1]:mb-2",
96
+ "[&_h2]:text-base [&_h2]:font-semibold [&_h2]:text-text-primary [&_h2]:mt-3 [&_h2]:mb-1.5",
97
+ "[&_h3]:text-sm [&_h3]:font-semibold [&_h3]:text-accent [&_h3]:mt-2 [&_h3]:mb-1",
98
+ "[&_code]:bg-surface-raised [&_code]:text-accent [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono",
99
+ "[&_pre]:bg-surface-raised [&_pre]:border [&_pre]:border-border [&_pre]:rounded-xl [&_pre]:p-4 [&_pre]:overflow-x-auto",
100
+ "[&_hr]:my-3 [&_hr]:border-border",
101
+ "[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-4 [&_blockquote]:text-text-secondary",
102
+ "[&_table]:w-full [&_table]:text-sm [&_table]:border-collapse [&_table]:my-2",
103
+ "[&_thead]:border-b [&_thead]:border-border",
104
+ "[&_th]:text-left [&_th]:px-2 [&_th]:py-1.5 [&_th]:font-semibold",
105
+ "[&_td]:px-2 [&_td]:py-1.5 [&_td]:border-t [&_td]:border-border/50",
106
+ "[&_a]:text-accent [&_a]:underline-offset-2 [&_a]:hover:text-accent/80",
107
+ className
108
+ ),
109
+ "data-testid": "response-message",
110
+ children: /* @__PURE__ */ jsx(
111
+ ReactMarkdown,
112
+ {
113
+ remarkPlugins: [remarkGfm],
114
+ rehypePlugins: [rehypeSanitize],
115
+ components: {
116
+ script: () => null,
117
+ iframe: () => null,
118
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "my-2", children }),
119
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "my-2 list-disc pl-6", children }),
120
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "my-2 list-decimal pl-6", children }),
121
+ li: ({ children, ...props }) => {
122
+ let content2 = children;
123
+ if (props.ordered) {
124
+ content2 = React.Children.map(children, (child, i) => {
125
+ if (i === 0 && typeof child === "string") {
126
+ return child.replace(/^\d+[.)]\s*/, "");
127
+ }
128
+ return child;
129
+ });
130
+ }
131
+ return /* @__PURE__ */ jsx("li", { className: "my-1", children: content2 });
132
+ },
133
+ strong: ({ children }) => /* @__PURE__ */ jsx("strong", { className: "font-semibold", children }),
134
+ em: ({ children }) => /* @__PURE__ */ jsx("em", { className: "italic text-text-secondary", children }),
135
+ h1: ({ children }) => /* @__PURE__ */ jsx("h1", { className: "text-base font-bold mt-4 mb-2", children }),
136
+ h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "text-sm font-bold mt-3 mb-1", children }),
137
+ h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold mt-2 mb-1", children }),
138
+ hr: () => /* @__PURE__ */ jsx("hr", { className: "my-3 border-border" }),
139
+ code: ({ children }) => /* @__PURE__ */ jsx("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
140
+ table: ({ children }) => /* @__PURE__ */ jsx("div", { className: "overflow-x-auto my-2", children: /* @__PURE__ */ jsx("table", { className: "w-full text-sm border-collapse", children }) }),
141
+ thead: ({ children }) => /* @__PURE__ */ jsx("thead", { className: "border-b border-border", children }),
142
+ th: ({ children }) => /* @__PURE__ */ jsx("th", { className: "text-left px-2 py-1.5 font-semibold", children }),
143
+ td: ({ children }) => /* @__PURE__ */ jsx("td", { className: "px-2 py-1.5 border-t border-border/50", children })
144
+ },
145
+ children: normalizeMarkdownLists(content)
146
+ }
147
+ )
148
+ }
149
+ );
150
+ }
151
+
69
152
  // src/streaming/StreamingMessage/StreamingMessage.tsx
70
- import { jsx, jsxs } from "react/jsx-runtime";
153
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
71
154
  var phaseLabels = {
72
155
  idle: "",
73
156
  waiting: "Waiting...",
@@ -76,14 +159,36 @@ var phaseLabels = {
76
159
  generating: "Writing...",
77
160
  verifying: "Verifying..."
78
161
  };
162
+ var CURSOR_STYLES = `
163
+ .sk-streaming-cursor > :not(ul,ol,blockquote,div:has(table)):last-child::after,
164
+ .sk-streaming-cursor > :is(ul,ol):last-child > li:last-child::after,
165
+ .sk-streaming-cursor > blockquote:last-child > p:last-child::after,
166
+ .sk-streaming-cursor > div:has(table):last-child table tbody tr:last-child td:last-child::after {
167
+ content: "";
168
+ display: inline-block;
169
+ width: 2px;
170
+ height: 1em;
171
+ background: var(--color-accent, #38bdf8);
172
+ animation: sk-cursor-blink 0.8s steps(1) infinite;
173
+ margin-left: 2px;
174
+ vertical-align: text-bottom;
175
+ }
176
+ @keyframes sk-cursor-blink {
177
+ 0%, 60% { opacity: 1; }
178
+ 61%, 100% { opacity: 0; }
179
+ }
180
+ `;
79
181
  function StreamingMessage({
80
182
  stream,
81
183
  onComplete,
184
+ onDraining,
82
185
  showPhases = true,
83
186
  className
84
187
  }) {
85
188
  const onCompleteRef = useRef2(onComplete);
86
189
  onCompleteRef.current = onComplete;
190
+ const onDrainingRef = useRef2(onDraining);
191
+ onDrainingRef.current = onDraining;
87
192
  const wasActiveRef = useRef2(stream.active);
88
193
  useEffect2(() => {
89
194
  if (wasActiveRef.current && !stream.active) {
@@ -92,42 +197,47 @@ function StreamingMessage({
92
197
  wasActiveRef.current = stream.active;
93
198
  }, [stream.active]);
94
199
  const phaseLabel = phaseLabels[stream.phase];
95
- const { displayed: displayedContent } = useCharacterDrain(stream.content);
96
- return /* @__PURE__ */ jsxs("div", { className, "data-testid": "streaming-message", children: [
200
+ const { displayed: rawDisplayed, isDraining } = useCharacterDrain(stream.content);
201
+ const displayedContent = stream.active || isDraining ? rawDisplayed.trimEnd() : rawDisplayed;
202
+ useEffect2(() => {
203
+ onDrainingRef.current?.(isDraining);
204
+ }, [isDraining]);
205
+ const agentLabel = stream.agent ? stream.agent.replace("_agent", "").replace("_", " ") : null;
206
+ const showPhaseIndicator = showPhases && stream.active && stream.phase !== "idle" && !displayedContent;
207
+ const showCursor = (stream.active || isDraining) && !!displayedContent;
208
+ return /* @__PURE__ */ jsxs("div", { className: twMerge2("flex w-full flex-col items-start", className), "data-testid": "streaming-message", children: [
97
209
  /* @__PURE__ */ jsxs("div", { "aria-live": "assertive", className: "sr-only", children: [
98
210
  stream.active && stream.phase !== "idle" && "Response started",
99
211
  !stream.active && stream.content && "Response complete"
100
212
  ] }),
213
+ showCursor && /* @__PURE__ */ jsx2("style", { children: CURSOR_STYLES }),
214
+ agentLabel && /* @__PURE__ */ jsx2("div", { className: "text-[11px] font-display font-semibold uppercase tracking-[0.08em] text-text-muted px-1 mb-1.5", children: agentLabel }),
101
215
  /* @__PURE__ */ jsxs("div", { className: "max-w-[88%] px-4 py-3 rounded-[18px] rounded-tl-[4px] bg-surface border border-border motion-safe:animate-springFromLeft", children: [
102
- showPhases && stream.active && stream.phase !== "idle" && /* @__PURE__ */ jsxs(
216
+ showPhaseIndicator && /* @__PURE__ */ jsxs(
103
217
  "div",
104
218
  {
105
- className: "flex items-center gap-2 mb-2 text-sm text-text-secondary",
219
+ className: "flex items-center gap-2 text-sm text-text-secondary",
106
220
  "data-testid": "phase-indicator",
107
221
  children: [
108
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx(Spinner, { size: "sm" }) }),
109
- /* @__PURE__ */ jsx("span", { children: phaseLabel })
222
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx2(WaveLoader, { size: "sm", color: "#38bdf8" }) }),
223
+ /* @__PURE__ */ jsx2("span", { children: phaseLabel })
110
224
  ]
111
225
  }
112
226
  ),
113
- /* @__PURE__ */ jsxs("div", { className: "text-sm leading-relaxed text-text-primary whitespace-pre-wrap", children: [
114
- displayedContent,
115
- stream.active && /* @__PURE__ */ jsx(
116
- "span",
117
- {
118
- className: "inline-block w-0.5 h-4 bg-accent align-text-bottom animate-pulse ml-0.5",
119
- "aria-hidden": "true",
120
- "data-testid": "streaming-cursor"
121
- }
122
- )
123
- ] })
227
+ displayedContent && /* @__PURE__ */ jsx2(
228
+ ResponseMessage,
229
+ {
230
+ content: displayedContent,
231
+ className: showCursor ? "sk-streaming-cursor" : void 0
232
+ }
233
+ )
124
234
  ] })
125
235
  ] });
126
236
  }
127
237
 
128
238
  // src/streaming/ThinkingIndicator/ThinkingIndicator.tsx
129
239
  import { useReducedMotion } from "@surf-kit/hooks";
130
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
240
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
131
241
  function ThinkingIndicator({ label = "Thinking...", className }) {
132
242
  const reducedMotion = useReducedMotion();
133
243
  return /* @__PURE__ */ jsxs2(
@@ -137,11 +247,11 @@ function ThinkingIndicator({ label = "Thinking...", className }) {
137
247
  className: `inline-flex items-center gap-2 text-sm motion-safe:animate-fadeSlideUpSm ${className ?? ""}`,
138
248
  "data-testid": "thinking-indicator",
139
249
  children: [
140
- /* @__PURE__ */ jsx2("span", { className: "text-text-secondary", children: label }),
250
+ /* @__PURE__ */ jsx3("span", { className: "text-text-secondary", children: label }),
141
251
  !reducedMotion && /* @__PURE__ */ jsxs2("span", { className: "flex gap-1", "aria-hidden": "true", "data-testid": "animated-dots", children: [
142
- /* @__PURE__ */ jsx2("span", { className: "w-1.5 h-1.5 rounded-full bg-current animate-bounce [animation-delay:0ms]" }),
143
- /* @__PURE__ */ jsx2("span", { className: "w-1.5 h-1.5 rounded-full bg-current animate-bounce [animation-delay:150ms]" }),
144
- /* @__PURE__ */ jsx2("span", { className: "w-1.5 h-1.5 rounded-full bg-current animate-bounce [animation-delay:300ms]" })
252
+ /* @__PURE__ */ jsx3("span", { className: "w-1.5 h-1.5 rounded-full bg-current animate-bounce [animation-delay:0ms]" }),
253
+ /* @__PURE__ */ jsx3("span", { className: "w-1.5 h-1.5 rounded-full bg-current animate-bounce [animation-delay:150ms]" }),
254
+ /* @__PURE__ */ jsx3("span", { className: "w-1.5 h-1.5 rounded-full bg-current animate-bounce [animation-delay:300ms]" })
145
255
  ] })
146
256
  ]
147
257
  }
@@ -149,8 +259,8 @@ function ThinkingIndicator({ label = "Thinking...", className }) {
149
259
  }
150
260
 
151
261
  // src/streaming/ToolExecution/ToolExecution.tsx
152
- import { Spinner as Spinner2 } from "@surf-kit/core";
153
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
262
+ import { WaveLoader as WaveLoader2 } from "@surf-kit/core";
263
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
154
264
  var defaultLabels = {
155
265
  search: "Searching knowledge base...",
156
266
  retrieve: "Retrieving documents...",
@@ -165,16 +275,16 @@ function ToolExecution({ tool, label, className }) {
165
275
  role: "status",
166
276
  "data-testid": "tool-execution",
167
277
  children: [
168
- /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx3(Spinner2, { size: "sm" }) }),
169
- /* @__PURE__ */ jsx3("span", { children: displayLabel })
278
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx4(WaveLoader2, { size: "sm", color: "#38bdf8" }) }),
279
+ /* @__PURE__ */ jsx4("span", { children: displayLabel })
170
280
  ]
171
281
  }
172
282
  );
173
283
  }
174
284
 
175
285
  // src/streaming/RetrievalProgress/RetrievalProgress.tsx
176
- import { Spinner as Spinner3 } from "@surf-kit/core";
177
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
286
+ import { WaveLoader as WaveLoader3 } from "@surf-kit/core";
287
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
178
288
  function RetrievalProgress({ sources, isActive, className }) {
179
289
  return /* @__PURE__ */ jsxs4(
180
290
  "div",
@@ -185,18 +295,18 @@ function RetrievalProgress({ sources, isActive, className }) {
185
295
  "data-testid": "retrieval-progress",
186
296
  children: [
187
297
  isActive && /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 text-sm text-text-secondary", children: [
188
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx4(Spinner3, { size: "sm" }) }),
189
- /* @__PURE__ */ jsx4("span", { children: "Retrieving sources..." })
298
+ /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx5(WaveLoader3, { size: "sm", color: "#38bdf8" }) }),
299
+ /* @__PURE__ */ jsx5("span", { children: "Retrieving sources..." })
190
300
  ] }),
191
- sources.length > 0 && /* @__PURE__ */ jsx4("ul", { className: "space-y-1", "data-testid": "source-list", children: sources.map((source, index) => /* @__PURE__ */ jsxs4(
301
+ sources.length > 0 && /* @__PURE__ */ jsx5("ul", { className: "space-y-1", "data-testid": "source-list", children: sources.map((source, index) => /* @__PURE__ */ jsxs4(
192
302
  "li",
193
303
  {
194
304
  className: "text-sm text-text-secondary flex items-center gap-2 animate-in fade-in slide-in-from-left-2",
195
305
  style: { animationDelay: `${index * 100}ms`, animationFillMode: "both" },
196
306
  "data-testid": "retrieval-source-item",
197
307
  children: [
198
- /* @__PURE__ */ jsx4("span", { className: "w-1.5 h-1.5 rounded-full bg-accent flex-shrink-0", "aria-hidden": "true" }),
199
- /* @__PURE__ */ jsx4("span", { className: "truncate", children: source.title })
308
+ /* @__PURE__ */ jsx5("span", { className: "w-1.5 h-1.5 rounded-full bg-accent flex-shrink-0", "aria-hidden": "true" }),
309
+ /* @__PURE__ */ jsx5("span", { className: "truncate", children: source.title })
200
310
  ]
201
311
  },
202
312
  source.document_id
@@ -207,7 +317,7 @@ function RetrievalProgress({ sources, isActive, className }) {
207
317
  }
208
318
 
209
319
  // src/streaming/VerificationProgress/VerificationProgress.tsx
210
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
320
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
211
321
  function VerificationProgress({
212
322
  isActive,
213
323
  label = "Checking accuracy...",
@@ -230,12 +340,12 @@ function VerificationProgress({
230
340
  viewBox: "0 0 24 24",
231
341
  "aria-hidden": "true",
232
342
  children: [
233
- /* @__PURE__ */ jsx5("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
234
- /* @__PURE__ */ jsx5("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
343
+ /* @__PURE__ */ jsx6("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
344
+ /* @__PURE__ */ jsx6("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
235
345
  ]
236
346
  }
237
347
  ),
238
- /* @__PURE__ */ jsx5("span", { className: "text-accent animate-pulse", children: label })
348
+ /* @__PURE__ */ jsx6("span", { className: "text-accent animate-pulse", children: label })
239
349
  ]
240
350
  }
241
351
  );
@@ -243,7 +353,7 @@ function VerificationProgress({
243
353
 
244
354
  // src/streaming/TypewriterText/TypewriterText.tsx
245
355
  import { useEffect as useEffect3, useState as useState2 } from "react";
246
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
356
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
247
357
  function TypewriterText({
248
358
  text,
249
359
  speed = 30,
@@ -278,14 +388,14 @@ function TypewriterText({
278
388
  }, [text, speed, delay, onComplete]);
279
389
  return /* @__PURE__ */ jsxs6("span", { className, children: [
280
390
  displayedText,
281
- showCursor && !isComplete && /* @__PURE__ */ jsx6("span", { className: "typewriter-cursor", "aria-hidden": "true" })
391
+ showCursor && !isComplete && /* @__PURE__ */ jsx7("span", { className: "typewriter-cursor", "aria-hidden": "true" })
282
392
  ] });
283
393
  }
284
394
 
285
395
  // src/streaming/TypingIndicator/TypingIndicator.tsx
286
- import { twMerge } from "tailwind-merge";
396
+ import { twMerge as twMerge3 } from "tailwind-merge";
287
397
  import { useReducedMotion as useReducedMotion2 } from "@surf-kit/hooks";
288
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
398
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
289
399
  var bounceKeyframes = `
290
400
  @keyframes typing-bounce {
291
401
  0%, 80%, 100% { transform: translateY(0); }
@@ -303,12 +413,12 @@ function TypingIndicator({
303
413
  {
304
414
  role: "status",
305
415
  "aria-label": label ?? "typing",
306
- className: twMerge("inline-flex items-center gap-2", className),
416
+ className: twMerge3("inline-flex items-center gap-2", className),
307
417
  "data-testid": "typing-indicator",
308
418
  children: [
309
- !reducedMotion && /* @__PURE__ */ jsx7("style", { children: bounceKeyframes }),
310
- label && /* @__PURE__ */ jsx7("span", { className: "text-sm text-text-secondary", children: label }),
311
- /* @__PURE__ */ jsx7("span", { className: "flex gap-1", "data-testid": "typing-dots", children: Array.from({ length: dotCount }, (_, i) => /* @__PURE__ */ jsx7(
419
+ !reducedMotion && /* @__PURE__ */ jsx8("style", { children: bounceKeyframes }),
420
+ label && /* @__PURE__ */ jsx8("span", { className: "text-sm text-text-secondary", children: label }),
421
+ /* @__PURE__ */ jsx8("span", { className: "flex gap-1", "data-testid": "typing-dots", children: Array.from({ length: dotCount }, (_, i) => /* @__PURE__ */ jsx8(
312
422
  "span",
313
423
  {
314
424
  className: "w-2 h-2 rounded-full bg-text-secondary",
@@ -325,9 +435,9 @@ function TypingIndicator({
325
435
  }
326
436
 
327
437
  // src/streaming/TextGlimmer/TextGlimmer.tsx
328
- import { twMerge as twMerge2 } from "tailwind-merge";
438
+ import { twMerge as twMerge4 } from "tailwind-merge";
329
439
  import { useReducedMotion as useReducedMotion3 } from "@surf-kit/hooks";
330
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
440
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
331
441
  var shimmerKeyframes = `
332
442
  @keyframes text-shimmer {
333
443
  0% { background-position: 200% 0; }
@@ -342,11 +452,11 @@ function TextGlimmer({ lines = 3, className }) {
342
452
  {
343
453
  role: "status",
344
454
  "aria-label": "Loading",
345
- className: twMerge2("flex flex-col gap-2", className),
455
+ className: twMerge4("flex flex-col gap-2", className),
346
456
  "data-testid": "text-glimmer",
347
457
  children: [
348
- !reducedMotion && /* @__PURE__ */ jsx8("style", { children: shimmerKeyframes }),
349
- Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx8(
458
+ !reducedMotion && /* @__PURE__ */ jsx9("style", { children: shimmerKeyframes }),
459
+ Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx9(
350
460
  "div",
351
461
  {
352
462
  className: "h-3 rounded bg-surface-raised",
@@ -368,9 +478,9 @@ function TextGlimmer({ lines = 3, className }) {
368
478
  }
369
479
 
370
480
  // src/streaming/StreamingList/StreamingList.tsx
371
- import { twMerge as twMerge3 } from "tailwind-merge";
481
+ import { twMerge as twMerge5 } from "tailwind-merge";
372
482
  import { useReducedMotion as useReducedMotion4 } from "@surf-kit/hooks";
373
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
483
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
374
484
  var fadeSlideInKeyframes = `
375
485
  @keyframes fadeSlideIn {
376
486
  from { opacity: 0; transform: translateY(8px); }
@@ -386,17 +496,17 @@ function StreamingList({
386
496
  }) {
387
497
  const reducedMotion = useReducedMotion4();
388
498
  if (items.length === 0 && !isStreaming) {
389
- return emptyMessage ? /* @__PURE__ */ jsx9("p", { className: twMerge3("text-sm text-text-secondary", className), "data-testid": "streaming-list-empty", children: emptyMessage }) : null;
499
+ return emptyMessage ? /* @__PURE__ */ jsx10("p", { className: twMerge5("text-sm text-text-secondary", className), "data-testid": "streaming-list-empty", children: emptyMessage }) : null;
390
500
  }
391
501
  return /* @__PURE__ */ jsxs9(
392
502
  "ul",
393
503
  {
394
504
  "aria-live": "polite",
395
- className: twMerge3("list-none p-0 m-0", className),
505
+ className: twMerge5("list-none p-0 m-0", className),
396
506
  "data-testid": "streaming-list",
397
507
  children: [
398
- !reducedMotion && /* @__PURE__ */ jsx9("style", { children: fadeSlideInKeyframes }),
399
- items.map((item, index) => /* @__PURE__ */ jsx9(
508
+ !reducedMotion && /* @__PURE__ */ jsx10("style", { children: fadeSlideInKeyframes }),
509
+ items.map((item, index) => /* @__PURE__ */ jsx10(
400
510
  "li",
401
511
  {
402
512
  style: reducedMotion ? void 0 : { animation: "fadeSlideIn 0.3s ease-out" },
@@ -405,16 +515,16 @@ function StreamingList({
405
515
  },
406
516
  index
407
517
  )),
408
- isStreaming && /* @__PURE__ */ jsx9("li", { "data-testid": "streaming-list-loading", children: /* @__PURE__ */ jsx9(TypingIndicator, {}) })
518
+ isStreaming && /* @__PURE__ */ jsx10("li", { "data-testid": "streaming-list-loading", children: /* @__PURE__ */ jsx10(TypingIndicator, {}) })
409
519
  ]
410
520
  }
411
521
  );
412
522
  }
413
523
 
414
524
  // src/streaming/StreamingStructure/StreamingStructure.tsx
415
- import { twMerge as twMerge4 } from "tailwind-merge";
525
+ import { twMerge as twMerge6 } from "tailwind-merge";
416
526
  import { useReducedMotion as useReducedMotion5 } from "@surf-kit/hooks";
417
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
527
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
418
528
  var fadeSlideInKeyframes2 = `
419
529
  @keyframes fadeSlideIn {
420
530
  from { opacity: 0; transform: translateY(8px); }
@@ -423,13 +533,13 @@ var fadeSlideInKeyframes2 = `
423
533
  `;
424
534
  function renderValue(value, reducedMotion) {
425
535
  if (value === null) {
426
- return /* @__PURE__ */ jsx10("span", { className: "italic text-text-secondary", children: "null" });
536
+ return /* @__PURE__ */ jsx11("span", { className: "italic text-text-secondary", children: "null" });
427
537
  }
428
538
  if (value === void 0) {
429
- return /* @__PURE__ */ jsx10("span", { className: "italic text-text-secondary", children: "undefined" });
539
+ return /* @__PURE__ */ jsx11("span", { className: "italic text-text-secondary", children: "undefined" });
430
540
  }
431
541
  if (Array.isArray(value)) {
432
- return /* @__PURE__ */ jsx10("ol", { className: "list-decimal pl-4 m-0", children: value.map((item, i) => /* @__PURE__ */ jsx10("li", { className: "text-text-secondary text-sm", children: renderValue(item, reducedMotion) }, i)) });
542
+ return /* @__PURE__ */ jsx11("ol", { className: "list-decimal pl-4 m-0", children: value.map((item, i) => /* @__PURE__ */ jsx11("li", { className: "text-text-secondary text-sm", children: renderValue(item, reducedMotion) }, i)) });
433
543
  }
434
544
  if (typeof value === "object") {
435
545
  return renderNestedDl(value, reducedMotion);
@@ -438,13 +548,13 @@ function renderValue(value, reducedMotion) {
438
548
  }
439
549
  function renderNestedDl(data, reducedMotion) {
440
550
  const entries = Object.entries(data);
441
- return /* @__PURE__ */ jsx10("dl", { className: "pl-4 m-0", "data-testid": "streaming-structure-nested", children: entries.map(([key, value]) => /* @__PURE__ */ jsxs10(
551
+ return /* @__PURE__ */ jsx11("dl", { className: "pl-4 m-0", "data-testid": "streaming-structure-nested", children: entries.map(([key, value]) => /* @__PURE__ */ jsxs10(
442
552
  "div",
443
553
  {
444
554
  style: reducedMotion ? void 0 : { animation: "fadeSlideIn 0.3s ease-out" },
445
555
  children: [
446
- /* @__PURE__ */ jsx10("dt", { className: "font-medium text-text-primary text-sm", children: key }),
447
- /* @__PURE__ */ jsx10("dd", { className: "text-text-secondary text-sm ml-0 mb-3", children: renderValue(value, reducedMotion) })
556
+ /* @__PURE__ */ jsx11("dt", { className: "font-medium text-text-primary text-sm", children: key }),
557
+ /* @__PURE__ */ jsx11("dd", { className: "text-text-secondary text-sm ml-0 mb-3", children: renderValue(value, reducedMotion) })
448
558
  ]
449
559
  },
450
560
  key
@@ -461,23 +571,23 @@ function StreamingStructure({
461
571
  "dl",
462
572
  {
463
573
  "aria-live": "polite",
464
- className: twMerge4("m-0", className),
574
+ className: twMerge6("m-0", className),
465
575
  "data-testid": "streaming-structure",
466
576
  children: [
467
- !reducedMotion && /* @__PURE__ */ jsx10("style", { children: fadeSlideInKeyframes2 }),
577
+ !reducedMotion && /* @__PURE__ */ jsx11("style", { children: fadeSlideInKeyframes2 }),
468
578
  entries.map(([key, value]) => /* @__PURE__ */ jsxs10(
469
579
  "div",
470
580
  {
471
581
  style: reducedMotion ? void 0 : { animation: "fadeSlideIn 0.3s ease-out" },
472
582
  "data-testid": "streaming-structure-entry",
473
583
  children: [
474
- /* @__PURE__ */ jsx10("dt", { className: "font-medium text-text-primary text-sm", children: key }),
475
- /* @__PURE__ */ jsx10("dd", { className: "text-text-secondary text-sm ml-0 mb-3", children: renderValue(value, reducedMotion) })
584
+ /* @__PURE__ */ jsx11("dt", { className: "font-medium text-text-primary text-sm", children: key }),
585
+ /* @__PURE__ */ jsx11("dd", { className: "text-text-secondary text-sm ml-0 mb-3", children: renderValue(value, reducedMotion) })
476
586
  ]
477
587
  },
478
588
  key
479
589
  )),
480
- isStreaming && /* @__PURE__ */ jsx10("div", { "data-testid": "streaming-structure-loading", children: /* @__PURE__ */ jsx10(TextGlimmer, { lines: 1 }) })
590
+ isStreaming && /* @__PURE__ */ jsx11("div", { "data-testid": "streaming-structure-loading", children: /* @__PURE__ */ jsx11(TextGlimmer, { lines: 1 }) })
481
591
  ]
482
592
  }
483
593
  );