@sarchauhan/chat 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,4386 @@
1
+ "use client";
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ ArtifactWidget: () => ArtifactWidget,
35
+ ArtifactsWidget: () => ArtifactsWidget,
36
+ BaseWidget: () => BaseWidget,
37
+ Chat: () => Chat,
38
+ ChatComposer: () => ChatComposer,
39
+ ChatContextProvider: () => ChatContextProvider,
40
+ LoadingState: () => LoadingState,
41
+ Message: () => Message,
42
+ MessageContent: () => MessageContent,
43
+ MessageFeedback: () => MessageFeedback,
44
+ MessageUsage: () => MessageUsage,
45
+ PatchWidget: () => PatchWidget,
46
+ ProviderId: () => ProviderId,
47
+ QuestionWidget: () => QuestionWidget,
48
+ ReadFileWidget: () => ReadFileWidget,
49
+ ResponsiveDetail: () => ResponsiveDetail,
50
+ SearchWidget: () => SearchWidget,
51
+ SubagentWidget: () => SubagentWidget,
52
+ TextSwap: () => TextSwap,
53
+ ThemeProvider: () => ThemeProvider,
54
+ ThemeToggle: () => ThemeToggle,
55
+ ThinkingBlock: () => ThinkingBlock,
56
+ WidgetProvider: () => WidgetProvider,
57
+ WidgetRenderer: () => WidgetRenderer,
58
+ applyAgentEvent: () => import_protocol7.applyAgentEvent,
59
+ calibrateCheckPath: () => calibrateCheckPath,
60
+ clearErrorShake: () => clearErrorShake,
61
+ closeDropdown: () => closeDropdown,
62
+ computeDiff: () => computeDiff,
63
+ computeTextDiff: () => computeTextDiff,
64
+ computeToolState: () => computeToolState,
65
+ computeToolWidget: () => computeToolWidget,
66
+ createAgentMessageState: () => import_protocol7.createAgentMessageState,
67
+ createArtifactData: () => import_protocol6.createArtifactData,
68
+ createSubagentData: () => import_protocol6.createSubagentData,
69
+ createWidgetData: () => import_protocol7.createWidgetData,
70
+ createWidgetRegistry: () => createWidgetRegistry,
71
+ defineAdapter: () => import_adapter.defineAdapter,
72
+ defineWidget: () => defineWidget,
73
+ dropdownOrigins: () => dropdownOrigins,
74
+ formatArtifactSize: () => formatArtifactSize,
75
+ formatElapsed: () => formatElapsed,
76
+ formatElapsedWords: () => formatElapsedWords,
77
+ iconSwapStates: () => iconSwapStates,
78
+ isProviderId: () => isProviderId,
79
+ motion: () => motion,
80
+ motionData: () => motionData,
81
+ motionRoot: () => motionRoot,
82
+ normalizeAgentMessage: () => import_protocol7.normalizeAgentMessage,
83
+ normalizeAgentParts: () => import_protocol7.normalizeAgentParts,
84
+ normalizeSearchResults: () => normalizeSearchResults,
85
+ openDropdown: () => openDropdown,
86
+ parseArtifact: () => import_protocol6.parseArtifact,
87
+ parseRegistryConfig: () => parseRegistryConfig,
88
+ parseSubagent: () => import_protocol6.parseSubagent,
89
+ prebuiltWidgets: () => prebuiltWidgets,
90
+ prefersReducedMotion: () => prefersReducedMotion,
91
+ readDurationMs: () => readDurationMs,
92
+ reduceAgentEvents: () => import_protocol7.reduceAgentEvents,
93
+ safeArtifactUrl: () => safeArtifactUrl,
94
+ safeResultUrl: () => safeResultUrl,
95
+ successCheckStates: () => successCheckStates,
96
+ swapText: () => swapText,
97
+ triggerErrorShake: () => triggerErrorShake,
98
+ useChat: () => useChat,
99
+ useComposer: () => useComposer,
100
+ useDropdownPresence: () => useDropdownPresence,
101
+ useMessages: () => useMessages,
102
+ useModel: () => useModel,
103
+ useTheme: () => useTheme,
104
+ useThread: () => useThread,
105
+ useWidgets: () => useWidgets
106
+ });
107
+ module.exports = __toCommonJS(src_exports);
108
+
109
+ // src/components/Chat.tsx
110
+ var import_lucide_react19 = require("lucide-react");
111
+ var import_react30 = require("react");
112
+
113
+ // src/theme/theme.context.tsx
114
+ var import_react = require("react");
115
+ var import_jsx_runtime = require("react/jsx-runtime");
116
+ var ThemeContext = (0, import_react.createContext)(null);
117
+ var STORAGE_KEY = "sarchauhan-chat-theme";
118
+ var getSystemTheme = () => {
119
+ if (typeof window === "undefined" || !window.matchMedia) {
120
+ return "light";
121
+ }
122
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
123
+ };
124
+ var resolveTheme = (theme) => theme === "system" ? getSystemTheme() : theme;
125
+ function ThemeProvider({
126
+ children,
127
+ defaultTheme = "system",
128
+ theme: controlledTheme,
129
+ onThemeChange,
130
+ storageKey = STORAGE_KEY
131
+ }) {
132
+ const [uncontrolledTheme, setUncontrolledTheme] = (0, import_react.useState)(defaultTheme);
133
+ const theme = controlledTheme != null ? controlledTheme : uncontrolledTheme;
134
+ const [resolvedTheme, setResolvedTheme] = (0, import_react.useState)(
135
+ theme === "dark" ? "dark" : "light"
136
+ );
137
+ (0, import_react.useEffect)(() => {
138
+ if (controlledTheme !== void 0) {
139
+ return;
140
+ }
141
+ const stored = window.localStorage.getItem(storageKey);
142
+ if (stored === "light" || stored === "dark" || stored === "system") {
143
+ setUncontrolledTheme(stored);
144
+ }
145
+ }, [controlledTheme, storageKey]);
146
+ (0, import_react.useEffect)(() => {
147
+ setResolvedTheme(resolveTheme(theme));
148
+ if (theme !== "system" || typeof window === "undefined") {
149
+ return;
150
+ }
151
+ const media = window.matchMedia("(prefers-color-scheme: dark)");
152
+ const onChange = () => setResolvedTheme(getSystemTheme());
153
+ media.addEventListener("change", onChange);
154
+ return () => media.removeEventListener("change", onChange);
155
+ }, [theme]);
156
+ const setTheme = (0, import_react.useCallback)(
157
+ (next) => {
158
+ onThemeChange == null ? void 0 : onThemeChange(next);
159
+ if (controlledTheme === void 0) {
160
+ setUncontrolledTheme(next);
161
+ if (typeof window !== "undefined") {
162
+ window.localStorage.setItem(storageKey, next);
163
+ }
164
+ }
165
+ },
166
+ [controlledTheme, onThemeChange, storageKey]
167
+ );
168
+ const toggleTheme = (0, import_react.useCallback)(() => {
169
+ const next = resolvedTheme === "dark" ? "light" : "dark";
170
+ setTheme(next);
171
+ }, [resolvedTheme, setTheme]);
172
+ const value = (0, import_react.useMemo)(
173
+ () => ({
174
+ theme,
175
+ resolvedTheme,
176
+ setTheme,
177
+ toggleTheme
178
+ }),
179
+ [resolvedTheme, setTheme, theme, toggleTheme]
180
+ );
181
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value, children });
182
+ }
183
+ function useTheme() {
184
+ const context = (0, import_react.useContext)(ThemeContext);
185
+ if (!context) {
186
+ throw new Error("useTheme must be used inside ThemeProvider");
187
+ }
188
+ return context;
189
+ }
190
+
191
+ // src/theme/theme.toggle.tsx
192
+ var import_lucide_react = require("lucide-react");
193
+ var import_jsx_runtime2 = require("react/jsx-runtime");
194
+ function ThemeToggle({ className }) {
195
+ const { resolvedTheme, toggleTheme } = useTheme();
196
+ const isDark = resolvedTheme === "dark";
197
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
198
+ "button",
199
+ {
200
+ type: "button",
201
+ className: ["chat-theme-toggle", className].filter(Boolean).join(" "),
202
+ onClick: toggleTheme,
203
+ "aria-label": isDark ? "Switch to light theme" : "Switch to dark theme",
204
+ title: isDark ? "Light mode" : "Dark mode",
205
+ children: isDark ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Sun, { size: 16, strokeWidth: 1.75 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Moon, { size: 16, strokeWidth: 1.75 })
206
+ }
207
+ );
208
+ }
209
+
210
+ // src/components/Chat/chat.tsx
211
+ var import_lucide_react7 = require("lucide-react");
212
+ var import_react13 = require("react");
213
+
214
+ // src/lib/utils.ts
215
+ var import_clsx = require("clsx");
216
+ var import_tailwind_merge = require("tailwind-merge");
217
+ function cn(...inputs) {
218
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
219
+ }
220
+
221
+ // src/motion/classes.ts
222
+ var motion = {
223
+ textSwap: "t-text-swap",
224
+ isExit: "is-exit",
225
+ isEnterStart: "is-enter-start",
226
+ iconSwap: "t-icon-swap",
227
+ icon: "t-icon",
228
+ successCheck: "t-success-check",
229
+ dropdown: "t-dropdown",
230
+ isOpen: "is-open",
231
+ isClosing: "is-closing",
232
+ inputWrap: "t-input-wrap",
233
+ input: "t-input",
234
+ errorMsg: "t-error-msg",
235
+ isError: "is-error",
236
+ isShaking: "is-shaking"
237
+ };
238
+ var iconSwapStates = ["a", "b"];
239
+ var successCheckStates = ["out", "in"];
240
+ var dropdownOrigins = [
241
+ "top-left",
242
+ "top-center",
243
+ "top-right",
244
+ "bottom-left",
245
+ "bottom-center",
246
+ "bottom-right"
247
+ ];
248
+ var motionData = {
249
+ state: "data-state",
250
+ icon: "data-icon",
251
+ origin: "data-origin",
252
+ open: "data-open"
253
+ };
254
+
255
+ // src/motion/helpers.ts
256
+ var CHAT_ROOT = ".chat-root";
257
+ var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
258
+ var motionRoot = (node) => {
259
+ var _a;
260
+ return (_a = node == null ? void 0 : node.closest(CHAT_ROOT)) != null ? _a : typeof document !== "undefined" ? document.querySelector(CHAT_ROOT) : null;
261
+ };
262
+ var readRaw = (name, node) => {
263
+ const root = motionRoot(node);
264
+ if (!root) {
265
+ return "";
266
+ }
267
+ return getComputedStyle(root).getPropertyValue(name);
268
+ };
269
+ var readDurationMs = (name, fallback, node) => {
270
+ const value = parseFloat(readRaw(name, node));
271
+ return Number.isFinite(value) ? value : fallback;
272
+ };
273
+ var revertTimers = /* @__PURE__ */ new WeakMap();
274
+ var shakeTimers = /* @__PURE__ */ new WeakMap();
275
+ var swapText = (el, next, options) => {
276
+ var _a;
277
+ if (prefersReducedMotion()) {
278
+ el.textContent = next;
279
+ (_a = options == null ? void 0 : options.onSwap) == null ? void 0 : _a.call(options);
280
+ return;
281
+ }
282
+ const dur = readDurationMs("--text-swap-dur", 200, el);
283
+ el.classList.add(motion.isExit);
284
+ return window.setTimeout(() => {
285
+ var _a2;
286
+ el.classList.remove(motion.isExit);
287
+ el.classList.add(motion.isEnterStart);
288
+ el.textContent = next;
289
+ (_a2 = options == null ? void 0 : options.onSwap) == null ? void 0 : _a2.call(options);
290
+ void el.offsetHeight;
291
+ el.classList.remove(motion.isEnterStart);
292
+ }, dur);
293
+ };
294
+ var openDropdown = (el) => {
295
+ el.classList.remove(motion.isClosing);
296
+ el.classList.add(motion.isOpen);
297
+ };
298
+ var closeDropdown = (el, onClosed) => {
299
+ el.classList.remove(motion.isOpen);
300
+ el.classList.add(motion.isClosing);
301
+ const closeMs = prefersReducedMotion() ? 0 : readDurationMs("--dropdown-close-dur", 150, el);
302
+ return window.setTimeout(() => {
303
+ el.classList.remove(motion.isClosing);
304
+ onClosed == null ? void 0 : onClosed();
305
+ }, closeMs);
306
+ };
307
+ var triggerErrorShake = (wrap, options) => {
308
+ var _a;
309
+ const input = wrap.matches(`.${motion.input}`) ? wrap : (_a = wrap.querySelector(`.${motion.input}`)) != null ? _a : wrap;
310
+ wrap.classList.add(motion.isError);
311
+ input.classList.add(motion.isError);
312
+ input.classList.remove(motion.isShaking);
313
+ void input.offsetWidth;
314
+ input.classList.add(motion.isShaking);
315
+ const existingShake = shakeTimers.get(input);
316
+ if (existingShake) {
317
+ window.clearTimeout(existingShake);
318
+ }
319
+ const shakeMs = readDurationMs("--shake-dur-a", 80, wrap) * 2 + readDurationMs("--shake-dur-b", 60, wrap) * 2;
320
+ shakeTimers.set(
321
+ input,
322
+ window.setTimeout(() => {
323
+ input.classList.remove(motion.isShaking);
324
+ shakeTimers.delete(input);
325
+ }, shakeMs + 20)
326
+ );
327
+ const existingRevert = revertTimers.get(wrap);
328
+ if (existingRevert) {
329
+ window.clearTimeout(existingRevert);
330
+ revertTimers.delete(wrap);
331
+ }
332
+ if ((options == null ? void 0 : options.revert) === false) {
333
+ return;
334
+ }
335
+ const hold = readDurationMs("--revert-hold", 3e3, wrap);
336
+ revertTimers.set(
337
+ wrap,
338
+ window.setTimeout(() => {
339
+ revertTimers.delete(wrap);
340
+ wrap.classList.remove(motion.isError);
341
+ input.classList.remove(motion.isError);
342
+ }, shakeMs + hold)
343
+ );
344
+ };
345
+ var clearErrorShake = (wrap) => {
346
+ var _a;
347
+ const input = wrap.matches(`.${motion.input}`) ? wrap : (_a = wrap.querySelector(`.${motion.input}`)) != null ? _a : wrap;
348
+ const existingRevert = revertTimers.get(wrap);
349
+ if (existingRevert) {
350
+ window.clearTimeout(existingRevert);
351
+ revertTimers.delete(wrap);
352
+ }
353
+ const existingShake = shakeTimers.get(input);
354
+ if (existingShake) {
355
+ window.clearTimeout(existingShake);
356
+ shakeTimers.delete(input);
357
+ }
358
+ wrap.classList.remove(motion.isError);
359
+ input.classList.remove(motion.isError, motion.isShaking);
360
+ };
361
+ var calibrateCheckPath = (path) => {
362
+ const len = Math.ceil(path.getTotalLength());
363
+ path.style.strokeDasharray = String(len);
364
+ path.style.strokeDashoffset = String(len);
365
+ };
366
+
367
+ // src/motion/text-swap.tsx
368
+ var import_react2 = require("react");
369
+ var import_jsx_runtime3 = require("react/jsx-runtime");
370
+ function TextSwap({ text, className, ...props }) {
371
+ const ref = (0, import_react2.useRef)(null);
372
+ const shownRef = (0, import_react2.useRef)(text);
373
+ (0, import_react2.useEffect)(() => {
374
+ const el = ref.current;
375
+ if (!el || shownRef.current === text) {
376
+ return;
377
+ }
378
+ if (prefersReducedMotion()) {
379
+ shownRef.current = text;
380
+ el.textContent = text;
381
+ return;
382
+ }
383
+ const dur = readDurationMs("--text-swap-dur", 200, el);
384
+ el.classList.add(motion.isExit);
385
+ const timer = window.setTimeout(() => {
386
+ el.classList.remove(motion.isExit);
387
+ el.classList.add(motion.isEnterStart);
388
+ el.textContent = text;
389
+ shownRef.current = text;
390
+ void el.offsetHeight;
391
+ el.classList.remove(motion.isEnterStart);
392
+ }, dur);
393
+ return () => window.clearTimeout(timer);
394
+ }, [text]);
395
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { ref, className: cn(motion.textSwap, className), ...props, children: shownRef.current });
396
+ }
397
+
398
+ // src/motion/use-dropdown-presence.ts
399
+ var import_react3 = require("react");
400
+ var resolveRoot = (root) => root && "current" in root ? root.current : root != null ? root : null;
401
+ function useDropdownPresence(open, root) {
402
+ const [mounted, setMounted] = (0, import_react3.useState)(open);
403
+ const [phase, setPhase] = (0, import_react3.useState)(open ? "open" : "rest");
404
+ const mountedRef = (0, import_react3.useRef)(open);
405
+ mountedRef.current = mounted;
406
+ (0, import_react3.useEffect)(() => {
407
+ const node = resolveRoot(root);
408
+ if (open) {
409
+ setMounted(true);
410
+ setPhase("rest");
411
+ const frame = window.requestAnimationFrame(() => {
412
+ window.requestAnimationFrame(() => setPhase("open"));
413
+ });
414
+ return () => window.cancelAnimationFrame(frame);
415
+ }
416
+ if (!mountedRef.current) {
417
+ return;
418
+ }
419
+ setPhase("closing");
420
+ const closeMs = prefersReducedMotion() ? 0 : readDurationMs("--dropdown-close-dur", 150, node);
421
+ const timer = window.setTimeout(() => {
422
+ setMounted(false);
423
+ setPhase("rest");
424
+ }, closeMs);
425
+ return () => window.clearTimeout(timer);
426
+ }, [open, root]);
427
+ const className = phase === "open" ? motion.isOpen : phase === "closing" ? motion.isClosing : void 0;
428
+ return { mounted, phase, className };
429
+ }
430
+
431
+ // src/components/Chat/chat.attachments.tsx
432
+ var import_lucide_react2 = require("lucide-react");
433
+ var import_react10 = require("react");
434
+
435
+ // src/components/Chat/context/index.ts
436
+ var import_react9 = require("react");
437
+
438
+ // src/components/Chat/context/composer.context.tsx
439
+ var import_react8 = require("react");
440
+
441
+ // src/components/Chat/chat.tooltip.tsx
442
+ var import_react4 = require("react");
443
+ var import_react_dom = require("react-dom");
444
+ var import_jsx_runtime4 = require("react/jsx-runtime");
445
+ var isEditableSelection = (selection) => {
446
+ var _a, _b;
447
+ const anchorElement = (_a = selection.anchorNode) == null ? void 0 : _a.parentElement;
448
+ const focusElement = (_b = selection.focusNode) == null ? void 0 : _b.parentElement;
449
+ return Boolean(
450
+ (anchorElement == null ? void 0 : anchorElement.closest("textarea,input,[contenteditable='true']")) || (focusElement == null ? void 0 : focusElement.closest("textarea,input,[contenteditable='true']"))
451
+ );
452
+ };
453
+ var getSelectionRect = (range) => {
454
+ const rect = range.getBoundingClientRect();
455
+ const fallbackRect = range.getClientRects()[0];
456
+ return rect.width || rect.height ? rect : fallbackRect;
457
+ };
458
+ var positionFromRange = (range, container) => {
459
+ const selectionRect = getSelectionRect(range);
460
+ if (!selectionRect) {
461
+ return null;
462
+ }
463
+ const containerRect = container.getBoundingClientRect();
464
+ return {
465
+ top: Math.max(8, selectionRect.top - containerRect.top + container.scrollTop),
466
+ left: selectionRect.left - containerRect.left + container.scrollLeft + selectionRect.width / 2
467
+ };
468
+ };
469
+ var readSelection = () => {
470
+ const selection = window.getSelection();
471
+ const text = selection == null ? void 0 : selection.toString().replace(/\s+/g, " ").trim();
472
+ if (!selection || !text || selection.rangeCount === 0 || selection.isCollapsed) {
473
+ return null;
474
+ }
475
+ if (isEditableSelection(selection)) {
476
+ return null;
477
+ }
478
+ return {
479
+ text,
480
+ range: selection.getRangeAt(0).cloneRange()
481
+ };
482
+ };
483
+ var getPortalContainer = (range) => {
484
+ const node = range.commonAncestorContainer;
485
+ const element = node instanceof Element ? node : node.parentElement;
486
+ const found = element == null ? void 0 : element.closest(".chat-messages");
487
+ return found instanceof HTMLElement ? found : null;
488
+ };
489
+ var ChatTooltip = (0, import_react4.memo)(function ChatTooltip2({
490
+ onAddReference
491
+ }) {
492
+ const [selectionAction, setSelectionAction] = (0, import_react4.useState)(null);
493
+ const rangeRef = (0, import_react4.useRef)(null);
494
+ const textRef = (0, import_react4.useRef)("");
495
+ (0, import_react4.useEffect)(() => {
496
+ const clearSelectionAction = () => {
497
+ rangeRef.current = null;
498
+ textRef.current = "";
499
+ setSelectionAction(null);
500
+ };
501
+ const syncPosition = () => {
502
+ const range = rangeRef.current;
503
+ if (!range) {
504
+ return;
505
+ }
506
+ const container = getPortalContainer(range);
507
+ if (!container) {
508
+ clearSelectionAction();
509
+ return;
510
+ }
511
+ const position = positionFromRange(range, container);
512
+ if (!position) {
513
+ clearSelectionAction();
514
+ return;
515
+ }
516
+ setSelectionAction({
517
+ text: textRef.current,
518
+ top: position.top,
519
+ left: position.left,
520
+ container
521
+ });
522
+ };
523
+ const captureSelection = () => {
524
+ const next = readSelection();
525
+ if (!next) {
526
+ clearSelectionAction();
527
+ return;
528
+ }
529
+ rangeRef.current = next.range;
530
+ textRef.current = next.text;
531
+ syncPosition();
532
+ };
533
+ document.addEventListener("mouseup", captureSelection);
534
+ document.addEventListener("keyup", captureSelection);
535
+ document.addEventListener("selectionchange", captureSelection);
536
+ window.addEventListener("scroll", syncPosition, true);
537
+ window.addEventListener("resize", syncPosition);
538
+ return () => {
539
+ document.removeEventListener("mouseup", captureSelection);
540
+ document.removeEventListener("keyup", captureSelection);
541
+ document.removeEventListener("selectionchange", captureSelection);
542
+ window.removeEventListener("scroll", syncPosition, true);
543
+ window.removeEventListener("resize", syncPosition);
544
+ };
545
+ }, [onAddReference]);
546
+ if (!selectionAction) {
547
+ return null;
548
+ }
549
+ return (0, import_react_dom.createPortal)(
550
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
551
+ "button",
552
+ {
553
+ type: "button",
554
+ className: "chat-reference-action",
555
+ style: { top: selectionAction.top, left: selectionAction.left },
556
+ "aria-label": "Add selected text as reference",
557
+ onPointerDown: (event) => event.preventDefault(),
558
+ onClick: () => {
559
+ var _a;
560
+ onAddReference(selectionAction.text);
561
+ (_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
562
+ rangeRef.current = null;
563
+ textRef.current = "";
564
+ setSelectionAction(null);
565
+ },
566
+ children: "Add reference"
567
+ }
568
+ ),
569
+ selectionAction.container
570
+ );
571
+ });
572
+
573
+ // src/components/Chat/context/message.helpers.ts
574
+ var normalizeReferenceText = (text) => text.replace(/\s+/g, " ").trim().slice(0, 4e3);
575
+ var createMessageId = (prefix) => {
576
+ var _a, _b, _c;
577
+ return (_c = (_b = (_a = globalThis.crypto) == null ? void 0 : _a.randomUUID) == null ? void 0 : _b.call(_a)) != null ? _c : `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
578
+ };
579
+ var createUserMessage = (text, files = []) => ({
580
+ id: createMessageId("msg"),
581
+ role: "user",
582
+ parts: [
583
+ ...files.map((file) => ({
584
+ type: "file",
585
+ mediaType: file.mediaType,
586
+ url: file.url,
587
+ filename: file.filename
588
+ })),
589
+ ...text ? [{ type: "text", text }] : []
590
+ ]
591
+ });
592
+ var updateMessageText = (message, text) => ({
593
+ ...message,
594
+ parts: [{ type: "text", text }]
595
+ });
596
+ var upsertAssistantMessage = (current, nextMessage) => {
597
+ const existingIndex = current.findIndex((message) => message.id === nextMessage.id);
598
+ if (existingIndex === -1) {
599
+ return [...current, nextMessage];
600
+ }
601
+ return current.map((message, index) => index === existingIndex ? nextMessage : message);
602
+ };
603
+
604
+ // src/components/Chat/context/messages.context.tsx
605
+ var import_react7 = require("react");
606
+ var import_react_dom2 = require("react-dom");
607
+
608
+ // src/lib/message/user.ts
609
+ var REFERENCE_PREFIX = "Use the following selected references as context:\n\n";
610
+ var USER_MESSAGE_MARKER = "\n\nUser message:\n";
611
+ var REFERENCE_PATTERN = /<reference \d+>\n([\s\S]*?)\n<\/reference \d+>/g;
612
+ var getMessageTextContent = (message) => message.parts.filter((part) => part.type === "text").map((part) => part.text).join("\n");
613
+ var parseUserReferenceMessage = (content) => {
614
+ if (!content.startsWith(REFERENCE_PREFIX)) {
615
+ return null;
616
+ }
617
+ const markerIndex = content.indexOf(USER_MESSAGE_MARKER);
618
+ if (markerIndex === -1) {
619
+ return null;
620
+ }
621
+ const references = [...content.slice(REFERENCE_PREFIX.length, markerIndex).matchAll(REFERENCE_PATTERN)].map((match) => match[1].trim()).filter(Boolean);
622
+ return references.length ? { references, message: content.slice(markerIndex + USER_MESSAGE_MARKER.length) } : null;
623
+ };
624
+ var getUserDisplayText = (message) => {
625
+ var _a, _b;
626
+ const text = getMessageTextContent(message);
627
+ return (_b = (_a = parseUserReferenceMessage(text)) == null ? void 0 : _a.message) != null ? _b : text;
628
+ };
629
+
630
+ // src/components/Chat/context/model.context.tsx
631
+ var import_react5 = require("react");
632
+
633
+ // src/components/Chat/context/types.ts
634
+ var ProviderId = /* @__PURE__ */ ((ProviderId2) => {
635
+ ProviderId2["SYMPHONY"] = "symphony";
636
+ ProviderId2["MOCK"] = "mock";
637
+ ProviderId2["OPENAI"] = "openai";
638
+ ProviderId2["GOOGLE"] = "google";
639
+ ProviderId2["GEMINI"] = "gemini";
640
+ ProviderId2["CLAUDE"] = "anthropic";
641
+ ProviderId2["GROK"] = "grok";
642
+ ProviderId2["OLLAMA"] = "ollama";
643
+ ProviderId2["LOCAL"] = "local";
644
+ return ProviderId2;
645
+ })(ProviderId || {});
646
+ var PROVIDER_IDS = new Set(Object.values(ProviderId));
647
+ var isProviderId = (value) => typeof value === "string" && PROVIDER_IDS.has(value);
648
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
649
+ var isRegistryModel = (value) => {
650
+ if (!isRecord(value) || typeof value.id !== "string" || typeof value.label !== "string") {
651
+ return false;
652
+ }
653
+ if (value.description !== void 0 && typeof value.description !== "string") {
654
+ return false;
655
+ }
656
+ if (value.thinkingLevels !== void 0 && (!Array.isArray(value.thinkingLevels) || !value.thinkingLevels.every((level) => typeof level === "string"))) {
657
+ return false;
658
+ }
659
+ return true;
660
+ };
661
+ var isRegistryProvider = (value) => isRecord(value) && typeof value.id === "string" && typeof value.label === "string" && typeof value.defaultModel === "string" && Array.isArray(value.models) && value.models.every(isRegistryModel) && (value.name === void 0 || typeof value.name === "string") && (value.logo === void 0 || typeof value.logo === "string");
662
+ var parseRegistryConfig = (value) => {
663
+ if (!isRecord(value) || typeof value.defaultProviderId !== "string" || !Array.isArray(value.providers)) {
664
+ return void 0;
665
+ }
666
+ const providers = value.providers.filter(isRegistryProvider);
667
+ if (providers.length === 0) {
668
+ return void 0;
669
+ }
670
+ return {
671
+ defaultProviderId: value.defaultProviderId,
672
+ providers
673
+ };
674
+ };
675
+ var defaultRegistry = {
676
+ defaultProviderId: "mock" /* MOCK */,
677
+ providers: [
678
+ {
679
+ id: "symphony" /* SYMPHONY */,
680
+ label: "Symphony (custom harness)",
681
+ defaultModel: "",
682
+ models: []
683
+ },
684
+ {
685
+ id: "mock" /* MOCK */,
686
+ label: "Mock",
687
+ defaultModel: "canned",
688
+ models: [{ id: "canned", label: "Canned replies" }]
689
+ },
690
+ {
691
+ id: "openai" /* OPENAI */,
692
+ label: "OpenAI",
693
+ defaultModel: "gpt-4.1",
694
+ models: [{ id: "gpt-4.1", label: "GPT-4.1" }]
695
+ },
696
+ {
697
+ id: "anthropic" /* CLAUDE */,
698
+ label: "Anthropic",
699
+ defaultModel: "claude-3-7-sonnet-20250219",
700
+ models: [{ id: "claude-3-7-sonnet-20250219", label: "Claude 3.7 Sonnet" }]
701
+ },
702
+ {
703
+ id: "google" /* GOOGLE */,
704
+ label: "Google",
705
+ defaultModel: "gemini-2.5-flash",
706
+ models: [{ id: "gemini-2.5-flash", label: "Gemini 2.5 Flash" }]
707
+ },
708
+ {
709
+ id: "ollama" /* OLLAMA */,
710
+ label: "Ollama",
711
+ defaultModel: "smallthinker:latest",
712
+ models: [{ id: "smallthinker:latest", label: "smallthinker:latest" }]
713
+ }
714
+ ]
715
+ };
716
+
717
+ // src/components/Chat/context/model.context.tsx
718
+ var import_jsx_runtime5 = require("react/jsx-runtime");
719
+ var ModelContext = (0, import_react5.createContext)(null);
720
+ function ModelProvider({
721
+ children,
722
+ defaultProvider = "mock" /* MOCK */,
723
+ registryUrl = "/api/ai/registry"
724
+ }) {
725
+ const [registry, setRegistry] = (0, import_react5.useState)(defaultRegistry);
726
+ const [provider, setProviderState] = (0, import_react5.useState)(defaultProvider);
727
+ const [model, setModelState] = (0, import_react5.useState)(
728
+ () => {
729
+ var _a, _b;
730
+ return (_b = (_a = defaultRegistry.providers.find((entry) => entry.id === defaultProvider)) == null ? void 0 : _a.defaultModel) != null ? _b : "";
731
+ }
732
+ );
733
+ const [thinkingLevels, setThinkingLevelsState] = (0, import_react5.useState)(() => {
734
+ const initial = {};
735
+ for (const p of defaultRegistry.providers) {
736
+ for (const m of p.models) {
737
+ const levels = m.thinkingLevels;
738
+ if (levels == null ? void 0 : levels.length) initial[`${p.id}::${m.id}`] = levels.includes("medium") ? "medium" : levels[0];
739
+ }
740
+ }
741
+ return initial;
742
+ });
743
+ const providerRef = (0, import_react5.useRef)(provider);
744
+ const modelRef = (0, import_react5.useRef)(model);
745
+ const thinkingLevelsRef = (0, import_react5.useRef)(thinkingLevels);
746
+ providerRef.current = provider;
747
+ modelRef.current = model;
748
+ thinkingLevelsRef.current = thinkingLevels;
749
+ (0, import_react5.useEffect)(() => {
750
+ let cancelled = false;
751
+ const loadRegistry = async () => {
752
+ var _a;
753
+ try {
754
+ const response = await fetch(registryUrl, { cache: "no-store" });
755
+ if (!response.ok) {
756
+ throw new Error("Failed to load registry");
757
+ }
758
+ const data = parseRegistryConfig(await response.json());
759
+ if (cancelled || !data) {
760
+ return;
761
+ }
762
+ setRegistry(data);
763
+ const nextThinking = {};
764
+ for (const p of data.providers) {
765
+ for (const m of p.models) {
766
+ const levels = m.thinkingLevels;
767
+ if (levels == null ? void 0 : levels.length) nextThinking[`${p.id}::${m.id}`] = levels.includes("medium") ? "medium" : levels[0];
768
+ }
769
+ }
770
+ setThinkingLevelsState((prev) => ({ ...nextThinking, ...prev }));
771
+ const preferred = (_a = data.providers.find((entry) => entry.id === data.defaultProviderId)) != null ? _a : data.providers[0];
772
+ if (preferred) {
773
+ setProviderState(preferred.id);
774
+ setModelState(preferred.defaultModel);
775
+ }
776
+ } catch {
777
+ if (!cancelled) {
778
+ setRegistry(defaultRegistry);
779
+ }
780
+ }
781
+ };
782
+ void loadRegistry();
783
+ return () => {
784
+ cancelled = true;
785
+ };
786
+ }, [registryUrl]);
787
+ (0, import_react5.useEffect)(() => {
788
+ var _a, _b;
789
+ const nextProvider = (_b = (_a = registry.providers.find((entry) => entry.id === provider)) != null ? _a : registry.providers.find((entry) => entry.id === registry.defaultProviderId)) != null ? _b : registry.providers[0];
790
+ if (!nextProvider) {
791
+ return;
792
+ }
793
+ const hasModel = nextProvider.models.some((entry) => entry.id === model);
794
+ if (!hasModel) {
795
+ setProviderState(nextProvider.id);
796
+ setModelState(nextProvider.defaultModel);
797
+ }
798
+ }, [model, provider, registry]);
799
+ const setProvider = (0, import_react5.useCallback)((nextProvider, nextModel) => {
800
+ setProviderState(nextProvider);
801
+ if (nextModel) {
802
+ setModelState(nextModel);
803
+ }
804
+ }, []);
805
+ const getThinkingLevel = (0, import_react5.useCallback)(
806
+ (providerId, modelId) => thinkingLevels[`${providerId}::${modelId}`],
807
+ [thinkingLevels]
808
+ );
809
+ const setThinkingLevel = (0, import_react5.useCallback)((providerId, modelId, level) => {
810
+ setThinkingLevelsState((prev) => ({ ...prev, [`${providerId}::${modelId}`]: level }));
811
+ }, []);
812
+ const setModel = (0, import_react5.useCallback)((nextModel) => {
813
+ setModelState(nextModel);
814
+ }, []);
815
+ const value = (0, import_react5.useMemo)(
816
+ () => ({
817
+ registry,
818
+ provider,
819
+ model,
820
+ thinkingLevels,
821
+ getThinkingLevel,
822
+ setThinkingLevel,
823
+ setProvider,
824
+ setModel,
825
+ providerRef,
826
+ modelRef,
827
+ thinkingLevelsRef
828
+ }),
829
+ [model, provider, registry, setModel, setProvider, thinkingLevels, getThinkingLevel, setThinkingLevel]
830
+ );
831
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ModelContext.Provider, { value, children });
832
+ }
833
+ function useModel() {
834
+ const context = (0, import_react5.useContext)(ModelContext);
835
+ if (!context) {
836
+ throw new Error("useModel must be used inside ModelProvider");
837
+ }
838
+ return context;
839
+ }
840
+
841
+ // src/components/Chat/context/thread.context.tsx
842
+ var import_react6 = require("react");
843
+ var import_jsx_runtime6 = require("react/jsx-runtime");
844
+ var ThreadContext = (0, import_react6.createContext)(null);
845
+ function ThreadProvider({
846
+ adapter,
847
+ children,
848
+ defaultThreadId
849
+ }) {
850
+ const [threads, setThreads] = (0, import_react6.useState)([]);
851
+ const [activeThreadId, setActiveThreadId] = (0, import_react6.useState)(defaultThreadId != null ? defaultThreadId : null);
852
+ const [isLoadingThread, setIsLoadingThread] = (0, import_react6.useState)(true);
853
+ const activeThreadIdRef = (0, import_react6.useRef)(activeThreadId);
854
+ activeThreadIdRef.current = activeThreadId;
855
+ const adapterRef = (0, import_react6.useRef)(adapter);
856
+ adapterRef.current = adapter;
857
+ (0, import_react6.useEffect)(() => {
858
+ let cancelled = false;
859
+ const bootstrap = async () => {
860
+ setIsLoadingThread(true);
861
+ if (defaultThreadId) {
862
+ setThreads(
863
+ (current) => current.some((thread2) => thread2.id === defaultThreadId) ? current : [{ id: defaultThreadId, title: "New chat" }, ...current]
864
+ );
865
+ setActiveThreadId(defaultThreadId);
866
+ setIsLoadingThread(false);
867
+ return;
868
+ }
869
+ const currentAdapter = adapterRef.current;
870
+ if (!currentAdapter.listThreads || !currentAdapter.createThread) {
871
+ const localThread = { id: createMessageId("thread"), title: "New chat" };
872
+ setThreads([localThread]);
873
+ setActiveThreadId(localThread.id);
874
+ setIsLoadingThread(false);
875
+ return;
876
+ }
877
+ const nextThreads = await currentAdapter.listThreads();
878
+ if (cancelled) {
879
+ return;
880
+ }
881
+ if (nextThreads.length > 0) {
882
+ setThreads(nextThreads);
883
+ setActiveThreadId(nextThreads[0].id);
884
+ setIsLoadingThread(false);
885
+ return;
886
+ }
887
+ const thread = await currentAdapter.createThread();
888
+ if (cancelled) {
889
+ return;
890
+ }
891
+ setThreads([thread]);
892
+ setActiveThreadId(thread.id);
893
+ setIsLoadingThread(false);
894
+ };
895
+ bootstrap().catch(() => {
896
+ if (!cancelled) {
897
+ setIsLoadingThread(false);
898
+ }
899
+ });
900
+ return () => {
901
+ cancelled = true;
902
+ };
903
+ }, [defaultThreadId]);
904
+ const selectThread = (0, import_react6.useCallback)(async (threadId) => {
905
+ setActiveThreadId((current) => current === threadId ? current : threadId);
906
+ }, []);
907
+ const createThread = (0, import_react6.useCallback)(async () => {
908
+ const currentAdapter = adapterRef.current;
909
+ const thread = currentAdapter.createThread ? await currentAdapter.createThread() : { id: createMessageId("thread"), title: "New chat" };
910
+ setThreads((current) => [thread, ...current]);
911
+ setActiveThreadId(thread.id);
912
+ }, []);
913
+ const deleteThread = (0, import_react6.useCallback)(
914
+ async (threadId) => {
915
+ var _a, _b;
916
+ await ((_b = (_a = adapterRef.current).deleteThread) == null ? void 0 : _b.call(_a, threadId));
917
+ setThreads((current) => {
918
+ const remaining = current.filter((thread) => thread.id !== threadId);
919
+ setActiveThreadId((active) => {
920
+ var _a2, _b2;
921
+ if (active !== threadId) {
922
+ return active;
923
+ }
924
+ const nextActive = (_b2 = (_a2 = remaining[0]) == null ? void 0 : _a2.id) != null ? _b2 : null;
925
+ if (!nextActive) {
926
+ void createThread();
927
+ }
928
+ return nextActive;
929
+ });
930
+ return remaining;
931
+ });
932
+ },
933
+ [createThread]
934
+ );
935
+ const value = (0, import_react6.useMemo)(
936
+ () => ({
937
+ threads,
938
+ activeThreadId,
939
+ isLoadingThread,
940
+ activeThreadIdRef,
941
+ setThreads,
942
+ setIsLoadingThread,
943
+ selectThread,
944
+ createThread,
945
+ deleteThread
946
+ }),
947
+ [
948
+ activeThreadId,
949
+ createThread,
950
+ deleteThread,
951
+ isLoadingThread,
952
+ selectThread,
953
+ threads
954
+ ]
955
+ );
956
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ThreadContext.Provider, { value, children });
957
+ }
958
+ function useThread() {
959
+ const context = (0, import_react6.useContext)(ThreadContext);
960
+ if (!context) {
961
+ throw new Error("useThread must be used inside ThreadProvider");
962
+ }
963
+ return context;
964
+ }
965
+
966
+ // src/components/Chat/context/messages.context.tsx
967
+ var import_jsx_runtime7 = require("react/jsx-runtime");
968
+ var MINIMUM_RESPONSE_LOADING_MS = 350;
969
+ var wait = (milliseconds) => new Promise((resolve) => window.setTimeout(resolve, milliseconds));
970
+ var hasVisibleAssistantContent = (message) => message.parts.some((part) => {
971
+ if (part.type === "text") {
972
+ return "text" in part && typeof part.text === "string" && part.text.trim().length > 0;
973
+ }
974
+ if (part.type === "data") {
975
+ return "name" in part && part.name !== "usage" && part.name !== "context" && part.name !== "context-warning";
976
+ }
977
+ return ["reasoning", "tool", "widget", "source-url", "source-document", "file", "unknown"].includes(part.type);
978
+ });
979
+ var MessagesContext = (0, import_react7.createContext)(null);
980
+ function MessagesProvider({ adapter, children }) {
981
+ const { activeThreadId, activeThreadIdRef, setThreads, setIsLoadingThread } = useThread();
982
+ const { providerRef, modelRef, thinkingLevelsRef } = useModel();
983
+ const [messages, setMessages] = (0, import_react7.useState)([]);
984
+ const [status, setStatus] = (0, import_react7.useState)("ready");
985
+ const [isWaitingForResponse, setIsWaitingForResponse] = (0, import_react7.useState)(false);
986
+ const messagesRef = (0, import_react7.useRef)(messages);
987
+ const statusRef = (0, import_react7.useRef)(status);
988
+ const adapterRef = (0, import_react7.useRef)(adapter);
989
+ const abortRef = (0, import_react7.useRef)(null);
990
+ messagesRef.current = messages;
991
+ statusRef.current = status;
992
+ adapterRef.current = adapter;
993
+ (0, import_react7.useEffect)(() => {
994
+ let cancelled = false;
995
+ const loadMessages = async () => {
996
+ if (!activeThreadId) {
997
+ setMessages([]);
998
+ setIsLoadingThread(false);
999
+ return;
1000
+ }
1001
+ const currentAdapter = adapterRef.current;
1002
+ if (!currentAdapter.loadMessages) {
1003
+ setIsLoadingThread(false);
1004
+ return;
1005
+ }
1006
+ setIsLoadingThread(true);
1007
+ try {
1008
+ const nextMessages = await currentAdapter.loadMessages(activeThreadId);
1009
+ if (cancelled) {
1010
+ return;
1011
+ }
1012
+ setMessages(nextMessages);
1013
+ setIsLoadingThread(false);
1014
+ } catch {
1015
+ if (!cancelled) {
1016
+ setMessages([]);
1017
+ setIsLoadingThread(false);
1018
+ setStatus("error");
1019
+ }
1020
+ }
1021
+ };
1022
+ void loadMessages();
1023
+ return () => {
1024
+ cancelled = true;
1025
+ };
1026
+ }, [activeThreadId, setIsLoadingThread]);
1027
+ const streamMessage = (0, import_react7.useCallback)(
1028
+ async ({
1029
+ message,
1030
+ nextMessages,
1031
+ provider,
1032
+ model,
1033
+ thinkingLevel
1034
+ }) => {
1035
+ var _a;
1036
+ const threadId = activeThreadIdRef.current;
1037
+ if (!threadId) {
1038
+ setIsWaitingForResponse(false);
1039
+ return;
1040
+ }
1041
+ (_a = abortRef.current) == null ? void 0 : _a.abort();
1042
+ const abortController = new AbortController();
1043
+ abortRef.current = abortController;
1044
+ setStatus("submitted");
1045
+ const responseStartedAt = Date.now();
1046
+ let receivedVisibleResponse = false;
1047
+ try {
1048
+ for await (const assistantMessage of adapterRef.current.sendMessage({
1049
+ threadId,
1050
+ message,
1051
+ messages: nextMessages,
1052
+ provider,
1053
+ model,
1054
+ thinkingLevel,
1055
+ signal: abortController.signal
1056
+ })) {
1057
+ if (!receivedVisibleResponse && hasVisibleAssistantContent(assistantMessage)) {
1058
+ receivedVisibleResponse = true;
1059
+ const remaining = MINIMUM_RESPONSE_LOADING_MS - (Date.now() - responseStartedAt);
1060
+ if (remaining > 0) {
1061
+ await wait(remaining);
1062
+ }
1063
+ if (abortController.signal.aborted) {
1064
+ setIsWaitingForResponse(false);
1065
+ setStatus("ready");
1066
+ return;
1067
+ }
1068
+ }
1069
+ if (receivedVisibleResponse) {
1070
+ setIsWaitingForResponse(false);
1071
+ setStatus("streaming");
1072
+ }
1073
+ setMessages((current) => upsertAssistantMessage(current, assistantMessage));
1074
+ }
1075
+ setStatus("ready");
1076
+ } catch (error) {
1077
+ setIsWaitingForResponse(false);
1078
+ if (abortController.signal.aborted) {
1079
+ setStatus("ready");
1080
+ return;
1081
+ }
1082
+ setStatus("error");
1083
+ throw error;
1084
+ } finally {
1085
+ setIsWaitingForResponse(false);
1086
+ if (abortRef.current === abortController) {
1087
+ abortRef.current = null;
1088
+ }
1089
+ }
1090
+ },
1091
+ [activeThreadIdRef]
1092
+ );
1093
+ const sendMessage = (0, import_react7.useCallback)(
1094
+ async (message, options) => {
1095
+ var _a, _b, _c, _d, _e;
1096
+ const text = message.text.trim();
1097
+ const files = (_a = message.files) != null ? _a : [];
1098
+ const threadId = activeThreadIdRef.current;
1099
+ if (!text && files.length === 0 || !threadId) {
1100
+ return;
1101
+ }
1102
+ const userMessage = createUserMessage(text, files);
1103
+ const nextMessages = [...messagesRef.current, userMessage];
1104
+ (0, import_react_dom2.flushSync)(() => {
1105
+ setMessages(nextMessages);
1106
+ setIsWaitingForResponse(true);
1107
+ });
1108
+ const resolvedProvider = (_c = (_b = options == null ? void 0 : options.body) == null ? void 0 : _b.provider) != null ? _c : providerRef.current;
1109
+ const resolvedModel = (_e = (_d = options == null ? void 0 : options.body) == null ? void 0 : _d.model) != null ? _e : modelRef.current;
1110
+ const thinkingLevel = thinkingLevelsRef.current[`${resolvedProvider}::${resolvedModel}`];
1111
+ await streamMessage({
1112
+ message: userMessage,
1113
+ nextMessages,
1114
+ provider: resolvedProvider,
1115
+ model: resolvedModel,
1116
+ thinkingLevel
1117
+ });
1118
+ },
1119
+ [activeThreadIdRef, modelRef, providerRef, streamMessage]
1120
+ );
1121
+ const editAndResendMessage = (0, import_react7.useCallback)(
1122
+ async (messageId, text) => {
1123
+ var _a;
1124
+ const trimmedText = text.trim();
1125
+ const threadId = activeThreadIdRef.current;
1126
+ const isSending2 = statusRef.current === "submitted" || statusRef.current === "streaming";
1127
+ if (!trimmedText || !threadId || isSending2) {
1128
+ return;
1129
+ }
1130
+ const previousMessages = messagesRef.current;
1131
+ const messageIndex = previousMessages.findIndex((message2) => message2.id === messageId);
1132
+ const message = previousMessages[messageIndex];
1133
+ if (!message || message.role !== "user") {
1134
+ return;
1135
+ }
1136
+ let editedMessages = previousMessages.slice(0, messageIndex + 1).map(
1137
+ (currentMessage) => currentMessage.id === messageId ? updateMessageText(currentMessage, trimmedText) : currentMessage
1138
+ );
1139
+ setThreads((current) => {
1140
+ const firstUserMessage = editedMessages.find(
1141
+ (currentMessage) => currentMessage.role === "user"
1142
+ );
1143
+ const firstUserTitle = firstUserMessage ? getUserDisplayText(firstUserMessage).trim().slice(0, 60) : "";
1144
+ return current.map(
1145
+ (thread) => thread.id === threadId && firstUserTitle ? { ...thread, title: firstUserTitle } : thread
1146
+ );
1147
+ });
1148
+ try {
1149
+ if (adapterRef.current.editMessage) {
1150
+ editedMessages = await adapterRef.current.editMessage({
1151
+ threadId,
1152
+ messageId,
1153
+ text: trimmedText
1154
+ });
1155
+ }
1156
+ const editedMessage = (_a = editedMessages.find((currentMessage) => currentMessage.id === messageId)) != null ? _a : updateMessageText(message, trimmedText);
1157
+ setMessages(editedMessages);
1158
+ setIsWaitingForResponse(true);
1159
+ const thinkingLevel = thinkingLevelsRef.current[`${providerRef.current}::${modelRef.current}`];
1160
+ await streamMessage({
1161
+ message: editedMessage,
1162
+ nextMessages: editedMessages,
1163
+ provider: providerRef.current,
1164
+ model: modelRef.current,
1165
+ thinkingLevel
1166
+ });
1167
+ } catch (error) {
1168
+ setIsWaitingForResponse(false);
1169
+ setMessages(previousMessages);
1170
+ throw error;
1171
+ }
1172
+ },
1173
+ [activeThreadIdRef, modelRef, providerRef, setThreads, streamMessage]
1174
+ );
1175
+ const stopResponse = (0, import_react7.useCallback)(() => {
1176
+ var _a;
1177
+ const isSending2 = statusRef.current === "submitted" || statusRef.current === "streaming";
1178
+ if (!isSending2) {
1179
+ return;
1180
+ }
1181
+ (_a = abortRef.current) == null ? void 0 : _a.abort();
1182
+ setIsWaitingForResponse(false);
1183
+ setStatus("ready");
1184
+ }, []);
1185
+ const isSending = status === "submitted" || status === "streaming";
1186
+ const value = (0, import_react7.useMemo)(
1187
+ () => ({
1188
+ messages,
1189
+ status,
1190
+ isSending,
1191
+ isWaitingForResponse,
1192
+ sendMessage,
1193
+ editAndResendMessage,
1194
+ stopResponse
1195
+ }),
1196
+ [editAndResendMessage, isSending, isWaitingForResponse, messages, sendMessage, status, stopResponse]
1197
+ );
1198
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessagesContext.Provider, { value, children });
1199
+ }
1200
+ function useMessages() {
1201
+ const context = (0, import_react7.useContext)(MessagesContext);
1202
+ if (!context) {
1203
+ throw new Error("useMessages must be used inside MessagesProvider");
1204
+ }
1205
+ return context;
1206
+ }
1207
+
1208
+ // src/components/Chat/context/composer.context.tsx
1209
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1210
+ var readFileAsDataUrl = (file) => new Promise((resolve, reject) => {
1211
+ const reader = new FileReader();
1212
+ reader.onload = () => {
1213
+ if (typeof reader.result === "string") {
1214
+ resolve(reader.result);
1215
+ return;
1216
+ }
1217
+ reject(new Error("Could not read file"));
1218
+ };
1219
+ reader.onerror = () => {
1220
+ var _a;
1221
+ reject((_a = reader.error) != null ? _a : new Error("Could not read file"));
1222
+ };
1223
+ reader.readAsDataURL(file);
1224
+ });
1225
+ var ComposerContext = (0, import_react8.createContext)(null);
1226
+ function ComposerProvider({ children }) {
1227
+ const { activeThreadId, activeThreadIdRef, isLoadingThread, setThreads } = useThread();
1228
+ const { providerRef, modelRef } = useModel();
1229
+ const { sendMessage, isSending } = useMessages();
1230
+ const [input, setInputState] = (0, import_react8.useState)("");
1231
+ const [references, setReferences] = (0, import_react8.useState)([]);
1232
+ const [attachments, setAttachments] = (0, import_react8.useState)([]);
1233
+ const inputRef = (0, import_react8.useRef)(input);
1234
+ const referencesRef = (0, import_react8.useRef)(references);
1235
+ const attachmentsRef = (0, import_react8.useRef)(attachments);
1236
+ inputRef.current = input;
1237
+ referencesRef.current = references;
1238
+ attachmentsRef.current = attachments;
1239
+ const setInput = (0, import_react8.useCallback)((value2) => {
1240
+ setInputState(value2);
1241
+ }, []);
1242
+ const addReference = (0, import_react8.useCallback)((text) => {
1243
+ const normalized = normalizeReferenceText(text);
1244
+ if (!normalized) {
1245
+ return;
1246
+ }
1247
+ setReferences((current) => {
1248
+ if (current.some((reference) => reference.text === normalized)) {
1249
+ return current;
1250
+ }
1251
+ return [
1252
+ ...current,
1253
+ {
1254
+ id: createMessageId("ref"),
1255
+ text: normalized
1256
+ }
1257
+ ];
1258
+ });
1259
+ }, []);
1260
+ const removeReference = (0, import_react8.useCallback)((id) => {
1261
+ setReferences((current) => current.filter((reference) => reference.id !== id));
1262
+ }, []);
1263
+ const clearReferences = (0, import_react8.useCallback)(() => {
1264
+ setReferences([]);
1265
+ }, []);
1266
+ const addFiles = (0, import_react8.useCallback)(async (list) => {
1267
+ const incoming = Array.from(list);
1268
+ const next = [];
1269
+ for (const file of incoming) {
1270
+ try {
1271
+ const url = await readFileAsDataUrl(file);
1272
+ next.push({
1273
+ id: createMessageId("file"),
1274
+ filename: file.name || "file",
1275
+ mediaType: file.type || "application/octet-stream",
1276
+ url
1277
+ });
1278
+ } catch {
1279
+ }
1280
+ }
1281
+ if (next.length === 0) {
1282
+ return;
1283
+ }
1284
+ setAttachments((current) => [...current, ...next]);
1285
+ }, []);
1286
+ const removeAttachment = (0, import_react8.useCallback)((id) => {
1287
+ setAttachments((current) => current.filter((attachment) => attachment.id !== id));
1288
+ }, []);
1289
+ const disabled = isSending || isLoadingThread || !activeThreadId;
1290
+ const canSend = !disabled && (!!input.trim() || attachments.length > 0);
1291
+ const disabledRef = (0, import_react8.useRef)(disabled);
1292
+ disabledRef.current = disabled;
1293
+ const submitInput = (0, import_react8.useCallback)(async () => {
1294
+ var _a;
1295
+ const text = inputRef.current.trim();
1296
+ const threadId = activeThreadIdRef.current;
1297
+ const attachmentsSnapshot = attachmentsRef.current;
1298
+ if (!text && attachmentsSnapshot.length === 0 || !threadId || disabledRef.current) {
1299
+ return;
1300
+ }
1301
+ const nextTitle = (text || ((_a = attachmentsSnapshot[0]) == null ? void 0 : _a.filename) || "").slice(0, 60);
1302
+ const referencesSnapshot = referencesRef.current;
1303
+ const referenceText = referencesSnapshot.map(
1304
+ (reference, index) => `<reference ${index + 1}>
1305
+ ${reference.text}
1306
+ </reference ${index + 1}>`
1307
+ ).join("\n\n");
1308
+ const messageText = referenceText ? `Use the following selected references as context:
1309
+
1310
+ ${referenceText}
1311
+
1312
+ User message:
1313
+ ${text}` : text;
1314
+ setInputState("");
1315
+ setReferences([]);
1316
+ setAttachments([]);
1317
+ setThreads((current) => {
1318
+ const next = current.map(
1319
+ (thread) => thread.id === threadId && thread.title === "New chat" ? { ...thread, title: nextTitle || thread.title } : thread
1320
+ );
1321
+ const selected = next.find((thread) => thread.id === threadId);
1322
+ const remaining = next.filter((thread) => thread.id !== threadId);
1323
+ return selected ? [selected, ...remaining] : next;
1324
+ });
1325
+ try {
1326
+ await sendMessage(
1327
+ {
1328
+ text: messageText,
1329
+ files: attachmentsSnapshot.map((file) => ({
1330
+ mediaType: file.mediaType,
1331
+ url: file.url,
1332
+ filename: file.filename
1333
+ }))
1334
+ },
1335
+ {
1336
+ body: {
1337
+ provider: providerRef.current,
1338
+ model: modelRef.current
1339
+ }
1340
+ }
1341
+ );
1342
+ } catch (error) {
1343
+ setInputState(text);
1344
+ setReferences(referencesSnapshot);
1345
+ setAttachments(attachmentsSnapshot);
1346
+ throw error;
1347
+ }
1348
+ }, [activeThreadIdRef, modelRef, providerRef, sendMessage, setThreads]);
1349
+ const value = (0, import_react8.useMemo)(
1350
+ () => ({
1351
+ input,
1352
+ setInput,
1353
+ references,
1354
+ addReference,
1355
+ removeReference,
1356
+ clearReferences,
1357
+ attachments,
1358
+ addFiles,
1359
+ removeAttachment,
1360
+ disabled,
1361
+ canSend,
1362
+ submitInput
1363
+ }),
1364
+ [
1365
+ addReference,
1366
+ canSend,
1367
+ clearReferences,
1368
+ disabled,
1369
+ input,
1370
+ addFiles,
1371
+ attachments,
1372
+ references,
1373
+ removeAttachment,
1374
+ removeReference,
1375
+ setInput,
1376
+ submitInput
1377
+ ]
1378
+ );
1379
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(ComposerContext.Provider, { value, children: [
1380
+ children,
1381
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChatTooltip, { onAddReference: addReference })
1382
+ ] });
1383
+ }
1384
+ function useComposer() {
1385
+ const context = (0, import_react8.useContext)(ComposerContext);
1386
+ if (!context) {
1387
+ throw new Error("useComposer must be used inside ComposerProvider");
1388
+ }
1389
+ return context;
1390
+ }
1391
+
1392
+ // src/components/Chat/context/chat.provider.tsx
1393
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1394
+ function ChatContextProvider({
1395
+ adapter,
1396
+ children,
1397
+ defaultProvider = "mock" /* MOCK */,
1398
+ defaultThreadId,
1399
+ registryUrl = "/api/ai/registry"
1400
+ }) {
1401
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ModelProvider, { defaultProvider, registryUrl, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ThreadProvider, { adapter, defaultThreadId, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessagesProvider, { adapter, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ComposerProvider, { children }) }) }) });
1402
+ }
1403
+
1404
+ // src/components/Chat/context/index.ts
1405
+ function useChat() {
1406
+ const composer = useComposer();
1407
+ const messages = useMessages();
1408
+ const model = useModel();
1409
+ const thread = useThread();
1410
+ return (0, import_react9.useMemo)(() => {
1411
+ const dispatch = (action) => {
1412
+ switch (action.type) {
1413
+ case "setInput":
1414
+ composer.setInput(action.data.input);
1415
+ break;
1416
+ case "setProvider":
1417
+ model.setProvider(action.data.provider, action.data.model);
1418
+ break;
1419
+ case "setModel":
1420
+ model.setModel(action.data.model);
1421
+ break;
1422
+ case "addReference":
1423
+ composer.addReference(action.data.text);
1424
+ break;
1425
+ case "removeReference":
1426
+ composer.removeReference(action.data.id);
1427
+ break;
1428
+ case "clearReferences":
1429
+ composer.clearReferences();
1430
+ break;
1431
+ default:
1432
+ break;
1433
+ }
1434
+ };
1435
+ return {
1436
+ state: {
1437
+ input: composer.input,
1438
+ provider: model.provider,
1439
+ model: model.model,
1440
+ references: composer.references,
1441
+ disabled: composer.disabled,
1442
+ sendDisabled: !composer.canSend
1443
+ },
1444
+ dispatch,
1445
+ messages: messages.messages,
1446
+ status: messages.status,
1447
+ activeThreadId: thread.activeThreadId,
1448
+ threads: thread.threads,
1449
+ isLoadingThread: thread.isLoadingThread,
1450
+ registry: model.registry,
1451
+ sendMessage: messages.sendMessage,
1452
+ submitInput: composer.submitInput,
1453
+ editAndResendMessage: messages.editAndResendMessage,
1454
+ stopResponse: messages.stopResponse,
1455
+ selectThread: thread.selectThread,
1456
+ createThread: thread.createThread,
1457
+ deleteThread: thread.deleteThread
1458
+ };
1459
+ }, [composer, messages, model, thread]);
1460
+ }
1461
+
1462
+ // src/components/Chat/chat.attachments.tsx
1463
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1464
+ var isImageMediaType = (mediaType) => mediaType.startsWith("image/");
1465
+ var ChatAttachments = () => {
1466
+ const { attachments, removeAttachment } = useComposer();
1467
+ if (attachments.length === 0) {
1468
+ return null;
1469
+ }
1470
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "chat-attachments", children: attachments.map((attachment) => {
1471
+ const image = isImageMediaType(attachment.mediaType);
1472
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1473
+ "div",
1474
+ {
1475
+ className: image ? "chat-attachment chat-attachment-image" : "chat-attachment chat-attachment-file",
1476
+ children: [
1477
+ image ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("img", { src: attachment.url, alt: attachment.filename }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1478
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react2.FileText, { size: 14, "aria-hidden": "true" }),
1479
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "chat-attachment-name", children: attachment.filename })
1480
+ ] }),
1481
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1482
+ "button",
1483
+ {
1484
+ type: "button",
1485
+ className: "chat-attachment-remove",
1486
+ "aria-label": `Remove ${attachment.filename}`,
1487
+ onClick: () => removeAttachment(attachment.id),
1488
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react2.X, { size: 12 })
1489
+ }
1490
+ )
1491
+ ]
1492
+ },
1493
+ attachment.id
1494
+ );
1495
+ }) });
1496
+ };
1497
+ var ChatAttachButton = () => {
1498
+ const { disabled, addFiles } = useComposer();
1499
+ const inputRef = (0, import_react10.useRef)(null);
1500
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1501
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1502
+ "button",
1503
+ {
1504
+ type: "button",
1505
+ className: "chat-attach",
1506
+ "aria-label": "Add attachment",
1507
+ disabled,
1508
+ onClick: () => {
1509
+ var _a;
1510
+ return (_a = inputRef.current) == null ? void 0 : _a.click();
1511
+ },
1512
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react2.Paperclip, { size: 16 })
1513
+ }
1514
+ ),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1516
+ "input",
1517
+ {
1518
+ ref: inputRef,
1519
+ className: "chat-attach-input",
1520
+ type: "file",
1521
+ multiple: true,
1522
+ tabIndex: -1,
1523
+ "aria-hidden": "true",
1524
+ onChange: (event) => {
1525
+ const files = event.currentTarget.files;
1526
+ if (files && files.length > 0) {
1527
+ void addFiles(files);
1528
+ }
1529
+ event.currentTarget.value = "";
1530
+ }
1531
+ }
1532
+ )
1533
+ ] });
1534
+ };
1535
+
1536
+ // src/components/Chat/chat.input.tsx
1537
+ var import_react11 = require("react");
1538
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1539
+ var ChatInput = ({
1540
+ placeholder = "Message...",
1541
+ expanded = true
1542
+ }) => {
1543
+ const { input, setInput, disabled, submitInput, attachments } = useComposer();
1544
+ const ref = (0, import_react11.useRef)(null);
1545
+ const hasDraft = input.trim().length > 0 || attachments.length > 0;
1546
+ (0, import_react11.useEffect)(() => {
1547
+ const el = ref.current;
1548
+ if (!el) return;
1549
+ if (!expanded) {
1550
+ el.style.height = "";
1551
+ el.style.overflowY = "hidden";
1552
+ return;
1553
+ }
1554
+ el.style.height = "auto";
1555
+ const shell = el.closest(".chat-composer-shell");
1556
+ const isSmall = (shell == null ? void 0 : shell.dataset.variant) === "small";
1557
+ const max = isSmall ? 128 : 320;
1558
+ el.style.height = `${Math.min(el.scrollHeight, max)}px`;
1559
+ el.style.overflowY = el.scrollHeight > max ? "auto" : "hidden";
1560
+ }, [expanded, input]);
1561
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "chat-composer-input", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1562
+ "textarea",
1563
+ {
1564
+ ref,
1565
+ value: input,
1566
+ onChange: (event) => {
1567
+ const wrap = event.currentTarget.closest(`.${motion.inputWrap}`);
1568
+ if (wrap) {
1569
+ clearErrorShake(wrap);
1570
+ }
1571
+ setInput(event.target.value);
1572
+ },
1573
+ placeholder,
1574
+ disabled,
1575
+ rows: 1,
1576
+ onKeyDown: (event) => {
1577
+ if (event.key !== "Enter" || event.shiftKey) return;
1578
+ if (event.nativeEvent.isComposing) return;
1579
+ event.preventDefault();
1580
+ if (disabled) {
1581
+ return;
1582
+ }
1583
+ if (!hasDraft) {
1584
+ const wrap = event.currentTarget.closest(`.${motion.inputWrap}`);
1585
+ if (wrap) {
1586
+ triggerErrorShake(wrap);
1587
+ }
1588
+ return;
1589
+ }
1590
+ void submitInput();
1591
+ }
1592
+ }
1593
+ ) });
1594
+ };
1595
+
1596
+ // src/components/Chat/chat.references.tsx
1597
+ var import_lucide_react3 = require("lucide-react");
1598
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1599
+ var ChatReferences = () => {
1600
+ const { references, removeReference } = useComposer();
1601
+ if (references.length === 0) {
1602
+ return null;
1603
+ }
1604
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "chat-references", children: references.map((reference, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "chat-reference", title: reference.text, children: [
1605
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "chat-reference-text", children: reference.text }),
1606
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1607
+ "button",
1608
+ {
1609
+ type: "button",
1610
+ className: "chat-icon-button",
1611
+ "aria-label": `Remove reference ${index + 1}`,
1612
+ onClick: () => removeReference(reference.id),
1613
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react3.X, { size: 12 })
1614
+ }
1615
+ )
1616
+ ] }, reference.id)) });
1617
+ };
1618
+
1619
+ // src/components/Chat/chat.send.tsx
1620
+ var import_lucide_react4 = require("lucide-react");
1621
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1622
+ var ChatSend = () => {
1623
+ const { canSend, submitInput } = useComposer();
1624
+ const { status, stopResponse, isSending } = useMessages();
1625
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1626
+ "button",
1627
+ {
1628
+ className: "chat-send",
1629
+ type: "button",
1630
+ "data-state": isSending ? "stop" : "send",
1631
+ onClick: isSending ? stopResponse : submitInput,
1632
+ disabled: isSending ? false : !canSend,
1633
+ "aria-label": isSending ? "Stop response" : "Send message",
1634
+ children: isSending ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Square, { size: 14, fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Send, { size: 16 })
1635
+ }
1636
+ );
1637
+ };
1638
+
1639
+ // src/components/Chat/chat.select.tsx
1640
+ var import_react12 = require("react");
1641
+
1642
+ // src/ui/select.tsx
1643
+ var import_lucide_react5 = require("lucide-react");
1644
+ var import_radix_ui = require("radix-ui");
1645
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1646
+ function Select({
1647
+ ...props
1648
+ }) {
1649
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_radix_ui.Select.Root, { "data-slot": "select", ...props });
1650
+ }
1651
+ function SelectGroup({
1652
+ ...props
1653
+ }) {
1654
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_radix_ui.Select.Group, { "data-slot": "select-group", ...props });
1655
+ }
1656
+ function SelectTrigger({
1657
+ className,
1658
+ size = "default",
1659
+ children,
1660
+ ...props
1661
+ }) {
1662
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1663
+ import_radix_ui.Select.Trigger,
1664
+ {
1665
+ "data-slot": "select-trigger",
1666
+ "data-size": size,
1667
+ className: cn(
1668
+ "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1669
+ className
1670
+ ),
1671
+ ...props,
1672
+ children: [
1673
+ children,
1674
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_radix_ui.Select.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.ChevronDownIcon, { className: "size-4 opacity-50" }) })
1675
+ ]
1676
+ }
1677
+ );
1678
+ }
1679
+ function SelectContent({
1680
+ className,
1681
+ children,
1682
+ portalContainer,
1683
+ position = "item-aligned",
1684
+ align = "center",
1685
+ ...props
1686
+ }) {
1687
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_radix_ui.Select.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1688
+ import_radix_ui.Select.Content,
1689
+ {
1690
+ "data-slot": "select-content",
1691
+ className: cn(
1692
+ "bg-popover text-popover-foreground relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
1693
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
1694
+ className
1695
+ ),
1696
+ position,
1697
+ align,
1698
+ ...props,
1699
+ children: [
1700
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SelectScrollUpButton, {}),
1701
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1702
+ import_radix_ui.Select.Viewport,
1703
+ {
1704
+ "data-slot": "select-viewport",
1705
+ className: cn(
1706
+ "p-1",
1707
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
1708
+ ),
1709
+ children
1710
+ }
1711
+ ),
1712
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SelectScrollDownButton, {})
1713
+ ]
1714
+ }
1715
+ ) });
1716
+ }
1717
+ function SelectLabel({
1718
+ className,
1719
+ ...props
1720
+ }) {
1721
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1722
+ import_radix_ui.Select.Label,
1723
+ {
1724
+ "data-slot": "select-label",
1725
+ className: cn("text-muted-foreground px-2 py-1.5 text-xs", className),
1726
+ ...props
1727
+ }
1728
+ );
1729
+ }
1730
+ function SelectItem({
1731
+ className,
1732
+ children,
1733
+ ...props
1734
+ }) {
1735
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1736
+ import_radix_ui.Select.Item,
1737
+ {
1738
+ "data-slot": "select-item",
1739
+ className: cn(
1740
+ "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
1741
+ className
1742
+ ),
1743
+ ...props,
1744
+ children: [
1745
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1746
+ "span",
1747
+ {
1748
+ "data-slot": "select-item-indicator",
1749
+ className: "absolute right-2 flex size-3.5 items-center justify-center",
1750
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_radix_ui.Select.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.CheckIcon, { className: "size-4" }) })
1751
+ }
1752
+ ),
1753
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_radix_ui.Select.ItemText, { children })
1754
+ ]
1755
+ }
1756
+ );
1757
+ }
1758
+ function SelectScrollUpButton({
1759
+ className,
1760
+ ...props
1761
+ }) {
1762
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1763
+ import_radix_ui.Select.ScrollUpButton,
1764
+ {
1765
+ "data-slot": "select-scroll-up-button",
1766
+ className: cn(
1767
+ "flex cursor-default items-center justify-center py-1",
1768
+ className
1769
+ ),
1770
+ ...props,
1771
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.ChevronUpIcon, { className: "size-4" })
1772
+ }
1773
+ );
1774
+ }
1775
+ function SelectScrollDownButton({
1776
+ className,
1777
+ ...props
1778
+ }) {
1779
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1780
+ import_radix_ui.Select.ScrollDownButton,
1781
+ {
1782
+ "data-slot": "select-scroll-down-button",
1783
+ className: cn(
1784
+ "flex cursor-default items-center justify-center py-1",
1785
+ className
1786
+ ),
1787
+ ...props,
1788
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.ChevronDownIcon, { className: "size-4" })
1789
+ }
1790
+ );
1791
+ }
1792
+
1793
+ // src/components/Chat/chat.select.tsx
1794
+ var import_lucide_react6 = require("lucide-react");
1795
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1796
+ var SELECT_ORIGIN = "top-left";
1797
+ var THINKING_ORIGIN = "top-right";
1798
+ var ProviderBadge = ({ logo, name }) => {
1799
+ if (logo) {
1800
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1801
+ "img",
1802
+ {
1803
+ className: "chat-model-provider-logo",
1804
+ src: logo,
1805
+ alt: "",
1806
+ "aria-hidden": "true"
1807
+ }
1808
+ );
1809
+ }
1810
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "chat-model-provider-logo chat-model-provider-fallback", "aria-hidden": "true", children: name.slice(0, 1) });
1811
+ };
1812
+ var ChatSelect = () => {
1813
+ var _a, _b, _c;
1814
+ const { provider, model, registry, setProvider, getThinkingLevel, setThinkingLevel } = useModel();
1815
+ const { isSending } = useMessages();
1816
+ const [portalContainer, setPortalContainer] = (0, import_react12.useState)(null);
1817
+ const [query, setQuery] = (0, import_react12.useState)("");
1818
+ const [thinkingOpen, setThinkingOpen] = (0, import_react12.useState)(null);
1819
+ const [menuOpen, setMenuOpen] = (0, import_react12.useState)(false);
1820
+ const rootRef = (0, import_react12.useRef)(null);
1821
+ const menu = useDropdownPresence(menuOpen, rootRef);
1822
+ const selectedValue = `${provider}::${model}`;
1823
+ const selectedProvider = registry.providers.find((entry) => entry.id === provider);
1824
+ const selectedModel = selectedProvider == null ? void 0 : selectedProvider.models.find((entry) => entry.id === model);
1825
+ const providerName = (_b = (_a = selectedProvider == null ? void 0 : selectedProvider.name) != null ? _a : selectedProvider == null ? void 0 : selectedProvider.label) != null ? _b : provider;
1826
+ const modelLabel = (_c = selectedModel == null ? void 0 : selectedModel.label) != null ? _c : model || "Loading models\u2026";
1827
+ const filteredProviders = (0, import_react12.useMemo)(() => {
1828
+ const q = query.trim().toLowerCase();
1829
+ if (!q) return registry.providers;
1830
+ return registry.providers.map((entry) => ({
1831
+ ...entry,
1832
+ models: entry.models.filter(
1833
+ (item) => item.label.toLowerCase().includes(q) || item.id.toLowerCase().includes(q) || item.description && item.description.toLowerCase().includes(q) || entry.label.toLowerCase().includes(q)
1834
+ )
1835
+ })).filter((entry) => entry.models.length > 0);
1836
+ }, [registry.providers, query]);
1837
+ const setRootElement = (0, import_react12.useCallback)((node) => {
1838
+ const found = node == null ? void 0 : node.closest(".chat-root");
1839
+ rootRef.current = found instanceof HTMLElement ? found : null;
1840
+ setPortalContainer(found instanceof HTMLElement ? found : null);
1841
+ }, []);
1842
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: setRootElement, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1843
+ Select,
1844
+ {
1845
+ open: menuOpen || menu.mounted,
1846
+ onOpenChange: setMenuOpen,
1847
+ value: selectedValue,
1848
+ onValueChange: (value) => {
1849
+ const separator = value.indexOf("::");
1850
+ if (separator <= 0) {
1851
+ return;
1852
+ }
1853
+ const nextProvider = value.slice(0, separator);
1854
+ const nextModel = value.slice(separator + 2);
1855
+ const match = registry.providers.find((entry) => entry.id === nextProvider);
1856
+ if (!match || !nextModel) {
1857
+ return;
1858
+ }
1859
+ setProvider(match.id, nextModel);
1860
+ },
1861
+ disabled: isSending,
1862
+ children: [
1863
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SelectTrigger, { className: "chat-model-trigger", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "chat-model-selected", children: [
1864
+ selectedModel ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ProviderBadge, { logo: selectedProvider == null ? void 0 : selectedProvider.logo, name: providerName }) : null,
1865
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: modelLabel })
1866
+ ] }) }),
1867
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1868
+ SelectContent,
1869
+ {
1870
+ align: "start",
1871
+ position: "popper",
1872
+ sideOffset: 6,
1873
+ collisionPadding: 12,
1874
+ className: cn("chat-model-content", motion.dropdown, menu.className),
1875
+ "data-origin": SELECT_ORIGIN,
1876
+ portalContainer,
1877
+ onCloseAutoFocus: (event) => {
1878
+ event.preventDefault();
1879
+ setQuery("");
1880
+ setThinkingOpen(null);
1881
+ },
1882
+ onPointerDownOutside: () => setThinkingOpen(null),
1883
+ children: [
1884
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "chat-model-search", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1885
+ "input",
1886
+ {
1887
+ autoFocus: true,
1888
+ placeholder: "Search models",
1889
+ value: query,
1890
+ onChange: (event) => setQuery(event.target.value),
1891
+ onKeyDown: (event) => event.stopPropagation(),
1892
+ className: "chat-model-search-input"
1893
+ }
1894
+ ) }),
1895
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "chat-model-list", children: filteredProviders.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "chat-model-empty", children: "No models found" }) : filteredProviders.map((entry) => {
1896
+ var _a2;
1897
+ const providerName2 = (_a2 = entry.name) != null ? _a2 : entry.label;
1898
+ const hideLabel = filteredProviders.length === 1;
1899
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react12.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(SelectGroup, { className: "chat-model-group", children: [
1900
+ hideLabel ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(SelectLabel, { className: "chat-model-label", children: [
1901
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ProviderBadge, { logo: entry.logo, name: providerName2 }),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: providerName2 })
1903
+ ] }),
1904
+ entry.models.map((item) => {
1905
+ var _a3;
1906
+ const key = `${entry.id}::${item.id}`;
1907
+ const levels = item.thinkingLevels;
1908
+ const defaultThinking = levels && levels.length > 0 ? levels.includes("medium") ? "medium" : levels[0] : void 0;
1909
+ const thinking = defaultThinking && levels ? { levels } : void 0;
1910
+ const activeThinking = defaultThinking ? (_a3 = getThinkingLevel(entry.id, item.id)) != null ? _a3 : defaultThinking : void 0;
1911
+ const isOpen = thinkingOpen === key;
1912
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1913
+ ModelRow,
1914
+ {
1915
+ itemKey: key,
1916
+ item,
1917
+ thinking,
1918
+ activeThinking,
1919
+ isOpen,
1920
+ onToggleThinking: () => setThinkingOpen(isOpen ? null : key),
1921
+ onPickThinking: (level) => {
1922
+ setThinkingLevel(entry.id, item.id, level);
1923
+ setThinkingOpen(null);
1924
+ }
1925
+ },
1926
+ key
1927
+ );
1928
+ })
1929
+ ] }) }, entry.id);
1930
+ }) })
1931
+ ]
1932
+ }
1933
+ )
1934
+ ]
1935
+ }
1936
+ ) });
1937
+ };
1938
+ var ModelRow = ({
1939
+ itemKey,
1940
+ item,
1941
+ thinking,
1942
+ activeThinking,
1943
+ isOpen,
1944
+ onToggleThinking,
1945
+ onPickThinking
1946
+ }) => {
1947
+ const menu = useDropdownPresence(isOpen);
1948
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "chat-model-row", children: [
1949
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(SelectItem, { value: itemKey, className: "chat-model-item", children: [
1950
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "chat-model-item-label", children: item.label }),
1951
+ item.description ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "chat-model-item-hint", children: item.description }) : thinking && activeThinking ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "chat-model-item-hint", children: activeThinking }) : null
1952
+ ] }),
1953
+ thinking ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1954
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1955
+ "button",
1956
+ {
1957
+ type: "button",
1958
+ "aria-label": "Thinking settings",
1959
+ className: "chat-model-thinking-trigger",
1960
+ "data-open": isOpen ? "true" : "false",
1961
+ onPointerDown: (event) => {
1962
+ event.preventDefault();
1963
+ event.stopPropagation();
1964
+ },
1965
+ onClick: (event) => {
1966
+ event.preventDefault();
1967
+ event.stopPropagation();
1968
+ onToggleThinking();
1969
+ },
1970
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.Ellipsis, { className: "chat-model-thinking-icon" })
1971
+ }
1972
+ ),
1973
+ menu.mounted ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1974
+ "div",
1975
+ {
1976
+ className: cn("chat-model-thinking-menu", motion.dropdown, menu.className),
1977
+ "data-origin": THINKING_ORIGIN,
1978
+ onPointerDown: (event) => event.stopPropagation(),
1979
+ onClick: (event) => event.stopPropagation(),
1980
+ children: thinking.levels.map((level) => {
1981
+ const isActive = level === activeThinking;
1982
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1983
+ "button",
1984
+ {
1985
+ type: "button",
1986
+ className: "chat-model-thinking-option",
1987
+ "data-active": isActive ? "true" : "false",
1988
+ onClick: (event) => {
1989
+ event.preventDefault();
1990
+ event.stopPropagation();
1991
+ onPickThinking(level);
1992
+ },
1993
+ children: [
1994
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: level }),
1995
+ isActive ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.Check, { className: "chat-model-thinking-check" }) : null
1996
+ ]
1997
+ },
1998
+ level
1999
+ );
2000
+ })
2001
+ }
2002
+ ) : null
2003
+ ] }) : null
2004
+ ] });
2005
+ };
2006
+
2007
+ // src/components/Chat/chat.tsx
2008
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2009
+ var focusStaysInComposer = (shell, node) => {
2010
+ if (node && shell.contains(node)) {
2011
+ return true;
2012
+ }
2013
+ return node instanceof Element && node.closest("[data-slot='select-content']") !== null;
2014
+ };
2015
+ var ChatComposer = ({
2016
+ showModelSelector = true,
2017
+ collapsedVariant = "pill",
2018
+ defaultExpanded = false
2019
+ }) => {
2020
+ const { status } = useMessages();
2021
+ const { input, attachments, references } = useComposer();
2022
+ const shellRef = (0, import_react13.useRef)(null);
2023
+ const [focused, setFocused] = (0, import_react13.useState)(defaultExpanded);
2024
+ const expanded = focused || input.trim().length > 0 || attachments.length > 0 || references.length > 0;
2025
+ (0, import_react13.useEffect)(() => {
2026
+ if (status !== "error" || !shellRef.current) {
2027
+ return;
2028
+ }
2029
+ triggerErrorShake(shellRef.current);
2030
+ }, [status]);
2031
+ (0, import_react13.useEffect)(() => {
2032
+ if (!focused) {
2033
+ return;
2034
+ }
2035
+ const onFocusIn = () => {
2036
+ const shell = shellRef.current;
2037
+ if (!shell) {
2038
+ return;
2039
+ }
2040
+ if (focusStaysInComposer(shell, document.activeElement)) {
2041
+ return;
2042
+ }
2043
+ setFocused(false);
2044
+ };
2045
+ document.addEventListener("focusin", onFocusIn, true);
2046
+ return () => document.removeEventListener("focusin", onFocusIn, true);
2047
+ }, [focused]);
2048
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2049
+ "div",
2050
+ {
2051
+ ref: shellRef,
2052
+ className: cn("chat-composer-shell", motion.inputWrap, motion.input),
2053
+ "data-expanded": expanded ? "true" : "false",
2054
+ "data-collapsed": collapsedVariant,
2055
+ onFocus: () => setFocused(true),
2056
+ onBlur: (event) => {
2057
+ const shell = event.currentTarget;
2058
+ const next = event.relatedTarget;
2059
+ if (next instanceof Node && focusStaysInComposer(shell, next)) {
2060
+ return;
2061
+ }
2062
+ window.setTimeout(() => {
2063
+ if (focusStaysInComposer(shell, document.activeElement)) {
2064
+ return;
2065
+ }
2066
+ setFocused(false);
2067
+ }, 0);
2068
+ },
2069
+ children: [
2070
+ expanded || collapsedVariant !== "circle" ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react7.MessageCircle, { className: "chat-composer-collapsed-icon", size: 18, "aria-hidden": "true" }),
2071
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatAttachments, {}),
2072
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatReferences, {}),
2073
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatInput, { expanded }),
2074
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "chat-composer-row", children: [
2075
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "chat-composer-tools", children: [
2076
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatAttachButton, {}),
2077
+ showModelSelector && expanded && collapsedVariant === "circle" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatSelect, {}) : null
2078
+ ] }),
2079
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatSend, {})
2080
+ ] })
2081
+ ]
2082
+ }
2083
+ );
2084
+ };
2085
+
2086
+ // src/components/Message/message.item.tsx
2087
+ var import_lucide_react18 = require("lucide-react");
2088
+ var import_react29 = require("react");
2089
+ var import_protocol5 = require("@sarchauhan/protocol");
2090
+
2091
+ // src/components/Message/message.content.tsx
2092
+ var import_protocol3 = require("@sarchauhan/protocol");
2093
+ var import_lucide_react14 = require("lucide-react");
2094
+ var import_react26 = require("react");
2095
+
2096
+ // src/lib/message/segment.ts
2097
+ var splitThinkingSegments = (content) => {
2098
+ const segments = [];
2099
+ let cursor = 0;
2100
+ while (cursor < content.length) {
2101
+ const openingIndex = content.indexOf("<thinking>", cursor);
2102
+ if (openingIndex === -1) {
2103
+ segments.push({
2104
+ type: "markdown",
2105
+ content: content.slice(cursor)
2106
+ });
2107
+ break;
2108
+ }
2109
+ if (openingIndex > cursor) {
2110
+ segments.push({
2111
+ type: "markdown",
2112
+ content: content.slice(cursor, openingIndex)
2113
+ });
2114
+ }
2115
+ const thinkingStart = openingIndex + "<thinking>".length;
2116
+ const closingIndex = content.indexOf("</thinking>", thinkingStart);
2117
+ if (closingIndex === -1) {
2118
+ segments.push({
2119
+ type: "thinking",
2120
+ content: content.slice(thinkingStart).trim(),
2121
+ isComplete: false
2122
+ });
2123
+ break;
2124
+ }
2125
+ segments.push({
2126
+ type: "thinking",
2127
+ content: content.slice(thinkingStart, closingIndex).trim(),
2128
+ isComplete: true
2129
+ });
2130
+ cursor = closingIndex + "</thinking>".length;
2131
+ }
2132
+ if (!segments.length) {
2133
+ return [{ type: "markdown", content }];
2134
+ }
2135
+ return segments;
2136
+ };
2137
+
2138
+ // src/widgets/artifact.tsx
2139
+ var import_react15 = require("react");
2140
+ var import_lucide_react9 = require("lucide-react");
2141
+
2142
+ // src/widgets/responsive-detail.tsx
2143
+ var import_react14 = require("react");
2144
+ var import_radix_ui2 = require("radix-ui");
2145
+ var import_lucide_react8 = require("lucide-react");
2146
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2147
+ function ResponsiveDetail({ title, description = "Details from this conversation", trigger, children }) {
2148
+ const origin = (0, import_react14.useRef)(null);
2149
+ const [presentation, setPresentation] = (0, import_react14.useState)({ theme: "light", style: {} });
2150
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: origin, className: "chat-detail-origin", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_radix_ui2.Dialog.Root, { onOpenChange: (open) => {
2151
+ var _a, _b;
2152
+ if (!open || !origin.current) return;
2153
+ const host = (_a = origin.current.closest(".chat-root")) != null ? _a : origin.current;
2154
+ const computed = window.getComputedStyle(host);
2155
+ const tokens = {};
2156
+ for (let index = 0; index < computed.length; index++) {
2157
+ const name = computed.item(index);
2158
+ if (name.startsWith("--chat-")) tokens[name] = computed.getPropertyValue(name);
2159
+ }
2160
+ const requested = host.getAttribute("data-theme");
2161
+ const dark = requested === "dark" || requested === "system" && ((_b = window.matchMedia) == null ? void 0 : _b.call(window, "(prefers-color-scheme: dark)").matches);
2162
+ setPresentation({ theme: dark ? "dark" : "light", style: tokens });
2163
+ }, children: [
2164
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_radix_ui2.Dialog.Trigger, { asChild: true, children: trigger }),
2165
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_radix_ui2.Dialog.Portal, { children: [
2166
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_radix_ui2.Dialog.Overlay, { className: "chat-detail-overlay" }),
2167
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_radix_ui2.Dialog.Content, { className: "chat-root chat-detail-panel", "data-theme": presentation.theme, style: presentation.style, children: [
2168
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "chat-detail-handle", "aria-hidden": "true" }),
2169
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("header", { className: "chat-detail-header", children: [
2170
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
2171
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_radix_ui2.Dialog.Title, { className: "chat-detail-title", children: title }),
2172
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_radix_ui2.Dialog.Description, { className: "chat-detail-description", children: description })
2173
+ ] }),
2174
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_radix_ui2.Dialog.Close, { className: "chat-detail-close", "aria-label": "Close details", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react8.X, { size: 18, "aria-hidden": "true" }) })
2175
+ ] }),
2176
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "chat-detail-body", children })
2177
+ ] })
2178
+ ] })
2179
+ ] }) });
2180
+ }
2181
+
2182
+ // src/widgets/artifact.tsx
2183
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2184
+ function safeArtifactUrl(value, image = false) {
2185
+ if (!value || /[\u0000-\u0020\u007f]/.test(value)) return void 0;
2186
+ if (/^blob:/i.test(value)) {
2187
+ try {
2188
+ new URL(value);
2189
+ return value;
2190
+ } catch {
2191
+ return void 0;
2192
+ }
2193
+ }
2194
+ if (image && /^data:image\/(?:png|jpeg|gif|webp|avif);base64,[a-z0-9+/=]+$/i.test(value)) return value;
2195
+ try {
2196
+ const parsed = new URL(value, "https://chat.invalid");
2197
+ if (!["https:", "http:"].includes(parsed.protocol)) return void 0;
2198
+ return value;
2199
+ } catch {
2200
+ return void 0;
2201
+ }
2202
+ }
2203
+ function formatArtifactSize(bytes) {
2204
+ if (bytes === void 0 || !Number.isFinite(bytes) || bytes < 0) return void 0;
2205
+ if (bytes < 1024) return bytes + " B";
2206
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
2207
+ return (bytes / (1024 * 1024)).toFixed(1) + " MB";
2208
+ }
2209
+ function ArtifactWidget({ artifact, className = "" }) {
2210
+ var _a;
2211
+ const { filename, mediaType, content, sizeBytes, error } = artifact;
2212
+ const state = (_a = artifact.status) != null ? _a : "ready";
2213
+ const image = mediaType.startsWith("image/");
2214
+ const [failedUrl, setFailedUrl] = (0, import_react15.useState)();
2215
+ const previewUrl = image ? safeArtifactUrl(artifact.url, true) : void 0;
2216
+ const link = safeArtifactUrl(artifact.url, image);
2217
+ const ready = state === "ready";
2218
+ const preview = ready && (previewUrl && failedUrl !== previewUrl || content !== void 0);
2219
+ const Icon = image ? import_lucide_react9.Image : import_lucide_react9.FileText;
2220
+ const label = state === "creating" ? "Creating\u2026" : state === "error" ? "Could not create file" : "Created";
2221
+ const metadata = [mediaType, formatArtifactSize(sizeBytes)].filter(Boolean).join(" \xB7 ");
2222
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "chat-prebuilt chat-artifact " + className, "aria-label": "Artifact: " + filename, "data-state": state, children: [
2223
+ ready && previewUrl && failedUrl !== previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "chat-artifact-thumbnail", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("img", { src: previewUrl, alt: filename, loading: "lazy", onError: () => setFailedUrl(previewUrl) }) }) : null,
2224
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "chat-artifact-row", children: [
2225
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "chat-artifact-icon", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { size: 20, "aria-hidden": "true" }) }),
2226
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "chat-artifact-heading", children: [
2227
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { title: filename, children: filename }),
2228
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: metadata })
2229
+ ] }),
2230
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "chat-artifact-state", role: "status", children: label })
2231
+ ] }),
2232
+ state === "error" && error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : null,
2233
+ ready && image && previewUrl && failedUrl === previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "chat-widget-empty", children: "Image preview unavailable." }) : null,
2234
+ ready && (preview || link) ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("footer", { className: "chat-artifact-actions", children: [
2235
+ preview ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ResponsiveDetail, { title: filename, description: metadata, trigger: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", children: "Preview" }), children: image && previewUrl && failedUrl !== previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("img", { className: "chat-artifact-full-image", src: previewUrl, alt: filename, onError: () => setFailedUrl(previewUrl) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { className: "chat-artifact-text", tabIndex: 0, children: content }) }) : null,
2236
+ link ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2237
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("a", { href: link, target: "_blank", rel: "noreferrer", children: [
2238
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.ExternalLink, { size: 14, "aria-hidden": "true" }),
2239
+ "Open"
2240
+ ] }),
2241
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("a", { href: link, download: filename, target: "_blank", rel: "noreferrer", children: [
2242
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.Download, { size: 14, "aria-hidden": "true" }),
2243
+ "Download"
2244
+ ] })
2245
+ ] }) : null
2246
+ ] }) : null
2247
+ ] });
2248
+ }
2249
+ function ArtifactsWidget({ artifacts, className = "" }) {
2250
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "chat-artifacts " + className, children: artifacts.map((artifact) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactWidget, { artifact }, artifact.id)) });
2251
+ }
2252
+
2253
+ // src/widgets/compute.ts
2254
+ var import_protocol = require("@sarchauhan/protocol");
2255
+ var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
2256
+ var string = (...values) => values.find((value) => typeof value === "string");
2257
+ var number = (...values) => values.find(
2258
+ (value) => typeof value === "number" && Number.isFinite(value)
2259
+ );
2260
+ var aliases = {
2261
+ read: "read-file",
2262
+ read_file: "read-file",
2263
+ readFile: "read-file",
2264
+ "read-file": "read-file",
2265
+ patch: "patch",
2266
+ apply_patch: "patch",
2267
+ edit_file: "patch",
2268
+ edit: "patch",
2269
+ search: "search",
2270
+ grep: "search",
2271
+ file_search: "search",
2272
+ web_search: "search",
2273
+ question: "question",
2274
+ ask_question: "question"
2275
+ };
2276
+ function computeToolState(part) {
2277
+ if (part.state === "output-error") return "error";
2278
+ if (part.state === "output-denied") return "denied";
2279
+ if (part.state === "approval-requested") return "approval";
2280
+ return part.state === "output-available" && !part.preliminary ? "complete" : "running";
2281
+ }
2282
+ function normalizeSearchResults(value) {
2283
+ if (!Array.isArray(value)) return [];
2284
+ return value.flatMap((item) => {
2285
+ const result = record(item);
2286
+ const path = string(result.path, result.file, result.url);
2287
+ if (!path) return [];
2288
+ return [
2289
+ {
2290
+ path,
2291
+ line: number(result.line, result.lineNumber),
2292
+ text: string(result.text, result.snippet, result.content),
2293
+ title: string(result.title),
2294
+ url: string(result.url)
2295
+ }
2296
+ ];
2297
+ });
2298
+ }
2299
+ function computeToolWidget(part) {
2300
+ var _a, _b, _c;
2301
+ const name = aliases[part.toolName];
2302
+ if (!name) {
2303
+ const output2 = record(part.output);
2304
+ if (part.state !== "output-available") return null;
2305
+ if (Array.isArray(output2.artifacts)) {
2306
+ const artifacts = output2.artifacts.flatMap((value) => {
2307
+ const artifact2 = (0, import_protocol.parseArtifact)(value);
2308
+ return artifact2 ? [artifact2] : [];
2309
+ });
2310
+ return artifacts.length ? { type: "widget", name: "artifacts", id: part.toolCallId, props: { artifacts } } : null;
2311
+ }
2312
+ const artifact = (0, import_protocol.parseArtifact)(output2.artifact);
2313
+ return artifact ? { type: "widget", name: "artifact", id: part.toolCallId, props: { artifact } } : null;
2314
+ }
2315
+ const input = record(part.input), output = record(part.output);
2316
+ const values = { ...input, ...output };
2317
+ const common2 = { state: computeToolState(part), error: part.errorText };
2318
+ let props;
2319
+ if (name === "read-file") {
2320
+ const path = string(
2321
+ values.path,
2322
+ values.file,
2323
+ values.filename,
2324
+ values.file_path
2325
+ );
2326
+ if (!path) return null;
2327
+ props = {
2328
+ ...common2,
2329
+ path,
2330
+ content: string(output.content, output.text, part.output),
2331
+ startLine: number(values.startLine, values.start_line, values.offset),
2332
+ language: string(values.language)
2333
+ };
2334
+ if (part.state === "output-available" && props.content === void 0)
2335
+ return null;
2336
+ } else if (name === "patch") {
2337
+ const before = string(values.before, values.old_string, values.oldText);
2338
+ const after = string(values.after, values.new_string, values.newText);
2339
+ const diff = (_a = string(
2340
+ output.diff,
2341
+ output.patch,
2342
+ input.diff,
2343
+ input.patch,
2344
+ part.input,
2345
+ part.output
2346
+ )) != null ? _a : before !== void 0 && after !== void 0 ? computeTextDiff(
2347
+ before,
2348
+ after,
2349
+ string(values.path, values.file_path, "file")
2350
+ ) : void 0;
2351
+ if (diff === void 0 || diff && !/^(@@|diff --git|--- |\*\*\* Begin Patch)/m.test(diff))
2352
+ return null;
2353
+ props = {
2354
+ ...common2,
2355
+ path: string(values.path, values.file, values.file_path),
2356
+ diff
2357
+ };
2358
+ } else if (name === "search") {
2359
+ const query = string(values.query, values.pattern, values.search);
2360
+ if (query === void 0) return null;
2361
+ const results = (_c = (_b = output.results) != null ? _b : output.matches) != null ? _c : Array.isArray(part.output) ? part.output : void 0;
2362
+ if (part.state === "output-available" && !Array.isArray(results))
2363
+ return null;
2364
+ props = {
2365
+ ...common2,
2366
+ query,
2367
+ results: normalizeSearchResults(results),
2368
+ total: number(output.total, output.totalCount)
2369
+ };
2370
+ } else {
2371
+ if (["output-error", "output-denied", "approval-requested"].includes(
2372
+ part.state
2373
+ ))
2374
+ return null;
2375
+ const prompt = string(input.prompt, input.question);
2376
+ if (!prompt) return null;
2377
+ props = { ...input, prompt };
2378
+ }
2379
+ return {
2380
+ type: "widget",
2381
+ name,
2382
+ id: part.toolCallId,
2383
+ props,
2384
+ interactive: name === "question" && part.state === "input-available"
2385
+ };
2386
+ }
2387
+ function computeDiff(diff) {
2388
+ let oldLine = 0, newLine = 0, inHunk = false, oldRemaining = 0, newRemaining = 0, additions = 0, deletions = 0;
2389
+ const lines = diff.replace(/\r\n/g, "\n").split("\n").map((text) => {
2390
+ var _a, _b;
2391
+ const hunk = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(text);
2392
+ if (hunk) {
2393
+ oldLine = Number(hunk[1]);
2394
+ newLine = Number(hunk[3]);
2395
+ oldRemaining = Number((_a = hunk[2]) != null ? _a : 1);
2396
+ newRemaining = Number((_b = hunk[4]) != null ? _b : 1);
2397
+ inHunk = true;
2398
+ return { kind: "header", text };
2399
+ }
2400
+ if (oldRemaining === 0 && newRemaining === 0) inHunk = false;
2401
+ if (!inHunk && /^(diff --git|--- |\+\+\+ |\*\*\* )/.test(text)) {
2402
+ inHunk = false;
2403
+ return { kind: "header", text };
2404
+ }
2405
+ if (text.startsWith("@@")) {
2406
+ inHunk = false;
2407
+ return { kind: "header", text };
2408
+ }
2409
+ if (text.startsWith("+")) {
2410
+ additions++;
2411
+ if (inHunk) newRemaining--;
2412
+ return { kind: "add", text, newLine: inHunk ? newLine++ : void 0 };
2413
+ }
2414
+ if (text.startsWith("-")) {
2415
+ deletions++;
2416
+ if (inHunk) oldRemaining--;
2417
+ return {
2418
+ kind: "remove",
2419
+ text,
2420
+ oldLine: inHunk ? oldLine++ : void 0
2421
+ };
2422
+ }
2423
+ if (inHunk && text.startsWith(" ")) {
2424
+ oldRemaining--;
2425
+ newRemaining--;
2426
+ return {
2427
+ kind: "context",
2428
+ text,
2429
+ oldLine: oldLine++,
2430
+ newLine: newLine++
2431
+ };
2432
+ }
2433
+ return { kind: "header", text };
2434
+ });
2435
+ return { lines, additions, deletions };
2436
+ }
2437
+ function safeResultUrl(url) {
2438
+ try {
2439
+ const parsed = new URL(url != null ? url : "");
2440
+ return ["https:", "http:"].includes(parsed.protocol) ? parsed.href : void 0;
2441
+ } catch {
2442
+ return void 0;
2443
+ }
2444
+ }
2445
+ function computeTextDiff(before, after, path = "file") {
2446
+ if (before === after) return "";
2447
+ const split = (text) => text === "" ? [] : text.replace(/\r\n/g, "\n").replace(/\n$/, "").split("\n");
2448
+ const oldLines = split(before), newLines = split(after);
2449
+ let prefix = 0, suffix = 0;
2450
+ while (prefix < oldLines.length && prefix < newLines.length && oldLines[prefix] === newLines[prefix])
2451
+ prefix++;
2452
+ while (suffix < oldLines.length - prefix && suffix < newLines.length - prefix && oldLines[oldLines.length - 1 - suffix] === newLines[newLines.length - 1 - suffix])
2453
+ suffix++;
2454
+ if (before.endsWith("\n") !== after.endsWith("\n")) suffix = 0;
2455
+ if (prefix === oldLines.length && prefix === newLines.length) {
2456
+ prefix = Math.max(0, prefix - 1);
2457
+ suffix = 0;
2458
+ }
2459
+ const start = Math.max(0, prefix - 3), tail = Math.min(3, suffix);
2460
+ const oldEnd = oldLines.length - suffix, newEnd = newLines.length - suffix;
2461
+ const oldCount = oldEnd + tail - start, newCount = newEnd + tail - start;
2462
+ const label = path.replace(/[\r\n]/g, "");
2463
+ const body = [
2464
+ ...oldLines.slice(start, prefix).map((line) => " " + line),
2465
+ ...oldLines.slice(prefix, oldEnd).flatMap((line, index) => [
2466
+ "-" + line,
2467
+ ...prefix + index === oldLines.length - 1 && !before.endsWith("\n") ? ["\"] : []
2468
+ ]),
2469
+ ...newLines.slice(prefix, newEnd).flatMap((line, index) => [
2470
+ "+" + line,
2471
+ ...prefix + index === newLines.length - 1 && !after.endsWith("\n") ? ["\"] : []
2472
+ ]),
2473
+ ...oldLines.slice(oldEnd, oldEnd + tail).map((line) => " " + line)
2474
+ ];
2475
+ return [
2476
+ `--- a/${label}`,
2477
+ `+++ b/${label}`,
2478
+ `@@ -${oldCount ? start + 1 : start},${oldCount} +${newCount ? start + 1 : start},${newCount} @@`,
2479
+ ...body
2480
+ ].join("\n");
2481
+ }
2482
+
2483
+ // src/widgets/registry.tsx
2484
+ var import_protocol2 = require("@sarchauhan/protocol");
2485
+
2486
+ // src/widgets/subagent.tsx
2487
+ var import_react16 = require("react");
2488
+ var import_lucide_react10 = require("lucide-react");
2489
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2490
+ var Depth = (0, import_react16.createContext)(0);
2491
+ var labels = { queued: "Queued", running: "Working", completed: "Completed", failed: "Failed", cancelled: "Cancelled" };
2492
+ function SubagentWidget({ subagent, className = "" }) {
2493
+ const depth = (0, import_react16.useContext)(Depth);
2494
+ const { title, task, state, summary, progress, messages = [], artifacts = [], error } = subagent;
2495
+ const Icon = state === "completed" ? import_lucide_react10.CircleCheck : state === "failed" ? import_lucide_react10.CircleX : state === "running" ? import_lucide_react10.LoaderCircle : import_lucide_react10.Bot;
2496
+ const canInspect = depth < 3;
2497
+ const transcript = messages.filter((message) => message.role !== "system");
2498
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: "chat-prebuilt chat-subagent " + className, "data-state": state, "aria-label": "Subagent: " + title, children: [
2499
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-subagent-heading", children: [
2500
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "chat-subagent-icon", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Icon, { size: 18, "aria-hidden": "true" }) }),
2501
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
2502
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { children: title }),
2503
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "chat-subagent-state", role: "status", children: labels[state] })
2504
+ ] }),
2505
+ canInspect ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2506
+ ResponsiveDetail,
2507
+ {
2508
+ title,
2509
+ description: task || "Subagent activity in this conversation",
2510
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { className: "chat-subagent-inspect", type: "button", "aria-label": "View activity for " + title, children: [
2511
+ "View activity",
2512
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.ArrowUpRight, { size: 14, "aria-hidden": "true" })
2513
+ ] }),
2514
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Depth.Provider, { value: depth + 1, children: [
2515
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-subagent-overview", children: [
2516
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "chat-subagent-state", children: labels[state] }),
2517
+ progress !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { children: [
2518
+ Math.round(progress * 100),
2519
+ "%"
2520
+ ] }) : null
2521
+ ] }),
2522
+ summary ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-subagent-summary", children: summary }) : null,
2523
+ error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : null,
2524
+ transcript.length ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "chat-subagent-transcript", children: transcript.map((message) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("article", { className: "chat-subagent-message", children: [
2525
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "chat-subagent-role", children: message.role === "user" ? "Task" : title }),
2526
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(MessageContent, { parts: message.parts, isUser: message.role === "user" })
2527
+ ] }, message.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-widget-empty", children: state === "queued" ? "Waiting to start." : state === "running" ? "Activity will appear as the agent works." : "No activity was recorded." }),
2528
+ artifacts.length ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-subagent-artifacts", children: [
2529
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { children: "Created files" }),
2530
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactsWidget, { artifacts })
2531
+ ] }) : null
2532
+ ] })
2533
+ }
2534
+ ) : null
2535
+ ] }),
2536
+ task ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-subagent-task", children: task }) : null,
2537
+ summary ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-subagent-summary", children: summary }) : null,
2538
+ state === "running" && progress !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("progress", { className: "chat-subagent-progress", value: progress, max: 1, "aria-label": "Progress for " + title }) : null,
2539
+ state === "failed" && error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : null
2540
+ ] });
2541
+ }
2542
+
2543
+ // src/widgets/patch.tsx
2544
+ var import_react17 = require("react");
2545
+
2546
+ // src/widgets/tool-frame.tsx
2547
+ var import_lucide_react11 = require("lucide-react");
2548
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2549
+ function ToolFrame({
2550
+ label,
2551
+ title,
2552
+ meta,
2553
+ state = "complete",
2554
+ error,
2555
+ className = "",
2556
+ children
2557
+ }) {
2558
+ const status = {
2559
+ running: "Working",
2560
+ complete: "Done",
2561
+ error: "Failed",
2562
+ denied: "Denied",
2563
+ approval: "Needs approval"
2564
+ }[state];
2565
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2566
+ "details",
2567
+ {
2568
+ className: `chat-prebuilt chat-tool-widget ${className}`,
2569
+ "data-state": state,
2570
+ open: state !== "complete",
2571
+ children: [
2572
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("summary", { children: [
2573
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.ChevronDown, { size: 14, "aria-hidden": "true" }),
2574
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "chat-tool-widget-label", children: label }),
2575
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "chat-tool-widget-title", title, children: title }),
2576
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "chat-tool-widget-meta", children: meta }),
2577
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "chat-tool-widget-status", role: "status", children: status })
2578
+ ] }),
2579
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "chat-tool-widget-body", children: error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : children })
2580
+ ]
2581
+ }
2582
+ );
2583
+ }
2584
+
2585
+ // src/widgets/patch.tsx
2586
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2587
+ function PatchWidget({
2588
+ path = "File changes",
2589
+ diff: rawDiff,
2590
+ before,
2591
+ after,
2592
+ maxLines = 100,
2593
+ ...props
2594
+ }) {
2595
+ const diff = (0, import_react17.useMemo)(
2596
+ () => rawDiff != null ? rawDiff : before !== void 0 && after !== void 0 ? computeTextDiff(before, after, path) : "",
2597
+ [rawDiff, before, after, path]
2598
+ );
2599
+ const [expanded, setExpanded] = (0, import_react17.useState)(false);
2600
+ const { lines, additions, deletions } = (0, import_react17.useMemo)(
2601
+ () => computeDiff(diff),
2602
+ [diff]
2603
+ );
2604
+ const limit = Math.max(1, maxLines);
2605
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2606
+ ToolFrame,
2607
+ {
2608
+ ...props,
2609
+ label: "Patch",
2610
+ title: path,
2611
+ meta: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2612
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "chat-diff-add-count", children: [
2613
+ "+",
2614
+ additions
2615
+ ] }),
2616
+ " ",
2617
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "chat-diff-remove-count", children: [
2618
+ "\u2212",
2619
+ deletions
2620
+ ] })
2621
+ ] }),
2622
+ children: [
2623
+ diff ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2624
+ "div",
2625
+ {
2626
+ className: "chat-code-preview chat-diff",
2627
+ role: "region",
2628
+ "aria-label": `Diff for ${path}`,
2629
+ tabIndex: 0,
2630
+ children: (expanded ? lines : lines.slice(0, limit)).map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "chat-code-line", "data-kind": line.kind, children: [
2631
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "chat-line-number", "aria-hidden": "true", children: line.oldLine }),
2632
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "chat-line-number", "aria-hidden": "true", children: line.newLine }),
2633
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("code", { children: line.text || " " })
2634
+ ] }, index))
2635
+ }
2636
+ ) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "chat-widget-empty", children: "No changes supplied." }),
2637
+ !expanded && lines.length > limit ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2638
+ "button",
2639
+ {
2640
+ className: "chat-widget-more",
2641
+ type: "button",
2642
+ onClick: () => setExpanded(true),
2643
+ children: [
2644
+ "Show full diff (",
2645
+ lines.length,
2646
+ " lines)"
2647
+ ]
2648
+ }
2649
+ ) : null
2650
+ ]
2651
+ }
2652
+ );
2653
+ }
2654
+
2655
+ // src/widgets/question.tsx
2656
+ var import_react18 = require("react");
2657
+ var import_lucide_react12 = require("lucide-react");
2658
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2659
+ function QuestionWidget({
2660
+ prompt,
2661
+ description,
2662
+ options = [],
2663
+ multiple = false,
2664
+ allowCustom = false,
2665
+ disabled = false,
2666
+ onSubmit,
2667
+ className = ""
2668
+ }) {
2669
+ const id = (0, import_react18.useId)();
2670
+ const [selected, setSelected] = (0, import_react18.useState)([]), [text, setText] = (0, import_react18.useState)("");
2671
+ const [status, setStatus] = (0, import_react18.useState)("idle");
2672
+ const [error, setError] = (0, import_react18.useState)();
2673
+ const submitting = (0, import_react18.useRef)(false);
2674
+ const choices = options.map(
2675
+ (option) => typeof option === "string" ? { label: option, value: option } : option
2676
+ );
2677
+ const locked = disabled || status !== "idle" || !onSubmit;
2678
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2679
+ "form",
2680
+ {
2681
+ className: `chat-prebuilt chat-question ${className}`,
2682
+ "aria-labelledby": `${id}-prompt`,
2683
+ onSubmit: async (event) => {
2684
+ event.preventDefault();
2685
+ if (locked || submitting.current || !selected.length && !text.trim())
2686
+ return;
2687
+ submitting.current = true;
2688
+ setStatus("sending");
2689
+ setError(void 0);
2690
+ try {
2691
+ await (onSubmit == null ? void 0 : onSubmit({
2692
+ values: selected,
2693
+ ...text.trim() ? { text: text.trim() } : {}
2694
+ }));
2695
+ setStatus("sent");
2696
+ } catch (cause) {
2697
+ setError(
2698
+ cause instanceof Error ? cause.message : "Could not send your answer. Try again."
2699
+ );
2700
+ setStatus("idle");
2701
+ } finally {
2702
+ submitting.current = false;
2703
+ }
2704
+ },
2705
+ children: [
2706
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-question-eyebrow", children: "Your input" }),
2707
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { id: `${id}-prompt`, children: prompt }),
2708
+ description ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "chat-question-description", children: description }) : null,
2709
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("fieldset", { disabled: locked, children: [
2710
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("legend", { className: "chat-sr-only", children: multiple ? "Select one or more options" : "Select an option" }),
2711
+ choices.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2712
+ "label",
2713
+ {
2714
+ className: "chat-question-option",
2715
+ "data-selected": selected.includes(option.value),
2716
+ children: [
2717
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2718
+ "input",
2719
+ {
2720
+ type: multiple ? "checkbox" : "radio",
2721
+ name: id,
2722
+ value: option.value,
2723
+ checked: selected.includes(option.value),
2724
+ onChange: () => setSelected(
2725
+ (current) => multiple ? current.includes(option.value) ? current.filter((value) => value !== option.value) : [...current, option.value] : [option.value]
2726
+ )
2727
+ }
2728
+ ),
2729
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { children: [
2730
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "chat-question-option-title", children: [
2731
+ option.label,
2732
+ option.recommended ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { children: "Recommended" }) : null
2733
+ ] }),
2734
+ option.description ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "chat-question-option-description", children: option.description }) : null
2735
+ ] })
2736
+ ]
2737
+ },
2738
+ `${option.value}-${index}`
2739
+ )),
2740
+ allowCustom || !choices.length ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { className: "chat-question-custom", children: [
2741
+ choices.length ? "Additional context" : "Your answer",
2742
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2743
+ "textarea",
2744
+ {
2745
+ rows: 2,
2746
+ value: text,
2747
+ onChange: (event) => setText(event.target.value),
2748
+ placeholder: "Type your answer\u2026"
2749
+ }
2750
+ )
2751
+ ] }) : null
2752
+ ] }),
2753
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("footer", { children: [
2754
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { role: "status", children: status === "sent" ? "Answer sent" : status === "sending" ? "Sending\u2026" : multiple ? "Choose one or more" : choices.length ? "Choose and confirm" : "Write and confirm" }),
2755
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2756
+ "button",
2757
+ {
2758
+ type: "submit",
2759
+ disabled: locked || !selected.length && !text.trim(),
2760
+ children: [
2761
+ status === "sent" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.Check, { size: 14, "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react12.ArrowUp, { size: 14, "aria-hidden": "true" }),
2762
+ status === "sent" ? "Submitted" : "Confirm"
2763
+ ]
2764
+ }
2765
+ )
2766
+ ] }),
2767
+ error ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : null
2768
+ ]
2769
+ }
2770
+ );
2771
+ }
2772
+
2773
+ // src/widgets/read-file.tsx
2774
+ var import_react19 = require("react");
2775
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2776
+ function ReadFileWidget({
2777
+ path,
2778
+ content,
2779
+ startLine = 1,
2780
+ language,
2781
+ maxLines = 80,
2782
+ ...props
2783
+ }) {
2784
+ var _a;
2785
+ const [expanded, setExpanded] = (0, import_react19.useState)(false);
2786
+ const lines = (_a = content == null ? void 0 : content.split(/\r?\n/)) != null ? _a : [];
2787
+ const limit = Math.max(1, maxLines);
2788
+ const firstLine = Math.max(1, Math.floor(startLine));
2789
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2790
+ ToolFrame,
2791
+ {
2792
+ ...props,
2793
+ label: "Read file",
2794
+ title: path,
2795
+ meta: lines.length ? `${lines.length} lines` : language,
2796
+ children: [
2797
+ content === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "chat-widget-empty", children: props.state === "running" ? "Reading file\u2026" : "No file content supplied." }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2798
+ "div",
2799
+ {
2800
+ className: "chat-code-preview",
2801
+ role: "region",
2802
+ "aria-label": `Contents of ${path}`,
2803
+ tabIndex: 0,
2804
+ children: (expanded ? lines : lines.slice(0, limit)).map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "chat-code-line", children: [
2805
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "chat-line-number", "aria-hidden": "true", children: firstLine + index }),
2806
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("code", { children: line || " " })
2807
+ ] }, index))
2808
+ }
2809
+ ),
2810
+ !expanded && lines.length > limit ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2811
+ "button",
2812
+ {
2813
+ className: "chat-widget-more",
2814
+ type: "button",
2815
+ onClick: () => setExpanded(true),
2816
+ children: [
2817
+ "Show ",
2818
+ lines.length - limit,
2819
+ " more lines"
2820
+ ]
2821
+ }
2822
+ ) : null
2823
+ ]
2824
+ }
2825
+ );
2826
+ }
2827
+
2828
+ // src/widgets/search.tsx
2829
+ var import_react20 = require("react");
2830
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2831
+ function SearchWidget({
2832
+ query,
2833
+ results = [],
2834
+ total,
2835
+ maxResults = 5,
2836
+ ...props
2837
+ }) {
2838
+ const [expanded, setExpanded] = (0, import_react20.useState)(false);
2839
+ const limit = Math.max(1, maxResults);
2840
+ const count = Math.max(results.length, total != null ? total : 0);
2841
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2842
+ ToolFrame,
2843
+ {
2844
+ ...props,
2845
+ label: "Search",
2846
+ title: query,
2847
+ meta: `${count} ${count === 1 ? "result" : "results"}`,
2848
+ children: [
2849
+ !results.length ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "chat-widget-empty", children: props.state === "running" ? "Searching\u2026" : "No results found." }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ol", { className: "chat-search-results", children: (expanded ? results : results.slice(0, limit)).map(
2850
+ (result, index) => {
2851
+ const href = safeResultUrl(result.url);
2852
+ const label = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
2853
+ result.title || result.path,
2854
+ result.line ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "chat-search-line", children: [
2855
+ ":",
2856
+ result.line
2857
+ ] }) : null
2858
+ ] });
2859
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("li", { children: [
2860
+ href ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href, target: "_blank", rel: "noreferrer", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "chat-search-path", children: label }),
2861
+ result.text ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { children: result.text }) : null
2862
+ ] }, `${result.path}-${result.line}-${index}`);
2863
+ }
2864
+ ) }),
2865
+ !expanded && results.length > limit ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2866
+ "button",
2867
+ {
2868
+ className: "chat-widget-more",
2869
+ type: "button",
2870
+ onClick: () => setExpanded(true),
2871
+ children: [
2872
+ "Show ",
2873
+ results.length - limit,
2874
+ " more results"
2875
+ ]
2876
+ }
2877
+ ) : null
2878
+ ]
2879
+ }
2880
+ );
2881
+ }
2882
+
2883
+ // src/widgets/registry.tsx
2884
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2885
+ var str = (value, fallback = "") => typeof value === "string" ? value : fallback;
2886
+ var num = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
2887
+ var common = (props) => ({
2888
+ state: props.state === "running" || props.state === "error" || props.state === "denied" || props.state === "approval" ? props.state : "complete",
2889
+ error: typeof props.error === "string" ? props.error : void 0
2890
+ });
2891
+ function Read(props) {
2892
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2893
+ ReadFileWidget,
2894
+ {
2895
+ ...common(props),
2896
+ path: str(props.path, "File"),
2897
+ content: typeof props.content === "string" ? props.content : void 0,
2898
+ startLine: num(props.startLine),
2899
+ language: str(props.language)
2900
+ }
2901
+ );
2902
+ }
2903
+ function Patch(props) {
2904
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2905
+ PatchWidget,
2906
+ {
2907
+ ...common(props),
2908
+ path: str(props.path, "File changes"),
2909
+ diff: typeof props.diff === "string" ? props.diff : void 0,
2910
+ before: typeof props.before === "string" ? props.before : void 0,
2911
+ after: typeof props.after === "string" ? props.after : void 0
2912
+ }
2913
+ );
2914
+ }
2915
+ function Search(props) {
2916
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2917
+ SearchWidget,
2918
+ {
2919
+ ...common(props),
2920
+ query: str(props.query),
2921
+ results: normalizeSearchResults(props.results),
2922
+ total: num(props.total)
2923
+ }
2924
+ );
2925
+ }
2926
+ function Question(props) {
2927
+ const options = Array.isArray(props.options) ? props.options.flatMap((item) => {
2928
+ if (typeof item === "string") return [{ label: item, value: item }];
2929
+ if (!item || typeof item !== "object" || typeof item.label !== "string" || typeof item.value !== "string")
2930
+ return [];
2931
+ return [
2932
+ {
2933
+ label: item.label,
2934
+ value: item.value,
2935
+ description: str(item.description),
2936
+ recommended: item.recommended === true
2937
+ }
2938
+ ];
2939
+ }) : [];
2940
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2941
+ QuestionWidget,
2942
+ {
2943
+ prompt: str(props.prompt, "Your answer"),
2944
+ description: str(props.description),
2945
+ options,
2946
+ multiple: props.multiple === true,
2947
+ allowCustom: props.allowCustom === true,
2948
+ disabled: !props.widget.interactive || props.widget.disabled,
2949
+ onSubmit: async (answer) => {
2950
+ const labels2 = answer.values.map(
2951
+ (value) => {
2952
+ var _a, _b;
2953
+ return (_b = (_a = options.find((option) => option.value === value)) == null ? void 0 : _a.label) != null ? _b : value;
2954
+ }
2955
+ );
2956
+ await props.widget.respond(
2957
+ answer,
2958
+ [...labels2, answer.text].filter(Boolean).join(", "),
2959
+ "answer"
2960
+ );
2961
+ }
2962
+ }
2963
+ );
2964
+ }
2965
+ function Artifact(props) {
2966
+ var _a;
2967
+ const artifact = (0, import_protocol2.parseArtifact)((_a = props.artifact) != null ? _a : props);
2968
+ return artifact ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactWidget, { artifact }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "chat-widget-empty", children: "File details are unavailable." });
2969
+ }
2970
+ function Artifacts(props) {
2971
+ const artifacts = Array.isArray(props.artifacts) ? props.artifacts.flatMap((value) => {
2972
+ const artifact = (0, import_protocol2.parseArtifact)(value);
2973
+ return artifact ? [artifact] : [];
2974
+ }) : [];
2975
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ArtifactsWidget, { artifacts });
2976
+ }
2977
+ function Subagent(props) {
2978
+ var _a;
2979
+ const subagent = (0, import_protocol2.parseSubagent)((_a = props.subagent) != null ? _a : props);
2980
+ return subagent ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SubagentWidget, { subagent }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "chat-widget-empty", children: "Agent details are unavailable." });
2981
+ }
2982
+ var prebuiltWidgets = {
2983
+ artifact: { name: "artifact", component: Artifact, shell: false },
2984
+ artifacts: { name: "artifacts", component: Artifacts, shell: false },
2985
+ subagent: { name: "subagent", component: Subagent, shell: false },
2986
+ "read-file": { name: "read-file", component: Read, shell: false },
2987
+ patch: { name: "patch", component: Patch, shell: false },
2988
+ search: { name: "search", component: Search, shell: false },
2989
+ question: { name: "question", component: Question, shell: false }
2990
+ };
2991
+
2992
+ // src/components/Widget/widget.context.tsx
2993
+ var import_react21 = require("react");
2994
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2995
+ function defineWidget(name, component, options = {}) {
2996
+ return {
2997
+ name,
2998
+ component,
2999
+ shell: true,
3000
+ ...options
3001
+ };
3002
+ }
3003
+ function createWidgetRegistry(widgets = {}) {
3004
+ if (Array.isArray(widgets)) {
3005
+ return Object.fromEntries(widgets.map((widget) => [widget.name, widget]));
3006
+ }
3007
+ return widgets;
3008
+ }
3009
+ function readWidgetValue(value, props, controls) {
3010
+ return typeof value === "function" ? value(props, controls) : value;
3011
+ }
3012
+ function getWidgetShellProps(definition, props, controls) {
3013
+ var _a;
3014
+ const title = readWidgetValue(definition.title, props, controls);
3015
+ return {
3016
+ label: (_a = readWidgetValue(definition.label, props, controls)) != null ? _a : definition.name.replace(/[-_]/g, " "),
3017
+ title: title != null ? title : definition.name,
3018
+ status: readWidgetValue(definition.status, props, controls),
3019
+ meta: readWidgetValue(definition.meta, props, controls),
3020
+ className: readWidgetValue(definition.className, props, controls)
3021
+ };
3022
+ }
3023
+ function isWidgetDefinition(entry) {
3024
+ return Boolean(entry && typeof entry === "object" && "component" in entry);
3025
+ }
3026
+ var WidgetContext = (0, import_react21.createContext)(null);
3027
+ function WidgetProvider({
3028
+ widgets = {},
3029
+ respondToWidget,
3030
+ disabled = false,
3031
+ children
3032
+ }) {
3033
+ const registry = (0, import_react21.useMemo)(() => ({ ...prebuiltWidgets, ...createWidgetRegistry(widgets) }), [widgets]);
3034
+ const value = (0, import_react21.useMemo)(
3035
+ () => ({
3036
+ widgets: registry,
3037
+ respondToWidget,
3038
+ disabled
3039
+ }),
3040
+ [disabled, registry, respondToWidget]
3041
+ );
3042
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(WidgetContext.Provider, { value, children });
3043
+ }
3044
+ function useWidgets() {
3045
+ const context = (0, import_react21.useContext)(WidgetContext);
3046
+ if (!context) {
3047
+ return {
3048
+ widgets: prebuiltWidgets,
3049
+ respondToWidget: async () => void 0,
3050
+ disabled: true
3051
+ };
3052
+ }
3053
+ return context;
3054
+ }
3055
+ function resolveWidgetPart(part, registry) {
3056
+ var _a;
3057
+ return (_a = registry[part.name]) != null ? _a : null;
3058
+ }
3059
+
3060
+ // src/ui/button.tsx
3061
+ var import_class_variance_authority = require("class-variance-authority");
3062
+ var import_radix_ui3 = require("radix-ui");
3063
+ var import_jsx_runtime27 = require("react/jsx-runtime");
3064
+ var buttonVariants = (0, import_class_variance_authority.cva)(
3065
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
3066
+ {
3067
+ variants: {
3068
+ variant: {
3069
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
3070
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
3071
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
3072
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
3073
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
3074
+ link: "text-primary underline-offset-4 hover:underline"
3075
+ },
3076
+ size: {
3077
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
3078
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
3079
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
3080
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
3081
+ icon: "size-9",
3082
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
3083
+ "icon-sm": "size-8",
3084
+ "icon-lg": "size-10"
3085
+ }
3086
+ },
3087
+ defaultVariants: {
3088
+ variant: "default",
3089
+ size: "default"
3090
+ }
3091
+ }
3092
+ );
3093
+ function Button({
3094
+ className,
3095
+ variant = "default",
3096
+ size = "default",
3097
+ asChild = false,
3098
+ skeleton = false,
3099
+ disabled,
3100
+ ...props
3101
+ }) {
3102
+ const Comp = asChild ? import_radix_ui3.Slot.Root : "button";
3103
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3104
+ Comp,
3105
+ {
3106
+ "data-slot": "button",
3107
+ "data-variant": variant,
3108
+ "data-size": size,
3109
+ "data-skeleton": skeleton ? "true" : void 0,
3110
+ "aria-busy": skeleton ? true : void 0,
3111
+ disabled: skeleton || disabled,
3112
+ className: cn(buttonVariants({ variant, size, className })),
3113
+ ...props
3114
+ }
3115
+ );
3116
+ }
3117
+
3118
+ // src/components/Message/message.skeleton.tsx
3119
+ var import_jsx_runtime28 = require("react/jsx-runtime");
3120
+ var TextSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "chat-text-skeleton", role: "status", "aria-label": "Assistant is writing", children: [
3121
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "chat-skeleton-bar" }),
3122
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "chat-skeleton-bar" }),
3123
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "chat-skeleton-bar chat-skeleton-bar-short" })
3124
+ ] });
3125
+ var WidgetActionSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "chat-widget-action-skeleton", "aria-label": "Widget actions are loading", children: [
3126
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Button, { skeleton: true, size: "sm", variant: "secondary", type: "button", tabIndex: -1, "aria-hidden": "true", children: "Confirm" }),
3127
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Button, { skeleton: true, size: "sm", variant: "outline", type: "button", tabIndex: -1, "aria-hidden": "true", children: "Cancel" })
3128
+ ] });
3129
+
3130
+ // src/components/Widget/widget.renderer.tsx
3131
+ var import_react22 = require("react");
3132
+
3133
+ // src/components/Widget/base.widget.tsx
3134
+ var import_jsx_runtime29 = require("react/jsx-runtime");
3135
+ function BaseWidget({
3136
+ label,
3137
+ title,
3138
+ status,
3139
+ meta,
3140
+ className,
3141
+ children
3142
+ }) {
3143
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("section", { className: cn("chat-widget-card", className), "aria-label": label, children: [
3144
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("header", { className: "chat-widget-header", children: [
3145
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "chat-widget-heading", children: [
3146
+ label ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "chat-widget-label-row", children: [
3147
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "chat-widget-status-dot", "aria-hidden": "true" }),
3148
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "chat-widget-label", children: label })
3149
+ ] }) : null,
3150
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "chat-widget-title", children: title })
3151
+ ] }),
3152
+ status ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "chat-widget-status", children: status }) : null
3153
+ ] }),
3154
+ children ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "chat-widget-body", children }) : null,
3155
+ meta ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "chat-widget-meta", children: meta }) : null
3156
+ ] });
3157
+ }
3158
+
3159
+ // src/components/Widget/widget.renderer.tsx
3160
+ var import_jsx_runtime30 = require("react/jsx-runtime");
3161
+ function WidgetRenderer({
3162
+ part,
3163
+ pending = false
3164
+ }) {
3165
+ const { widgets, respondToWidget, disabled } = useWidgets();
3166
+ const entry = resolveWidgetPart(part, widgets);
3167
+ const [submitted, setSubmitted] = (0, import_react22.useState)(false);
3168
+ const responsePending = (0, import_react22.useRef)(false);
3169
+ const widgetDisabled = disabled || submitted;
3170
+ const respond = async (value, label, actionId) => {
3171
+ if (!part.interactive || disabled || submitted || responsePending.current) {
3172
+ return;
3173
+ }
3174
+ responsePending.current = true;
3175
+ setSubmitted(true);
3176
+ try {
3177
+ await respondToWidget({
3178
+ widgetId: part.id,
3179
+ name: part.name,
3180
+ actionId,
3181
+ value,
3182
+ label
3183
+ });
3184
+ } catch (error) {
3185
+ setSubmitted(false);
3186
+ throw error;
3187
+ } finally {
3188
+ responsePending.current = false;
3189
+ }
3190
+ };
3191
+ const controls = {
3192
+ widgetId: part.id,
3193
+ widgetName: part.name,
3194
+ interactive: Boolean(part.interactive),
3195
+ disabled: widgetDisabled,
3196
+ respond,
3197
+ respondWith: async (response) => {
3198
+ await respond(response.value, response.label, response.actionId);
3199
+ }
3200
+ };
3201
+ const frame = (node) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "chat-widget", "data-pending": pending ? "true" : void 0, children: [
3202
+ node,
3203
+ pending ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(WidgetActionSkeleton, {}) : null
3204
+ ] });
3205
+ if (!entry) {
3206
+ return frame(
3207
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3208
+ BaseWidget,
3209
+ {
3210
+ label: "Unhandled widget",
3211
+ title: part.name,
3212
+ status: "Raw props",
3213
+ className: "chat-widget-missing",
3214
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("pre", { className: "agent-tool-code", children: JSON.stringify(part.props, null, 2) })
3215
+ }
3216
+ )
3217
+ );
3218
+ }
3219
+ if (isWidgetDefinition(entry)) {
3220
+ const Component2 = entry.component;
3221
+ const content = /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Component2, { ...part.props, widget: controls });
3222
+ if (entry.shell === false) {
3223
+ return frame(content);
3224
+ }
3225
+ return frame(
3226
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(BaseWidget, { ...getWidgetShellProps(entry, part.props, controls), children: content })
3227
+ );
3228
+ }
3229
+ const Component = entry;
3230
+ return frame(
3231
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3232
+ Component,
3233
+ {
3234
+ id: part.id,
3235
+ name: part.name,
3236
+ props: part.props,
3237
+ interactive: part.interactive,
3238
+ disabled: widgetDisabled,
3239
+ onRespond: async (response) => {
3240
+ if (!part.interactive || disabled || submitted || responsePending.current) {
3241
+ return;
3242
+ }
3243
+ responsePending.current = true;
3244
+ setSubmitted(true);
3245
+ try {
3246
+ await respondToWidget(response);
3247
+ } catch (error) {
3248
+ setSubmitted(false);
3249
+ throw error;
3250
+ } finally {
3251
+ responsePending.current = false;
3252
+ }
3253
+ }
3254
+ }
3255
+ )
3256
+ );
3257
+ }
3258
+
3259
+ // src/components/Message/message.markdown.tsx
3260
+ var import_react23 = require("react");
3261
+ var import_code_markdown = require("@sarchauhan/code-markdown");
3262
+ var import_react_markdown = __toESM(require("react-markdown"));
3263
+ var import_remark_gfm = __toESM(require("remark-gfm"));
3264
+
3265
+ // src/components/Message/message.markdown.theme.ts
3266
+ var chatCodeThemes = {
3267
+ light: {
3268
+ name: "chat-light",
3269
+ shikiTheme: "github-light",
3270
+ colors: {
3271
+ background: "#ffffff",
3272
+ foreground: "#0d0d0d",
3273
+ comment: "#6e6e80",
3274
+ keyword: "#9b174c",
3275
+ string: "#166534",
3276
+ function: "#1d4ed8",
3277
+ variable: "#0d0d0d",
3278
+ number: "#7c3aed",
3279
+ operator: "#9b174c",
3280
+ punctuation: "#6e6e80",
3281
+ type: "#0369a1",
3282
+ tag: "#166534",
3283
+ attribute: "#1d4ed8",
3284
+ constant: "#b45309",
3285
+ surface: "#f7f7f8",
3286
+ overlay: "#d8d8df",
3287
+ subtext: "#6e6e80"
3288
+ }
3289
+ },
3290
+ dark: {
3291
+ name: "chat-dark",
3292
+ shikiTheme: "github-dark",
3293
+ colors: {
3294
+ background: "#212121",
3295
+ foreground: "#ececec",
3296
+ comment: "#8f8f8f",
3297
+ keyword: "#ff7b72",
3298
+ string: "#a5d6a7",
3299
+ function: "#79c0ff",
3300
+ variable: "#ececec",
3301
+ number: "#d2a8ff",
3302
+ operator: "#ff7b72",
3303
+ punctuation: "#b4b4b4",
3304
+ type: "#79c0ff",
3305
+ tag: "#7ee787",
3306
+ attribute: "#79c0ff",
3307
+ constant: "#ffa657",
3308
+ surface: "#2f2f2f",
3309
+ overlay: "#454545",
3310
+ subtext: "#b4b4b4"
3311
+ }
3312
+ }
3313
+ };
3314
+
3315
+ // src/components/Message/message.markdown.tsx
3316
+ var import_jsx_runtime31 = require("react/jsx-runtime");
3317
+ var markdownPlugins = {
3318
+ remark: [import_remark_gfm.default],
3319
+ rehype: []
3320
+ };
3321
+ var SUPPORTED_LANGUAGES = /* @__PURE__ */ new Set([
3322
+ "c",
3323
+ "h",
3324
+ "cpp",
3325
+ "cxx",
3326
+ "cc",
3327
+ "hpp",
3328
+ "hxx",
3329
+ "go",
3330
+ "javascript",
3331
+ "js",
3332
+ "jsx",
3333
+ "mjs",
3334
+ "python",
3335
+ "py",
3336
+ "rust",
3337
+ "rs",
3338
+ "typescript",
3339
+ "ts",
3340
+ "tsx"
3341
+ ]);
3342
+ var isSupportedLanguage = (value) => SUPPORTED_LANGUAGES.has(value);
3343
+ var getCodeLanguage = (className) => {
3344
+ var _a;
3345
+ const match = className == null ? void 0 : className.match(/language-([\w-]+)/);
3346
+ const language = (_a = match == null ? void 0 : match[1]) == null ? void 0 : _a.toLowerCase();
3347
+ return language && isSupportedLanguage(language) ? language : "typescript";
3348
+ };
3349
+ var getTextContent = (value) => {
3350
+ if (typeof value === "string" || typeof value === "number") {
3351
+ return String(value);
3352
+ }
3353
+ if (Array.isArray(value)) {
3354
+ return value.map(getTextContent).join("");
3355
+ }
3356
+ return "";
3357
+ };
3358
+ var MarkdownCodeBlock = ({
3359
+ code,
3360
+ language
3361
+ }) => {
3362
+ const { resolvedTheme } = useTheme();
3363
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3364
+ import_code_markdown.CodeMarkdown,
3365
+ {
3366
+ className: "chat-code-markdown",
3367
+ language,
3368
+ theme: chatCodeThemes[resolvedTheme],
3369
+ showCopyButton: true,
3370
+ showLineNumbers: true,
3371
+ showLanguage: true,
3372
+ children: code
3373
+ }
3374
+ );
3375
+ };
3376
+ var MarkdownPre = ({ className, children }) => {
3377
+ const child = import_react23.Children.toArray(children)[0];
3378
+ const code = (0, import_react23.isValidElement)(child) ? getTextContent(child.props.children) : getTextContent(children);
3379
+ const codeClassName = (0, import_react23.isValidElement)(child) ? child.props.className : void 0;
3380
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: cn("my-5", className), children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3381
+ MarkdownCodeBlock,
3382
+ {
3383
+ language: getCodeLanguage(codeClassName),
3384
+ code: code.replace(/\n$/, "")
3385
+ }
3386
+ ) });
3387
+ };
3388
+ var markdownComponents = {
3389
+ a: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3390
+ "a",
3391
+ {
3392
+ className: cn(
3393
+ "font-medium text-primary underline underline-offset-2 decoration-primary/30 decoration-1 hover:decoration-primary/70",
3394
+ className
3395
+ ),
3396
+ target: "_blank",
3397
+ rel: "noreferrer noopener",
3398
+ ...props
3399
+ }
3400
+ ),
3401
+ p: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3402
+ "p",
3403
+ {
3404
+ className: cn("my-[0.85em] text-inherit chat-text-body first:mt-0 last:mb-0", className),
3405
+ style: { fontSize: "var(--chat-body-size)", lineHeight: "var(--chat-body-leading)" },
3406
+ ...props
3407
+ }
3408
+ ),
3409
+ h1: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3410
+ "h1",
3411
+ {
3412
+ className: cn("mt-8 mb-3 chat-text-heading-1", className),
3413
+ style: {
3414
+ fontSize: "var(--chat-heading-1-size)",
3415
+ lineHeight: "var(--chat-heading-1-leading)",
3416
+ fontWeight: "var(--chat-heading-1-weight)",
3417
+ letterSpacing: "var(--chat-heading-1-tracking)"
3418
+ },
3419
+ ...props
3420
+ }
3421
+ ),
3422
+ h2: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3423
+ "h2",
3424
+ {
3425
+ className: cn("mt-8 mb-3", className),
3426
+ style: {
3427
+ fontSize: "var(--chat-fs-18)",
3428
+ lineHeight: "var(--chat-leading-tight)",
3429
+ fontWeight: "var(--chat-weight-semibold)",
3430
+ letterSpacing: "var(--chat-tracking-tight)"
3431
+ },
3432
+ ...props
3433
+ }
3434
+ ),
3435
+ h3: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3436
+ "h3",
3437
+ {
3438
+ className: cn("mt-6 mb-2", className),
3439
+ style: {
3440
+ fontSize: "var(--chat-fs-16)",
3441
+ lineHeight: "var(--chat-leading-tight)",
3442
+ fontWeight: "var(--chat-weight-semibold)",
3443
+ letterSpacing: "var(--chat-tracking-tight)"
3444
+ },
3445
+ ...props
3446
+ }
3447
+ ),
3448
+ h4: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3449
+ "h4",
3450
+ {
3451
+ className: cn("mt-6 mb-2", className),
3452
+ style: {
3453
+ fontSize: "var(--chat-fs-15)",
3454
+ lineHeight: "var(--chat-leading-tight)",
3455
+ fontWeight: "var(--chat-weight-semibold)",
3456
+ letterSpacing: "var(--chat-tracking-normal)"
3457
+ },
3458
+ ...props
3459
+ }
3460
+ ),
3461
+ ul: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3462
+ "ul",
3463
+ {
3464
+ className: cn("my-4 list-disc space-y-2 pl-6 chat-text-body", className),
3465
+ style: { fontSize: "var(--chat-body-size)", lineHeight: "var(--chat-body-leading)" },
3466
+ ...props
3467
+ }
3468
+ ),
3469
+ ol: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3470
+ "ol",
3471
+ {
3472
+ className: cn("my-4 list-decimal space-y-2 pl-6 chat-text-body", className),
3473
+ style: { fontSize: "var(--chat-body-size)", lineHeight: "var(--chat-body-leading)" },
3474
+ ...props
3475
+ }
3476
+ ),
3477
+ li: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3478
+ "li",
3479
+ {
3480
+ className: cn("pl-1", className),
3481
+ style: { lineHeight: "var(--chat-leading-normal)" },
3482
+ ...props
3483
+ }
3484
+ ),
3485
+ blockquote: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("blockquote", { className: cn("md-blockquote", className), ...props }),
3486
+ hr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("hr", { className: cn("my-6 h-px border-0 bg-current opacity-10", className), ...props }),
3487
+ table: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "md-table-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("table", { className: cn("md-table", className), ...props }) }),
3488
+ thead: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("thead", { ...props }),
3489
+ tbody: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("tbody", { ...props }),
3490
+ tr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("tr", { ...props }),
3491
+ th: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("th", { ...props }),
3492
+ td: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("td", { ...props }),
3493
+ pre: MarkdownPre,
3494
+ // React Markdown v10 no longer consistently provides the legacy `inline`
3495
+ // prop. Fenced code is handled by the custom `pre` renderer above, so a
3496
+ // standalone `code` element should always be rendered as inline code.
3497
+ code: ({ className, children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", { className: cn("md-inline-code", className), ...props, children })
3498
+ };
3499
+ var MarkdownContent = ({ children, className }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: cn("md-content break-words text-inherit", className), children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
3500
+ import_react_markdown.default,
3501
+ {
3502
+ remarkPlugins: markdownPlugins.remark,
3503
+ rehypePlugins: markdownPlugins.rehype,
3504
+ components: markdownComponents,
3505
+ children
3506
+ }
3507
+ ) });
3508
+
3509
+ // src/components/Message/message.thinking.tsx
3510
+ var import_lucide_react13 = require("lucide-react");
3511
+ var import_react25 = require("react");
3512
+
3513
+ // src/components/Message/message.loading.tsx
3514
+ var import_react24 = require("react");
3515
+ var import_jsx_runtime32 = require("react/jsx-runtime");
3516
+ var useElapsedTime = (active) => {
3517
+ const startedAtRef = (0, import_react24.useRef)(0);
3518
+ const [elapsed, setElapsed] = (0, import_react24.useState)(0);
3519
+ (0, import_react24.useEffect)(() => {
3520
+ if (!active) {
3521
+ return;
3522
+ }
3523
+ startedAtRef.current = Date.now();
3524
+ setElapsed(0);
3525
+ const timer = window.setInterval(() => {
3526
+ setElapsed(Date.now() - startedAtRef.current);
3527
+ }, 100);
3528
+ return () => window.clearInterval(timer);
3529
+ }, [active]);
3530
+ return elapsed;
3531
+ };
3532
+ var formatElapsed = (milliseconds, showTenths = false) => {
3533
+ const totalSeconds = Math.max(0, milliseconds / 1e3);
3534
+ const minutes = Math.floor(totalSeconds / 60);
3535
+ const seconds = totalSeconds - minutes * 60;
3536
+ const formattedSeconds = showTenths ? seconds.toFixed(1) : String(Math.floor(seconds));
3537
+ return minutes > 0 ? `${minutes}m ${formattedSeconds}s` : `${formattedSeconds}s`;
3538
+ };
3539
+ var formatElapsedWords = (milliseconds) => {
3540
+ const seconds = Math.max(0, Math.floor(milliseconds / 1e3));
3541
+ if (seconds < 60) {
3542
+ return `${seconds} ${seconds === 1 ? "second" : "seconds"}`;
3543
+ }
3544
+ const minutes = Math.floor(seconds / 60);
3545
+ const remainder = seconds % 60;
3546
+ const minuteLabel = `${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
3547
+ return remainder > 0 ? `${minuteLabel} ${remainder} ${remainder === 1 ? "second" : "seconds"}` : minuteLabel;
3548
+ };
3549
+ var PixelGrid = () => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "chat-pixel-grid", "aria-hidden": "true", children: Array.from({ length: 9 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", {}, index)) });
3550
+ var LoadingState = ({ label = "Churning", compact = false }) => {
3551
+ const elapsed = useElapsedTime(true);
3552
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: `chat-loading${compact ? " chat-loading-inline" : ""}`, role: "status", "aria-live": "polite", children: [
3553
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(PixelGrid, {}),
3554
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TextSwap, { className: "chat-loading-label", text: label }),
3555
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "chat-loading-timer", role: "timer", children: formatElapsed(elapsed, true) }),
3556
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "chat-visually-hidden", children: "Loading conversation" })
3557
+ ] });
3558
+ };
3559
+
3560
+ // src/components/Message/message.thinking.tsx
3561
+ var import_jsx_runtime33 = require("react/jsx-runtime");
3562
+ var ThinkingBlock = ({ isComplete, elapsedMs, children }) => {
3563
+ const [isOpen, setIsOpen] = (0, import_react25.useState)(true);
3564
+ const measuredElapsed = useElapsedTime(!isComplete);
3565
+ const elapsed = elapsedMs != null ? elapsedMs : measuredElapsed;
3566
+ (0, import_react25.useEffect)(() => {
3567
+ if (!isComplete) {
3568
+ setIsOpen(true);
3569
+ }
3570
+ }, [isComplete]);
3571
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
3572
+ "details",
3573
+ {
3574
+ className: cn(
3575
+ "md-thinking",
3576
+ isComplete ? "md-thinking-complete" : "md-thinking-pending"
3577
+ ),
3578
+ open: isOpen,
3579
+ onToggle: (event) => setIsOpen(event.currentTarget.open),
3580
+ children: [
3581
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("summary", { children: [
3582
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react13.Sparkles, { className: "md-thinking-sparkle", "aria-hidden": "true" }),
3583
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3584
+ TextSwap,
3585
+ {
3586
+ className: "md-thinking-label",
3587
+ text: isComplete ? `Thought for ${formatElapsedWords(elapsed)}` : "Thinking"
3588
+ }
3589
+ ),
3590
+ isComplete && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react13.ChevronDown, { className: "md-thinking-chevron", "aria-hidden": "true" })
3591
+ ] }),
3592
+ children
3593
+ ]
3594
+ }
3595
+ );
3596
+ };
3597
+
3598
+ // src/components/Message/message.content.tsx
3599
+ var import_jsx_runtime34 = require("react/jsx-runtime");
3600
+ var isPropsRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
3601
+ var formatJson = (value) => {
3602
+ if (typeof value === "string") {
3603
+ return value;
3604
+ }
3605
+ try {
3606
+ return JSON.stringify(value, null, 2);
3607
+ } catch {
3608
+ return String(value);
3609
+ }
3610
+ };
3611
+ var toolDetail = (part) => {
3612
+ var _a, _b, _c, _d, _e, _f;
3613
+ const source = (_a = part.output) != null ? _a : part.input;
3614
+ if (!isPropsRecord(source)) {
3615
+ return null;
3616
+ }
3617
+ const value = (_f = (_e = (_d = (_c = (_b = source.path) != null ? _b : source.file) != null ? _c : source.filename) != null ? _d : source.query) != null ? _e : source.command) != null ? _f : source.url;
3618
+ return typeof value === "string" && value.trim() ? value : null;
3619
+ };
3620
+ var toolStateLabel = (state) => {
3621
+ switch (state) {
3622
+ case "input-streaming":
3623
+ return "Preparing";
3624
+ case "input-available":
3625
+ return "Ready";
3626
+ case "approval-requested":
3627
+ return "Needs approval";
3628
+ case "approval-responded":
3629
+ return "Approval sent";
3630
+ case "output-available":
3631
+ return "Done";
3632
+ case "output-error":
3633
+ return "Error";
3634
+ case "output-denied":
3635
+ return "Denied";
3636
+ default:
3637
+ return state;
3638
+ }
3639
+ };
3640
+ var ReasoningBlock = ({ part }) => {
3641
+ const isComplete = part.state !== "streaming";
3642
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ThinkingBlock, { isComplete, children: !!part.text.trim() && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "md-thinking-body", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MarkdownContent, { children: part.text }) }) });
3643
+ };
3644
+ var ToolStatusIcon = ({
3645
+ isPending,
3646
+ isDone
3647
+ }) => {
3648
+ const pathRef = (0, import_react26.useRef)(null);
3649
+ const [sawPending, setSawPending] = (0, import_react26.useState)(isPending);
3650
+ const iconState = isPending ? "a" : "b";
3651
+ const playCheck = Boolean(sawPending && isDone);
3652
+ const checkState = playCheck ? "in" : "out";
3653
+ if (isPending && !sawPending) {
3654
+ setSawPending(true);
3655
+ }
3656
+ (0, import_react26.useLayoutEffect)(() => {
3657
+ if (pathRef.current) {
3658
+ calibrateCheckPath(pathRef.current);
3659
+ }
3660
+ }, [playCheck]);
3661
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-tool-dot", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: motion.iconSwap, "data-state": iconState, children: [
3662
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: motion.icon, "data-icon": "a", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-tool-spinner" }) }),
3663
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: motion.icon, "data-icon": "b", children: isDone ? playCheck ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: motion.successCheck, "data-state": checkState, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("svg", { viewBox: "0 0 12 12", width: "10", height: "10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3664
+ "path",
3665
+ {
3666
+ ref: pathRef,
3667
+ d: "M2.5 6.5 5 9l4.5-6",
3668
+ stroke: "currentColor",
3669
+ strokeWidth: "1.6",
3670
+ strokeLinecap: "round",
3671
+ strokeLinejoin: "round"
3672
+ }
3673
+ ) }) }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("svg", { viewBox: "0 0 12 12", width: "10", height: "10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3674
+ "path",
3675
+ {
3676
+ d: "M2.5 6.5 5 9l4.5-6",
3677
+ stroke: "currentColor",
3678
+ strokeWidth: "1.6",
3679
+ strokeLinecap: "round",
3680
+ strokeLinejoin: "round"
3681
+ }
3682
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("svg", { viewBox: "0 0 12 12", width: "10", height: "10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3683
+ "path",
3684
+ {
3685
+ d: "M3.2 3.2 8.8 8.8M8.8 3.2 3.2 8.8",
3686
+ stroke: "currentColor",
3687
+ strokeWidth: "1.6",
3688
+ strokeLinecap: "round"
3689
+ }
3690
+ ) }) })
3691
+ ] }) });
3692
+ };
3693
+ var ToolBlock = ({ part }) => {
3694
+ var _a;
3695
+ const wrapRef = (0, import_react26.useRef)(null);
3696
+ const isPending = part.state === "input-streaming" || part.state === "input-available" || part.state === "approval-requested";
3697
+ const isError = part.state === "output-error" || part.state === "output-denied";
3698
+ const isDone = !isPending && !isError;
3699
+ const detail = toolDetail(part);
3700
+ (0, import_react26.useEffect)(() => {
3701
+ if (!isError || !wrapRef.current) {
3702
+ return;
3703
+ }
3704
+ triggerErrorShake(wrapRef.current, { revert: false });
3705
+ }, [isError]);
3706
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
3707
+ "details",
3708
+ {
3709
+ ref: wrapRef,
3710
+ className: cn(
3711
+ "agent-tool",
3712
+ motion.inputWrap,
3713
+ isPending ? "agent-tool-pending" : isError ? "agent-tool-error" : "agent-tool-complete"
3714
+ ),
3715
+ open: isPending || isError,
3716
+ children: [
3717
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("summary", { className: cn(motion.input, isError && motion.isError), children: [
3718
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react14.ChevronDown, { className: "agent-tool-chevron", "aria-hidden": "true" }),
3719
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ToolStatusIcon, { isPending, isDone }),
3720
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-tool-name", children: (_a = part.title) != null ? _a : part.toolName }),
3721
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-tool-chip", children: detail }) : null,
3722
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(TextSwap, { className: "agent-tool-state", text: toolStateLabel(part.state) })
3723
+ ] }),
3724
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "agent-tool-body", children: [
3725
+ part.input !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "agent-tool-section", children: [
3726
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "agent-tool-section-label", children: "Input" }),
3727
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { className: "agent-tool-code", children: formatJson(part.input) })
3728
+ ] }),
3729
+ part.output !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "agent-tool-section", children: [
3730
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "agent-tool-section-label", children: "Output" }),
3731
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { className: "agent-tool-code", children: formatJson(part.output) })
3732
+ ] }),
3733
+ part.errorText && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "agent-tool-section", children: [
3734
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "agent-tool-section-label", children: "Error" }),
3735
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { className: "agent-tool-code agent-tool-error", children: part.errorText })
3736
+ ] })
3737
+ ] })
3738
+ ]
3739
+ }
3740
+ );
3741
+ };
3742
+ var SourceUrlBlock = ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("a", { className: "agent-source", href: part.url, target: "_blank", rel: "noreferrer", children: [
3743
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-source-label", children: "Source" }),
3744
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-source-title", children: part.title || part.url })
3745
+ ] });
3746
+ var SourceDocumentBlock = ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "agent-source agent-source-document", children: [
3747
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-source-label", children: "Document" }),
3748
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-source-title", children: part.title }),
3749
+ part.filename && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-source-meta", children: part.filename })
3750
+ ] });
3751
+ var FileBlock = ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ArtifactWidget, { artifact: {
3752
+ id: part.url,
3753
+ filename: part.filename || (part.mediaType.startsWith("image/") ? "Generated image" : "Generated file"),
3754
+ mediaType: part.mediaType,
3755
+ url: part.url,
3756
+ status: "ready"
3757
+ } });
3758
+ var AgentEventBlock = ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("details", { className: "agent-tool agent-event", children: [
3759
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("summary", { children: [
3760
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-event-marker", "aria-hidden": "true" }),
3761
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "agent-tool-name", children: [
3762
+ "data.",
3763
+ part.name
3764
+ ] })
3765
+ ] }),
3766
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "agent-tool-body", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { className: "agent-tool-code", children: formatJson(part.data) }) })
3767
+ ] });
3768
+ var TextWithLegacyThinking = ({ text, isUser }) => {
3769
+ var _a;
3770
+ const userReferenceMessage = isUser ? parseUserReferenceMessage(text) : null;
3771
+ const content = (_a = userReferenceMessage == null ? void 0 : userReferenceMessage.message) != null ? _a : text;
3772
+ const segments = splitThinkingSegments(content);
3773
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
3774
+ userReferenceMessage && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "chat-user-reference", children: userReferenceMessage.references.map((reference, index) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
3775
+ "div",
3776
+ {
3777
+ className: "chat-user-reference-item",
3778
+ children: [
3779
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "chat-reference-label", children: [
3780
+ "Reference ",
3781
+ index + 1
3782
+ ] }),
3783
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "chat-reference-text", children: reference })
3784
+ ]
3785
+ },
3786
+ `${index}-${reference.slice(0, 16)}`
3787
+ )) }),
3788
+ segments.map((segment, index) => {
3789
+ var _a2;
3790
+ if (!segment.content.trim() && segment.type !== "thinking") {
3791
+ return null;
3792
+ }
3793
+ if (segment.type === "thinking" && !isUser) {
3794
+ const isComplete = (_a2 = segment.isComplete) != null ? _a2 : true;
3795
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ThinkingBlock, { isComplete, children: !!segment.content.trim() && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "md-thinking-body", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MarkdownContent, { children: segment.content }) }) }, `thinking-${index}`);
3796
+ }
3797
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MarkdownContent, { children: segment.content }, `md-${index}`);
3798
+ })
3799
+ ] });
3800
+ };
3801
+ var asWidgetFromTool = (part) => {
3802
+ const source = part.state === "output-available" && part.output !== void 0 ? part.output : part.input;
3803
+ if (!isPropsRecord(source)) {
3804
+ return null;
3805
+ }
3806
+ return {
3807
+ type: "widget",
3808
+ name: part.toolName,
3809
+ id: part.toolCallId,
3810
+ props: source,
3811
+ interactive: part.toolName === "question" || source.interactive === true
3812
+ };
3813
+ };
3814
+ var asWidgetFromData = (part) => ({
3815
+ type: "widget",
3816
+ name: part.name,
3817
+ id: part.id,
3818
+ props: isPropsRecord(part.data) ? part.data : { value: part.data },
3819
+ interactive: isPropsRecord(part.data) ? part.data.interactive === true : false
3820
+ });
3821
+ var PartView = ({ part, index, isUser }) => {
3822
+ const { widgets } = useWidgets();
3823
+ if (part.type === "widget") {
3824
+ return isUser ? null : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(WidgetRenderer, { part }, `widget-${part.id || index}`);
3825
+ }
3826
+ if (part.type === "tool" && !isUser) {
3827
+ const entry = widgets[part.toolName];
3828
+ const isCustom = entry && entry !== prebuiltWidgets[part.toolName];
3829
+ const widgetPart = isCustom ? asWidgetFromTool(part) : computeToolWidget(part);
3830
+ if (widgetPart) {
3831
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3832
+ WidgetRenderer,
3833
+ {
3834
+ part: widgetPart,
3835
+ pending: part.state === "input-streaming"
3836
+ },
3837
+ `tool-widget-${part.toolCallId || index}`
3838
+ );
3839
+ }
3840
+ }
3841
+ if (part.type === "data" && !isUser && widgets[part.name]) {
3842
+ const builtin = widgets[part.name] === prebuiltWidgets[part.name];
3843
+ if (builtin && (part.name === "artifact" && !(0, import_protocol3.parseArtifact)(part.data) || part.name === "subagent" && !(0, import_protocol3.parseSubagent)(part.data))) return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(AgentEventBlock, { part });
3844
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3845
+ WidgetRenderer,
3846
+ {
3847
+ part: asWidgetFromData(part)
3848
+ },
3849
+ `data-widget-${part.name}-${part.id || index}`
3850
+ );
3851
+ }
3852
+ switch (part.type) {
3853
+ case "text":
3854
+ if (!isUser && part.state === "streaming" && part.text.trim().length === 0) {
3855
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(TextSkeleton, {}, `text-${index}`);
3856
+ }
3857
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(TextWithLegacyThinking, { text: part.text, isUser }, `text-${index}`);
3858
+ case "reasoning":
3859
+ return isUser ? null : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReasoningBlock, { part }, `reasoning-${index}`);
3860
+ case "tool":
3861
+ return isUser ? null : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ToolBlock, { part }, `tool-${part.toolCallId || index}`);
3862
+ case "source-url":
3863
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SourceUrlBlock, { part }, `source-url-${part.sourceId || index}`);
3864
+ case "source-document":
3865
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SourceDocumentBlock, { part }, `source-doc-${part.sourceId || index}`);
3866
+ case "file":
3867
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(FileBlock, { part }, `file-${index}`);
3868
+ case "data":
3869
+ if (part.name === "usage" || part.name === "context" || part.name === "context-warning") {
3870
+ return null;
3871
+ }
3872
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(AgentEventBlock, { part }, `data-${part.name}-${part.id || index}`);
3873
+ case "unknown":
3874
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("details", { className: "agent-tool agent-event", children: [
3875
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("summary", { children: [
3876
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-event-marker", "aria-hidden": "true" }),
3877
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "agent-tool-name", children: part.rawType })
3878
+ ] }),
3879
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "agent-tool-body", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { className: "agent-tool-code", children: formatJson(part.raw) }) })
3880
+ ] }, `unknown-${index}`);
3881
+ default:
3882
+ return null;
3883
+ }
3884
+ };
3885
+ var MessageContent = ({ parts, isUser = false }) => {
3886
+ const agentParts = (0, import_protocol3.normalizeAgentParts)(parts);
3887
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3888
+ "div",
3889
+ {
3890
+ className: cn(
3891
+ "chat-message-content break-words",
3892
+ isUser ? "md-content-user" : "md-content-assistant"
3893
+ ),
3894
+ children: agentParts.map((part, index) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(PartView, { part, index, isUser }, `${part.type}-${index}`))
3895
+ }
3896
+ );
3897
+ };
3898
+
3899
+ // src/components/Message/message.feedback.tsx
3900
+ var import_lucide_react17 = require("lucide-react");
3901
+ var import_react28 = require("react");
3902
+
3903
+ // src/components/Message/message.copy.tsx
3904
+ var import_lucide_react15 = require("lucide-react");
3905
+ var import_react27 = require("react");
3906
+ var import_jsx_runtime35 = require("react/jsx-runtime");
3907
+ var MessageCopy = ({ text, disabled = false }) => {
3908
+ const [isCopied, setIsCopied] = (0, import_react27.useState)(false);
3909
+ const copyMessage = async () => {
3910
+ await navigator.clipboard.writeText(text);
3911
+ setIsCopied(true);
3912
+ window.setTimeout(() => setIsCopied(false), 1500);
3913
+ };
3914
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3915
+ "button",
3916
+ {
3917
+ type: "button",
3918
+ className: "chat-feedback-button",
3919
+ title: isCopied ? "Copied" : "Copy response",
3920
+ "aria-label": isCopied ? "Copied" : "Copy response",
3921
+ onClick: () => void copyMessage(),
3922
+ disabled,
3923
+ children: isCopied ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react15.Check, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react15.Copy, { size: 16 })
3924
+ }
3925
+ );
3926
+ };
3927
+
3928
+ // src/components/Message/message.regenerate.tsx
3929
+ var import_lucide_react16 = require("lucide-react");
3930
+ var import_jsx_runtime36 = require("react/jsx-runtime");
3931
+ var MessageRegenerate = ({ onRegenerate, disabled = false }) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3932
+ "button",
3933
+ {
3934
+ type: "button",
3935
+ className: "chat-feedback-button",
3936
+ title: "Regenerate response",
3937
+ "aria-label": "Regenerate response",
3938
+ disabled,
3939
+ onClick: onRegenerate,
3940
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react16.RotateCcw, { size: 17 })
3941
+ }
3942
+ );
3943
+
3944
+ // src/components/Message/message.feedback.tsx
3945
+ var import_jsx_runtime37 = require("react/jsx-runtime");
3946
+ var MessageFeedback = ({
3947
+ responseText,
3948
+ onRegenerate,
3949
+ canRegenerate,
3950
+ disabled = false
3951
+ }) => {
3952
+ const [feedback, setFeedback] = (0, import_react28.useState)(null);
3953
+ if (!responseText.trim()) {
3954
+ return null;
3955
+ }
3956
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "chat-message-feedback", "aria-label": "Message actions", children: [
3957
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MessageCopy, { text: responseText, disabled }),
3958
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3959
+ MessageRegenerate,
3960
+ {
3961
+ onRegenerate,
3962
+ disabled: !canRegenerate || disabled
3963
+ }
3964
+ ),
3965
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3966
+ "button",
3967
+ {
3968
+ type: "button",
3969
+ className: `chat-feedback-button${feedback === "up" ? " is-selected" : ""}`,
3970
+ title: "Good response",
3971
+ "aria-label": "Good response",
3972
+ "aria-pressed": feedback === "up",
3973
+ onClick: () => setFeedback(feedback === "up" ? null : "up"),
3974
+ disabled,
3975
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react17.ThumbsUp, { size: 18 })
3976
+ }
3977
+ ),
3978
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3979
+ "button",
3980
+ {
3981
+ type: "button",
3982
+ className: `chat-feedback-button${feedback === "down" ? " is-selected" : ""}`,
3983
+ title: "Poor response",
3984
+ "aria-label": "Poor response",
3985
+ "aria-pressed": feedback === "down",
3986
+ onClick: () => setFeedback(feedback === "down" ? null : "down"),
3987
+ disabled,
3988
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react17.ThumbsDown, { size: 18 })
3989
+ }
3990
+ )
3991
+ ] });
3992
+ };
3993
+
3994
+ // src/components/Message/message.usage.tsx
3995
+ var import_protocol4 = require("@sarchauhan/protocol");
3996
+ var import_jsx_runtime38 = require("react/jsx-runtime");
3997
+ var formatTokens = (value) => new Intl.NumberFormat("en-US").format(value);
3998
+ var isTokenCount = (value) => typeof value === "number" && Number.isFinite(value);
3999
+ var getContextMetrics = (context) => {
4000
+ const currentTokens = context == null ? void 0 : context.current_tokens;
4001
+ const contextWindow = context == null ? void 0 : context.context_window;
4002
+ return isTokenCount(currentTokens) && isTokenCount(contextWindow) ? { currentTokens, contextWindow } : null;
4003
+ };
4004
+ var MessageUsage = ({ parts }) => {
4005
+ var _a, _b;
4006
+ const usage = (0, import_protocol4.parseUsage)((_a = parts.find((part) => part.name === "usage")) == null ? void 0 : _a.data);
4007
+ const context = (0, import_protocol4.parseContext)((_b = parts.find((part) => part.name === "context")) == null ? void 0 : _b.data);
4008
+ const contextMetrics = getContextMetrics(context);
4009
+ const tokenMetrics = usage ? [
4010
+ ["in", usage.input_tokens],
4011
+ ["out", usage.output_tokens],
4012
+ ["reasoning", usage.reasoning_tokens],
4013
+ ["total", usage.total_tokens]
4014
+ ].filter((metric) => isTokenCount(metric[1])) : [];
4015
+ if (!contextMetrics && tokenMetrics.length === 0) return null;
4016
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "chat-message-usage", "aria-label": "Context and token usage", children: [
4017
+ contextMetrics ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
4018
+ "Context ",
4019
+ formatTokens(contextMetrics.currentTokens),
4020
+ " / ",
4021
+ formatTokens(contextMetrics.contextWindow),
4022
+ " (",
4023
+ Math.round(contextMetrics.currentTokens / contextMetrics.contextWindow * 100),
4024
+ "%)"
4025
+ ] }) : null,
4026
+ tokenMetrics.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
4027
+ contextMetrics ? " \xB7 " : null,
4028
+ "Tokens ",
4029
+ tokenMetrics.map(([label, value]) => `${label} ${formatTokens(value)}`).join(" \xB7 ")
4030
+ ] }) : null
4031
+ ] });
4032
+ };
4033
+
4034
+ // src/components/Message/message.item.tsx
4035
+ var import_jsx_runtime39 = require("react/jsx-runtime");
4036
+ var getMessageTargetId = (messageId) => `chat-message-${messageId}`;
4037
+ var MessageItem = ({ message }) => {
4038
+ var _a;
4039
+ const { editAndResendMessage, isSending, messages } = useMessages();
4040
+ const [isEditing, setIsEditing] = (0, import_react29.useState)(false);
4041
+ const [draft, setDraft] = (0, import_react29.useState)(() => getUserDisplayText(message));
4042
+ const [isSubmittingEdit, setIsSubmittingEdit] = (0, import_react29.useState)(false);
4043
+ const isUser = message.role === "user";
4044
+ const isActiveAssistantMessage = isSending && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.id) === message.id;
4045
+ const assistantText = message.parts.filter((part) => part.type === "text").map((part) => "text" in part ? String(part.text) : "").join("\n").trim();
4046
+ const dataParts = (0, import_protocol5.normalizeAgentParts)(message.parts).filter(
4047
+ (part) => part.type === "data"
4048
+ );
4049
+ const previousUserMessage = [...messages].reverse().find((item) => item.role === "user");
4050
+ const cancelEdit = () => {
4051
+ setDraft(getUserDisplayText(message));
4052
+ setIsEditing(false);
4053
+ };
4054
+ const submitEdit = async () => {
4055
+ if (!draft.trim() || isSending || isSubmittingEdit) {
4056
+ return;
4057
+ }
4058
+ setIsSubmittingEdit(true);
4059
+ try {
4060
+ await editAndResendMessage(message.id, draft);
4061
+ setIsEditing(false);
4062
+ } finally {
4063
+ setIsSubmittingEdit(false);
4064
+ }
4065
+ };
4066
+ if (isUser) {
4067
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { id: getMessageTargetId(message.id), className: "chat-message chat-message-user", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: `chat-message-user-inner${isEditing ? " is-editing" : ""}`, children: [
4068
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "chat-message-bubble", children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4069
+ "textarea",
4070
+ {
4071
+ className: "chat-edit-area",
4072
+ value: draft,
4073
+ disabled: isSubmittingEdit,
4074
+ autoFocus: true,
4075
+ onChange: (event) => setDraft(event.target.value),
4076
+ onKeyDown: (event) => {
4077
+ if (event.key !== "Enter" || event.shiftKey) return;
4078
+ if (event.nativeEvent.isComposing) return;
4079
+ event.preventDefault();
4080
+ void submitEdit();
4081
+ }
4082
+ }
4083
+ ) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MessageContent, { parts: message.parts, isUser: true }) }),
4084
+ isEditing ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "chat-message-actions", children: [
4085
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4086
+ "button",
4087
+ {
4088
+ type: "button",
4089
+ className: "chat-text-button",
4090
+ onClick: cancelEdit,
4091
+ disabled: isSubmittingEdit,
4092
+ children: "Cancel"
4093
+ }
4094
+ ),
4095
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4096
+ "button",
4097
+ {
4098
+ type: "button",
4099
+ className: "chat-text-button chat-text-button-done",
4100
+ onClick: submitEdit,
4101
+ disabled: !draft.trim() || isSubmittingEdit || isSending,
4102
+ children: "Done"
4103
+ }
4104
+ )
4105
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4106
+ "button",
4107
+ {
4108
+ type: "button",
4109
+ className: "chat-icon-button",
4110
+ onClick: () => {
4111
+ setDraft(getUserDisplayText(message));
4112
+ setIsEditing(true);
4113
+ },
4114
+ disabled: isSending,
4115
+ "aria-label": "Edit and resend message",
4116
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_lucide_react18.Pencil, { size: 14 })
4117
+ }
4118
+ )
4119
+ ] }) });
4120
+ }
4121
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "chat-message chat-message-assistant", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "chat-message-assistant-inner", children: [
4122
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MessageContent, { parts: message.parts, isUser: false }),
4123
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MessageUsage, { parts: dataParts }),
4124
+ isActiveAssistantMessage ? null : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
4125
+ MessageFeedback,
4126
+ {
4127
+ responseText: assistantText,
4128
+ canRegenerate: !!previousUserMessage,
4129
+ disabled: isSending,
4130
+ onRegenerate: () => {
4131
+ if (previousUserMessage) {
4132
+ void editAndResendMessage(
4133
+ previousUserMessage.id,
4134
+ getUserDisplayText(previousUserMessage)
4135
+ );
4136
+ }
4137
+ }
4138
+ }
4139
+ )
4140
+ ] }) });
4141
+ };
4142
+
4143
+ // src/components/Message/message.tsx
4144
+ var import_jsx_runtime40 = require("react/jsx-runtime");
4145
+ var WaitingForResponse = () => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "chat-response-status", role: "status", "aria-live": "polite", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TextSkeleton, {}) });
4146
+ var Message = () => {
4147
+ const { messages, isWaitingForResponse } = useMessages();
4148
+ const { isLoadingThread } = useThread();
4149
+ if (isLoadingThread) {
4150
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "chat-messages-inner", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "chat-loading chat-loading-initial", role: "status", "aria-live": "polite", children: "Loading conversation\u2026" }) });
4151
+ }
4152
+ if (messages.length === 0) {
4153
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "chat-messages-inner", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "chat-empty", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { children: [
4154
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "chat-empty-title", children: "How can I help?" }),
4155
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "chat-empty-copy", children: "Ask a question, explore ideas, or use tools and widgets when the agent needs them." })
4156
+ ] }) }) });
4157
+ }
4158
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "chat-messages-inner", children: [
4159
+ messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MessageItem, { message }, message.id)),
4160
+ isWaitingForResponse ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(WaitingForResponse, {}) : null
4161
+ ] });
4162
+ };
4163
+
4164
+ // src/components/Chat.tsx
4165
+ var import_jsx_runtime41 = require("react/jsx-runtime");
4166
+ function ChatShell({
4167
+ className,
4168
+ style,
4169
+ widgets,
4170
+ showThemeToggle = true,
4171
+ showModelSelector = true,
4172
+ collapsedVariant = "pill",
4173
+ defaultExpanded = false
4174
+ }) {
4175
+ const { sendMessage, isSending, messages, status } = useMessages();
4176
+ const { createThread } = useThread();
4177
+ const { resolvedTheme } = useTheme();
4178
+ const registry = (0, import_react30.useMemo)(() => createWidgetRegistry(widgets), [widgets]);
4179
+ const messagesRef = (0, import_react30.useRef)(null);
4180
+ (0, import_react30.useLayoutEffect)(() => {
4181
+ const container = messagesRef.current;
4182
+ if (!container) {
4183
+ return;
4184
+ }
4185
+ container.scrollTop = container.scrollHeight;
4186
+ }, [messages, status]);
4187
+ (0, import_react30.useLayoutEffect)(() => {
4188
+ const container = messagesRef.current;
4189
+ if (!container || status !== "submitted" && status !== "streaming") {
4190
+ return;
4191
+ }
4192
+ const scrollToEnd = () => {
4193
+ container.scrollTop = container.scrollHeight;
4194
+ };
4195
+ const observer = new ResizeObserver(scrollToEnd);
4196
+ observer.observe(container);
4197
+ const inner = container.firstElementChild;
4198
+ if (inner) {
4199
+ observer.observe(inner);
4200
+ }
4201
+ scrollToEnd();
4202
+ return () => observer.disconnect();
4203
+ }, [status]);
4204
+ const respondToWidget = (0, import_react30.useCallback)(
4205
+ async (response) => {
4206
+ var _a, _b;
4207
+ const text = (_b = (_a = response.label) != null ? _a : response.actionId) != null ? _b : typeof response.value === "string" ? response.value : JSON.stringify(response.value);
4208
+ if (!text.trim()) {
4209
+ return;
4210
+ }
4211
+ await sendMessage({ text });
4212
+ },
4213
+ [sendMessage]
4214
+ );
4215
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4216
+ WidgetProvider,
4217
+ {
4218
+ widgets: registry,
4219
+ respondToWidget,
4220
+ disabled: isSending,
4221
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
4222
+ "div",
4223
+ {
4224
+ className: ["chat-root", className].filter(Boolean).join(" "),
4225
+ style,
4226
+ "data-theme": resolvedTheme,
4227
+ children: [
4228
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "chat-toolbar", children: [
4229
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4230
+ "button",
4231
+ {
4232
+ type: "button",
4233
+ className: "chat-theme-toggle",
4234
+ onClick: () => void createThread(),
4235
+ "aria-label": "Start a new chat",
4236
+ title: "New chat",
4237
+ disabled: isSending,
4238
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react19.PenSquare, { size: 16, strokeWidth: 1.75 })
4239
+ }
4240
+ ),
4241
+ showThemeToggle && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ThemeToggle, {})
4242
+ ] }),
4243
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "chat-messages", ref: messagesRef, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Message, {}) }),
4244
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "chat-composer", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4245
+ ChatComposer,
4246
+ {
4247
+ showModelSelector,
4248
+ collapsedVariant,
4249
+ defaultExpanded
4250
+ }
4251
+ ) })
4252
+ ]
4253
+ }
4254
+ )
4255
+ }
4256
+ );
4257
+ }
4258
+ function Chat({
4259
+ adapter,
4260
+ className,
4261
+ defaultThreadId,
4262
+ defaultProvider,
4263
+ registryUrl,
4264
+ style,
4265
+ widgets,
4266
+ theme,
4267
+ defaultTheme = "system",
4268
+ onThemeChange,
4269
+ showThemeToggle = true,
4270
+ showModelSelector = true,
4271
+ collapsedVariant = "pill",
4272
+ defaultExpanded = false
4273
+ }) {
4274
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4275
+ ThemeProvider,
4276
+ {
4277
+ theme,
4278
+ defaultTheme,
4279
+ onThemeChange,
4280
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4281
+ ChatContextProvider,
4282
+ {
4283
+ adapter,
4284
+ defaultThreadId,
4285
+ defaultProvider,
4286
+ registryUrl,
4287
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4288
+ ChatShell,
4289
+ {
4290
+ className,
4291
+ style,
4292
+ widgets,
4293
+ showThemeToggle,
4294
+ showModelSelector,
4295
+ collapsedVariant,
4296
+ defaultExpanded
4297
+ }
4298
+ )
4299
+ }
4300
+ )
4301
+ }
4302
+ );
4303
+ }
4304
+
4305
+ // src/index.ts
4306
+ var import_adapter = require("@sarchauhan/adapter");
4307
+ var import_protocol7 = require("@sarchauhan/protocol");
4308
+
4309
+ // src/widgets/index.ts
4310
+ var import_protocol6 = require("@sarchauhan/protocol");
4311
+ // Annotate the CommonJS export names for ESM import in node:
4312
+ 0 && (module.exports = {
4313
+ ArtifactWidget,
4314
+ ArtifactsWidget,
4315
+ BaseWidget,
4316
+ Chat,
4317
+ ChatComposer,
4318
+ ChatContextProvider,
4319
+ LoadingState,
4320
+ Message,
4321
+ MessageContent,
4322
+ MessageFeedback,
4323
+ MessageUsage,
4324
+ PatchWidget,
4325
+ ProviderId,
4326
+ QuestionWidget,
4327
+ ReadFileWidget,
4328
+ ResponsiveDetail,
4329
+ SearchWidget,
4330
+ SubagentWidget,
4331
+ TextSwap,
4332
+ ThemeProvider,
4333
+ ThemeToggle,
4334
+ ThinkingBlock,
4335
+ WidgetProvider,
4336
+ WidgetRenderer,
4337
+ applyAgentEvent,
4338
+ calibrateCheckPath,
4339
+ clearErrorShake,
4340
+ closeDropdown,
4341
+ computeDiff,
4342
+ computeTextDiff,
4343
+ computeToolState,
4344
+ computeToolWidget,
4345
+ createAgentMessageState,
4346
+ createArtifactData,
4347
+ createSubagentData,
4348
+ createWidgetData,
4349
+ createWidgetRegistry,
4350
+ defineAdapter,
4351
+ defineWidget,
4352
+ dropdownOrigins,
4353
+ formatArtifactSize,
4354
+ formatElapsed,
4355
+ formatElapsedWords,
4356
+ iconSwapStates,
4357
+ isProviderId,
4358
+ motion,
4359
+ motionData,
4360
+ motionRoot,
4361
+ normalizeAgentMessage,
4362
+ normalizeAgentParts,
4363
+ normalizeSearchResults,
4364
+ openDropdown,
4365
+ parseArtifact,
4366
+ parseRegistryConfig,
4367
+ parseSubagent,
4368
+ prebuiltWidgets,
4369
+ prefersReducedMotion,
4370
+ readDurationMs,
4371
+ reduceAgentEvents,
4372
+ safeArtifactUrl,
4373
+ safeResultUrl,
4374
+ successCheckStates,
4375
+ swapText,
4376
+ triggerErrorShake,
4377
+ useChat,
4378
+ useComposer,
4379
+ useDropdownPresence,
4380
+ useMessages,
4381
+ useModel,
4382
+ useTheme,
4383
+ useThread,
4384
+ useWidgets
4385
+ });
4386
+ //# sourceMappingURL=index.js.map