@neuronection/assistant-ui 0.23.0 → 0.24.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 (155) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +9 -0
  3. package/dist/about.js +1 -1
  4. package/dist/ai-magic-fill.js +1 -1
  5. package/dist/chat-branch-tree.d.ts +45 -0
  6. package/dist/chat-branch-tree.js +3 -0
  7. package/dist/chat-branch-tree.js.map +1 -0
  8. package/dist/chat-composer.d.ts +50 -0
  9. package/dist/chat-composer.js +3 -0
  10. package/dist/chat-composer.js.map +1 -0
  11. package/dist/chat-core.d.ts +154 -0
  12. package/dist/chat-core.js +4 -0
  13. package/dist/chat-core.js.map +1 -0
  14. package/dist/chat-drawer.d.ts +32 -0
  15. package/dist/chat-drawer.js +3 -0
  16. package/dist/chat-drawer.js.map +1 -0
  17. package/dist/chat-launcher.d.ts +28 -0
  18. package/dist/chat-launcher.js +3 -0
  19. package/dist/chat-launcher.js.map +1 -0
  20. package/dist/chat-markdown.d.ts +64 -0
  21. package/dist/chat-markdown.js +3 -0
  22. package/dist/chat-markdown.js.map +1 -0
  23. package/dist/chat-message.d.ts +108 -0
  24. package/dist/chat-message.js +3 -0
  25. package/dist/chat-message.js.map +1 -0
  26. package/dist/chat-panel.d.ts +28 -0
  27. package/dist/chat-panel.js +3 -0
  28. package/dist/chat-panel.js.map +1 -0
  29. package/dist/chat-reasoning.d.ts +27 -0
  30. package/dist/chat-reasoning.js +3 -0
  31. package/dist/chat-reasoning.js.map +1 -0
  32. package/dist/chat-session-list.d.ts +51 -0
  33. package/dist/chat-session-list.js +3 -0
  34. package/dist/chat-session-list.js.map +1 -0
  35. package/dist/chat-tool-card.d.ts +37 -0
  36. package/dist/chat-tool-card.js +3 -0
  37. package/dist/chat-tool-card.js.map +1 -0
  38. package/dist/chat-transcript.d.ts +33 -0
  39. package/dist/chat-transcript.js +3 -0
  40. package/dist/chat-transcript.js.map +1 -0
  41. package/dist/{chunk-CZ2BL2ZL.js → chunk-3JJ2WCPN.js} +2 -2
  42. package/dist/{chunk-CZ2BL2ZL.js.map → chunk-3JJ2WCPN.js.map} +1 -1
  43. package/dist/chunk-5IOLDMDY.js +3 -0
  44. package/dist/chunk-5IOLDMDY.js.map +1 -0
  45. package/dist/{chunk-EODV6JK7.js → chunk-5QTHDB3D.js} +3 -3
  46. package/dist/{chunk-EODV6JK7.js.map → chunk-5QTHDB3D.js.map} +1 -1
  47. package/dist/chunk-6E6RRLKU.js +3 -0
  48. package/dist/chunk-6E6RRLKU.js.map +1 -0
  49. package/dist/chunk-6GNLY2EB.js +272 -0
  50. package/dist/chunk-6GNLY2EB.js.map +1 -0
  51. package/dist/chunk-743FJDRA.js +184 -0
  52. package/dist/chunk-743FJDRA.js.map +1 -0
  53. package/dist/chunk-BSIWLVDX.js +217 -0
  54. package/dist/chunk-BSIWLVDX.js.map +1 -0
  55. package/dist/chunk-BVJT67B5.js +134 -0
  56. package/dist/chunk-BVJT67B5.js.map +1 -0
  57. package/dist/chunk-DZBTJZZV.js +201 -0
  58. package/dist/chunk-DZBTJZZV.js.map +1 -0
  59. package/dist/chunk-HQIYSW2D.js +131 -0
  60. package/dist/chunk-HQIYSW2D.js.map +1 -0
  61. package/dist/chunk-JPDD5AFN.js +119 -0
  62. package/dist/chunk-JPDD5AFN.js.map +1 -0
  63. package/dist/chunk-LSCWBNG3.js +3 -0
  64. package/dist/chunk-LSCWBNG3.js.map +1 -0
  65. package/dist/chunk-NKYPNEOX.js +198 -0
  66. package/dist/chunk-NKYPNEOX.js.map +1 -0
  67. package/dist/{chunk-INMAUGBK.js → chunk-OH7AJ3WY.js} +3 -3
  68. package/dist/{chunk-INMAUGBK.js.map → chunk-OH7AJ3WY.js.map} +1 -1
  69. package/dist/chunk-PAQ6YQ7Y.js +3 -0
  70. package/dist/chunk-PAQ6YQ7Y.js.map +1 -0
  71. package/dist/chunk-QVDCFZSE.js +72 -0
  72. package/dist/chunk-QVDCFZSE.js.map +1 -0
  73. package/dist/chunk-RPLEI6LQ.js +102 -0
  74. package/dist/chunk-RPLEI6LQ.js.map +1 -0
  75. package/dist/chunk-S62VJVWB.js +36 -0
  76. package/dist/chunk-S62VJVWB.js.map +1 -0
  77. package/dist/chunk-X3C2FBMR.js +141 -0
  78. package/dist/chunk-X3C2FBMR.js.map +1 -0
  79. package/dist/{chunk-7YLR4AGA.js → chunk-XZWLTTHA.js} +2 -2
  80. package/dist/{chunk-7YLR4AGA.js.map → chunk-XZWLTTHA.js.map} +1 -1
  81. package/dist/chunk-Z4IBQ53C.js +75 -0
  82. package/dist/chunk-Z4IBQ53C.js.map +1 -0
  83. package/dist/{chunk-7KD4MG75.js → chunk-ZK2V2LPA.js} +3 -3
  84. package/dist/chunk-ZK2V2LPA.js.map +1 -0
  85. package/dist/copy-button.js +1 -1
  86. package/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
  87. package/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
  88. package/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  89. package/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  90. package/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  91. package/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  92. package/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  93. package/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  94. package/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  95. package/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  96. package/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  97. package/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  98. package/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  99. package/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  100. package/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  101. package/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
  102. package/dist/fonts/KaTeX_Main-Bold.woff +0 -0
  103. package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  104. package/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  105. package/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  106. package/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  107. package/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
  108. package/dist/fonts/KaTeX_Main-Italic.woff +0 -0
  109. package/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  110. package/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
  111. package/dist/fonts/KaTeX_Main-Regular.woff +0 -0
  112. package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  113. package/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  114. package/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  115. package/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  116. package/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
  117. package/dist/fonts/KaTeX_Math-Italic.woff +0 -0
  118. package/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  119. package/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  120. package/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  121. package/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  122. package/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  123. package/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  124. package/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  125. package/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  126. package/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  127. package/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  128. package/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
  129. package/dist/fonts/KaTeX_Script-Regular.woff +0 -0
  130. package/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  131. package/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
  132. package/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
  133. package/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  134. package/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
  135. package/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
  136. package/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  137. package/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
  138. package/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
  139. package/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  140. package/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
  141. package/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
  142. package/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  143. package/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  144. package/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  145. package/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  146. package/dist/index.d.ts +15 -0
  147. package/dist/index.js +39 -26
  148. package/dist/index.js.map +1 -1
  149. package/dist/portal.js +1 -1
  150. package/dist/settings-shell.js +1 -1
  151. package/dist/styles.css +1 -1
  152. package/dist/tree-YaIz73vo.d.ts +54 -0
  153. package/dist/types-DZwzmyKE.d.ts +44 -0
  154. package/package.json +56 -2
  155. package/dist/chunk-7KD4MG75.js.map +0 -1
