@djangocfg/ui-tools 2.1.385 → 2.1.389

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +25 -11
  2. package/dist/ChatRoot-EFNXQXXN.cjs +15 -0
  3. package/dist/{ChatRoot-JVR3M3H2.mjs.map → ChatRoot-EFNXQXXN.cjs.map} +1 -1
  4. package/dist/ChatRoot-FITF5RVP.mjs +6 -0
  5. package/dist/{ChatRoot-LXIUBOXF.cjs.map → ChatRoot-FITF5RVP.mjs.map} +1 -1
  6. package/dist/{DocsLayout-2P3ONDWJ.mjs → DocsLayout-EKASBSP7.mjs} +3 -3
  7. package/dist/{DocsLayout-2P3ONDWJ.mjs.map → DocsLayout-EKASBSP7.mjs.map} +1 -1
  8. package/dist/{DocsLayout-2YZNS5VK.cjs → DocsLayout-OURFYWQE.cjs} +8 -8
  9. package/dist/{DocsLayout-2YZNS5VK.cjs.map → DocsLayout-OURFYWQE.cjs.map} +1 -1
  10. package/dist/MapContainer-AKIPABJK.mjs +4 -0
  11. package/dist/MapContainer-AKIPABJK.mjs.map +1 -0
  12. package/dist/MapContainer-STVDMC36.cjs +17 -0
  13. package/dist/MapContainer-STVDMC36.cjs.map +1 -0
  14. package/dist/{chunk-HIK6BPL7.mjs → chunk-2NG4SXEP.mjs} +6 -5
  15. package/dist/chunk-2NG4SXEP.mjs.map +1 -0
  16. package/dist/chunk-4LFB7I5K.cjs +1387 -0
  17. package/dist/chunk-4LFB7I5K.cjs.map +1 -0
  18. package/dist/{MapContainer-76YL2JXL.cjs → chunk-5D2OCOPQ.cjs} +3 -2
  19. package/dist/chunk-5D2OCOPQ.cjs.map +1 -0
  20. package/dist/chunk-6ZX2G25W.mjs +1361 -0
  21. package/dist/chunk-6ZX2G25W.mjs.map +1 -0
  22. package/dist/{MapContainer-7HXBI3OH.mjs → chunk-7CWGZPO3.mjs} +3 -3
  23. package/dist/chunk-7CWGZPO3.mjs.map +1 -0
  24. package/dist/{chunk-FIRK5CEH.cjs → chunk-7IYXZUJO.cjs} +8 -4
  25. package/dist/chunk-7IYXZUJO.cjs.map +1 -0
  26. package/dist/{chunk-PEKBT75W.mjs → chunk-DMX7W4XZ.mjs} +53 -1387
  27. package/dist/chunk-DMX7W4XZ.mjs.map +1 -0
  28. package/dist/chunk-NTVBIIUD.mjs +1439 -0
  29. package/dist/chunk-NTVBIIUD.mjs.map +1 -0
  30. package/dist/{chunk-HPK3EWBF.cjs → chunk-TBSHZO5R.cjs} +50 -1409
  31. package/dist/chunk-TBSHZO5R.cjs.map +1 -0
  32. package/dist/chunk-W75B7Y6C.cjs +1478 -0
  33. package/dist/chunk-W75B7Y6C.cjs.map +1 -0
  34. package/dist/index.cjs +1269 -1790
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +660 -623
  37. package/dist/index.d.ts +660 -623
  38. package/dist/index.mjs +856 -1427
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/launcher-5Y42OBSN.mjs +6 -0
  41. package/dist/launcher-5Y42OBSN.mjs.map +1 -0
  42. package/dist/launcher-PMW2YB24.cjs +59 -0
  43. package/dist/launcher-PMW2YB24.cjs.map +1 -0
  44. package/package.json +23 -18
  45. package/src/components/index.ts +2 -2
  46. package/src/index.ts +20 -2
  47. package/src/tools/AudioPlayer/lazy.tsx +100 -0
  48. package/src/tools/Chat/README.md +85 -1
  49. package/src/tools/Chat/components/MessageBubble.tsx +1 -1
  50. package/src/tools/Chat/context/ChatProvider.tsx +42 -0
  51. package/src/tools/Chat/index.ts +1 -1
  52. package/src/tools/Chat/lazy.tsx +300 -1
  53. package/src/tools/CodeEditor/lazy.tsx +70 -0
  54. package/src/tools/Map/lazy.tsx +38 -1
  55. package/src/tools/MarkdownEditor/lazy.tsx +42 -0
  56. package/src/{components/markdown → tools}/MarkdownMessage/CodeBlock.tsx +1 -1
  57. package/src/{components/markdown → tools}/MarkdownMessage/CollapseToggle.tsx +1 -1
  58. package/src/{components/markdown → tools}/MarkdownMessage/MarkdownMessage.tsx +1 -1
  59. package/src/{components/markdown → tools}/MarkdownMessage/components.tsx +2 -2
  60. package/src/tools/OpenapiViewer/components/DocsLayout/ApiIntroSection.tsx +1 -1
  61. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/index.tsx +1 -1
  62. package/src/tools/SpeechRecognition/README.md +48 -0
  63. package/dist/ChatRoot-JVR3M3H2.mjs +0 -5
  64. package/dist/ChatRoot-LXIUBOXF.cjs +0 -14
  65. package/dist/MapContainer-76YL2JXL.cjs.map +0 -1
  66. package/dist/MapContainer-7HXBI3OH.mjs.map +0 -1
  67. package/dist/chunk-FIRK5CEH.cjs.map +0 -1
  68. package/dist/chunk-HIK6BPL7.mjs.map +0 -1
  69. package/dist/chunk-HPK3EWBF.cjs.map +0 -1
  70. package/dist/chunk-PEKBT75W.mjs.map +0 -1
  71. package/src/components/markdown/index.ts +0 -19
  72. /package/src/{components/markdown → hooks}/useCollapsibleContent.ts +0 -0
  73. /package/src/{components/markdown → tools}/MarkdownMessage/ActionRow.tsx +0 -0
  74. /package/src/{components/markdown → tools}/MarkdownMessage/ChatMessageRow.tsx +0 -0
  75. /package/src/{components/markdown → tools}/MarkdownMessage/README.md +0 -0
  76. /package/src/{components/markdown → tools}/MarkdownMessage/index.ts +0 -0
  77. /package/src/{components/markdown → tools}/MarkdownMessage/linkRules.ts +0 -0
  78. /package/src/{components/markdown → tools}/MarkdownMessage/plainText.ts +0 -0
  79. /package/src/{components/markdown → tools}/MarkdownMessage/sanitize.ts +0 -0
  80. /package/src/{components/markdown → tools}/MarkdownMessage/types.ts +0 -0
@@ -1,13 +1,9 @@
1
- import { TOOL_CALL, DESTRUCTIVE_SURFACE, TOGGLE, ANCHOR, BUBBLE_SURFACE, MarkdownMessage } from './chunk-HIK6BPL7.mjs';
2
1
  import { __name } from './chunk-N2XQF2OL.mjs';
3
- import { createContext, forwardRef, useRef, useEffect, memo, useState, useCallback, useImperativeHandle, useMemo, useReducer, useContext } from 'react';
4
- import { cn, isDev } from '@djangocfg/ui-core/lib';
5
2
  import { consola } from 'consola';
6
- import { useCopy, useLocalStorage, useMediaQuery, useNotificationSounds } from '@djangocfg/ui-core/hooks';
7
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
- import { Paperclip, Square, Send, ChevronDown, ChevronRight, Loader2, File, X, Sparkles, AlertCircle, RefreshCw, ArrowDown, ExternalLink, Copy, Pencil, Trash } from 'lucide-react';
9
- import { Button, Textarea, Spinner, Avatar, AvatarImage, AvatarFallback } from '@djangocfg/ui-core/components';
10
- import { Virtuoso } from 'react-virtuoso';
3
+ import { isDev } from '@djangocfg/ui-core/lib';
4
+ import { createContext, useReducer, useRef, useEffect, useCallback, useState, useMemo, useContext } from 'react';
5
+ import { useLocalStorage, useMediaQuery, useNotificationSounds } from '@djangocfg/ui-core/hooks';
6
+ import { jsx } from 'react/jsx-runtime';
11
7
 
12
8
  // src/tools/Chat/types/labels.ts
