@djangocfg/ui-tools 2.1.384 → 2.1.387

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