@@ -0,0 +1,3 @@
1
+ export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher } from './chunk-BSIWLVDX.js';
2
+ //# sourceMappingURL=chat-message.js.map
3
+ //# sourceMappingURL=chat-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-message.js"}
@@ -0,0 +1,28 @@
1
+ import * as React from 'react';
2
+
3
+ type ChatPanelVariant = 'page' | 'sidebar' | 'bubble';
4
+ interface ChatPanelProps {
5
+ /** Layout tier: full page (centered, wide), sidebar (dense column), bubble (compact widget body). */
6
+ variant: ChatPanelVariant;
7
+ /** Header row: title node + action nodes (session list, branch tree, expand, close). */
8
+ title?: React.ReactNode;
9
+ actions?: React.ReactNode;
10
+ /** Status strip under the header (connection warnings, context summary). */
11
+ banner?: React.ReactNode;
12
+ /** Usually `<ChatTranscript …/>`. */
13
+ transcript: React.ReactNode;
14
+ /** Usually `<ChatComposer …/>`. */
15
+ composer?: React.ReactNode;
16
+ /** Disclaimer row under the composer (health guidance, etc.). */
17
+ footer?: React.ReactNode;
18
+ className?: string;
19
+ }
20
+ /**
21
+ * The composed chat host — the one uniform surface assembly behind the
22
+ * family's three shapes (full page / sidepanel / bubble). Owns layout
23
+ * only; transcript, composer and every feature slot stay app-composed
24
+ * (ADR-006 tier 3, `RichTextEditor` precedent).
25
+ */
26
+ declare const ChatPanel: React.ForwardRefExoticComponent<ChatPanelProps & React.RefAttributes<HTMLDivElement>>;
27
+
28
+ export { ChatPanel, type ChatPanelProps, type ChatPanelVariant };
@@ -0,0 +1,3 @@
1
+ export { ChatPanel } from './chunk-S62VJVWB.js';
2
+ //# sourceMappingURL=chat-panel.js.map
3
+ //# sourceMappingURL=chat-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-panel.js"}
@@ -0,0 +1,27 @@
1
+ import * as React from 'react';
2
+ import { LucideIcon } from 'lucide-react';
3
+
4
+ interface ChatReasoningLabels {
5
+ title: string;
6
+ streaming: string;
7
+ }
8
+ interface ChatReasoningProps {
9
+ /** Accumulated reasoning text (family `delta kind="reasoning"`). */
10
+ text: string;
11
+ /** Live reasoning stream — spinner + streaming label while on. */
12
+ streaming?: boolean;
13
+ open?: boolean;
14
+ defaultOpen?: boolean;
15
+ onOpenChange?: (open: boolean) => void;
16
+ labels?: Partial<ChatReasoningLabels>;
17
+ icon?: LucideIcon;
18
+ className?: string;
19
+ }
20
+ /**
21
+ * Collapsible thinking block for reasoning models (study's
22
+ * `ReasoningBubble`, family-standard): streams live while the model
23
+ * reasons, collapses to a summary row when done. Controlled-first.
24
+ */
25
+ declare const ChatReasoning: React.ForwardRefExoticComponent<ChatReasoningProps & React.RefAttributes<HTMLDivElement>>;
26
+
27
+ export { ChatReasoning, type ChatReasoningLabels, type ChatReasoningProps };
@@ -0,0 +1,3 @@
1
+ export { ChatReasoning } from './chunk-QVDCFZSE.js';
2
+ //# sourceMappingURL=chat-reasoning.js.map
3
+ //# sourceMappingURL=chat-reasoning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-reasoning.js"}
@@ -0,0 +1,51 @@
1
+ import * as React from 'react';
2
+ import { LucideIcon } from 'lucide-react';
3
+
4
+ interface ChatSessionView {
5
+ id: string;
6
+ title: string;
7
+ updatedAt?: string | number | Date;
8
+ meta?: Record<string, unknown>;
9
+ }
10
+ interface ChatSessionListLabels {
11
+ search: string;
12
+ searchPlaceholder: string;
13
+ newChat: string;
14
+ rename: string;
15
+ delete: string;
16
+ export: string;
17
+ today: string;
18
+ yesterday: string;
19
+ earlier: string;
20
+ empty: string;
21
+ noResults: string;
22
+ }
23
+ interface ChatSessionListIcons {
24
+ newChat: LucideIcon;
25
+ rename: LucideIcon;
26
+ delete: LucideIcon;
27
+ export: LucideIcon;
28
+ }
29
+ interface ChatSessionListProps {
30
+ sessions: ChatSessionView[];
31
+ activeId?: string | null;
32
+ onSelect: (id: string) => void;
33
+ onNew?: () => void;
34
+ onRename?: (id: string) => void;
35
+ onDelete?: (id: string) => void;
36
+ onExport?: (id: string) => void;
37
+ searchable?: boolean;
38
+ groupByDate?: boolean;
39
+ labels?: Partial<ChatSessionListLabels>;
40
+ icons?: Partial<ChatSessionListIcons>;
41
+ className?: string;
42
+ }
43
+ /**
44
+ * The session list beside a full-page chat (study's `ChatSessionList` +
45
+ * health's history overlay, generalized): fuzzy search, date grouping,
46
+ * active marking, per-session actions (rename/delete/export) via the
47
+ * menu when handlers are provided. All actions stay app-side.
48
+ */
49
+ declare const ChatSessionList: React.ForwardRefExoticComponent<ChatSessionListProps & React.RefAttributes<HTMLDivElement>>;
50
+
51
+ export { ChatSessionList, type ChatSessionListIcons, type ChatSessionListLabels, type ChatSessionListProps, type ChatSessionView };
@@ -0,0 +1,3 @@
1
+ export { ChatSessionList } from './chunk-NKYPNEOX.js';
2
+ //# sourceMappingURL=chat-session-list.js.map
3
+ //# sourceMappingURL=chat-session-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-session-list.js"}
@@ -0,0 +1,37 @@
1
+ import * as React from 'react';
2
+ import { LucideIcon } from 'lucide-react';
3
+
4
+ interface ChatToolCardLabels {
5
+ running: string;
6
+ done: string;
7
+ failed: string;
8
+ args: string;
9
+ result: string;
10
+ details: string;
11
+ }
12
+ interface ChatToolCardProps {
13
+ name: string;
14
+ /** Human title, e.g. "Searching the job catalog". */
15
+ title?: string;
16
+ status: 'running' | 'done' | 'failed';
17
+ /** Serialized arguments (JSON string or formatted text). */
18
+ args?: string;
19
+ /** Serialized result. */
20
+ result?: string;
21
+ durationMs?: number;
22
+ open?: boolean;
23
+ defaultOpen?: boolean;
24
+ onOpenChange?: (open: boolean) => void;
25
+ labels?: Partial<ChatToolCardLabels>;
26
+ icon?: LucideIcon;
27
+ className?: string;
28
+ }
29
+ /**
30
+ * Inline tool-call observation card (study's `ToolCallCard` + health's tool
31
+ * chips, generalized): status, duration, expandable args/result. The
32
+ * inspector stays app-side (health opens its own modal from `onOpenChange`
33
+ * or wrapping markup).
34
+ */
35
+ declare const ChatToolCard: React.ForwardRefExoticComponent<ChatToolCardProps & React.RefAttributes<HTMLDivElement>>;
36
+
37
+ export { ChatToolCard, type ChatToolCardLabels, type ChatToolCardProps };
@@ -0,0 +1,3 @@
1
+ export { ChatToolCard } from './chunk-JPDD5AFN.js';
2
+ //# sourceMappingURL=chat-tool-card.js.map
3
+ //# sourceMappingURL=chat-tool-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-tool-card.js"}
@@ -0,0 +1,33 @@
1
+ import * as React from 'react';
2
+ import { e as ChatMessageView } from './types-DZwzmyKE.js';
3
+
4
+ interface ChatTranscriptLabels {
5
+ log: string;
6
+ scrollToBottom: string;
7
+ empty: string;
8
+ replied: string;
9
+ }
10
+ interface ChatTranscriptProps {
11
+ items: ChatMessageView[];
12
+ /** Override the default `ChatMessage` + `MarkdownSurface` rendering. */
13
+ renderItem?: (message: ChatMessageView, index: number) => React.ReactNode;
14
+ /** Streaming tail — the live turn bubble (or any node). */
15
+ live?: React.ReactNode;
16
+ emptyState?: React.ReactNode;
17
+ /** Stick to bottom while the user hasn't scrolled away. Default true. */
18
+ autoScroll?: boolean;
19
+ /** Distance from the bottom that still counts as "at the bottom". Default 120 px. */
20
+ scrollThresholdPx?: number;
21
+ /** Virtualize long transcripts (dynamic row measurement). Default false. */
22
+ virtualized?: boolean;
23
+ labels?: Partial<ChatTranscriptLabels>;
24
+ className?: string;
25
+ }
26
+ /**
27
+ * The conversation list: `role="log"` with polite turn-completion
28
+ * announcements, stick-to-bottom auto-scroll with a jump-to-latest pill,
29
+ * optional virtualization for thousand-message threads.
30
+ */
31
+ declare const ChatTranscript: React.ForwardRefExoticComponent<ChatTranscriptProps & React.RefAttributes<HTMLDivElement>>;
32
+
33
+ export { ChatTranscript, type ChatTranscriptLabels, type ChatTranscriptProps };
@@ -0,0 +1,3 @@
1
+ export { ChatTranscript } from './chunk-BVJT67B5.js';
2
+ //# sourceMappingURL=chat-transcript.js.map
3
+ //# sourceMappingURL=chat-transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-transcript.js"}
@@ -85,5 +85,5 @@ var CopyButton = React.forwardRef(
85
85
  );