13
9
  var DEFAULT_LABELS = {
@@ -337,32 +333,6 @@ function createId(prefix = "m") {
337
333
  return `${prefix}_${Date.now().toString(36)}_${counter.toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
338
334
  }
339
335
  __name(createId, "createId");
340
- var SCOPES = ["bootstrap", "transport", "stream", "lifecycle", "tools", "error"];
341
- var cache = /* @__PURE__ */ new Map();
342
- function buildLogger(enabled) {
343
- const root = consola.withTag("chat");
344
- const subs = Object.fromEntries(
345
- SCOPES.map((scope) => [scope, root.withTag(scope)])
346
- );
347
- if (!enabled) {
348
- for (const scope of SCOPES) {
349
- if (scope === "error") continue;
350
- subs[scope].level = -999;
351
- }
352
- }
353
- return { ...subs, enabled };
354
- }
355
- __name(buildLogger, "buildLogger");
356
- function getChatLogger(debug) {
357
- const enabled = debug ?? isDev;
358
- let logger = cache.get(enabled);
359
- if (!logger) {
360
- logger = buildLogger(enabled);
361
- cache.set(enabled, logger);
362
- }
363
- return logger;
364
- }
365
- __name(getChatLogger, "getChatLogger");
366
336
 
367
337
  // src/tools/Chat/core/markdown.ts
368
338
  function createTokenBuffer(onFlush, windowMs = LIMITS.streamCoalesceMs) {
@@ -400,8 +370,32 @@ function createTokenBuffer(onFlush, windowMs = LIMITS.streamCoalesceMs) {
400
370
  };
401
371
  }
402
372
  __name(createTokenBuffer, "createTokenBuffer");
403
-
404
- // src/tools/Chat/hooks/useChat.ts
373
+ var SCOPES = ["bootstrap", "transport", "stream", "lifecycle", "tools", "error"];
374
+ var cache = /* @__PURE__ */ new Map();
375
+ function buildLogger(enabled) {
376
+ const root = consola.withTag("chat");
377
+ const subs = Object.fromEntries(
378
+ SCOPES.map((scope) => [scope, root.withTag(scope)])
379
+ );
380
+ if (!enabled) {
381
+ for (const scope of SCOPES) {
382
+ if (scope === "error") continue;
383
+ subs[scope].level = -999;
384
+ }
385
+ }
386
+ return { ...subs, enabled };
387
+ }
388
+ __name(buildLogger, "buildLogger");
389
+ function getChatLogger(debug) {
390
+ const enabled = debug ?? isDev;
391
+ let logger = cache.get(enabled);
392
+ if (!logger) {
393
+ logger = buildLogger(enabled);
394
+ cache.set(enabled, logger);
395
+ }
396
+ return logger;
397
+ }
398
+ __name(getChatLogger, "getChatLogger");
405
399
  function useChat(config) {
406
400
  const [state, dispatch] = useReducer(reducer, initialState);
407
401
  const stateRef = useRef(state);
@@ -969,8 +963,6 @@ var DEFAULT_CHAT_SOUNDS = {
969
963
  mention: mention_default,
970
964
  notification: notification_default
971
965
  };
972
-
973
- // src/tools/Chat/hooks/useChatAudio.ts
974
966
  var STORAGE_KEY = "djangocfg-chat-audio:prefs";
975
967
  var DEFAULT_EVENT_VOLUMES = {
976
968
  error: 0.25,
@@ -1012,6 +1004,26 @@ function useChatAudio(config = {}) {
1012
1004
  }
1013
1005
  __name(useChatAudio, "useChatAudio");
1014
1006
  var Ctx = createContext(null);
1007
+ var GLOBAL_KEY = "__djangocfg_chat_ctx_stamps__";
1008
+ var stamp = /* @__PURE__ */ Symbol("djangocfg.chat.ctx");
1009
+ function markCtxLoad() {
1010
+ if (typeof globalThis === "undefined") return;
1011
+ const g = globalThis;
1012
+ let slot = g[GLOBAL_KEY];
1013
+ if (!slot) {
1014
+ slot = { stamps: /* @__PURE__ */ new Set(), warned: false };
1015
+ g[GLOBAL_KEY] = slot;
1016
+ }
1017
+ slot.stamps.add(stamp);
1018
+ if (slot.stamps.size > 1 && !slot.warned && process.env.NODE_ENV !== "production") {
1019
+ slot.warned = true;
1020
+ console.warn(
1021
+ "[@djangocfg/ui-tools/chat] Two ChatProvider context instances detected \u2014 this means `@djangocfg/ui-tools` was loaded twice (one bundle via the root `.` export \u2192 `dist/`, another via a `./chat` / `./speech-recognition` subpath \u2192 `src/`). Symptom: `useChatContextOptional()` returns `null` for descendants of `<ChatProvider>`, so VoiceComposerSlot drops transcripts, useChatReset silently no-ops, etc. \n\nFix: import every Chat surface from the SAME subpath. Recommended:\n import { ChatRoot, ChatLauncher, useChatContextOptional, \u2026 } from '@djangocfg/ui-tools/chat';\n import { VoiceComposerSlot } from '@djangocfg/ui-tools/speech-recognition';\n\n(See packages/ui-tools/src/tools/Chat/README.md \u2192 \"Anti-patterns\".)"
1022
+ );
1023
+ }
1024
+ }
1025
+ __name(markCtxLoad, "markCtxLoad");
1026
+ markCtxLoad();
1015
1027
  function ChatProvider({
1016
1028
  transport,
1017
1029
  config = {},
@@ -1095,1353 +1107,7 @@ function useChatContextOptional() {
1095
1107
  return useContext(Ctx);
1096
1108
  }
1097
1109
  __name(useChatContextOptional, "useChatContextOptional");
1098
- function useAutoFocusOnStreamEnd(options = {}) {
1099
- const { isStreaming: isStreamingProp, targetRef, enabled = true, delayMs = 0 } = options;
1100
- const ctx = useChatContextOptional();
1101
- const isStreaming = isStreamingProp ?? ctx?.isStreaming ?? false;
1102
- const composerHandleRef = useRef(null);
1103
- composerHandleRef.current = ctx?.composer ?? null;
1104
- const prevStreamingRef = useRef(isStreaming);
1105
- useEffect(() => {
1106
- const wasStreaming = prevStreamingRef.current;
1107
- prevStreamingRef.current = isStreaming;
1108
- if (!enabled) return;
1109
- if (!(wasStreaming && !isStreaming)) return;
1110
- const focusNow = /* @__PURE__ */ __name(() => {
1111
- const explicit = targetRef?.current;
1112
- const target = explicit ?? composerHandleRef.current;
1113
- target?.focus();
1114
- }, "focusNow");
1115
- if (delayMs > 0) {
1116
- const id = window.setTimeout(focusNow, delayMs);
1117
- return () => window.clearTimeout(id);
1118
- }
1119
- const raf = requestAnimationFrame(focusNow);
1120
- return () => cancelAnimationFrame(raf);
1121
- }, [isStreaming, enabled, delayMs, targetRef]);
1122
- }
1123
- __name(useAutoFocusOnStreamEnd, "useAutoFocusOnStreamEnd");
1124
- function useRegisterComposer(handle) {
1125
- const ctx = useChatContextOptional();
1126
- const register = ctx?.registerComposer;
1127
- const focus = handle.focus;
1128
- const moveCursorToEnd = handle.moveCursorToEnd;
1129
- useEffect(() => {
1130
- if (!register) return;
1131
- register({ focus, moveCursorToEnd });
1132
- return () => register(null);
1133
- }, [register, focus, moveCursorToEnd]);
1134
- }
1135
- __name(useRegisterComposer, "useRegisterComposer");
1136
-
1137
- // src/tools/Chat/utils/sanitizeDraft.ts
1138
- function sanitizeDraft(input) {
1139
- if (!input) return "";
1140
- let s = input.replace(/[​‌‍]/g, "");
1141
- s = s.replace(/\r\n?/g, "\n");
1142
- s = s.trim();
1143
- return s;
1144
- }
1145
- __name(sanitizeDraft, "sanitizeDraft");
1146
- function isSubmittableDraft(input) {
1147
- return sanitizeDraft(input).length > 0;
1148
- }
1149
- __name(isSubmittableDraft, "isSubmittableDraft");
1150
-
1151
- // src/tools/Chat/hooks/useChatComposer.ts
1152
- var MAX_TEXTAREA_HEIGHT = 240;
1153
- function useChatComposer(options) {
1154
- const {
1155
- onSubmit,
1156
- initialValue = "",
1157
- maxLength = LIMITS.messageMaxLength,
1158
- maxAttachments = LIMITS.attachmentsMax,
1159
- disabled = false,
1160
- submitOn = "enter",
1161
- history = { enabled: true, size: LIMITS.composerHistorySize },
1162
- onPasteFiles,
1163
- persistKey,
1164
- preserveExactValue = false
1165
- } = options;
1166
- const initialFromStorage = (() => {
1167
- if (!persistKey || typeof window === "undefined") return initialValue;
1168
- try {
1169
- const stored = window.sessionStorage.getItem(`chat:draft:${persistKey}`);
1170
- return stored && stored.length > 0 ? stored : initialValue;
1171
- } catch {
1172
- return initialValue;
1173
- }
1174
- })();
1175
- const [value, setValueState] = useState(initialFromStorage);
1176
- useEffect(() => {
1177
- if (!persistKey || typeof window === "undefined") return;
1178
- try {
1179
- const k = `chat:draft:${persistKey}`;
1180
- if (value.length > 0) window.sessionStorage.setItem(k, value);
1181
- else window.sessionStorage.removeItem(k);
1182
- } catch {
1183
- }
1184
- }, [value, persistKey]);
1185
- const [attachments, setAttachments] = useState([]);
1186
- const [isSubmitting, setIsSubmitting] = useState(false);
1187
- const textareaRef = useRef(null);
1188
- const historyRef = useRef({ items: [], index: -1 });
1189
- const setValue = useCallback(
1190
- (next) => {
1191
- setValueState(next.length > maxLength ? next.slice(0, maxLength) : next);
1192
- },
1193
- [maxLength]
1194
- );
1195
- useEffect(() => {
1196
- const el = textareaRef.current;
1197
- if (!el) return;
1198
- el.style.height = "auto";
1199
- el.style.height = `${Math.min(el.scrollHeight, MAX_TEXTAREA_HEIGHT)}px`;
1200
- }, [value]);
1201
- const reset = useCallback(() => {
1202
- setValueState("");
1203
- setAttachments([]);
1204
- historyRef.current.index = -1;
1205
- }, []);
1206
- const focus = useCallback(() => {
1207
- requestAnimationFrame(() => textareaRef.current?.focus());
1208
- }, []);
1209
- const submit = useCallback(async () => {
1210
- const cleaned = preserveExactValue ? value : sanitizeDraft(value);
1211
- if (!cleaned && attachments.length === 0 || isSubmitting || disabled) return;
1212
- setIsSubmitting(true);
1213
- try {
1214
- if (history.enabled !== false && cleaned) {
1215
- const buf = historyRef.current.items;
1216
- if (buf[buf.length - 1] !== cleaned) {
1217
- buf.push(cleaned);
1218
- if (buf.length > (history.size ?? LIMITS.composerHistorySize)) buf.shift();
1219
- }
1220
- historyRef.current.index = -1;
1221
- }
1222
- const snapshot = [...attachments];
1223
- reset();
1224
- await onSubmit(cleaned, snapshot);
1225
- } finally {
1226
- setIsSubmitting(false);
1227
- }
1228
- }, [value, attachments, isSubmitting, disabled, history, onSubmit, reset, preserveExactValue]);
1229
- const addAttachment = useCallback(
1230
- (a) => {
1231
- setAttachments((prev) => {
1232
- if (prev.some((p) => p.id === a.id)) {
1233
- return prev.map((p) => p.id === a.id ? a : p);
1234
- }
1235
- if (prev.length >= maxAttachments) return prev;
1236
- return [...prev, a];
1237
- });
1238
- },
1239
- [maxAttachments]
1240
- );
1241
- const removeAttachment = useCallback((id) => {
1242
- setAttachments((prev) => prev.filter((a) => a.id !== id));
1243
- }, []);
1244
- const recallPrevious = useCallback(() => {
1245
- const { items } = historyRef.current;
1246
- if (!items.length) return;
1247
- const next = historyRef.current.index < 0 ? items.length - 1 : Math.max(0, historyRef.current.index - 1);
1248
- historyRef.current.index = next;
1249
- setValueState(items[next]);
1250
- }, []);
1251
- const recallNext = useCallback(() => {
1252
- const { items } = historyRef.current;
1253
- if (!items.length || historyRef.current.index < 0) return;
1254
- const next = historyRef.current.index + 1;
1255
- if (next >= items.length) {
1256
- historyRef.current.index = -1;
1257
- setValueState("");
1258
- return;
1259
- }
1260
- historyRef.current.index = next;
1261
- setValueState(items[next]);
1262
- }, []);
1263
- const onChange = useCallback(
1264
- (e) => {
1265
- setValue(e.target.value);
1266
- },
1267
- [setValue]
1268
- );
1269
- const onKeyDown = useCallback(
1270
- (e) => {
1271
- if (e.key === "Enter") {
1272
- const isCmd = e.metaKey || e.ctrlKey;
1273
- const shouldSend = submitOn === "cmd+enter" ? isCmd : !e.shiftKey;
1274
- if (shouldSend) {
1275
- e.preventDefault();
1276
- void submit();
1277
- }
1278
- return;
1279
- }
1280
- if (history.enabled !== false && value === "" && attachments.length === 0) {
1281
- if (e.key === "ArrowUp") {
1282
- e.preventDefault();
1283
- recallPrevious();
1284
- } else if (e.key === "ArrowDown" && historyRef.current.index >= 0) {
1285
- e.preventDefault();
1286
- recallNext();
1287
- }
1288
- }
1289
- },
1290
- [submitOn, submit, history, value, attachments.length, recallPrevious, recallNext]
1291
- );
1292
- const onPaste = useCallback(
1293
- (e) => {
1294
- const files = Array.from(e.clipboardData?.files ?? []);
1295
- if (files.length && onPasteFiles) {
1296
- e.preventDefault();
1297
- onPasteFiles(files);
1298
- }
1299
- },
1300
- [onPasteFiles]
1301
- );
1302
- const canSubmit = !disabled && !isSubmitting && ((preserveExactValue ? value.trim().length : sanitizeDraft(value).length) > 0 || attachments.length > 0);
1303
- return {
1304
- value,
1305
- setValue,
1306
- attachments,
1307
- addAttachment,
1308
- removeAttachment,
1309
- isSubmitting,
1310
- canSubmit,
1311
- submit,
1312
- reset,
1313
- focus,
1314
- textareaRef,
1315
- textareaProps: {
1316
- ref: textareaRef,
1317
- value,
1318
- disabled,
1319
- onChange,
1320
- onKeyDown,
1321
- onPaste
1322
- },
1323
- recallPrevious,
1324
- recallNext
1325
- };
1326
- }
1327
- __name(useChatComposer, "useChatComposer");
1328
- function useFocusOnEmptyClick(options = {}) {
1329
- const { targetRef, enabled = true, skipWhileStreaming = true } = options;
1330
- const ctx = useChatContextOptional();
1331
- const composerHandleRef = useRef(null);
1332
- composerHandleRef.current = ctx?.composer ?? null;
1333
- const isStreamingRef = useRef(false);
1334
- isStreamingRef.current = ctx?.isStreaming ?? false;
1335
- return useCallback(
1336
- (event) => {
1337
- if (!enabled) return;
1338
- if (skipWhileStreaming && isStreamingRef.current) return;
1339
- const pointerType = event.nativeEvent.pointerType;
1340
- if (pointerType && pointerType !== "mouse") return;
1341
- const selection = typeof window !== "undefined" ? window.getSelection?.() : null;
1342
- if (selection && !selection.isCollapsed && selection.toString().length > 0) {
1343
- return;
1344
- }
1345
- const target = event.target;
1346
- if (!target) return;
1347
- if (isInteractive(target)) return;
1348
- const explicit = targetRef?.current;
1349
- if (explicit) {
1350
- explicit.focus?.();
1351
- return;
1352
- }
1353
- composerHandleRef.current?.focus?.();
1354
- },
1355
- [enabled, skipWhileStreaming, targetRef]
1356
- );
1357
- }
1358
- __name(useFocusOnEmptyClick, "useFocusOnEmptyClick");
1359
- var INTERACTIVE_SELECTORS = [
1360
- "a[href]",
1361
- "button",
1362
- "input",
1363
- "textarea",
1364
- "select",
1365
- "label",
1366
- "summary",
1367
- '[role="button"]',
1368
- '[role="link"]',
1369
- '[role="menuitem"]',
1370
- '[role="tab"]',
1371
- '[contenteditable]:not([contenteditable="false"])',
1372
- "[data-no-autofocus]"
1373
- ].join(",");
1374
- function isInteractive(el) {
1375
- if (!el) return false;
1376
- return !!el.closest(INTERACTIVE_SELECTORS);
1377
- }
1378
- __name(isInteractive, "isInteractive");
1379
- function useChatBubbleStyles(role, isError) {
1380
- return useMemo(() => {
1381
- const isUser = role === "user";
1382
- const variant = isUser ? "user" : isError ? "error" : "assistant";
1383
- return {
1384
- surface: BUBBLE_SURFACE[variant],
1385
- anchor: isUser ? ANCHOR.user : ANCHOR.assistant,
1386
- toggle: isUser ? TOGGLE.user : TOGGLE.assistant
1387
- };
1388
- }, [role, isError]);
1389
- }
1390
- __name(useChatBubbleStyles, "useChatBubbleStyles");
1391
- function useChatRoleStyles(isUser) {
1392
- return useMemo(
1393
- () => ({
1394
- anchor: isUser ? ANCHOR.user : ANCHOR.assistant,
1395
- toggle: isUser ? TOGGLE.user : TOGGLE.assistant
1396
- }),
1397
- [isUser]
1398
- );
1399
- }
1400
- __name(useChatRoleStyles, "useChatRoleStyles");
1401
- function useChatDestructiveStyles() {
1402
- return DESTRUCTIVE_STYLES;
1403
- }
1404
- __name(useChatDestructiveStyles, "useChatDestructiveStyles");
1405
- var DESTRUCTIVE_STYLES = {
1406
- banner: DESTRUCTIVE_SURFACE.banner,
1407
- hover: DESTRUCTIVE_SURFACE.hover,
1408
- hoverStrong: DESTRUCTIVE_SURFACE.hoverStrong,
1409
- text: DESTRUCTIVE_SURFACE.text,
1410
- menuItem: DESTRUCTIVE_SURFACE.menuItem,
1411
- toolErrorText: TOOL_CALL.errorText
1412
- };
1413
- function AttachmentsGrid({
1414
- attachments,
1415
- maxVisible,
1416
- onClick,
1417
- onRemove,
1418
- isInComposer = false,
1419
- layout = "wrap",
1420
- className
1421
- }) {
1422
- if (!attachments?.length) return null;
1423
- const visible = maxVisible ? attachments.slice(0, maxVisible) : attachments;
1424
- return /* @__PURE__ */ jsx(
1425
- "div",
1426
- {
1427
- className: cn(
1428
- layout === "grid" ? "grid grid-cols-3 gap-2" : "flex flex-wrap gap-2",
1429
- className
1430
- ),
1431
- children: visible.map((a) => /* @__PURE__ */ jsx(
1432
- AttachmentTile,
1433
- {
1434
- attachment: a,
1435
- isInComposer,
1436
- onClick: onClick ? () => onClick(a) : void 0,
1437
- onRemove: onRemove ? () => onRemove(a) : void 0
1438
- },
1439
- a.id
1440
- ))
1441
- }
1442
- );
1443
- }
1444
- __name(AttachmentsGrid, "AttachmentsGrid");
1445
- function AttachmentsList({
1446
- attachments,
1447
- maxVisible,
1448
- onClick,
1449
- onRemove,
1450
- renderers,
1451
- isInComposer = false,
1452
- className
1453
- }) {
1454
- if (!attachments?.length) return null;
1455
- const visible = maxVisible ? attachments.slice(0, maxVisible) : attachments;
1456
- return /* @__PURE__ */ jsx("div", { className: cn("flex w-full flex-col gap-2", className), children: visible.map((a) => {
1457
- const renderer = renderers?.[a.type] ?? renderers?.default;
1458
- const args = {
1459
- attachment: a,
1460
- isInComposer,
1461
- onClick: onClick ? () => onClick(a) : void 0,
1462
- onRemove: onRemove ? () => onRemove(a) : void 0
1463
- };
1464
- if (renderer) {
1465
- return /* @__PURE__ */ jsxs("div", { className: "relative w-full min-w-0", children: [
1466
- renderer(args),
1467
- args.onRemove ? /* @__PURE__ */ jsx(RemoveBtn, { onRemove: args.onRemove }) : null
1468
- ] }, a.id);
1469
- }
1470
- return /* @__PURE__ */ jsx(AttachmentTile, { ...args }, a.id);
1471
- }) });
1472
- }
1473
- __name(AttachmentsList, "AttachmentsList");
1474
- function Attachments(props) {
1475
- const { renderers, layout, ...rest } = props;
1476
- if (renderers) {
1477
- return /* @__PURE__ */ jsx(AttachmentsList, { ...rest, renderers });
1478
- }
1479
- return /* @__PURE__ */ jsx(AttachmentsGrid, { ...rest, layout: layout === "grid" ? "grid" : "wrap" });
1480
- }
1481
- __name(Attachments, "Attachments");
1482
- function AttachmentTile({ attachment, onClick, onRemove }) {
1483
- const isImage = attachment.type === "image";
1484
- const isUploading = attachment.status === "uploading";
1485
- const inner = isImage ? /* @__PURE__ */ jsx(
1486
- "img",
1487
- {
1488
- src: attachment.thumbnailUrl ?? attachment.url,
1489
- alt: attachment.name ?? "attachment",
1490
- className: "h-16 w-16 rounded-md object-cover",
1491
- loading: "lazy"
1492
- }
1493
- ) : /* @__PURE__ */ jsxs("div", { className: "flex max-w-44 items-center gap-2 rounded-md border border-border bg-background/60 px-2 py-1.5 text-xs", children: [
1494
- /* @__PURE__ */ jsx(File, { "aria-hidden": true, className: "size-4 shrink-0 text-muted-foreground" }),
1495
- /* @__PURE__ */ jsx("span", { className: "truncate", children: attachment.name ?? "file" })
1496
- ] });
1497
- return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1498
- onClick ? /* @__PURE__ */ jsx("button", { type: "button", onClick, className: "block", children: inner }) : inner,
1499
- isUploading ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center rounded-md bg-background/70 text-[10px] font-medium", children: attachment.progress != null ? `${Math.round(attachment.progress * 100)}%` : "\u2026" }) : null,
1500
- onRemove ? /* @__PURE__ */ jsx(RemoveBtn, { onRemove }) : null
1501
- ] });
1502
- }
1503
- __name(AttachmentTile, "AttachmentTile");
1504
- function RemoveBtn({ onRemove }) {
1505
- const styles = useChatDestructiveStyles();
1506
- return /* @__PURE__ */ jsx(
1507
- "button",
1508
- {
1509
- type: "button",
1510
- "aria-label": "Remove attachment",
1511
- onClick: onRemove,
1512
- className: cn(
1513
- "absolute -right-1.5 -top-1.5 grid h-4 w-4 place-items-center rounded-full border border-border bg-background text-muted-foreground",
1514
- styles.hoverStrong
1515
- ),
1516
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": true, className: "size-2.5" })
1517
- }
1518
- );
1519
- }
1520
- __name(RemoveBtn, "RemoveBtn");
1521
- var SIZE_CLASSES = {
1522
- sm: {
1523
- slot: "[&>:not(textarea)]:h-8",
1524
- button: "h-8 w-8",
1525
- iconButton: "size-3.5",
1526
- textarea: "min-h-8 max-h-48 px-3 py-1.5",
1527
- text: "text-sm",
1528
- padding: "gap-1.5",
1529
- containerPadding: "px-2 pt-1.5 pb-[max(0.375rem,env(safe-area-inset-bottom))]"
1530
- },
1531
- md: {
1532
- slot: "[&>:not(textarea)]:h-9",
1533
- button: "h-9 w-9",
1534
- iconButton: "size-4",
1535
- textarea: "min-h-9 max-h-60 px-3.5 py-2",
1536
- text: "text-base sm:text-sm",
1537
- padding: "gap-1.5",
1538
- containerPadding: "px-2.5 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]"
1539
- },
1540
- lg: {
1541
- slot: "[&>:not(textarea)]:h-12",
1542
- button: "h-12 w-12",
1543
- iconButton: "size-5",
1544
- textarea: "min-h-12 max-h-72 px-4 py-3",
1545
- text: "text-base",
1546
- padding: "gap-2",
1547
- containerPadding: "px-3.5 pt-3 pb-[max(0.875rem,env(safe-area-inset-bottom))]"
1548
- }
1549
- };
1550
- var Composer = forwardRef(/* @__PURE__ */ __name(function Composer2({
1551
- composer,
1552
- placeholder = "Type a message...",
1553
- disabled,
1554
- showAttachmentButton = false,
1555
- onPickFiles,
1556
- toolbarStart,
1557
- toolbarEnd,
1558
- attachmentTray,
1559
- className,
1560
- textareaClassName,
1561
- size = "md",
1562
- isStreaming: isStreamingProp,
1563
- onCancel: onCancelProp
1564
- }, ref) {
1565
- const ctx = useChatContextOptional();
1566
- const isStreaming = isStreamingProp ?? ctx?.isStreaming ?? false;
1567
- const onCancel = onCancelProp ?? ctx?.cancelStream;
1568
- const isDisabled = disabled ?? isStreaming;
1569
- const sz = SIZE_CLASSES[size];
1570
- const register = ctx?.registerComposer;
1571
- const composerFocus = composer.focus;
1572
- const composerSetValue = composer.setValue;
1573
- const textareaRef = composer.textareaRef;
1574
- const getValueRef = useRef(() => composer.value);
1575
- getValueRef.current = () => composer.value;
1576
- useEffect(() => {
1577
- if (!register) return;
1578
- register({
1579
- focus: composerFocus,
1580
- moveCursorToEnd: /* @__PURE__ */ __name(() => {
1581
- const el = textareaRef.current;
1582
- if (!el) return;
1583
- const end = el.value.length;
1584
- el.setSelectionRange(end, end);
1585
- }, "moveCursorToEnd"),
1586
- getValue: /* @__PURE__ */ __name(() => getValueRef.current(), "getValue"),
1587
- setValue: composerSetValue
1588
- });
1589
- return () => register(null);
1590
- }, [register, composerFocus, composerSetValue, textareaRef]);
1591
- return /* @__PURE__ */ jsxs(
1592
- "div",
1593
- {
1594
- ref,
1595
- className: cn(
1596
- "border-t border-border bg-background/95",
1597
- sz.containerPadding,
1598
- className
1599
- ),
1600
- children: [
1601
- composer.attachments.length > 0 ? /* @__PURE__ */ jsx("div", { className: "mb-1.5", children: attachmentTray ?? /* @__PURE__ */ jsx(
1602
- Attachments,
1603
- {
1604
- attachments: composer.attachments,
1605
- onRemove: (a) => composer.removeAttachment(a.id)
1606
- }
1607
- ) }) : null,
1608
- /* @__PURE__ */ jsxs("div", { className: cn("flex items-end [&>:not(textarea)]:shrink-0", sz.padding, sz.slot), children: [
1609
- showAttachmentButton ? /* @__PURE__ */ jsx(
1610
- Button,
1611
- {
1612
- type: "button",
1613
- variant: "ghost",
1614
- size: "icon",
1615
- onClick: onPickFiles,
1616
- "aria-label": "Attach files",
1617
- disabled: isDisabled,
1618
- className: sz.button,
1619
- children: /* @__PURE__ */ jsx(Paperclip, { "aria-hidden": true, className: sz.iconButton })
1620
- }
1621
- ) : null,
1622
- toolbarStart,
1623
- /* @__PURE__ */ jsx(
1624
- Textarea,
1625
- {
1626
- ...composer.textareaProps,
1627
- rows: 1,
1628
- placeholder,
1629
- "aria-label": placeholder,
1630
- "aria-multiline": "true",
1631
- disabled: isDisabled,
1632
- className: cn(
1633
- "flex-1 resize-none rounded-2xl",
1634
- sz.textarea,
1635
- sz.text,
1636
- textareaClassName
1637
- )
1638
- }
1639
- ),
1640
- toolbarEnd,
1641
- isStreaming ? /* @__PURE__ */ jsx(
1642
- Button,
1643
- {
1644
- type: "button",
1645
- variant: "secondary",
1646
- size: "icon",
1647
- onClick: onCancel,
1648
- "aria-label": "Stop",
1649
- "aria-keyshortcuts": "Escape",
1650
- className: sz.button,
1651
- children: /* @__PURE__ */ jsx(Square, { "aria-hidden": true, className: sz.iconButton })
1652
- }
1653
- ) : /* @__PURE__ */ jsx(
1654
- Button,
1655
- {
1656
- type: "button",
1657
- size: "icon",
1658
- onClick: () => void composer.submit(),
1659
- disabled: !composer.canSubmit,
1660
- "aria-label": "Send",
1661
- "aria-keyshortcuts": "Enter",
1662
- className: sz.button,
1663
- children: /* @__PURE__ */ jsx(Send, { "aria-hidden": true, className: sz.iconButton })
1664
- }
1665
- )
1666
- ] })
1667
- ]
1668
- }
1669
- );
1670
- }, "Composer"));
1671
- function EmptyState({
1672
- greeting,
1673
- description,
1674
- suggestions,
1675
- onPickSuggestion,
1676
- className
1677
- }) {
1678
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-center gap-3 px-4 py-12 text-center", className), children: [
1679
- /* @__PURE__ */ jsx("div", { className: "grid size-10 place-items-center rounded-full bg-muted", children: /* @__PURE__ */ jsx(Sparkles, { "aria-hidden": true, className: "size-5 text-muted-foreground" }) }),
1680
- greeting ? /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: greeting }) : null,
1681
- description ? /* @__PURE__ */ jsx("p", { className: "max-w-md text-sm text-muted-foreground", children: description }) : null,
1682
- suggestions?.length ? /* @__PURE__ */ jsx("div", { className: "mt-2 grid w-full max-w-md grid-cols-1 gap-2 sm:grid-cols-2", children: suggestions.map((s) => /* @__PURE__ */ jsx(
1683
- "button",
1684
- {
1685
- type: "button",
1686
- onClick: () => onPickSuggestion?.(s.prompt),
1687
- className: "rounded-lg border border-border bg-background/60 px-3 py-2 text-left text-xs hover:bg-accent",
1688
- children: s.label
1689
- },
1690
- s.prompt
1691
- )) }) : null
1692
- ] });
1693
- }
1694
- __name(EmptyState, "EmptyState");
1695
- function ErrorBanner({ error, onDismiss, onRetry, className }) {
1696
- const styles = useChatDestructiveStyles();
1697
- if (!error) return null;
1698
- return /* @__PURE__ */ jsxs(
1699
- "div",
1700
- {
1701
- role: "alert",
1702
- className: cn(
1703
- "mx-2.5 my-2 flex items-start gap-2 rounded-md px-3 py-2 text-xs",
1704
- styles.banner,
1705
- className
1706
- ),
1707
- children: [
1708
- /* @__PURE__ */ jsx(AlertCircle, { "aria-hidden": true, className: "mt-0.5 size-3.5 shrink-0" }),
1709
- /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 break-words", children: error }),
1710
- onRetry ? /* @__PURE__ */ jsxs(
1711
- "button",
1712
- {
1713
- type: "button",
1714
- onClick: onRetry,
1715
- className: cn("inline-flex items-center gap-1 rounded px-1.5 py-0.5", styles.hover),
1716
- children: [
1717
- /* @__PURE__ */ jsx(RefreshCw, { "aria-hidden": true, className: "size-3" }),
1718
- " Retry"
1719
- ]
1720
- }
1721
- ) : null,
1722
- onDismiss ? /* @__PURE__ */ jsx(
1723
- "button",
1724
- {
1725
- type: "button",
1726
- "aria-label": "Dismiss",
1727
- onClick: onDismiss,
1728
- className: cn("rounded p-0.5", styles.hover),
1729
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": true, className: "size-3" })
1730
- }
1731
- ) : null
1732
- ]
1733
- }
1734
- );
1735
- }
1736
- __name(ErrorBanner, "ErrorBanner");
1737
- function JumpToLatest({ visible, unreadCount = 0, onClick, className }) {
1738
- if (!visible) return null;
1739
- return /* @__PURE__ */ jsxs(
1740
- "button",
1741
- {
1742
- type: "button",
1743
- onClick,
1744
- "aria-live": "polite",
1745
- className: cn(
1746
- "pointer-events-auto inline-flex items-center gap-1.5 rounded-full border border-border bg-background px-3 py-1 text-xs shadow-md hover:bg-accent",
1747
- className
1748
- ),
1749
- children: [
1750
- /* @__PURE__ */ jsx(ArrowDown, { "aria-hidden": true, className: "size-3.5" }),
1751
- unreadCount > 0 ? `${unreadCount} new` : "Jump to latest"
1752
- ]
1753
- }
1754
- );
1755
- }
1756
- __name(JumpToLatest, "JumpToLatest");
1757
-
1758
- // src/tools/Chat/core/persona.ts
1759
- var FALLBACK_USER = { name: "You", initials: "You" };
1760
- var FALLBACK_ASSISTANT = { name: "AI", initials: "AI" };
1761
- function resolvePersona(message, user, assistant) {
1762
- if (message.sender) return message.sender;
1763
- if (message.role === "user") return user ?? FALLBACK_USER;
1764
- if (message.role === "assistant") return assistant ?? FALLBACK_ASSISTANT;
1765
- return { name: message.role };
1766
- }
1767
- __name(resolvePersona, "resolvePersona");
1768
- function deriveInitials(persona, role) {
1769
- if (persona.initials) return persona.initials;
1770
- if (persona.name) {
1771
- const parts = persona.name.trim().split(/\s+/);
1772
- if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
1773
- return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
1774
- }
1775
- if (role === "user") return "You";
1776
- if (role === "assistant") return "AI";
1777
- return "?";
1778
- }
1779
- __name(deriveInitials, "deriveInitials");
1780
- function StreamingIndicatorRaw({ variant = "dots", label, className }) {
1781
- return /* @__PURE__ */ jsxs(
1782
- "span",
1783
- {
1784
- className: cn("inline-flex items-center gap-1.5 text-xs text-muted-foreground", className),
1785
- "aria-live": "off",
1786
- children: [
1787
- variant === "dots" ? /* @__PURE__ */ jsxs("span", { className: "inline-flex gap-0.5", "aria-hidden": true, children: [
1788
- /* @__PURE__ */ jsx("span", { className: "size-1 animate-bounce rounded-full bg-current [animation-delay:-0.2s]" }),
1789
- /* @__PURE__ */ jsx("span", { className: "size-1 animate-bounce rounded-full bg-current [animation-delay:-0.1s]" }),
1790
- /* @__PURE__ */ jsx("span", { className: "size-1 animate-bounce rounded-full bg-current" })
1791
- ] }) : /* @__PURE__ */ jsx("span", { className: "inline-block size-1.5 animate-pulse rounded-full bg-current", "aria-hidden": true }),
1792
- label ? /* @__PURE__ */ jsx("span", { className: "italic", children: label }) : null
1793
- ]
1794
- }
1795
- );
1796
- }
1797
- __name(StreamingIndicatorRaw, "StreamingIndicatorRaw");
1798
- var StreamingIndicator = memo(StreamingIndicatorRaw);
1799
- function Sources({ sources, layout = "inline", maxVisible, onClick, className }) {
1800
- if (!sources?.length) return null;
1801
- const visible = maxVisible ? sources.slice(0, maxVisible) : sources;
1802
- const remaining = maxVisible ? Math.max(0, sources.length - maxVisible) : 0;
1803
- return /* @__PURE__ */ jsxs(
1804
- "div",
1805
- {
1806
- className: cn(
1807
- "mt-2 flex flex-wrap gap-1.5",
1808
- layout === "grid" && "grid grid-cols-2",
1809
- className
1810
- ),
1811
- children: [
1812
- visible.map((s, i) => {
1813
- const handle = onClick ? () => onClick(s) : void 0;
1814
- const Tag = handle ? "button" : "a";
1815
- const props = handle ? { type: "button", onClick: handle } : { href: s.url, target: "_blank", rel: "noopener noreferrer" };
1816
- return /* @__PURE__ */ jsxs(
1817
- Tag,
1818
- {
1819
- ...props,
1820
- className: "inline-flex max-w-full items-center gap-1 rounded-md border border-border bg-background/60 px-2 py-1 text-xs text-foreground/80 hover:bg-accent hover:text-foreground",
1821
- title: s.snippet ?? s.title,
1822
- children: [
1823
- /* @__PURE__ */ jsx("span", { className: "truncate", children: s.title || s.url }),
1824
- /* @__PURE__ */ jsx(ExternalLink, { "aria-hidden": true, className: "size-3 shrink-0 opacity-60" })
1825
- ]
1826
- },
1827
- `${s.url}-${i}`
1828
- );
1829
- }),
1830
- remaining > 0 ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center rounded-md border border-dashed border-border px-2 py-1 text-xs text-muted-foreground", children: [
1831
- "+",
1832
- remaining
1833
- ] }) : null
1834
- ]
1835
- }
1836
- );
1837
- }
1838
- __name(Sources, "Sources");
1839
- function ToolCalls({
1840
- calls,
1841
- defaultExpanded = false,
1842
- expandWhileStreaming = true,
1843
- renderInput,
1844
- renderOutput,
1845
- renderStreaming,
1846
- renderPayload,
1847
- renderAfterCalls,
1848
- renderToolCall,
1849
- hideToolCalls = false,
1850
- className
1851
- }) {
1852
- if (!calls?.length) return null;
1853
- return /* @__PURE__ */ jsxs("div", { className: cn("mt-2 space-y-1.5", className), children: [
1854
- !hideToolCalls && calls.map(
1855
- (call) => renderToolCall ? /* @__PURE__ */ jsx("div", { children: renderToolCall(call) }, call.id) : /* @__PURE__ */ jsx(
1856
- ToolCallItem,
1857
- {
1858
- call,
1859
- defaultExpanded,
1860
- expandWhileStreaming,
1861
- renderInput,
1862
- renderOutput,
1863
- renderStreaming,
1864
- renderPayload
1865
- },
1866
- call.id
1867
- )
1868
- ),
1869
- renderAfterCalls ? renderAfterCalls(calls) : null
1870
- ] });
1871
- }
1872
- __name(ToolCalls, "ToolCalls");
1873
- var ToolCallItem = memo(/* @__PURE__ */ __name(function ToolCallItem2({
1874
- call,
1875
- defaultExpanded,
1876
- expandWhileStreaming,
1877
- renderInput,
1878
- renderOutput,
1879
- renderStreaming,
1880
- renderPayload
1881
- }) {
1882
- const isRunning = call.status === "running";
1883
- const initialOpen = defaultExpanded || expandWhileStreaming && isRunning;
1884
- const [open, setOpen] = useState(initialOpen);
1885
- const userToggledRef = useRef(false);
1886
- const wasRunningRef = useRef(isRunning);
1887
- useEffect(() => {
1888
- if (wasRunningRef.current && !isRunning) {
1889
- if (!userToggledRef.current && !defaultExpanded) {
1890
- setOpen(false);
1891
- }
1892
- }
1893
- wasRunningRef.current = isRunning;
1894
- }, [isRunning, defaultExpanded]);
1895
- const handleToggle = /* @__PURE__ */ __name(() => {
1896
- userToggledRef.current = true;
1897
- setOpen((v) => !v);
1898
- }, "handleToggle");
1899
- const Icon = open ? ChevronDown : ChevronRight;
1900
- const statusColor = call.status === "success" ? "text-emerald-500" : call.status === "error" ? "text-destructive" : call.status === "cancelled" ? "text-muted-foreground" : "text-amber-500";
1901
- const renderValue = /* @__PURE__ */ __name((value, kind) => {
1902
- if (kind === "input" && renderInput) return renderInput(value, call);
1903
- if (kind === "output" && renderOutput) return renderOutput(value, call);
1904
- if (kind === "streaming" && renderStreaming)
1905
- return renderStreaming(typeof value === "string" ? value : String(value), call);
1906
- if (renderPayload) return renderPayload(value, kind, call);
1907
- return /* @__PURE__ */ jsx(DefaultPayload, { value, kind });
1908
- }, "renderValue");
1909
- return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-md border border-border bg-muted/30", children: [
1910
- /* @__PURE__ */ jsxs(
1911
- "button",
1912
- {
1913
- type: "button",
1914
- onClick: handleToggle,
1915
- "aria-expanded": open,
1916
- className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-xs hover:bg-muted/60",
1917
- children: [
1918
- /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "size-3 shrink-0 text-muted-foreground" }),
1919
- isRunning ? /* @__PURE__ */ jsx(Loader2, { "aria-hidden": true, className: "size-3 shrink-0 animate-spin text-amber-500" }) : /* @__PURE__ */ jsx("span", { className: cn("size-2 shrink-0 rounded-full", statusColor.replace("text-", "bg-")) }),
1920
- /* @__PURE__ */ jsx("span", { className: "font-mono text-foreground", children: call.name }),
1921
- /* @__PURE__ */ jsx("span", { className: cn("ml-auto", statusColor), children: call.status })
1922
- ]
1923
- }
1924
- ),
1925
- open ? /* @__PURE__ */ jsxs("div", { className: "space-y-1 border-t border-border px-2 py-1.5 text-[11px]", children: [
1926
- call.input != null ? renderValue(call.input, "input") : null,
1927
- call.streamingText != null ? renderValue(call.streamingText, "streaming") : call.output !== void 0 ? renderValue(call.output, "output") : null
1928
- ] }) : null
1929
- ] });
1930
- }, "ToolCallItem"), (prev, next) => {
1931
- const a = prev.call;
1932
- const b = next.call;
1933
- return a.id === b.id && a.status === b.status && a.output === b.output && a.streamingText === b.streamingText && prev.defaultExpanded === next.defaultExpanded && prev.expandWhileStreaming === next.expandWhileStreaming && prev.renderInput === next.renderInput && prev.renderOutput === next.renderOutput && prev.renderStreaming === next.renderStreaming && prev.renderPayload === next.renderPayload;
1934
- });
1935
- function DefaultPayload({ value, kind }) {
1936
- const isStreamingOrString = kind === "streaming" || typeof value === "string";
1937
- const muted = kind === "input";
1938
- return /* @__PURE__ */ jsx(
1939
- "pre",
1940
- {
1941
- className: cn(
1942
- "overflow-auto rounded bg-background/60 p-1.5 font-mono",
1943
- kind === "input" ? "max-h-32" : "max-h-48",
1944
- muted ? "text-muted-foreground" : "text-foreground/90"
1945
- ),
1946
- children: isStreamingOrString ? String(value) : safeStringify(value)
1947
- }
1948
- );
1949
- }
1950
- __name(DefaultPayload, "DefaultPayload");
1951
- function safeStringify(value) {
1952
- try {
1953
- return JSON.stringify(value, null, 2);
1954
- } catch {
1955
- return String(value);
1956
- }
1957
- }
1958
- __name(safeStringify, "safeStringify");
1959
- function MessageActionsRaw({
1960
- role,
1961
- onCopy,
1962
- onRegenerate,
1963
- onEdit,
1964
- onDelete,
1965
- hideOn,
1966
- className
1967
- }) {
1968
- if (hideOn?.includes(role)) return null;
1969
- return /* @__PURE__ */ jsxs(
1970
- "div",
1971
- {
1972
- className: cn(
1973
- "mt-1 flex items-center gap-0.5 opacity-0 transition-opacity group-hover/msg:opacity-100 focus-within:opacity-100",
1974
- className
1975
- ),
1976
- children: [
1977
- onCopy ? /* @__PURE__ */ jsx(ActionButton, { onClick: onCopy, label: "Copy", icon: Copy }) : null,
1978
- onRegenerate && role === "assistant" ? /* @__PURE__ */ jsx(ActionButton, { onClick: onRegenerate, label: "Regenerate", icon: RefreshCw }) : null,
1979
- onEdit && role === "user" ? /* @__PURE__ */ jsx(ActionButton, { onClick: onEdit, label: "Edit", icon: Pencil }) : null,
1980
- onDelete ? /* @__PURE__ */ jsx(ActionButton, { onClick: onDelete, label: "Delete", icon: Trash, destructive: true }) : null
1981
- ]
1982
- }
1983
- );
1984
- }
1985
- __name(MessageActionsRaw, "MessageActionsRaw");
1986
- var ActionButton = memo(/* @__PURE__ */ __name(function ActionButton2({
1987
- onClick,
1988
- label,
1989
- icon: Icon,
1990
- destructive
1991
- }) {
1992
- const styles = useChatDestructiveStyles();
1993
- return /* @__PURE__ */ jsx(
1994
- "button",
1995
- {
1996
- type: "button",
1997
- onClick,
1998
- "aria-label": label,
1999
- className: cn(
2000
- "rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground",
2001
- destructive && cn(styles.hover, "hover:text-destructive")
2002
- ),
2003
- children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "size-3" })
2004
- }
2005
- );
2006
- }, "ActionButton"));
2007
- var MessageActions = memo(MessageActionsRaw);
2008
- var MessageBubbleInner = /* @__PURE__ */ __name(({
2009
- message,
2010
- isUser: isUserProp,
2011
- showAvatar = true,
2012
- avatarSrc,
2013
- avatarFallback,
2014
- user,
2015
- assistant,
2016
- showTimestamp = false,
2017
- showActions = true,
2018
- isCompact = false,
2019
- className,
2020
- beforeContent,
2021
- afterContent,
2022
- toolCallsRenderer,
2023
- toolCallsProps,
2024
- sourcesRenderer,
2025
- attachmentsRenderer,
2026
- attachmentRenderers,
2027
- onAttachmentOpen,
2028
- onCopy,
2029
- onRegenerate,
2030
- onEdit,
2031
- onDelete,
2032
- messageActionsExtra,
2033
- streamingIndicator
2034
- }) => {
2035
- const isUser = isUserProp ?? message.role === "user";
2036
- const isStreaming = !!message.isStreaming;
2037
- const isErr = !!message.isError;
2038
- const { surface: bubbleSurface } = useChatBubbleStyles(
2039
- isUser ? "user" : "assistant",
2040
- isErr
2041
- );
2042
- const ctx = useChatContextOptional();
2043
- const persona = resolvePersona(
2044
- message,
2045
- user ?? ctx?.config.user,
2046
- assistant ?? ctx?.config.assistant
2047
- );
2048
- const initials = deriveInitials(persona, message.role);
2049
- const personaName = persona.name ?? (isUser ? "You" : "Assistant");
2050
- return /* @__PURE__ */ jsxs(
2051
- "div",
2052
- {
2053
- role: "article",
2054
- "aria-label": `${personaName} said: ${message.content.slice(0, 80)}`,
2055
- "aria-busy": isStreaming || void 0,
2056
- "data-role": message.role,
2057
- className: cn(
2058
- "group/msg flex gap-2.5 px-2.5 py-2",
2059
- isUser ? "flex-row-reverse" : "flex-row",
2060
- className
2061
- ),
2062
- children: [
2063
- showAvatar ? /* @__PURE__ */ jsxs(
2064
- Avatar,
2065
- {
2066
- className: "size-7 shrink-0",
2067
- title: persona.description ?? personaName,
2068
- children: [
2069
- avatarSrc || persona.avatarUrl ? /* @__PURE__ */ jsx(AvatarImage, { src: avatarSrc ?? persona.avatarUrl, alt: personaName }) : null,
2070
- /* @__PURE__ */ jsx(AvatarFallback, { className: "text-[10px]", children: avatarFallback ?? initials })
2071
- ]
2072
- }
2073
- ) : null,
2074
- /* @__PURE__ */ jsxs("div", { className: cn("min-w-0 flex-1", isUser && "flex flex-col items-end"), children: [
2075
- beforeContent,
2076
- message.attachments?.length ? attachmentsRenderer ? attachmentsRenderer(message.attachments) : /* @__PURE__ */ jsx("div", { className: "mb-1.5 w-full", children: attachmentRenderers ? /* @__PURE__ */ jsx(
2077
- AttachmentsList,
2078
- {
2079
- attachments: message.attachments,
2080
- renderers: attachmentRenderers,
2081
- onClick: onAttachmentOpen,
2082
- className: isUser ? "items-end" : void 0
2083
- }
2084
- ) : /* @__PURE__ */ jsx(
2085
- AttachmentsGrid,
2086
- {
2087
- attachments: message.attachments,
2088
- onClick: onAttachmentOpen,
2089
- className: isUser ? "justify-end" : void 0
2090
- }
2091
- ) }) : null,
2092
- /* @__PURE__ */ jsxs(
2093
- "div",
2094
- {
2095
- className: cn(
2096
- "inline-block max-w-full rounded-2xl px-3.5 py-2 text-sm",
2097
- bubbleSurface
2098
- ),
2099
- children: [
2100
- isStreaming && message.toolActivity ? /* @__PURE__ */ jsx("div", { className: "mb-1.5", children: streamingIndicator ? streamingIndicator(message) : /* @__PURE__ */ jsx(StreamingIndicator, { label: message.toolActivity }) }) : null,
2101
- message.content || !isStreaming ? /* @__PURE__ */ jsx(
2102
- MarkdownMessage,
2103
- {
2104
- content: message.content || (isErr ? "*Failed to generate a response.*" : ""),
2105
- isUser,
2106
- isCompact,
2107
- plainText: isStreaming
2108
- }
2109
- ) : streamingIndicator ? streamingIndicator(message) : /* @__PURE__ */ jsx(StreamingIndicator, {})
2110
- ]
2111
- }
2112
- ),
2113
- message.toolCalls?.length ? toolCallsRenderer ? toolCallsRenderer(message.toolCalls) : /* @__PURE__ */ jsx(ToolCalls, { calls: message.toolCalls, ...toolCallsProps }) : null,
2114
- message.sources?.length && !isStreaming ? sourcesRenderer ? sourcesRenderer(message.sources) : /* @__PURE__ */ jsx(Sources, { sources: message.sources }) : null,
2115
- showActions && !isStreaming ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
2116
- /* @__PURE__ */ jsx(
2117
- MessageActions,
2118
- {
2119
- role: message.role,
2120
- onCopy,
2121
- onRegenerate,
2122
- onEdit,
2123
- onDelete
2124
- }
2125
- ),
2126
- messageActionsExtra ? messageActionsExtra(message) : null
2127
- ] }) : null,
2128
- showTimestamp ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-[10px] text-muted-foreground", children: new Date(message.createdAt).toLocaleTimeString() }) : null,
2129
- afterContent
2130
- ] })
2131
- ]
2132
- }
2133
- );
2134
- }, "MessageBubbleInner");
2135
- var MessageBubble = memo(MessageBubbleInner, (prev, next) => {
2136
- const a = prev.message;
2137
- const b = next.message;
2138
- return a.id === b.id && a.content === b.content && a.isStreaming === b.isStreaming && a.isError === b.isError && (a.version ?? 0) === (b.version ?? 0) && a.toolActivity === b.toolActivity && a.toolCalls === b.toolCalls && a.sources === b.sources && a.attachments === b.attachments;
2139
- });
2140
- MessageBubble.displayName = "MessageBubble";
2141
- var MessageList = forwardRef(/* @__PURE__ */ __name(function MessageList2({
2142
- messages: messagesProp,
2143
- renderItem,
2144
- renderEmpty,
2145
- isLoadingMore: isLoadingMoreProp,
2146
- onStartReached,
2147
- className,
2148
- itemClassName,
2149
- noVirtualize = false,
2150
- defaultItemHeight: _deprecatedDefaultItemHeight,
2151
- onAtBottomChange,
2152
- atBottomThreshold = 120,
2153
- scrollAnchorId
2154
- }, ref) {
2155
- const ctx = useChatContextOptional();
2156
- const messages = messagesProp ?? ctx?.messages ?? [];
2157
- const isLoadingMore = isLoadingMoreProp ?? ctx?.isLoadingMore ?? false;
2158
- const { copyToClipboard } = useCopy();
2159
- const virtuosoRef = useRef(null);
2160
- const scrollerRef = useRef(null);
2161
- const [isScrollable, setIsScrollable] = useState(false);
2162
- const lastReportedAtBottomRef = useRef(null);
2163
- const reportAtBottom = useCallback(
2164
- (value) => {
2165
- if (lastReportedAtBottomRef.current === value) return;
2166
- lastReportedAtBottomRef.current = value;
2167
- onAtBottomChange?.(value);
2168
- },
2169
- [onAtBottomChange]
2170
- );
2171
- const didInitialScrollRef = useRef(false);
2172
- useImperativeHandle(
2173
- ref,
2174
- () => ({
2175
- scrollToBottom: /* @__PURE__ */ __name((smooth = false) => {
2176
- virtuosoRef.current?.scrollToIndex({
2177
- index: "LAST",
2178
- behavior: smooth ? "smooth" : "auto",
2179
- align: "end"
2180
- });
2181
- }, "scrollToBottom"),
2182
- scrollToIndex: /* @__PURE__ */ __name((index, smooth = false) => {
2183
- virtuosoRef.current?.scrollToIndex({
2184
- index,
2185
- behavior: smooth ? "smooth" : "auto"
2186
- });
2187
- }, "scrollToIndex")
2188
- }),
2189
- []
2190
- );
2191
- const defaultRenderItem = useCallback(
2192
- (m) => /* @__PURE__ */ jsx("div", { className: itemClassName, children: /* @__PURE__ */ jsx(
2193
- MessageBubble,
2194
- {
2195
- message: m,
2196
- onCopy: () => void copyToClipboard(m.content),
2197
- onRegenerate: ctx ? () => void ctx.regenerate(m.id) : void 0,
2198
- onDelete: ctx ? () => ctx.deleteMessage(m.id) : void 0
2199
- }
2200
- ) }),
2201
- [itemClassName, ctx, copyToClipboard]
2202
- );
2203
- const itemRenderer = renderItem ?? defaultRenderItem;
2204
- useEffect(() => {
2205
- if (didInitialScrollRef.current) return;
2206
- if (messages.length === 0) return;
2207
- didInitialScrollRef.current = true;
2208
- const id = requestAnimationFrame(() => {
2209
- virtuosoRef.current?.scrollToIndex({
2210
- index: "LAST",
2211
- align: "end",
2212
- behavior: "auto"
2213
- });
2214
- });
2215
- return () => cancelAnimationFrame(id);
2216
- }, [messages.length]);
2217
- useEffect(() => {
2218
- if (scrollAnchorId == null) return;
2219
- if (!didInitialScrollRef.current) return;
2220
- let raf1 = 0;
2221
- let raf2 = 0;
2222
- raf1 = requestAnimationFrame(() => {
2223
- raf2 = requestAnimationFrame(() => {
2224
- virtuosoRef.current?.scrollToIndex({
2225
- index: "LAST",
2226
- align: "end",
2227
- behavior: "smooth"
2228
- });
2229
- });
2230
- });
2231
- return () => {
2232
- cancelAnimationFrame(raf1);
2233
- cancelAnimationFrame(raf2);
2234
- };
2235
- }, [scrollAnchorId]);
2236
- useEffect(() => {
2237
- const el = scrollerRef.current;
2238
- if (!el || el === window || !(el instanceof HTMLElement)) return;
2239
- const probe = /* @__PURE__ */ __name(() => {
2240
- const scrollable = el.scrollHeight > el.clientHeight + 1;
2241
- setIsScrollable(scrollable);
2242
- if (!scrollable) reportAtBottom(true);
2243
- }, "probe");
2244
- probe();
2245
- const ro = new ResizeObserver(probe);
2246
- ro.observe(el);
2247
- return () => ro.disconnect();
2248
- }, [reportAtBottom, messages.length]);
2249
- const computeItemKey = useCallback(
2250
- (index, m) => m?.id ?? index,
2251
- []
2252
- );
2253
- const startReachedHandler = useMemo(() => {
2254
- if (!onStartReached) return void 0;
2255
- let inFlight = false;
2256
- return () => {
2257
- if (inFlight || isLoadingMore) return;
2258
- inFlight = true;
2259
- try {
2260
- onStartReached();
2261
- } finally {
2262
- queueMicrotask(() => {
2263
- inFlight = false;
2264
- });
2265
- }
2266
- };
2267
- }, [onStartReached, isLoadingMore]);
2268
- if (messages.length === 0) {
2269
- return /* @__PURE__ */ jsx(
2270
- "div",
2271
- {
2272
- role: "log",
2273
- "aria-live": "polite",
2274
- "aria-atomic": "false",
2275
- className: cn("flex-1 overflow-y-auto", className),
2276
- children: renderEmpty?.() ?? null
2277
- }
2278
- );
2279
- }
2280
- if (noVirtualize) {
2281
- return /* @__PURE__ */ jsxs(
2282
- "div",
2283
- {
2284
- role: "log",
2285
- "aria-live": "polite",
2286
- "aria-atomic": "false",
2287
- className: cn("flex-1 overflow-y-auto", className),
2288
- children: [
2289
- isLoadingMore ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ jsx(Spinner, { className: "size-4 text-muted-foreground" }) }) : null,
2290
- messages.map((m, i) => /* @__PURE__ */ jsx("div", { children: itemRenderer(m, i) }, m.id ?? i))
2291
- ]
2292
- }
2293
- );
2294
- }
2295
- return /* @__PURE__ */ jsx(
2296
- Virtuoso,
2297
- {
2298
- ref: virtuosoRef,
2299
- role: "log",
2300
- "aria-live": "polite",
2301
- "aria-atomic": "false",
2302
- className: cn("flex-1", className),
2303
- data: messages,
2304
- computeItemKey,
2305
- itemContent: (index, m) => m ? itemRenderer(m, index) : null,
2306
- initialTopMostItemIndex: messages.length > 0 ? messages.length - 1 : 0,
2307
- atBottomThreshold,
2308
- followOutput: (isAtBottom) => isAtBottom ? "auto" : false,
2309
- scrollerRef: (el) => {
2310
- scrollerRef.current = el;
2311
- },
2312
- atBottomStateChange: (atBottom) => {
2313
- reportAtBottom(!isScrollable ? true : atBottom);
2314
- },
2315
- startReached: startReachedHandler,
2316
- components: isLoadingMore ? {
2317
- Header: /* @__PURE__ */ __name(() => /* @__PURE__ */ jsx("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ jsx(Spinner, { className: "size-4 text-muted-foreground" }) }), "Header")
2318
- } : EMPTY_COMPONENTS
2319
- }
2320
- );
2321
- }, "MessageList"));
2322
- var EMPTY_COMPONENTS = {};
2323
- function ChatRoot(props) {
2324
- const { transport, config, initialSessionId, autoCreateSession, streaming, audio, debug, className, listClassName, ...slots } = props;
2325
- return /* @__PURE__ */ jsx(
2326
- ChatProvider,
2327
- {
2328
- transport,
2329
- config,
2330
- initialSessionId,
2331
- autoCreateSession,
2332
- streaming,
2333
- audio,
2334
- debug,
2335
- children: /* @__PURE__ */ jsx(ChatRootShell, { className, listClassName, slots })
2336
- }
2337
- );
2338
- }
2339
- __name(ChatRoot, "ChatRoot");
2340
- function ChatRootShell({ className, listClassName, slots }) {
2341
- const chat = useChatContext();
2342
- const composer = useChatComposer({
2343
- onSubmit: /* @__PURE__ */ __name((content, attachments) => chat.sendMessage(content, attachments), "onSubmit"),
2344
- disabled: chat.isStreaming
2345
- });
2346
- const onMessagesMouseUp = useFocusOnEmptyClick({
2347
- enabled: slots.focusOnEmptyClick !== false
2348
- });
2349
- useAutoFocusOnStreamEnd();
2350
- const listRef = useRef(null);
2351
- const [isAtBottom, setIsAtBottom] = useState(true);
2352
- const lastUserMessageId = useMemo(() => {
2353
- const msgs = chat.messages;
2354
- for (let i = msgs.length - 1; i >= 0; i -= 1) {
2355
- if (msgs[i].role === "user") return msgs[i].id;
2356
- }
2357
- return null;
2358
- }, [chat.messages]);
2359
- const handleStartReached = chat.hasMore && !chat.isLoadingMore ? () => void chat.loadMore() : void 0;
2360
- const greeting = chat.config.greeting ?? "How can I help?";
2361
- const description = chat.config.description;
2362
- const suggestions = chat.config.suggestions;
2363
- const headerNode = slots.renderHeader ? slots.renderHeader(chat) : slots.header;
2364
- const emptyNode = slots.empty ?? (slots.renderEmpty ? slots.renderEmpty({ setValue: composer.setValue, focus: composer.focus }) : /* @__PURE__ */ jsx(
2365
- EmptyState,
2366
- {
2367
- greeting,
2368
- description,
2369
- suggestions,
2370
- onPickSuggestion: (prompt) => {
2371
- composer.setValue(prompt);
2372
- composer.focus();
2373
- }
2374
- }
2375
- ));
2376
- const renderItem = slots.renderMessage ?? ((m) => /* @__PURE__ */ jsx(
2377
- MessageBubble,
2378
- {
2379
- message: m,
2380
- toolCallsProps: slots.toolCallsProps,
2381
- attachmentRenderers: slots.attachmentRenderers,
2382
- onAttachmentOpen: slots.onAttachmentOpen,
2383
- onCopy: () => copy(m.content),
2384
- onRegenerate: () => void chat.regenerate(m.id),
2385
- onDelete: () => chat.deleteMessage(m.id)
2386
- },
2387
- m.id
2388
- ));
2389
- return /* @__PURE__ */ jsxs("div", { className: cn("relative flex h-full min-h-0 flex-col overflow-hidden", className), children: [
2390
- slots.banner ?? null,
2391
- headerNode ?? null,
2392
- /* @__PURE__ */ jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", onMouseUp: onMessagesMouseUp, children: [
2393
- /* @__PURE__ */ jsx(
2394
- ErrorBanner,
2395
- {
2396
- error: chat.error,
2397
- onDismiss: chat.error ? () => chat.clearMessages() : void 0,
2398
- onRetry: chat.error ? () => void chat.regenerate() : void 0
2399
- }
2400
- ),
2401
- /* @__PURE__ */ jsx(
2402
- MessageList,
2403
- {
2404
- ref: listRef,
2405
- renderItem,
2406
- renderEmpty: () => /* @__PURE__ */ jsx(Fragment, { children: emptyNode }),
2407
- className: listClassName,
2408
- onStartReached: handleStartReached,
2409
- onAtBottomChange: setIsAtBottom,
2410
- scrollAnchorId: lastUserMessageId
2411
- }
2412
- ),
2413
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-2 flex justify-center", children: slots.jumpToLatest ?? /* @__PURE__ */ jsx(
2414
- JumpToLatest,
2415
- {
2416
- visible: !isAtBottom,
2417
- onClick: () => listRef.current?.scrollToBottom(true)
2418
- }
2419
- ) })
2420
- ] }),
2421
- !slots.hideComposer && /* @__PURE__ */ jsx(
2422
- Composer,
2423
- {
2424
- composer,
2425
- placeholder: chat.config.placeholder,
2426
- showAttachmentButton: slots.showAttachmentButton,
2427
- onPickFiles: slots.onPickFiles,
2428
- toolbarStart: slots.composerToolbarStart,
2429
- toolbarEnd: slots.composerToolbarEnd,
2430
- attachmentTray: slots.composerAttachmentTray,
2431
- size: slots.composerSize
2432
- }
2433
- ),
2434
- slots.footer ?? null
2435
- ] });
2436
- }
2437
- __name(ChatRootShell, "ChatRootShell");
2438
- function copy(text) {
2439
- if (typeof navigator !== "undefined" && navigator.clipboard) {
2440
- void navigator.clipboard.writeText(text);
2441
- }
2442
- }
2443
- __name(copy, "copy");
2444
1110
 
2445
- export { Attachments, AttachmentsGrid, AttachmentsList, CHAT_EVENT_NAME, CSS_VARS, ChatProvider, ChatRoot, Composer, DEFAULT_CHAT_SOUNDS, DEFAULT_LABELS, DEFAULT_SIDEBAR, DEFAULT_Z_INDEX, EmptyState, ErrorBanner, HOTKEYS, JumpToLatest, LIMITS, MessageActions, MessageBubble, MessageList, STORAGE_KEYS, Sources, StreamingIndicator, ToolCalls, createId, createTokenBuffer, deriveInitials, getChatLogger, initialState, isSubmittableDraft, reducer, resolvePersona, sanitizeDraft, useAutoFocusOnStreamEnd, useChat, useChatAudio, useChatBubbleStyles, useChatComposer, useChatContext, useChatContextOptional, useChatDestructiveStyles, useChatLayout, useChatRoleStyles, useFocusOnEmptyClick, useRegisterComposer };
2446
- //# sourceMappingURL=chunk-PEKBT75W.mjs.map
2447
- //# sourceMappingURL=chunk-PEKBT75W.mjs.map
1111
+ export { CHAT_EVENT_NAME, CSS_VARS, ChatProvider, DEFAULT_CHAT_SOUNDS, DEFAULT_LABELS, DEFAULT_SIDEBAR, DEFAULT_Z_INDEX, HOTKEYS, LIMITS, STORAGE_KEYS, createId, createTokenBuffer, getChatLogger, initialState, reducer, useChat, useChatAudio, useChatContext, useChatContextOptional, useChatLayout };
1112
+ //# sourceMappingURL=chunk-DMX7W4XZ.mjs.map
1113
+ //# sourceMappingURL=chunk-DMX7W4XZ.mjs.map