@assistant-ui/react 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js ADDED
@@ -0,0 +1,1644 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ ActionBarPrimitive: () => actionBar_exports,
34
+ AssistantRuntimeProvider: () => AssistantRuntimeProvider,
35
+ BranchPickerPrimitive: () => branchPicker_exports,
36
+ ComposerPrimitive: () => composer_exports,
37
+ ContentPartPrimitive: () => contentPart_exports,
38
+ INTERNAL: () => internal_exports,
39
+ MessagePrimitive: () => message_exports,
40
+ ThreadPrimitive: () => thread_exports,
41
+ useBeginMessageEdit: () => useBeginMessageEdit,
42
+ useCopyMessage: () => useCopyMessage,
43
+ useGoToNextBranch: () => useGoToNextBranch,
44
+ useGoToPreviousBranch: () => useGoToPreviousBranch,
45
+ useLocalRuntime: () => useLocalRuntime,
46
+ useReloadMessage: () => useReloadMessage
47
+ });
48
+ module.exports = __toCommonJS(src_exports);
49
+
50
+ // src/actions/useCopyMessage.tsx
51
+ var import_react4 = require("react");
52
+
53
+ // src/context/MessageContext.ts
54
+ var import_react = require("react");
55
+ var MessageContext = (0, import_react.createContext)(null);
56
+ var useMessageContext = () => {
57
+ const context = (0, import_react.useContext)(MessageContext);
58
+ if (!context)
59
+ throw new Error(
60
+ "This component can only be used inside a component passed to <ThreadPrimitive.Messages components={...} />."
61
+ );
62
+ return context;
63
+ };
64
+
65
+ // src/utils/combined/useCombinedStore.ts
66
+ var import_react3 = require("react");
67
+
68
+ // src/utils/combined/createCombinedStore.ts
69
+ var import_react2 = require("react");
70
+ var createCombinedStore = (stores) => {
71
+ const subscribe = (callback) => {
72
+ const unsubscribes = stores.map((store) => store.subscribe(callback));
73
+ return () => {
74
+ for (const unsub of unsubscribes) {
75
+ unsub();
76
+ }
77
+ };
78
+ };
79
+ return (selector) => {
80
+ const getSnapshot = () => selector(...stores.map((store) => store.getState()));
81
+ return (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
82
+ };
83
+ };
84
+
85
+ // src/utils/combined/useCombinedStore.ts
86
+ var useCombinedStore = (stores, selector) => {
87
+ const useCombined = (0, import_react3.useMemo)(() => createCombinedStore(stores), stores);
88
+ return useCombined(selector);
89
+ };
90
+
91
+ // src/utils/getMessageText.tsx
92
+ var getMessageText = (message) => {
93
+ const textParts = message.content.filter(
94
+ (part) => part.type === "text"
95
+ );
96
+ return textParts.map((part) => part.text).join("\n\n");
97
+ };
98
+
99
+ // src/actions/useCopyMessage.tsx
100
+ var useCopyMessage = ({ copiedDuration = 3e3 }) => {
101
+ const { useMessage, useComposer } = useMessageContext();
102
+ const hasCopyableContent = useCombinedStore(
103
+ [useMessage, useComposer],
104
+ (m, c) => {
105
+ return c.isEditing || m.message.content.some((c2) => c2.type === "text");
106
+ }
107
+ );
108
+ const callback = (0, import_react4.useCallback)(() => {
109
+ const { isEditing, value: composerValue } = useComposer.getState();
110
+ const { message, setIsCopied } = useMessage.getState();
111
+ const valueToCopy = isEditing ? composerValue : getMessageText(message);
112
+ navigator.clipboard.writeText(valueToCopy);
113
+ setIsCopied(true);
114
+ setTimeout(() => setIsCopied(false), copiedDuration);
115
+ }, [useComposer, useMessage, copiedDuration]);
116
+ if (!hasCopyableContent) return null;
117
+ return callback;
118
+ };
119
+
120
+ // src/actions/useReloadMessage.tsx
121
+ var import_react6 = require("react");
122
+
123
+ // src/context/ThreadContext.ts
124
+ var import_react5 = require("react");
125
+ var ThreadContext = (0, import_react5.createContext)(null);
126
+ var useThreadContext = () => {
127
+ const context = (0, import_react5.useContext)(ThreadContext);
128
+ if (!context)
129
+ throw new Error("This component must be used within an AssistantRuntimeProvider.");
130
+ return context;
131
+ };
132
+
133
+ // src/actions/useReloadMessage.tsx
134
+ var useReloadMessage = () => {
135
+ const { useThread, useViewport } = useThreadContext();
136
+ const { useMessage } = useMessageContext();
137
+ const disabled = useCombinedStore(
138
+ [useThread, useMessage],
139
+ (t, m) => t.isRunning || m.message.role !== "assistant"
140
+ );
141
+ const callback = (0, import_react6.useCallback)(() => {
142
+ const { parentId } = useMessage.getState();
143
+ useThread.getState().startRun(parentId);
144
+ useViewport.getState().scrollToBottom();
145
+ }, [useMessage, useThread, useViewport]);
146
+ if (disabled) return null;
147
+ return callback;
148
+ };
149
+
150
+ // src/actions/useBeginMessageEdit.tsx
151
+ var import_react7 = require("react");
152
+ var useBeginMessageEdit = () => {
153
+ const { useMessage, useComposer } = useMessageContext();
154
+ const disabled = useCombinedStore(
155
+ [useMessage, useComposer],
156
+ (m, c) => m.message.role !== "user" || c.isEditing
157
+ );
158
+ const callback = (0, import_react7.useCallback)(() => {
159
+ const { edit } = useComposer.getState();
160
+ edit();
161
+ }, [useComposer]);
162
+ if (disabled) return null;
163
+ return callback;
164
+ };
165
+
166
+ // src/actions/useGoToNextBranch.tsx
167
+ var import_react8 = require("react");
168
+ var useGoToNextBranch = () => {
169
+ const { useThread } = useThreadContext();
170
+ const { useMessage, useComposer } = useMessageContext();
171
+ const disabled = useCombinedStore(
172
+ [useMessage, useComposer],
173
+ (m, c) => c.isEditing || m.branches.indexOf(m.message.id) + 1 >= m.branches.length
174
+ );
175
+ const callback = (0, import_react8.useCallback)(() => {
176
+ const { message, branches } = useMessage.getState();
177
+ useThread.getState().switchToBranch(branches[branches.indexOf(message.id) + 1]);
178
+ }, [useMessage, useThread]);
179
+ if (disabled) return null;
180
+ return callback;
181
+ };
182
+
183
+ // src/actions/useGoToPreviousBranch.tsx
184
+ var import_react9 = require("react");
185
+ var useGoToPreviousBranch = () => {
186
+ const { useThread } = useThreadContext();
187
+ const { useMessage, useComposer } = useMessageContext();
188
+ const disabled = useCombinedStore(
189
+ [useMessage, useComposer],
190
+ (m, c) => c.isEditing || m.branches.indexOf(m.message.id) <= 0
191
+ );
192
+ const callback = (0, import_react9.useCallback)(() => {
193
+ const { message, branches } = useMessage.getState();
194
+ useThread.getState().switchToBranch(branches[branches.indexOf(message.id) - 1]);
195
+ }, [useMessage, useThread]);
196
+ if (disabled) return null;
197
+ return callback;
198
+ };
199
+
200
+ // src/primitives/thread/index.ts
201
+ var thread_exports = {};
202
+ __export(thread_exports, {
203
+ Empty: () => ThreadEmpty,
204
+ If: () => ThreadIf,
205
+ Messages: () => ThreadMessages,
206
+ Root: () => ThreadRoot,
207
+ ScrollToBottom: () => ThreadScrollToBottom,
208
+ Suggestion: () => ThreadSuggestion,
209
+ Viewport: () => ThreadViewport
210
+ });
211
+
212
+ // src/primitives/thread/ThreadRoot.tsx
213
+ var import_react_primitive = require("@radix-ui/react-primitive");
214
+ var import_react10 = require("react");
215
+ var import_jsx_runtime = require("react/jsx-runtime");
216
+ var ThreadRoot = (0, import_react10.forwardRef)(
217
+ (props, ref) => {
218
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...props, ref });
219
+ }
220
+ );
221
+
222
+ // src/primitives/thread/ThreadIf.tsx
223
+ var useThreadIf = (props) => {
224
+ const { useThread } = useThreadContext();
225
+ return useThread((thread) => {
226
+ if (props.empty === true && thread.messages.length !== 0) return false;
227
+ if (props.empty === false && thread.messages.length === 0) return false;
228
+ if (props.running === true && !thread.isRunning) return false;
229
+ if (props.running === false && thread.isRunning) return false;
230
+ return true;
231
+ });
232
+ };
233
+ var ThreadIf = ({ children, ...query }) => {
234
+ const result = useThreadIf(query);
235
+ return result ? children : null;
236
+ };
237
+
238
+ // src/primitives/thread/ThreadEmpty.tsx
239
+ var import_jsx_runtime2 = require("react/jsx-runtime");
240
+ var ThreadEmpty = ({ children }) => {
241
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ThreadIf, { empty: true, children });
242
+ };
243
+
244
+ // src/primitives/thread/ThreadViewport.tsx
245
+ var import_primitive = require("@radix-ui/primitive");
246
+ var import_react_compose_refs = require("@radix-ui/react-compose-refs");
247
+ var import_react_primitive2 = require("@radix-ui/react-primitive");
248
+ var import_react13 = require("react");
249
+
250
+ // src/utils/hooks/useOnResizeContent.tsx
251
+ var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
252
+ var import_react11 = require("react");
253
+ var useOnResizeContent = (ref, callback) => {
254
+ const callbackRef = (0, import_react_use_callback_ref.useCallbackRef)(callback);
255
+ (0, import_react11.useEffect)(() => {
256
+ const el = ref.current;
257
+ if (!el) return;
258
+ const resizeObserver = new ResizeObserver(() => {
259
+ callbackRef();
260
+ });
261
+ const mutationObserver = new MutationObserver((mutations) => {
262
+ for (const mutation of mutations) {
263
+ for (const node of mutation.addedNodes) {
264
+ if (node instanceof Element) {
265
+ resizeObserver.observe(node);
266
+ }
267
+ }
268
+ for (const node of mutation.removedNodes) {
269
+ if (node instanceof Element) {
270
+ resizeObserver.unobserve(node);
271
+ }
272
+ }
273
+ }
274
+ callbackRef();
275
+ });
276
+ resizeObserver.observe(el);
277
+ mutationObserver.observe(el, { childList: true });
278
+ for (const child of el.children) {
279
+ resizeObserver.observe(child);
280
+ }
281
+ return () => {
282
+ resizeObserver.disconnect();
283
+ mutationObserver.disconnect();
284
+ };
285
+ }, [ref.current, callbackRef]);
286
+ };
287
+
288
+ // src/utils/hooks/useOnScrollToBottom.tsx
289
+ var import_react_use_callback_ref2 = require("@radix-ui/react-use-callback-ref");
290
+ var import_react12 = require("react");
291
+ var useOnScrollToBottom = (callback) => {
292
+ const callbackRef = (0, import_react_use_callback_ref2.useCallbackRef)(callback);
293
+ const { useViewport } = useThreadContext();
294
+ (0, import_react12.useEffect)(() => {
295
+ return useViewport.getState().onScrollToBottom(() => {
296
+ callbackRef();
297
+ });
298
+ }, [useViewport, callbackRef]);
299
+ };
300
+
301
+ // src/primitives/thread/ThreadViewport.tsx
302
+ var import_jsx_runtime3 = require("react/jsx-runtime");
303
+ var ThreadViewport = (0, import_react13.forwardRef)(({ autoScroll = true, onScroll, children, ...rest }, forwardedRef) => {
304
+ const messagesEndRef = (0, import_react13.useRef)(null);
305
+ const divRef = (0, import_react13.useRef)(null);
306
+ const ref = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, divRef);
307
+ const { useViewport } = useThreadContext();
308
+ const firstRenderRef = (0, import_react13.useRef)(true);
309
+ const isScrollingToBottomRef = (0, import_react13.useRef)(false);
310
+ const lastScrollTop = (0, import_react13.useRef)(0);
311
+ const scrollToBottom = () => {
312
+ const div = messagesEndRef.current;
313
+ if (!div || !autoScroll) return;
314
+ const behavior = firstRenderRef.current ? "instant" : "auto";
315
+ firstRenderRef.current = false;
316
+ isScrollingToBottomRef.current = true;
317
+ div.scrollIntoView({ behavior });
318
+ };
319
+ useOnResizeContent(divRef, () => {
320
+ if (!isScrollingToBottomRef.current && !useViewport.getState().isAtBottom) {
321
+ handleScroll();
322
+ } else {
323
+ scrollToBottom();
324
+ }
325
+ });
326
+ useOnScrollToBottom(() => {
327
+ scrollToBottom();
328
+ });
329
+ const handleScroll = () => {
330
+ const div = divRef.current;
331
+ if (!div) return;
332
+ const isAtBottom = useViewport.getState().isAtBottom;
333
+ const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
334
+ if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
335
+ } else if (newIsAtBottom !== isAtBottom) {
336
+ isScrollingToBottomRef.current = false;
337
+ useViewport.setState({ isAtBottom: newIsAtBottom });
338
+ }
339
+ lastScrollTop.current = div.scrollTop;
340
+ };
341
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
342
+ import_react_primitive2.Primitive.div,
343
+ {
344
+ ...rest,
345
+ onScroll: (0, import_primitive.composeEventHandlers)(onScroll, handleScroll),
346
+ ref,
347
+ children: [
348
+ children,
349
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: messagesEndRef })
350
+ ]
351
+ }
352
+ );
353
+ });
354
+
355
+ // src/primitives/thread/ThreadMessages.tsx
356
+ var import_react16 = require("react");
357
+
358
+ // src/context/providers/MessageProvider.tsx
359
+ var import_react14 = require("react");
360
+ var import_zustand2 = require("zustand");
361
+
362
+ // src/context/stores/MessageComposer.ts
363
+ var import_zustand = require("zustand");
364
+
365
+ // src/context/stores/BaseComposer.ts
366
+ var makeBaseComposer = (set) => ({
367
+ value: "",
368
+ setValue: (value) => {
369
+ set({ value });
370
+ }
371
+ });
372
+
373
+ // src/context/stores/MessageComposer.ts
374
+ var makeEditComposerStore = ({
375
+ onEdit,
376
+ onSend
377
+ }) => (0, import_zustand.create)()((set, get, store) => ({
378
+ ...makeBaseComposer(set, get, store),
379
+ isEditing: false,
380
+ edit: () => {
381
+ const value = onEdit();
382
+ set({ isEditing: true, value });
383
+ },
384
+ send: () => {
385
+ const value = get().value;
386
+ set({ isEditing: false });
387
+ onSend(value);
388
+ },
389
+ cancel: () => {
390
+ if (!get().isEditing) return false;
391
+ set({ isEditing: false });
392
+ return true;
393
+ }
394
+ }));
395
+
396
+ // src/context/providers/MessageProvider.tsx
397
+ var import_jsx_runtime4 = require("react/jsx-runtime");
398
+ var getIsLast = (thread, message) => {
399
+ return thread.messages[thread.messages.length - 1]?.id === message.id;
400
+ };
401
+ var syncMessage = (thread, useMessage, messageIndex) => {
402
+ const parentId = thread.messages[messageIndex - 1]?.id ?? null;
403
+ const message = thread.messages[messageIndex];
404
+ if (!message) return;
405
+ const isLast = getIsLast(thread, message);
406
+ const branches = thread.getBranches(message.id);
407
+ const currentState = useMessage.getState();
408
+ if (currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
409
+ return;
410
+ useMessage.setState({
411
+ message,
412
+ parentId,
413
+ branches,
414
+ isLast
415
+ });
416
+ };
417
+ var useMessageContext2 = (messageIndex) => {
418
+ const { useThread } = useThreadContext();
419
+ const [context] = (0, import_react14.useState)(() => {
420
+ const useMessage = (0, import_zustand2.create)((set) => ({
421
+ message: null,
422
+ parentId: null,
423
+ branches: [],
424
+ isLast: false,
425
+ inProgressIndicator: null,
426
+ isCopied: false,
427
+ isHovering: false,
428
+ setInProgressIndicator: (value) => {
429
+ set({ inProgressIndicator: value });
430
+ },
431
+ setIsCopied: (value) => {
432
+ set({ isCopied: value });
433
+ },
434
+ setIsHovering: (value) => {
435
+ set({ isHovering: value });
436
+ }
437
+ }));
438
+ const useComposer = makeEditComposerStore({
439
+ onEdit: () => {
440
+ const message = useMessage.getState().message;
441
+ if (message.role !== "user")
442
+ throw new Error(
443
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
444
+ );
445
+ const text = getMessageText(message);
446
+ return text;
447
+ },
448
+ onSend: (text) => {
449
+ const { message, parentId } = useMessage.getState();
450
+ if (message.role !== "user")
451
+ throw new Error(
452
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
453
+ );
454
+ const nonTextParts = message.content.filter(
455
+ (part) => part.type !== "text" && part.type !== "ui"
456
+ );
457
+ useThread.getState().append({
458
+ parentId,
459
+ content: [{ type: "text", text }, ...nonTextParts]
460
+ });
461
+ }
462
+ });
463
+ syncMessage(useThread.getState(), useMessage, messageIndex);
464
+ return { useMessage, useComposer };
465
+ });
466
+ (0, import_react14.useEffect)(() => {
467
+ return useThread.subscribe((thread) => {
468
+ syncMessage(thread, context.useMessage, messageIndex);
469
+ });
470
+ }, [context, useThread, messageIndex]);
471
+ return context;
472
+ };
473
+ var MessageProvider = ({
474
+ messageIndex,
475
+ children
476
+ }) => {
477
+ const context = useMessageContext2(messageIndex);
478
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MessageContext.Provider, { value: context, children });
479
+ };
480
+
481
+ // src/context/ComposerContext.ts
482
+ var import_react15 = require("react");
483
+ var useComposerContext = () => {
484
+ const { useComposer } = useThreadContext();
485
+ const { useComposer: useEditComposer } = (0, import_react15.useContext)(MessageContext) ?? {};
486
+ return (0, import_react15.useMemo)(
487
+ () => ({
488
+ useComposer: useEditComposer ?? useComposer,
489
+ type: useEditComposer ? "edit" : "new"
490
+ }),
491
+ [useEditComposer, useComposer]
492
+ );
493
+ };
494
+
495
+ // src/primitives/composer/ComposerIf.tsx
496
+ var useComposerIf = (props) => {
497
+ const { useComposer } = useComposerContext();
498
+ return useComposer((composer) => {
499
+ if (props.editing === true && !composer.isEditing) return false;
500
+ if (props.editing === false && composer.isEditing) return false;
501
+ return true;
502
+ });
503
+ };
504
+ var ComposerIf = ({ children, ...query }) => {
505
+ const result = useComposerIf(query);
506
+ return result ? children : null;
507
+ };
508
+
509
+ // src/primitives/message/MessageIf.tsx
510
+ var useMessageIf = (props) => {
511
+ const { useMessage } = useMessageContext();
512
+ return useMessage(({ message, branches, isLast, isCopied, isHovering }) => {
513
+ if (props.hasBranches === true && branches.length < 2) return false;
514
+ if (props.user && message.role !== "user") return false;
515
+ if (props.assistant && message.role !== "assistant") return false;
516
+ if (props.lastOrHover === true && !isHovering && !isLast) return false;
517
+ if (props.copied === true && !isCopied) return false;
518
+ if (props.copied === false && isCopied) return false;
519
+ return true;
520
+ });
521
+ };
522
+ var MessageIf = ({ children, ...query }) => {
523
+ const result = useMessageIf(query);
524
+ return result ? children : null;
525
+ };
526
+
527
+ // src/primitives/thread/ThreadMessages.tsx
528
+ var import_jsx_runtime5 = require("react/jsx-runtime");
529
+ var getComponents = (components) => {
530
+ return {
531
+ EditComposer: components.EditComposer ?? components.UserMessage ?? components.Message,
532
+ UserMessage: components.UserMessage ?? components.Message,
533
+ AssistantMessage: components.AssistantMessage ?? components.Message
534
+ };
535
+ };
536
+ var ThreadMessageImpl = ({
537
+ messageIndex,
538
+ components
539
+ }) => {
540
+ const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
541
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(MessageProvider, { messageIndex, children: [
542
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(MessageIf, { user: true, children: [
543
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ComposerIf, { editing: false, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(UserMessage, {}) }),
544
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ComposerIf, { editing: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EditComposer, {}) })
545
+ ] }),
546
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageIf, { assistant: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AssistantMessage, {}) })
547
+ ] });
548
+ };
549
+ var ThreadMessage = (0, import_react16.memo)(
550
+ ThreadMessageImpl,
551
+ (prev, next) => prev.messageIndex === next.messageIndex && prev.components.UserMessage === next.components.UserMessage && prev.components.EditComposer === next.components.EditComposer && prev.components.AssistantMessage === next.components.AssistantMessage
552
+ );
553
+ var ThreadMessages = ({ components }) => {
554
+ const { useThread } = useThreadContext();
555
+ const messagesLength = useThread((t) => t.messages.length);
556
+ if (messagesLength === 0) return null;
557
+ return new Array(messagesLength).fill(null).map((_, idx) => {
558
+ const messageIndex = idx;
559
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
560
+ ThreadMessage,
561
+ {
562
+ messageIndex,
563
+ components
564
+ },
565
+ messageIndex
566
+ );
567
+ });
568
+ };
569
+
570
+ // src/primitives/thread/ThreadScrollToBottom.tsx
571
+ var import_primitive2 = require("@radix-ui/primitive");
572
+ var import_react_primitive3 = require("@radix-ui/react-primitive");
573
+ var import_react17 = require("react");
574
+ var import_jsx_runtime6 = require("react/jsx-runtime");
575
+ var ThreadScrollToBottom = (0, import_react17.forwardRef)(({ onClick, ...rest }, ref) => {
576
+ const { useViewport } = useThreadContext();
577
+ const isAtBottom = useViewport((s) => s.isAtBottom);
578
+ const handleScrollToBottom = () => {
579
+ useViewport.getState().scrollToBottom();
580
+ };
581
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
582
+ import_react_primitive3.Primitive.button,
583
+ {
584
+ ...rest,
585
+ disabled: isAtBottom,
586
+ ref,
587
+ onClick: (0, import_primitive2.composeEventHandlers)(onClick, handleScrollToBottom)
588
+ }
589
+ );
590
+ });
591
+
592
+ // src/primitives/thread/ThreadSuggestion.tsx
593
+ var import_primitive3 = require("@radix-ui/primitive");
594
+ var import_react_primitive4 = require("@radix-ui/react-primitive");
595
+ var import_react18 = require("react");
596
+ var import_jsx_runtime7 = require("react/jsx-runtime");
597
+ var ThreadSuggestion = (0, import_react18.forwardRef)(({ onClick, prompt, method, autoSend: send, ...rest }, ref) => {
598
+ const { useThread, useComposer } = useThreadContext();
599
+ const isDisabled = useThread((t) => t.isRunning);
600
+ const handleApplySuggestion = () => {
601
+ const thread = useThread.getState();
602
+ const composer = useComposer.getState();
603
+ composer.setValue(prompt);
604
+ if (send && !thread.isRunning) {
605
+ composer.send();
606
+ }
607
+ };
608
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
609
+ import_react_primitive4.Primitive.button,
610
+ {
611
+ ...rest,
612
+ disabled: isDisabled,
613
+ ref,
614
+ onClick: (0, import_primitive3.composeEventHandlers)(onClick, handleApplySuggestion)
615
+ }
616
+ );
617
+ });
618
+
619
+ // src/primitives/composer/index.ts
620
+ var composer_exports = {};
621
+ __export(composer_exports, {
622
+ Cancel: () => ComposerCancel,
623
+ If: () => ComposerIf,
624
+ Input: () => ComposerInput,
625
+ Root: () => ComposerRoot,
626
+ Send: () => ComposerSend
627
+ });
628
+
629
+ // src/primitives/composer/ComposerRoot.tsx
630
+ var import_primitive4 = require("@radix-ui/primitive");
631
+ var import_react_compose_refs2 = require("@radix-ui/react-compose-refs");
632
+ var import_react_primitive5 = require("@radix-ui/react-primitive");
633
+ var import_react19 = require("react");
634
+ var import_jsx_runtime8 = require("react/jsx-runtime");
635
+ var ComposerRoot = (0, import_react19.forwardRef)(
636
+ ({ onSubmit, ...rest }, forwardedRef) => {
637
+ const { useViewport } = useThreadContext();
638
+ const { useComposer } = useComposerContext();
639
+ const formRef = (0, import_react19.useRef)(null);
640
+ const ref = (0, import_react_compose_refs2.useComposedRefs)(forwardedRef, formRef);
641
+ const handleSubmit = (e) => {
642
+ const composerState = useComposer.getState();
643
+ if (!composerState.isEditing) return;
644
+ e.preventDefault();
645
+ composerState.send();
646
+ useViewport.getState().scrollToBottom();
647
+ };
648
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
649
+ import_react_primitive5.Primitive.form,
650
+ {
651
+ ...rest,
652
+ ref,
653
+ onSubmit: (0, import_primitive4.composeEventHandlers)(onSubmit, handleSubmit)
654
+ }
655
+ );
656
+ }
657
+ );
658
+
659
+ // src/primitives/composer/ComposerInput.tsx
660
+ var import_primitive5 = require("@radix-ui/primitive");
661
+ var import_react_compose_refs3 = require("@radix-ui/react-compose-refs");
662
+ var import_react_slot = require("@radix-ui/react-slot");
663
+ var import_react20 = require("react");
664
+ var import_react_textarea_autosize = __toESM(require("react-textarea-autosize"));
665
+ var import_jsx_runtime9 = require("react/jsx-runtime");
666
+ var ComposerInput = (0, import_react20.forwardRef)(
667
+ ({ autoFocus = false, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
668
+ const { useThread } = useThreadContext();
669
+ const { useComposer, type } = useComposerContext();
670
+ const value = useComposer((c) => {
671
+ if (!c.isEditing) return "";
672
+ return c.value;
673
+ });
674
+ const Component = asChild ? import_react_slot.Slot : import_react_textarea_autosize.default;
675
+ const textareaRef = (0, import_react20.useRef)(null);
676
+ const ref = (0, import_react_compose_refs3.useComposedRefs)(forwardedRef, textareaRef);
677
+ const handleKeyPress = (e) => {
678
+ if (disabled) return;
679
+ if (e.key === "Escape") {
680
+ const composer = useComposer.getState();
681
+ if (composer.cancel()) {
682
+ e.preventDefault();
683
+ }
684
+ } else if (e.key === "Enter" && e.shiftKey === false) {
685
+ const isRunning = useThread.getState().isRunning;
686
+ if (!isRunning) {
687
+ e.preventDefault();
688
+ textareaRef.current?.closest("form")?.requestSubmit();
689
+ }
690
+ }
691
+ };
692
+ const autoFocusEnabled = autoFocus && !disabled;
693
+ const focus = (0, import_react20.useCallback)(() => {
694
+ const textarea = textareaRef.current;
695
+ if (!textarea || !autoFocusEnabled) return;
696
+ console.log("focus");
697
+ textarea.focus();
698
+ textarea.setSelectionRange(
699
+ textareaRef.current.value.length,
700
+ textareaRef.current.value.length
701
+ );
702
+ }, [autoFocusEnabled]);
703
+ (0, import_react20.useEffect)(() => focus(), [focus]);
704
+ useOnScrollToBottom(() => {
705
+ if (type === "new") {
706
+ focus();
707
+ }
708
+ });
709
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
710
+ Component,
711
+ {
712
+ value,
713
+ ...rest,
714
+ ref,
715
+ autoFocus,
716
+ disabled,
717
+ onChange: (0, import_primitive5.composeEventHandlers)(onChange, (e) => {
718
+ const composerState = useComposer.getState();
719
+ if (!composerState.isEditing) return;
720
+ return composerState.setValue(e.target.value);
721
+ }),
722
+ onKeyDown: (0, import_primitive5.composeEventHandlers)(onKeyDown, handleKeyPress)
723
+ }
724
+ );
725
+ }
726
+ );
727
+
728
+ // src/primitives/composer/ComposerSend.tsx
729
+ var import_react_primitive6 = require("@radix-ui/react-primitive");
730
+ var import_react21 = require("react");
731
+ var import_jsx_runtime10 = require("react/jsx-runtime");
732
+ var ComposerSend = (0, import_react21.forwardRef)(
733
+ ({ disabled, ...rest }, ref) => {
734
+ const { useComposer } = useComposerContext();
735
+ const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
736
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
737
+ import_react_primitive6.Primitive.button,
738
+ {
739
+ type: "submit",
740
+ ...rest,
741
+ ref,
742
+ disabled: disabled || !hasValue
743
+ }
744
+ );
745
+ }
746
+ );
747
+
748
+ // src/primitives/composer/ComposerCancel.tsx
749
+ var import_primitive6 = require("@radix-ui/primitive");
750
+ var import_react_primitive7 = require("@radix-ui/react-primitive");
751
+ var import_react22 = require("react");
752
+ var import_jsx_runtime11 = require("react/jsx-runtime");
753
+ var ComposerCancel = (0, import_react22.forwardRef)(({ onClick, ...rest }, ref) => {
754
+ const { useComposer } = useComposerContext();
755
+ const handleCancel = () => {
756
+ useComposer.getState().cancel();
757
+ };
758
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
759
+ import_react_primitive7.Primitive.button,
760
+ {
761
+ type: "button",
762
+ ...rest,
763
+ ref,
764
+ onClick: (0, import_primitive6.composeEventHandlers)(onClick, handleCancel)
765
+ }
766
+ );
767
+ });
768
+
769
+ // src/primitives/message/index.ts
770
+ var message_exports = {};
771
+ __export(message_exports, {
772
+ Content: () => MessageContent,
773
+ If: () => MessageIf,
774
+ InProgress: () => MessageInProgress,
775
+ Root: () => MessageRoot
776
+ });
777
+
778
+ // src/primitives/message/MessageRoot.tsx
779
+ var import_primitive7 = require("@radix-ui/primitive");
780
+ var import_react_primitive8 = require("@radix-ui/react-primitive");
781
+ var import_react23 = require("react");
782
+ var import_jsx_runtime12 = require("react/jsx-runtime");
783
+ var MessageRoot = (0, import_react23.forwardRef)(
784
+ ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
785
+ const { useMessage } = useMessageContext();
786
+ const setIsHovering = useMessage((s) => s.setIsHovering);
787
+ const handleMouseEnter = () => {
788
+ setIsHovering(true);
789
+ };
790
+ const handleMouseLeave = () => {
791
+ setIsHovering(false);
792
+ };
793
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
794
+ import_react_primitive8.Primitive.div,
795
+ {
796
+ ...rest,
797
+ ref,
798
+ onMouseEnter: (0, import_primitive7.composeEventHandlers)(onMouseEnter, handleMouseEnter),
799
+ onMouseLeave: (0, import_primitive7.composeEventHandlers)(onMouseLeave, handleMouseLeave)
800
+ }
801
+ );
802
+ }
803
+ );
804
+
805
+ // src/primitives/message/MessageContent.tsx
806
+ var import_react28 = require("react");
807
+
808
+ // src/context/AssistantContext.ts
809
+ var import_react24 = require("react");
810
+ var AssistantContext = (0, import_react24.createContext)(
811
+ null
812
+ );
813
+ var useAssistantContext = () => {
814
+ const context = (0, import_react24.useContext)(AssistantContext);
815
+ if (!context)
816
+ throw new Error(
817
+ "This component must be used within an AssistantRuntimeProvider."
818
+ );
819
+ return context;
820
+ };
821
+
822
+ // src/context/ContentPartContext.ts
823
+ var import_react25 = require("react");
824
+ var ContentPartContext = (0, import_react25.createContext)(
825
+ null
826
+ );
827
+ var useContentPartContext = () => {
828
+ const context = (0, import_react25.useContext)(ContentPartContext);
829
+ if (!context)
830
+ throw new Error(
831
+ "This component can only be used inside a component passed to <MessagePrimitive.Content components={...} >."
832
+ );
833
+ return context;
834
+ };
835
+
836
+ // src/context/providers/ContentPartProvider.tsx
837
+ var import_react26 = require("react");
838
+ var import_zustand3 = require("zustand");
839
+ var import_jsx_runtime13 = require("react/jsx-runtime");
840
+ var syncContentPart = ({ message }, useContentPart, partIndex) => {
841
+ const part = message.content[partIndex];
842
+ if (!part) return;
843
+ const messageStatus = message.role === "assistant" ? message.status : "done";
844
+ const status = partIndex === message.content.length - 1 ? messageStatus : "done";
845
+ const currentState = useContentPart.getState();
846
+ if (currentState.part === part && currentState.status === status) return;
847
+ useContentPart.setState({ part, status });
848
+ };
849
+ var useContentPartContext2 = (partIndex) => {
850
+ const { useMessage } = useMessageContext();
851
+ const [context] = (0, import_react26.useState)(() => {
852
+ const useContentPart = (0, import_zustand3.create)(() => ({
853
+ part: { type: "text", text: "" },
854
+ status: "done"
855
+ }));
856
+ syncContentPart(useMessage.getState(), useContentPart, partIndex);
857
+ return { useContentPart };
858
+ });
859
+ (0, import_react26.useEffect)(() => {
860
+ return useMessage.subscribe((message) => {
861
+ syncContentPart(message, context.useContentPart, partIndex);
862
+ });
863
+ }, [context, useMessage, partIndex]);
864
+ return context;
865
+ };
866
+ var ContentPartProvider = ({
867
+ partIndex,
868
+ children
869
+ }) => {
870
+ const context = useContentPartContext2(partIndex);
871
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ContentPartContext.Provider, { value: context, children });
872
+ };
873
+
874
+ // src/primitives/contentPart/ContentPartDisplay.tsx
875
+ var ContentPartDisplay = () => {
876
+ const { useContentPart } = useContentPartContext();
877
+ const display = useContentPart((c) => {
878
+ if (c.part.type !== "ui")
879
+ throw new Error(
880
+ "ContentPartDisplay can only be used inside ui content parts."
881
+ );
882
+ return c.part.display;
883
+ });
884
+ return display ?? null;
885
+ };
886
+
887
+ // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
888
+ var ContentPartInProgressIndicator = () => {
889
+ const { useMessage } = useMessageContext();
890
+ const { useContentPart } = useContentPartContext();
891
+ const indicator = useCombinedStore(
892
+ [useMessage, useContentPart],
893
+ (m, c) => c.status === "in_progress" ? m.inProgressIndicator : null
894
+ );
895
+ return indicator;
896
+ };
897
+
898
+ // src/primitives/contentPart/ContentPartText.tsx
899
+ var import_react_primitive9 = require("@radix-ui/react-primitive");
900
+ var import_react27 = require("react");
901
+ var import_jsx_runtime14 = require("react/jsx-runtime");
902
+ var ContentPartText = (0, import_react27.forwardRef)((props, forwardedRef) => {
903
+ const { useContentPart } = useContentPartContext();
904
+ const text = useContentPart((c) => {
905
+ if (c.part.type !== "text")
906
+ throw new Error(
907
+ "ContentPartText can only be used inside text content parts."
908
+ );
909
+ return c.part.text;
910
+ });
911
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_primitive9.Primitive.span, { ...props, ref: forwardedRef, children: text });
912
+ });
913
+
914
+ // src/primitives/message/MessageContent.tsx
915
+ var import_jsx_runtime15 = require("react/jsx-runtime");
916
+ var defaultComponents = {
917
+ Text: () => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
918
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ContentPartText, {}),
919
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ContentPartInProgressIndicator, {})
920
+ ] }),
921
+ Image: () => null,
922
+ UI: () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ContentPartDisplay, {}),
923
+ tools: {
924
+ Fallback: (props) => {
925
+ const { useToolRenderers } = useAssistantContext();
926
+ const Render = useToolRenderers(
927
+ (s) => s.getToolRenderer(props.part.toolName)
928
+ );
929
+ if (!Render) return null;
930
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Render, { ...props });
931
+ }
932
+ }
933
+ };
934
+ var MessageContentPartComponent = ({
935
+ components: {
936
+ Text = defaultComponents.Text,
937
+ Image = defaultComponents.Image,
938
+ UI = defaultComponents.UI,
939
+ tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
940
+ } = {}
941
+ }) => {
942
+ const { useContentPart } = useContentPartContext();
943
+ const { part, status } = useContentPart();
944
+ const type = part.type;
945
+ switch (type) {
946
+ case "text":
947
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { part, status });
948
+ case "image":
949
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Image, { part, status });
950
+ case "ui":
951
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UI, { part, status });
952
+ case "tool-call": {
953
+ const Tool = by_name[part.toolName] || Fallback;
954
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Tool, { part, status });
955
+ }
956
+ default:
957
+ throw new Error(`Unknown content part type: ${type}`);
958
+ }
959
+ };
960
+ var MessageContentPartImpl = ({
961
+ partIndex,
962
+ components
963
+ }) => {
964
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ContentPartProvider, { partIndex, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MessageContentPartComponent, { components }) });
965
+ };
966
+ var MessageContentPart = (0, import_react28.memo)(
967
+ MessageContentPartImpl,
968
+ (prev, next) => prev.partIndex === next.partIndex && prev.components?.Text === next.components?.Text && prev.components?.Image === next.components?.Image && prev.components?.UI === next.components?.UI && prev.components?.tools === next.components?.tools
969
+ );
970
+ var MessageContent = ({ components }) => {
971
+ const { useMessage } = useMessageContext();
972
+ const contentLength = useMessage((s) => s.message.content.length);
973
+ return new Array(contentLength).fill(null).map((_, idx) => {
974
+ const partIndex = idx;
975
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
976
+ MessageContentPart,
977
+ {
978
+ partIndex,
979
+ components
980
+ },
981
+ partIndex
982
+ );
983
+ });
984
+ };
985
+
986
+ // src/primitives/message/MessageInProgress.tsx
987
+ var import_react_primitive10 = require("@radix-ui/react-primitive");
988
+ var import_react29 = require("react");
989
+ var import_jsx_runtime16 = require("react/jsx-runtime");
990
+ var MessageInProgress = (0, import_react29.forwardRef)((props, ref) => {
991
+ const { useMessage } = useMessageContext();
992
+ (0, import_react29.useMemo)(() => {
993
+ useMessage.getState().setInProgressIndicator(/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_primitive10.Primitive.span, { ...props, ref }));
994
+ }, [useMessage, props, ref]);
995
+ return null;
996
+ });
997
+
998
+ // src/primitives/branchPicker/index.ts
999
+ var branchPicker_exports = {};
1000
+ __export(branchPicker_exports, {
1001
+ Count: () => BranchPickerCount,
1002
+ Next: () => BranchPickerNext,
1003
+ Number: () => BranchPickerNumber,
1004
+ Previous: () => BranchPickerPrevious,
1005
+ Root: () => BranchPickerRoot
1006
+ });
1007
+
1008
+ // src/utils/createActionButton.tsx
1009
+ var import_primitive8 = require("@radix-ui/primitive");
1010
+ var import_react_primitive11 = require("@radix-ui/react-primitive");
1011
+ var import_react30 = require("react");
1012
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1013
+ var createActionButton = (useActionButton) => {
1014
+ return (0, import_react30.forwardRef)(
1015
+ (props, forwardedRef) => {
1016
+ const onClick = useActionButton(props);
1017
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1018
+ import_react_primitive11.Primitive.button,
1019
+ {
1020
+ type: "button",
1021
+ disabled: !onClick,
1022
+ ...props,
1023
+ ref: forwardedRef,
1024
+ onClick: (0, import_primitive8.composeEventHandlers)(props.onClick, onClick ?? void 0)
1025
+ }
1026
+ );
1027
+ }
1028
+ );
1029
+ };
1030
+
1031
+ // src/primitives/branchPicker/BranchPickerNext.tsx
1032
+ var BranchPickerNext = createActionButton(useGoToNextBranch);
1033
+
1034
+ // src/primitives/branchPicker/BranchPickerPrevious.tsx
1035
+ var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
1036
+
1037
+ // src/primitives/branchPicker/BranchPickerCount.tsx
1038
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1039
+ var BranchPickerCount = () => {
1040
+ const { useMessage } = useMessageContext();
1041
+ const branchCount = useMessage((s) => s.branches.length);
1042
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: branchCount });
1043
+ };
1044
+
1045
+ // src/primitives/branchPicker/BranchPickerNumber.tsx
1046
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1047
+ var BranchPickerNumber = () => {
1048
+ const { useMessage } = useMessageContext();
1049
+ const branchIdx = useMessage((s) => s.branches.indexOf(s.message.id));
1050
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children: branchIdx + 1 });
1051
+ };
1052
+
1053
+ // src/primitives/branchPicker/BranchPickerRoot.tsx
1054
+ var import_react_primitive12 = require("@radix-ui/react-primitive");
1055
+ var import_react31 = require("react");
1056
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1057
+ var BranchPickerRoot = (0, import_react31.forwardRef)(({ hideWhenSingleBranch, ...rest }, ref) => {
1058
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_primitive12.Primitive.div, { ...rest, ref }) });
1059
+ });
1060
+
1061
+ // src/primitives/actionBar/index.ts
1062
+ var actionBar_exports = {};
1063
+ __export(actionBar_exports, {
1064
+ Copy: () => ActionBarCopy,
1065
+ Edit: () => ActionBarEdit,
1066
+ Reload: () => ActionBarReload,
1067
+ Root: () => ActionBarRoot
1068
+ });
1069
+
1070
+ // src/primitives/actionBar/ActionBarRoot.tsx
1071
+ var import_react_primitive13 = require("@radix-ui/react-primitive");
1072
+ var import_react32 = require("react");
1073
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1074
+ var ActionBarRoot = (0, import_react32.forwardRef)(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
1075
+ const { useThread } = useThreadContext();
1076
+ const { useMessage } = useMessageContext();
1077
+ const hideAndfloatStatus = useCombinedStore(
1078
+ [useThread, useMessage],
1079
+ (t, m) => {
1080
+ if (hideWhenRunning && t.isRunning) return "hidden" /* Hidden */;
1081
+ const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
1082
+ if (!autohideEnabled) return "normal" /* Normal */;
1083
+ if (!m.isHovering) return "hidden" /* Hidden */;
1084
+ if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
1085
+ return "floating" /* Floating */;
1086
+ return "normal" /* Normal */;
1087
+ }
1088
+ );
1089
+ if (hideAndfloatStatus === "hidden" /* Hidden */) return null;
1090
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1091
+ import_react_primitive13.Primitive.div,
1092
+ {
1093
+ ...hideAndfloatStatus === "floating" /* Floating */ ? { "data-floating": "true" } : null,
1094
+ ...rest,
1095
+ ref
1096
+ }
1097
+ );
1098
+ });
1099
+
1100
+ // src/primitives/actionBar/ActionBarCopy.tsx
1101
+ var ActionBarCopy = createActionButton(useCopyMessage);
1102
+
1103
+ // src/primitives/actionBar/ActionBarReload.tsx
1104
+ var ActionBarReload = createActionButton(useReloadMessage);
1105
+
1106
+ // src/primitives/actionBar/ActionBarEdit.tsx
1107
+ var ActionBarEdit = createActionButton(useBeginMessageEdit);
1108
+
1109
+ // src/primitives/contentPart/index.ts
1110
+ var contentPart_exports = {};
1111
+ __export(contentPart_exports, {
1112
+ Display: () => ContentPartDisplay,
1113
+ Image: () => ContentPartImage,
1114
+ InProgressIndicator: () => ContentPartInProgressIndicator,
1115
+ Text: () => ContentPartText
1116
+ });
1117
+
1118
+ // src/primitives/contentPart/ContentPartImage.tsx
1119
+ var import_react_primitive14 = require("@radix-ui/react-primitive");
1120
+ var import_react33 = require("react");
1121
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1122
+ var ContentPartImage = (0, import_react33.forwardRef)((props, forwardedRef) => {
1123
+ const { useContentPart } = useContentPartContext();
1124
+ const image = useContentPart((c) => {
1125
+ if (c.part.type !== "image")
1126
+ throw new Error(
1127
+ "ContentPartImage can only be used inside image content parts."
1128
+ );
1129
+ return c.part.image;
1130
+ });
1131
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_primitive14.Primitive.img, { src: image, ...props, ref: forwardedRef });
1132
+ });
1133
+
1134
+ // src/runtime/local/useLocalRuntime.tsx
1135
+ var import_react34 = require("react");
1136
+
1137
+ // src/utils/ModelConfigTypes.ts
1138
+ var mergeModelConfigs = (configSet) => {
1139
+ const configs = Array.from(configSet).map((c) => c()).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
1140
+ return configs.reduce((acc, config) => {
1141
+ if (config.system) {
1142
+ if (acc.system) {
1143
+ acc.system += `
1144
+
1145
+ ${config.system}`;
1146
+ } else {
1147
+ acc.system = config.system;
1148
+ }
1149
+ }
1150
+ if (config.tools) {
1151
+ for (const [name, tool] of Object.entries(config.tools)) {
1152
+ if (acc.tools?.[name]) {
1153
+ throw new Error(
1154
+ `You tried to define a tool with the name ${name}, but it already exists.`
1155
+ );
1156
+ }
1157
+ if (!acc.tools) acc.tools = {};
1158
+ acc.tools[name] = tool;
1159
+ }
1160
+ }
1161
+ return acc;
1162
+ }, {});
1163
+ };
1164
+
1165
+ // src/runtime/utils/idUtils.tsx
1166
+ var import_non_secure = require("nanoid/non-secure");
1167
+ var generateId = (0, import_non_secure.customAlphabet)(
1168
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
1169
+ 7
1170
+ );
1171
+ var optimisticPrefix = "__optimistic__";
1172
+ var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1173
+
1174
+ // src/runtime/utils/MessageRepository.tsx
1175
+ var findHead = (message) => {
1176
+ if (message.next) return findHead(message.next);
1177
+ return message;
1178
+ };
1179
+ var MessageRepository = class {
1180
+ messages = /* @__PURE__ */ new Map();
1181
+ // message_id -> item
1182
+ head = null;
1183
+ root = {
1184
+ children: []
1185
+ };
1186
+ performOp(newParent, child, operation) {
1187
+ const parentOrRoot = child.prev ?? this.root;
1188
+ const newParentOrRoot = newParent ?? this.root;
1189
+ if (operation === "relink" && parentOrRoot === newParentOrRoot) return;
1190
+ if (operation !== "link") {
1191
+ parentOrRoot.children = parentOrRoot.children.filter(
1192
+ (m) => m !== child.current.id
1193
+ );
1194
+ if (child.prev?.next === child) {
1195
+ const fallbackId = child.prev.children.at(-1);
1196
+ const fallback = fallbackId ? this.messages.get(fallbackId) : null;
1197
+ if (fallback === void 0) {
1198
+ throw new Error(
1199
+ "MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui."
1200
+ );
1201
+ }
1202
+ child.prev.next = fallback;
1203
+ }
1204
+ }
1205
+ if (operation !== "cut") {
1206
+ newParentOrRoot.children = [
1207
+ ...newParentOrRoot.children,
1208
+ child.current.id
1209
+ ];
1210
+ if (newParent && (findHead(child) === this.head || newParent.next === null)) {
1211
+ newParent.next = child;
1212
+ }
1213
+ child.prev = newParent;
1214
+ }
1215
+ }
1216
+ getMessages() {
1217
+ const messages = new Array(this.head?.level ?? 0);
1218
+ for (let current = this.head; current; current = current.prev) {
1219
+ messages[current.level] = current.current;
1220
+ }
1221
+ return messages;
1222
+ }
1223
+ addOrUpdateMessage(parentId, message) {
1224
+ const existingItem = this.messages.get(message.id);
1225
+ const prev = parentId ? this.messages.get(parentId) : null;
1226
+ if (prev === void 0)
1227
+ throw new Error(
1228
+ "MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui."
1229
+ );
1230
+ if (existingItem) {
1231
+ existingItem.current = message;
1232
+ this.performOp(prev, existingItem, "relink");
1233
+ return;
1234
+ }
1235
+ const newItem = {
1236
+ prev,
1237
+ current: message,
1238
+ next: null,
1239
+ children: [],
1240
+ level: prev ? prev.level + 1 : 0
1241
+ };
1242
+ this.messages.set(message.id, newItem);
1243
+ this.performOp(prev, newItem, "link");
1244
+ if (this.head === prev) {
1245
+ this.head = newItem;
1246
+ }
1247
+ }
1248
+ appendOptimisticMessage(parentId, message) {
1249
+ let optimisticId;
1250
+ do {
1251
+ optimisticId = generateOptimisticId();
1252
+ } while (this.messages.has(optimisticId));
1253
+ this.addOrUpdateMessage(parentId, {
1254
+ ...message,
1255
+ id: optimisticId,
1256
+ createdAt: /* @__PURE__ */ new Date(),
1257
+ ...message.role === "assistant" ? { status: "in_progress" } : void 0
1258
+ });
1259
+ return optimisticId;
1260
+ }
1261
+ deleteMessage(messageId, replacementId) {
1262
+ const message = this.messages.get(messageId);
1263
+ if (!message)
1264
+ throw new Error(
1265
+ "MessageRepository(deleteMessage): Optimistic message not found. This is likely an internal bug in assistant-ui."
1266
+ );
1267
+ const replacement = replacementId === void 0 ? message.prev : replacementId === null ? null : this.messages.get(replacementId);
1268
+ if (replacement === void 0)
1269
+ throw new Error(
1270
+ "MessageRepository(deleteMessage): Replacement not found. This is likely an internal bug in assistant-ui."
1271
+ );
1272
+ for (const child of message.children) {
1273
+ const childMessage = this.messages.get(child);
1274
+ if (!childMessage)
1275
+ throw new Error(
1276
+ "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
1277
+ );
1278
+ this.performOp(replacement, childMessage, "relink");
1279
+ }
1280
+ this.performOp(null, message, "cut");
1281
+ this.messages.delete(messageId);
1282
+ if (this.head === message) {
1283
+ this.head = replacement ? findHead(replacement) : null;
1284
+ }
1285
+ }
1286
+ getBranches(messageId) {
1287
+ const message = this.messages.get(messageId);
1288
+ if (!message)
1289
+ throw new Error(
1290
+ "MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui."
1291
+ );
1292
+ const { children } = message.prev ?? this.root;
1293
+ return children;
1294
+ }
1295
+ switchToBranch(messageId) {
1296
+ const message = this.messages.get(messageId);
1297
+ if (!message)
1298
+ throw new Error(
1299
+ "MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui."
1300
+ );
1301
+ if (message.prev) {
1302
+ message.prev.next = message;
1303
+ }
1304
+ this.head = findHead(message);
1305
+ }
1306
+ resetHead(messageId) {
1307
+ if (messageId === null) {
1308
+ this.head = null;
1309
+ return;
1310
+ }
1311
+ const message = this.messages.get(messageId);
1312
+ if (!message)
1313
+ throw new Error(
1314
+ "MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui."
1315
+ );
1316
+ this.head = message;
1317
+ for (let current = message; current; current = current.prev) {
1318
+ if (current.prev) {
1319
+ current.prev.next = current;
1320
+ }
1321
+ }
1322
+ }
1323
+ };
1324
+
1325
+ // src/runtime/local/LocalRuntime.tsx
1326
+ var LocalRuntime = class {
1327
+ constructor(adapter) {
1328
+ this.adapter = adapter;
1329
+ }
1330
+ _subscriptions = /* @__PURE__ */ new Set();
1331
+ _configProviders = /* @__PURE__ */ new Set();
1332
+ abortController = null;
1333
+ repository = new MessageRepository();
1334
+ get messages() {
1335
+ return this.repository.getMessages();
1336
+ }
1337
+ get isRunning() {
1338
+ return this.abortController != null;
1339
+ }
1340
+ getBranches(messageId) {
1341
+ return this.repository.getBranches(messageId);
1342
+ }
1343
+ switchToBranch(branchId) {
1344
+ this.repository.switchToBranch(branchId);
1345
+ this.notifySubscribers();
1346
+ }
1347
+ async append(message) {
1348
+ const userMessageId = generateId();
1349
+ const userMessage = {
1350
+ id: userMessageId,
1351
+ role: "user",
1352
+ content: message.content,
1353
+ createdAt: /* @__PURE__ */ new Date()
1354
+ };
1355
+ this.repository.addOrUpdateMessage(message.parentId, userMessage);
1356
+ await this.startRun(userMessageId);
1357
+ }
1358
+ async startRun(parentId) {
1359
+ const id = generateId();
1360
+ this.repository.resetHead(parentId);
1361
+ const messages = this.repository.getMessages();
1362
+ const message = {
1363
+ id,
1364
+ role: "assistant",
1365
+ status: "in_progress",
1366
+ content: [{ type: "text", text: "" }],
1367
+ createdAt: /* @__PURE__ */ new Date()
1368
+ };
1369
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1370
+ this.abortController?.abort();
1371
+ this.abortController = new AbortController();
1372
+ this.notifySubscribers();
1373
+ try {
1374
+ const updateHandler = ({ content }) => {
1375
+ message.content = content;
1376
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1377
+ this.notifySubscribers();
1378
+ };
1379
+ const result = await this.adapter.run({
1380
+ messages,
1381
+ abortSignal: this.abortController.signal,
1382
+ config: mergeModelConfigs(this._configProviders),
1383
+ onUpdate: updateHandler
1384
+ });
1385
+ updateHandler(result);
1386
+ message.status = "done";
1387
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1388
+ } catch (e) {
1389
+ message.status = "error";
1390
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1391
+ console.error(e);
1392
+ } finally {
1393
+ this.abortController = null;
1394
+ this.notifySubscribers();
1395
+ }
1396
+ }
1397
+ cancelRun() {
1398
+ if (!this.abortController) return;
1399
+ this.abortController.abort();
1400
+ this.abortController = null;
1401
+ this.notifySubscribers();
1402
+ }
1403
+ notifySubscribers() {
1404
+ for (const callback of this._subscriptions) callback();
1405
+ }
1406
+ subscribe(callback) {
1407
+ this._subscriptions.add(callback);
1408
+ return () => this._subscriptions.delete(callback);
1409
+ }
1410
+ registerModelConfigProvider(provider) {
1411
+ this._configProviders.add(provider);
1412
+ return () => this._configProviders.delete(provider);
1413
+ }
1414
+ };
1415
+
1416
+ // src/runtime/local/useLocalRuntime.tsx
1417
+ var useLocalRuntime = (adapter) => {
1418
+ const [runtime] = (0, import_react34.useState)(() => new LocalRuntime(adapter));
1419
+ (0, import_react34.useInsertionEffect)(() => {
1420
+ runtime.adapter = adapter;
1421
+ });
1422
+ return runtime;
1423
+ };
1424
+
1425
+ // src/context/providers/AssistantRuntimeProvider.tsx
1426
+ var import_react37 = require("react");
1427
+
1428
+ // src/context/providers/AssistantProvider.tsx
1429
+ var import_react36 = require("react");
1430
+
1431
+ // src/context/stores/AssistantModelConfig.ts
1432
+ var import_zustand4 = require("zustand");
1433
+
1434
+ // src/utils/ProxyConfigProvider.ts
1435
+ var ProxyConfigProvider = class {
1436
+ _providers = /* @__PURE__ */ new Set();
1437
+ getModelConfig() {
1438
+ return mergeModelConfigs(this._providers);
1439
+ }
1440
+ registerModelConfigProvider(provider) {
1441
+ this._providers.add(provider);
1442
+ return () => {
1443
+ this._providers.delete(provider);
1444
+ };
1445
+ }
1446
+ };
1447
+
1448
+ // src/context/stores/AssistantModelConfig.ts
1449
+ var makeAssistantModelConfigStore = () => (0, import_zustand4.create)(() => {
1450
+ const proxy = new ProxyConfigProvider();
1451
+ return {
1452
+ getModelConfig: () => {
1453
+ return proxy.getModelConfig();
1454
+ },
1455
+ registerModelConfigProvider: (provider) => {
1456
+ return proxy.registerModelConfigProvider(provider);
1457
+ }
1458
+ };
1459
+ });
1460
+
1461
+ // src/context/stores/AssistantToolRenderers.ts
1462
+ var import_zustand5 = require("zustand");
1463
+ var makeAssistantToolRenderersStore = () => (0, import_zustand5.create)((set) => {
1464
+ const renderers = /* @__PURE__ */ new Map();
1465
+ return {
1466
+ getToolRenderer: (name) => {
1467
+ const arr = renderers.get(name);
1468
+ const last = arr?.at(-1);
1469
+ if (last) return last;
1470
+ return null;
1471
+ },
1472
+ setToolRenderer: (name, render) => {
1473
+ let arr = renderers.get(name);
1474
+ if (!arr) {
1475
+ arr = [];
1476
+ renderers.set(name, arr);
1477
+ }
1478
+ arr.push(render);
1479
+ set({});
1480
+ return () => {
1481
+ const index = arr.indexOf(render);
1482
+ if (index !== -1) {
1483
+ arr.splice(index, 1);
1484
+ }
1485
+ set({});
1486
+ };
1487
+ }
1488
+ };
1489
+ });
1490
+
1491
+ // src/context/providers/ThreadProvider.tsx
1492
+ var import_react35 = require("react");
1493
+
1494
+ // src/context/stores/Composer.ts
1495
+ var import_zustand6 = require("zustand");
1496
+ var makeComposerStore = (useThread) => (0, import_zustand6.create)()((set, get, store) => {
1497
+ return {
1498
+ ...makeBaseComposer(set, get, store),
1499
+ isEditing: true,
1500
+ send: () => {
1501
+ const { setValue, value } = get();
1502
+ setValue("");
1503
+ useThread.getState().append({
1504
+ parentId: useThread.getState().messages.at(-1)?.id ?? null,
1505
+ content: [{ type: "text", text: value }]
1506
+ });
1507
+ },
1508
+ cancel: () => {
1509
+ const thread = useThread.getState();
1510
+ if (!thread.isRunning) return false;
1511
+ useThread.getState().cancelRun();
1512
+ return true;
1513
+ }
1514
+ };
1515
+ });
1516
+
1517
+ // src/context/stores/Thread.ts
1518
+ var import_zustand7 = require("zustand");
1519
+ var makeThreadStore = (runtimeRef) => {
1520
+ const useThread = (0, import_zustand7.create)(() => ({
1521
+ messages: runtimeRef.current.messages,
1522
+ isRunning: runtimeRef.current.isRunning,
1523
+ getBranches: (messageId) => runtimeRef.current.getBranches(messageId),
1524
+ switchToBranch: (branchId) => runtimeRef.current.switchToBranch(branchId),
1525
+ startRun: (parentId) => runtimeRef.current.startRun(parentId),
1526
+ append: (message) => runtimeRef.current.append(message),
1527
+ cancelRun: () => runtimeRef.current.cancelRun()
1528
+ }));
1529
+ const onRuntimeUpdate = () => {
1530
+ useThread.setState({
1531
+ messages: runtimeRef.current.messages,
1532
+ isRunning: runtimeRef.current.isRunning
1533
+ });
1534
+ };
1535
+ return {
1536
+ useThread,
1537
+ onRuntimeUpdate
1538
+ };
1539
+ };
1540
+
1541
+ // src/context/stores/ThreadViewport.tsx
1542
+ var import_zustand8 = require("zustand");
1543
+ var makeThreadViewportStore = () => {
1544
+ const scrollToBottomListeners = /* @__PURE__ */ new Set();
1545
+ return (0, import_zustand8.create)(() => ({
1546
+ isAtBottom: true,
1547
+ scrollToBottom: () => {
1548
+ for (const listener of scrollToBottomListeners) {
1549
+ listener();
1550
+ }
1551
+ },
1552
+ onScrollToBottom: (callback) => {
1553
+ scrollToBottomListeners.add(callback);
1554
+ return () => {
1555
+ scrollToBottomListeners.delete(callback);
1556
+ };
1557
+ }
1558
+ }));
1559
+ };
1560
+
1561
+ // src/context/providers/ThreadProvider.tsx
1562
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1563
+ var ThreadProvider = ({
1564
+ children,
1565
+ runtime
1566
+ }) => {
1567
+ const runtimeRef = (0, import_react35.useRef)(runtime);
1568
+ (0, import_react35.useInsertionEffect)(() => {
1569
+ runtimeRef.current = runtime;
1570
+ });
1571
+ const [{ context, onRuntimeUpdate }] = (0, import_react35.useState)(() => {
1572
+ const { useThread, onRuntimeUpdate: onRuntimeUpdate2 } = makeThreadStore(runtimeRef);
1573
+ const useViewport = makeThreadViewportStore();
1574
+ const useComposer = makeComposerStore(useThread);
1575
+ return {
1576
+ context: {
1577
+ useViewport,
1578
+ useThread,
1579
+ useComposer
1580
+ },
1581
+ onRuntimeUpdate: onRuntimeUpdate2
1582
+ };
1583
+ });
1584
+ (0, import_react35.useEffect)(() => {
1585
+ onRuntimeUpdate();
1586
+ return runtime.subscribe(onRuntimeUpdate);
1587
+ }, [onRuntimeUpdate, runtime]);
1588
+ const RuntimeSynchronizer = runtime.unstable_synchronizer;
1589
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(ThreadContext.Provider, { value: context, children: [
1590
+ RuntimeSynchronizer && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RuntimeSynchronizer, {}),
1591
+ children
1592
+ ] });
1593
+ };
1594
+
1595
+ // src/context/providers/AssistantProvider.tsx
1596
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1597
+ var AssistantProvider = ({ children, runtime }) => {
1598
+ const runtimeRef = (0, import_react36.useRef)(runtime);
1599
+ (0, import_react36.useInsertionEffect)(() => {
1600
+ runtimeRef.current = runtime;
1601
+ });
1602
+ const [context] = (0, import_react36.useState)(() => {
1603
+ const useModelConfig = makeAssistantModelConfigStore();
1604
+ const useToolRenderers = makeAssistantToolRenderersStore();
1605
+ return { useModelConfig, useToolRenderers };
1606
+ });
1607
+ const getModelCOnfig = context.useModelConfig((c) => c.getModelConfig);
1608
+ (0, import_react36.useEffect)(() => {
1609
+ return runtime.registerModelConfigProvider(getModelCOnfig);
1610
+ }, [runtime, getModelCOnfig]);
1611
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AssistantContext.Provider, { value: context, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ThreadProvider, { runtime, children }) });
1612
+ };
1613
+
1614
+ // src/context/providers/AssistantRuntimeProvider.tsx
1615
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1616
+ var AssistantRuntimeProviderImpl = ({ children, runtime }) => {
1617
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AssistantProvider, { runtime, children });
1618
+ };
1619
+ var AssistantRuntimeProvider = (0, import_react37.memo)(AssistantRuntimeProviderImpl);
1620
+
1621
+ // src/internal.ts
1622
+ var internal_exports = {};
1623
+ __export(internal_exports, {
1624
+ MessageRepository: () => MessageRepository,
1625
+ ProxyConfigProvider: () => ProxyConfigProvider
1626
+ });
1627
+ // Annotate the CommonJS export names for ESM import in node:
1628
+ 0 && (module.exports = {
1629
+ ActionBarPrimitive,
1630
+ AssistantRuntimeProvider,
1631
+ BranchPickerPrimitive,
1632
+ ComposerPrimitive,
1633
+ ContentPartPrimitive,
1634
+ INTERNAL,
1635
+ MessagePrimitive,
1636
+ ThreadPrimitive,
1637
+ useBeginMessageEdit,
1638
+ useCopyMessage,
1639
+ useGoToNextBranch,
1640
+ useGoToPreviousBranch,
1641
+ useLocalRuntime,
1642
+ useReloadMessage
1643
+ });
1644
+ //# sourceMappingURL=index.js.map