86
86
 
87
87
  export { CopyButton };
88
- //# sourceMappingURL=chunk-CZ2BL2ZL.js.map
89
- //# sourceMappingURL=chunk-CZ2BL2ZL.js.map
88
+ //# sourceMappingURL=chunk-3JJ2WCPN.js.map
89
+ //# sourceMappingURL=chunk-3JJ2WCPN.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/copy-button/CopyButton.tsx"],"names":["CopyButton"],"mappings":"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","file":"chunk-CZ2BL2ZL.js","sourcesContent":["import * as React from 'react'\nimport { Check, Copy } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport interface CopyButtonProps\n extends Omit<React.ComponentProps<'button'>, 'value' | 'children'> {\n value: string\n label?: string\n size?: number\n hideWhenEmpty?: boolean\n copiedDuration?: number\n onCopied?: () => void\n onCopyError?: (error: unknown) => void\n}\n\nfunction writeClipboard(value: string): Promise<void> {\n if (navigator?.clipboard?.writeText) {\n return navigator.clipboard.writeText(value)\n }\n return new Promise((resolve, reject) => {\n try {\n const textarea = document.createElement('textarea')\n textarea.value = value\n textarea.style.position = 'fixed'\n textarea.style.opacity = '0'\n document.body.appendChild(textarea)\n textarea.select()\n document.execCommand('copy')\n document.body.removeChild(textarea)\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n}\n\nexport const CopyButton = React.forwardRef<HTMLButtonElement, CopyButtonProps>(\n function CopyButton(\n {\n value,\n label = 'Copy',\n size = 14,\n hideWhenEmpty = true,\n copiedDuration = 1500,\n onCopied,\n onCopyError,\n className,\n onClick,\n ...props\n },\n ref,\n ) {\n const [copied, setCopied] = React.useState(false)\n const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n\n React.useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current)\n },\n [],\n )\n\n if (hideWhenEmpty && !value) return null\n\n const Icon = copied ? Check : Copy\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-as=\"copy-button\"\n data-copied={copied || undefined}\n aria-label={label}\n title={label}\n onClick={(event) => {\n onClick?.(event)\n if (event.defaultPrevented || !value) return\n event.preventDefault()\n event.stopPropagation()\n writeClipboard(value).then(\n () => {\n setCopied(true)\n if (timer.current) clearTimeout(timer.current)\n timer.current = setTimeout(() => setCopied(false), copiedDuration)\n onCopied?.()\n },\n (error) => {\n onCopyError?.(error)\n },\n )\n }}\n className={cn(\n 'inline-flex cursor-pointer items-center justify-center rounded-[var(--as-radius-sm)] p-0.5 text-[var(--as-muted-fg)] transition-colors hover:text-[var(--as-primary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]',\n copied && 'text-[var(--as-success)] hover:text-[var(--as-success)]',\n className,\n )}\n {...props}\n >\n <Icon style={{ width: size, height: size }} aria-hidden />\n </button>\n )\n },\n)\n"]}
1
+ {"version":3,"sources":["../src/components/copy-button/CopyButton.tsx"],"names":["CopyButton"],"mappings":"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","file":"chunk-3JJ2WCPN.js","sourcesContent":["import * as React from 'react'\nimport { Check, Copy } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport interface CopyButtonProps\n extends Omit<React.ComponentProps<'button'>, 'value' | 'children'> {\n value: string\n label?: string\n size?: number\n hideWhenEmpty?: boolean\n copiedDuration?: number\n onCopied?: () => void\n onCopyError?: (error: unknown) => void\n}\n\nfunction writeClipboard(value: string): Promise<void> {\n if (navigator?.clipboard?.writeText) {\n return navigator.clipboard.writeText(value)\n }\n return new Promise((resolve, reject) => {\n try {\n const textarea = document.createElement('textarea')\n textarea.value = value\n textarea.style.position = 'fixed'\n textarea.style.opacity = '0'\n document.body.appendChild(textarea)\n textarea.select()\n document.execCommand('copy')\n document.body.removeChild(textarea)\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n}\n\nexport const CopyButton = React.forwardRef<HTMLButtonElement, CopyButtonProps>(\n function CopyButton(\n {\n value,\n label = 'Copy',\n size = 14,\n hideWhenEmpty = true,\n copiedDuration = 1500,\n onCopied,\n onCopyError,\n className,\n onClick,\n ...props\n },\n ref,\n ) {\n const [copied, setCopied] = React.useState(false)\n const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n\n React.useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current)\n },\n [],\n )\n\n if (hideWhenEmpty && !value) return null\n\n const Icon = copied ? Check : Copy\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-as=\"copy-button\"\n data-copied={copied || undefined}\n aria-label={label}\n title={label}\n onClick={(event) => {\n onClick?.(event)\n if (event.defaultPrevented || !value) return\n event.preventDefault()\n event.stopPropagation()\n writeClipboard(value).then(\n () => {\n setCopied(true)\n if (timer.current) clearTimeout(timer.current)\n timer.current = setTimeout(() => setCopied(false), copiedDuration)\n onCopied?.()\n },\n (error) => {\n onCopyError?.(error)\n },\n )\n }}\n className={cn(\n 'inline-flex cursor-pointer items-center justify-center rounded-[var(--as-radius-sm)] p-0.5 text-[var(--as-muted-fg)] transition-colors hover:text-[var(--as-primary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]',\n copied && 'text-[var(--as-success)] hover:text-[var(--as-success)]',\n className,\n )}\n {...props}\n >\n <Icon style={{ width: size, height: size }} aria-hidden />\n </button>\n )\n },\n)\n"]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-5IOLDMDY.js.map
3
+ //# sourceMappingURL=chunk-5IOLDMDY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-5IOLDMDY.js"}
@@ -1,5 +1,5 @@
1
- import { FormModal } from './chunk-62GIJMWT.js';
2
1
  import { Textarea } from './chunk-C74WWM23.js';
2
+ import { FormModal } from './chunk-62GIJMWT.js';
3
3
  import * as React from 'react';
4
4
  import { Sparkles } from 'lucide-react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -70,5 +70,5 @@ function AiMagicFill({
70
70
  }
