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