@oakkles/llm-ui-react 0.1.1

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 ADDED
@@ -0,0 +1,2518 @@
1
+ import { createContext, useState, useEffect, useRef, useMemo, useCallback, useContext, isValidElement } from 'react';
2
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
+ import { clsx } from 'clsx';
4
+ import { twMerge } from 'tailwind-merge';
5
+ import ReactMarkdown from 'react-markdown';
6
+ import remarkGfm from 'remark-gfm';
7
+ import { useShikiHighlighter } from 'react-shiki';
8
+
9
+ // src/components/bubble/BubblePrimitive.tsx
10
+ var statusTextMap = {
11
+ sending: "\u53D1\u9001\u4E2D",
12
+ sent: "\u5DF2\u53D1\u9001",
13
+ error: "\u53D1\u9001\u5931\u8D25"
14
+ };
15
+ function formatTimestamp(timestamp) {
16
+ if (typeof timestamp === "string") {
17
+ return timestamp;
18
+ }
19
+ return timestamp.toLocaleTimeString([], {
20
+ hour: "2-digit",
21
+ minute: "2-digit"
22
+ });
23
+ }
24
+ function BubblePrimitive({
25
+ role,
26
+ content,
27
+ avatar,
28
+ timestamp,
29
+ status,
30
+ loading,
31
+ children,
32
+ actions,
33
+ className,
34
+ style
35
+ }) {
36
+ return /* @__PURE__ */ jsxs(
37
+ "div",
38
+ {
39
+ className,
40
+ style,
41
+ "data-role": role,
42
+ "data-status": status,
43
+ "data-loading": loading,
44
+ "data-has-actions": actions ? "" : void 0,
45
+ children: [
46
+ avatar && /* @__PURE__ */ jsx("div", { className: "llm-bubble__avatar", "data-slot": "bubble-avatar", children: avatar }),
47
+ /* @__PURE__ */ jsxs("div", { className: "llm-bubble__body", "data-slot": "bubble-body", children: [
48
+ (children ?? content) && /* @__PURE__ */ jsx("div", { className: "llm-bubble__content", "data-slot": "bubble-content", children: children ?? content }),
49
+ (timestamp || status || loading) && /* @__PURE__ */ jsxs("div", { className: "llm-bubble__meta", "data-slot": "bubble-meta", children: [
50
+ timestamp && /* @__PURE__ */ jsx("span", { className: "llm-bubble__time", "data-slot": "bubble-time", children: formatTimestamp(timestamp) }),
51
+ status && /* @__PURE__ */ jsx("span", { className: "llm-bubble__status", "data-slot": "bubble-status", children: statusTextMap[status] }),
52
+ loading && /* @__PURE__ */ jsx("span", { className: "llm-bubble__loading", "data-slot": "bubble-loading", children: "\u601D\u8003\u4E2D" })
53
+ ] }),
54
+ actions ? /* @__PURE__ */ jsx("div", { className: "llm-bubble__actions", "data-slot": "bubble-actions", children: actions }) : null
55
+ ] })
56
+ ]
57
+ }
58
+ );
59
+ }
60
+ function cn(...inputs) {
61
+ return twMerge(clsx(inputs));
62
+ }
63
+ function Bubble({ className, ...props }) {
64
+ return /* @__PURE__ */ jsx(BubblePrimitive, { className: cn("llm-bubble", className), ...props });
65
+ }
66
+ function getLanguageLabel(language) {
67
+ const normalizedLanguage = language.toLowerCase();
68
+ const labels = {
69
+ astro: "Astro",
70
+ bash: "Bash",
71
+ bat: "Batch",
72
+ c: "C",
73
+ cpp: "C++",
74
+ "c++": "C++",
75
+ csharp: "C#",
76
+ cs: "C#",
77
+ css: "CSS",
78
+ dart: "Dart",
79
+ diff: "Diff",
80
+ docker: "Dockerfile",
81
+ dockerfile: "Dockerfile",
82
+ elixir: "Elixir",
83
+ ex: "Elixir",
84
+ go: "Go",
85
+ graphql: "GraphQL",
86
+ groovy: "Groovy",
87
+ html: "HTML",
88
+ java: "Java",
89
+ javascript: "JavaScript",
90
+ js: "JavaScript",
91
+ json: "JSON",
92
+ jsonc: "JSONC",
93
+ jsx: "JavaScript JSX",
94
+ kotlin: "Kotlin",
95
+ kt: "Kotlin",
96
+ less: "Less",
97
+ lua: "Lua",
98
+ markdown: "Markdown",
99
+ md: "Markdown",
100
+ objectivec: "Objective-C",
101
+ objc: "Objective-C",
102
+ perl: "Perl",
103
+ php: "PHP",
104
+ plaintext: "Plain Text",
105
+ powershell: "PowerShell",
106
+ prisma: "Prisma",
107
+ ps1: "PowerShell",
108
+ py: "Python",
109
+ python: "Python",
110
+ r: "R",
111
+ rb: "Ruby",
112
+ ruby: "Ruby",
113
+ rust: "Rust",
114
+ rs: "Rust",
115
+ sass: "Sass",
116
+ scala: "Scala",
117
+ scss: "SCSS",
118
+ shell: "Shell",
119
+ sh: "Shell",
120
+ sql: "SQL",
121
+ svelte: "Svelte",
122
+ swift: "Swift",
123
+ text: "Plain Text",
124
+ toml: "TOML",
125
+ ts: "TypeScript",
126
+ tsx: "TypeScript TSX",
127
+ typescript: "TypeScript",
128
+ vue: "Vue",
129
+ wasm: "WebAssembly",
130
+ xml: "XML",
131
+ yaml: "YAML",
132
+ yml: "YAML",
133
+ zig: "Zig"
134
+ };
135
+ return labels[normalizedLanguage] ?? language;
136
+ }
137
+ function CodeIcon() {
138
+ return /* @__PURE__ */ jsxs(
139
+ "svg",
140
+ {
141
+ "aria-hidden": "true",
142
+ className: "llm-code-highlighter__code-icon",
143
+ fill: "none",
144
+ height: "16",
145
+ viewBox: "0 0 24 24",
146
+ width: "16",
147
+ xmlns: "http://www.w3.org/2000/svg",
148
+ children: [
149
+ /* @__PURE__ */ jsx(
150
+ "path",
151
+ {
152
+ d: "m9 18-6-6 6-6",
153
+ stroke: "currentColor",
154
+ strokeLinecap: "round",
155
+ strokeLinejoin: "round",
156
+ strokeWidth: "2"
157
+ }
158
+ ),
159
+ /* @__PURE__ */ jsx(
160
+ "path",
161
+ {
162
+ d: "m15 6 6 6-6 6",
163
+ stroke: "currentColor",
164
+ strokeLinecap: "round",
165
+ strokeLinejoin: "round",
166
+ strokeWidth: "2"
167
+ }
168
+ )
169
+ ]
170
+ }
171
+ );
172
+ }
173
+ function CopyIcon() {
174
+ return /* @__PURE__ */ jsxs(
175
+ "svg",
176
+ {
177
+ "aria-hidden": "true",
178
+ className: "llm-code-highlighter__copy-icon",
179
+ fill: "none",
180
+ height: "16",
181
+ viewBox: "0 0 24 24",
182
+ width: "16",
183
+ xmlns: "http://www.w3.org/2000/svg",
184
+ children: [
185
+ /* @__PURE__ */ jsx(
186
+ "rect",
187
+ {
188
+ height: "13",
189
+ rx: "2",
190
+ stroke: "currentColor",
191
+ strokeLinecap: "round",
192
+ strokeLinejoin: "round",
193
+ strokeWidth: "2",
194
+ width: "13",
195
+ x: "9",
196
+ y: "2"
197
+ }
198
+ ),
199
+ /* @__PURE__ */ jsx(
200
+ "path",
201
+ {
202
+ d: "M5 9H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-1",
203
+ stroke: "currentColor",
204
+ strokeLinecap: "round",
205
+ strokeLinejoin: "round",
206
+ strokeWidth: "2"
207
+ }
208
+ )
209
+ ]
210
+ }
211
+ );
212
+ }
213
+ var codeTheme = { light: "github-light", dark: "github-dark" };
214
+ function CheckIcon() {
215
+ return /* @__PURE__ */ jsx(
216
+ "svg",
217
+ {
218
+ "aria-hidden": "true",
219
+ className: "llm-code-highlighter__copy-icon",
220
+ fill: "none",
221
+ height: "16",
222
+ viewBox: "0 0 24 24",
223
+ width: "16",
224
+ xmlns: "http://www.w3.org/2000/svg",
225
+ children: /* @__PURE__ */ jsx(
226
+ "path",
227
+ {
228
+ d: "m20 6-11 11-5-5",
229
+ stroke: "currentColor",
230
+ strokeLinecap: "round",
231
+ strokeLinejoin: "round",
232
+ strokeWidth: "2"
233
+ }
234
+ )
235
+ }
236
+ );
237
+ }
238
+ function CodeHighlighterPrimitive({
239
+ code,
240
+ copyable = true,
241
+ language = "text",
242
+ showLineNumbers = false,
243
+ startingLineNumber = 1,
244
+ className
245
+ }) {
246
+ const [copied, setCopied] = useState(false);
247
+ const languageLabel = getLanguageLabel(language);
248
+ const highlightedCode = useShikiHighlighter(code, language, codeTheme, {
249
+ defaultColor: "light-dark()",
250
+ showLineNumbers,
251
+ startingLineNumber
252
+ });
253
+ useEffect(() => {
254
+ if (!copied) return;
255
+ const timer = window.setTimeout(() => {
256
+ setCopied(false);
257
+ }, 1500);
258
+ return () => window.clearTimeout(timer);
259
+ }, [copied]);
260
+ const handleCopy = async () => {
261
+ await navigator.clipboard.writeText(code);
262
+ setCopied(true);
263
+ };
264
+ return /* @__PURE__ */ jsxs("div", { className, children: [
265
+ /* @__PURE__ */ jsxs("div", { className: "llm-code-highlighter__header", children: [
266
+ /* @__PURE__ */ jsxs("div", { className: "llm-code-highlighter__title", children: [
267
+ /* @__PURE__ */ jsx(CodeIcon, {}),
268
+ /* @__PURE__ */ jsx("span", { className: "llm-code-highlighter__language", children: languageLabel })
269
+ ] }),
270
+ copyable ? /* @__PURE__ */ jsx(
271
+ "button",
272
+ {
273
+ "aria-label": copied ? "Code copied" : "Copy code",
274
+ className: "llm-code-highlighter__copy",
275
+ onClick: handleCopy,
276
+ type: "button",
277
+ children: copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {})
278
+ }
279
+ ) : null
280
+ ] }),
281
+ /* @__PURE__ */ jsx("div", { className: "llm-code-highlighter__body", children: highlightedCode ? /* @__PURE__ */ jsx("div", { className: "rs-root not-prose", children: highlightedCode }) : /* @__PURE__ */ jsx("pre", { "aria-hidden": "true", className: "llm-code-highlighter__placeholder", children: /* @__PURE__ */ jsx("code", { children: code }) }) })
282
+ ] });
283
+ }
284
+ function CodeHighlighter({
285
+ className,
286
+ ...props
287
+ }) {
288
+ return /* @__PURE__ */ jsx(
289
+ CodeHighlighterPrimitive,
290
+ {
291
+ className: cn("llm-code-highlighter", className),
292
+ ...props
293
+ }
294
+ );
295
+ }
296
+
297
+ // src/utils/markdown.ts
298
+ function sanitizeMarkdown(content) {
299
+ const codeBlockCount = (content.match(/```/g) || []).length;
300
+ if (codeBlockCount % 2 !== 0) {
301
+ content += `${content.endsWith("\n") ? "" : "\n"}
302
+ \`\`\``;
303
+ }
304
+ const stripped = content.replace(/```/g, "");
305
+ const inlineCount = (stripped.match(/`/g) || []).length;
306
+ if (inlineCount % 2 !== 0) {
307
+ content += "`";
308
+ }
309
+ return content;
310
+ }
311
+ function getCodeLanguage(className) {
312
+ return className?.match(/language-([\w-]+)/)?.[1] ?? "text";
313
+ }
314
+ function getCodeContent(children) {
315
+ return String(children ?? "").replace(/\n$/, "");
316
+ }
317
+ function hasOpenCodeFence(content) {
318
+ return (content.match(/```/g) ?? []).length % 2 !== 0;
319
+ }
320
+ function isCodeElement(node) {
321
+ return isValidElement(node);
322
+ }
323
+ var markdownComponents = {
324
+ code: ({ children, className }) => /* @__PURE__ */ jsx("code", { className, children }),
325
+ img: ({ alt, src, title }) => /* @__PURE__ */ jsx("img", { alt, loading: "lazy", src, title }),
326
+ pre: ({ children }) => {
327
+ if (!isCodeElement(children)) return null;
328
+ return /* @__PURE__ */ jsx(
329
+ CodeHighlighter,
330
+ {
331
+ code: getCodeContent(children.props.children),
332
+ language: getCodeLanguage(children.props.className)
333
+ }
334
+ );
335
+ }
336
+ };
337
+ function MarkPrimitive({
338
+ content,
339
+ streaming = false,
340
+ className
341
+ }) {
342
+ const hasStreamingCodeFence = streaming && hasOpenCodeFence(content);
343
+ const parsedContent = hasStreamingCodeFence ? sanitizeMarkdown(content) : content;
344
+ return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(
345
+ ReactMarkdown,
346
+ {
347
+ remarkPlugins: [remarkGfm],
348
+ components: markdownComponents,
349
+ children: parsedContent
350
+ }
351
+ ) });
352
+ }
353
+ function Mark({ className, ...props }) {
354
+ return /* @__PURE__ */ jsx(MarkPrimitive, { className: cn("llm-mark", className), ...props });
355
+ }
356
+ var senderPrefixActions = [
357
+ { key: "upload", label: "\u4E0A\u4F20\u9644\u4EF6" },
358
+ { key: "image", label: "\u6DFB\u52A0\u56FE\u7247" },
359
+ { key: "search", label: "\u8054\u7F51\u641C\u7D22" },
360
+ { key: "reasoning", label: "\u6DF1\u5EA6\u601D\u8003" }
361
+ ];
362
+ var defaultModelOptions = [
363
+ { value: "gpt-4o", label: "GPT-4o" },
364
+ { value: "claude-sonnet-4", label: "Claude Sonnet 4" },
365
+ { value: "gemini-2.5-pro", label: "Gemini 2.5 Pro" },
366
+ { value: "deepseek-r1", label: "DeepSeek R1" }
367
+ ];
368
+ function PlusIcon() {
369
+ return /* @__PURE__ */ jsxs(
370
+ "svg",
371
+ {
372
+ "aria-hidden": "true",
373
+ className: "llm-sender__prefix-icon",
374
+ fill: "none",
375
+ height: "16",
376
+ viewBox: "0 0 24 24",
377
+ width: "16",
378
+ xmlns: "http://www.w3.org/2000/svg",
379
+ children: [
380
+ /* @__PURE__ */ jsx(
381
+ "path",
382
+ {
383
+ d: "M12 5v14",
384
+ stroke: "currentColor",
385
+ strokeLinecap: "round",
386
+ strokeLinejoin: "round",
387
+ strokeWidth: "2"
388
+ }
389
+ ),
390
+ /* @__PURE__ */ jsx(
391
+ "path",
392
+ {
393
+ d: "M5 12h14",
394
+ stroke: "currentColor",
395
+ strokeLinecap: "round",
396
+ strokeLinejoin: "round",
397
+ strokeWidth: "2"
398
+ }
399
+ )
400
+ ]
401
+ }
402
+ );
403
+ }
404
+ function VoiceIcon() {
405
+ return /* @__PURE__ */ jsxs(
406
+ "svg",
407
+ {
408
+ "aria-hidden": "true",
409
+ className: "llm-sender__suffix-icon",
410
+ fill: "none",
411
+ height: "16",
412
+ viewBox: "0 0 24 24",
413
+ width: "16",
414
+ xmlns: "http://www.w3.org/2000/svg",
415
+ children: [
416
+ /* @__PURE__ */ jsx(
417
+ "path",
418
+ {
419
+ d: "M12 3a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V6a3 3 0 0 0-3-3Z",
420
+ stroke: "currentColor",
421
+ strokeLinecap: "round",
422
+ strokeLinejoin: "round",
423
+ strokeWidth: "2"
424
+ }
425
+ ),
426
+ /* @__PURE__ */ jsx(
427
+ "path",
428
+ {
429
+ d: "M19 10v2a7 7 0 0 1-14 0v-2",
430
+ stroke: "currentColor",
431
+ strokeLinecap: "round",
432
+ strokeLinejoin: "round",
433
+ strokeWidth: "2"
434
+ }
435
+ ),
436
+ /* @__PURE__ */ jsx(
437
+ "path",
438
+ {
439
+ d: "M12 19v3",
440
+ stroke: "currentColor",
441
+ strokeLinecap: "round",
442
+ strokeLinejoin: "round",
443
+ strokeWidth: "2"
444
+ }
445
+ )
446
+ ]
447
+ }
448
+ );
449
+ }
450
+ function SendIcon() {
451
+ return /* @__PURE__ */ jsxs(
452
+ "svg",
453
+ {
454
+ "aria-hidden": "true",
455
+ className: "llm-sender__send-icon",
456
+ fill: "none",
457
+ height: "16",
458
+ viewBox: "0 0 24 24",
459
+ width: "16",
460
+ xmlns: "http://www.w3.org/2000/svg",
461
+ children: [
462
+ /* @__PURE__ */ jsx(
463
+ "path",
464
+ {
465
+ d: "M5 12h14",
466
+ stroke: "currentColor",
467
+ strokeLinecap: "round",
468
+ strokeLinejoin: "round",
469
+ strokeWidth: "2"
470
+ }
471
+ ),
472
+ /* @__PURE__ */ jsx(
473
+ "path",
474
+ {
475
+ d: "m13 6 6 6-6 6",
476
+ stroke: "currentColor",
477
+ strokeLinecap: "round",
478
+ strokeLinejoin: "round",
479
+ strokeWidth: "2"
480
+ }
481
+ )
482
+ ]
483
+ }
484
+ );
485
+ }
486
+ function StopIcon() {
487
+ return /* @__PURE__ */ jsx(
488
+ "svg",
489
+ {
490
+ "aria-hidden": "true",
491
+ className: "llm-sender__send-icon",
492
+ fill: "none",
493
+ height: "16",
494
+ viewBox: "0 0 24 24",
495
+ width: "16",
496
+ xmlns: "http://www.w3.org/2000/svg",
497
+ children: /* @__PURE__ */ jsx(
498
+ "rect",
499
+ {
500
+ height: "8",
501
+ rx: "1.5",
502
+ stroke: "currentColor",
503
+ strokeWidth: "2",
504
+ width: "8",
505
+ x: "8",
506
+ y: "8"
507
+ }
508
+ )
509
+ }
510
+ );
511
+ }
512
+ function SenderPrimitive({
513
+ value,
514
+ defaultValue = "",
515
+ onChange,
516
+ onSend,
517
+ onCancel,
518
+ onPrefixAction,
519
+ onModelChange,
520
+ onVoiceClick,
521
+ loading = false,
522
+ disabled = false,
523
+ placeholder = "\u8F93\u5165\u6D88\u606F...",
524
+ model,
525
+ modelOptions = defaultModelOptions,
526
+ prefix,
527
+ suffix,
528
+ className
529
+ }) {
530
+ const [innerMessage, setInnerMessage] = useState(defaultValue);
531
+ const controlled = value !== void 0;
532
+ const message = controlled ? value : innerMessage;
533
+ const textareaRef = useRef(null);
534
+ const prefixMenuRef = useRef(null);
535
+ const modelMenuRef = useRef(null);
536
+ const [prefixMenuOpen, setPrefixMenuOpen] = useState(false);
537
+ const [modelMenuOpen, setModelMenuOpen] = useState(false);
538
+ const [selectedModel, setSelectedModel] = useState(
539
+ model ?? modelOptions[0]?.value ?? ""
540
+ );
541
+ useEffect(() => {
542
+ const textarea = textareaRef.current;
543
+ if (!textarea) return;
544
+ textarea.style.height = "auto";
545
+ textarea.style.height = `${textarea.scrollHeight}px`;
546
+ }, [message]);
547
+ useEffect(() => {
548
+ const handlePointerDown = (event) => {
549
+ const target = event.target;
550
+ if (!(target instanceof Node)) return;
551
+ if (!prefixMenuRef.current?.contains(target)) {
552
+ setPrefixMenuOpen(false);
553
+ }
554
+ if (!modelMenuRef.current?.contains(target)) {
555
+ setModelMenuOpen(false);
556
+ }
557
+ };
558
+ document.addEventListener("pointerdown", handlePointerDown);
559
+ return () => {
560
+ document.removeEventListener("pointerdown", handlePointerDown);
561
+ };
562
+ }, []);
563
+ const handleMessageChange = (nextMessage) => {
564
+ if (!controlled) {
565
+ setInnerMessage(nextMessage);
566
+ }
567
+ onChange?.(nextMessage);
568
+ };
569
+ const handleSend = () => {
570
+ const nextMessage = message.trim();
571
+ if (!nextMessage || disabled || loading) return;
572
+ onSend?.(nextMessage);
573
+ handleMessageChange("");
574
+ };
575
+ const handleAction = () => {
576
+ if (loading) {
577
+ onCancel?.();
578
+ return;
579
+ }
580
+ handleSend();
581
+ };
582
+ const handleKeyDown = (event) => {
583
+ if (event.key !== "Enter" || event.shiftKey) return;
584
+ event.preventDefault();
585
+ handleSend();
586
+ };
587
+ const handlePrefixAction = (action) => {
588
+ onPrefixAction?.(action);
589
+ setPrefixMenuOpen(false);
590
+ };
591
+ const selectedModelLabel = modelOptions.find((option) => option.value === selectedModel)?.label ?? selectedModel;
592
+ const handleModelChange = (nextModel) => {
593
+ setSelectedModel(nextModel);
594
+ onModelChange?.(nextModel);
595
+ setModelMenuOpen(false);
596
+ };
597
+ const handleVoiceClick = () => {
598
+ if (disabled) return;
599
+ onVoiceClick?.();
600
+ };
601
+ return /* @__PURE__ */ jsxs(
602
+ "div",
603
+ {
604
+ className,
605
+ "data-disabled": disabled ? "" : void 0,
606
+ "data-loading": loading ? "" : void 0,
607
+ children: [
608
+ /* @__PURE__ */ jsx(
609
+ "textarea",
610
+ {
611
+ className: "llm-sender__textarea",
612
+ disabled,
613
+ onChange: (event) => handleMessageChange(event.target.value),
614
+ ref: textareaRef,
615
+ onKeyDown: handleKeyDown,
616
+ placeholder,
617
+ rows: 1,
618
+ value: message
619
+ }
620
+ ),
621
+ /* @__PURE__ */ jsxs("div", { className: "llm-sender__footer", children: [
622
+ /* @__PURE__ */ jsx("div", { className: "llm-sender__prefix", children: prefix ?? /* @__PURE__ */ jsxs("div", { className: "llm-sender__prefix-menu", ref: prefixMenuRef, children: [
623
+ /* @__PURE__ */ jsx(
624
+ "button",
625
+ {
626
+ "aria-expanded": prefixMenuOpen,
627
+ "aria-label": "\u6253\u5F00\u66F4\u591A\u64CD\u4F5C",
628
+ className: "llm-sender__prefix-trigger",
629
+ disabled,
630
+ onClick: () => setPrefixMenuOpen((open) => !open),
631
+ type: "button",
632
+ children: /* @__PURE__ */ jsx(PlusIcon, {})
633
+ }
634
+ ),
635
+ prefixMenuOpen ? /* @__PURE__ */ jsx("div", { className: "llm-sender__prefix-list", role: "menu", children: senderPrefixActions.map((action) => /* @__PURE__ */ jsx(
636
+ "button",
637
+ {
638
+ className: "llm-sender__prefix-item",
639
+ onClick: () => handlePrefixAction(action.key),
640
+ role: "menuitem",
641
+ type: "button",
642
+ children: action.label
643
+ },
644
+ action.key
645
+ )) }) : null
646
+ ] }) }),
647
+ /* @__PURE__ */ jsxs("div", { className: "llm-sender__actions", children: [
648
+ /* @__PURE__ */ jsx("div", { className: "llm-sender__suffix", children: suffix ?? /* @__PURE__ */ jsxs(Fragment, { children: [
649
+ /* @__PURE__ */ jsxs("div", { className: "llm-sender__model-menu", ref: modelMenuRef, children: [
650
+ /* @__PURE__ */ jsx(
651
+ "button",
652
+ {
653
+ "aria-expanded": modelMenuOpen,
654
+ className: "llm-sender__suffix-button llm-sender__model",
655
+ disabled,
656
+ onClick: () => setModelMenuOpen((open) => !open),
657
+ type: "button",
658
+ children: selectedModelLabel
659
+ }
660
+ ),
661
+ modelMenuOpen ? /* @__PURE__ */ jsx("div", { className: "llm-sender__model-list", role: "menu", children: modelOptions.map((option) => /* @__PURE__ */ jsx(
662
+ "button",
663
+ {
664
+ "aria-current": option.value === selectedModel ? "true" : void 0,
665
+ className: "llm-sender__model-item",
666
+ onClick: () => handleModelChange(option.value),
667
+ role: "menuitem",
668
+ type: "button",
669
+ children: option.label
670
+ },
671
+ option.value
672
+ )) }) : null
673
+ ] }),
674
+ /* @__PURE__ */ jsx(
675
+ "button",
676
+ {
677
+ "aria-label": "\u8BED\u97F3\u8F93\u5165",
678
+ className: "llm-sender__suffix-button",
679
+ disabled,
680
+ onClick: handleVoiceClick,
681
+ type: "button",
682
+ children: /* @__PURE__ */ jsx(VoiceIcon, {})
683
+ }
684
+ )
685
+ ] }) }),
686
+ /* @__PURE__ */ jsx(
687
+ "button",
688
+ {
689
+ "aria-label": loading ? "\u505C\u6B62\u751F\u6210" : "\u53D1\u9001\u6D88\u606F",
690
+ className: "llm-sender__send",
691
+ "data-loading": loading ? "" : void 0,
692
+ disabled: disabled || !loading && !message.trim(),
693
+ onClick: handleAction,
694
+ type: "button",
695
+ children: loading ? /* @__PURE__ */ jsx(StopIcon, {}) : /* @__PURE__ */ jsx(SendIcon, {})
696
+ }
697
+ )
698
+ ] })
699
+ ] })
700
+ ]
701
+ }
702
+ );
703
+ }
704
+ function Sender({ className, ...props }) {
705
+ return /* @__PURE__ */ jsx(SenderPrimitive, { className: cn("llm-sender", className), ...props });
706
+ }
707
+ function SparkIcon() {
708
+ return /* @__PURE__ */ jsxs(
709
+ "svg",
710
+ {
711
+ "aria-hidden": "true",
712
+ className: "llm-think__icon",
713
+ fill: "none",
714
+ height: "16",
715
+ viewBox: "0 0 24 24",
716
+ width: "16",
717
+ xmlns: "http://www.w3.org/2000/svg",
718
+ children: [
719
+ /* @__PURE__ */ jsx(
720
+ "path",
721
+ {
722
+ d: "M12 3 9.9 8.2 5 10.1l4.9 1.9L12 17l2.1-5 4.9-1.9-4.9-1.9L12 3Z",
723
+ stroke: "currentColor",
724
+ strokeLinejoin: "round",
725
+ strokeWidth: "1.8"
726
+ }
727
+ ),
728
+ /* @__PURE__ */ jsx(
729
+ "path",
730
+ {
731
+ d: "m18 15-.9 2.1L15 18l2.1.9L18 21l.9-2.1L21 18l-2.1-.9L18 15Z",
732
+ stroke: "currentColor",
733
+ strokeLinejoin: "round",
734
+ strokeWidth: "1.8"
735
+ }
736
+ )
737
+ ]
738
+ }
739
+ );
740
+ }
741
+ function ChevronIcon() {
742
+ return /* @__PURE__ */ jsx(
743
+ "svg",
744
+ {
745
+ "aria-hidden": "true",
746
+ className: "llm-think__chevron",
747
+ fill: "none",
748
+ height: "16",
749
+ viewBox: "0 0 24 24",
750
+ width: "16",
751
+ xmlns: "http://www.w3.org/2000/svg",
752
+ children: /* @__PURE__ */ jsx(
753
+ "path",
754
+ {
755
+ d: "m6 9 6 6 6-6",
756
+ stroke: "currentColor",
757
+ strokeLinecap: "round",
758
+ strokeLinejoin: "round",
759
+ strokeWidth: "2"
760
+ }
761
+ )
762
+ }
763
+ );
764
+ }
765
+ function ThinkingDots() {
766
+ return /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "llm-think__dots", children: [
767
+ /* @__PURE__ */ jsx("span", {}),
768
+ /* @__PURE__ */ jsx("span", {}),
769
+ /* @__PURE__ */ jsx("span", {})
770
+ ] });
771
+ }
772
+ function ThinkPrimitive({
773
+ content,
774
+ status = "thinking",
775
+ label,
776
+ defaultOpen = true,
777
+ className,
778
+ style
779
+ }) {
780
+ const [open, setOpen] = useState(defaultOpen);
781
+ const title = label ?? (status === "thinking" ? "\u601D\u8003\u4E2D" : "\u5DF2\u5B8C\u6210\u601D\u8003");
782
+ return /* @__PURE__ */ jsxs(
783
+ "section",
784
+ {
785
+ className,
786
+ "data-open": open ? "" : void 0,
787
+ "data-status": status,
788
+ style,
789
+ children: [
790
+ /* @__PURE__ */ jsxs(
791
+ "button",
792
+ {
793
+ "aria-expanded": open,
794
+ className: "llm-think__header",
795
+ onClick: () => setOpen((nextOpen) => !nextOpen),
796
+ type: "button",
797
+ children: [
798
+ /* @__PURE__ */ jsxs("span", { className: "llm-think__title", children: [
799
+ /* @__PURE__ */ jsx(SparkIcon, {}),
800
+ /* @__PURE__ */ jsx("span", { children: title }),
801
+ status === "thinking" ? /* @__PURE__ */ jsx(ThinkingDots, {}) : null
802
+ ] }),
803
+ /* @__PURE__ */ jsx(ChevronIcon, {})
804
+ ]
805
+ }
806
+ ),
807
+ /* @__PURE__ */ jsx("div", { className: "llm-think__content", hidden: !open, children: content ? /* @__PURE__ */ jsx("div", { className: "llm-think__text", children: content }) : /* @__PURE__ */ jsx("div", { className: "llm-think__placeholder", children: "\u6B63\u5728\u5206\u6790\u4E0A\u4E0B\u6587\u4E0E\u7528\u6237\u610F\u56FE" }) })
808
+ ]
809
+ }
810
+ );
811
+ }
812
+ function Think({ className, ...props }) {
813
+ return /* @__PURE__ */ jsx(ThinkPrimitive, { className: cn("llm-think", className), ...props });
814
+ }
815
+ var defaultTitleMap = {
816
+ success: "\u64CD\u4F5C\u6210\u529F",
817
+ error: "\u64CD\u4F5C\u5931\u8D25",
818
+ loading: "\u5904\u7406\u4E2D"
819
+ };
820
+ function SuccessIcon() {
821
+ return /* @__PURE__ */ jsx(
822
+ "svg",
823
+ {
824
+ "aria-hidden": "true",
825
+ className: "llm-notification__icon-svg",
826
+ fill: "none",
827
+ height: "18",
828
+ viewBox: "0 0 24 24",
829
+ width: "18",
830
+ xmlns: "http://www.w3.org/2000/svg",
831
+ children: /* @__PURE__ */ jsx(
832
+ "path",
833
+ {
834
+ d: "m6 12 4 4 8-8",
835
+ stroke: "currentColor",
836
+ strokeLinecap: "round",
837
+ strokeLinejoin: "round",
838
+ strokeWidth: "2.4"
839
+ }
840
+ )
841
+ }
842
+ );
843
+ }
844
+ function ErrorIcon() {
845
+ return /* @__PURE__ */ jsxs(
846
+ "svg",
847
+ {
848
+ "aria-hidden": "true",
849
+ className: "llm-notification__icon-svg",
850
+ fill: "none",
851
+ height: "18",
852
+ viewBox: "0 0 24 24",
853
+ width: "18",
854
+ xmlns: "http://www.w3.org/2000/svg",
855
+ children: [
856
+ /* @__PURE__ */ jsx(
857
+ "path",
858
+ {
859
+ d: "m8 8 8 8",
860
+ stroke: "currentColor",
861
+ strokeLinecap: "round",
862
+ strokeWidth: "2.4"
863
+ }
864
+ ),
865
+ /* @__PURE__ */ jsx(
866
+ "path",
867
+ {
868
+ d: "m16 8-8 8",
869
+ stroke: "currentColor",
870
+ strokeLinecap: "round",
871
+ strokeWidth: "2.4"
872
+ }
873
+ )
874
+ ]
875
+ }
876
+ );
877
+ }
878
+ function LoadingIcon() {
879
+ return /* @__PURE__ */ jsx(
880
+ "svg",
881
+ {
882
+ "aria-hidden": "true",
883
+ className: "llm-notification__icon-svg llm-notification__icon-svg--loading",
884
+ fill: "none",
885
+ height: "18",
886
+ viewBox: "0 0 24 24",
887
+ width: "18",
888
+ xmlns: "http://www.w3.org/2000/svg",
889
+ children: /* @__PURE__ */ jsx(
890
+ "path",
891
+ {
892
+ d: "M21 12a9 9 0 1 1-3.2-6.9",
893
+ stroke: "currentColor",
894
+ strokeLinecap: "round",
895
+ strokeWidth: "2.4"
896
+ }
897
+ )
898
+ }
899
+ );
900
+ }
901
+ function CloseIcon() {
902
+ return /* @__PURE__ */ jsxs(
903
+ "svg",
904
+ {
905
+ "aria-hidden": "true",
906
+ className: "llm-notification__close-icon",
907
+ fill: "none",
908
+ height: "16",
909
+ viewBox: "0 0 24 24",
910
+ width: "16",
911
+ xmlns: "http://www.w3.org/2000/svg",
912
+ children: [
913
+ /* @__PURE__ */ jsx(
914
+ "path",
915
+ {
916
+ d: "m7 7 10 10",
917
+ stroke: "currentColor",
918
+ strokeLinecap: "round",
919
+ strokeWidth: "2"
920
+ }
921
+ ),
922
+ /* @__PURE__ */ jsx(
923
+ "path",
924
+ {
925
+ d: "m17 7-10 10",
926
+ stroke: "currentColor",
927
+ strokeLinecap: "round",
928
+ strokeWidth: "2"
929
+ }
930
+ )
931
+ ]
932
+ }
933
+ );
934
+ }
935
+ function DefaultIcon({ type }) {
936
+ if (type === "success") return /* @__PURE__ */ jsx(SuccessIcon, {});
937
+ if (type === "error") return /* @__PURE__ */ jsx(ErrorIcon, {});
938
+ return /* @__PURE__ */ jsx(LoadingIcon, {});
939
+ }
940
+ function NotificationPrimitive({
941
+ type = "success",
942
+ title,
943
+ description,
944
+ duration = 4500,
945
+ showProgress = false,
946
+ closeable = true,
947
+ icon,
948
+ onClose,
949
+ className,
950
+ style
951
+ }) {
952
+ useEffect(() => {
953
+ if (!duration || type === "loading") return;
954
+ const timer = window.setTimeout(() => {
955
+ onClose?.();
956
+ }, duration);
957
+ return () => {
958
+ window.clearTimeout(timer);
959
+ };
960
+ }, [duration, onClose, type]);
961
+ return /* @__PURE__ */ jsxs(
962
+ "section",
963
+ {
964
+ "aria-live": type === "error" ? "assertive" : "polite",
965
+ className,
966
+ "data-type": type,
967
+ role: type === "error" ? "alert" : "status",
968
+ style,
969
+ children: [
970
+ /* @__PURE__ */ jsx("div", { className: "llm-notification__icon", children: icon ?? /* @__PURE__ */ jsx(DefaultIcon, { type }) }),
971
+ /* @__PURE__ */ jsxs("div", { className: "llm-notification__body", children: [
972
+ /* @__PURE__ */ jsx("div", { className: "llm-notification__title", children: title ?? defaultTitleMap[type] }),
973
+ description ? /* @__PURE__ */ jsx("div", { className: "llm-notification__description", children: description }) : null
974
+ ] }),
975
+ closeable ? /* @__PURE__ */ jsx(
976
+ "button",
977
+ {
978
+ "aria-label": "\u5173\u95ED\u901A\u77E5",
979
+ className: "llm-notification__close",
980
+ onClick: onClose,
981
+ type: "button",
982
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
983
+ }
984
+ ) : null,
985
+ showProgress && duration > 0 && type !== "loading" ? /* @__PURE__ */ jsx(
986
+ "div",
987
+ {
988
+ "aria-hidden": "true",
989
+ className: "llm-notification__progress",
990
+ style: { animationDuration: `${duration}ms` }
991
+ }
992
+ ) : null
993
+ ]
994
+ }
995
+ );
996
+ }
997
+ function Notification({ className, ...props }) {
998
+ return /* @__PURE__ */ jsx(NotificationPrimitive, { className: cn("llm-notification", className), ...props });
999
+ }
1000
+ function NotificationStack({
1001
+ items,
1002
+ onClose,
1003
+ className
1004
+ }) {
1005
+ return /* @__PURE__ */ jsx("div", { className: cn("llm-notification-stack", className), children: items.map(({ id, onClose: itemOnClose, ...item }) => /* @__PURE__ */ jsx(
1006
+ Notification,
1007
+ {
1008
+ ...item,
1009
+ onClose: () => {
1010
+ itemOnClose?.();
1011
+ onClose?.(id);
1012
+ }
1013
+ },
1014
+ id
1015
+ )) });
1016
+ }
1017
+ function CopyIcon2() {
1018
+ return /* @__PURE__ */ jsxs(
1019
+ "svg",
1020
+ {
1021
+ "aria-hidden": "true",
1022
+ fill: "none",
1023
+ height: "16",
1024
+ viewBox: "0 0 24 24",
1025
+ width: "16",
1026
+ xmlns: "http://www.w3.org/2000/svg",
1027
+ children: [
1028
+ /* @__PURE__ */ jsx(
1029
+ "path",
1030
+ {
1031
+ d: "M8 8.5V6a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.5",
1032
+ stroke: "currentColor",
1033
+ strokeLinecap: "round",
1034
+ strokeLinejoin: "round",
1035
+ strokeWidth: "1.8"
1036
+ }
1037
+ ),
1038
+ /* @__PURE__ */ jsx(
1039
+ "path",
1040
+ {
1041
+ d: "M4 10a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z",
1042
+ stroke: "currentColor",
1043
+ strokeLinejoin: "round",
1044
+ strokeWidth: "1.8"
1045
+ }
1046
+ )
1047
+ ]
1048
+ }
1049
+ );
1050
+ }
1051
+ function CheckIcon2() {
1052
+ return /* @__PURE__ */ jsx(
1053
+ "svg",
1054
+ {
1055
+ "aria-hidden": "true",
1056
+ fill: "none",
1057
+ height: "16",
1058
+ viewBox: "0 0 24 24",
1059
+ width: "16",
1060
+ xmlns: "http://www.w3.org/2000/svg",
1061
+ children: /* @__PURE__ */ jsx(
1062
+ "path",
1063
+ {
1064
+ d: "m5 12.5 4.2 4.2L19 6.8",
1065
+ stroke: "currentColor",
1066
+ strokeLinecap: "round",
1067
+ strokeLinejoin: "round",
1068
+ strokeWidth: "2"
1069
+ }
1070
+ )
1071
+ }
1072
+ );
1073
+ }
1074
+ function ReloadIcon() {
1075
+ return /* @__PURE__ */ jsx(
1076
+ "svg",
1077
+ {
1078
+ "aria-hidden": "true",
1079
+ fill: "none",
1080
+ height: "16",
1081
+ viewBox: "0 0 24 24",
1082
+ width: "16",
1083
+ xmlns: "http://www.w3.org/2000/svg",
1084
+ children: /* @__PURE__ */ jsx(
1085
+ "path",
1086
+ {
1087
+ d: "M20 12a8 8 0 1 1-2.34-5.66L20 8.68M20 4v4.68h-4.68",
1088
+ stroke: "currentColor",
1089
+ strokeLinecap: "round",
1090
+ strokeLinejoin: "round",
1091
+ strokeWidth: "1.8"
1092
+ }
1093
+ )
1094
+ }
1095
+ );
1096
+ }
1097
+ function EditIcon() {
1098
+ return /* @__PURE__ */ jsxs(
1099
+ "svg",
1100
+ {
1101
+ "aria-hidden": "true",
1102
+ fill: "none",
1103
+ height: "16",
1104
+ viewBox: "0 0 24 24",
1105
+ width: "16",
1106
+ xmlns: "http://www.w3.org/2000/svg",
1107
+ children: [
1108
+ /* @__PURE__ */ jsx(
1109
+ "path",
1110
+ {
1111
+ d: "m4 20 4.8-1.2L19 8.6 15.4 5 5.2 15.2z",
1112
+ stroke: "currentColor",
1113
+ strokeLinecap: "round",
1114
+ strokeLinejoin: "round",
1115
+ strokeWidth: "1.8"
1116
+ }
1117
+ ),
1118
+ /* @__PURE__ */ jsx(
1119
+ "path",
1120
+ {
1121
+ d: "m13.8 6.6 3.6 3.6",
1122
+ stroke: "currentColor",
1123
+ strokeLinecap: "round",
1124
+ strokeWidth: "1.8"
1125
+ }
1126
+ )
1127
+ ]
1128
+ }
1129
+ );
1130
+ }
1131
+ function ThumbsUpIcon() {
1132
+ return /* @__PURE__ */ jsx(
1133
+ "svg",
1134
+ {
1135
+ "aria-hidden": "true",
1136
+ fill: "none",
1137
+ height: "16",
1138
+ viewBox: "0 0 24 24",
1139
+ width: "16",
1140
+ xmlns: "http://www.w3.org/2000/svg",
1141
+ children: /* @__PURE__ */ jsx(
1142
+ "path",
1143
+ {
1144
+ d: "M7 21H4a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h3m0 10V10l4-7 1.4 1.4a3 3 0 0 1 .8 2.7L12.8 10H19a2 2 0 0 1 2 2.3l-1 6A3 3 0 0 1 17 21z",
1145
+ stroke: "currentColor",
1146
+ strokeLinecap: "round",
1147
+ strokeLinejoin: "round",
1148
+ strokeWidth: "1.8"
1149
+ }
1150
+ )
1151
+ }
1152
+ );
1153
+ }
1154
+ function ThumbsDownIcon() {
1155
+ return /* @__PURE__ */ jsx(
1156
+ "svg",
1157
+ {
1158
+ "aria-hidden": "true",
1159
+ fill: "none",
1160
+ height: "16",
1161
+ viewBox: "0 0 24 24",
1162
+ width: "16",
1163
+ xmlns: "http://www.w3.org/2000/svg",
1164
+ children: /* @__PURE__ */ jsx(
1165
+ "path",
1166
+ {
1167
+ d: "M17 3h3a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-3m0-10v11l-4 7-1.4-1.4a3 3 0 0 1-.8-2.7l.4-2.9H5a2 2 0 0 1-2-2.3l1-6A3 3 0 0 1 7 3z",
1168
+ stroke: "currentColor",
1169
+ strokeLinecap: "round",
1170
+ strokeLinejoin: "round",
1171
+ strokeWidth: "1.8"
1172
+ }
1173
+ )
1174
+ }
1175
+ );
1176
+ }
1177
+ function SummaryIcon() {
1178
+ return /* @__PURE__ */ jsxs(
1179
+ "svg",
1180
+ {
1181
+ "aria-hidden": "true",
1182
+ fill: "none",
1183
+ height: "16",
1184
+ viewBox: "0 0 24 24",
1185
+ width: "16",
1186
+ xmlns: "http://www.w3.org/2000/svg",
1187
+ children: [
1188
+ /* @__PURE__ */ jsx(
1189
+ "path",
1190
+ {
1191
+ d: "M5 5.5h14M5 10h10M5 14.5h7",
1192
+ stroke: "currentColor",
1193
+ strokeLinecap: "round",
1194
+ strokeWidth: "1.8"
1195
+ }
1196
+ ),
1197
+ /* @__PURE__ */ jsx(
1198
+ "path",
1199
+ {
1200
+ d: "m15 17 1.6 1.6L20 15",
1201
+ stroke: "currentColor",
1202
+ strokeLinecap: "round",
1203
+ strokeLinejoin: "round",
1204
+ strokeWidth: "1.8"
1205
+ }
1206
+ )
1207
+ ]
1208
+ }
1209
+ );
1210
+ }
1211
+ function PolishIcon() {
1212
+ return /* @__PURE__ */ jsxs(
1213
+ "svg",
1214
+ {
1215
+ "aria-hidden": "true",
1216
+ fill: "none",
1217
+ height: "16",
1218
+ viewBox: "0 0 24 24",
1219
+ width: "16",
1220
+ xmlns: "http://www.w3.org/2000/svg",
1221
+ children: [
1222
+ /* @__PURE__ */ jsx(
1223
+ "path",
1224
+ {
1225
+ d: "m4 20 6.2-1.4L19 9.8 14.2 5 5.4 13.8z",
1226
+ stroke: "currentColor",
1227
+ strokeLinecap: "round",
1228
+ strokeLinejoin: "round",
1229
+ strokeWidth: "1.8"
1230
+ }
1231
+ ),
1232
+ /* @__PURE__ */ jsx(
1233
+ "path",
1234
+ {
1235
+ d: "M15.5 3.5 20.5 8.5M5 4.5h3M6.5 3v3M19 17h2M20 16v2",
1236
+ stroke: "currentColor",
1237
+ strokeLinecap: "round",
1238
+ strokeWidth: "1.8"
1239
+ }
1240
+ )
1241
+ ]
1242
+ }
1243
+ );
1244
+ }
1245
+ function ExplainCodeIcon() {
1246
+ return /* @__PURE__ */ jsx(
1247
+ "svg",
1248
+ {
1249
+ "aria-hidden": "true",
1250
+ fill: "none",
1251
+ height: "16",
1252
+ viewBox: "0 0 24 24",
1253
+ width: "16",
1254
+ xmlns: "http://www.w3.org/2000/svg",
1255
+ children: /* @__PURE__ */ jsx(
1256
+ "path",
1257
+ {
1258
+ d: "m8 9-3 3 3 3M16 9l3 3-3 3M13.5 6.5l-3 11",
1259
+ stroke: "currentColor",
1260
+ strokeLinecap: "round",
1261
+ strokeLinejoin: "round",
1262
+ strokeWidth: "1.8"
1263
+ }
1264
+ )
1265
+ }
1266
+ );
1267
+ }
1268
+ var defaultIcons = {
1269
+ copy: /* @__PURE__ */ jsx(CopyIcon2, {}),
1270
+ regenerate: /* @__PURE__ */ jsx(ReloadIcon, {}),
1271
+ reload: /* @__PURE__ */ jsx(ReloadIcon, {}),
1272
+ edit: /* @__PURE__ */ jsx(EditIcon, {}),
1273
+ correct: /* @__PURE__ */ jsx(EditIcon, {}),
1274
+ like: /* @__PURE__ */ jsx(ThumbsUpIcon, {}),
1275
+ dislike: /* @__PURE__ */ jsx(ThumbsDownIcon, {}),
1276
+ summary: /* @__PURE__ */ jsx(SummaryIcon, {}),
1277
+ polish: /* @__PURE__ */ jsx(PolishIcon, {}),
1278
+ "explain-code": /* @__PURE__ */ jsx(ExplainCodeIcon, {})
1279
+ };
1280
+ function getActionIcon(item, copied) {
1281
+ if (copied) return /* @__PURE__ */ jsx(CheckIcon2, {});
1282
+ return item.icon ?? defaultIcons[item.key];
1283
+ }
1284
+ function ActionsPrimitive({
1285
+ items,
1286
+ onAction,
1287
+ copiedKey = "copy",
1288
+ copiedDuration = 1800,
1289
+ orientation = "horizontal",
1290
+ size = "md",
1291
+ className,
1292
+ style
1293
+ }) {
1294
+ const [copied, setCopied] = useState(false);
1295
+ useEffect(() => {
1296
+ if (!copied) return;
1297
+ const timer = window.setTimeout(() => setCopied(false), copiedDuration);
1298
+ return () => window.clearTimeout(timer);
1299
+ }, [copied, copiedDuration]);
1300
+ const handleAction = (item) => {
1301
+ if (item.disabled) return;
1302
+ if (item.key === copiedKey) {
1303
+ setCopied(true);
1304
+ }
1305
+ onAction?.(item.key, item);
1306
+ };
1307
+ return /* @__PURE__ */ jsx(
1308
+ "div",
1309
+ {
1310
+ className,
1311
+ "data-orientation": orientation,
1312
+ "data-size": size,
1313
+ role: "toolbar",
1314
+ style,
1315
+ children: items.map((item) => {
1316
+ const itemCopied = item.key === copiedKey && copied;
1317
+ const icon = getActionIcon(item, itemCopied);
1318
+ return /* @__PURE__ */ jsxs(
1319
+ "button",
1320
+ {
1321
+ "aria-label": item.label,
1322
+ className: "llm-actions__item",
1323
+ "data-copied": itemCopied ? "" : void 0,
1324
+ "data-variant": item.variant,
1325
+ disabled: item.disabled,
1326
+ onClick: () => handleAction(item),
1327
+ title: item.label,
1328
+ type: "button",
1329
+ children: [
1330
+ icon ? /* @__PURE__ */ jsx("span", { className: "llm-actions__icon", children: icon }) : null,
1331
+ /* @__PURE__ */ jsx("span", { className: "llm-actions__label", children: itemCopied ? "\u5DF2\u590D\u5236" : item.label })
1332
+ ]
1333
+ },
1334
+ item.key
1335
+ );
1336
+ })
1337
+ }
1338
+ );
1339
+ }
1340
+ function Actions({ className, ...props }) {
1341
+ return /* @__PURE__ */ jsx(ActionsPrimitive, { className: cn("llm-actions", className), ...props });
1342
+ }
1343
+
1344
+ // src/components/actions/ActionsPreset.ts
1345
+ var actionPresets = {
1346
+ copy: { key: "copy", label: "\u590D\u5236" },
1347
+ regenerate: { key: "regenerate", label: "\u91CD\u65B0\u751F\u6210" },
1348
+ correct: { key: "correct", label: "\u7EA0\u9519" },
1349
+ summary: { key: "summary", label: "\u603B\u7ED3" },
1350
+ polish: { key: "polish", label: "\u6DA6\u8272" },
1351
+ "explain-code": { key: "explain-code", label: "\u89E3\u91CA\u4EE3\u7801" }
1352
+ };
1353
+ function createPresetActions(keys) {
1354
+ return keys.map((key) => actionPresets[key]);
1355
+ }
1356
+ function PromptsPrimitive({
1357
+ items,
1358
+ onPrompt,
1359
+ title,
1360
+ description,
1361
+ emptyText = "\u6682\u65E0\u63D0\u793A\u8BCD",
1362
+ columns = 2,
1363
+ className,
1364
+ style
1365
+ }) {
1366
+ const hasHeader = Boolean(title || description);
1367
+ const handlePrompt = (item) => {
1368
+ if (item.disabled) return;
1369
+ onPrompt?.(item.key, item);
1370
+ };
1371
+ return /* @__PURE__ */ jsxs("section", { className, "data-columns": columns, style, children: [
1372
+ hasHeader ? /* @__PURE__ */ jsxs("div", { className: "llm-prompts__header", children: [
1373
+ title ? /* @__PURE__ */ jsx("div", { className: "llm-prompts__title", children: title }) : null,
1374
+ description ? /* @__PURE__ */ jsx("div", { className: "llm-prompts__description", children: description }) : null
1375
+ ] }) : null,
1376
+ items.length > 0 ? /* @__PURE__ */ jsx("div", { className: "llm-prompts__list", children: items.map((item) => /* @__PURE__ */ jsxs(
1377
+ "button",
1378
+ {
1379
+ "aria-label": typeof item.title === "string" ? item.title : void 0,
1380
+ className: "llm-prompts__item",
1381
+ disabled: item.disabled,
1382
+ onClick: () => handlePrompt(item),
1383
+ type: "button",
1384
+ children: [
1385
+ item.icon ? /* @__PURE__ */ jsx("span", { className: "llm-prompts__icon", children: item.icon }) : null,
1386
+ /* @__PURE__ */ jsx("span", { className: "llm-prompts__item-title", children: item.title })
1387
+ ]
1388
+ },
1389
+ item.key
1390
+ )) }) : /* @__PURE__ */ jsx("div", { className: "llm-prompts__empty", children: emptyText })
1391
+ ] });
1392
+ }
1393
+ function Prompts({ className, ...props }) {
1394
+ return /* @__PURE__ */ jsx(PromptsPrimitive, { className: cn("llm-prompts", className), ...props });
1395
+ }
1396
+ function formatTimestamp2(timestamp) {
1397
+ if (!timestamp) return void 0;
1398
+ if (typeof timestamp === "string") return timestamp;
1399
+ return timestamp.toLocaleTimeString([], {
1400
+ hour: "2-digit",
1401
+ minute: "2-digit"
1402
+ });
1403
+ }
1404
+ function PinIcon() {
1405
+ return /* @__PURE__ */ jsx(
1406
+ "svg",
1407
+ {
1408
+ "aria-hidden": "true",
1409
+ fill: "none",
1410
+ height: "14",
1411
+ viewBox: "0 0 24 24",
1412
+ width: "14",
1413
+ xmlns: "http://www.w3.org/2000/svg",
1414
+ children: /* @__PURE__ */ jsx(
1415
+ "path",
1416
+ {
1417
+ d: "m14.5 4.5 5 5-3.2 3.2.8 5.4-1.2 1.2-4.4-4.4-4.7 4.7-2.4.8.8-2.4 4.7-4.7-4.4-4.4 1.2-1.2 5.4.8 3.2-3.2Z",
1418
+ stroke: "currentColor",
1419
+ strokeLinejoin: "round",
1420
+ strokeWidth: "1.8"
1421
+ }
1422
+ )
1423
+ }
1424
+ );
1425
+ }
1426
+ function StarIcon() {
1427
+ return /* @__PURE__ */ jsx(
1428
+ "svg",
1429
+ {
1430
+ "aria-hidden": "true",
1431
+ fill: "currentColor",
1432
+ height: "14",
1433
+ viewBox: "0 0 24 24",
1434
+ width: "14",
1435
+ xmlns: "http://www.w3.org/2000/svg",
1436
+ children: /* @__PURE__ */ jsx("path", { d: "m12 3 2.7 5.47 6.03.88-4.36 4.25 1.03 6-5.4-2.84-5.4 2.84 1.03-6-4.36-4.25 6.03-.88L12 3Z" })
1437
+ }
1438
+ );
1439
+ }
1440
+ function MoreIcon() {
1441
+ return /* @__PURE__ */ jsxs(
1442
+ "svg",
1443
+ {
1444
+ "aria-hidden": "true",
1445
+ className: "llm-conversation-item__menu-icon",
1446
+ fill: "none",
1447
+ height: "16",
1448
+ viewBox: "0 0 24 24",
1449
+ width: "16",
1450
+ xmlns: "http://www.w3.org/2000/svg",
1451
+ children: [
1452
+ /* @__PURE__ */ jsx(
1453
+ "path",
1454
+ {
1455
+ d: "M12 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z",
1456
+ fill: "currentColor"
1457
+ }
1458
+ ),
1459
+ /* @__PURE__ */ jsx(
1460
+ "path",
1461
+ {
1462
+ d: "M19 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z",
1463
+ fill: "currentColor"
1464
+ }
1465
+ ),
1466
+ /* @__PURE__ */ jsx(
1467
+ "path",
1468
+ {
1469
+ d: "M5 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z",
1470
+ fill: "currentColor"
1471
+ }
1472
+ )
1473
+ ]
1474
+ }
1475
+ );
1476
+ }
1477
+ function ConversationItemPrimitive({
1478
+ conversation,
1479
+ active = false,
1480
+ onSelect,
1481
+ onDelete,
1482
+ onPin,
1483
+ onFavorite,
1484
+ className,
1485
+ style
1486
+ }) {
1487
+ const rootRef = useRef(null);
1488
+ const [menuOpen, setMenuOpen] = useState(false);
1489
+ const timestamp = formatTimestamp2(conversation.timestamp);
1490
+ useEffect(() => {
1491
+ if (!menuOpen) return;
1492
+ const handlePointerDown = (event) => {
1493
+ if (!rootRef.current?.contains(event.target)) {
1494
+ setMenuOpen(false);
1495
+ }
1496
+ };
1497
+ document.addEventListener("pointerdown", handlePointerDown);
1498
+ return () => {
1499
+ document.removeEventListener("pointerdown", handlePointerDown);
1500
+ };
1501
+ }, [menuOpen]);
1502
+ const handleAction = (action) => {
1503
+ if (action === "pin") {
1504
+ onPin?.(conversation.id);
1505
+ }
1506
+ if (action === "favorite") {
1507
+ onFavorite?.(conversation.id);
1508
+ }
1509
+ if (action === "delete") {
1510
+ onDelete?.(conversation.id);
1511
+ }
1512
+ setMenuOpen(false);
1513
+ };
1514
+ return /* @__PURE__ */ jsxs(
1515
+ "article",
1516
+ {
1517
+ ref: rootRef,
1518
+ className,
1519
+ "data-active": active ? "" : void 0,
1520
+ "data-favorite": conversation.favorite ? "" : void 0,
1521
+ "data-pinned": conversation.pinned ? "" : void 0,
1522
+ style,
1523
+ children: [
1524
+ /* @__PURE__ */ jsx(
1525
+ "button",
1526
+ {
1527
+ "aria-current": active ? "true" : void 0,
1528
+ className: "llm-conversation-item__main",
1529
+ onClick: () => onSelect?.(conversation.id),
1530
+ type: "button",
1531
+ children: /* @__PURE__ */ jsx("span", { className: "llm-conversation-item__content", children: /* @__PURE__ */ jsxs("span", { className: "llm-conversation-item__header", children: [
1532
+ /* @__PURE__ */ jsx("span", { className: "llm-conversation-item__title", children: conversation.title }),
1533
+ timestamp ? /* @__PURE__ */ jsx("span", { className: "llm-conversation-item__time", children: timestamp }) : null
1534
+ ] }) })
1535
+ }
1536
+ ),
1537
+ /* @__PURE__ */ jsxs("div", { className: "llm-conversation-item__actions", children: [
1538
+ conversation.pinned ? /* @__PURE__ */ jsx(
1539
+ "button",
1540
+ {
1541
+ "aria-label": "\u53D6\u6D88\u7F6E\u9876",
1542
+ className: "llm-conversation-item__status-button",
1543
+ onClick: () => handleAction("pin"),
1544
+ type: "button",
1545
+ children: /* @__PURE__ */ jsx(PinIcon, {})
1546
+ }
1547
+ ) : null,
1548
+ conversation.favorite ? /* @__PURE__ */ jsx(
1549
+ "button",
1550
+ {
1551
+ "aria-label": "\u53D6\u6D88\u6536\u85CF",
1552
+ className: "llm-conversation-item__status-button",
1553
+ onClick: () => handleAction("favorite"),
1554
+ type: "button",
1555
+ children: /* @__PURE__ */ jsx(StarIcon, {})
1556
+ }
1557
+ ) : null,
1558
+ /* @__PURE__ */ jsx(
1559
+ "button",
1560
+ {
1561
+ "aria-expanded": menuOpen,
1562
+ "aria-label": "\u6253\u5F00\u4F1A\u8BDD\u64CD\u4F5C",
1563
+ className: "llm-conversation-item__menu-trigger",
1564
+ onClick: () => setMenuOpen((open) => !open),
1565
+ type: "button",
1566
+ children: /* @__PURE__ */ jsx(MoreIcon, {})
1567
+ }
1568
+ ),
1569
+ menuOpen ? /* @__PURE__ */ jsxs("div", { className: "llm-conversation-item__menu", role: "menu", children: [
1570
+ /* @__PURE__ */ jsx(
1571
+ "button",
1572
+ {
1573
+ className: "llm-conversation-item__menu-item",
1574
+ onClick: () => handleAction("pin"),
1575
+ role: "menuitem",
1576
+ type: "button",
1577
+ children: conversation.pinned ? "\u53D6\u6D88\u7F6E\u9876" : "\u7F6E\u9876"
1578
+ }
1579
+ ),
1580
+ /* @__PURE__ */ jsx(
1581
+ "button",
1582
+ {
1583
+ className: "llm-conversation-item__menu-item",
1584
+ onClick: () => handleAction("favorite"),
1585
+ role: "menuitem",
1586
+ type: "button",
1587
+ children: conversation.favorite ? "\u53D6\u6D88\u6536\u85CF" : "\u6536\u85CF"
1588
+ }
1589
+ ),
1590
+ /* @__PURE__ */ jsx(
1591
+ "button",
1592
+ {
1593
+ className: "llm-conversation-item__menu-item",
1594
+ "data-danger": "",
1595
+ onClick: () => handleAction("delete"),
1596
+ role: "menuitem",
1597
+ type: "button",
1598
+ children: "\u5220\u9664"
1599
+ }
1600
+ )
1601
+ ] }) : null
1602
+ ] })
1603
+ ]
1604
+ }
1605
+ );
1606
+ }
1607
+ function ConversationItem({
1608
+ className,
1609
+ ...props
1610
+ }) {
1611
+ return /* @__PURE__ */ jsx(
1612
+ ConversationItemPrimitive,
1613
+ {
1614
+ className: cn("llm-conversation-item", className),
1615
+ ...props
1616
+ }
1617
+ );
1618
+ }
1619
+ function clamp(value, min, max) {
1620
+ return Math.min(Math.max(value, min), max);
1621
+ }
1622
+ function useVirtualList({
1623
+ items,
1624
+ itemHeight,
1625
+ overscan = 5,
1626
+ enabled = true,
1627
+ getItemKey
1628
+ }) {
1629
+ const containerRef = useRef(null);
1630
+ const [scrollTop, setScrollTop] = useState(0);
1631
+ const [viewportHeight, setViewportHeight] = useState(0);
1632
+ const safeItemHeight = Math.max(1, itemHeight);
1633
+ const safeOverscan = Math.max(0, overscan);
1634
+ const totalSize = items.length * safeItemHeight;
1635
+ useEffect(() => {
1636
+ if (!enabled) return;
1637
+ const container = containerRef.current;
1638
+ if (!container) return;
1639
+ const updateViewportHeight = () => {
1640
+ setViewportHeight(container.clientHeight);
1641
+ };
1642
+ updateViewportHeight();
1643
+ if (typeof ResizeObserver === "undefined") {
1644
+ return;
1645
+ }
1646
+ const observer = new ResizeObserver(updateViewportHeight);
1647
+ observer.observe(container);
1648
+ return () => observer.disconnect();
1649
+ }, [enabled]);
1650
+ useEffect(() => {
1651
+ if (!enabled) return;
1652
+ const container = containerRef.current;
1653
+ if (!container) return;
1654
+ const handleScroll = () => {
1655
+ setScrollTop(container.scrollTop);
1656
+ };
1657
+ handleScroll();
1658
+ container.addEventListener("scroll", handleScroll, { passive: true });
1659
+ return () => container.removeEventListener("scroll", handleScroll);
1660
+ }, [enabled]);
1661
+ const virtualItems = useMemo(() => {
1662
+ const listItems = [];
1663
+ if (!enabled) {
1664
+ for (let index = 0; index < items.length; index += 1) {
1665
+ const item = items[index];
1666
+ if (item === void 0) continue;
1667
+ listItems.push({
1668
+ item,
1669
+ index,
1670
+ key: getItemKey?.(item, index) ?? index,
1671
+ start: index * safeItemHeight,
1672
+ size: safeItemHeight
1673
+ });
1674
+ }
1675
+ return listItems;
1676
+ }
1677
+ const startIndex = clamp(
1678
+ Math.floor(scrollTop / safeItemHeight) - safeOverscan,
1679
+ 0,
1680
+ items.length
1681
+ );
1682
+ const endIndex = clamp(
1683
+ Math.ceil((scrollTop + viewportHeight) / safeItemHeight) + safeOverscan,
1684
+ startIndex,
1685
+ items.length
1686
+ );
1687
+ for (let index = startIndex; index < endIndex; index += 1) {
1688
+ const item = items[index];
1689
+ if (item === void 0) continue;
1690
+ listItems.push({
1691
+ item,
1692
+ index,
1693
+ key: getItemKey?.(item, index) ?? index,
1694
+ start: index * safeItemHeight,
1695
+ size: safeItemHeight
1696
+ });
1697
+ }
1698
+ return listItems;
1699
+ }, [
1700
+ enabled,
1701
+ getItemKey,
1702
+ items,
1703
+ safeItemHeight,
1704
+ safeOverscan,
1705
+ scrollTop,
1706
+ viewportHeight
1707
+ ]);
1708
+ const scrollToIndex = useCallback(
1709
+ (index, align = "start") => {
1710
+ const container = containerRef.current;
1711
+ if (!container) return;
1712
+ const clampedIndex = clamp(index, 0, Math.max(0, items.length - 1));
1713
+ const itemStart = clampedIndex * safeItemHeight;
1714
+ const itemEnd = itemStart + safeItemHeight;
1715
+ const maxScrollTop = Math.max(0, totalSize - container.clientHeight);
1716
+ let nextScrollTop = itemStart;
1717
+ if (align === "center") {
1718
+ nextScrollTop = itemStart - (container.clientHeight - safeItemHeight) / 2;
1719
+ }
1720
+ if (align === "end") {
1721
+ nextScrollTop = itemEnd - container.clientHeight;
1722
+ }
1723
+ container.scrollTo({
1724
+ top: clamp(nextScrollTop, 0, maxScrollTop),
1725
+ behavior: "smooth"
1726
+ });
1727
+ },
1728
+ [items.length, safeItemHeight, totalSize]
1729
+ );
1730
+ return {
1731
+ containerRef,
1732
+ virtualItems,
1733
+ totalSize,
1734
+ scrollToIndex
1735
+ };
1736
+ }
1737
+ function normalizeSearchText(value) {
1738
+ return value.trim().toLowerCase();
1739
+ }
1740
+ function SearchIcon() {
1741
+ return /* @__PURE__ */ jsx(
1742
+ "svg",
1743
+ {
1744
+ "aria-hidden": "true",
1745
+ fill: "none",
1746
+ height: "16",
1747
+ viewBox: "0 0 24 24",
1748
+ width: "16",
1749
+ xmlns: "http://www.w3.org/2000/svg",
1750
+ children: /* @__PURE__ */ jsx(
1751
+ "path",
1752
+ {
1753
+ d: "m20 20-4.3-4.3m1.8-5.2a7 7 0 1 1-14 0 7 7 0 0 1 14 0Z",
1754
+ stroke: "currentColor",
1755
+ strokeLinecap: "round",
1756
+ strokeLinejoin: "round",
1757
+ strokeWidth: "1.8"
1758
+ }
1759
+ )
1760
+ }
1761
+ );
1762
+ }
1763
+ function ConversationListPrimitive({
1764
+ conversations,
1765
+ activeId,
1766
+ onSelect,
1767
+ onDelete,
1768
+ onPin,
1769
+ onFavorite,
1770
+ onCollapsedChange,
1771
+ onNewConversation,
1772
+ collapsed = false,
1773
+ searchable = false,
1774
+ searchPlaceholder = "\u641C\u7D22\u4F1A\u8BDD...",
1775
+ title,
1776
+ emptyText,
1777
+ virtualized = false,
1778
+ itemHeight = 56,
1779
+ overscan = 6,
1780
+ className,
1781
+ style
1782
+ }) {
1783
+ const [searchOpen, setSearchOpen] = useState(false);
1784
+ const [searchValue, setSearchValue] = useState("");
1785
+ const keyword = normalizeSearchText(searchValue);
1786
+ const visibleConversations = useMemo(() => {
1787
+ const filteredConversations = keyword ? conversations.filter((conversation) => {
1788
+ const titleMatched = conversation.title.toLowerCase().includes(keyword);
1789
+ const messageMatched = conversation.lastMessage?.toLowerCase().includes(keyword) ?? false;
1790
+ return titleMatched || messageMatched;
1791
+ }) : conversations;
1792
+ return filteredConversations.map((conversation, index) => ({ conversation, index })).sort((a, b) => {
1793
+ if (a.conversation.pinned === b.conversation.pinned) {
1794
+ return a.index - b.index;
1795
+ }
1796
+ return a.conversation.pinned ? -1 : 1;
1797
+ }).map(({ conversation }) => conversation);
1798
+ }, [conversations, keyword]);
1799
+ const resolvedEmptyText = emptyText ?? (keyword ? "\u672A\u627E\u5230\u76F8\u5173\u4F1A\u8BDD" : "\u6682\u65E0\u4F1A\u8BDD");
1800
+ const { containerRef, totalSize, virtualItems } = useVirtualList({
1801
+ items: visibleConversations,
1802
+ itemHeight,
1803
+ overscan,
1804
+ enabled: virtualized,
1805
+ getItemKey: (conversation) => conversation.id
1806
+ });
1807
+ return /* @__PURE__ */ jsxs(
1808
+ "aside",
1809
+ {
1810
+ className,
1811
+ "data-collapsed": collapsed ? "" : void 0,
1812
+ "data-virtualized": virtualized ? "" : void 0,
1813
+ style,
1814
+ children: [
1815
+ /* @__PURE__ */ jsxs("div", { className: "llm-conversation-list__header", children: [
1816
+ /* @__PURE__ */ jsxs("div", { className: "llm-conversation-list__toolbar", children: [
1817
+ /* @__PURE__ */ jsx(
1818
+ "button",
1819
+ {
1820
+ "aria-label": collapsed ? "\u6253\u5F00\u8FB9\u680F" : "\u5173\u95ED\u8FB9\u680F",
1821
+ className: "llm-conversation-list__icon-button",
1822
+ onClick: () => onCollapsedChange?.(!collapsed),
1823
+ type: "button",
1824
+ children: collapsed ? "\u203A" : "\u2039"
1825
+ }
1826
+ ),
1827
+ /* @__PURE__ */ jsxs("div", { className: "llm-conversation-list__toolbar-actions", children: [
1828
+ searchable && !collapsed ? /* @__PURE__ */ jsx(
1829
+ "button",
1830
+ {
1831
+ "aria-expanded": searchOpen,
1832
+ "aria-label": "\u641C\u7D22\u4F1A\u8BDD",
1833
+ className: "llm-conversation-list__icon-button",
1834
+ onClick: () => setSearchOpen((open) => !open),
1835
+ type: "button",
1836
+ children: /* @__PURE__ */ jsx(SearchIcon, {})
1837
+ }
1838
+ ) : null,
1839
+ /* @__PURE__ */ jsx(
1840
+ "button",
1841
+ {
1842
+ "aria-label": "\u6253\u5F00\u65B0\u804A\u5929",
1843
+ className: "llm-conversation-list__icon-button",
1844
+ onClick: onNewConversation,
1845
+ type: "button",
1846
+ children: "+"
1847
+ }
1848
+ )
1849
+ ] })
1850
+ ] }),
1851
+ title ? /* @__PURE__ */ jsx("div", { className: "llm-conversation-list__title", children: title }) : null,
1852
+ searchable && searchOpen && !collapsed ? /* @__PURE__ */ jsxs("label", { className: "llm-conversation-list__search", children: [
1853
+ /* @__PURE__ */ jsx("span", { className: "llm-conversation-list__search-label", children: "\u641C\u7D22\u4F1A\u8BDD" }),
1854
+ /* @__PURE__ */ jsx(
1855
+ "input",
1856
+ {
1857
+ "aria-label": "\u641C\u7D22\u4F1A\u8BDD",
1858
+ className: "llm-conversation-list__search-input",
1859
+ onChange: (event) => setSearchValue(event.target.value),
1860
+ placeholder: searchPlaceholder,
1861
+ type: "search",
1862
+ value: searchValue
1863
+ }
1864
+ )
1865
+ ] }) : null
1866
+ ] }),
1867
+ !collapsed ? /* @__PURE__ */ jsx("div", { className: "llm-conversation-list__body", ref: containerRef, children: visibleConversations.length > 0 ? /* @__PURE__ */ jsx(
1868
+ "div",
1869
+ {
1870
+ className: "llm-conversation-list__items",
1871
+ "data-virtualized": virtualized ? "" : void 0,
1872
+ role: "list",
1873
+ style: virtualized ? { height: totalSize } : void 0,
1874
+ children: (virtualized ? virtualItems : visibleConversations.map((conversation, index) => ({
1875
+ item: conversation,
1876
+ index,
1877
+ key: conversation.id,
1878
+ start: index * itemHeight,
1879
+ size: itemHeight
1880
+ }))).map((virtualItem) => /* @__PURE__ */ jsx(
1881
+ "div",
1882
+ {
1883
+ className: "llm-conversation-list__item",
1884
+ "data-virtualized": virtualized ? "" : void 0,
1885
+ role: "listitem",
1886
+ style: virtualized ? {
1887
+ height: virtualItem.size,
1888
+ transform: `translateY(${virtualItem.start}px)`
1889
+ } : void 0,
1890
+ children: /* @__PURE__ */ jsx(
1891
+ ConversationItem,
1892
+ {
1893
+ active: virtualItem.item.id === activeId,
1894
+ conversation: virtualItem.item,
1895
+ ...onSelect && { onSelect },
1896
+ ...onDelete && { onDelete },
1897
+ ...onFavorite && { onFavorite },
1898
+ ...onPin && { onPin }
1899
+ }
1900
+ )
1901
+ },
1902
+ virtualItem.key
1903
+ ))
1904
+ }
1905
+ ) : /* @__PURE__ */ jsx("div", { className: "llm-conversation-list__empty", children: resolvedEmptyText }) }) : null
1906
+ ]
1907
+ }
1908
+ );
1909
+ }
1910
+ function ConversationList({
1911
+ className,
1912
+ ...props
1913
+ }) {
1914
+ return /* @__PURE__ */ jsx(
1915
+ ConversationListPrimitive,
1916
+ {
1917
+ className: cn("llm-conversation-list", className),
1918
+ ...props
1919
+ }
1920
+ );
1921
+ }
1922
+ function defaultRenderMessage(message) {
1923
+ return /* @__PURE__ */ jsx(
1924
+ Bubble,
1925
+ {
1926
+ role: message.role,
1927
+ ...message.actions && { actions: message.actions },
1928
+ ...message.avatar && { avatar: message.avatar },
1929
+ ...message.content && { content: message.content },
1930
+ ...message.loading !== void 0 && { loading: message.loading },
1931
+ ...message.status && { status: message.status },
1932
+ ...message.timestamp && { timestamp: message.timestamp }
1933
+ }
1934
+ );
1935
+ }
1936
+ function MessageListPrimitive({
1937
+ messages,
1938
+ virtualized = false,
1939
+ itemHeight = 112,
1940
+ overscan = 5,
1941
+ emptyText = "\u6682\u65E0\u6D88\u606F",
1942
+ renderMessage,
1943
+ role = "log",
1944
+ ariaLabel = "\u6D88\u606F\u5217\u8868",
1945
+ className,
1946
+ style
1947
+ }) {
1948
+ const { containerRef, totalSize, virtualItems } = useVirtualList({
1949
+ items: messages,
1950
+ itemHeight,
1951
+ overscan,
1952
+ enabled: virtualized,
1953
+ getItemKey: (message) => message.id
1954
+ });
1955
+ const isLog = role === "log";
1956
+ const listItems = virtualized ? virtualItems : messages.map((message, index) => ({
1957
+ item: message,
1958
+ index,
1959
+ key: message.id,
1960
+ start: index * itemHeight,
1961
+ size: itemHeight
1962
+ }));
1963
+ return /* @__PURE__ */ jsx(
1964
+ "section",
1965
+ {
1966
+ "aria-label": ariaLabel,
1967
+ "aria-live": isLog ? "polite" : void 0,
1968
+ className,
1969
+ "data-virtualized": virtualized ? "" : void 0,
1970
+ role,
1971
+ style,
1972
+ children: /* @__PURE__ */ jsx("div", { className: "llm-message-list__body", ref: containerRef, children: messages.length > 0 ? /* @__PURE__ */ jsx(
1973
+ "div",
1974
+ {
1975
+ className: "llm-message-list__items",
1976
+ "data-virtualized": virtualized ? "" : void 0,
1977
+ role: isLog ? void 0 : "list",
1978
+ style: virtualized ? { height: totalSize } : void 0,
1979
+ children: listItems.map((virtualItem) => /* @__PURE__ */ jsx(
1980
+ "div",
1981
+ {
1982
+ className: "llm-message-list__item",
1983
+ "data-virtualized": virtualized ? "" : void 0,
1984
+ role: isLog ? "article" : "listitem",
1985
+ style: virtualized ? {
1986
+ height: virtualItem.size,
1987
+ transform: `translateY(${virtualItem.start}px)`
1988
+ } : void 0,
1989
+ children: renderMessage ? renderMessage(virtualItem.item, virtualItem.index) : defaultRenderMessage(virtualItem.item)
1990
+ },
1991
+ virtualItem.key
1992
+ ))
1993
+ }
1994
+ ) : /* @__PURE__ */ jsx("div", { className: "llm-message-list__empty", children: emptyText }) })
1995
+ }
1996
+ );
1997
+ }
1998
+ function MessageList({ className, ...props }) {
1999
+ return /* @__PURE__ */ jsx(
2000
+ MessageListPrimitive,
2001
+ {
2002
+ className: cn("llm-message-list", className),
2003
+ ...props
2004
+ }
2005
+ );
2006
+ }
2007
+ function ChevronIcon2() {
2008
+ return /* @__PURE__ */ jsx(
2009
+ "svg",
2010
+ {
2011
+ "aria-hidden": "true",
2012
+ className: "llm-thought__chevron",
2013
+ fill: "none",
2014
+ height: "16",
2015
+ viewBox: "0 0 24 24",
2016
+ width: "16",
2017
+ xmlns: "http://www.w3.org/2000/svg",
2018
+ children: /* @__PURE__ */ jsx(
2019
+ "path",
2020
+ {
2021
+ d: "m9 6 6 6-6 6",
2022
+ stroke: "currentColor",
2023
+ strokeLinecap: "round",
2024
+ strokeLinejoin: "round",
2025
+ strokeWidth: "2"
2026
+ }
2027
+ )
2028
+ }
2029
+ );
2030
+ }
2031
+ function StatusIcon({ status }) {
2032
+ if (status === "loading") {
2033
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "llm-thought__spinner", children: /* @__PURE__ */ jsx("span", {}) });
2034
+ }
2035
+ if (status === "success") {
2036
+ return /* @__PURE__ */ jsx(
2037
+ "svg",
2038
+ {
2039
+ "aria-hidden": "true",
2040
+ fill: "none",
2041
+ height: "14",
2042
+ viewBox: "0 0 24 24",
2043
+ width: "14",
2044
+ children: /* @__PURE__ */ jsx(
2045
+ "path",
2046
+ {
2047
+ d: "m5 12.5 4.2 4.2L19 6.8",
2048
+ stroke: "currentColor",
2049
+ strokeLinecap: "round",
2050
+ strokeLinejoin: "round",
2051
+ strokeWidth: "2.4"
2052
+ }
2053
+ )
2054
+ }
2055
+ );
2056
+ }
2057
+ if (status === "error") {
2058
+ return /* @__PURE__ */ jsx(
2059
+ "svg",
2060
+ {
2061
+ "aria-hidden": "true",
2062
+ fill: "none",
2063
+ height: "14",
2064
+ viewBox: "0 0 24 24",
2065
+ width: "14",
2066
+ children: /* @__PURE__ */ jsx(
2067
+ "path",
2068
+ {
2069
+ d: "m7 7 10 10M17 7 7 17",
2070
+ stroke: "currentColor",
2071
+ strokeLinecap: "round",
2072
+ strokeWidth: "2.4"
2073
+ }
2074
+ )
2075
+ }
2076
+ );
2077
+ }
2078
+ if (status === "abort") {
2079
+ return /* @__PURE__ */ jsx(
2080
+ "svg",
2081
+ {
2082
+ "aria-hidden": "true",
2083
+ fill: "none",
2084
+ height: "14",
2085
+ viewBox: "0 0 24 24",
2086
+ width: "14",
2087
+ children: /* @__PURE__ */ jsx(
2088
+ "path",
2089
+ {
2090
+ d: "M7 12h10",
2091
+ stroke: "currentColor",
2092
+ strokeLinecap: "round",
2093
+ strokeWidth: "2.4"
2094
+ }
2095
+ )
2096
+ }
2097
+ );
2098
+ }
2099
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "llm-thought__pending-dot" });
2100
+ }
2101
+ function hasExpandableContent(item) {
2102
+ return Boolean(item.status === "loading" && item.content);
2103
+ }
2104
+ function ThoughtNode({
2105
+ item,
2106
+ depth,
2107
+ line,
2108
+ isExpanded,
2109
+ onToggle
2110
+ }) {
2111
+ const status = item.status ?? "pending";
2112
+ const expandable = item.collapsible ?? hasExpandableContent(item);
2113
+ const expanded = expandable && isExpanded(item.key);
2114
+ const nodeId = `llm-thought-node-${item.key}`;
2115
+ const contentId = `llm-thought-content-${item.key}`;
2116
+ return /* @__PURE__ */ jsxs("li", { className: "llm-thought__item", "data-depth": depth, "data-status": status, children: [
2117
+ /* @__PURE__ */ jsx("div", { className: "llm-thought__rail", "data-line": line ? "" : void 0, children: item.icon === false ? null : /* @__PURE__ */ jsx("span", { className: "llm-thought__icon", children: item.icon ?? /* @__PURE__ */ jsx(StatusIcon, { status }) }) }),
2118
+ /* @__PURE__ */ jsxs("div", { className: "llm-thought__node", children: [
2119
+ /* @__PURE__ */ jsxs("div", { className: "llm-thought__header", children: [
2120
+ /* @__PURE__ */ jsx("div", { className: "llm-thought__heading", id: nodeId, children: /* @__PURE__ */ jsx("span", { className: "llm-thought__item-title", children: item.title }) }),
2121
+ expandable ? /* @__PURE__ */ jsx(
2122
+ "button",
2123
+ {
2124
+ "aria-controls": contentId,
2125
+ "aria-expanded": expanded,
2126
+ "aria-labelledby": nodeId,
2127
+ className: "llm-thought__toggle",
2128
+ onClick: () => onToggle(item),
2129
+ type: "button",
2130
+ children: /* @__PURE__ */ jsx(ChevronIcon2, {})
2131
+ }
2132
+ ) : null
2133
+ ] }),
2134
+ hasExpandableContent(item) ? /* @__PURE__ */ jsx(
2135
+ "div",
2136
+ {
2137
+ className: "llm-thought__content",
2138
+ hidden: !expanded,
2139
+ id: contentId,
2140
+ children: status === "loading" && item.content ? /* @__PURE__ */ jsx("div", { className: "llm-thought__body", children: item.content }) : null
2141
+ }
2142
+ ) : null
2143
+ ] })
2144
+ ] });
2145
+ }
2146
+ function ThoughtList({
2147
+ items,
2148
+ depth,
2149
+ line,
2150
+ isExpanded,
2151
+ onToggle
2152
+ }) {
2153
+ return /* @__PURE__ */ jsx("ol", { className: "llm-thought__list", children: items.map((item) => /* @__PURE__ */ jsx(
2154
+ ThoughtNode,
2155
+ {
2156
+ depth,
2157
+ isExpanded,
2158
+ item,
2159
+ line,
2160
+ onToggle
2161
+ },
2162
+ item.key
2163
+ )) });
2164
+ }
2165
+ function ThoughtPrimitive({
2166
+ items,
2167
+ title,
2168
+ description,
2169
+ defaultExpandedKeys,
2170
+ expandedKeys,
2171
+ onExpand,
2172
+ line = true,
2173
+ compact = false,
2174
+ emptyText = "\u6682\u65E0\u601D\u8003\u6B65\u9AA4",
2175
+ className,
2176
+ style
2177
+ }) {
2178
+ const [innerExpandedKeys, setInnerExpandedKeys] = useState(
2179
+ () => defaultExpandedKeys ?? []
2180
+ );
2181
+ const mergedExpandedKeys = expandedKeys ?? innerExpandedKeys;
2182
+ const hasHeader = Boolean(title || description);
2183
+ const isExpanded = (key) => mergedExpandedKeys.includes(key);
2184
+ const handleToggle = (item) => {
2185
+ const nextExpandedKeys = isExpanded(item.key) ? mergedExpandedKeys.filter((key) => key !== item.key) : [...mergedExpandedKeys, item.key];
2186
+ if (!expandedKeys) setInnerExpandedKeys(nextExpandedKeys);
2187
+ onExpand?.(nextExpandedKeys, item);
2188
+ };
2189
+ return /* @__PURE__ */ jsxs(
2190
+ "section",
2191
+ {
2192
+ className,
2193
+ "data-compact": compact ? "" : void 0,
2194
+ style,
2195
+ children: [
2196
+ hasHeader ? /* @__PURE__ */ jsxs("div", { className: "llm-thought__section-header", children: [
2197
+ title ? /* @__PURE__ */ jsx("div", { className: "llm-thought__title", children: title }) : null,
2198
+ description ? /* @__PURE__ */ jsx("div", { className: "llm-thought__summary", children: description }) : null
2199
+ ] }) : null,
2200
+ items.length > 0 ? /* @__PURE__ */ jsx(
2201
+ ThoughtList,
2202
+ {
2203
+ depth: 0,
2204
+ isExpanded,
2205
+ items,
2206
+ line,
2207
+ onToggle: handleToggle
2208
+ }
2209
+ ) : /* @__PURE__ */ jsx("div", { className: "llm-thought__empty", children: emptyText })
2210
+ ]
2211
+ }
2212
+ );
2213
+ }
2214
+ function Thought({ className, ...props }) {
2215
+ return /* @__PURE__ */ jsx(ThoughtPrimitive, { className: cn("llm-thought", className), ...props });
2216
+ }
2217
+ function ChevronIcon3() {
2218
+ return /* @__PURE__ */ jsx(
2219
+ "svg",
2220
+ {
2221
+ "aria-hidden": "true",
2222
+ className: "llm-citation__chevron",
2223
+ fill: "none",
2224
+ height: "16",
2225
+ viewBox: "0 0 24 24",
2226
+ width: "16",
2227
+ xmlns: "http://www.w3.org/2000/svg",
2228
+ children: /* @__PURE__ */ jsx(
2229
+ "path",
2230
+ {
2231
+ d: "m6 9 6 6 6-6",
2232
+ stroke: "currentColor",
2233
+ strokeLinecap: "round",
2234
+ strokeLinejoin: "round",
2235
+ strokeWidth: "2"
2236
+ }
2237
+ )
2238
+ }
2239
+ );
2240
+ }
2241
+ function getHost(url) {
2242
+ if (!url) return void 0;
2243
+ try {
2244
+ return new URL(url).host;
2245
+ } catch {
2246
+ return url;
2247
+ }
2248
+ }
2249
+ function CitationPreview({ item }) {
2250
+ return /* @__PURE__ */ jsxs("span", { className: "llm-citation__preview", role: "tooltip", children: [
2251
+ /* @__PURE__ */ jsx("span", { className: "llm-citation__preview-title", children: item.title }),
2252
+ item.description ? /* @__PURE__ */ jsx("span", { className: "llm-citation__preview-description", children: item.description }) : null,
2253
+ item.url ? /* @__PURE__ */ jsx("span", { className: "llm-citation__preview-url", children: getHost(item.url) }) : null
2254
+ ] });
2255
+ }
2256
+ function CitationInlinePrimitive({
2257
+ item,
2258
+ index = 1,
2259
+ active = false,
2260
+ onCitation,
2261
+ className,
2262
+ style
2263
+ }) {
2264
+ const label = `\u5F15\u7528\u6765\u6E90 ${index}`;
2265
+ const handleClick = () => {
2266
+ onCitation?.(item.key, item);
2267
+ };
2268
+ return /* @__PURE__ */ jsxs(
2269
+ "span",
2270
+ {
2271
+ className,
2272
+ "data-active": active ? "" : void 0,
2273
+ style,
2274
+ children: [
2275
+ /* @__PURE__ */ jsxs(
2276
+ "button",
2277
+ {
2278
+ "aria-label": label,
2279
+ className: "llm-citation__inline-trigger",
2280
+ onClick: handleClick,
2281
+ type: "button",
2282
+ children: [
2283
+ "[",
2284
+ index,
2285
+ "]"
2286
+ ]
2287
+ }
2288
+ ),
2289
+ /* @__PURE__ */ jsx(CitationPreview, { item })
2290
+ ]
2291
+ }
2292
+ );
2293
+ }
2294
+ function CitationPrimitive({
2295
+ items,
2296
+ title,
2297
+ defaultExpanded = true,
2298
+ expanded,
2299
+ onExpand,
2300
+ onCitation,
2301
+ emptyText = "\u6682\u65E0\u5F15\u7528\u6765\u6E90",
2302
+ className,
2303
+ style
2304
+ }) {
2305
+ const [innerExpanded, setInnerExpanded] = useState(defaultExpanded);
2306
+ const mergedExpanded = expanded ?? innerExpanded;
2307
+ const heading = title ?? `Used ${items.length} sources`;
2308
+ const handleExpand = () => {
2309
+ const nextExpanded = !mergedExpanded;
2310
+ if (expanded === void 0) setInnerExpanded(nextExpanded);
2311
+ onExpand?.(nextExpanded);
2312
+ };
2313
+ const handleCitation = (item) => {
2314
+ onCitation?.(item.key, item);
2315
+ };
2316
+ return /* @__PURE__ */ jsxs(
2317
+ "section",
2318
+ {
2319
+ className,
2320
+ "data-expanded": mergedExpanded ? "" : void 0,
2321
+ style,
2322
+ children: [
2323
+ /* @__PURE__ */ jsxs(
2324
+ "button",
2325
+ {
2326
+ "aria-expanded": mergedExpanded,
2327
+ className: "llm-citation__header",
2328
+ onClick: handleExpand,
2329
+ type: "button",
2330
+ children: [
2331
+ /* @__PURE__ */ jsx("span", { className: "llm-citation__title", children: heading }),
2332
+ /* @__PURE__ */ jsx(ChevronIcon3, {})
2333
+ ]
2334
+ }
2335
+ ),
2336
+ /* @__PURE__ */ jsx("div", { className: "llm-citation__content", hidden: !mergedExpanded, children: items.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "llm-citation__list", children: items.map((item) => /* @__PURE__ */ jsx("li", { className: "llm-citation__item", children: /* @__PURE__ */ jsxs(
2337
+ "button",
2338
+ {
2339
+ className: "llm-citation__item-button",
2340
+ onClick: () => handleCitation(item),
2341
+ type: "button",
2342
+ children: [
2343
+ item.icon ? /* @__PURE__ */ jsx("span", { className: "llm-citation__item-icon", children: item.icon }) : null,
2344
+ /* @__PURE__ */ jsx("span", { className: "llm-citation__item-title", children: item.title })
2345
+ ]
2346
+ }
2347
+ ) }, item.key)) }) : /* @__PURE__ */ jsx("div", { className: "llm-citation__empty", children: emptyText }) })
2348
+ ]
2349
+ }
2350
+ );
2351
+ }
2352
+ function Citation({ className, ...props }) {
2353
+ return /* @__PURE__ */ jsx(CitationPrimitive, { className: cn("llm-citation", className), ...props });
2354
+ }
2355
+ function CitationInline({ className, ...props }) {
2356
+ return /* @__PURE__ */ jsx(
2357
+ CitationInlinePrimitive,
2358
+ {
2359
+ className: cn("llm-citation-inline", className),
2360
+ ...props
2361
+ }
2362
+ );
2363
+ }
2364
+ Citation.Inline = CitationInline;
2365
+
2366
+ // src/locale/zh-CN.ts
2367
+ var zhCN = {
2368
+ think: {
2369
+ loading: "\u601D\u8003\u4E2D...",
2370
+ done: "\u5DF2\u5B8C\u6210"
2371
+ },
2372
+ sender: {
2373
+ placeholder: "\u8F93\u5165\u6D88\u606F...",
2374
+ send: "\u53D1\u9001"
2375
+ }
2376
+ };
2377
+ var zh_CN_default = zhCN;
2378
+
2379
+ // src/locale/en-US.ts
2380
+ var enUS = {
2381
+ think: {
2382
+ loading: "Thinking...",
2383
+ done: "Done"
2384
+ },
2385
+ sender: {
2386
+ placeholder: "Type a message...",
2387
+ send: "Send"
2388
+ }
2389
+ };
2390
+ var en_US_default = enUS;
2391
+ var configContext = createContext(
2392
+ void 0
2393
+ );
2394
+ function ConfigProvider({
2395
+ theme,
2396
+ locale,
2397
+ ai,
2398
+ children,
2399
+ components
2400
+ }) {
2401
+ const [themeState, setThemeState] = useState({
2402
+ mode: theme?.mode ?? "system",
2403
+ primaryColor: theme?.primaryColor ?? "oklch(0.205 0 0)"
2404
+ });
2405
+ const setTheme = (newTheme) => {
2406
+ setThemeState((prev) => ({ ...prev, ...newTheme }));
2407
+ };
2408
+ const value = {
2409
+ theme: themeState,
2410
+ setTheme,
2411
+ locale: typeof locale === "string" ? locale === "en-US" ? en_US_default : zh_CN_default : locale ?? zh_CN_default,
2412
+ ...ai && { ai },
2413
+ ...components && { components }
2414
+ };
2415
+ const resolveMode = value.theme.mode === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : value.theme.mode;
2416
+ document.documentElement.setAttribute("data-theme", resolveMode);
2417
+ return /* @__PURE__ */ jsx(configContext.Provider, { value, children });
2418
+ }
2419
+ function useConfig() {
2420
+ const context = useContext(configContext);
2421
+ if (!context) {
2422
+ throw new Error("useConfig \u5FC5\u987B\u5728 ConfigProvider \u5185\u90E8\u4F7F\u7528");
2423
+ }
2424
+ return context;
2425
+ }
2426
+
2427
+ // src/hooks/useLocale.ts
2428
+ function useLocale() {
2429
+ const context = useConfig();
2430
+ return context.locale;
2431
+ }
2432
+
2433
+ // src/hooks/useTheme.ts
2434
+ function useTheme() {
2435
+ const context = useConfig();
2436
+ const setMode = (mode) => {
2437
+ context.setTheme({ mode });
2438
+ };
2439
+ const isDark = context.theme.mode === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches : context.theme.mode === "dark";
2440
+ return {
2441
+ mode: context.theme.mode,
2442
+ isDark,
2443
+ setMode,
2444
+ primaryColor: context.theme.primaryColor
2445
+ };
2446
+ }
2447
+ function useStream() {
2448
+ const [state, setState] = useState("idle");
2449
+ const [content, setContent] = useState("");
2450
+ const abortRef = useRef(new AbortController());
2451
+ const start = useCallback(
2452
+ async (generator, options) => {
2453
+ abortRef.current = new AbortController();
2454
+ setState("streaming");
2455
+ setContent("");
2456
+ let nextContent = "";
2457
+ try {
2458
+ for await (const token of generator) {
2459
+ if (abortRef.current.signal.aborted) break;
2460
+ nextContent += token;
2461
+ setContent(nextContent);
2462
+ options?.onToken?.(nextContent, token);
2463
+ }
2464
+ if (!abortRef.current.signal.aborted) {
2465
+ setState("complete");
2466
+ options?.onComplete?.(nextContent);
2467
+ }
2468
+ } catch {
2469
+ setState("error");
2470
+ options?.onError?.();
2471
+ }
2472
+ },
2473
+ []
2474
+ );
2475
+ const cancel = useCallback(() => {
2476
+ abortRef.current.abort();
2477
+ setState("idle");
2478
+ }, []);
2479
+ return { content, state, start, cancel };
2480
+ }
2481
+
2482
+ // src/utils/stream.ts
2483
+ async function* streamToGenerator(stream, encoding = "utf-8") {
2484
+ const reader = stream.getReader();
2485
+ const decoder = new TextDecoder(encoding);
2486
+ try {
2487
+ while (true) {
2488
+ const { value, done } = await reader.read();
2489
+ if (done) break;
2490
+ yield decoder.decode(value, { stream: true });
2491
+ }
2492
+ } finally {
2493
+ reader.releaseLock();
2494
+ }
2495
+ }
2496
+ function generatorToStream(gen) {
2497
+ const encoder = new TextEncoder();
2498
+ return new ReadableStream({
2499
+ async pull(controller) {
2500
+ const { value, done } = await gen.next();
2501
+ if (done) {
2502
+ controller.close();
2503
+ } else {
2504
+ controller.enqueue(encoder.encode(value));
2505
+ }
2506
+ }
2507
+ });
2508
+ }
2509
+ async function* mockStream(text, delay = 50) {
2510
+ for (const char of text) {
2511
+ yield char;
2512
+ await new Promise((resolve) => setTimeout(resolve, delay));
2513
+ }
2514
+ }
2515
+
2516
+ export { Actions, ActionsPrimitive, Bubble, BubblePrimitive, Citation, CitationInlinePrimitive, CitationPrimitive, CodeHighlighter, CodeHighlighterPrimitive, ConfigProvider, ConversationItem, ConversationItemPrimitive, ConversationList, ConversationListPrimitive, Mark, MarkPrimitive, MessageList, MessageListPrimitive, Notification, NotificationPrimitive, NotificationStack, Prompts, PromptsPrimitive, Sender, SenderPrimitive, Think, ThinkPrimitive, Thought, ThoughtPrimitive, actionPresets, createPresetActions, en_US_default as enUS, generatorToStream, mockStream, sanitizeMarkdown, streamToGenerator, useConfig, useLocale, useStream, useTheme, useVirtualList, zh_CN_default as zhCN };
2517
+ //# sourceMappingURL=index.js.map
2518
+ //# sourceMappingURL=index.js.map