71
71
 
72
72
  export { AiMagicFill };
73
- //# sourceMappingURL=chunk-EODV6JK7.js.map
74
- //# sourceMappingURL=chunk-EODV6JK7.js.map
73
+ //# sourceMappingURL=chunk-5QTHDB3D.js.map
74
+ //# sourceMappingURL=chunk-5QTHDB3D.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ai-magic-fill/AiMagicFill.tsx"],"names":[],"mappings":";;;;;;AAqBO,SAAS,WAAA,CAAY;AAAA,EAC1B,IAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA,GAAO,KAAA;AAAA,EACP,KAAA;AAAA,EACA,KAAA,GAAQ,YAAA;AAAA,EACR,QAAA,GAAW,4BAAA;AAAA,EACX,WAAA;AAAA,EACA,WAAA,GAAc,kBAAA;AAAA,EACd,WAAA,GAAc,8BAAA;AAAA,EACd,WAAA;AAAA,EACA,WAAA,GAAc,QAAA;AAAA,EACd;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAU,eAAS,EAAE,CAAA;AAE7C,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,MAAM,OAAA,GAAU,OAAO,IAAA,EAAK;AAC5B,IAAA,IAAI,CAAC,WAAW,IAAA,EAAM;AACtB,IAAA,QAAA,CAAS,OAAO,CAAA;AAChB,IAAA,SAAA,CAAU,EAAE,CAAA;AAAA,EACd,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,YAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA,EAAa,QAAA;AAAA,MACb,IAAA,EAAM,QAAA;AAAA,MACN,WAAA,EAAa,WAAA,IAAe,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA;AAAA,MAC1C,WAAA;AAAA,MACA,UAAA,EAAY,IAAA;AAAA,MACZ,cAAA,EAAgB,CAAC,MAAA,CAAO,IAAA,EAAK;AAAA,MAC7B,QAAA,EAAU,MAAA;AAAA,MACV,gBAAA,EAAkB,SAAA;AAAA,MAElB,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAQ,eAAA,EAAgB,WAAU,qBAAA,EACrC,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uBAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAQ,sBAAA;AAAA,cACR,SAAA,EAAU,6EAAA;AAAA,cAET,QAAA,EAAA;AAAA;AAAA,WACH;AAAA,0BACA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,EAAA,EAAG,sBAAA;AAAA,cACH,IAAA,EAAM,CAAA;AAAA,cACN,KAAA,EAAO,MAAA;AAAA,cACP,UAAU,CAAC,KAAA,KACT,SAAA,CAAU,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,cAE9B,WAAA;AAAA,cACA,SAAA,EAAU;AAAA;AAAA;AACZ,SAAA,EACF,CAAA;AAAA,QACC,8BACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4MAAA,EACV,uBACH,CAAA,GACE,IAAA;AAAA,QACH,KAAA,uBACE,GAAA,EAAA,EAAE,IAAA,EAAK,SAAQ,SAAA,EAAU,+CAAA,EACvB,iBACH,CAAA,GACE;AAAA,OAAA,EACN;AAAA;AAAA,GACF;AAEJ","file":"chunk-EODV6JK7.js","sourcesContent":["import * as React from 'react'\nimport { Sparkles } from 'lucide-react'\nimport { FormModal } from '../form-modal/FormModal'\nimport { Textarea } from '../textarea/Textarea'\n\nexport interface AiMagicFillProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onSubmit: (prompt: string) => void\n busy?: boolean\n error?: string | null\n title?: string\n subtitle?: string\n description?: string\n promptLabel?: string\n placeholder?: string\n submitLabel?: string\n cancelLabel?: string\n className?: string\n}\n\nexport function AiMagicFill({\n open,\n onOpenChange,\n onSubmit,\n busy = false,\n error,\n title = 'Magic Fill',\n subtitle = 'AI-powered data extraction',\n description,\n promptLabel = 'Describe details',\n placeholder = 'Describe the data here…',\n submitLabel,\n cancelLabel = 'Cancel',\n className,\n}: AiMagicFillProps) {\n const [prompt, setPrompt] = React.useState('')\n\n const submit = () => {\n const trimmed = prompt.trim()\n if (!trimmed || busy) return\n onSubmit(trimmed)\n setPrompt('')\n }\n\n return (\n <FormModal\n open={open}\n onOpenChange={onOpenChange}\n title={title}\n description={subtitle}\n icon={Sparkles}\n submitLabel={submitLabel ?? `Apply ${title}`}\n cancelLabel={cancelLabel}\n submitting={busy}\n submitDisabled={!prompt.trim()}\n onSubmit={submit}\n contentClassName={className}\n >\n <div data-as=\"ai-magic-fill\" className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-1.5\">\n <label\n htmlFor=\"ai-magic-fill-prompt\"\n className=\"text-[11px] font-bold uppercase tracking-[0.18em] text-[var(--as-muted-fg)]\"\n >\n {promptLabel}\n </label>\n <Textarea\n id=\"ai-magic-fill-prompt\"\n rows={5}\n value={prompt}\n onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>\n setPrompt(event.target.value)\n }\n placeholder={placeholder}\n className=\"resize-none leading-relaxed\"\n />\n </div>\n {description ? (\n <p className=\"rounded-[var(--as-radius)] border border-[color-mix(in_srgb,var(--as-ai)_25%,transparent)] bg-[color-mix(in_srgb,var(--as-ai)_8%,transparent)] p-3 text-xs font-medium leading-relaxed text-[var(--as-fg)]\">\n {description}\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"text-xs font-semibold text-[var(--as-danger)]\">\n {error}\n </p>\n ) : null}\n </div>\n </FormModal>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/components/ai-magic-fill/AiMagicFill.tsx"],"names":[],"mappings":";;;;;;AAqBO,SAAS,WAAA,CAAY;AAAA,EAC1B,IAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA,GAAO,KAAA;AAAA,EACP,KAAA;AAAA,EACA,KAAA,GAAQ,YAAA;AAAA,EACR,QAAA,GAAW,4BAAA;AAAA,EACX,WAAA;AAAA,EACA,WAAA,GAAc,kBAAA;AAAA,EACd,WAAA,GAAc,8BAAA;AAAA,EACd,WAAA;AAAA,EACA,WAAA,GAAc,QAAA;AAAA,EACd;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAU,eAAS,EAAE,CAAA;AAE7C,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,MAAM,OAAA,GAAU,OAAO,IAAA,EAAK;AAC5B,IAAA,IAAI,CAAC,WAAW,IAAA,EAAM;AACtB,IAAA,QAAA,CAAS,OAAO,CAAA;AAChB,IAAA,SAAA,CAAU,EAAE,CAAA;AAAA,EACd,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,YAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA,EAAa,QAAA;AAAA,MACb,IAAA,EAAM,QAAA;AAAA,MACN,WAAA,EAAa,WAAA,IAAe,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA;AAAA,MAC1C,WAAA;AAAA,MACA,UAAA,EAAY,IAAA;AAAA,MACZ,cAAA,EAAgB,CAAC,MAAA,CAAO,IAAA,EAAK;AAAA,MAC7B,QAAA,EAAU,MAAA;AAAA,MACV,gBAAA,EAAkB,SAAA;AAAA,MAElB,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAQ,eAAA,EAAgB,WAAU,qBAAA,EACrC,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uBAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAQ,sBAAA;AAAA,cACR,SAAA,EAAU,6EAAA;AAAA,cAET,QAAA,EAAA;AAAA;AAAA,WACH;AAAA,0BACA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,EAAA,EAAG,sBAAA;AAAA,cACH,IAAA,EAAM,CAAA;AAAA,cACN,KAAA,EAAO,MAAA;AAAA,cACP,UAAU,CAAC,KAAA,KACT,SAAA,CAAU,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,cAE9B,WAAA;AAAA,cACA,SAAA,EAAU;AAAA;AAAA;AACZ,SAAA,EACF,CAAA;AAAA,QACC,8BACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4MAAA,EACV,uBACH,CAAA,GACE,IAAA;AAAA,QACH,KAAA,uBACE,GAAA,EAAA,EAAE,IAAA,EAAK,SAAQ,SAAA,EAAU,+CAAA,EACvB,iBACH,CAAA,GACE;AAAA,OAAA,EACN;AAAA;AAAA,GACF;AAEJ","file":"chunk-5QTHDB3D.js","sourcesContent":["import * as React from 'react'\nimport { Sparkles } from 'lucide-react'\nimport { FormModal } from '../form-modal/FormModal'\nimport { Textarea } from '../textarea/Textarea'\n\nexport interface AiMagicFillProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onSubmit: (prompt: string) => void\n busy?: boolean\n error?: string | null\n title?: string\n subtitle?: string\n description?: string\n promptLabel?: string\n placeholder?: string\n submitLabel?: string\n cancelLabel?: string\n className?: string\n}\n\nexport function AiMagicFill({\n open,\n onOpenChange,\n onSubmit,\n busy = false,\n error,\n title = 'Magic Fill',\n subtitle = 'AI-powered data extraction',\n description,\n promptLabel = 'Describe details',\n placeholder = 'Describe the data here…',\n submitLabel,\n cancelLabel = 'Cancel',\n className,\n}: AiMagicFillProps) {\n const [prompt, setPrompt] = React.useState('')\n\n const submit = () => {\n const trimmed = prompt.trim()\n if (!trimmed || busy) return\n onSubmit(trimmed)\n setPrompt('')\n }\n\n return (\n <FormModal\n open={open}\n onOpenChange={onOpenChange}\n title={title}\n description={subtitle}\n icon={Sparkles}\n submitLabel={submitLabel ?? `Apply ${title}`}\n cancelLabel={cancelLabel}\n submitting={busy}\n submitDisabled={!prompt.trim()}\n onSubmit={submit}\n contentClassName={className}\n >\n <div data-as=\"ai-magic-fill\" className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-1.5\">\n <label\n htmlFor=\"ai-magic-fill-prompt\"\n className=\"text-[11px] font-bold uppercase tracking-[0.18em] text-[var(--as-muted-fg)]\"\n >\n {promptLabel}\n </label>\n <Textarea\n id=\"ai-magic-fill-prompt\"\n rows={5}\n value={prompt}\n onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>\n setPrompt(event.target.value)\n }\n placeholder={placeholder}\n className=\"resize-none leading-relaxed\"\n />\n </div>\n {description ? (\n <p className=\"rounded-[var(--as-radius)] border border-[color-mix(in_srgb,var(--as-ai)_25%,transparent)] bg-[color-mix(in_srgb,var(--as-ai)_8%,transparent)] p-3 text-xs font-medium leading-relaxed text-[var(--as-fg)]\">\n {description}\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"text-xs font-semibold text-[var(--as-danger)]\">\n {error}\n </p>\n ) : null}\n </div>\n </FormModal>\n )\n}\n"]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-6E6RRLKU.js.map
3
+ //# sourceMappingURL=chunk-6E6RRLKU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-6E6RRLKU.js"}
@@ -0,0 +1,272 @@
1
+ import { useState, useRef, useCallback, useEffect } from 'react';
2
+
3
+ // src/components/chat-core/liveTurnReducer.ts
4
+ var initialLiveTurnState = {
5
+ status: "idle",
6
+ text: null,
7
+ reasoning: null,
8
+ toolCalls: [],
9
+ nodes: [],
10
+ error: null,
11
+ interruptPayload: null,
12
+ runId: null,
13
+ stopped: false,
14
+ startedAt: null,
15
+ finishedAt: null
16
+ };
17
+ function isTerminal(state) {
18
+ return state.status === "done" || state.status === "error" || state.stopped;
19
+ }
20
+ function upsertNode(nodes, id, label, status) {
21
+ const index = nodes.findIndex((node) => node.id === id);
22
+ if (index === -1) {
23
+ return [...nodes, { id, label, status }];
24
+ }
25
+ const next = nodes.slice();
26
+ const current = next[index];
27
+ next[index] = { ...current, label: label ?? current.label, status };
28
+ return next;
29
+ }
30
+ function upsertToolCall(state, event) {
31
+ const index = state.toolCalls.findIndex((call) => call.id === event.id);
32
+ const merged = {
33
+ id: event.id,
34
+ name: event.name,
35
+ title: event.title,
36
+ status: event.status,
37
+ args: event.args,
38
+ result: event.result,
39
+ durationMs: event.durationMs
40
+ };
41
+ if (index === -1) {
42
+ return [...state.toolCalls, merged];
43
+ }
44
+ const next = state.toolCalls.slice();
45
+ const current = next[index];
46
+ next[index] = {
47
+ ...current,
48
+ ...merged,
49
+ title: merged.title ?? current.title,
50
+ args: merged.args ?? current.args,
51
+ result: merged.result ?? current.result,
52
+ durationMs: merged.durationMs ?? current.durationMs
53
+ };
54
+ return next;
55
+ }
56
+ function liveTurnReducer(state, action) {
57
+ switch (action.type) {
58
+ case "send":
59
+ return { ...initialLiveTurnState, status: "pending", startedAt: action.at };
60
+ case "stop": {
61
+ if (state.status !== "pending" && state.status !== "streaming") {
62
+ return state;
63
+ }
64
+ return { ...state, status: "interrupted", stopped: true, finishedAt: action.at };
65
+ }
66
+ case "reset":
67
+ return initialLiveTurnState;
68
+ case "event": {
69
+ const { event, at = Date.now() } = action;
70
+ if (state.status === "idle" || isTerminal(state)) {
71
+ return state;
72
+ }
73
+ if (event.run_id !== void 0 && state.runId !== null && event.run_id !== state.runId) {
74
+ return state;
75
+ }
76
+ switch (event.event) {
77
+ case "flow_started":
78
+ return {
79
+ ...state,
80
+ runId: event.run_id ?? state.runId,
81
+ nodes: event.steps !== void 0 && event.steps.length > 0 ? event.steps.map((step) => ({ id: step.id, label: step.label, status: "pending" })) : state.nodes
82
+ };
83
+ case "node_started":
84
+ return { ...state, nodes: upsertNode(state.nodes, event.node, event.label, "running") };
85
+ case "node_finished":
86
+ return { ...state, nodes: upsertNode(state.nodes, event.node, event.label, event.outcome) };
87
+ case "delta": {
88
+ const streaming = { ...state, status: "streaming" };
89
+ if (event.kind === "reasoning") {
90
+ return { ...streaming, reasoning: (state.reasoning ?? "") + event.text };
91
+ }
92
+ return { ...streaming, text: (state.text ?? "") + event.text };
93
+ }
94
+ case "tool_call":
95
+ return { ...state, toolCalls: upsertToolCall(state, event) };
96
+ case "interrupt":
97
+ return { ...state, status: "interrupted", interruptPayload: event.payload, finishedAt: at };
98
+ case "flow_finished":
99
+ return { ...state, status: "done", finishedAt: at };
100
+ case "flow_failed":
101
+ return {
102
+ ...state,
103
+ status: "error",
104
+ error: { code: event.code, message: event.message, retryable: event.retryable },
105
+ finishedAt: at
106
+ };
107
+ default:
108
+ return state;
109
+ }
110
+ }
111
+ default:
112
+ return state;
113
+ }
114
+ }
115
+ function useChatStream(options) {
116
+ const { transport, flushMs = 33, timeoutMs = 9e4 } = options;
117
+ const [state, setState] = useState(initialLiveTurnState);
118
+ const stateRef = useRef(state);
119
+ const dispatch = useCallback((action) => {
120
+ const next = liveTurnReducer(stateRef.current, action);
121
+ stateRef.current = next;
122
+ setState(next);
123
+ }, []);
124
+ const transportRef = useRef(transport);
125
+ transportRef.current = transport;
126
+ const textBufferRef = useRef("");
127
+ const reasoningBufferRef = useRef("");
128
+ const flushTimerRef = useRef(null);
129
+ const timeoutTimerRef = useRef(null);
130
+ const terminalRef = useRef(false);
131
+ const cancelFlush = useCallback(() => {
132
+ if (flushTimerRef.current !== null) {
133
+ window.clearTimeout(flushTimerRef.current);
134
+ flushTimerRef.current = null;
135
+ }
136
+ }, []);
137
+ const flush = useCallback(() => {
138
+ cancelFlush();
139
+ const text = textBufferRef.current;
140
+ const reasoning = reasoningBufferRef.current;
141
+ textBufferRef.current = "";
142
+ reasoningBufferRef.current = "";
143
+ if (text !== "") {
144
+ dispatch({ type: "event", event: { event: "delta", text, kind: "text" } });
145
+ }
146
+ if (reasoning !== "") {
147
+ dispatch({ type: "event", event: { event: "delta", text: reasoning, kind: "reasoning" } });
148
+ }
149
+ }, [cancelFlush, dispatch]);
150
+ const scheduleFlush = useCallback(() => {
151
+ if (flushTimerRef.current !== null) {
152
+ return;
153
+ }
154
+ flushTimerRef.current = window.setTimeout(() => {
155
+ flushTimerRef.current = null;
156
+ flush();
157
+ }, flushMs);
158
+ }, [flush, flushMs]);
159
+ const clearTimeoutTimer = useCallback(() => {
160
+ if (timeoutTimerRef.current !== null) {
161
+ window.clearTimeout(timeoutTimerRef.current);
162
+ timeoutTimerRef.current = null;
163
+ }
164
+ }, []);
165
+ useEffect(() => {
166
+ const unsubscribe = transportRef.current.subscribe({
167
+ onEvent: (event) => {
168
+ if (terminalRef.current) {
169
+ return;
170
+ }
171
+ if (event.event === "delta") {
172
+ if (event.kind === "reasoning") {
173
+ reasoningBufferRef.current += event.text;
174
+ } else {
175
+ textBufferRef.current += event.text;
176
+ }
177
+ scheduleFlush();
178
+ return;
179
+ }
180
+ flush();
181
+ if (event.event === "flow_finished" || event.event === "flow_failed") {
182
+ terminalRef.current = true;
183
+ clearTimeoutTimer();
184
+ }
185
+ dispatch({ type: "event", event });
186
+ }
187
+ });
188
+ return unsubscribe;
189
+ }, [scheduleFlush, flush, clearTimeoutTimer, dispatch]);
190
+ useEffect(
191
+ () => () => {
192
+ cancelFlush();
193
+ clearTimeoutTimer();
194
+ },
195
+ [cancelFlush, clearTimeoutTimer]
196
+ );
197
+ const send = useCallback(
198
+ async (text) => {
199
+ const trimmed = text.trim();
200
+ const active = stateRef.current.status === "pending" || stateRef.current.status === "streaming";
201
+ if (trimmed === "" || active) {
202
+ return false;
203
+ }
204
+ terminalRef.current = false;
205
+ textBufferRef.current = "";
206
+ reasoningBufferRef.current = "";
207
+ cancelFlush();
208
+ clearTimeoutTimer();
209
+ dispatch({ type: "send", at: Date.now() });
210
+ timeoutTimerRef.current = window.setTimeout(() => {
211
+ if (terminalRef.current) {
212
+ return;
213
+ }
214
+ terminalRef.current = true;
215
+ flush();
216
+ dispatch({
217
+ type: "event",
218
+ event: { event: "flow_failed", code: "timeout", message: "Chat turn timed out", retryable: true }
219
+ });
220
+ }, timeoutMs);
221
+ try {
222
+ await transportRef.current.send({ text: trimmed });
223
+ } catch (sendError) {
224
+ if (terminalRef.current) {
225
+ return true;
226
+ }
227
+ terminalRef.current = true;
228
+ clearTimeoutTimer();
229
+ flush();
230
+ dispatch({
231
+ type: "event",
232
+ event: {
233
+ event: "flow_failed",
234
+ code: "send_failed",
235
+ message: sendError instanceof Error ? sendError.message : String(sendError),
236
+ retryable: true
237
+ }
238
+ });
239
+ }
240
+ return true;
241
+ },
242
+ [cancelFlush, clearTimeoutTimer, dispatch, flush, timeoutMs]
243
+ );
244
+ const stop = useCallback(async () => {
245
+ const current = stateRef.current;
246
+ if (current.status !== "pending" && current.status !== "streaming") {
247
+ return;
248
+ }
249
+ terminalRef.current = true;
250
+ clearTimeoutTimer();
251
+ flush();
252
+ dispatch({ type: "stop", at: Date.now() });
253
+ await transportRef.current.stop?.().catch(() => void 0);
254
+ }, [clearTimeoutTimer, dispatch, flush]);
255
+ const reset = useCallback(() => {
256
+ terminalRef.current = false;
257
+ cancelFlush();
258
+ clearTimeoutTimer();
259
+ dispatch({ type: "reset" });
260
+ }, [cancelFlush, clearTimeoutTimer, dispatch]);
261
+ return {
262
+ ...state,
263
+ live: state.status === "idle" ? null : state,
264
+ send,
265
+ stop,
266
+ reset
267
+ };
268
+ }
269
+
270
+ export { initialLiveTurnState, liveTurnReducer, useChatStream };
271
+ //# sourceMappingURL=chunk-6GNLY2EB.js.map
272
+ //# sourceMappingURL=chunk-6GNLY2EB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/chat-core/liveTurnReducer.ts","../src/components/chat-core/useChatStream.ts"],"names":[],"mappings":"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","file":"chunk-6GNLY2EB.js","sourcesContent":["import type { ChatStreamEvent } from './events'\nimport type { ChatError } from './types'\n\nexport type LiveTurnStatus = 'idle' | 'pending' | 'streaming' | 'interrupted' | 'done' | 'error'\n\nexport interface LiveNodeState {\n id: string\n label?: string\n status: 'pending' | 'running' | 'done' | 'failed' | 'interrupted'\n}\n\nexport interface LiveToolCall {\n id: string\n name: string\n title?: string\n status: 'running' | 'done' | 'failed'\n args?: string\n result?: string\n durationMs?: number\n}\n\n/**\n * Ephemeral state of the in-flight assistant turn. `text`/`reasoning` are\n * `null` until the first delta (study's \"not streaming yet\" sentinel);\n * `interrupted` is a resumable pause (HITL) unless `stopped` marks a user\n * cancel; `stopped`/`done`/`error` are terminal for event intake.\n */\nexport interface LiveTurnState {\n status: LiveTurnStatus\n text: string | null\n reasoning: string | null\n toolCalls: LiveToolCall[]\n nodes: LiveNodeState[]\n error: ChatError | null\n interruptPayload: unknown | null\n runId: string | null\n stopped: boolean\n startedAt: number | null\n finishedAt: number | null\n}\n\nexport type LiveTurnAction =\n | { type: 'send'; at: number }\n | { type: 'event'; event: ChatStreamEvent; at?: number }\n | { type: 'stop'; at: number }\n | { type: 'reset' }\n\nexport const initialLiveTurnState: LiveTurnState = {\n status: 'idle',\n text: null,\n reasoning: null,\n toolCalls: [],\n nodes: [],\n error: null,\n interruptPayload: null,\n runId: null,\n stopped: false,\n startedAt: null,\n finishedAt: null,\n}\n\nfunction isTerminal(state: LiveTurnState): boolean {\n return state.status === 'done' || state.status === 'error' || state.stopped\n}\n\nfunction upsertNode(nodes: LiveNodeState[], id: string, label: string | undefined, status: LiveNodeState['status']): LiveNodeState[] {\n const index = nodes.findIndex((node) => node.id === id)\n if (index === -1) {\n return [...nodes, { id, label, status }]\n }\n const next = nodes.slice()\n const current = next[index]!\n next[index] = { ...current, label: label ?? current.label, status }\n return next\n}\n\nfunction upsertToolCall(state: LiveTurnState, event: Extract<ChatStreamEvent, { event: 'tool_call' }>): LiveToolCall[] {\n const index = state.toolCalls.findIndex((call) => call.id === event.id)\n const merged = {\n id: event.id,\n name: event.name,\n title: event.title,\n status: event.status,\n args: event.args,\n result: event.result,\n durationMs: event.durationMs,\n }\n if (index === -1) {\n return [...state.toolCalls, merged]\n }\n const next = state.toolCalls.slice()\n const current = next[index]!\n next[index] = {\n ...current,\n ...merged,\n title: merged.title ?? current.title,\n args: merged.args ?? current.args,\n result: merged.result ?? current.result,\n durationMs: merged.durationMs ?? current.durationMs,\n }\n return next\n}\n\n/**\n * Pure state machine for one streamed assistant turn — the fixture-testable\n * core behind `useChatStream` (same role career's `chatFlow.ts` plays for\n * `FlowStatusCard`). Unknown event names are ignored (additive contract).\n */\nexport function liveTurnReducer(state: LiveTurnState, action: LiveTurnAction): LiveTurnState {\n switch (action.type) {\n case 'send':\n return { ...initialLiveTurnState, status: 'pending', startedAt: action.at }\n case 'stop': {\n if (state.status !== 'pending' && state.status !== 'streaming') {\n return state\n }\n return { ...state, status: 'interrupted', stopped: true, finishedAt: action.at }\n }\n case 'reset':\n return initialLiveTurnState\n case 'event': {\n const { event, at = Date.now() } = action\n if (state.status === 'idle' || isTerminal(state)) {\n return state\n }\n if (event.run_id !== undefined && state.runId !== null && event.run_id !== state.runId) {\n return state\n }\n switch (event.event) {\n case 'flow_started':\n return {\n ...state,\n runId: event.run_id ?? state.runId,\n nodes:\n event.steps !== undefined && event.steps.length > 0\n ? event.steps.map((step): LiveNodeState => ({ id: step.id, label: step.label, status: 'pending' }))\n : state.nodes,\n }\n case 'node_started':\n return { ...state, nodes: upsertNode(state.nodes, event.node, event.label, 'running') }\n case 'node_finished':\n return { ...state, nodes: upsertNode(state.nodes, event.node, event.label, event.outcome) }\n case 'delta': {\n const streaming = { ...state, status: 'streaming' as const }\n if (event.kind === 'reasoning') {\n return { ...streaming, reasoning: (state.reasoning ?? '') + event.text }\n }\n return { ...streaming, text: (state.text ?? '') + event.text }\n }\n case 'tool_call':\n return { ...state, toolCalls: upsertToolCall(state, event) }\n case 'interrupt':\n return { ...state, status: 'interrupted', interruptPayload: event.payload, finishedAt: at }\n case 'flow_finished':\n return { ...state, status: 'done', finishedAt: at }\n case 'flow_failed':\n return {\n ...state,\n status: 'error',\n error: { code: event.code, message: event.message, retryable: event.retryable },\n finishedAt: at,\n }\n default:\n return state\n }\n }\n default:\n return state\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { ChatStreamEvent } from './events'\nimport { initialLiveTurnState, liveTurnReducer, type LiveTurnAction, type LiveTurnState } from './liveTurnReducer'\n\nexport interface ChatStreamTransport {\n /** Enqueue/send a user turn. Resolves when accepted; errors surface as a failed turn. */\n send(input: { text: string }): Promise<void>\n /** Subscribe to the session's stream events; returns an unsubscribe function. */\n subscribe(handlers: { onEvent: (event: ChatStreamEvent) => void }): () => void\n /** Best-effort cancel of the in-flight turn (backend stop endpoint). */\n stop?(): Promise<void>\n}\n\nexport interface UseChatStreamOptions {\n transport: ChatStreamTransport\n /** Delta coalescing window. Default 33 ms (study's rAF-scale budget). */\n flushMs?: number\n /** Watchdog for a turn that never terminates. Default 90 000 ms. */\n timeoutMs?: number\n}\n\nexport interface UseChatStreamResult extends LiveTurnState {\n /** The live turn, or `null` when idle — hand to the transcript's `live` slot. */\n live: LiveTurnState | null\n /** Returns false and does nothing for blank input or while a turn is active. */\n send(text: string): Promise<boolean>\n stop(): Promise<void>\n reset(): void\n}\n\n/**\n * Transport-injected live-turn state machine for chat surfaces: send →\n * pending → streaming (coalesced text/reasoning deltas, tool calls, node\n * progress) → done / error / interrupted. Persists nothing — the app owns\n * sessions, messages and the branching endpoints; after a terminal state\n * the app refetches and calls `reset()`.\n */\nexport function useChatStream(options: UseChatStreamOptions): UseChatStreamResult {\n const { transport, flushMs = 33, timeoutMs = 90_000 } = options\n const [state, setState] = useState<LiveTurnState>(initialLiveTurnState)\n const stateRef = useRef(state)\n const dispatch = useCallback((action: LiveTurnAction) => {\n const next = liveTurnReducer(stateRef.current, action)\n stateRef.current = next\n setState(next)\n }, [])\n\n const transportRef = useRef(transport)\n transportRef.current = transport\n\n const textBufferRef = useRef('')\n const reasoningBufferRef = useRef('')\n const flushTimerRef = useRef<number | null>(null)\n const timeoutTimerRef = useRef<number | null>(null)\n const terminalRef = useRef(false)\n\n const cancelFlush = useCallback(() => {\n if (flushTimerRef.current !== null) {\n window.clearTimeout(flushTimerRef.current)\n flushTimerRef.current = null\n }\n }, [])\n\n const flush = useCallback(() => {\n cancelFlush()\n const text = textBufferRef.current\n const reasoning = reasoningBufferRef.current\n textBufferRef.current = ''\n reasoningBufferRef.current = ''\n if (text !== '') {\n dispatch({ type: 'event', event: { event: 'delta', text, kind: 'text' } })\n }\n if (reasoning !== '') {\n dispatch({ type: 'event', event: { event: 'delta', text: reasoning, kind: 'reasoning' } })\n }\n }, [cancelFlush, dispatch])\n\n const scheduleFlush = useCallback(() => {\n if (flushTimerRef.current !== null) {\n return\n }\n flushTimerRef.current = window.setTimeout(() => {\n flushTimerRef.current = null\n flush()\n }, flushMs)\n }, [flush, flushMs])\n\n const clearTimeoutTimer = useCallback(() => {\n if (timeoutTimerRef.current !== null) {\n window.clearTimeout(timeoutTimerRef.current)\n timeoutTimerRef.current = null\n }\n }, [])\n\n useEffect(() => {\n const unsubscribe = transportRef.current.subscribe({\n onEvent: (event) => {\n if (terminalRef.current) {\n return\n }\n if (event.event === 'delta') {\n if (event.kind === 'reasoning') {\n reasoningBufferRef.current += event.text\n } else {\n textBufferRef.current += event.text\n }\n scheduleFlush()\n return\n }\n flush()\n if (event.event === 'flow_finished' || event.event === 'flow_failed') {\n terminalRef.current = true\n clearTimeoutTimer()\n }\n dispatch({ type: 'event', event })\n },\n })\n return unsubscribe\n }, [scheduleFlush, flush, clearTimeoutTimer, dispatch])\n\n useEffect(\n () => () => {\n cancelFlush()\n clearTimeoutTimer()\n },\n [cancelFlush, clearTimeoutTimer],\n )\n\n const send = useCallback(\n async (text: string) => {\n const trimmed = text.trim()\n const active = stateRef.current.status === 'pending' || stateRef.current.status === 'streaming'\n if (trimmed === '' || active) {\n return false\n }\n terminalRef.current = false\n textBufferRef.current = ''\n reasoningBufferRef.current = ''\n cancelFlush()\n clearTimeoutTimer()\n dispatch({ type: 'send', at: Date.now() })\n timeoutTimerRef.current = window.setTimeout(() => {\n if (terminalRef.current) {\n return\n }\n terminalRef.current = true\n flush()\n dispatch({\n type: 'event',\n event: { event: 'flow_failed', code: 'timeout', message: 'Chat turn timed out', retryable: true },\n })\n }, timeoutMs)\n try {\n await transportRef.current.send({ text: trimmed })\n } catch (sendError) {\n if (terminalRef.current) {\n return true\n }\n terminalRef.current = true\n clearTimeoutTimer()\n flush()\n dispatch({\n type: 'event',\n event: {\n event: 'flow_failed',\n code: 'send_failed',\n message: sendError instanceof Error ? sendError.message : String(sendError),\n retryable: true,\n },\n })\n }\n return true\n },\n [cancelFlush, clearTimeoutTimer, dispatch, flush, timeoutMs],\n )\n\n const stop = useCallback(async () => {\n const current = stateRef.current\n if (current.status !== 'pending' && current.status !== 'streaming') {\n return\n }\n terminalRef.current = true\n clearTimeoutTimer()\n flush()\n dispatch({ type: 'stop', at: Date.now() })\n await transportRef.current.stop?.().catch(() => undefined)\n }, [clearTimeoutTimer, dispatch, flush])\n\n const reset = useCallback(() => {\n terminalRef.current = false\n cancelFlush()\n clearTimeoutTimer()\n dispatch({ type: 'reset' })\n }, [cancelFlush, clearTimeoutTimer, dispatch])\n\n return {\n ...state,\n live: state.status === 'idle' ? null : state,\n send,\n stop,\n reset,\n }\n}\n"]}