reachat 3.2.2 → 3.2.3

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.
package/dist/index.js CHANGED
@@ -10,67 +10,4179 @@
10
10
  console.error("vite-plugin-css-injected-by-js", e);
11
11
  }
12
12
  })();
13
- import { A, b, C, c, d, e, f, g, h, i, j, k, F, M, l, m, n, o, p, q, r, s, t, u, N, R, v, w, x, y, z, B, D, E, G, H, T, I, J, K, L, O, P, Q, U, V, W, X, Y, Z, _, $, a0, a1, a2, a3 } from "./index-BiStNXJ4.js";
14
- import "react/jsx-runtime";
15
- import "react";
16
- import "reablocks";
17
- import "motion/react";
13
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
14
+ import * as React from "react";
15
+ import { createContext, useContext, useRef, forwardRef, useState, useEffect, useCallback, useImperativeHandle, memo, useMemo, lazy, Suspense, isValidElement, cloneElement, Component } from "react";
16
+ import { Button, cn, List, ListItem, Ellipsis, DateFormat, Redact, IconButton, Card, useInfinityList, useComponentTheme, ConnectedOverlay } from "reablocks";
17
+ import { useEditor, EditorContent, ReactRenderer, posToDOMRect } from "@tiptap/react";
18
+ import { computePosition, shift, flip } from "@floating-ui/dom";
19
+ import Document from "@tiptap/extension-document";
20
+ import Paragraph from "@tiptap/extension-paragraph";
21
+ import Text from "@tiptap/extension-text";
22
+ import HardBreak from "@tiptap/extension-hard-break";
23
+ import Placeholder from "@tiptap/extension-placeholder";
24
+ import Mention from "@tiptap/extension-mention";
25
+ import { Slot } from "@radix-ui/react-slot";
26
+ import { motion, AnimatePresence } from "motion/react";
27
+ import ReactMarkdown from "react-markdown";
28
+ import rehypeKatex from "rehype-katex";
29
+ import rehypeRaw from "rehype-raw";
30
+ import { Prism } from "react-syntax-highlighter";
31
+ import { SparklineChart, RadialAreaChart, RadialAreaSeries, RadialBarChart, RadialBarSeries, PieChart, PieArcSeries, AreaChart, AreaSeries, LinearYAxis, LinearXAxis, LineChart, LineSeries, BarChart, BarSeries } from "reaviz";
32
+ import { findAndReplace } from "mdast-util-find-and-replace";
33
+ import debounce from "lodash/debounce.js";
34
+ import { useHotkeys } from "reakeys";
35
+ import remarkGfm from "remark-gfm";
36
+ import remarkYoutube from "remark-youtube";
37
+ import remarkMath from "remark-math";
38
+ import { isToday, isYesterday, isThisWeek, differenceInYears, format } from "date-fns";
39
+ import { offset } from "@floating-ui/react";
40
+ import { z } from "zod";
41
+ const SvgSend = (props) => /* @__PURE__ */ React.createElement("svg", { width: 17, height: 17, viewBox: "0 0 17 17", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props }, /* @__PURE__ */ React.createElement("g", { id: "send" }, /* @__PURE__ */ React.createElement("path", { id: "Vector", d: "M14.6111 2.33327C14.5349 2.3339 14.4598 2.35194 14.3917 2.386L2.39168 8.386C2.31456 8.42456 2.24872 8.4824 2.20055 8.55391C2.15238 8.62543 2.12352 8.70818 2.11677 8.79414C2.11002 8.88009 2.12561 8.96634 2.16203 9.04449C2.19845 9.12264 2.25446 9.19005 2.32462 9.24017L4.52514 10.8124L5.47371 13.6581C5.50257 13.7447 5.55457 13.8217 5.62406 13.8808C5.69355 13.9399 5.7779 13.9789 5.86796 13.9935C5.95802 14.0082 6.05036 13.9979 6.13499 13.9638C6.21962 13.9297 6.2933 13.873 6.34806 13.8001L7.05249 12.8606L10.3207 15.2376C10.3843 15.2839 10.4579 15.3146 10.5355 15.3271C10.6132 15.3396 10.6927 15.3336 10.7676 15.3097C10.8425 15.2857 10.9107 15.2444 10.9667 15.1891C11.0226 15.1338 11.0647 15.0661 11.0896 14.9915L15.0896 2.99147C15.1148 2.91597 15.1216 2.83555 15.1094 2.7569C15.0972 2.67825 15.0665 2.60363 15.0197 2.53926C14.9729 2.47488 14.9114 2.42261 14.8403 2.38678C14.7693 2.35096 14.6907 2.33261 14.6111 2.33327ZM13.2478 5.35345L10.3565 14.0266L7.67293 12.0755L13.2478 5.35345ZM10.684 5.35801L4.934 9.87559L3.58113 8.90879L10.684 5.35801ZM11.2784 6.16205L6.56746 11.843C6.56681 11.8437 6.56616 11.8443 6.56551 11.845L6.56355 11.8476C6.55841 11.8538 6.55342 11.8601 6.54858 11.8665C6.54319 11.8733 6.53798 11.8802 6.53295 11.8873L6.12085 12.4361L5.53426 10.6751L11.2784 6.16205Z", fill: "currentColor" })));
42
+ const SvgStop = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-octagon-x", ...props }, /* @__PURE__ */ React.createElement("path", { d: "m15 9-6 6" }), /* @__PURE__ */ React.createElement("path", { d: "M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z" }), /* @__PURE__ */ React.createElement("path", { d: "m9 9 6 6" }));
43
+ const ChatContext = createContext({
44
+ sessions: [],
45
+ activeSessionId: null
46
+ });
47
+ const SvgPaperclip = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-paperclip", ...props }, /* @__PURE__ */ React.createElement("path", { d: "m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48" }));
48
+ const FileInput = ({
49
+ allowedFiles,
50
+ multiple,
51
+ onFileUpload,
52
+ isLoading,
53
+ disabled,
54
+ attachIcon = /* @__PURE__ */ jsx(SvgPaperclip, {})
55
+ }) => {
56
+ const { theme } = useContext(ChatContext);
57
+ const fileInputRef = useRef(null);
58
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
59
+ /* @__PURE__ */ jsx(
60
+ "input",
61
+ {
62
+ type: "file",
63
+ ref: fileInputRef,
64
+ className: "hidden",
65
+ accept: allowedFiles.join(","),
66
+ multiple,
67
+ onChange: (e) => {
68
+ onFileUpload(e);
69
+ if (fileInputRef.current) {
70
+ fileInputRef.current.value = "";
71
+ }
72
+ }
73
+ }
74
+ ),
75
+ /* @__PURE__ */ jsx(
76
+ Button,
77
+ {
78
+ title: "Upload",
79
+ variant: "text",
80
+ disabled: isLoading || disabled,
81
+ className: cn(theme.input.upload),
82
+ onClick: () => fileInputRef.current?.click(),
83
+ children: attachIcon
84
+ }
85
+ )
86
+ ] });
87
+ };
88
+ const chatTheme = {
89
+ base: "dark:text-white text-gray-500",
90
+ console: "flex w-full gap-4 h-full",
91
+ companion: "w-full h-full overflow-hidden",
92
+ empty: "text-center flex-1",
93
+ appbar: "flex p-5",
94
+ status: {
95
+ base: "py-2 px-3 rounded-lg bg-gray-100/50 dark:bg-gray-800/30",
96
+ header: "flex items-center gap-2",
97
+ icon: {
98
+ base: "flex-shrink-0 w-4 h-4",
99
+ loading: "text-blue-500 dark:text-blue-400",
100
+ complete: "text-green-500 dark:text-green-400",
101
+ error: "text-red-500 dark:text-red-400"
102
+ },
103
+ text: {
104
+ base: "text-sm",
105
+ loading: "text-gray-600 dark:text-gray-400",
106
+ complete: "text-gray-600 dark:text-gray-400",
107
+ error: "text-red-600 dark:text-red-400"
108
+ },
109
+ steps: {
110
+ base: "mt-1 ml-6 space-y-0.5",
111
+ step: {
112
+ base: "flex items-center gap-2",
113
+ icon: "flex-shrink-0 w-3.5 h-3.5",
114
+ text: "text-sm",
115
+ loading: "text-gray-500 dark:text-gray-500",
116
+ complete: "text-gray-500 dark:text-gray-500",
117
+ error: "text-red-500 dark:text-red-400"
118
+ }
119
+ }
120
+ },
121
+ sessions: {
122
+ base: "overflow-auto",
123
+ console: "min-w-[150px] w-[30%] max-w-[300px] dark:bg-[#11111F] bg-[#F2F3F7] p-5 rounded-3xl",
124
+ companion: "w-full h-full",
125
+ group: "text-xs dart:text-gray-400 text-gray-700 mt-4 hover:bg-transparent mb-1",
126
+ create: "relative mb-4 rounded-[10px] text-white",
127
+ session: {
128
+ base: [
129
+ "group my-1 rounded-[10px] p-2 text-gray-500 border border-transparent hover:bg-gray-300 hover:border-gray-400 [&_svg]:text-gray-500",
130
+ "dark:text-typography dark:text-gray-400 dark:hover:bg-gray-800/50 dark:hover:border-gray-700/50 dark:[&_svg]:text-gray-200"
131
+ ].join(" "),
132
+ active: [
133
+ "border border-gray-300 hover:border-gray-400 text-gray-700 bg-gray-200 hover:bg-gray-300 ",
134
+ "dark:text-gray-500 dark:bg-gray-800/70 dark:border-gray-700/50 dark:text-white dark:border-gray-700/70 dark:hover:bg-gray-800/50",
135
+ "[&_button]:opacity-100!"
136
+ ].join(" "),
137
+ delete: "[&>svg]:w-4 [&>svg]:h-4 opacity-0 group-hover:opacity-50!"
138
+ }
139
+ },
140
+ messages: {
141
+ base: "",
142
+ console: "flex flex-col mx-5 flex-1 min-h-0",
143
+ companion: "flex w-full h-full",
144
+ back: "self-start p-0 my-2",
145
+ inner: "flex-1 h-full flex flex-col",
146
+ title: ["text-base font-bold text-gray-500", "dark:text-gray-200"].join(
147
+ " "
148
+ ),
149
+ date: "text-xs whitespace-nowrap text-gray-400",
150
+ content: [
151
+ "mt-2 flex-1 overflow-auto [&_hr]:bg-gray-200",
152
+ "dark:[&_hr]:bg-gray-800/60"
153
+ ].join(" "),
154
+ header: "flex justify-between items-center gap-2",
155
+ showMore: "mb-4",
156
+ message: {
157
+ base: "mt-4 mb-4 flex flex-col p-0 rounded-sm border-none bg-transparent",
158
+ question: [
159
+ "relative font-semibold mb-4 px-4 py-4 pb-2 rounded-3xl rounded-br-none text-typography border bg-gray-200 border-gray-300 text-gray-900",
160
+ "dark:bg-gray-900/60 dark:border-gray-700/50 dark:text-gray-100"
161
+ ].join(" "),
162
+ response: [
163
+ "relative data-[compact=false]:px-4 text-gray-900",
164
+ "dark:text-gray-100"
165
+ ].join(" "),
166
+ overlay: "overflow-y-hidden max-h-[350px] after:content-[''] after:absolute after:inset-x-0 after:bottom-0 after:h-16 after:bg-linear-to-b after:from-transparent dark:after:to-gray-900 after:to-gray-200",
167
+ cursor: "inline-block w-1 h-4 bg-current",
168
+ expand: "absolute bottom-1 right-1 z-10",
169
+ scrollToBottom: {
170
+ container: "absolute bottom-2 left-1/2 transform -translate-x-1/2 z-10",
171
+ button: "rounded-full p-2 shadow-lg"
172
+ },
173
+ files: {
174
+ base: "mb-2 flex flex-wrap gap-3 ",
175
+ file: {
176
+ base: [
177
+ "flex items-center gap-2 border border-gray-300 px-3 py-2 rounded-lg cursor-pointer",
178
+ "dark:border-gray-700"
179
+ ].join(" "),
180
+ name: ["text-sm text-gray-500", "dark:text-gray-200"].join(" ")
181
+ }
182
+ },
183
+ sources: {
184
+ base: "my-4 flex flex-wrap gap-3",
185
+ source: {
186
+ base: [
187
+ "flex gap-2 border border-gray-200 px-4 py-2 rounded-lg cursor-pointer",
188
+ "dark:border-gray-700"
189
+ ].join(" "),
190
+ companion: "flex-1 px-3 py-1.5",
191
+ image: "max-w-10 max-h-10 rounded-md w-full h-fit self-center",
192
+ title: "text-md block",
193
+ url: "text-sm text-blue-400 underline"
194
+ }
195
+ },
196
+ markdown: {
197
+ hr: "my-4 border-t border-stroke-neutral-4",
198
+ copy: "sticky py-1 [&>svg]:w-4 [&>svg]:h-4 opacity-50",
199
+ p: "mb-2",
200
+ a: "text-buttons-colors-link-primary-text-resting underline",
201
+ table: "table-auto w-full m-2",
202
+ th: "px-4 py-2 text-left font-bold border-b border-stroke-neutral-4",
203
+ td: "px-4 py-2",
204
+ code: "m-2 rounded-b relative",
205
+ inlineCode: "bg-gradient-neutral-200 p-1 rounded",
206
+ toolbar: "text-xs flex items-center justify-between px-2 py-1 rounded-t sticky top-0 backdrop-blur-md bg-gradient-neutral-500/50",
207
+ li: "mb-2 ml-6",
208
+ ul: "mb-4 list-disc",
209
+ ol: "mb-4 list-decimal",
210
+ h1: "text-4xl font-bold mb-4 mt-6",
211
+ h2: "text-3xl font-bold mb-3 mt-5",
212
+ h3: "text-2xl font-bold mb-3 mt-4",
213
+ h4: "text-xl font-bold mb-2 mt-3",
214
+ h5: "text-lg font-bold mb-2 mt-2",
215
+ h6: "text-base font-bold mb-2 mt-2"
216
+ },
217
+ footer: {
218
+ base: "mt-3 flex gap-1.5",
219
+ copy: [
220
+ "p-3 rounded-[10px] [&>svg]:w-4 [&>svg]:h-4 opacity-50 hover:opacity-100! hover:bg-gray-200 hover:text-gray-500",
221
+ "dark:hover:bg-gray-800 dark:hover:text-white text-gray-400"
222
+ ].join(" "),
223
+ upvote: "p-3 rounded-[10px] [&>svg]:w-4 [&>svg]:h-4 opacity-50 hover:opacity-100! hover:bg-gray-700/40 hover:text-white text-gray-400",
224
+ downvote: "p-3 rounded-[10px] [&>svg]:w-4 [&>svg]:h-4 opacity-50 hover:opacity-100! hover:bg-gray-700/40 hover:text-white text-gray-400",
225
+ refresh: "p-3 rounded-[10px] [&>svg]:w-4 [&>svg]:h-4 opacity-50 hover:opacity-100! hover:bg-gray-700/40 hover:text-white text-gray-400"
226
+ }
227
+ }
228
+ },
229
+ input: {
230
+ base: "flex mt-4 relative",
231
+ upload: ["px-5 py-2 text-gray-400 size-10", "dark:gray-500"].join(" "),
232
+ input: [
233
+ "w-full border rounded-3xl px-3 py-2 pr-16 text-gray-500 border-gray-200 hover:bg-blue-100 hover:border-blue-500 after:hidden after:mx-10! bg-white [&>textarea]:w-full [&>textarea]:flex-none",
234
+ "dark:border-gray-700/50 dark:text-gray-200 dark:bg-gray-950 dark:hover:bg-blue-950/40"
235
+ ].join(" "),
236
+ actions: {
237
+ base: "absolute flex gap-2 items-center right-5 inset-y-1/2 -translate-y-1/2 z-10",
238
+ send: [
239
+ "px-3 py-3 hover:bg-primary-hover rounded-full bg-gray-200 hover:bg-gray-300 text-gray-500",
240
+ "dark:text-white light:text-gray-500 dark:bg-gray-800 dark:hover:bg-gray-700"
241
+ ].join(" "),
242
+ stop: "px-2 py-2 bg-red-500 text-white rounded-full hover:bg-red-700 "
243
+ },
244
+ popup: {
245
+ base: [
246
+ "bg-white border border-gray-200 rounded-lg shadow-lg overflow-hidden min-w-[200px] max-w-[300px]",
247
+ "dark:bg-gray-900 dark:border-gray-700"
248
+ ].join(" "),
249
+ content: "overflow-y-auto max-h-[250px]",
250
+ item: [
251
+ "flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors",
252
+ "hover:bg-gray-100 dark:hover:bg-gray-800"
253
+ ].join(" "),
254
+ itemHighlighted: "bg-gray-100 dark:bg-gray-800",
255
+ itemIcon: [
256
+ "flex-shrink-0 w-5 h-5 text-gray-500 [&>svg]:w-full [&>svg]:h-full",
257
+ "dark:text-gray-400"
258
+ ].join(" "),
259
+ itemContent: "flex flex-col min-w-0 flex-1",
260
+ itemLabel: [
261
+ "text-sm font-medium text-gray-900 truncate",
262
+ "dark:text-gray-100"
263
+ ].join(" "),
264
+ itemDescription: "text-xs text-gray-500 dark:text-gray-400 truncate",
265
+ itemShortcut: "text-xs text-gray-400 dark:text-gray-500 ml-auto",
266
+ empty: "px-3 py-4 text-sm text-center text-gray-500 dark:text-gray-400",
267
+ loading: [
268
+ "flex items-center justify-center gap-2 px-3 py-4 text-gray-500",
269
+ "dark:text-gray-400"
270
+ ].join(" ")
271
+ },
272
+ tag: {
273
+ base: [
274
+ "inline-flex items-center px-1.5 py-0.5 mx-0.5 rounded",
275
+ "font-medium text-sm leading-[1.2] relative top-[1px]"
276
+ ].join(" "),
277
+ mention: [
278
+ "bg-blue-100 dark:bg-blue-900/30",
279
+ "text-blue-700 dark:text-blue-300"
280
+ ].join(" "),
281
+ command: [
282
+ "bg-purple-100 dark:bg-purple-900/30",
283
+ "text-purple-700 dark:text-purple-300"
284
+ ].join(" ")
285
+ },
286
+ editor: {
287
+ base: [
288
+ "outline-none w-full overflow-y-auto",
289
+ "text-inherit font-inherit",
290
+ "[&_.tiptap-paragraph]:m-0"
291
+ ].join(" "),
292
+ container: "px-3 py-2 pr-16",
293
+ placeholder: [
294
+ "[&_.is-editor-empty]:before:content-[attr(data-placeholder)]",
295
+ "[&_.is-editor-empty]:before:text-gray-400",
296
+ "[&_.is-editor-empty]:before:dark:text-gray-500",
297
+ "[&_.is-editor-empty]:before:float-left",
298
+ "[&_.is-editor-empty]:before:h-0",
299
+ "[&_.is-editor-empty]:before:pointer-events-none"
300
+ ].join(" ")
301
+ }
302
+ },
303
+ suggestions: {
304
+ base: "flex flex-wrap gap-2 mt-4",
305
+ item: {
306
+ base: [
307
+ "rounded-full! max-w-full py-2 px-4",
308
+ "bg-gray-100 border-gray-200 hover:bg-gray-200 hover:border-gray-300 text-gray-700",
309
+ "dark:bg-gray-800/50 dark:border-gray-700 dark:hover:bg-gray-700/70 dark:hover:border-gray-600 dark:text-gray-200",
310
+ "[&>svg]:w-4 [&>svg]:h-4 [&>svg]:text-blue-500 [&>svg]:dark:text-blue-400 [&>svg]:flex-shrink-0"
311
+ ].join(" "),
312
+ icon: "w-4 h-4 text-blue-500 dark:text-blue-400 flex-shrink-0",
313
+ text: "text-sm truncate"
314
+ }
315
+ },
316
+ chart: {
317
+ base: "my-6",
318
+ title: "text-sm font-medium mb-2 text-gray-600 dark:text-gray-400",
319
+ content: "flex items-center justify-center",
320
+ error: {
321
+ base: [
322
+ "my-4 p-4 border rounded",
323
+ "border-red-300 bg-red-50 text-red-500",
324
+ "dark:border-red-700 dark:bg-red-900/20"
325
+ ].join(" "),
326
+ title: "text-red-600 dark:text-red-400 text-sm font-medium mb-2",
327
+ code: "text-xs overflow-auto"
328
+ },
329
+ warning: {
330
+ base: [
331
+ "my-4 p-4 border rounded",
332
+ "border-yellow-300 bg-yellow-50 text-yellow-600",
333
+ "dark:border-yellow-700 dark:bg-yellow-900/20 dark:text-yellow-400"
334
+ ].join(" "),
335
+ title: "text-yellow-600 dark:text-yellow-400 text-sm font-medium mb-2"
336
+ }
337
+ },
338
+ component: {
339
+ base: "my-4"
340
+ }
341
+ };
342
+ const POPUP_STYLE = { zIndex: 9999 };
343
+ const MentionList = forwardRef(
344
+ ({ items, command, triggerChar, config, query }, ref) => {
345
+ const [selectedIndex, setSelectedIndex] = useState(0);
346
+ const itemRefs = useRef([]);
347
+ const { theme } = useContext(ChatContext);
348
+ const popupTheme = theme?.input?.popup || chatTheme.input.popup;
349
+ useEffect(() => {
350
+ setSelectedIndex(0);
351
+ }, [items]);
352
+ useEffect(() => {
353
+ if (itemRefs.current[selectedIndex]) {
354
+ itemRefs.current[selectedIndex]?.scrollIntoView({
355
+ block: "nearest",
356
+ behavior: "smooth"
357
+ });
358
+ }
359
+ }, [selectedIndex]);
360
+ const selectItem = useCallback(
361
+ (index) => {
362
+ const item = items[index];
363
+ if (!item) return;
364
+ if (config.onSelect) {
365
+ config.onSelect(item, (text) => {
366
+ command({ id: item.id, label: text || item.label });
367
+ });
368
+ } else {
369
+ command({ id: item.id, label: item.label });
370
+ }
371
+ },
372
+ [items, command, config]
373
+ );
374
+ useImperativeHandle(ref, () => ({
375
+ onKeyDown: ({ event }) => {
376
+ if (event.key === "ArrowUp") {
377
+ event.preventDefault();
378
+ setSelectedIndex((prev) => prev <= 0 ? items.length - 1 : prev - 1);
379
+ return true;
380
+ }
381
+ if (event.key === "ArrowDown") {
382
+ event.preventDefault();
383
+ setSelectedIndex((prev) => prev >= items.length - 1 ? 0 : prev + 1);
384
+ return true;
385
+ }
386
+ if (event.key === "Enter" || event.key === "Tab") {
387
+ event.preventDefault();
388
+ selectItem(selectedIndex);
389
+ return true;
390
+ }
391
+ return false;
392
+ }
393
+ }));
394
+ const popupId = `mention-list-${triggerChar}`;
395
+ return /* @__PURE__ */ jsx(
396
+ List,
397
+ {
398
+ className: cn(popupTheme.base, popupTheme.content),
399
+ style: POPUP_STYLE,
400
+ role: "listbox",
401
+ id: popupId,
402
+ "aria-label": `${triggerChar === "@" ? "Mentions" : "Commands"} suggestions`,
403
+ children: items.length === 0 ? /* @__PURE__ */ jsx(ListItem, { className: cn(popupTheme.empty), disabled: true, dense: true, children: config.renderEmpty ? config.renderEmpty(query || "") : query ? `No results for "${query}"` : "No items available" }) : items.map((item, index) => /* @__PURE__ */ jsx(
404
+ "div",
405
+ {
406
+ id: `${popupId}-option-${item.id}`,
407
+ role: "option",
408
+ "aria-selected": index === selectedIndex,
409
+ ref: (el) => {
410
+ itemRefs.current[index] = el;
411
+ },
412
+ onClick: () => selectItem(index),
413
+ onMouseEnter: () => setSelectedIndex(index),
414
+ className: "cursor-pointer",
415
+ children: config.renderItem ? config.renderItem(item, index === selectedIndex) : /* @__PURE__ */ jsx(
416
+ DefaultItemRenderer,
417
+ {
418
+ item,
419
+ isHighlighted: index === selectedIndex,
420
+ popupTheme
421
+ }
422
+ )
423
+ },
424
+ item.id
425
+ ))
426
+ }
427
+ );
428
+ }
429
+ );
430
+ const DefaultItemRenderer = memo(
431
+ ({ item, isHighlighted, popupTheme }) => {
432
+ const shortcut = "shortcut" in item ? item.shortcut : void 0;
433
+ return /* @__PURE__ */ jsx(
434
+ ListItem,
435
+ {
436
+ className: cn(
437
+ popupTheme.item,
438
+ isHighlighted && popupTheme.itemHighlighted
439
+ ),
440
+ dense: true,
441
+ start: item.icon ? /* @__PURE__ */ jsx("span", { className: cn(popupTheme.itemIcon), children: item.icon }) : void 0,
442
+ end: shortcut ? /* @__PURE__ */ jsx("span", { className: cn(popupTheme.itemShortcut), children: shortcut }) : void 0,
443
+ children: /* @__PURE__ */ jsxs("div", { className: cn(popupTheme.itemContent), children: [
444
+ /* @__PURE__ */ jsx("span", { className: cn(popupTheme.itemLabel), children: item.label }),
445
+ item.description && /* @__PURE__ */ jsx("span", { className: cn(popupTheme.itemDescription), children: item.description })
446
+ ] })
447
+ }
448
+ );
449
+ }
450
+ );
451
+ DefaultItemRenderer.displayName = "DefaultItemRenderer";
452
+ MentionList.displayName = "MentionList";
453
+ function updatePopupPosition(editor, element) {
454
+ const virtualElement = {
455
+ getBoundingClientRect: () => posToDOMRect(
456
+ editor.view,
457
+ editor.state.selection.from,
458
+ editor.state.selection.to
459
+ )
460
+ };
461
+ computePosition(virtualElement, element, {
462
+ placement: "bottom-start",
463
+ strategy: "absolute",
464
+ middleware: [shift(), flip()]
465
+ }).then(({ x, y, strategy }) => {
466
+ element.style.width = "max-content";
467
+ element.style.position = strategy;
468
+ element.style.left = `${x}px`;
469
+ element.style.top = `${y}px`;
470
+ });
471
+ }
472
+ function createSuggestionConfig(config, triggerChar, suggestionActiveRef) {
473
+ return {
474
+ char: triggerChar,
475
+ allowSpaces: false,
476
+ // Fetch and filter suggestion items based on query
477
+ items: async ({ query }) => {
478
+ if (config.onSearch) {
479
+ return await config.onSearch(query);
480
+ }
481
+ if (!config.items) return [];
482
+ if (!query) return config.items.slice(0, config.maxResults || 10);
483
+ const lowerQuery = query.toLowerCase();
484
+ return config.items.filter(
485
+ (item) => item.label.toLowerCase().includes(lowerQuery) || item.description?.toLowerCase().includes(lowerQuery)
486
+ ).slice(0, config.maxResults || 10);
487
+ },
488
+ // Render callbacks for managing the popup lifecycle
489
+ render: () => {
490
+ let component = null;
491
+ return {
492
+ // Called when suggestion is triggered
493
+ onStart: (props) => {
494
+ suggestionActiveRef.current = true;
495
+ component = new ReactRenderer(MentionList, {
496
+ props: {
497
+ ...props,
498
+ triggerChar,
499
+ config
500
+ },
501
+ editor: props.editor
502
+ });
503
+ if (!props.clientRect) {
504
+ return;
505
+ }
506
+ component.element.style.position = "absolute";
507
+ document.body.appendChild(component.element);
508
+ updatePopupPosition(props.editor, component.element);
509
+ },
510
+ // Called when query or items change
511
+ onUpdate: (props) => {
512
+ component?.updateProps({
513
+ ...props,
514
+ triggerChar,
515
+ config
516
+ });
517
+ if (!props.clientRect) {
518
+ return;
519
+ }
520
+ if (component?.element) {
521
+ updatePopupPosition(props.editor, component.element);
522
+ }
523
+ },
524
+ // Handle keyboard navigation (Escape closes popup)
525
+ onKeyDown: (props) => {
526
+ if (props.event.key === "Escape") {
527
+ component?.destroy();
528
+ return true;
529
+ }
530
+ return component?.ref?.onKeyDown(props) ?? false;
531
+ },
532
+ // Cleanup when suggestion is dismissed
533
+ onExit: () => {
534
+ suggestionActiveRef.current = false;
535
+ component?.element?.remove();
536
+ component?.destroy();
537
+ }
538
+ };
539
+ }
540
+ };
541
+ }
542
+ const RichTextInput = forwardRef(
543
+ ({
544
+ value = "",
545
+ placeholder = "Type a message...",
546
+ disabled = false,
547
+ autoFocus = true,
548
+ className,
549
+ minHeight = 24,
550
+ maxHeight = 200,
551
+ mentions,
552
+ commands,
553
+ onSubmit,
554
+ onChange
555
+ }, ref) => {
556
+ const { theme } = useContext(ChatContext);
557
+ const containerRef = useRef(null);
558
+ const suggestionActiveRef = useRef(false);
559
+ const extensions = useMemo(() => {
560
+ const exts = [
561
+ Document,
562
+ Paragraph.configure({
563
+ HTMLAttributes: {
564
+ class: "tiptap-paragraph"
565
+ }
566
+ }),
567
+ Text,
568
+ HardBreak,
569
+ Placeholder.configure({
570
+ placeholder,
571
+ emptyEditorClass: "is-editor-empty"
572
+ })
573
+ ];
574
+ if (mentions) {
575
+ exts.push(
576
+ Mention.configure({
577
+ HTMLAttributes: {
578
+ class: cn(theme?.input?.tag?.base, theme?.input?.tag?.mention)
579
+ },
580
+ suggestion: createSuggestionConfig(
581
+ mentions,
582
+ mentions.trigger || "@",
583
+ suggestionActiveRef
584
+ )
585
+ }).extend({
586
+ name: "mention"
587
+ })
588
+ );
589
+ }
590
+ if (commands) {
591
+ exts.push(
592
+ Mention.configure({
593
+ HTMLAttributes: {
594
+ class: cn(theme?.input?.tag?.base, theme?.input?.tag?.command)
595
+ },
596
+ suggestion: createSuggestionConfig(
597
+ commands,
598
+ commands.trigger || "/",
599
+ suggestionActiveRef
600
+ )
601
+ }).extend({
602
+ name: "command"
603
+ })
604
+ );
605
+ }
606
+ return exts;
607
+ }, [placeholder, mentions, commands, theme]);
608
+ const editor = useEditor({
609
+ extensions,
610
+ content: value ? `<p>${value}</p>` : "",
611
+ editable: !disabled,
612
+ immediatelyRender: false,
613
+ onUpdate: ({ editor: editor2 }) => {
614
+ const text = editor2.getText();
615
+ onChange?.(text);
616
+ },
617
+ editorProps: {
618
+ attributes: {
619
+ class: cn(
620
+ theme?.input?.editor?.base,
621
+ theme?.input?.editor?.placeholder
622
+ ),
623
+ style: `min-height: ${minHeight}px; max-height: ${maxHeight}px;`,
624
+ role: "textbox",
625
+ "aria-multiline": "true",
626
+ "aria-placeholder": placeholder,
627
+ "aria-disabled": disabled ? "true" : "false",
628
+ tabindex: disabled ? "-1" : "0"
629
+ },
630
+ handleKeyDown: (view, event) => {
631
+ if (suggestionActiveRef.current) {
632
+ return false;
633
+ }
634
+ if (event.key === "Enter" && !event.shiftKey) {
635
+ const text = view.state.doc.textContent;
636
+ if (text.trim() && onSubmit) {
637
+ event.preventDefault();
638
+ onSubmit(text);
639
+ editor?.commands.clearContent();
640
+ return true;
641
+ }
642
+ }
643
+ return false;
644
+ }
645
+ }
646
+ });
647
+ useEffect(() => {
648
+ if (autoFocus && editor) {
649
+ setTimeout(() => {
650
+ editor.commands.focus("end");
651
+ }, 0);
652
+ }
653
+ }, [editor, autoFocus]);
654
+ useImperativeHandle(ref, () => ({
655
+ focus: () => {
656
+ editor?.commands.focus();
657
+ },
658
+ getValue: () => {
659
+ return editor?.getText() || "";
660
+ },
661
+ setValue: (newValue) => {
662
+ editor?.commands.setContent(newValue ? `<p>${newValue}</p>` : "");
663
+ },
664
+ insertText: (text) => {
665
+ editor?.commands.insertContent(text);
666
+ }
667
+ }));
668
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cn("relative w-full", className), children: /* @__PURE__ */ jsx(EditorContent, { editor }) });
669
+ }
670
+ );
671
+ RichTextInput.displayName = "RichTextInput";
672
+ const ChatInput = forwardRef(
673
+ ({
674
+ allowedFiles,
675
+ placeholder = "Type a message...",
676
+ allowMultipleFiles = false,
677
+ defaultValue,
678
+ className,
679
+ sendIcon = /* @__PURE__ */ jsx(SvgSend, {}),
680
+ stopIcon = /* @__PURE__ */ jsx(SvgStop, {}),
681
+ attachIcon,
682
+ mentions,
683
+ commands,
684
+ minHeight = 24,
685
+ maxHeight = 200,
686
+ autoFocus = true,
687
+ onMessageChange
688
+ }, ref) => {
689
+ const {
690
+ theme,
691
+ isLoading,
692
+ disabled,
693
+ sendMessage,
694
+ stopMessage,
695
+ fileUpload,
696
+ activeSessionId
697
+ } = useContext(ChatContext);
698
+ const [message, setMessage] = useState(defaultValue || "");
699
+ const inputRef = useRef(null);
700
+ const containerRef = useRef(null);
701
+ useEffect(() => {
702
+ if (autoFocus) {
703
+ inputRef.current?.focus();
704
+ }
705
+ }, [activeSessionId, autoFocus]);
706
+ useImperativeHandle(ref, () => ({
707
+ focus: () => {
708
+ inputRef.current?.focus();
709
+ },
710
+ getValue: () => {
711
+ return inputRef.current?.getValue() || "";
712
+ },
713
+ setValue: (value) => {
714
+ setMessage(value);
715
+ inputRef.current?.setValue(value);
716
+ onMessageChange?.(value);
717
+ },
718
+ insertText: (text) => {
719
+ inputRef.current?.insertText(text);
720
+ }
721
+ }));
722
+ const handleSendMessage = useCallback(() => {
723
+ const currentMessage = inputRef.current?.getValue();
724
+ if (currentMessage.trim()) {
725
+ sendMessage?.(currentMessage);
726
+ setMessage("");
727
+ inputRef.current?.setValue("");
728
+ }
729
+ }, [sendMessage]);
730
+ const handleSubmit = useCallback(
731
+ (value) => {
732
+ if (value.trim()) {
733
+ sendMessage?.(value);
734
+ setMessage("");
735
+ }
736
+ },
737
+ [sendMessage]
738
+ );
739
+ const handleChange = useCallback(
740
+ (value) => {
741
+ setMessage(value);
742
+ onMessageChange?.(value);
743
+ },
744
+ [onMessageChange]
745
+ );
746
+ const handleFileUpload = (event) => {
747
+ const files = event.target.files;
748
+ if (files?.length && fileUpload) {
749
+ fileUpload(allowMultipleFiles ? Array.from(files) : files[0]);
750
+ }
751
+ };
752
+ const mentionsConfig = useMemo(
753
+ () => mentions ? { ...mentions, trigger: mentions.trigger || "@" } : void 0,
754
+ [mentions]
755
+ );
756
+ const commandsConfig = useMemo(
757
+ () => commands ? { ...commands, trigger: commands.trigger || "/" } : void 0,
758
+ [commands]
759
+ );
760
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cn(theme.input.base, className), children: /* @__PURE__ */ jsxs("div", { className: cn("relative flex-1", theme.input.input), children: [
761
+ /* @__PURE__ */ jsx(
762
+ RichTextInput,
763
+ {
764
+ ref: inputRef,
765
+ value: message,
766
+ onChange: handleChange,
767
+ onSubmit: handleSubmit,
768
+ placeholder,
769
+ disabled: isLoading || disabled,
770
+ autoFocus,
771
+ minHeight,
772
+ maxHeight,
773
+ className: theme.input.editor.container,
774
+ mentions: mentionsConfig,
775
+ commands: commandsConfig
776
+ }
777
+ ),
778
+ /* @__PURE__ */ jsxs("div", { className: cn(theme.input.actions.base), children: [
779
+ allowedFiles?.length > 0 && /* @__PURE__ */ jsx(
780
+ FileInput,
781
+ {
782
+ allowedFiles,
783
+ multiple: allowMultipleFiles,
784
+ onFileUpload: handleFileUpload,
785
+ isLoading,
786
+ disabled,
787
+ attachIcon
788
+ }
789
+ ),
790
+ isLoading && /* @__PURE__ */ jsx(
791
+ Button,
792
+ {
793
+ title: "Stop",
794
+ className: cn(theme.input.actions.stop),
795
+ onClick: stopMessage,
796
+ disabled,
797
+ children: stopIcon
798
+ }
799
+ ),
800
+ /* @__PURE__ */ jsx(
801
+ Button,
802
+ {
803
+ title: "Send",
804
+ className: cn(theme.input.actions.send),
805
+ onClick: handleSendMessage,
806
+ disabled: isLoading || disabled,
807
+ children: sendIcon
808
+ }
809
+ )
810
+ ] })
811
+ ] }) });
812
+ }
813
+ );
814
+ const SessionEmpty = ({
815
+ children
816
+ }) => {
817
+ const { theme } = useContext(ChatContext);
818
+ return /* @__PURE__ */ jsx("div", { className: cn(theme.empty), children });
819
+ };
820
+ const SessionMessagesHeader = ({ children }) => {
821
+ const { activeSession, theme } = useContext(ChatContext);
822
+ const Comp = children ? Slot : "header";
823
+ if (!activeSession) {
824
+ return null;
825
+ }
826
+ return /* @__PURE__ */ jsx(Comp, { className: cn(theme.messages.header), children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
827
+ /* @__PURE__ */ jsx("h2", { className: cn(theme.messages.title), children: /* @__PURE__ */ jsx(Ellipsis, { limit: 125, value: activeSession.title }) }),
828
+ /* @__PURE__ */ jsx(
829
+ DateFormat,
830
+ {
831
+ className: cn(theme.messages.date),
832
+ date: activeSession.createdAt
833
+ }
834
+ )
835
+ ] }) });
836
+ };
837
+ const SvgBack = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-chevron-left", ...props }, /* @__PURE__ */ React.createElement("path", { d: "m15 18-6-6 6-6" }));
838
+ const SessionMessagePanel = ({
839
+ children,
840
+ allowBack = true
841
+ }) => {
842
+ const { activeSessionId, theme, isCompact, selectSession, viewType } = useContext(ChatContext);
843
+ const isVisible = isCompact && activeSessionId || viewType === "chat" || !isCompact;
844
+ return isVisible && /* @__PURE__ */ jsx(
845
+ motion.div,
846
+ {
847
+ initial: { translateX: "200%" },
848
+ animate: {
849
+ translateX: "0%",
850
+ transition: {
851
+ type: "tween",
852
+ ease: "linear",
853
+ duration: 0.2,
854
+ when: "beforeChildren"
855
+ }
856
+ },
857
+ exit: { translateX: "200%" },
858
+ className: cn(theme.messages.base, {
859
+ [theme.messages.companion]: isCompact,
860
+ [theme.messages.console]: !isCompact
861
+ }),
862
+ children: /* @__PURE__ */ jsxs("div", { className: cn(theme.messages.inner), children: [
863
+ allowBack && isCompact && viewType !== "chat" && /* @__PURE__ */ jsxs(
864
+ Button,
865
+ {
866
+ variant: "text",
867
+ size: "small",
868
+ onClick: () => selectSession(null),
869
+ className: cn(theme.messages.back),
870
+ children: [
871
+ /* @__PURE__ */ jsx(SvgBack, {}),
872
+ "Back"
873
+ ]
874
+ }
875
+ ),
876
+ children
877
+ ] })
878
+ }
879
+ );
880
+ };
881
+ const SvgCopy = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-copy", ...props }, /* @__PURE__ */ React.createElement("rect", { width: 14, height: 14, x: 8, y: 8, rx: 2, ry: 2 }), /* @__PURE__ */ React.createElement("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" }));
882
+ const dark = {
883
+ 'code[class*="language-"]': {
884
+ "background": "#11111f",
885
+ "color": "#e2e8f0",
886
+ "textShadow": "0 1px rgba(0, 0, 0, 0.3)",
887
+ "fontFamily": '"Fira Code", "Fira Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace',
888
+ "direction": "ltr",
889
+ "textAlign": "left",
890
+ "whiteSpace": "pre",
891
+ "wordSpacing": "normal",
892
+ "wordBreak": "normal",
893
+ "lineHeight": "1.5",
894
+ "MozTabSize": "2",
895
+ "OTabSize": "2",
896
+ "tabSize": "2",
897
+ "WebkitHyphens": "none",
898
+ "MozHyphens": "none",
899
+ "msHyphens": "none",
900
+ "hyphens": "none"
901
+ },
902
+ 'pre[class*="language-"]': {
903
+ "background": "#11111f",
904
+ "color": "#e2e8f0",
905
+ "textShadow": "0 1px rgba(0, 0, 0, 0.3)",
906
+ "fontFamily": '"Fira Code", "Fira Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace',
907
+ "direction": "ltr",
908
+ "textAlign": "left",
909
+ "whiteSpace": "pre",
910
+ "wordSpacing": "normal",
911
+ "wordBreak": "normal",
912
+ "lineHeight": "1.5",
913
+ "MozTabSize": "2",
914
+ "OTabSize": "2",
915
+ "tabSize": "2",
916
+ "WebkitHyphens": "none",
917
+ "MozHyphens": "none",
918
+ "msHyphens": "none",
919
+ "hyphens": "none",
920
+ "padding": "1em",
921
+ "margin": "0",
922
+ "overflow": "auto"
923
+ },
924
+ 'code[class*="language-"]::-moz-selection': {
925
+ "background": "#1e293b",
926
+ "color": "inherit",
927
+ "textShadow": "none"
928
+ },
929
+ 'code[class*="language-"] *::-moz-selection': {
930
+ "background": "#1e293b",
931
+ "color": "inherit",
932
+ "textShadow": "none"
933
+ },
934
+ 'pre[class*="language-"] *::-moz-selection': {
935
+ "background": "#1e293b",
936
+ "color": "inherit",
937
+ "textShadow": "none"
938
+ },
939
+ 'code[class*="language-"]::selection': {
940
+ "background": "#1e293b",
941
+ "color": "inherit",
942
+ "textShadow": "none"
943
+ },
944
+ 'code[class*="language-"] *::selection': {
945
+ "background": "#1e293b",
946
+ "color": "inherit",
947
+ "textShadow": "none"
948
+ },
949
+ 'pre[class*="language-"] *::selection': {
950
+ "background": "#1e293b",
951
+ "color": "inherit",
952
+ "textShadow": "none"
953
+ },
954
+ ':not(pre) > code[class*="language-"]': {
955
+ "padding": "0.2em 0.3em",
956
+ "borderRadius": "0.3em",
957
+ "whiteSpace": "normal"
958
+ },
959
+ "comment": {
960
+ "color": "#64748b",
961
+ "fontStyle": "italic"
962
+ },
963
+ "prolog": {
964
+ "color": "#64748b"
965
+ },
966
+ "cdata": {
967
+ "color": "#64748b"
968
+ },
969
+ "doctype": {
970
+ "color": "#e2e8f0"
971
+ },
972
+ "punctuation": {
973
+ "color": "#e2e8f0"
974
+ },
975
+ "entity": {
976
+ "color": "#3b82f6",
977
+ "cursor": "help"
978
+ },
979
+ "attr-name": {
980
+ "color": "#f59e0b"
981
+ },
982
+ "class-name": {
983
+ "color": "#f59e0b"
984
+ },
985
+ "boolean": {
986
+ "color": "#3b82f6"
987
+ },
988
+ "constant": {
989
+ "color": "#3b82f6"
990
+ },
991
+ "number": {
992
+ "color": "#3b82f6"
993
+ },
994
+ "atrule": {
995
+ "color": "#f59e0b"
996
+ },
997
+ "keyword": {
998
+ "color": "#f472b6"
999
+ },
1000
+ "property": {
1001
+ "color": "#3b82f6"
1002
+ },
1003
+ "tag": {
1004
+ "color": "#3b82f6"
1005
+ },
1006
+ "symbol": {
1007
+ "color": "#3b82f6"
1008
+ },
1009
+ "deleted": {
1010
+ "color": "#ef4444"
1011
+ },
1012
+ "important": {
1013
+ "color": "#f472b6"
1014
+ },
1015
+ "selector": {
1016
+ "color": "#10b981"
1017
+ },
1018
+ "string": {
1019
+ "color": "#10b981"
1020
+ },
1021
+ "char": {
1022
+ "color": "#10b981"
1023
+ },
1024
+ "builtin": {
1025
+ "color": "#10b981"
1026
+ },
1027
+ "inserted": {
1028
+ "color": "#10b981"
1029
+ },
1030
+ "regex": {
1031
+ "color": "#10b981"
1032
+ },
1033
+ "attr-value": {
1034
+ "color": "#10b981"
1035
+ },
1036
+ "attr-value > .token.punctuation": {
1037
+ "color": "#10b981"
1038
+ },
1039
+ "variable": {
1040
+ "color": "#60a5fa"
1041
+ },
1042
+ "operator": {
1043
+ "color": "#60a5fa"
1044
+ },
1045
+ "function": {
1046
+ "color": "#60a5fa"
1047
+ },
1048
+ "url": {
1049
+ "color": "#60a5fa"
1050
+ },
1051
+ "attr-value > .token.punctuation.attr-equals": {
1052
+ "color": "#e2e8f0"
1053
+ },
1054
+ "special-attr > .token.attr-value > .token.value.css": {
1055
+ "color": "#e2e8f0"
1056
+ },
1057
+ ".language-css .token.selector": {
1058
+ "color": "#3b82f6"
1059
+ },
1060
+ ".language-css .token.property": {
1061
+ "color": "#e2e8f0"
1062
+ },
1063
+ ".language-css .token.function": {
1064
+ "color": "#60a5fa"
1065
+ },
1066
+ ".language-css .token.url > .token.function": {
1067
+ "color": "#60a5fa"
1068
+ },
1069
+ ".language-css .token.url > .token.string.url": {
1070
+ "color": "#10b981"
1071
+ },
1072
+ ".language-css .token.important": {
1073
+ "color": "#f472b6"
1074
+ },
1075
+ ".language-css .token.atrule .token.rule": {
1076
+ "color": "#f472b6"
1077
+ },
1078
+ ".language-javascript .token.operator": {
1079
+ "color": "#f472b6"
1080
+ },
1081
+ ".language-javascript .token.template-string > .token.interpolation > .token.interpolation-punctuation.punctuation": {
1082
+ "color": "#ef4444"
1083
+ },
1084
+ ".language-json .token.operator": {
1085
+ "color": "#e2e8f0"
1086
+ },
1087
+ ".language-json .token.null.keyword": {
1088
+ "color": "#3b82f6"
1089
+ },
1090
+ ".language-markdown .token.url": {
1091
+ "color": "#e2e8f0"
1092
+ },
1093
+ ".language-markdown .token.url > .token.operator": {
1094
+ "color": "#e2e8f0"
1095
+ },
1096
+ ".language-markdown .token.url-reference.url > .token.string": {
1097
+ "color": "#e2e8f0"
1098
+ },
1099
+ ".language-markdown .token.url > .token.content": {
1100
+ "color": "#60a5fa"
1101
+ },
1102
+ ".language-markdown .token.url > .token.url": {
1103
+ "color": "#60a5fa"
1104
+ },
1105
+ ".language-markdown .token.url-reference.url": {
1106
+ "color": "#60a5fa"
1107
+ },
1108
+ ".language-markdown .token.blockquote.punctuation": {
1109
+ "color": "#64748b",
1110
+ "fontStyle": "italic"
1111
+ },
1112
+ ".language-markdown .token.hr.punctuation": {
1113
+ "color": "#64748b",
1114
+ "fontStyle": "italic"
1115
+ },
1116
+ ".language-markdown .token.code-snippet": {
1117
+ "color": "#10b981"
1118
+ },
1119
+ ".language-markdown .token.bold .token.content": {
1120
+ "color": "#f59e0b"
1121
+ },
1122
+ ".language-markdown .token.italic .token.content": {
1123
+ "color": "#f472b6"
1124
+ },
1125
+ ".language-markdown .token.strike .token.content": {
1126
+ "color": "#3b82f6"
1127
+ },
1128
+ ".language-markdown .token.strike .token.punctuation": {
1129
+ "color": "#3b82f6"
1130
+ },
1131
+ ".language-markdown .token.list.punctuation": {
1132
+ "color": "#3b82f6"
1133
+ },
1134
+ ".language-markdown .token.title.important > .token.punctuation": {
1135
+ "color": "#3b82f6"
1136
+ },
1137
+ "bold": {
1138
+ "fontWeight": "bold"
1139
+ },
1140
+ "italic": {
1141
+ "fontStyle": "italic"
1142
+ },
1143
+ "namespace": {
1144
+ "Opacity": "0.8"
1145
+ },
1146
+ "token.tab:not(:empty):before": {
1147
+ "color": "#64748b",
1148
+ "textShadow": "none"
1149
+ },
1150
+ "token.cr:before": {
1151
+ "color": "#64748b",
1152
+ "textShadow": "none"
1153
+ },
1154
+ "token.lf:before": {
1155
+ "color": "#64748b",
1156
+ "textShadow": "none"
1157
+ },
1158
+ "token.space:before": {
1159
+ "color": "#64748b",
1160
+ "textShadow": "none"
1161
+ },
1162
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item": {
1163
+ "marginRight": "0.4em"
1164
+ },
1165
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > button": {
1166
+ "background": "#1e293b",
1167
+ "color": "#94a3b8",
1168
+ "padding": "0.1em 0.4em",
1169
+ "borderRadius": "0.3em"
1170
+ },
1171
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > a": {
1172
+ "background": "#1e293b",
1173
+ "color": "#94a3b8",
1174
+ "padding": "0.1em 0.4em",
1175
+ "borderRadius": "0.3em"
1176
+ },
1177
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > span": {
1178
+ "background": "#1e293b",
1179
+ "color": "#94a3b8",
1180
+ "padding": "0.1em 0.4em",
1181
+ "borderRadius": "0.3em"
1182
+ },
1183
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover": {
1184
+ "background": "#3b82f6",
1185
+ "color": "#ffffff"
1186
+ },
1187
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus": {
1188
+ "background": "#3b82f6",
1189
+ "color": "#ffffff"
1190
+ },
1191
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover": {
1192
+ "background": "#3b82f6",
1193
+ "color": "#ffffff"
1194
+ },
1195
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus": {
1196
+ "background": "#3b82f6",
1197
+ "color": "#ffffff"
1198
+ },
1199
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover": {
1200
+ "background": "#3b82f6",
1201
+ "color": "#ffffff"
1202
+ },
1203
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus": {
1204
+ "background": "#3b82f6",
1205
+ "color": "#ffffff"
1206
+ },
1207
+ ".line-highlight.line-highlight": {
1208
+ "background": "rgba(59, 130, 246, 0.08)"
1209
+ },
1210
+ ".line-highlight.line-highlight:before": {
1211
+ "background": "#1e293b",
1212
+ "color": "#e2e8f0",
1213
+ "padding": "0.1em 0.6em",
1214
+ "borderRadius": "0.3em",
1215
+ "boxShadow": "0 2px 0 0 rgba(0, 0, 0, 0.2)"
1216
+ },
1217
+ ".line-highlight.line-highlight[data-end]:after": {
1218
+ "background": "#1e293b",
1219
+ "color": "#e2e8f0",
1220
+ "padding": "0.1em 0.6em",
1221
+ "borderRadius": "0.3em",
1222
+ "boxShadow": "0 2px 0 0 rgba(0, 0, 0, 0.2)"
1223
+ },
1224
+ "pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before": {
1225
+ "backgroundColor": "rgba(59, 130, 246, 0.08)"
1226
+ },
1227
+ ".line-numbers.line-numbers .line-numbers-rows": {
1228
+ "borderRightColor": "#1e293b"
1229
+ },
1230
+ ".command-line .command-line-prompt": {
1231
+ "borderRightColor": "#1e293b"
1232
+ },
1233
+ ".line-numbers .line-numbers-rows > span:before": {
1234
+ "color": "#64748b"
1235
+ },
1236
+ ".command-line .command-line-prompt > span:before": {
1237
+ "color": "#64748b"
1238
+ },
1239
+ ".rainbow-braces .token.token.punctuation.brace-level-1": {
1240
+ "color": "#3b82f6"
1241
+ },
1242
+ ".rainbow-braces .token.token.punctuation.brace-level-5": {
1243
+ "color": "#3b82f6"
1244
+ },
1245
+ ".rainbow-braces .token.token.punctuation.brace-level-9": {
1246
+ "color": "#3b82f6"
1247
+ },
1248
+ ".rainbow-braces .token.token.punctuation.brace-level-2": {
1249
+ "color": "#10b981"
1250
+ },
1251
+ ".rainbow-braces .token.token.punctuation.brace-level-6": {
1252
+ "color": "#10b981"
1253
+ },
1254
+ ".rainbow-braces .token.token.punctuation.brace-level-10": {
1255
+ "color": "#10b981"
1256
+ },
1257
+ ".rainbow-braces .token.token.punctuation.brace-level-3": {
1258
+ "color": "#60a5fa"
1259
+ },
1260
+ ".rainbow-braces .token.token.punctuation.brace-level-7": {
1261
+ "color": "#60a5fa"
1262
+ },
1263
+ ".rainbow-braces .token.token.punctuation.brace-level-11": {
1264
+ "color": "#60a5fa"
1265
+ },
1266
+ ".rainbow-braces .token.token.punctuation.brace-level-4": {
1267
+ "color": "#f472b6"
1268
+ },
1269
+ ".rainbow-braces .token.token.punctuation.brace-level-8": {
1270
+ "color": "#f472b6"
1271
+ },
1272
+ ".rainbow-braces .token.token.punctuation.brace-level-12": {
1273
+ "color": "#f472b6"
1274
+ },
1275
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix)": {
1276
+ "backgroundColor": "rgba(239, 68, 68, 0.15)"
1277
+ },
1278
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix)": {
1279
+ "backgroundColor": "rgba(239, 68, 68, 0.15)"
1280
+ },
1281
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix)::-moz-selection": {
1282
+ "backgroundColor": "rgba(239, 68, 68, 0.25)"
1283
+ },
1284
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix) *::-moz-selection": {
1285
+ "backgroundColor": "rgba(239, 68, 68, 0.25)"
1286
+ },
1287
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix)::-moz-selection": {
1288
+ "backgroundColor": "rgba(239, 68, 68, 0.25)"
1289
+ },
1290
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix) *::-moz-selection": {
1291
+ "backgroundColor": "rgba(239, 68, 68, 0.25)"
1292
+ },
1293
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix)::selection": {
1294
+ "backgroundColor": "rgba(239, 68, 68, 0.25)"
1295
+ },
1296
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix) *::selection": {
1297
+ "backgroundColor": "rgba(239, 68, 68, 0.25)"
1298
+ },
1299
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix)::selection": {
1300
+ "backgroundColor": "rgba(239, 68, 68, 0.25)"
1301
+ },
1302
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix) *::selection": {
1303
+ "backgroundColor": "rgba(239, 68, 68, 0.25)"
1304
+ },
1305
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix)": {
1306
+ "backgroundColor": "rgba(16, 185, 129, 0.15)"
1307
+ },
1308
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix)": {
1309
+ "backgroundColor": "rgba(16, 185, 129, 0.15)"
1310
+ },
1311
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix)::-moz-selection": {
1312
+ "backgroundColor": "rgba(16, 185, 129, 0.25)"
1313
+ },
1314
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix) *::-moz-selection": {
1315
+ "backgroundColor": "rgba(16, 185, 129, 0.25)"
1316
+ },
1317
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix)::-moz-selection": {
1318
+ "backgroundColor": "rgba(16, 185, 129, 0.25)"
1319
+ },
1320
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix) *::-moz-selection": {
1321
+ "backgroundColor": "rgba(16, 185, 129, 0.25)"
1322
+ },
1323
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix)::selection": {
1324
+ "backgroundColor": "rgba(16, 185, 129, 0.25)"
1325
+ },
1326
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix) *::selection": {
1327
+ "backgroundColor": "rgba(16, 185, 129, 0.25)"
1328
+ },
1329
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix)::selection": {
1330
+ "backgroundColor": "rgba(16, 185, 129, 0.25)"
1331
+ },
1332
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix) *::selection": {
1333
+ "backgroundColor": "rgba(16, 185, 129, 0.25)"
1334
+ },
1335
+ ".prism-previewer.prism-previewer:before": {
1336
+ "borderColor": "#11111f"
1337
+ },
1338
+ ".prism-previewer-gradient.prism-previewer-gradient div": {
1339
+ "borderColor": "#11111f",
1340
+ "borderRadius": "0.3em"
1341
+ },
1342
+ ".prism-previewer-color.prism-previewer-color:before": {
1343
+ "borderRadius": "0.3em"
1344
+ },
1345
+ ".prism-previewer-easing.prism-previewer-easing:before": {
1346
+ "borderRadius": "0.3em"
1347
+ },
1348
+ ".prism-previewer.prism-previewer:after": {
1349
+ "borderTopColor": "#11111f"
1350
+ },
1351
+ ".prism-previewer-flipped.prism-previewer-flipped.after": {
1352
+ "borderBottomColor": "#11111f"
1353
+ },
1354
+ ".prism-previewer-angle.prism-previewer-angle:before": {
1355
+ "background": "#1e293b"
1356
+ },
1357
+ ".prism-previewer-time.prism-previewer-time:before": {
1358
+ "background": "#1e293b"
1359
+ },
1360
+ ".prism-previewer-easing.prism-previewer-easing": {
1361
+ "background": "#1e293b"
1362
+ },
1363
+ ".prism-previewer-angle.prism-previewer-angle circle": {
1364
+ "stroke": "#e2e8f0",
1365
+ "strokeOpacity": "1"
1366
+ },
1367
+ ".prism-previewer-time.prism-previewer-time circle": {
1368
+ "stroke": "#e2e8f0",
1369
+ "strokeOpacity": "1"
1370
+ },
1371
+ ".prism-previewer-easing.prism-previewer-easing circle": {
1372
+ "stroke": "#e2e8f0",
1373
+ "fill": "transparent"
1374
+ },
1375
+ ".prism-previewer-easing.prism-previewer-easing path": {
1376
+ "stroke": "#e2e8f0"
1377
+ },
1378
+ ".prism-previewer-easing.prism-previewer-easing line": {
1379
+ "stroke": "#e2e8f0"
1380
+ }
1381
+ };
1382
+ const light = {
1383
+ 'code[class*="language-"]': {
1384
+ "background": "#fff",
1385
+ "color": "#1e293b",
1386
+ "textShadow": "none",
1387
+ "fontFamily": '"Fira Code", "Fira Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace',
1388
+ "direction": "ltr",
1389
+ "textAlign": "left",
1390
+ "whiteSpace": "pre",
1391
+ "wordSpacing": "normal",
1392
+ "wordBreak": "normal",
1393
+ "lineHeight": "1.5",
1394
+ "MozTabSize": "2",
1395
+ "OTabSize": "2",
1396
+ "tabSize": "2",
1397
+ "WebkitHyphens": "none",
1398
+ "MozHyphens": "none",
1399
+ "msHyphens": "none",
1400
+ "hyphens": "none"
1401
+ },
1402
+ 'pre[class*="language-"]': {
1403
+ "background": "#fff",
1404
+ "color": "#1e293b",
1405
+ "textShadow": "none",
1406
+ "fontFamily": '"Fira Code", "Fira Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace',
1407
+ "direction": "ltr",
1408
+ "textAlign": "left",
1409
+ "whiteSpace": "pre",
1410
+ "wordSpacing": "normal",
1411
+ "wordBreak": "normal",
1412
+ "lineHeight": "1.5",
1413
+ "MozTabSize": "2",
1414
+ "OTabSize": "2",
1415
+ "tabSize": "2",
1416
+ "WebkitHyphens": "none",
1417
+ "MozHyphens": "none",
1418
+ "msHyphens": "none",
1419
+ "hyphens": "none",
1420
+ "padding": "1em",
1421
+ "margin": "0.5em 0",
1422
+ "overflow": "auto",
1423
+ "borderRadius": "0.3em",
1424
+ "border": "1px solid #e2e8f0"
1425
+ },
1426
+ 'code[class*="language-"]::-moz-selection': {
1427
+ "background": "#e2e8f0",
1428
+ "color": "inherit",
1429
+ "textShadow": "none"
1430
+ },
1431
+ 'code[class*="language-"] *::-moz-selection': {
1432
+ "background": "#e2e8f0",
1433
+ "color": "inherit",
1434
+ "textShadow": "none"
1435
+ },
1436
+ 'pre[class*="language-"] *::-moz-selection': {
1437
+ "background": "#e2e8f0",
1438
+ "color": "inherit",
1439
+ "textShadow": "none"
1440
+ },
1441
+ 'code[class*="language-"]::selection': {
1442
+ "background": "#e2e8f0",
1443
+ "color": "inherit",
1444
+ "textShadow": "none"
1445
+ },
1446
+ 'code[class*="language-"] *::selection': {
1447
+ "background": "#e2e8f0",
1448
+ "color": "inherit",
1449
+ "textShadow": "none"
1450
+ },
1451
+ 'pre[class*="language-"] *::selection': {
1452
+ "background": "#e2e8f0",
1453
+ "color": "inherit",
1454
+ "textShadow": "none"
1455
+ },
1456
+ ':not(pre) > code[class*="language-"]': {
1457
+ "padding": "0.2em 0.3em",
1458
+ "borderRadius": "0.3em",
1459
+ "whiteSpace": "normal",
1460
+ "background": "#f1f5f9"
1461
+ },
1462
+ "comment": {
1463
+ "color": "#64748b",
1464
+ "fontStyle": "italic"
1465
+ },
1466
+ "prolog": {
1467
+ "color": "#64748b"
1468
+ },
1469
+ "cdata": {
1470
+ "color": "#64748b"
1471
+ },
1472
+ "doctype": {
1473
+ "color": "#1e293b"
1474
+ },
1475
+ "punctuation": {
1476
+ "color": "#64748b"
1477
+ },
1478
+ "entity": {
1479
+ "color": "#3b82f6",
1480
+ "cursor": "help"
1481
+ },
1482
+ "attr-name": {
1483
+ "color": "#ea580c"
1484
+ },
1485
+ "class-name": {
1486
+ "color": "#ea580c"
1487
+ },
1488
+ "boolean": {
1489
+ "color": "#3b82f6"
1490
+ },
1491
+ "constant": {
1492
+ "color": "#3b82f6"
1493
+ },
1494
+ "number": {
1495
+ "color": "#3b82f6"
1496
+ },
1497
+ "atrule": {
1498
+ "color": "#ea580c"
1499
+ },
1500
+ "keyword": {
1501
+ "color": "#9333ea"
1502
+ },
1503
+ "property": {
1504
+ "color": "#3b82f6"
1505
+ },
1506
+ "tag": {
1507
+ "color": "#3b82f6"
1508
+ },
1509
+ "symbol": {
1510
+ "color": "#3b82f6"
1511
+ },
1512
+ "deleted": {
1513
+ "color": "#dc2626"
1514
+ },
1515
+ "important": {
1516
+ "color": "#9333ea"
1517
+ },
1518
+ "selector": {
1519
+ "color": "#16a34a"
1520
+ },
1521
+ "string": {
1522
+ "color": "#16a34a"
1523
+ },
1524
+ "char": {
1525
+ "color": "#16a34a"
1526
+ },
1527
+ "builtin": {
1528
+ "color": "#16a34a"
1529
+ },
1530
+ "inserted": {
1531
+ "color": "#16a34a"
1532
+ },
1533
+ "regex": {
1534
+ "color": "#16a34a"
1535
+ },
1536
+ "attr-value": {
1537
+ "color": "#16a34a"
1538
+ },
1539
+ "attr-value > .token.punctuation": {
1540
+ "color": "#16a34a"
1541
+ },
1542
+ "variable": {
1543
+ "color": "#3b82f6"
1544
+ },
1545
+ "operator": {
1546
+ "color": "#3b82f6"
1547
+ },
1548
+ "function": {
1549
+ "color": "#3b82f6"
1550
+ },
1551
+ "url": {
1552
+ "color": "#3b82f6"
1553
+ },
1554
+ "attr-value > .token.punctuation.attr-equals": {
1555
+ "color": "#64748b"
1556
+ },
1557
+ "special-attr > .token.attr-value > .token.value.css": {
1558
+ "color": "#1e293b"
1559
+ },
1560
+ ".language-css .token.selector": {
1561
+ "color": "#3b82f6"
1562
+ },
1563
+ ".language-css .token.property": {
1564
+ "color": "#1e293b"
1565
+ },
1566
+ ".language-css .token.function": {
1567
+ "color": "#3b82f6"
1568
+ },
1569
+ ".language-css .token.url > .token.function": {
1570
+ "color": "#3b82f6"
1571
+ },
1572
+ ".language-css .token.url > .token.string.url": {
1573
+ "color": "#16a34a"
1574
+ },
1575
+ ".language-css .token.important": {
1576
+ "color": "#9333ea"
1577
+ },
1578
+ ".language-css .token.atrule .token.rule": {
1579
+ "color": "#9333ea"
1580
+ },
1581
+ ".language-javascript .token.operator": {
1582
+ "color": "#9333ea"
1583
+ },
1584
+ ".language-javascript .token.template-string > .token.interpolation > .token.interpolation-punctuation.punctuation": {
1585
+ "color": "#dc2626"
1586
+ },
1587
+ ".language-json .token.operator": {
1588
+ "color": "#1e293b"
1589
+ },
1590
+ ".language-json .token.null.keyword": {
1591
+ "color": "#3b82f6"
1592
+ },
1593
+ ".language-markdown .token.url": {
1594
+ "color": "#1e293b"
1595
+ },
1596
+ ".language-markdown .token.url > .token.operator": {
1597
+ "color": "#1e293b"
1598
+ },
1599
+ ".language-markdown .token.url-reference.url > .token.string": {
1600
+ "color": "#1e293b"
1601
+ },
1602
+ ".language-markdown .token.url > .token.content": {
1603
+ "color": "#3b82f6"
1604
+ },
1605
+ ".language-markdown .token.url > .token.url": {
1606
+ "color": "#3b82f6"
1607
+ },
1608
+ ".language-markdown .token.url-reference.url": {
1609
+ "color": "#3b82f6"
1610
+ },
1611
+ ".language-markdown .token.blockquote.punctuation": {
1612
+ "color": "#64748b",
1613
+ "fontStyle": "italic"
1614
+ },
1615
+ ".language-markdown .token.hr.punctuation": {
1616
+ "color": "#64748b",
1617
+ "fontStyle": "italic"
1618
+ },
1619
+ ".language-markdown .token.code-snippet": {
1620
+ "color": "#16a34a"
1621
+ },
1622
+ ".language-markdown .token.bold .token.content": {
1623
+ "color": "#ea580c"
1624
+ },
1625
+ ".language-markdown .token.italic .token.content": {
1626
+ "color": "#9333ea"
1627
+ },
1628
+ ".language-markdown .token.strike .token.content": {
1629
+ "color": "#3b82f6"
1630
+ },
1631
+ ".language-markdown .token.strike .token.punctuation": {
1632
+ "color": "#3b82f6"
1633
+ },
1634
+ ".language-markdown .token.list.punctuation": {
1635
+ "color": "#3b82f6"
1636
+ },
1637
+ ".language-markdown .token.title.important > .token.punctuation": {
1638
+ "color": "#3b82f6"
1639
+ },
1640
+ "bold": {
1641
+ "fontWeight": "bold"
1642
+ },
1643
+ "italic": {
1644
+ "fontStyle": "italic"
1645
+ },
1646
+ "namespace": {
1647
+ "Opacity": "0.8"
1648
+ },
1649
+ "token.tab:not(:empty):before": {
1650
+ "color": "#94a3b8"
1651
+ },
1652
+ "token.cr:before": {
1653
+ "color": "#94a3b8"
1654
+ },
1655
+ "token.lf:before": {
1656
+ "color": "#94a3b8"
1657
+ },
1658
+ "token.space:before": {
1659
+ "color": "#94a3b8"
1660
+ },
1661
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item": {
1662
+ "marginRight": "0.4em"
1663
+ },
1664
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > button": {
1665
+ "background": "#f1f5f9",
1666
+ "color": "#475569",
1667
+ "padding": "0.1em 0.4em",
1668
+ "borderRadius": "0.3em"
1669
+ },
1670
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > a": {
1671
+ "background": "#f1f5f9",
1672
+ "color": "#475569",
1673
+ "padding": "0.1em 0.4em",
1674
+ "borderRadius": "0.3em"
1675
+ },
1676
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > span": {
1677
+ "background": "#f1f5f9",
1678
+ "color": "#475569",
1679
+ "padding": "0.1em 0.4em",
1680
+ "borderRadius": "0.3em"
1681
+ },
1682
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover": {
1683
+ "background": "#3b82f6",
1684
+ "color": "#ffffff"
1685
+ },
1686
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus": {
1687
+ "background": "#3b82f6",
1688
+ "color": "#ffffff"
1689
+ },
1690
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover": {
1691
+ "background": "#3b82f6",
1692
+ "color": "#ffffff"
1693
+ },
1694
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus": {
1695
+ "background": "#3b82f6",
1696
+ "color": "#ffffff"
1697
+ },
1698
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover": {
1699
+ "background": "#3b82f6",
1700
+ "color": "#ffffff"
1701
+ },
1702
+ "div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus": {
1703
+ "background": "#3b82f6",
1704
+ "color": "#ffffff"
1705
+ },
1706
+ ".line-highlight.line-highlight": {
1707
+ "background": "rgba(59, 130, 246, 0.08)"
1708
+ },
1709
+ ".line-highlight.line-highlight:before": {
1710
+ "background": "#f1f5f9",
1711
+ "color": "#1e293b",
1712
+ "padding": "0.1em 0.6em",
1713
+ "borderRadius": "0.3em",
1714
+ "boxShadow": "0 2px 0 0 rgba(0, 0, 0, 0.1)"
1715
+ },
1716
+ ".line-highlight.line-highlight[data-end]:after": {
1717
+ "background": "#f1f5f9",
1718
+ "color": "#1e293b",
1719
+ "padding": "0.1em 0.6em",
1720
+ "borderRadius": "0.3em",
1721
+ "boxShadow": "0 2px 0 0 rgba(0, 0, 0, 0.1)"
1722
+ },
1723
+ "pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before": {
1724
+ "backgroundColor": "rgba(59, 130, 246, 0.08)"
1725
+ },
1726
+ ".line-numbers.line-numbers .line-numbers-rows": {
1727
+ "borderRightColor": "#e2e8f0"
1728
+ },
1729
+ ".command-line .command-line-prompt": {
1730
+ "borderRightColor": "#e2e8f0"
1731
+ },
1732
+ ".line-numbers .line-numbers-rows > span:before": {
1733
+ "color": "#94a3b8"
1734
+ },
1735
+ ".command-line .command-line-prompt > span:before": {
1736
+ "color": "#94a3b8"
1737
+ },
1738
+ ".rainbow-braces .token.token.punctuation.brace-level-1": {
1739
+ "color": "#3b82f6"
1740
+ },
1741
+ ".rainbow-braces .token.token.punctuation.brace-level-5": {
1742
+ "color": "#3b82f6"
1743
+ },
1744
+ ".rainbow-braces .token.token.punctuation.brace-level-9": {
1745
+ "color": "#3b82f6"
1746
+ },
1747
+ ".rainbow-braces .token.token.punctuation.brace-level-2": {
1748
+ "color": "#16a34a"
1749
+ },
1750
+ ".rainbow-braces .token.token.punctuation.brace-level-6": {
1751
+ "color": "#16a34a"
1752
+ },
1753
+ ".rainbow-braces .token.token.punctuation.brace-level-10": {
1754
+ "color": "#16a34a"
1755
+ },
1756
+ ".rainbow-braces .token.token.punctuation.brace-level-3": {
1757
+ "color": "#ea580c"
1758
+ },
1759
+ ".rainbow-braces .token.token.punctuation.brace-level-7": {
1760
+ "color": "#ea580c"
1761
+ },
1762
+ ".rainbow-braces .token.token.punctuation.brace-level-11": {
1763
+ "color": "#ea580c"
1764
+ },
1765
+ ".rainbow-braces .token.token.punctuation.brace-level-4": {
1766
+ "color": "#9333ea"
1767
+ },
1768
+ ".rainbow-braces .token.token.punctuation.brace-level-8": {
1769
+ "color": "#9333ea"
1770
+ },
1771
+ ".rainbow-braces .token.token.punctuation.brace-level-12": {
1772
+ "color": "#9333ea"
1773
+ },
1774
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix)": {
1775
+ "backgroundColor": "rgba(220, 38, 38, 0.15)"
1776
+ },
1777
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix)": {
1778
+ "backgroundColor": "rgba(220, 38, 38, 0.15)"
1779
+ },
1780
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix)::-moz-selection": {
1781
+ "backgroundColor": "rgba(220, 38, 38, 0.25)"
1782
+ },
1783
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix) *::-moz-selection": {
1784
+ "backgroundColor": "rgba(220, 38, 38, 0.25)"
1785
+ },
1786
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix)::-moz-selection": {
1787
+ "backgroundColor": "rgba(220, 38, 38, 0.25)"
1788
+ },
1789
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix) *::-moz-selection": {
1790
+ "backgroundColor": "rgba(220, 38, 38, 0.25)"
1791
+ },
1792
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix)::selection": {
1793
+ "backgroundColor": "rgba(220, 38, 38, 0.25)"
1794
+ },
1795
+ "pre.diff-highlight > code .token.token.deleted:not(.prefix) *::selection": {
1796
+ "backgroundColor": "rgba(220, 38, 38, 0.25)"
1797
+ },
1798
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix)::selection": {
1799
+ "backgroundColor": "rgba(220, 38, 38, 0.25)"
1800
+ },
1801
+ "pre > code.diff-highlight .token.token.deleted:not(.prefix) *::selection": {
1802
+ "backgroundColor": "rgba(220, 38, 38, 0.25)"
1803
+ },
1804
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix)": {
1805
+ "backgroundColor": "rgba(22, 163, 74, 0.15)"
1806
+ },
1807
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix)": {
1808
+ "backgroundColor": "rgba(22, 163, 74, 0.15)"
1809
+ },
1810
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix)::-moz-selection": {
1811
+ "backgroundColor": "rgba(22, 163, 74, 0.25)"
1812
+ },
1813
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix) *::-moz-selection": {
1814
+ "backgroundColor": "rgba(22, 163, 74, 0.25)"
1815
+ },
1816
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix)::-moz-selection": {
1817
+ "backgroundColor": "rgba(22, 163, 74, 0.25)"
1818
+ },
1819
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix) *::-moz-selection": {
1820
+ "backgroundColor": "rgba(22, 163, 74, 0.25)"
1821
+ },
1822
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix)::selection": {
1823
+ "backgroundColor": "rgba(22, 163, 74, 0.25)"
1824
+ },
1825
+ "pre.diff-highlight > code .token.token.inserted:not(.prefix) *::selection": {
1826
+ "backgroundColor": "rgba(22, 163, 74, 0.25)"
1827
+ },
1828
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix)::selection": {
1829
+ "backgroundColor": "rgba(22, 163, 74, 0.25)"
1830
+ },
1831
+ "pre > code.diff-highlight .token.token.inserted:not(.prefix) *::selection": {
1832
+ "backgroundColor": "rgba(22, 163, 74, 0.25)"
1833
+ },
1834
+ ".prism-previewer.prism-previewer:before": {
1835
+ "borderColor": "#fff"
1836
+ },
1837
+ ".prism-previewer-gradient.prism-previewer-gradient div": {
1838
+ "borderColor": "#fff",
1839
+ "borderRadius": "0.3em"
1840
+ },
1841
+ ".prism-previewer-color.prism-previewer-color:before": {
1842
+ "borderRadius": "0.3em"
1843
+ },
1844
+ ".prism-previewer-easing.prism-previewer-easing:before": {
1845
+ "borderRadius": "0.3em"
1846
+ },
1847
+ ".prism-previewer.prism-previewer:after": {
1848
+ "borderTopColor": "#fff"
1849
+ },
1850
+ ".prism-previewer-flipped.prism-previewer-flipped.after": {
1851
+ "borderBottomColor": "#fff"
1852
+ },
1853
+ ".prism-previewer-angle.prism-previewer-angle:before": {
1854
+ "background": "#f1f5f9"
1855
+ },
1856
+ ".prism-previewer-time.prism-previewer-time:before": {
1857
+ "background": "#f1f5f9"
1858
+ },
1859
+ ".prism-previewer-easing.prism-previewer-easing": {
1860
+ "background": "#f1f5f9"
1861
+ },
1862
+ ".prism-previewer-angle.prism-previewer-angle circle": {
1863
+ "stroke": "#1e293b",
1864
+ "strokeOpacity": "1"
1865
+ },
1866
+ ".prism-previewer-time.prism-previewer-time circle": {
1867
+ "stroke": "#1e293b",
1868
+ "strokeOpacity": "1"
1869
+ },
1870
+ ".prism-previewer-easing.prism-previewer-easing circle": {
1871
+ "stroke": "#1e293b",
1872
+ "fill": "transparent"
1873
+ },
1874
+ ".prism-previewer-easing.prism-previewer-easing path": {
1875
+ "stroke": "#1e293b"
1876
+ },
1877
+ ".prism-previewer-easing.prism-previewer-easing line": {
1878
+ "stroke": "#1e293b"
1879
+ }
1880
+ };
1881
+ const CodeHighlighter = ({
1882
+ className,
1883
+ children,
1884
+ inlineClassName,
1885
+ copyClassName,
1886
+ copyIcon = /* @__PURE__ */ jsx(SvgCopy, {}),
1887
+ language,
1888
+ toolbarClassName,
1889
+ theme = dark,
1890
+ ...props
1891
+ }) => {
1892
+ const match = language?.match(/language-(\w+)/);
1893
+ const lang = match ? match[1] : "text";
1894
+ const isInline = !match;
1895
+ const handleCopy = (text) => {
1896
+ navigator.clipboard.writeText(text).then(() => {
1897
+ console.log("Text copied to clipboard");
1898
+ }).catch((err) => {
1899
+ console.error("Could not copy text: ", err);
1900
+ });
1901
+ };
1902
+ if (isInline) {
1903
+ return /* @__PURE__ */ jsx("code", { className: cn(inlineClassName), ...props, children });
1904
+ }
1905
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
1906
+ /* @__PURE__ */ jsxs("div", { className: cn(toolbarClassName), children: [
1907
+ /* @__PURE__ */ jsx("div", { children: lang }),
1908
+ copyIcon && /* @__PURE__ */ jsx(
1909
+ Button,
1910
+ {
1911
+ className: cn(copyClassName),
1912
+ size: "small",
1913
+ variant: "text",
1914
+ title: "Copy code",
1915
+ onClick: () => handleCopy(children),
1916
+ children: copyIcon
1917
+ }
1918
+ )
1919
+ ] }),
1920
+ /* @__PURE__ */ jsx(Prism, { language: lang, style: theme, children })
1921
+ ] });
1922
+ };
1923
+ const TableComponent = ({ children, ...props }) => /* @__PURE__ */ jsx("table", { ...props, children });
1924
+ const TableHeaderCell = ({ children, ...props }) => /* @__PURE__ */ jsx("th", { ...props, children });
1925
+ const TableDataCell = ({ children, ...props }) => /* @__PURE__ */ jsx("td", { ...props, children });
1926
+ const Markdown = ({
1927
+ children,
1928
+ remarkPlugins,
1929
+ rehypePlugins = [rehypeRaw, rehypeKatex],
1930
+ theme: themeProp,
1931
+ customComponents
1932
+ }) => {
1933
+ const { theme: contextTheme, markdownComponents } = useContext(ChatContext);
1934
+ const theme = themeProp || contextTheme;
1935
+ const components = useMemo(() => {
1936
+ const defaultComponents = {
1937
+ code: ({ className, children: children2, ...props }) => /* @__PURE__ */ jsx(
1938
+ CodeHighlighter,
1939
+ {
1940
+ ...props,
1941
+ language: cn(className),
1942
+ inlineClassName: cn(theme.messages.message.markdown.inlineCode),
1943
+ className: cn(theme.messages.message.markdown.code, className),
1944
+ copyClassName: cn(theme.messages.message.markdown.copy),
1945
+ toolbarClassName: cn(theme.messages.message.markdown.toolbar),
1946
+ children: children2
1947
+ }
1948
+ ),
1949
+ table: (props) => /* @__PURE__ */ jsx(
1950
+ TableComponent,
1951
+ {
1952
+ ...props,
1953
+ className: cn(theme.messages.message.markdown.table)
1954
+ }
1955
+ ),
1956
+ th: (props) => /* @__PURE__ */ jsx(
1957
+ TableHeaderCell,
1958
+ {
1959
+ ...props,
1960
+ className: cn(theme.messages.message.markdown.th)
1961
+ }
1962
+ ),
1963
+ td: (props) => /* @__PURE__ */ jsx(
1964
+ TableDataCell,
1965
+ {
1966
+ ...props,
1967
+ className: cn(theme.messages.message.markdown.td)
1968
+ }
1969
+ ),
1970
+ a: (props) => /* @__PURE__ */ jsx("a", { ...props, className: cn(theme.messages.message.markdown.a) }),
1971
+ hr: (props) => /* @__PURE__ */ jsx("hr", { ...props, className: cn(theme.messages.message.markdown.hr) }),
1972
+ p: (props) => /* @__PURE__ */ jsx("p", { ...props, className: cn(theme.messages.message.markdown.p) }),
1973
+ li: (props) => /* @__PURE__ */ jsx("li", { ...props, className: cn(theme.messages.message.markdown.li) }),
1974
+ ul: (props) => /* @__PURE__ */ jsx("ul", { ...props, className: cn(theme.messages.message.markdown.ul) }),
1975
+ ol: (props) => /* @__PURE__ */ jsx("ol", { ...props, className: cn(theme.messages.message.markdown.ol) }),
1976
+ h1: (props) => /* @__PURE__ */ jsx("h1", { ...props, className: cn(theme.messages.message.markdown.h1) }),
1977
+ h2: (props) => /* @__PURE__ */ jsx("h2", { ...props, className: cn(theme.messages.message.markdown.h2) }),
1978
+ h3: (props) => /* @__PURE__ */ jsx("h3", { ...props, className: cn(theme.messages.message.markdown.h3) }),
1979
+ h4: (props) => /* @__PURE__ */ jsx("h4", { ...props, className: cn(theme.messages.message.markdown.h4) }),
1980
+ h5: (props) => /* @__PURE__ */ jsx("h5", { ...props, className: cn(theme.messages.message.markdown.h5) }),
1981
+ h6: (props) => /* @__PURE__ */ jsx("h6", { ...props, className: cn(theme.messages.message.markdown.h6) }),
1982
+ // 'redact' is a custom element created by remarkRedact, not a standard
1983
+ // HTML tag, so it falls outside react-markdown's Components type.
1984
+ redact: ((props) => /* @__PURE__ */ jsx(
1985
+ Redact,
1986
+ {
1987
+ value: props["data-redact-value"] || props.children,
1988
+ allowToggle: true,
1989
+ tooltipText: `${props["data-redact-name"] || "Sensitive"} information - Click to toggle`
1990
+ }
1991
+ ))
1992
+ };
1993
+ return {
1994
+ ...defaultComponents,
1995
+ ...markdownComponents,
1996
+ ...customComponents
1997
+ };
1998
+ }, [theme, markdownComponents, customComponents]);
1999
+ return /* @__PURE__ */ jsx(
2000
+ ReactMarkdown,
2001
+ {
2002
+ remarkPlugins,
2003
+ rehypePlugins,
2004
+ components,
2005
+ children
2006
+ }
2007
+ );
2008
+ };
2009
+ const ComponentError = ({
2010
+ variant = "error",
2011
+ title,
2012
+ message,
2013
+ code
2014
+ }) => {
2015
+ const { theme } = useContext(ChatContext);
2016
+ const styles = variant === "warning" ? theme.chart.warning : theme.chart.error;
2017
+ return /* @__PURE__ */ jsxs("div", { className: styles.base, children: [
2018
+ title && /* @__PURE__ */ jsx("div", { className: styles.title, children: title }),
2019
+ message && /* @__PURE__ */ jsx("div", { children: message }),
2020
+ code && "code" in styles && /* @__PURE__ */ jsx("pre", { className: styles.code, children: /* @__PURE__ */ jsx("code", { children: code }) })
2021
+ ] });
2022
+ };
2023
+ const ChartRenderer = ({
2024
+ config,
2025
+ className
2026
+ }) => {
2027
+ const { theme } = useContext(ChatContext);
2028
+ const { type, data, width = 400, height = 300, title } = config;
2029
+ const chartElement = useMemo(() => {
2030
+ const chartData = data.filter(
2031
+ (d) => typeof d.data === "number"
2032
+ ).map((d) => ({
2033
+ key: d.key,
2034
+ data: d.data
2035
+ }));
2036
+ if (!chartData || chartData.length === 0) {
2037
+ return /* @__PURE__ */ jsx(ComponentError, { variant: "warning", message: "No chart data available" });
2038
+ }
2039
+ for (const point of chartData) {
2040
+ if (typeof point.data !== "number" || isNaN(point.data)) {
2041
+ return /* @__PURE__ */ jsx(
2042
+ ComponentError,
2043
+ {
2044
+ message: `Invalid data point: ${JSON.stringify(point)}`
2045
+ }
2046
+ );
2047
+ }
2048
+ }
2049
+ const chartProps = {
2050
+ width,
2051
+ height,
2052
+ data: chartData
2053
+ };
2054
+ try {
2055
+ switch (type) {
2056
+ case "bar":
2057
+ return /* @__PURE__ */ jsx(BarChart, { ...chartProps, series: /* @__PURE__ */ jsx(BarSeries, {}) });
2058
+ case "line":
2059
+ return /* @__PURE__ */ jsx(
2060
+ LineChart,
2061
+ {
2062
+ ...chartProps,
2063
+ xAxis: /* @__PURE__ */ jsx(LinearXAxis, { type: "category" }),
2064
+ yAxis: /* @__PURE__ */ jsx(LinearYAxis, { type: "value" }),
2065
+ series: /* @__PURE__ */ jsx(LineSeries, {})
2066
+ }
2067
+ );
2068
+ case "area":
2069
+ return /* @__PURE__ */ jsx(
2070
+ AreaChart,
2071
+ {
2072
+ ...chartProps,
2073
+ xAxis: /* @__PURE__ */ jsx(LinearXAxis, { type: "category" }),
2074
+ yAxis: /* @__PURE__ */ jsx(LinearYAxis, { type: "value" }),
2075
+ series: /* @__PURE__ */ jsx(AreaSeries, {})
2076
+ }
2077
+ );
2078
+ case "pie":
2079
+ return /* @__PURE__ */ jsx(
2080
+ PieChart,
2081
+ {
2082
+ width,
2083
+ height,
2084
+ data: chartData,
2085
+ series: /* @__PURE__ */ jsx(PieArcSeries, {})
2086
+ }
2087
+ );
2088
+ case "radialBar":
2089
+ return /* @__PURE__ */ jsx(
2090
+ RadialBarChart,
2091
+ {
2092
+ width,
2093
+ height,
2094
+ data: chartData,
2095
+ series: /* @__PURE__ */ jsx(RadialBarSeries, {})
2096
+ }
2097
+ );
2098
+ case "radialArea":
2099
+ return /* @__PURE__ */ jsx(
2100
+ RadialAreaChart,
2101
+ {
2102
+ width,
2103
+ height,
2104
+ data: chartData,
2105
+ series: /* @__PURE__ */ jsx(RadialAreaSeries, {})
2106
+ }
2107
+ );
2108
+ case "sparkline":
2109
+ return /* @__PURE__ */ jsx(SparklineChart, { width, height, data: chartData });
2110
+ default:
2111
+ return /* @__PURE__ */ jsx(ComponentError, { message: `Unknown chart type: ${type}` });
2112
+ }
2113
+ } catch (error) {
2114
+ return /* @__PURE__ */ jsx(ComponentError, { message: `Chart render error: ${String(error)}` });
2115
+ }
2116
+ }, [type, data, width, height]);
2117
+ return /* @__PURE__ */ jsxs("div", { className: cn(theme.chart.base, className), children: [
2118
+ title && /* @__PURE__ */ jsx("div", { className: theme.chart.title, children: title }),
2119
+ /* @__PURE__ */ jsx("div", { className: theme.chart.content, children: chartElement })
2120
+ ] });
2121
+ };
2122
+ const CVE_REGEX = /(CVE-(19|20)\d{2}-\d{4,7})/gi;
2123
+ const remarkCve = () => (tree) => {
2124
+ findAndReplace(tree, [
2125
+ [
2126
+ CVE_REGEX,
2127
+ (value) => ({
2128
+ type: "link",
2129
+ url: `https://cve.mitre.org/cgi-bin/cvename.cgi?name=${value.trim()}`,
2130
+ children: [{ type: "text", value: value.trim() }]
2131
+ })
2132
+ ]
2133
+ ]);
2134
+ };
2135
+ const remarkComponent = (_options = {}) => {
2136
+ return () => {
2137
+ };
2138
+ };
2139
+ function remarkRedact(matchers) {
2140
+ return () => (tree) => {
2141
+ if (!tree || !matchers || matchers.length === 0) {
2142
+ return;
2143
+ }
2144
+ const patterns = [];
2145
+ for (const { name, pattern, validate } of matchers) {
2146
+ patterns.push([
2147
+ pattern,
2148
+ (value) => {
2149
+ if (validate && !validate(value)) {
2150
+ return false;
2151
+ }
2152
+ return {
2153
+ type: "html",
2154
+ value: `<redact data-redact-name="${name}" data-redact-value="${value.replace(/"/g, "&quot;")}">${value}</redact>`
2155
+ };
2156
+ }
2157
+ ]);
2158
+ }
2159
+ if (patterns.length > 0) {
2160
+ try {
2161
+ findAndReplace(tree, patterns);
2162
+ } catch (err) {
2163
+ console.warn("Redact plugin error:", err);
2164
+ }
2165
+ }
2166
+ };
2167
+ }
2168
+ const ssnMatcher = {
2169
+ name: "SSN",
2170
+ pattern: /\b\d{3}-\d{2}-\d{4}\b/g
2171
+ };
2172
+ const creditCardMatcher = {
2173
+ name: "Credit Card",
2174
+ pattern: /\b(?:\d[ -]*?){13,19}\b/g,
2175
+ validate: (match) => {
2176
+ if (/(?:years?|year|yr|yrs|old|age|phone|tel|call)/.test(match)) {
2177
+ return false;
2178
+ }
2179
+ const cardNumber = match.replace(/[ -]/g, "");
2180
+ return cardNumber.length >= 13 && cardNumber.length <= 19;
2181
+ }
2182
+ };
2183
+ const bitcoinMatcher = {
2184
+ name: "Bitcoin",
2185
+ pattern: /\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b/g
2186
+ };
2187
+ const commonRedactMatchers = [
2188
+ ssnMatcher,
2189
+ creditCardMatcher,
2190
+ bitcoinMatcher
2191
+ ];
2192
+ const SvgFile = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 16, height: 16, viewBox: "0 0 16 16", fill: "currentColor", ...props }, /* @__PURE__ */ React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M2.7036 1.37034C3.04741 1.02653 3.51373 0.833374 3.99996 0.833374H9.33329H9.33331C9.47275 0.833374 9.59885 0.890449 9.68954 0.98251L13.6843 4.97722C13.7763 5.0679 13.8333 5.19398 13.8333 5.33337L13.8333 5.3379V13.3334C13.8333 13.8196 13.6401 14.2859 13.2963 14.6297C12.9525 14.9736 12.4862 15.1667 12 15.1667H3.99996C3.51373 15.1667 3.04741 14.9736 2.7036 14.6297C2.35978 14.2859 2.16663 13.8196 2.16663 13.3334V2.66671C2.16663 2.18048 2.35978 1.71416 2.7036 1.37034ZM3.99996 1.83337H8.83331V5.33337C8.83331 5.60952 9.05717 5.83337 9.33331 5.83337H12.8333V13.3334C12.8333 13.5544 12.7455 13.7663 12.5892 13.9226C12.4329 14.0789 12.221 14.1667 12 14.1667H3.99996C3.77895 14.1667 3.56698 14.0789 3.4107 13.9226C3.25442 13.7663 3.16663 13.5544 3.16663 13.3334V2.66671C3.16663 2.44569 3.25442 2.23373 3.4107 2.07745C3.56698 1.92117 3.77895 1.83337 3.99996 1.83337ZM9.83331 2.5405L12.1262 4.83337H9.83331V2.5405ZM5.33331 8.16663C5.05717 8.16663 4.83331 8.39048 4.83331 8.66663C4.83331 8.94277 5.05717 9.16663 5.33331 9.16663H10.6666C10.9428 9.16663 11.1666 8.94277 11.1666 8.66663C11.1666 8.39048 10.9428 8.16663 10.6666 8.16663H5.33331ZM4.83331 11.3334C4.83331 11.0572 5.05717 10.8334 5.33331 10.8334H10.6666C10.9428 10.8334 11.1666 11.0572 11.1666 11.3334C11.1666 11.6095 10.9428 11.8334 10.6666 11.8334H5.33331C5.05717 11.8334 4.83331 11.6095 4.83331 11.3334ZM5.33331 5.5C5.05717 5.5 4.83331 5.72386 4.83331 6C4.83331 6.27614 5.05717 6.5 5.33331 6.5H6.66665C6.94279 6.5 7.16665 6.27614 7.16665 6C7.16665 5.72386 6.94279 5.5 6.66665 5.5H5.33331Z" }));
2193
+ const DefaultFileRenderer$2 = lazy(() => Promise.resolve().then(() => DefaultFileRenderer$1));
2194
+ const CSVFileRenderer$2 = lazy(() => Promise.resolve().then(() => CSVFileRenderer$1));
2195
+ const ImageFileRenderer$2 = lazy(() => Promise.resolve().then(() => ImageFileRenderer$1));
2196
+ const PDFFileRenderer$2 = lazy(() => Promise.resolve().then(() => PDFFileRenderer$1));
2197
+ const FILE_TYPE_RENDERER_MAP = {
2198
+ "image/": ImageFileRenderer$2,
2199
+ "text/csv": CSVFileRenderer$2,
2200
+ "application/pdf": PDFFileRenderer$2
2201
+ };
2202
+ const MessageFile = ({
2203
+ name,
2204
+ type,
2205
+ url,
2206
+ limit = 100,
2207
+ fileIcon = /* @__PURE__ */ jsx(SvgFile, {})
2208
+ }) => {
2209
+ const { theme } = useContext(ChatContext);
2210
+ const FileRenderer = useMemo(() => {
2211
+ const Renderer = Object.keys(FILE_TYPE_RENDERER_MAP).find((key) => type?.startsWith(key)) ?? "default";
2212
+ return FILE_TYPE_RENDERER_MAP[Renderer] || DefaultFileRenderer$2;
2213
+ }, [type]);
2214
+ return /* @__PURE__ */ jsx(
2215
+ "div",
2216
+ {
2217
+ className: cn(theme.messages.message.files.file.base),
2218
+ children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsx(FileRenderer, { name, url, fileIcon, limit }) })
2219
+ }
2220
+ );
2221
+ };
2222
+ const DefaultFileRenderer = ({
2223
+ name,
2224
+ limit = 100,
2225
+ fileIcon = /* @__PURE__ */ jsx(SvgFile, {})
2226
+ }) => /* @__PURE__ */ jsxs("figure", { className: "flex items-center gap-2", children: [
2227
+ fileIcon,
2228
+ name && /* @__PURE__ */ jsx("figcaption", { className: cn("file-name-class"), children: /* @__PURE__ */ jsx(Ellipsis, { value: name, limit }) })
2229
+ ] });
2230
+ const DefaultFileRenderer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2231
+ __proto__: null,
2232
+ default: DefaultFileRenderer
2233
+ }, Symbol.toStringTag, { value: "Module" }));
2234
+ const sanitizeSVGCell = (cell) => {
2235
+ const trimmed = cell.trim();
2236
+ const escaped = trimmed.replace(/"/g, '""');
2237
+ const prefix = /^[=+\-@]/.test(trimmed) ? "'" : "";
2238
+ const needsQuotes = /[",\n\r]/.test(escaped) || prefix;
2239
+ return needsQuotes ? `"${prefix}${escaped}"` : escaped;
2240
+ };
2241
+ const parseCSV = (csvString) => {
2242
+ try {
2243
+ const rows = csvString.split("\n");
2244
+ return rows.map((row) => row.split(",").map((cell) => sanitizeSVGCell(cell)));
2245
+ } catch (error) {
2246
+ console.error("Error parsing CSV:", error);
2247
+ throw new Error("Failed to parse CSV file.");
2248
+ }
2249
+ };
2250
+ const SvgDownload = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-cloud-download", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" }), /* @__PURE__ */ React.createElement("path", { d: "M12 12v9" }), /* @__PURE__ */ React.createElement("path", { d: "m8 17 4 4 4-4" }));
2251
+ const CSVFileRenderer = ({ name, url, fileIcon }) => {
2252
+ const [isLoading, setIsLoading] = useState(true);
2253
+ const [csvData, setCsvData] = useState([]);
2254
+ const [error, setError] = useState(null);
2255
+ const [isModalOpen, setIsModalOpen] = useState(false);
2256
+ const modalRef = useRef(null);
2257
+ useEffect(() => {
2258
+ const fetchCsvData = async () => {
2259
+ try {
2260
+ setIsLoading(true);
2261
+ const response = await fetch(url);
2262
+ const data = parseCSV(await response.text());
2263
+ setCsvData(data);
2264
+ } catch {
2265
+ setError("Failed to load CSV file.");
2266
+ } finally {
2267
+ setIsLoading(false);
2268
+ }
2269
+ };
2270
+ fetchCsvData();
2271
+ }, [url]);
2272
+ const toggleModal = () => {
2273
+ setIsModalOpen((prev) => !prev);
2274
+ };
2275
+ const handleClickOutside = (event) => {
2276
+ if (modalRef.current && !modalRef.current.contains(event.target)) {
2277
+ setIsModalOpen(false);
2278
+ }
2279
+ };
2280
+ useEffect(() => {
2281
+ if (isModalOpen) {
2282
+ document.addEventListener("mousedown", handleClickOutside);
2283
+ } else {
2284
+ document.removeEventListener("mousedown", handleClickOutside);
2285
+ }
2286
+ return () => {
2287
+ document.removeEventListener("mousedown", handleClickOutside);
2288
+ };
2289
+ }, [isModalOpen]);
2290
+ const downloadCSV = () => {
2291
+ if (csvData.length === 0) return;
2292
+ const csvContent = csvData.map((row) => row.join(",")).join("\n");
2293
+ const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
2294
+ const url2 = URL.createObjectURL(blob);
2295
+ const link = document.createElement("a");
2296
+ link.href = url2;
2297
+ link.setAttribute("download", `${name || "data"}`);
2298
+ document.body.appendChild(link);
2299
+ link.click();
2300
+ document.body.removeChild(link);
2301
+ };
2302
+ const renderTable = (data, maxRows) => /* @__PURE__ */ jsxs(
2303
+ motion.table,
2304
+ {
2305
+ layout: true,
2306
+ className: "w-full",
2307
+ transition: { type: "spring", stiffness: 100, damping: 20 },
2308
+ children: [
2309
+ /* @__PURE__ */ jsx("thead", { className: "sticky top-0 bg-gray-200 dark:bg-gray-800 z-10", children: /* @__PURE__ */ jsxs("tr", { children: [
2310
+ /* @__PURE__ */ jsx("th", { className: "py-4 px-6", children: "#" }),
2311
+ data[0].map((header, index) => /* @__PURE__ */ jsx("th", { className: "py-4 px-6", children: header }, `header-${index}`))
2312
+ ] }) }),
2313
+ /* @__PURE__ */ jsx("tbody", { children: data.slice(1, maxRows).map((row, rowIndex) => /* @__PURE__ */ jsxs(
2314
+ "tr",
2315
+ {
2316
+ className: "border-b border-panel-accent light:border-gray-700 hover:bg-panel-accent hover:light:bg-gray-700/40 transition-colors text-base",
2317
+ children: [
2318
+ /* @__PURE__ */ jsx("td", { className: "py-4 px-6", children: rowIndex + 1 }),
2319
+ row.map((cell, cellIndex) => /* @__PURE__ */ jsx("td", { className: "py-4 px-6", children: cell }, `cell-${rowIndex}-${cellIndex}`))
2320
+ ]
2321
+ },
2322
+ `row-${rowIndex}`
2323
+ )) })
2324
+ ]
2325
+ }
2326
+ );
2327
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
2328
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-4", children: [
2329
+ /* @__PURE__ */ jsxs("div", { className: "csv-icon flex items-center", children: [
2330
+ fileIcon,
2331
+ name && /* @__PURE__ */ jsx("figcaption", { className: "ml-1", children: name })
2332
+ ] }),
2333
+ /* @__PURE__ */ jsxs("div", { className: "csv-icon flex items-center gap-6", children: [
2334
+ /* @__PURE__ */ jsx(IconButton, { size: "small", variant: "text", onClick: downloadCSV, children: /* @__PURE__ */ jsx(SvgDownload, {}) }),
2335
+ /* @__PURE__ */ jsx(IconButton, { size: "small", variant: "text", onClick: toggleModal, children: /* @__PURE__ */ jsx(SvgCopy, {}) })
2336
+ ] })
2337
+ ] }),
2338
+ error && /* @__PURE__ */ jsx("div", { className: "error-message", children: error }),
2339
+ isLoading && !csvData && /* @__PURE__ */ jsx("div", { className: "text-text-secondary", children: "Loading..." }),
2340
+ /* @__PURE__ */ jsx("div", { className: "flex justify-between", children: !error && csvData.length > 0 && renderTable(csvData, 6) }),
2341
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isModalOpen && /* @__PURE__ */ jsx(
2342
+ motion.div,
2343
+ {
2344
+ className: "fixed inset-0 bg-black/70 flex justify-center items-center z-50",
2345
+ initial: { opacity: 0 },
2346
+ animate: { opacity: 1 },
2347
+ exit: { opacity: 0 },
2348
+ transition: { duration: 0.3 },
2349
+ children: /* @__PURE__ */ jsx(
2350
+ motion.div,
2351
+ {
2352
+ ref: modalRef,
2353
+ className: "bg-white dark:bg-gray-900 rounded-md w-11/12 h-5/6 overflow-auto",
2354
+ initial: { scale: 0.8 },
2355
+ animate: { scale: 1 },
2356
+ exit: { scale: 0.8 },
2357
+ transition: { duration: 0.3 },
2358
+ children: !error && csvData.length > 0 && renderTable(csvData)
2359
+ }
2360
+ )
2361
+ }
2362
+ ) })
2363
+ ] });
2364
+ };
2365
+ const CSVFileRenderer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2366
+ __proto__: null,
2367
+ default: CSVFileRenderer
2368
+ }, Symbol.toStringTag, { value: "Module" }));
2369
+ const ImageFileRenderer = ({ url }) => /* @__PURE__ */ jsx("img", { src: url, alt: "Image", className: "size-10" });
2370
+ const ImageFileRenderer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2371
+ __proto__: null,
2372
+ default: ImageFileRenderer
2373
+ }, Symbol.toStringTag, { value: "Module" }));
2374
+ const PDFFileRenderer = ({ name, url, fileIcon }) => /* @__PURE__ */ jsxs("figure", { className: "csv-icon flex items-center gap-2", onClick: () => window.open(url, "_blank"), children: [
2375
+ fileIcon,
2376
+ name && /* @__PURE__ */ jsx("figcaption", { className: "file-name", children: name })
2377
+ ] });
2378
+ const PDFFileRenderer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2379
+ __proto__: null,
2380
+ default: PDFFileRenderer
2381
+ }, Symbol.toStringTag, { value: "Module" }));
2382
+ const MessageFiles = memo(({ files, children }) => {
2383
+ const { theme } = useContext(ChatContext);
2384
+ const Comp = children ? Slot : MessageFile;
2385
+ const [expanded, setExpanded] = useState(false);
2386
+ const { imageFiles, otherFiles } = useMemo(() => {
2387
+ if (!files || files.length === 0) {
2388
+ return {
2389
+ imageFiles: [],
2390
+ otherFiles: []
2391
+ };
2392
+ }
2393
+ return files.reduce(
2394
+ (acc, file) => {
2395
+ if (file.type?.startsWith("image/")) {
2396
+ acc.imageFiles.push(file);
2397
+ } else {
2398
+ acc.otherFiles.push(file);
2399
+ }
2400
+ return acc;
2401
+ },
2402
+ {
2403
+ imageFiles: [],
2404
+ otherFiles: []
2405
+ }
2406
+ );
2407
+ }, [files]);
2408
+ if (!files || files.length === 0) {
2409
+ return null;
2410
+ }
2411
+ const maxImageLength = 3;
2412
+ const truncateImages = !expanded && imageFiles.length > maxImageLength;
2413
+ const renderImageFiles = (images) => {
2414
+ return truncateImages ? images.slice(0, maxImageLength).map((image, index) => /* @__PURE__ */ jsxs(
2415
+ "figure",
2416
+ {
2417
+ className: index === 0 ? "col-span-2 row-span-2" : "relative",
2418
+ children: [
2419
+ /* @__PURE__ */ jsx(
2420
+ "img",
2421
+ {
2422
+ src: image.url,
2423
+ alt: image.name,
2424
+ className: "relative w-full h-full object-cover rounded-lg"
2425
+ }
2426
+ ),
2427
+ index === maxImageLength - 1 && /* @__PURE__ */ jsxs(
2428
+ "div",
2429
+ {
2430
+ className: "absolute top-0 left-0 w-full h-full flex justify-center items-center bg-black bg-opacity-50 rounded-lg cursor-pointer",
2431
+ onClick: () => setExpanded(true),
2432
+ children: [
2433
+ "+",
2434
+ (imageFiles.length - maxImageLength).toLocaleString()
2435
+ ]
2436
+ }
2437
+ )
2438
+ ]
2439
+ },
2440
+ index
2441
+ )) : images.map((image, index) => /* @__PURE__ */ jsx(Comp, { ...image, children }, index));
2442
+ };
2443
+ return /* @__PURE__ */ jsxs(
2444
+ "div",
2445
+ {
2446
+ className: cn(
2447
+ theme.messages.message.files.base,
2448
+ truncateImages ? "grid grid-rows-2 grid-flow-col gap-2 w-1/3" : ""
2449
+ ),
2450
+ children: [
2451
+ imageFiles.length > 0 && renderImageFiles(imageFiles),
2452
+ otherFiles.length > 0 && otherFiles.map((file, index) => /* @__PURE__ */ jsx(Comp, { ...file, children }, index))
2453
+ ]
2454
+ }
2455
+ );
2456
+ });
2457
+ MessageFiles.displayName = "MessageFiles";
2458
+ const MessageQuestion = memo(
2459
+ ({ children, ...props }) => {
2460
+ const { theme, remarkPlugins } = useContext(ChatContext);
2461
+ const { question, files } = props;
2462
+ const Comp = children ? Slot : "div";
2463
+ const [expanded, setExpanded] = useState(false);
2464
+ const isLong = question.length > 500;
2465
+ return /* @__PURE__ */ jsx(
2466
+ Comp,
2467
+ {
2468
+ className: cn(theme.messages.message.question, {
2469
+ [theme.messages.message.overlay]: isLong && !expanded
2470
+ }),
2471
+ ...props,
2472
+ children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
2473
+ /* @__PURE__ */ jsx(MessageFiles, { files }),
2474
+ /* @__PURE__ */ jsx(Markdown, { remarkPlugins, theme, children: question }),
2475
+ isLong && !expanded && /* @__PURE__ */ jsx(
2476
+ Button,
2477
+ {
2478
+ variant: "link",
2479
+ size: "small",
2480
+ className: theme.messages.message.expand,
2481
+ onClick: () => setExpanded(true),
2482
+ children: "Show more"
2483
+ }
2484
+ )
2485
+ ] })
2486
+ }
2487
+ );
2488
+ }
2489
+ );
2490
+ MessageQuestion.displayName = "MessageQuestion";
2491
+ const MessageResponse = memo(
2492
+ ({ response, isLoading, children }) => {
2493
+ const { theme, isCompact, remarkPlugins } = useContext(ChatContext);
2494
+ const Comp = children ? Slot : "div";
2495
+ return /* @__PURE__ */ jsx(
2496
+ Comp,
2497
+ {
2498
+ "data-compact": isCompact,
2499
+ className: cn(theme.messages.message.response),
2500
+ children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
2501
+ /* @__PURE__ */ jsx(Markdown, { remarkPlugins, theme, children: response }),
2502
+ isLoading && /* @__PURE__ */ jsx(
2503
+ motion.div,
2504
+ {
2505
+ className: cn(theme.messages.message.cursor),
2506
+ animate: { opacity: [1, 0] },
2507
+ transition: {
2508
+ duration: 0.7,
2509
+ repeat: Infinity,
2510
+ repeatType: "reverse"
2511
+ }
2512
+ }
2513
+ )
2514
+ ] })
2515
+ }
2516
+ );
2517
+ }
2518
+ );
2519
+ const MessageSource = ({ title, url, image, limit = 50 }) => {
2520
+ const { theme, isCompact } = useContext(ChatContext);
2521
+ return /* @__PURE__ */ jsxs(
2522
+ "figure",
2523
+ {
2524
+ className: cn(theme.messages.message.sources.source.base, {
2525
+ [theme.messages.message.sources.source.companion]: isCompact
2526
+ }),
2527
+ onClick: () => {
2528
+ if (url) {
2529
+ window.open(url, "_blank");
2530
+ }
2531
+ },
2532
+ children: [
2533
+ image && /* @__PURE__ */ jsx("img", { src: image, alt: title, className: cn(theme.messages.message.sources.source.image) }),
2534
+ (title || url) && /* @__PURE__ */ jsxs("figcaption", { children: [
2535
+ title && /* @__PURE__ */ jsx("span", { className: cn(theme.messages.message.sources.source.title), children: /* @__PURE__ */ jsx(Ellipsis, { value: title, limit }) }),
2536
+ url && /* @__PURE__ */ jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: cn(theme.messages.message.sources.source.url), children: url })
2537
+ ] })
2538
+ ]
2539
+ }
2540
+ );
2541
+ };
2542
+ const MessageSources = memo(
2543
+ ({ sources, children }) => {
2544
+ const { theme } = useContext(ChatContext);
2545
+ const Comp = children ? Slot : MessageSource;
2546
+ if (!sources || sources.length === 0) {
2547
+ return null;
2548
+ }
2549
+ return /* @__PURE__ */ jsx("div", { className: cn(theme.messages.message.sources.base), children: sources.map((source, index) => /* @__PURE__ */ jsx(Comp, { ...source, children }, index)) });
2550
+ }
2551
+ );
2552
+ MessageSources.displayName = "MessageSources";
2553
+ const SvgThumbsDown = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-thumbs-down", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M17 14V2" }), /* @__PURE__ */ React.createElement("path", { d: "M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z" }));
2554
+ const SvgThumbsUp = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-thumbs-up", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M7 10v12" }), /* @__PURE__ */ React.createElement("path", { d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z" }));
2555
+ const SvgRefresh = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-refresh-ccw", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }), /* @__PURE__ */ React.createElement("path", { d: "M3 3v5h5" }), /* @__PURE__ */ React.createElement("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }), /* @__PURE__ */ React.createElement("path", { d: "M16 16h5v5" }));
2556
+ const MessageActions = memo(
2557
+ ({ children, ...props }) => {
2558
+ const { theme } = useContext(ChatContext);
2559
+ const {
2560
+ question,
2561
+ response,
2562
+ copyIcon = /* @__PURE__ */ jsx(SvgCopy, {}),
2563
+ thumbsUpIcon = /* @__PURE__ */ jsx(SvgThumbsUp, {}),
2564
+ thumbsDownIcon = /* @__PURE__ */ jsx(SvgThumbsDown, {}),
2565
+ refreshIcon = /* @__PURE__ */ jsx(SvgRefresh, {}),
2566
+ onCopy,
2567
+ onUpvote,
2568
+ onDownvote,
2569
+ onRefresh
2570
+ } = props;
2571
+ const Comp = children ? Slot : "div";
2572
+ const handleCopy = useCallback((text) => {
2573
+ navigator.clipboard.writeText(text).then(() => {
2574
+ console.log("Text copied to clipboard");
2575
+ }).catch((err) => {
2576
+ console.error("Could not copy text: ", err);
2577
+ });
2578
+ }, []);
2579
+ const handleCopyClick = useCallback(() => {
2580
+ if (onCopy) {
2581
+ onCopy();
2582
+ } else {
2583
+ handleCopy(`${question}${response ? `
2584
+ ${response}` : ""}`);
2585
+ }
2586
+ }, [onCopy, handleCopy, question, response]);
2587
+ return (copyIcon || thumbsDownIcon || thumbsUpIcon || refreshIcon) && /* @__PURE__ */ jsx(Comp, { className: cn(theme.messages.message.footer.base), children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
2588
+ copyIcon && /* @__PURE__ */ jsx(
2589
+ IconButton,
2590
+ {
2591
+ variant: "text",
2592
+ disablePadding: true,
2593
+ title: "Copy question and response",
2594
+ className: cn(theme.messages.message.footer.copy),
2595
+ onClick: handleCopyClick,
2596
+ children: copyIcon
2597
+ }
2598
+ ),
2599
+ thumbsUpIcon && /* @__PURE__ */ jsx(
2600
+ IconButton,
2601
+ {
2602
+ variant: "text",
2603
+ disablePadding: true,
2604
+ title: "Upvote",
2605
+ className: cn(theme.messages.message.footer.upvote),
2606
+ onClick: onUpvote,
2607
+ children: thumbsUpIcon
2608
+ }
2609
+ ),
2610
+ thumbsDownIcon && /* @__PURE__ */ jsx(
2611
+ IconButton,
2612
+ {
2613
+ variant: "text",
2614
+ disablePadding: true,
2615
+ title: "Downvote",
2616
+ className: cn(theme.messages.message.footer.downvote),
2617
+ onClick: onDownvote,
2618
+ children: thumbsDownIcon
2619
+ }
2620
+ ),
2621
+ refreshIcon && /* @__PURE__ */ jsx(
2622
+ IconButton,
2623
+ {
2624
+ variant: "text",
2625
+ disablePadding: true,
2626
+ title: "Refresh",
2627
+ className: cn(theme.messages.message.footer.refresh),
2628
+ onClick: onRefresh,
2629
+ children: refreshIcon
2630
+ }
2631
+ )
2632
+ ] }) });
2633
+ }
2634
+ );
2635
+ MessageActions.displayName = "MessageActions";
2636
+ const messageVariants = {
2637
+ hidden: {
2638
+ opacity: 0,
2639
+ y: 20
2640
+ },
2641
+ visible: {
2642
+ opacity: 1,
2643
+ y: 0,
2644
+ transition: {
2645
+ duration: 0.3
2646
+ }
2647
+ }
2648
+ };
2649
+ const SessionMessage = memo(
2650
+ ({ conversation, isLast, children, className }) => {
2651
+ const { theme, isLoading } = useContext(ChatContext);
2652
+ return /* @__PURE__ */ jsx(motion.div, { variants: messageVariants, children: /* @__PURE__ */ jsx(Card, { className: cn(theme.messages.message.base, className), children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
2653
+ /* @__PURE__ */ jsx(
2654
+ MessageQuestion,
2655
+ {
2656
+ question: conversation.question,
2657
+ files: conversation.files
2658
+ }
2659
+ ),
2660
+ /* @__PURE__ */ jsx(
2661
+ MessageResponse,
2662
+ {
2663
+ response: conversation.response,
2664
+ isLoading: isLast && isLoading
2665
+ }
2666
+ ),
2667
+ /* @__PURE__ */ jsx(MessageSources, { sources: conversation.sources }),
2668
+ /* @__PURE__ */ jsx(
2669
+ MessageActions,
2670
+ {
2671
+ question: conversation.question,
2672
+ response: conversation.response
2673
+ }
2674
+ )
2675
+ ] }) }) }, conversation.id);
2676
+ }
2677
+ );
2678
+ SessionMessage.displayName = "SessionMessage";
2679
+ const SvgArrowDown = (props) => /* @__PURE__ */ React.createElement("svg", { width: 20, height: 20, viewBox: "0 0 20 20", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg", className: "shrink-0 mix-blend-luminosity", "aria-hidden": "true", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M10 3C10.2761 3.00006 10.5 3.2239 10.5 3.5V15.293L14.6465 11.1465C14.8418 10.9514 15.1583 10.9513 15.3536 11.1465C15.5487 11.3417 15.5486 11.6583 15.3536 11.8535L10.3535 16.8535C10.2598 16.9473 10.1326 17 10 17C9.90062 17 9.8042 16.9703 9.72268 16.916L9.64651 16.8535L4.6465 11.8535C4.45138 11.6582 4.45128 11.3417 4.6465 11.1465C4.84172 10.9513 5.15827 10.9514 5.35353 11.1465L9.50003 15.293V3.5C9.50003 3.22386 9.72389 3 10 3Z" }));
2680
+ const containerVariants = {
2681
+ hidden: {},
2682
+ visible: {
2683
+ transition: {
2684
+ staggerChildren: 0.07,
2685
+ when: "beforeChildren"
2686
+ }
2687
+ }
2688
+ };
2689
+ const SessionMessages = ({
2690
+ children,
2691
+ newSessionContent,
2692
+ limit = 10,
2693
+ className,
2694
+ showMoreText = "Show more",
2695
+ autoScroll = true,
2696
+ showLoadMoreButton = false,
2697
+ showScrollBottomButton,
2698
+ loadMoreButtonDisabled,
2699
+ onScroll,
2700
+ onLoadMore
2701
+ }) => {
2702
+ const { activeSession, theme } = useContext(ChatContext);
2703
+ const contentRef = useRef(null);
2704
+ const messagesRef = useRef(null);
2705
+ const [isAnimating, setIsAnimating] = useState(true);
2706
+ const [iAtBottom, setIsAtBottom] = useState(true);
2707
+ useEffect(() => {
2708
+ if (!contentRef.current || !showScrollBottomButton) {
2709
+ return;
2710
+ }
2711
+ const handleScroll = debounce(() => {
2712
+ if (contentRef.current) {
2713
+ setIsAtBottom(
2714
+ contentRef.current.scrollHeight - contentRef.current.clientHeight === contentRef.current.scrollTop
2715
+ );
2716
+ }
2717
+ }, 50);
2718
+ const currentRef = contentRef.current;
2719
+ currentRef.addEventListener("scroll", handleScroll);
2720
+ return () => currentRef.removeEventListener("scroll", handleScroll);
2721
+ }, [showScrollBottomButton]);
2722
+ useEffect(() => {
2723
+ if (contentRef.current && autoScroll) {
2724
+ requestAnimationFrame(
2725
+ () => contentRef.current.scrollTop = contentRef.current.scrollHeight
2726
+ );
2727
+ }
2728
+ }, [activeSession, autoScroll, isAnimating]);
2729
+ const handleShowMore = () => {
2730
+ showNext(limit);
2731
+ requestAnimationFrame(() => contentRef.current.scrollTop = 0);
2732
+ };
2733
+ const handleScrollToBottom = () => {
2734
+ if (contentRef.current) {
2735
+ contentRef.current.scrollTo({
2736
+ top: contentRef.current.scrollHeight,
2737
+ behavior: "smooth"
2738
+ });
2739
+ }
2740
+ };
2741
+ const reversedConvos = useMemo(
2742
+ () => [...activeSession?.conversations ?? []].reverse(),
2743
+ [activeSession]
2744
+ );
2745
+ const { data, hasMore, showNext } = useInfinityList({
2746
+ items: reversedConvos,
2747
+ size: limit
2748
+ });
2749
+ const reReversedConvo = useMemo(() => [...data].reverse(), [data]);
2750
+ const convosToRender = limit ? reReversedConvo : activeSession?.conversations;
2751
+ if (!activeSession) {
2752
+ return /* @__PURE__ */ jsx(SessionEmpty, { children: newSessionContent });
2753
+ }
2754
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative flex-1 overflow-y-hidden", className), children: [
2755
+ /* @__PURE__ */ jsxs(
2756
+ "div",
2757
+ {
2758
+ className: cn(theme.messages.content, className, "h-full"),
2759
+ ref: contentRef,
2760
+ id: activeSession?.id,
2761
+ onScrollCapture: onScroll,
2762
+ children: [
2763
+ (showLoadMoreButton || hasMore) && /* @__PURE__ */ jsx(
2764
+ Button,
2765
+ {
2766
+ disabled: loadMoreButtonDisabled,
2767
+ variant: "outline",
2768
+ className: cn(theme.messages.showMore),
2769
+ fullWidth: true,
2770
+ onClick: onLoadMore ?? handleShowMore,
2771
+ children: showMoreText
2772
+ }
2773
+ ),
2774
+ /* @__PURE__ */ jsx(AnimatePresence, { children: /* @__PURE__ */ jsx(
2775
+ motion.div,
2776
+ {
2777
+ ref: messagesRef,
2778
+ variants: containerVariants,
2779
+ initial: "hidden",
2780
+ animate: "visible",
2781
+ onAnimationComplete: () => requestAnimationFrame(() => {
2782
+ setIsAnimating(false);
2783
+ if (contentRef.current && autoScroll) {
2784
+ contentRef.current.scrollTop = contentRef.current.scrollHeight;
2785
+ }
2786
+ }),
2787
+ children: children ? children(convosToRender) : convosToRender.map((conversation, index) => /* @__PURE__ */ jsx(
2788
+ SessionMessage,
2789
+ {
2790
+ conversation,
2791
+ isLast: index === convosToRender.length - 1
2792
+ },
2793
+ conversation.id
2794
+ ))
2795
+ },
2796
+ activeSession?.id
2797
+ ) })
2798
+ ]
2799
+ }
2800
+ ),
2801
+ /* @__PURE__ */ jsx(AnimatePresence, { children: !iAtBottom && showScrollBottomButton && /* @__PURE__ */ jsx(
2802
+ motion.div,
2803
+ {
2804
+ initial: { y: 100, opacity: 0 },
2805
+ animate: { y: 0, opacity: 1 },
2806
+ exit: { y: 100, opacity: 0 },
2807
+ transition: { duration: 0.3, ease: "easeOut" },
2808
+ className: theme.messages?.message?.scrollToBottom?.container,
2809
+ children: /* @__PURE__ */ jsx(
2810
+ IconButton,
2811
+ {
2812
+ onClick: handleScrollToBottom,
2813
+ className: theme.messages?.message?.scrollToBottom?.button,
2814
+ size: "small",
2815
+ children: /* @__PURE__ */ jsx(SvgArrowDown, {})
2816
+ }
2817
+ )
2818
+ }
2819
+ ) })
2820
+ ] });
2821
+ };
2822
+ const useDimensions = () => {
2823
+ const [ref, setRef] = useState(null);
2824
+ const [width, setWidth] = useState(void 0);
2825
+ const rafId = useRef(null);
2826
+ const observe = useCallback((element) => {
2827
+ if (element) setRef(element);
2828
+ }, []);
2829
+ useEffect(() => {
2830
+ if (!ref) return;
2831
+ const resizeObserver = new ResizeObserver((entries) => {
2832
+ if (rafId.current !== null) {
2833
+ cancelAnimationFrame(rafId.current);
2834
+ }
2835
+ rafId.current = requestAnimationFrame(() => {
2836
+ for (const entry of entries) {
2837
+ setWidth(entry.contentRect.width);
2838
+ }
2839
+ rafId.current = null;
2840
+ });
2841
+ });
2842
+ resizeObserver.observe(ref);
2843
+ return () => {
2844
+ if (rafId.current !== null) {
2845
+ cancelAnimationFrame(rafId.current);
2846
+ rafId.current = null;
2847
+ }
2848
+ resizeObserver.disconnect();
2849
+ };
2850
+ }, [ref]);
2851
+ return { width, observe };
2852
+ };
2853
+ const defaultRemarkPlugins = [remarkGfm, remarkYoutube, remarkMath];
2854
+ const Chat = ({
2855
+ children,
2856
+ viewType = "console",
2857
+ sessions,
2858
+ onSelectSession,
2859
+ onDeleteSession,
2860
+ onSendMessage,
2861
+ onStopMessage,
2862
+ onFileUpload,
2863
+ isLoading,
2864
+ activeSessionId,
2865
+ theme: customTheme = chatTheme,
2866
+ onNewSession,
2867
+ remarkPlugins = defaultRemarkPlugins,
2868
+ markdownComponents,
2869
+ components: componentCatalog2,
2870
+ disabled,
2871
+ style,
2872
+ className
2873
+ }) => {
2874
+ const theme = useComponentTheme("chat", customTheme);
2875
+ const [internalActiveSessionID, setInternalActiveSessionID] = useState(activeSessionId);
2876
+ const { width, observe } = useDimensions();
2877
+ const isCompact = viewType === "companion" || width && width < 767;
2878
+ useEffect(() => {
2879
+ setInternalActiveSessionID(activeSessionId);
2880
+ }, [activeSessionId]);
2881
+ const handleSelectSession = useCallback(
2882
+ (sessionId) => {
2883
+ setInternalActiveSessionID(sessionId);
2884
+ onSelectSession?.(sessionId);
2885
+ },
2886
+ [onSelectSession]
2887
+ );
2888
+ const handleDeleteSession = useCallback(
2889
+ (sessionId) => {
2890
+ setInternalActiveSessionID(void 0);
2891
+ onDeleteSession?.(sessionId);
2892
+ },
2893
+ [onDeleteSession]
2894
+ );
2895
+ const handleCreateNewSession = useCallback(() => {
2896
+ setInternalActiveSessionID(void 0);
2897
+ onNewSession?.();
2898
+ }, [onNewSession]);
2899
+ useHotkeys([
2900
+ {
2901
+ name: "Create new session",
2902
+ category: "Chat",
2903
+ keys: "meta+shift+s",
2904
+ callback: (event) => {
2905
+ event.preventDefault();
2906
+ handleCreateNewSession();
2907
+ }
2908
+ }
2909
+ ]);
2910
+ const activeSession = useMemo(
2911
+ () => sessions.find((session) => session.id === internalActiveSessionID),
2912
+ [sessions, internalActiveSessionID]
2913
+ );
2914
+ const mergedRemarkPlugins = useMemo(() => {
2915
+ if (!componentCatalog2) return remarkPlugins;
2916
+ return [...remarkPlugins, componentCatalog2.remarkPlugin];
2917
+ }, [remarkPlugins, componentCatalog2]);
2918
+ const mergedMarkdownComponents = useMemo(() => {
2919
+ if (!componentCatalog2) return markdownComponents;
2920
+ return {
2921
+ ...componentCatalog2.components,
2922
+ ...markdownComponents
2923
+ };
2924
+ }, [markdownComponents, componentCatalog2]);
2925
+ const contextValue = useMemo(
2926
+ () => ({
2927
+ sessions,
2928
+ activeSession,
2929
+ remarkPlugins: mergedRemarkPlugins,
2930
+ markdownComponents: mergedMarkdownComponents,
2931
+ theme,
2932
+ disabled,
2933
+ isLoading,
2934
+ isCompact,
2935
+ viewType,
2936
+ activeSessionId: internalActiveSessionID,
2937
+ selectSession: handleSelectSession,
2938
+ deleteSession: handleDeleteSession,
2939
+ createSession: handleCreateNewSession,
2940
+ sendMessage: onSendMessage,
2941
+ stopMessage: onStopMessage,
2942
+ fileUpload: onFileUpload
2943
+ }),
2944
+ [
2945
+ isLoading,
2946
+ isCompact,
2947
+ viewType,
2948
+ disabled,
2949
+ theme,
2950
+ mergedRemarkPlugins,
2951
+ mergedMarkdownComponents,
2952
+ sessions,
2953
+ activeSession,
2954
+ internalActiveSessionID,
2955
+ handleSelectSession,
2956
+ handleDeleteSession,
2957
+ handleCreateNewSession,
2958
+ onSendMessage,
2959
+ onStopMessage,
2960
+ onFileUpload
2961
+ ]
2962
+ );
2963
+ return /* @__PURE__ */ jsx(ChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: /* @__PURE__ */ jsx(
2964
+ "div",
2965
+ {
2966
+ ref: observe,
2967
+ className: cn(className, theme.base, {
2968
+ [theme.companion]: isCompact,
2969
+ [theme.console]: !isCompact
2970
+ }),
2971
+ style,
2972
+ children
2973
+ }
2974
+ ) }) });
2975
+ };
2976
+ const SvgTrash = (props) => /* @__PURE__ */ React.createElement("svg", { width: 14, height: 14, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props }, /* @__PURE__ */ React.createElement("g", { id: "Delete" }, /* @__PURE__ */ React.createElement("path", { id: "Vector", d: "M5.97905 1.16666C5.90859 1.16576 5.83895 1.18189 5.77605 1.21368C5.71316 1.24547 5.65888 1.29199 5.61783 1.34926C5.57677 1.40654 5.55016 1.47288 5.54025 1.54265C5.53034 1.61242 5.53743 1.68355 5.56092 1.75H4.27007C3.7342 1.75 3.2324 2.01817 2.93535 2.46435L2.24492 3.5H2.18738C2.12941 3.49918 2.07185 3.50989 2.01805 3.5315C1.96425 3.55312 1.91529 3.58522 1.874 3.62593C1.83271 3.66663 1.79993 3.71514 1.77755 3.76863C1.75518 3.82211 1.74365 3.87952 1.74365 3.9375C1.74365 3.99548 1.75518 4.05288 1.77755 4.10636C1.79993 4.15985 1.83271 4.20836 1.874 4.24907C1.91529 4.28977 1.96425 4.32187 2.01805 4.34349C2.07185 4.3651 2.12941 4.37582 2.18738 4.375H2.41012C2.44765 4.38067 2.48576 4.38143 2.52348 4.37727L3.24468 11.1084C3.33169 11.9199 4.02367 12.5417 4.83973 12.5417H9.15947C9.97553 12.5417 10.6675 11.9199 10.7545 11.1084L11.4763 4.37727C11.5133 4.38124 11.5506 4.38047 11.5874 4.375H11.8124C11.8704 4.37582 11.9279 4.3651 11.9817 4.34349C12.0355 4.32187 12.0845 4.28977 12.1258 4.24907C12.1671 4.20836 12.1998 4.15985 12.2222 4.10636C12.2446 4.05288 12.2561 3.99548 12.2561 3.9375C12.2561 3.87952 12.2446 3.82211 12.2222 3.76863C12.1998 3.71514 12.1671 3.66663 12.1258 3.62593C12.0845 3.58522 12.0355 3.55312 11.9817 3.5315C11.9279 3.50989 11.8704 3.49918 11.8124 3.5H11.7548L11.0644 2.46435C10.7671 2.01841 10.2654 1.75 9.7297 1.75H8.43885C8.46234 1.68355 8.46943 1.61242 8.45952 1.54265C8.44961 1.47288 8.423 1.40654 8.38194 1.34926C8.34089 1.29199 8.2866 1.24547 8.22371 1.21368C8.16082 1.18189 8.09118 1.16576 8.02072 1.16666H5.97905ZM4.27007 2.625H9.7297C9.97394 2.625 10.2009 2.74639 10.3364 2.9497L10.7033 3.5H3.29651L3.66338 2.9497L3.66395 2.94913C3.79913 2.74608 4.02543 2.625 4.27007 2.625ZM3.40361 4.375H10.5962L9.88465 11.015C9.8445 11.3894 9.53575 11.6667 9.15947 11.6667H4.83973C4.46345 11.6667 4.15527 11.3894 4.11512 11.015L3.40361 4.375Z", fill: "currentColor" })));
2977
+ const SvgChat = (props) => /* @__PURE__ */ React.createElement("svg", { width: 16, height: 17, viewBox: "0 0 16 17", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M8 3C4.55375 3 1.75 5.23753 1.75 7.98828C1.75 9.70653 2.83659 11.2762 4.62109 12.188C4.11184 13.0465 3.62587 13.7378 3.62012 13.7461C3.50687 13.9071 3.49862 14.1196 3.59912 14.2891C3.69012 14.4418 3.8543 14.5342 4.0293 14.5342C4.0483 14.5342 4.06743 14.533 4.08643 14.5308C4.15168 14.5233 5.66214 14.3364 7.50439 12.9604C7.67239 12.9712 7.8385 12.9766 8 12.9766C11.4462 12.9766 14.25 10.739 14.25 7.98828C14.25 5.23753 11.4462 3 8 3ZM8 4C10.8948 4 13.25 5.78903 13.25 7.98828C13.25 10.1875 10.8948 11.9766 8 11.9766C7.8055 11.9766 7.60225 11.968 7.396 11.9497C7.271 11.9382 7.1454 11.9752 7.0459 12.0527C6.3589 12.5855 5.72033 12.9308 5.20508 13.1528C5.38383 12.8648 5.57691 12.5418 5.76416 12.2061C5.83416 12.0813 5.84705 11.9324 5.7998 11.7974C5.75255 11.6624 5.64983 11.5542 5.51758 11.5C3.81033 10.7993 2.75 9.45328 2.75 7.98828C2.75 5.78903 5.10525 4 8 4ZM5.5 7.25C5.08575 7.25 4.75 7.58575 4.75 8C4.75 8.41425 5.08575 8.75 5.5 8.75C5.91425 8.75 6.25 8.41425 6.25 8C6.25 7.58575 5.91425 7.25 5.5 7.25ZM8 7.25C7.58575 7.25 7.25 7.58575 7.25 8C7.25 8.41425 7.58575 8.75 8 8.75C8.41425 8.75 8.75 8.41425 8.75 8C8.75 7.58575 8.41425 7.25 8 7.25ZM10.5 7.25C10.0857 7.25 9.75 7.58575 9.75 8C9.75 8.41425 10.0857 8.75 10.5 8.75C10.9143 8.75 11.25 8.41425 11.25 8C11.25 7.58575 10.9143 7.25 10.5 7.25Z", fill: "currentColor" }));
2978
+ const SessionListItem = memo(
2979
+ ({
2980
+ children,
2981
+ session,
2982
+ deletable = true,
2983
+ limit = 100,
2984
+ deleteIcon = /* @__PURE__ */ jsx(SvgTrash, {}),
2985
+ chatIcon = /* @__PURE__ */ jsx(SvgChat, { className: "mr-2" })
2986
+ }) => {
2987
+ const { activeSessionId, selectSession, deleteSession, theme } = useContext(ChatContext);
2988
+ const Comp = children ? Slot : ListItem;
2989
+ const handleSelect = useCallback(() => {
2990
+ selectSession?.(session.id);
2991
+ }, [selectSession, session.id]);
2992
+ const handleDelete = useCallback(
2993
+ (e) => {
2994
+ e.stopPropagation();
2995
+ deleteSession(session.id);
2996
+ },
2997
+ [deleteSession, session.id]
2998
+ );
2999
+ return /* @__PURE__ */ jsx(
3000
+ Comp,
3001
+ {
3002
+ dense: true,
3003
+ disableGutters: true,
3004
+ active: session.id === activeSessionId,
3005
+ className: cn(theme.sessions.session.base, {
3006
+ [theme.sessions.session.active]: session.id === activeSessionId
3007
+ }),
3008
+ onClick: handleSelect,
3009
+ start: chatIcon,
3010
+ end: /* @__PURE__ */ jsx(Fragment, { children: deletable && /* @__PURE__ */ jsx(
3011
+ IconButton,
3012
+ {
3013
+ size: "small",
3014
+ variant: "text",
3015
+ onClick: handleDelete,
3016
+ className: cn(theme.sessions.session.delete),
3017
+ children: deleteIcon
3018
+ }
3019
+ ) }),
3020
+ children: children || /* @__PURE__ */ jsx(Ellipsis, { value: session.title, limit })
3021
+ }
3022
+ );
3023
+ }
3024
+ );
3025
+ SessionListItem.displayName = "SessionListItem";
3026
+ const SessionsList = ({
3027
+ children,
3028
+ templates
3029
+ }) => {
3030
+ const { theme, isCompact, activeSessionId, createSession } = useContext(ChatContext);
3031
+ const isVisible = isCompact && !activeSessionId;
3032
+ return (!isCompact || isVisible) && /* @__PURE__ */ jsxs(
3033
+ motion.div,
3034
+ {
3035
+ initial: { translateX: "-100%" },
3036
+ animate: {
3037
+ translateX: "0%",
3038
+ transition: {
3039
+ type: "tween",
3040
+ ease: "linear",
3041
+ duration: 0.2,
3042
+ when: "beforeChildren"
3043
+ }
3044
+ },
3045
+ exit: { translateX: "-100%" },
3046
+ className: cn(theme.sessions.base, {
3047
+ [theme.sessions.companion]: isCompact,
3048
+ [theme.sessions.console]: !isCompact
3049
+ }),
3050
+ children: [
3051
+ /* @__PURE__ */ jsx(List, { children }),
3052
+ templates && !activeSessionId && /* @__PURE__ */ jsx("div", { className: "mt-4", children: templates.map((template) => /* @__PURE__ */ jsx("div", { onClick: () => createSession?.(), children: /* @__PURE__ */ jsx(
3053
+ SessionListItem,
3054
+ {
3055
+ session: {
3056
+ id: template.id,
3057
+ title: template.title,
3058
+ conversations: []
3059
+ },
3060
+ chatIcon: template.icon,
3061
+ deletable: false
3062
+ }
3063
+ ) }, template.id)) })
3064
+ ]
3065
+ }
3066
+ );
3067
+ };
3068
+ const SvgPlus = (props) => /* @__PURE__ */ React.createElement("svg", { width: 17, height: 17, viewBox: "0 0 17 17", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props }, /* @__PURE__ */ React.createElement("g", { id: "add" }, /* @__PURE__ */ React.createElement("path", { id: "Vector", d: "M13.1667 9.16658H9.16671V13.1666H7.83337V9.16658H3.83337V7.83325H7.83337V3.83325H9.16671V7.83325H13.1667V9.16658Z", fill: "currentColor" })));
3069
+ const NewSessionButton = ({
3070
+ children,
3071
+ newSessionText = "New Session"
3072
+ }) => {
3073
+ const { theme, createSession, disabled } = useContext(ChatContext);
3074
+ const Comp = children ? Slot : Button;
3075
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
3076
+ Comp,
3077
+ {
3078
+ fullWidth: true,
3079
+ disableMargins: true,
3080
+ color: "primary",
3081
+ start: /* @__PURE__ */ jsx(SvgPlus, {}),
3082
+ className: cn(theme.sessions.create),
3083
+ disabled,
3084
+ onClick: createSession,
3085
+ children: children || newSessionText
3086
+ }
3087
+ ) });
3088
+ };
3089
+ const sortOrder = [
3090
+ "Today",
3091
+ "Yesterday",
3092
+ "Last Week",
3093
+ "Last Month",
3094
+ "January",
3095
+ "February",
3096
+ "March",
3097
+ "April",
3098
+ "May",
3099
+ "June",
3100
+ "July",
3101
+ "August",
3102
+ "September",
3103
+ "October",
3104
+ "November",
3105
+ "December",
3106
+ "Last Year"
3107
+ ];
3108
+ const sortOrderMap = new Map(sortOrder.map((v, i) => [v, i]));
3109
+ function groupSessionsByDate(sessions) {
3110
+ const grouped = {};
3111
+ const now = /* @__PURE__ */ new Date();
3112
+ sessions.forEach((session) => {
3113
+ const createdAt = session.createdAt ? new Date(session.createdAt) : null;
3114
+ let group;
3115
+ if (!createdAt || isNaN(createdAt.getTime())) {
3116
+ group = "Last Year";
3117
+ } else if (isToday(createdAt)) {
3118
+ group = "Today";
3119
+ } else if (isYesterday(createdAt)) {
3120
+ group = "Yesterday";
3121
+ } else if (isThisWeek(createdAt)) {
3122
+ group = "Last Week";
3123
+ } else if (differenceInYears(now, createdAt) === 0) {
3124
+ const monthDiff = now.getMonth() - createdAt.getMonth();
3125
+ const yearDiff = now.getFullYear() - createdAt.getFullYear();
3126
+ const adjustedMonthDiff = yearDiff > 0 ? monthDiff + 12 : monthDiff;
3127
+ if (adjustedMonthDiff === 1 || adjustedMonthDiff === 0 && now.getDate() > createdAt.getDate()) {
3128
+ group = "Last Month";
3129
+ } else {
3130
+ group = format(createdAt, "MMMM");
3131
+ }
3132
+ } else {
3133
+ group = "Last Year";
3134
+ }
3135
+ if (!grouped[group]) grouped[group] = [];
3136
+ grouped[group].push(session);
3137
+ });
3138
+ const sortedGroups = Object.keys(grouped).sort(
3139
+ (a, b) => (sortOrderMap.get(a) ?? 999) - (sortOrderMap.get(b) ?? 999)
3140
+ );
3141
+ return sortedGroups.map((heading) => ({
3142
+ heading,
3143
+ sessions: grouped[heading].sort(
3144
+ (a, b) => (b.createdAt ? new Date(b.createdAt).getTime() : 0) - (a.createdAt ? new Date(a.createdAt).getTime() : 0)
3145
+ )
3146
+ }));
3147
+ }
3148
+ const SessionsGroup = ({
3149
+ heading,
3150
+ children
3151
+ }) => {
3152
+ const { theme } = useContext(ChatContext);
3153
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3154
+ heading && /* @__PURE__ */ jsx(
3155
+ ListItem,
3156
+ {
3157
+ disableGutters: true,
3158
+ disablePadding: true,
3159
+ className: cn(theme.sessions.group),
3160
+ children: heading
3161
+ }
3162
+ ),
3163
+ children
3164
+ ] });
3165
+ };
3166
+ const SessionGroups = ({ children }) => {
3167
+ const { sessions } = useContext(ChatContext);
3168
+ const groups = useMemo(() => groupSessionsByDate(sessions), [sessions]);
3169
+ return /* @__PURE__ */ jsx(Fragment, { children: children ? children(groups) : groups.map(({ heading, sessions: sessions2 }) => /* @__PURE__ */ jsx(SessionsGroup, { heading, children: sessions2.map((session) => /* @__PURE__ */ jsx(SessionListItem, { session }, session.id)) }, heading)) });
3170
+ };
3171
+ const AppBar = ({
3172
+ content,
3173
+ theme: customTheme = chatTheme
3174
+ }) => {
3175
+ const theme = useComponentTheme("chat", customTheme);
3176
+ return /* @__PURE__ */ jsx("div", { className: cn(theme.appbar), children: content });
3177
+ };
3178
+ const DEFAULT_MODIFIERS = [offset({ mainAxis: 0, crossAxis: -40 })];
3179
+ const ChatBubble = memo(
3180
+ ({
3181
+ children,
3182
+ bubbleContent,
3183
+ position = "right-end",
3184
+ modifiers = DEFAULT_MODIFIERS,
3185
+ className
3186
+ }) => {
3187
+ const [isOpen, setIsOpen] = useState(false);
3188
+ const ref = useRef(null);
3189
+ const handleOpen = useCallback(() => setIsOpen(true), []);
3190
+ const handleClose = useCallback(() => setIsOpen(false), []);
3191
+ const handleToggle = useCallback(() => setIsOpen((prev) => !prev), []);
3192
+ const renderContent = useCallback(() => /* @__PURE__ */ jsx(Fragment, { children }), [children]);
3193
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3194
+ /* @__PURE__ */ jsx(
3195
+ ConnectedOverlay,
3196
+ {
3197
+ placement: position,
3198
+ modifiers,
3199
+ reference: ref.current,
3200
+ open: isOpen,
3201
+ onOpen: handleOpen,
3202
+ onClose: handleClose,
3203
+ content: renderContent
3204
+ }
3205
+ ),
3206
+ /* @__PURE__ */ jsx("div", { ref, className, onClick: handleToggle, children: bubbleContent })
3207
+ ] });
3208
+ }
3209
+ );
3210
+ const ChatSuggestion = ({
3211
+ content,
3212
+ onClick
3213
+ }) => {
3214
+ const { theme, disabled, isLoading } = useContext(ChatContext);
3215
+ const handleClick = () => {
3216
+ if (disabled || isLoading) return;
3217
+ onClick?.(content);
3218
+ };
3219
+ return /* @__PURE__ */ jsx(
3220
+ Button,
3221
+ {
3222
+ type: "button",
3223
+ variant: "outline",
3224
+ disableMargins: true,
3225
+ className: cn(theme.suggestions.item.base, {
3226
+ "opacity-50 cursor-not-allowed": disabled || isLoading
3227
+ }),
3228
+ onClick: handleClick,
3229
+ disabled: disabled || isLoading,
3230
+ children: /* @__PURE__ */ jsx("span", { className: cn(theme.suggestions.item.text), children: content })
3231
+ }
3232
+ );
3233
+ };
3234
+ const ChatSuggestions = ({
3235
+ suggestions,
3236
+ className,
3237
+ onSuggestionClick,
3238
+ children
3239
+ }) => {
3240
+ const { theme } = useContext(ChatContext);
3241
+ if (!suggestions || suggestions.length === 0) {
3242
+ return null;
3243
+ }
3244
+ return /* @__PURE__ */ jsx("div", { className: cn(theme.suggestions.base, className), children: suggestions.map((suggestion) => {
3245
+ if (children && isValidElement(children)) {
3246
+ return cloneElement(children, {
3247
+ key: suggestion.id,
3248
+ ...suggestion,
3249
+ onClick: onSuggestionClick
3250
+ });
3251
+ }
3252
+ return /* @__PURE__ */ jsx(
3253
+ ChatSuggestion,
3254
+ {
3255
+ ...suggestion,
3256
+ onClick: onSuggestionClick
3257
+ },
3258
+ suggestion.id
3259
+ );
3260
+ }) });
3261
+ };
3262
+ const SvgSpinner = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }));
3263
+ const SvgCheck = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", ...props }, /* @__PURE__ */ React.createElement("polyline", { points: "20 6 9 17 4 12" }));
3264
+ const SvgError = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", ...props }, /* @__PURE__ */ React.createElement("circle", { cx: 12, cy: 12, r: 10 }), /* @__PURE__ */ React.createElement("line", { x1: 15, y1: 9, x2: 9, y2: 15 }), /* @__PURE__ */ React.createElement("line", { x1: 9, y1: 9, x2: 15, y2: 15 }));
3265
+ const StatusIcon = ({
3266
+ state,
3267
+ className,
3268
+ colorClassName
3269
+ }) => {
3270
+ switch (state) {
3271
+ case "loading":
3272
+ return /* @__PURE__ */ jsx(
3273
+ motion.div,
3274
+ {
3275
+ animate: { rotate: 360 },
3276
+ transition: { duration: 1, repeat: Infinity, ease: "linear" },
3277
+ className: cn(className, colorClassName),
3278
+ children: /* @__PURE__ */ jsx(SvgSpinner, { className: "w-full h-full" })
3279
+ }
3280
+ );
3281
+ case "complete":
3282
+ return /* @__PURE__ */ jsx(
3283
+ motion.div,
3284
+ {
3285
+ initial: { scale: 0, opacity: 0 },
3286
+ animate: { scale: 1, opacity: 1 },
3287
+ transition: { type: "spring", stiffness: 500, damping: 25 },
3288
+ className: cn(className, colorClassName),
3289
+ children: /* @__PURE__ */ jsx(SvgCheck, { className: "w-full h-full" })
3290
+ }
3291
+ );
3292
+ case "error":
3293
+ return /* @__PURE__ */ jsx(
3294
+ motion.div,
3295
+ {
3296
+ initial: { scale: 0, opacity: 0 },
3297
+ animate: { scale: 1, opacity: 1 },
3298
+ transition: { type: "spring", stiffness: 500, damping: 25 },
3299
+ className: cn(className, colorClassName),
3300
+ children: /* @__PURE__ */ jsx(SvgError, { className: "w-full h-full" })
3301
+ }
3302
+ );
3303
+ }
3304
+ };
3305
+ const MessageStatusItem = ({ step }) => {
3306
+ const { theme: chatTheme$1 } = useContext(ChatContext);
3307
+ const theme = (chatTheme$1 ?? chatTheme).status.steps.step;
3308
+ const stepStatus = step.status || "loading";
3309
+ return /* @__PURE__ */ jsxs(
3310
+ motion.div,
3311
+ {
3312
+ initial: { opacity: 0, x: -10 },
3313
+ animate: { opacity: 1, x: 0 },
3314
+ transition: { duration: 0.2 },
3315
+ className: theme.base,
3316
+ children: [
3317
+ /* @__PURE__ */ jsx(
3318
+ StatusIcon,
3319
+ {
3320
+ state: stepStatus,
3321
+ className: theme.icon,
3322
+ colorClassName: theme[stepStatus]
3323
+ }
3324
+ ),
3325
+ /* @__PURE__ */ jsx(
3326
+ "span",
3327
+ {
3328
+ className: cn(
3329
+ theme.text,
3330
+ stepStatus === "loading" && theme.loading,
3331
+ stepStatus === "complete" && theme.complete,
3332
+ stepStatus === "error" && theme.error
3333
+ ),
3334
+ children: step.text
3335
+ }
3336
+ )
3337
+ ]
3338
+ }
3339
+ );
3340
+ };
3341
+ const MessageStatus = ({
3342
+ status = "loading",
3343
+ text,
3344
+ steps,
3345
+ icon,
3346
+ className,
3347
+ children
3348
+ }) => {
3349
+ const { theme: chatTheme$1 } = useContext(ChatContext);
3350
+ const theme = (chatTheme$1 ?? chatTheme).status;
3351
+ const Comp = children ? Slot : "div";
3352
+ return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
3353
+ motion.div,
3354
+ {
3355
+ initial: { opacity: 0, y: -10 },
3356
+ animate: { opacity: 1, y: 0 },
3357
+ exit: { opacity: 0, y: -10 },
3358
+ transition: { duration: 0.2 },
3359
+ children: /* @__PURE__ */ jsx(Comp, { className: cn(theme.base, className), children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
3360
+ /* @__PURE__ */ jsxs("div", { className: theme.header, children: [
3361
+ icon || /* @__PURE__ */ jsx(
3362
+ StatusIcon,
3363
+ {
3364
+ state: status,
3365
+ className: theme.icon.base,
3366
+ colorClassName: theme.icon[status]
3367
+ }
3368
+ ),
3369
+ /* @__PURE__ */ jsx(
3370
+ "span",
3371
+ {
3372
+ className: cn(
3373
+ theme.text.base,
3374
+ status === "loading" && theme.text.loading,
3375
+ status === "complete" && theme.text.complete,
3376
+ status === "error" && theme.text.error
3377
+ ),
3378
+ children: text
3379
+ }
3380
+ )
3381
+ ] }),
3382
+ steps && steps.length > 0 && /* @__PURE__ */ jsx("div", { className: theme.steps.base, children: steps.map((step) => /* @__PURE__ */ jsx(MessageStatusItem, { step }, step.id)) })
3383
+ ] }) })
3384
+ }
3385
+ ) });
3386
+ };
3387
+ var AgUiEventType = /* @__PURE__ */ ((AgUiEventType2) => {
3388
+ AgUiEventType2["RUN_STARTED"] = "RUN_STARTED";
3389
+ AgUiEventType2["RUN_FINISHED"] = "RUN_FINISHED";
3390
+ AgUiEventType2["RUN_ERROR"] = "RUN_ERROR";
3391
+ AgUiEventType2["STEP_STARTED"] = "STEP_STARTED";
3392
+ AgUiEventType2["STEP_FINISHED"] = "STEP_FINISHED";
3393
+ AgUiEventType2["TEXT_MESSAGE_START"] = "TEXT_MESSAGE_START";
3394
+ AgUiEventType2["TEXT_MESSAGE_CONTENT"] = "TEXT_MESSAGE_CONTENT";
3395
+ AgUiEventType2["TEXT_MESSAGE_END"] = "TEXT_MESSAGE_END";
3396
+ AgUiEventType2["TEXT_MESSAGE_CHUNK"] = "TEXT_MESSAGE_CHUNK";
3397
+ AgUiEventType2["TOOL_CALL_START"] = "TOOL_CALL_START";
3398
+ AgUiEventType2["TOOL_CALL_ARGS"] = "TOOL_CALL_ARGS";
3399
+ AgUiEventType2["TOOL_CALL_END"] = "TOOL_CALL_END";
3400
+ AgUiEventType2["TOOL_CALL_RESULT"] = "TOOL_CALL_RESULT";
3401
+ AgUiEventType2["TOOL_CALL_CHUNK"] = "TOOL_CALL_CHUNK";
3402
+ AgUiEventType2["STATE_SNAPSHOT"] = "STATE_SNAPSHOT";
3403
+ AgUiEventType2["STATE_DELTA"] = "STATE_DELTA";
3404
+ AgUiEventType2["MESSAGES_SNAPSHOT"] = "MESSAGES_SNAPSHOT";
3405
+ AgUiEventType2["RAW"] = "RAW";
3406
+ AgUiEventType2["CUSTOM"] = "CUSTOM";
3407
+ return AgUiEventType2;
3408
+ })(AgUiEventType || {});
3409
+ function generateId() {
3410
+ return Math.random().toString(36).substring(2, 11);
3411
+ }
3412
+ function addConversationToSession(sessions, sessionId, conversation) {
3413
+ return sessions.map((s) => {
3414
+ if (s.id !== sessionId) return s;
3415
+ return {
3416
+ ...s,
3417
+ updatedAt: conversation.createdAt,
3418
+ conversations: [...s.conversations, conversation]
3419
+ };
3420
+ });
3421
+ }
3422
+ function updateConversationInSession(sessions, sessionId, conversationId, response) {
3423
+ return sessions.map((s) => {
3424
+ if (s.id !== sessionId) return s;
3425
+ return {
3426
+ ...s,
3427
+ updatedAt: /* @__PURE__ */ new Date(),
3428
+ conversations: s.conversations.map((c) => {
3429
+ if (c.id !== conversationId) return c;
3430
+ return { ...c, response, updatedAt: /* @__PURE__ */ new Date() };
3431
+ })
3432
+ };
3433
+ });
3434
+ }
3435
+ function sessionsToAgUiMessages(session) {
3436
+ const messages = [];
3437
+ for (const conv of session.conversations) {
3438
+ messages.push({
3439
+ id: `${conv.id}-q`,
3440
+ role: "user",
3441
+ content: conv.question
3442
+ });
3443
+ if (conv.response) {
3444
+ messages.push({
3445
+ id: `${conv.id}-r`,
3446
+ role: "assistant",
3447
+ content: conv.response
3448
+ });
3449
+ }
3450
+ }
3451
+ return messages;
3452
+ }
3453
+ function parseSSELine(line) {
3454
+ const trimmed = line.trim();
3455
+ if (!trimmed || trimmed.startsWith(":")) return null;
3456
+ if (trimmed.startsWith("data:")) {
3457
+ const data = trimmed.slice(5).trim();
3458
+ if (data === "[DONE]") return null;
3459
+ try {
3460
+ return JSON.parse(data);
3461
+ } catch (err) {
3462
+ return new Error(
3463
+ `Failed to parse AG-UI event: ${err instanceof Error ? err.message : err}`
3464
+ );
3465
+ }
3466
+ }
3467
+ return null;
3468
+ }
3469
+ async function* parseSSE(response, signal) {
3470
+ const reader = response.body?.getReader();
3471
+ if (!reader) {
3472
+ throw new Error("Response body is not readable");
3473
+ }
3474
+ const decoder = new TextDecoder();
3475
+ let buffer = "";
3476
+ try {
3477
+ while (!signal.aborted) {
3478
+ const { done, value } = await reader.read();
3479
+ if (done) break;
3480
+ buffer += decoder.decode(value, { stream: true });
3481
+ const lines = buffer.split("\n");
3482
+ buffer = lines.pop() || "";
3483
+ for (const line of lines) {
3484
+ const result = parseSSELine(line);
3485
+ if (result !== null) yield result;
3486
+ }
3487
+ }
3488
+ if (buffer.trim()) {
3489
+ const result = parseSSELine(buffer);
3490
+ if (result !== null) yield result;
3491
+ }
3492
+ } finally {
3493
+ reader.releaseLock();
3494
+ }
3495
+ }
3496
+ function useAgUi({
3497
+ agent,
3498
+ initialSessions = [],
3499
+ initialActiveSessionId,
3500
+ tools = [],
3501
+ context = [],
3502
+ forwardedProps = {},
3503
+ headers = {},
3504
+ onToolCall,
3505
+ onError,
3506
+ onEvent
3507
+ }) {
3508
+ const [sessions, setSessions] = useState(initialSessions);
3509
+ const [activeSessionId, setActiveSessionId] = useState(
3510
+ initialActiveSessionId
3511
+ );
3512
+ const [isLoading, setIsLoading] = useState(false);
3513
+ const abortRef = useRef(null);
3514
+ const onToolCallRef = useRef(onToolCall);
3515
+ onToolCallRef.current = onToolCall;
3516
+ const onErrorRef = useRef(onError);
3517
+ onErrorRef.current = onError;
3518
+ const onEventRef = useRef(onEvent);
3519
+ onEventRef.current = onEvent;
3520
+ useEffect(() => {
3521
+ return () => {
3522
+ abortRef.current?.abort();
3523
+ };
3524
+ }, []);
3525
+ const selectSession = useCallback((sessionId) => {
3526
+ setActiveSessionId(sessionId);
3527
+ }, []);
3528
+ const deleteSession = useCallback(
3529
+ (sessionId) => {
3530
+ setSessions((prev) => prev.filter((s) => s.id !== sessionId));
3531
+ if (activeSessionId === sessionId) {
3532
+ setActiveSessionId(void 0);
3533
+ }
3534
+ },
3535
+ [activeSessionId]
3536
+ );
3537
+ const createSession = useCallback(() => {
3538
+ const id = generateId();
3539
+ const newSession = {
3540
+ id,
3541
+ title: "New Session",
3542
+ createdAt: /* @__PURE__ */ new Date(),
3543
+ updatedAt: /* @__PURE__ */ new Date(),
3544
+ conversations: []
3545
+ };
3546
+ setSessions((prev) => [newSession, ...prev]);
3547
+ setActiveSessionId(id);
3548
+ }, []);
3549
+ const stopMessage = useCallback(() => {
3550
+ abortRef.current?.abort();
3551
+ abortRef.current = null;
3552
+ setIsLoading(false);
3553
+ }, []);
3554
+ const sendMessage = useCallback(
3555
+ async (message) => {
3556
+ abortRef.current?.abort();
3557
+ const abortController = new AbortController();
3558
+ abortRef.current = abortController;
3559
+ let sessionId = activeSessionId;
3560
+ if (!sessionId) {
3561
+ sessionId = generateId();
3562
+ const newSession = {
3563
+ id: sessionId,
3564
+ title: message.slice(0, 50),
3565
+ createdAt: /* @__PURE__ */ new Date(),
3566
+ updatedAt: /* @__PURE__ */ new Date(),
3567
+ conversations: []
3568
+ };
3569
+ setSessions((prev) => [newSession, ...prev]);
3570
+ setActiveSessionId(sessionId);
3571
+ }
3572
+ const conversationId = generateId();
3573
+ const now = /* @__PURE__ */ new Date();
3574
+ setSessions(
3575
+ (prev) => addConversationToSession(prev, sessionId, {
3576
+ id: conversationId,
3577
+ question: message,
3578
+ createdAt: now
3579
+ })
3580
+ );
3581
+ setIsLoading(true);
3582
+ const currentSession = [
3583
+ ...sessions.find((s) => s.id === sessionId)?.conversations ?? []
3584
+ ];
3585
+ const historyMessages = sessionsToAgUiMessages({
3586
+ conversations: currentSession
3587
+ });
3588
+ historyMessages.push({
3589
+ id: `${conversationId}-q`,
3590
+ role: "user",
3591
+ content: message
3592
+ });
3593
+ const runId = generateId();
3594
+ const input = {
3595
+ threadId: sessionId,
3596
+ runId,
3597
+ messages: historyMessages,
3598
+ tools,
3599
+ context,
3600
+ state: null,
3601
+ forwardedProps
3602
+ };
3603
+ try {
3604
+ const response = await fetch(agent, {
3605
+ method: "POST",
3606
+ headers: {
3607
+ "Content-Type": "application/json",
3608
+ Accept: "text/event-stream",
3609
+ ...headers
3610
+ },
3611
+ body: JSON.stringify(input),
3612
+ signal: abortController.signal
3613
+ });
3614
+ if (!response.ok) {
3615
+ throw new Error(
3616
+ `Agent returned ${response.status}: ${response.statusText}`
3617
+ );
3618
+ }
3619
+ let responseText = "";
3620
+ const toolCalls = /* @__PURE__ */ new Map();
3621
+ const updateResponse = (text) => {
3622
+ setSessions(
3623
+ (prev) => updateConversationInSession(prev, sessionId, conversationId, text)
3624
+ );
3625
+ };
3626
+ for await (const eventOrError of parseSSE(
3627
+ response,
3628
+ abortController.signal
3629
+ )) {
3630
+ if (eventOrError instanceof Error) {
3631
+ onErrorRef.current?.(eventOrError);
3632
+ continue;
3633
+ }
3634
+ const event = eventOrError;
3635
+ onEventRef.current?.(event);
3636
+ switch (event.type) {
3637
+ case AgUiEventType.TEXT_MESSAGE_CONTENT: {
3638
+ responseText += event.delta;
3639
+ updateResponse(responseText);
3640
+ break;
3641
+ }
3642
+ case AgUiEventType.TEXT_MESSAGE_CHUNK: {
3643
+ if (event.delta) {
3644
+ responseText += event.delta;
3645
+ updateResponse(responseText);
3646
+ }
3647
+ break;
3648
+ }
3649
+ case AgUiEventType.TOOL_CALL_START: {
3650
+ toolCalls.set(event.toolCallId, {
3651
+ name: event.toolCallName,
3652
+ args: ""
3653
+ });
3654
+ break;
3655
+ }
3656
+ case AgUiEventType.TOOL_CALL_ARGS: {
3657
+ const tc = toolCalls.get(event.toolCallId);
3658
+ if (tc) {
3659
+ tc.args += event.delta;
3660
+ }
3661
+ break;
3662
+ }
3663
+ case AgUiEventType.TOOL_CALL_END: {
3664
+ const tc = toolCalls.get(event.toolCallId);
3665
+ if (tc && onToolCallRef.current) {
3666
+ try {
3667
+ await onToolCallRef.current({
3668
+ toolCallId: event.toolCallId,
3669
+ toolCallName: tc.name,
3670
+ args: tc.args
3671
+ });
3672
+ } catch {
3673
+ }
3674
+ }
3675
+ toolCalls.delete(event.toolCallId);
3676
+ break;
3677
+ }
3678
+ case AgUiEventType.RUN_ERROR: {
3679
+ const err = new Error(event.message);
3680
+ onErrorRef.current?.(err);
3681
+ break;
3682
+ }
3683
+ case AgUiEventType.RUN_FINISHED: {
3684
+ break;
3685
+ }
3686
+ }
3687
+ }
3688
+ } catch (err) {
3689
+ if (err instanceof DOMException && err.name === "AbortError") {
3690
+ return;
3691
+ }
3692
+ const error = err instanceof Error ? err : new Error(String(err));
3693
+ onErrorRef.current?.(error);
3694
+ } finally {
3695
+ if (abortRef.current === abortController) {
3696
+ abortRef.current = null;
3697
+ }
3698
+ setIsLoading(false);
3699
+ }
3700
+ },
3701
+ [activeSessionId, agent, context, forwardedProps, headers, sessions, tools]
3702
+ );
3703
+ return {
3704
+ sessions,
3705
+ activeSessionId,
3706
+ isLoading,
3707
+ selectSession,
3708
+ deleteSession,
3709
+ createSession,
3710
+ sendMessage,
3711
+ stopMessage
3712
+ };
3713
+ }
3714
+ function validateSpec(raw, definitions) {
3715
+ let parsed;
3716
+ try {
3717
+ parsed = JSON.parse(raw);
3718
+ } catch {
3719
+ return {
3720
+ ok: false,
3721
+ error: {
3722
+ type: "invalid_json",
3723
+ message: "Failed to parse component JSON",
3724
+ raw
3725
+ }
3726
+ };
3727
+ }
3728
+ const specArray = Array.isArray(parsed) ? parsed : [parsed];
3729
+ const validated = [];
3730
+ for (const item of specArray) {
3731
+ const result = validateSingleSpec(item, raw, definitions);
3732
+ if (!result.ok) {
3733
+ return { ok: false, error: result.error };
3734
+ }
3735
+ validated.push(result.spec);
3736
+ }
3737
+ return { ok: true, specs: validated };
3738
+ }
3739
+ function validateSingleSpec(item, raw, definitions) {
3740
+ if (!item || typeof item !== "object" || !("type" in item)) {
3741
+ return {
3742
+ ok: false,
3743
+ error: {
3744
+ type: "invalid_json",
3745
+ message: 'Component spec must be an object with a "type" field',
3746
+ raw
3747
+ }
3748
+ };
3749
+ }
3750
+ const spec = item;
3751
+ if (typeof spec.type !== "string") {
3752
+ return {
3753
+ ok: false,
3754
+ error: {
3755
+ type: "invalid_json",
3756
+ message: '"type" must be a string',
3757
+ raw
3758
+ }
3759
+ };
3760
+ }
3761
+ const componentType = spec.type;
3762
+ const definition = definitions[componentType];
3763
+ if (!definition) {
3764
+ return {
3765
+ ok: false,
3766
+ error: {
3767
+ type: "unknown_component",
3768
+ message: `Unknown component "${componentType}". Available: ${Object.keys(definitions).join(", ")}`,
3769
+ raw,
3770
+ componentType
3771
+ }
3772
+ };
3773
+ }
3774
+ const props = spec.props && typeof spec.props === "object" && !Array.isArray(spec.props) ? spec.props : {};
3775
+ const parseResult = definition.props.safeParse(props);
3776
+ if (!parseResult.success) {
3777
+ return {
3778
+ ok: false,
3779
+ error: {
3780
+ type: "invalid_props",
3781
+ message: `Invalid props for "${componentType}": ${parseResult.error.issues.map((i) => i.message).join(", ")}`,
3782
+ raw,
3783
+ componentType,
3784
+ issues: parseResult.error.issues.map((i) => ({
3785
+ message: i.message,
3786
+ path: i.path
3787
+ }))
3788
+ }
3789
+ };
3790
+ }
3791
+ let validatedChildren;
3792
+ if (spec.children) {
3793
+ if (!Array.isArray(spec.children)) {
3794
+ return {
3795
+ ok: false,
3796
+ error: {
3797
+ type: "invalid_json",
3798
+ message: '"children" must be an array',
3799
+ raw,
3800
+ componentType
3801
+ }
3802
+ };
3803
+ }
3804
+ validatedChildren = [];
3805
+ for (const child of spec.children) {
3806
+ const childResult = validateSingleSpec(child, raw, definitions);
3807
+ if (!childResult.ok) {
3808
+ return childResult;
3809
+ }
3810
+ validatedChildren.push(childResult.spec);
3811
+ }
3812
+ }
3813
+ return {
3814
+ ok: true,
3815
+ spec: {
3816
+ type: componentType,
3817
+ props: parseResult.data,
3818
+ ...validatedChildren ? { children: validatedChildren } : {}
3819
+ }
3820
+ };
3821
+ }
3822
+ const ComponentRenderer = ({
3823
+ raw,
3824
+ definitions,
3825
+ options
3826
+ }) => {
3827
+ const { theme, sendMessage } = useContext(ChatContext);
3828
+ const result = useMemo(
3829
+ () => validateSpec(raw, definitions),
3830
+ [raw, definitions]
3831
+ );
3832
+ if (!result.ok) {
3833
+ const error = result.error;
3834
+ const custom = options?.onError?.(error);
3835
+ if (custom !== void 0) {
3836
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3837
+ }
3838
+ return /* @__PURE__ */ jsx(
3839
+ ComponentError,
3840
+ {
3841
+ title: errorTitle(error.type),
3842
+ message: error.message,
3843
+ code: error.raw
3844
+ }
3845
+ );
3846
+ }
3847
+ const specs = result.specs;
3848
+ return /* @__PURE__ */ jsx("div", { className: theme.component?.base, children: specs.map((spec, index) => /* @__PURE__ */ jsx(
3849
+ SpecRenderer,
3850
+ {
3851
+ spec,
3852
+ definitions,
3853
+ options,
3854
+ sendMessage
3855
+ },
3856
+ `${spec.type}-${index}-${stableKey(spec)}`
3857
+ )) });
3858
+ };
3859
+ const SpecRenderer = ({
3860
+ spec,
3861
+ definitions,
3862
+ options,
3863
+ sendMessage
3864
+ }) => {
3865
+ const definition = definitions[spec.type];
3866
+ if (!definition) {
3867
+ const error = {
3868
+ type: "unknown_component",
3869
+ message: `Unknown component "${spec.type}"`,
3870
+ raw: JSON.stringify(spec),
3871
+ componentType: spec.type
3872
+ };
3873
+ const custom = options?.onError?.(error);
3874
+ if (custom !== void 0) {
3875
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3876
+ }
3877
+ return /* @__PURE__ */ jsx(ComponentError, { title: errorTitle(error.type), message: error.message });
3878
+ }
3879
+ const RenderedComponent = definition.component;
3880
+ const children = spec.children?.map((child, index) => /* @__PURE__ */ jsx(
3881
+ SpecRenderer,
3882
+ {
3883
+ spec: child,
3884
+ definitions,
3885
+ options,
3886
+ sendMessage
3887
+ },
3888
+ `${child.type}-${index}-${stableKey(child)}`
3889
+ ));
3890
+ return /* @__PURE__ */ jsx(SpecErrorBoundary, { spec, options, children: /* @__PURE__ */ jsx(RenderedComponent, { ...spec.props, sendMessage, children }) });
3891
+ };
3892
+ class SpecErrorBoundary extends Component {
3893
+ constructor() {
3894
+ super(...arguments);
3895
+ this.state = { error: null };
3896
+ }
3897
+ static getDerivedStateFromError(error) {
3898
+ return { error };
3899
+ }
3900
+ render() {
3901
+ if (this.state.error) {
3902
+ const { spec, options } = this.props;
3903
+ const catalogError = {
3904
+ type: "render_error",
3905
+ message: `Error rendering "${spec.type}": ${this.state.error.message}`,
3906
+ raw: JSON.stringify(spec),
3907
+ componentType: spec.type
3908
+ };
3909
+ const custom = options?.onError?.(catalogError);
3910
+ if (custom !== void 0) {
3911
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3912
+ }
3913
+ return /* @__PURE__ */ jsx(
3914
+ ComponentError,
3915
+ {
3916
+ title: errorTitle(catalogError.type),
3917
+ message: catalogError.message
3918
+ }
3919
+ );
3920
+ }
3921
+ return this.props.children;
3922
+ }
3923
+ }
3924
+ function stableKey(spec) {
3925
+ const str = JSON.stringify({
3926
+ t: spec.type,
3927
+ p: spec.props,
3928
+ c: spec.children
3929
+ });
3930
+ let h = 0;
3931
+ for (let i = 0; i < str.length; i++) {
3932
+ h = h * 31 + str.charCodeAt(i) | 0;
3933
+ }
3934
+ return (h >>> 0).toString(36);
3935
+ }
3936
+ function errorTitle(type) {
3937
+ switch (type) {
3938
+ case "unknown_component":
3939
+ return "Unknown Component";
3940
+ case "invalid_props":
3941
+ return "Invalid Props";
3942
+ case "render_error":
3943
+ return "Render Error";
3944
+ default:
3945
+ return "Invalid Component";
3946
+ }
3947
+ }
3948
+ function getChildText(children) {
3949
+ if (children === null || children === void 0) {
3950
+ return "";
3951
+ }
3952
+ if (typeof children === "string") {
3953
+ return children;
3954
+ }
3955
+ if (typeof children === "number") {
3956
+ return String(children);
3957
+ }
3958
+ if (Array.isArray(children)) {
3959
+ return children.map(getChildText).join("");
3960
+ }
3961
+ if (typeof children === "object") {
3962
+ if ("props" in children && children.props) {
3963
+ const element = children;
3964
+ return getChildText(element.props.children);
3965
+ }
3966
+ }
3967
+ return "";
3968
+ }
3969
+ function createComponentPre(definitions, options) {
3970
+ const language = options?.language ?? "component";
3971
+ const className = `language-${language}`;
3972
+ const ComponentPre = ({ children, ...props }) => {
3973
+ if (children && typeof children === "object" && "props" in children) {
3974
+ const codeElement = children;
3975
+ if (codeElement.props?.className === className) {
3976
+ const codeContent = getChildText(codeElement.props?.children);
3977
+ if (codeContent) {
3978
+ return /* @__PURE__ */ jsx(
3979
+ ComponentRenderer,
3980
+ {
3981
+ raw: codeContent,
3982
+ definitions,
3983
+ options
3984
+ }
3985
+ );
3986
+ }
3987
+ }
3988
+ }
3989
+ return /* @__PURE__ */ jsx("pre", { ...props, children });
3990
+ };
3991
+ ComponentPre.displayName = "ComponentPre";
3992
+ return ComponentPre;
3993
+ }
3994
+ function describeJsonSchemaProperty(prop, indent = "") {
3995
+ const description = prop.description ? ` // ${prop.description}` : "";
3996
+ if (prop.anyOf) {
3997
+ const nonNull = prop.anyOf.filter((s) => !(s.type === "null"));
3998
+ const hasNull = prop.anyOf.some((s) => s.type === "null");
3999
+ if (nonNull.length === 1 && hasNull) {
4000
+ return `${describeJsonSchemaProperty(nonNull[0], indent)} | null${description}`;
4001
+ }
4002
+ const parts = prop.anyOf.map(
4003
+ (s) => describeJsonSchemaProperty(s, indent)
4004
+ );
4005
+ return `${parts.join(" | ")}${description}`;
4006
+ }
4007
+ if (prop.enum) {
4008
+ return `${prop.enum.map((v) => `"${v}"`).join(" | ")}${description}`;
4009
+ }
4010
+ if (prop.type === "array") {
4011
+ const items = prop.items ? describeJsonSchemaProperty(prop.items, indent) : "any";
4012
+ return `${items}[]${description}`;
4013
+ }
4014
+ if (prop.type === "object" && prop.properties) {
4015
+ const required = new Set(prop.required ?? []);
4016
+ const fields = [];
4017
+ for (const [key, value] of Object.entries(prop.properties)) {
4018
+ const opt = required.has(key) ? "" : "?";
4019
+ fields.push(
4020
+ `${indent} ${key}: ${describeJsonSchemaProperty(value, indent + " ")}${opt}`
4021
+ );
4022
+ }
4023
+ return `{
4024
+ ${fields.join(",\n")}
4025
+ ${indent}}${description}`;
4026
+ }
4027
+ if (prop.type === "string") return `string${description}`;
4028
+ if (prop.type === "number" || prop.type === "integer")
4029
+ return `number${description}`;
4030
+ if (prop.type === "boolean") return `boolean${description}`;
4031
+ if (prop.type === "null") return `null${description}`;
4032
+ return `any${description}`;
4033
+ }
4034
+ function describeProps(schema) {
4035
+ try {
4036
+ const jsonSchema = z.toJSONSchema(schema);
4037
+ if (jsonSchema.type === "object" && jsonSchema.properties) {
4038
+ return describeJsonSchemaProperty(jsonSchema);
4039
+ }
4040
+ return "Record<string, any>";
4041
+ } catch {
4042
+ return "Record<string, any>";
4043
+ }
4044
+ }
4045
+ function generatePrompt(definitions, language = "component") {
4046
+ const names = Object.keys(definitions);
4047
+ if (names.length === 0) {
4048
+ return "";
4049
+ }
4050
+ const componentDocs = names.map((name) => {
4051
+ const def = definitions[name];
4052
+ const propsDesc = describeProps(def.props);
4053
+ return `- **${name}**: ${def.description}
4054
+ Props: ${propsDesc}`;
4055
+ }).join("\n\n");
4056
+ return `When you need to render a dynamic UI component in your response, use a fenced code block with language \`${language}\` containing a JSON object:
4057
+
4058
+ \`\`\`${language}
4059
+ { "type": "ComponentName", "props": { ... } }
4060
+ \`\`\`
4061
+
4062
+ For multiple components, use a JSON array:
4063
+
4064
+ \`\`\`${language}
4065
+ [
4066
+ { "type": "ComponentA", "props": { ... } },
4067
+ { "type": "ComponentB", "props": { ... } }
4068
+ ]
4069
+ \`\`\`
4070
+
4071
+ For nested/composed layouts, use the "children" field:
4072
+
4073
+ \`\`\`${language}
4074
+ {
4075
+ "type": "Parent",
4076
+ "props": { ... },
4077
+ "children": [
4078
+ { "type": "Child", "props": { ... } }
4079
+ ]
4080
+ }
4081
+ \`\`\`
4082
+
4083
+ Available components:
4084
+
4085
+ ${componentDocs}`;
4086
+ }
4087
+ function componentCatalog(definitions, options) {
4088
+ const language = options?.language ?? "component";
4089
+ const plugin = remarkComponent.bind(void 0, {
4090
+ language
4091
+ });
4092
+ const Pre = createComponentPre(definitions, options);
4093
+ return {
4094
+ remarkPlugin: plugin,
4095
+ components: { pre: Pre },
4096
+ systemPrompt: () => generatePrompt(definitions, language),
4097
+ definitions
4098
+ };
4099
+ }
4100
+ function createChartComponentDef() {
4101
+ const chartPropsSchema = z.object({
4102
+ type: z.enum([
4103
+ "bar",
4104
+ "line",
4105
+ "area",
4106
+ "pie",
4107
+ "radialBar",
4108
+ "radialArea",
4109
+ "sparkline"
4110
+ ]).describe("Chart type"),
4111
+ data: z.array(z.object({ key: z.string(), data: z.number() })).describe("Array of { key, data } data points"),
4112
+ width: z.number().describe("Chart width in px").optional(),
4113
+ height: z.number().describe("Chart height in px").optional(),
4114
+ title: z.string().describe("Chart title").optional()
4115
+ });
4116
+ return {
4117
+ description: "Renders a chart. Supported types: bar, line, area, pie, radialBar, radialArea, sparkline",
4118
+ props: chartPropsSchema,
4119
+ component: ({
4120
+ children: _children,
4121
+ sendMessage: _sendMessage,
4122
+ ...config
4123
+ }) => /* @__PURE__ */ jsx(ChartRenderer, { config })
4124
+ };
4125
+ }
18
4126
  export {
19
- A as AgUiEventType,
20
- b as AppBar,
21
- C as ChartRenderer,
22
- c as Chat,
23
- d as ChatBubble,
24
- e as ChatContext,
25
- f as ChatInput,
26
- g as ChatSuggestion,
27
- h as ChatSuggestions,
28
- i as CodeHighlighter,
29
- j as ComponentError,
30
- k as ComponentRenderer,
31
- F as FileInput,
32
- M as Markdown,
33
- l as MentionList,
34
- m as MessageActions,
35
- n as MessageFile,
36
- o as MessageFiles,
37
- p as MessageQuestion,
38
- q as MessageResponse,
39
- r as MessageSource,
40
- s as MessageSources,
41
- t as MessageStatus,
42
- u as MessageStatusItem,
43
- N as NewSessionButton,
44
- R as RichTextInput,
45
- v as SessionEmpty,
46
- w as SessionGroups,
47
- x as SessionListItem,
48
- y as SessionMessage,
49
- z as SessionMessagePanel,
50
- B as SessionMessages,
51
- D as SessionMessagesHeader,
52
- E as SessionsGroup,
53
- G as SessionsList,
54
- H as StatusIcon,
55
- T as TableComponent,
56
- I as TableDataCell,
57
- J as TableHeaderCell,
58
- K as bitcoinMatcher,
59
- L as chatTheme,
60
- O as commonRedactMatchers,
61
- P as componentCatalog,
62
- Q as createChartComponentDef,
63
- U as createComponentPre,
64
- V as creditCardMatcher,
65
- W as dark,
66
- X as generatePrompt,
67
- Y as groupSessionsByDate,
68
- Z as light,
69
- _ as remarkComponent,
70
- $ as remarkCve,
71
- a0 as remarkRedact,
72
- a1 as ssnMatcher,
73
- a2 as useAgUi,
74
- a3 as validateSpec
4127
+ AgUiEventType,
4128
+ AppBar,
4129
+ CSVFileRenderer,
4130
+ ChartRenderer,
4131
+ Chat,
4132
+ ChatBubble,
4133
+ ChatContext,
4134
+ ChatInput,
4135
+ ChatSuggestion,
4136
+ ChatSuggestions,
4137
+ CodeHighlighter,
4138
+ ComponentError,
4139
+ ComponentRenderer,
4140
+ DefaultFileRenderer,
4141
+ FileInput,
4142
+ ImageFileRenderer,
4143
+ Markdown,
4144
+ MentionList,
4145
+ MessageActions,
4146
+ MessageFile,
4147
+ MessageFiles,
4148
+ MessageQuestion,
4149
+ MessageResponse,
4150
+ MessageSource,
4151
+ MessageSources,
4152
+ MessageStatus,
4153
+ MessageStatusItem,
4154
+ NewSessionButton,
4155
+ PDFFileRenderer,
4156
+ RichTextInput,
4157
+ SessionEmpty,
4158
+ SessionGroups,
4159
+ SessionListItem,
4160
+ SessionMessage,
4161
+ SessionMessagePanel,
4162
+ SessionMessages,
4163
+ SessionMessagesHeader,
4164
+ SessionsGroup,
4165
+ SessionsList,
4166
+ StatusIcon,
4167
+ TableComponent,
4168
+ TableDataCell,
4169
+ TableHeaderCell,
4170
+ bitcoinMatcher,
4171
+ chatTheme,
4172
+ commonRedactMatchers,
4173
+ componentCatalog,
4174
+ createChartComponentDef,
4175
+ createComponentPre,
4176
+ creditCardMatcher,
4177
+ dark,
4178
+ generatePrompt,
4179
+ groupSessionsByDate,
4180
+ light,
4181
+ remarkComponent,
4182
+ remarkCve,
4183
+ remarkRedact,
4184
+ ssnMatcher,
4185
+ useAgUi,
4186
+ validateSpec
75
4187
  };
76
4188
  //# sourceMappingURL=index.js.map