@assistant-ui/react 0.0.19 → 0.0.21

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.mjs CHANGED
@@ -4,6 +4,156 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
+ // src/actions/useCopyMessage.tsx
8
+ import { useCallback } from "react";
9
+
10
+ // src/context/MessageContext.ts
11
+ import { createContext, useContext } from "react";
12
+ var MessageContext = createContext(null);
13
+ var useMessageContext = () => {
14
+ const context = useContext(MessageContext);
15
+ if (!context)
16
+ throw new Error(
17
+ "This component can only be used inside a component passed to <ThreadPrimitive.Messages components={...} />."
18
+ );
19
+ return context;
20
+ };
21
+
22
+ // src/utils/combined/useCombinedStore.ts
23
+ import { useMemo } from "react";
24
+
25
+ // src/utils/combined/createCombinedStore.ts
26
+ import { useSyncExternalStore } from "react";
27
+ var createCombinedStore = (stores) => {
28
+ const subscribe = (callback) => {
29
+ const unsubscribes = stores.map((store) => store.subscribe(callback));
30
+ return () => {
31
+ for (const unsub of unsubscribes) {
32
+ unsub();
33
+ }
34
+ };
35
+ };
36
+ return (selector) => {
37
+ const getSnapshot = () => selector(...stores.map((store) => store.getState()));
38
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
39
+ };
40
+ };
41
+
42
+ // src/utils/combined/useCombinedStore.ts
43
+ var useCombinedStore = (stores, selector) => {
44
+ const useCombined = useMemo(() => createCombinedStore(stores), stores);
45
+ return useCombined(selector);
46
+ };
47
+
48
+ // src/utils/getMessageText.tsx
49
+ var getMessageText = (message) => {
50
+ const textParts = message.content.filter(
51
+ (part) => part.type === "text"
52
+ );
53
+ return textParts.map((part) => part.text).join("\n\n");
54
+ };
55
+
56
+ // src/actions/useCopyMessage.tsx
57
+ var useCopyMessage = ({ copiedDuration = 3e3 }) => {
58
+ const { useMessage, useComposer } = useMessageContext();
59
+ const hasCopyableContent = useCombinedStore(
60
+ [useMessage, useComposer],
61
+ (m, c) => {
62
+ return c.isEditing || m.message.content.some((c2) => c2.type === "text");
63
+ }
64
+ );
65
+ const callback = useCallback(() => {
66
+ const { isEditing, value: composerValue } = useComposer.getState();
67
+ const { message, setIsCopied } = useMessage.getState();
68
+ const valueToCopy = isEditing ? composerValue : getMessageText(message);
69
+ navigator.clipboard.writeText(valueToCopy);
70
+ setIsCopied(true);
71
+ setTimeout(() => setIsCopied(false), copiedDuration);
72
+ }, [useComposer, useMessage, copiedDuration]);
73
+ if (!hasCopyableContent) return null;
74
+ return callback;
75
+ };
76
+
77
+ // src/actions/useReloadMessage.tsx
78
+ import { useCallback as useCallback2 } from "react";
79
+
80
+ // src/context/ThreadContext.ts
81
+ import { createContext as createContext2, useContext as useContext2 } from "react";
82
+ var ThreadContext = createContext2(null);
83
+ var useThreadContext = () => {
84
+ const context = useContext2(ThreadContext);
85
+ if (!context)
86
+ throw new Error("This component must be used within an AssistantProvider.");
87
+ return context;
88
+ };
89
+
90
+ // src/actions/useReloadMessage.tsx
91
+ var useReloadMessage = () => {
92
+ const { useThread, useViewport } = useThreadContext();
93
+ const { useMessage } = useMessageContext();
94
+ const disabled = useCombinedStore(
95
+ [useThread, useMessage],
96
+ (t, m) => t.isRunning || m.message.role !== "assistant"
97
+ );
98
+ const callback = useCallback2(() => {
99
+ const { parentId } = useMessage.getState();
100
+ useThread.getState().startRun(parentId);
101
+ useViewport.getState().scrollToBottom();
102
+ }, [useMessage, useThread, useViewport]);
103
+ if (disabled) return null;
104
+ return callback;
105
+ };
106
+
107
+ // src/actions/useBeginMessageEdit.tsx
108
+ import { useCallback as useCallback3 } from "react";
109
+ var useBeginMessageEdit = () => {
110
+ const { useMessage, useComposer } = useMessageContext();
111
+ const disabled = useCombinedStore(
112
+ [useMessage, useComposer],
113
+ (m, c) => m.message.role !== "user" || c.isEditing
114
+ );
115
+ const callback = useCallback3(() => {
116
+ const { edit } = useComposer.getState();
117
+ edit();
118
+ }, [useComposer]);
119
+ if (disabled) return null;
120
+ return callback;
121
+ };
122
+
123
+ // src/actions/useGoToNextBranch.tsx
124
+ import { useCallback as useCallback4 } from "react";
125
+ var useGoToNextBranch = () => {
126
+ const { useThread } = useThreadContext();
127
+ const { useMessage, useComposer } = useMessageContext();
128
+ const disabled = useCombinedStore(
129
+ [useMessage, useComposer],
130
+ (m, c) => c.isEditing || m.branches.indexOf(m.message.id) + 1 >= m.branches.length
131
+ );
132
+ const callback = useCallback4(() => {
133
+ const { message, branches } = useMessage.getState();
134
+ useThread.getState().switchToBranch(branches[branches.indexOf(message.id) + 1]);
135
+ }, [useMessage, useThread]);
136
+ if (disabled) return null;
137
+ return callback;
138
+ };
139
+
140
+ // src/actions/useGoToPreviousBranch.tsx
141
+ import { useCallback as useCallback5 } from "react";
142
+ var useGoToPreviousBranch = () => {
143
+ const { useThread } = useThreadContext();
144
+ const { useMessage, useComposer } = useMessageContext();
145
+ const disabled = useCombinedStore(
146
+ [useMessage, useComposer],
147
+ (m, c) => c.isEditing || m.branches.indexOf(m.message.id) <= 0
148
+ );
149
+ const callback = useCallback5(() => {
150
+ const { message, branches } = useMessage.getState();
151
+ useThread.getState().switchToBranch(branches[branches.indexOf(message.id) - 1]);
152
+ }, [useMessage, useThread]);
153
+ if (disabled) return null;
154
+ return callback;
155
+ };
156
+
7
157
  // src/primitives/thread/index.ts
8
158
  var thread_exports = {};
9
159
  __export(thread_exports, {
@@ -28,21 +178,9 @@ var ThreadRoot = forwardRef(
28
178
  }
29
179
  );
30
180
 
31
- // src/utils/context/AssistantContext.ts
32
- import { createContext, useContext } from "react";
33
- var AssistantContext = createContext(null);
34
- var useAssistantContext = () => {
35
- const context = useContext(AssistantContext);
36
- if (!context)
37
- throw new Error(
38
- "This component must be used within a AssistantProvider."
39
- );
40
- return context;
41
- };
42
-
43
181
  // src/primitives/thread/ThreadIf.tsx
44
182
  var useThreadIf = (props) => {
45
- const { useThread } = useAssistantContext();
183
+ const { useThread } = useThreadContext();
46
184
  return useThread((thread) => {
47
185
  if (props.empty === true && thread.messages.length !== 0) return false;
48
186
  if (props.empty === false && thread.messages.length === 0) return false;
@@ -113,7 +251,7 @@ import { useCallbackRef as useCallbackRef2 } from "@radix-ui/react-use-callback-
113
251
  import { useEffect as useEffect2 } from "react";
114
252
  var useOnScrollToBottom = (callback) => {
115
253
  const callbackRef = useCallbackRef2(callback);
116
- const { useViewport } = useAssistantContext();
254
+ const { useViewport } = useThreadContext();
117
255
  useEffect2(() => {
118
256
  return useViewport.getState().onScrollToBottom(() => {
119
257
  callbackRef();
@@ -127,7 +265,7 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re
127
265
  const messagesEndRef = useRef(null);
128
266
  const divRef = useRef(null);
129
267
  const ref = useComposedRefs(forwardedRef, divRef);
130
- const { useViewport } = useAssistantContext();
268
+ const { useViewport } = useThreadContext();
131
269
  const firstRenderRef = useRef(true);
132
270
  const isScrollingToBottomRef = useRef(false);
133
271
  const lastScrollTop = useRef(0);
@@ -175,78 +313,23 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re
175
313
  );
176
314
  });
177
315
 
178
- // src/utils/context/useComposerContext.ts
179
- import { useContext as useContext3 } from "react";
180
-
181
- // src/utils/context/useMessageContext.ts
182
- import { createContext as createContext2, useContext as useContext2 } from "react";
183
- var MessageContext = createContext2(null);
184
- var useMessageContext = () => {
185
- const context = useContext2(MessageContext);
186
- if (!context)
187
- throw new Error(
188
- "This component must be used within a MessagePrimitive.Provider."
189
- );
190
- return context;
191
- };
192
-
193
- // src/utils/context/useComposerContext.ts
194
- var useComposerContext = () => {
195
- const { useComposer: useAssisstantComposer } = useAssistantContext();
196
- const { useComposer: useMessageComposer } = useContext3(MessageContext) ?? {};
197
- return {
198
- useComposer: useMessageComposer ?? useAssisstantComposer,
199
- type: useMessageComposer ? "message" : "assistant"
200
- };
201
- };
202
-
203
- // src/primitives/composer/ComposerIf.tsx
204
- var useComposerIf = (props) => {
205
- const { useComposer } = useComposerContext();
206
- return useComposer((composer) => {
207
- if (props.editing === true && !composer.isEditing) return false;
208
- if (props.editing === false && composer.isEditing) return false;
209
- return true;
210
- });
211
- };
212
- var ComposerIf = ({ children, ...query }) => {
213
- const result = useComposerIf(query);
214
- return result ? children : null;
215
- };
216
-
217
- // src/primitives/message/index.ts
218
- var message_exports = {};
219
- __export(message_exports, {
220
- Content: () => MessageContent,
221
- If: () => MessageIf,
222
- InProgress: () => MessageInProgress,
223
- Provider: () => MessageProvider,
224
- Root: () => MessageRoot
225
- });
226
-
227
- // src/primitives/message/MessageProvider.tsx
228
- import { useMemo, useState } from "react";
316
+ // src/context/providers/MessageProvider.tsx
317
+ import { useEffect as useEffect3, useState } from "react";
229
318
  import { create as create2 } from "zustand";
230
319
 
231
- // src/utils/context/getMessageText.tsx
232
- var getMessageText = (message) => {
233
- const textParts = message.content.filter(
234
- (part) => part.type === "text"
235
- );
236
- return textParts.map((part) => part.text).join("\n\n");
237
- };
320
+ // src/context/stores/MessageComposer.ts
321
+ import { create } from "zustand";
238
322
 
239
- // src/utils/context/stores/ComposerStore.ts
240
- import {
241
- create
242
- } from "zustand";
323
+ // src/context/stores/BaseComposer.ts
243
324
  var makeBaseComposer = (set) => ({
244
325
  value: "",
245
326
  setValue: (value) => {
246
327
  set({ value });
247
328
  }
248
329
  });
249
- var makeMessageComposerStore = ({
330
+
331
+ // src/context/stores/MessageComposer.ts
332
+ var makeEditComposerStore = ({
250
333
  onEdit,
251
334
  onSend
252
335
  }) => create()((set, get, store) => ({
@@ -267,34 +350,30 @@ var makeMessageComposerStore = ({
267
350
  return true;
268
351
  }
269
352
  }));
270
- var makeThreadComposerStore = (useThread) => create()((set, get, store) => {
271
- return {
272
- ...makeBaseComposer(set, get, store),
273
- isEditing: true,
274
- send: () => {
275
- const { value } = get();
276
- set({ value: "" });
277
- useThread.getState().append({
278
- parentId: useThread.getState().messages.at(-1)?.id ?? null,
279
- content: [{ type: "text", text: value }]
280
- });
281
- },
282
- cancel: () => {
283
- const thread = useThread.getState();
284
- if (!thread.isRunning) return false;
285
- useThread.getState().cancelRun();
286
- return true;
287
- }
288
- };
289
- });
290
353
 
291
- // src/primitives/message/MessageProvider.tsx
354
+ // src/context/providers/MessageProvider.tsx
292
355
  import { jsx as jsx4 } from "react/jsx-runtime";
293
356
  var getIsLast = (thread, message) => {
294
357
  return thread.messages[thread.messages.length - 1]?.id === message.id;
295
358
  };
296
- var useMessageContext2 = () => {
297
- const { useThread } = useAssistantContext();
359
+ var syncMessage = (thread, useMessage, messageIndex) => {
360
+ const parentId = thread.messages[messageIndex - 1]?.id ?? null;
361
+ const message = thread.messages[messageIndex];
362
+ if (!message) return;
363
+ const isLast = getIsLast(thread, message);
364
+ const branches = thread.getBranches(message.id);
365
+ const currentState = useMessage.getState();
366
+ if (currentState.message === message && currentState.parentId === parentId && currentState.branches === branches && currentState.isLast === isLast)
367
+ return;
368
+ useMessage.setState({
369
+ message,
370
+ parentId,
371
+ branches,
372
+ isLast
373
+ });
374
+ };
375
+ var useMessageContext2 = (messageIndex) => {
376
+ const { useThread } = useThreadContext();
298
377
  const [context] = useState(() => {
299
378
  const useMessage = create2((set) => ({
300
379
  message: null,
@@ -314,7 +393,7 @@ var useMessageContext2 = () => {
314
393
  set({ isHovering: value });
315
394
  }
316
395
  }));
317
- const useComposer = makeMessageComposerStore({
396
+ const useComposer = makeEditComposerStore({
318
397
  onEdit: () => {
319
398
  const message = useMessage.getState().message;
320
399
  if (message.role !== "user")
@@ -339,58 +418,51 @@ var useMessageContext2 = () => {
339
418
  });
340
419
  }
341
420
  });
421
+ syncMessage(useThread.getState(), useMessage, messageIndex);
342
422
  return { useMessage, useComposer };
343
423
  });
424
+ useEffect3(() => {
425
+ return useThread.subscribe((thread) => {
426
+ syncMessage(thread, context.useMessage, messageIndex);
427
+ });
428
+ }, [context, useThread, messageIndex]);
344
429
  return context;
345
430
  };
346
431
  var MessageProvider = ({
347
- message,
348
- parentId,
432
+ messageIndex,
349
433
  children
350
434
  }) => {
351
- const { useThread } = useAssistantContext();
352
- const context = useMessageContext2();
353
- const isLast = useThread((thread) => getIsLast(thread, message));
354
- const branches = useThread((thread) => thread.getBranches(message.id));
355
- useMemo(() => {
356
- context.useMessage.setState({
357
- message,
358
- parentId,
359
- branches,
360
- isLast
361
- });
362
- }, [context, message, parentId, branches, isLast]);
435
+ const context = useMessageContext2(messageIndex);
363
436
  return /* @__PURE__ */ jsx4(MessageContext.Provider, { value: context, children });
364
437
  };
365
438
 
366
- // src/primitives/message/MessageRoot.tsx
367
- import { composeEventHandlers as composeEventHandlers2 } from "@radix-ui/primitive";
368
- import {
369
- Primitive as Primitive3
370
- } from "@radix-ui/react-primitive";
371
- import { forwardRef as forwardRef3 } from "react";
372
- import { jsx as jsx5 } from "react/jsx-runtime";
373
- var MessageRoot = forwardRef3(
374
- ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
375
- const { useMessage } = useMessageContext();
376
- const setIsHovering = useMessage((s) => s.setIsHovering);
377
- const handleMouseEnter = () => {
378
- setIsHovering(true);
379
- };
380
- const handleMouseLeave = () => {
381
- setIsHovering(false);
382
- };
383
- return /* @__PURE__ */ jsx5(
384
- Primitive3.div,
385
- {
386
- ...rest,
387
- ref,
388
- onMouseEnter: composeEventHandlers2(onMouseEnter, handleMouseEnter),
389
- onMouseLeave: composeEventHandlers2(onMouseLeave, handleMouseLeave)
390
- }
391
- );
392
- }
393
- );
439
+ // src/context/ComposerContext.ts
440
+ import { useContext as useContext3, useMemo as useMemo2 } from "react";
441
+ var useComposerContext = () => {
442
+ const { useComposer } = useThreadContext();
443
+ const { useComposer: useEditComposer } = useContext3(MessageContext) ?? {};
444
+ return useMemo2(
445
+ () => ({
446
+ useComposer: useEditComposer ?? useComposer,
447
+ type: useEditComposer ? "edit" : "new"
448
+ }),
449
+ [useEditComposer, useComposer]
450
+ );
451
+ };
452
+
453
+ // src/primitives/composer/ComposerIf.tsx
454
+ var useComposerIf = (props) => {
455
+ const { useComposer } = useComposerContext();
456
+ return useComposer((composer) => {
457
+ if (props.editing === true && !composer.isEditing) return false;
458
+ if (props.editing === false && composer.isEditing) return false;
459
+ return true;
460
+ });
461
+ };
462
+ var ComposerIf = ({ children, ...query }) => {
463
+ const result = useComposerIf(query);
464
+ return result ? children : null;
465
+ };
394
466
 
395
467
  // src/primitives/message/MessageIf.tsx
396
468
  var useMessageIf = (props) => {
@@ -410,162 +482,8 @@ var MessageIf = ({ children, ...query }) => {
410
482
  return result ? children : null;
411
483
  };
412
484
 
413
- // src/utils/context/combined/useCombinedStore.ts
414
- import { useMemo as useMemo2 } from "react";
415
-
416
- // src/utils/context/combined/createCombinedStore.ts
417
- import { useSyncExternalStore } from "react";
418
- var createCombinedStore = (stores) => {
419
- const subscribe = (callback) => {
420
- const unsubscribes = stores.map((store) => store.subscribe(callback));
421
- return () => {
422
- for (const unsub of unsubscribes) {
423
- unsub();
424
- }
425
- };
426
- };
427
- return (selector) => {
428
- const getSnapshot = () => selector(...stores.map((store) => store.getState()));
429
- return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
430
- };
431
- };
432
-
433
- // src/utils/context/combined/useCombinedStore.ts
434
- var useCombinedStore = (stores, selector) => {
435
- const useCombined = useMemo2(() => createCombinedStore(stores), stores);
436
- return useCombined(selector);
437
- };
438
-
439
- // src/utils/context/useContentPartContext.ts
440
- import { createContext as createContext3, useContext as useContext4 } from "react";
441
- var ContentPartContext = createContext3(null);
442
- var useContentPartContext = () => {
443
- const context = useContext4(ContentPartContext);
444
- if (!context)
445
- throw new Error(
446
- "This component must be used within a ContentPartPrimitive.Provider."
447
- );
448
- return context;
449
- };
450
-
451
- // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
452
- var ContentPartInProgressIndicator = () => {
453
- const { useMessage } = useMessageContext();
454
- const { useContentPart } = useContentPartContext();
455
- const indicator = useCombinedStore(
456
- [useMessage, useContentPart],
457
- (m, c) => c.status === "in_progress" ? m.inProgressIndicator : null
458
- );
459
- return indicator;
460
- };
461
-
462
- // src/primitives/contentPart/ContentPartProvider.tsx
463
- import { useMemo as useMemo3, useState as useState2 } from "react";
464
- import { create as create3 } from "zustand";
465
- import { jsx as jsx6 } from "react/jsx-runtime";
466
- var useContentPartContext2 = () => {
467
- const [context] = useState2(() => {
468
- const useContentPart = create3(() => ({
469
- part: null,
470
- status: "done"
471
- }));
472
- return { useContentPart };
473
- });
474
- return context;
475
- };
476
- var ContentPartProvider = ({
477
- part,
478
- status,
479
- children
480
- }) => {
481
- const context = useContentPartContext2();
482
- useMemo3(() => {
483
- context.useContentPart.setState(
484
- {
485
- part,
486
- status
487
- },
488
- true
489
- );
490
- }, [context, part, status]);
491
- return /* @__PURE__ */ jsx6(ContentPartContext.Provider, { value: context, children });
492
- };
493
-
494
- // src/primitives/message/MessageContent.tsx
495
- import { Fragment, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
496
- var defaultComponents = {
497
- Text: ({ part }) => /* @__PURE__ */ jsxs2(Fragment, { children: [
498
- part.text,
499
- /* @__PURE__ */ jsx7(ContentPartInProgressIndicator, {})
500
- ] }),
501
- Image: () => null,
502
- UI: ({ part }) => part.display,
503
- tools: {
504
- Fallback: () => null
505
- }
506
- };
507
- var MessageContent = ({
508
- components: {
509
- Text = defaultComponents.Text,
510
- Image = defaultComponents.Image,
511
- UI = defaultComponents.UI,
512
- tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
513
- } = {}
514
- }) => {
515
- const { useMessage } = useMessageContext();
516
- const message = useMessage((s) => s.message);
517
- const content = message.content;
518
- const status = message.role === "assistant" ? message.status : "done";
519
- return /* @__PURE__ */ jsx7(Fragment, { children: content.map((part, i) => {
520
- const key = i;
521
- const type = part.type;
522
- let component = null;
523
- switch (type) {
524
- case "text":
525
- component = /* @__PURE__ */ jsx7(Text, { part });
526
- break;
527
- case "image":
528
- component = /* @__PURE__ */ jsx7(Image, { part });
529
- break;
530
- case "ui":
531
- component = /* @__PURE__ */ jsx7(UI, { part });
532
- break;
533
- case "tool-call": {
534
- const Tool = by_name[part.name] || Fallback;
535
- component = /* @__PURE__ */ jsx7(Tool, { part });
536
- break;
537
- }
538
- default:
539
- throw new Error(`Unknown content part type: ${type}`);
540
- }
541
- return /* @__PURE__ */ jsx7(
542
- ContentPartProvider,
543
- {
544
- part,
545
- status: i === content.length - 1 ? status : "done",
546
- children: component
547
- },
548
- key
549
- );
550
- }) });
551
- };
552
-
553
- // src/primitives/message/MessageInProgress.tsx
554
- import {
555
- Primitive as Primitive4
556
- } from "@radix-ui/react-primitive";
557
- import { forwardRef as forwardRef4, useMemo as useMemo4 } from "react";
558
- import { jsx as jsx8 } from "react/jsx-runtime";
559
- var MessageInProgress = forwardRef4((props, ref) => {
560
- const { useMessage } = useMessageContext();
561
- useMemo4(() => {
562
- useMessage.getState().setInProgressIndicator(/* @__PURE__ */ jsx8(Primitive4.div, { ...props, ref }));
563
- }, [useMessage, props, ref]);
564
- return null;
565
- });
566
-
567
485
  // src/primitives/thread/ThreadMessages.tsx
568
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
486
+ import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
569
487
  var getComponents = (components) => {
570
488
  return {
571
489
  EditComposer: components.EditComposer ?? components.UserMessage ?? components.Message,
@@ -574,64 +492,62 @@ var getComponents = (components) => {
574
492
  };
575
493
  };
576
494
  var ThreadMessages = ({ components }) => {
577
- const { useThread } = useAssistantContext();
578
- const thread = useThread();
579
- const messages = thread.messages;
495
+ const { useThread } = useThreadContext();
496
+ const messagesLength = useThread((t) => t.messages.length);
580
497
  const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
581
- if (messages.length === 0) return null;
582
- return /* @__PURE__ */ jsx9(Fragment2, { children: messages.map((message, idx) => {
583
- const parentId = messages[idx - 1]?.id ?? null;
584
- return /* @__PURE__ */ jsxs3(
498
+ if (messagesLength === 0) return null;
499
+ return /* @__PURE__ */ jsx5(Fragment, { children: new Array(messagesLength).fill(null).map((_, idx) => {
500
+ const messageIndex = idx;
501
+ return /* @__PURE__ */ jsxs2(
585
502
  MessageProvider,
586
503
  {
587
- message,
588
- parentId,
504
+ messageIndex,
589
505
  children: [
590
- /* @__PURE__ */ jsxs3(MessageIf, { user: true, children: [
591
- /* @__PURE__ */ jsx9(ComposerIf, { editing: false, children: /* @__PURE__ */ jsx9(UserMessage, {}) }),
592
- /* @__PURE__ */ jsx9(ComposerIf, { editing: true, children: /* @__PURE__ */ jsx9(EditComposer, {}) })
506
+ /* @__PURE__ */ jsxs2(MessageIf, { user: true, children: [
507
+ /* @__PURE__ */ jsx5(ComposerIf, { editing: false, children: /* @__PURE__ */ jsx5(UserMessage, {}) }),
508
+ /* @__PURE__ */ jsx5(ComposerIf, { editing: true, children: /* @__PURE__ */ jsx5(EditComposer, {}) })
593
509
  ] }),
594
- /* @__PURE__ */ jsx9(MessageIf, { assistant: true, children: /* @__PURE__ */ jsx9(AssistantMessage, {}) })
510
+ /* @__PURE__ */ jsx5(MessageIf, { assistant: true, children: /* @__PURE__ */ jsx5(AssistantMessage, {}) })
595
511
  ]
596
512
  },
597
- parentId ?? "__ROOT__"
513
+ messageIndex
598
514
  );
599
515
  }) });
600
516
  };
601
517
 
602
518
  // src/primitives/thread/ThreadScrollToBottom.tsx
603
- import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
519
+ import { composeEventHandlers as composeEventHandlers2 } from "@radix-ui/primitive";
604
520
  import {
605
- Primitive as Primitive5
521
+ Primitive as Primitive3
606
522
  } from "@radix-ui/react-primitive";
607
- import { forwardRef as forwardRef5 } from "react";
608
- import { jsx as jsx10 } from "react/jsx-runtime";
609
- var ThreadScrollToBottom = forwardRef5(({ onClick, ...rest }, ref) => {
610
- const { useViewport } = useAssistantContext();
523
+ import { forwardRef as forwardRef3 } from "react";
524
+ import { jsx as jsx6 } from "react/jsx-runtime";
525
+ var ThreadScrollToBottom = forwardRef3(({ onClick, ...rest }, ref) => {
526
+ const { useViewport } = useThreadContext();
611
527
  const isAtBottom = useViewport((s) => s.isAtBottom);
612
528
  const handleScrollToBottom = () => {
613
529
  useViewport.getState().scrollToBottom();
614
530
  };
615
- return /* @__PURE__ */ jsx10(
616
- Primitive5.button,
531
+ return /* @__PURE__ */ jsx6(
532
+ Primitive3.button,
617
533
  {
618
534
  ...rest,
619
535
  disabled: isAtBottom,
620
536
  ref,
621
- onClick: composeEventHandlers3(onClick, handleScrollToBottom)
537
+ onClick: composeEventHandlers2(onClick, handleScrollToBottom)
622
538
  }
623
539
  );
624
540
  });
625
541
 
626
542
  // src/primitives/thread/ThreadSuggestion.tsx
627
- import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
543
+ import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
628
544
  import {
629
- Primitive as Primitive6
545
+ Primitive as Primitive4
630
546
  } from "@radix-ui/react-primitive";
631
- import { forwardRef as forwardRef6 } from "react";
632
- import { jsx as jsx11 } from "react/jsx-runtime";
633
- var ThreadSuggestion = forwardRef6(({ onClick, prompt, method, autoSend: send, ...rest }, ref) => {
634
- const { useThread, useComposer } = useAssistantContext();
547
+ import { forwardRef as forwardRef4 } from "react";
548
+ import { jsx as jsx7 } from "react/jsx-runtime";
549
+ var ThreadSuggestion = forwardRef4(({ onClick, prompt, method, autoSend: send, ...rest }, ref) => {
550
+ const { useThread, useComposer } = useThreadContext();
635
551
  const isDisabled = useThread((t) => t.isRunning);
636
552
  const handleApplySuggestion = () => {
637
553
  const thread = useThread.getState();
@@ -641,13 +557,13 @@ var ThreadSuggestion = forwardRef6(({ onClick, prompt, method, autoSend: send, .
641
557
  composer.send();
642
558
  }
643
559
  };
644
- return /* @__PURE__ */ jsx11(
645
- Primitive6.button,
560
+ return /* @__PURE__ */ jsx7(
561
+ Primitive4.button,
646
562
  {
647
563
  ...rest,
648
564
  disabled: isDisabled,
649
565
  ref,
650
- onClick: composeEventHandlers4(onClick, handleApplySuggestion)
566
+ onClick: composeEventHandlers3(onClick, handleApplySuggestion)
651
567
  }
652
568
  );
653
569
  });
@@ -663,16 +579,16 @@ __export(composer_exports, {
663
579
  });
664
580
 
665
581
  // src/primitives/composer/ComposerRoot.tsx
666
- import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
582
+ import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
667
583
  import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
668
584
  import {
669
- Primitive as Primitive7
585
+ Primitive as Primitive5
670
586
  } from "@radix-ui/react-primitive";
671
- import { forwardRef as forwardRef7, useRef as useRef2 } from "react";
672
- import { jsx as jsx12 } from "react/jsx-runtime";
673
- var ComposerRoot = forwardRef7(
587
+ import { forwardRef as forwardRef5, useRef as useRef2 } from "react";
588
+ import { jsx as jsx8 } from "react/jsx-runtime";
589
+ var ComposerRoot = forwardRef5(
674
590
  ({ onSubmit, ...rest }, forwardedRef) => {
675
- const { useViewport } = useAssistantContext();
591
+ const { useViewport } = useThreadContext();
676
592
  const { useComposer } = useComposerContext();
677
593
  const formRef = useRef2(null);
678
594
  const ref = useComposedRefs2(forwardedRef, formRef);
@@ -683,32 +599,32 @@ var ComposerRoot = forwardRef7(
683
599
  composerState.send();
684
600
  useViewport.getState().scrollToBottom();
685
601
  };
686
- return /* @__PURE__ */ jsx12(
687
- Primitive7.form,
602
+ return /* @__PURE__ */ jsx8(
603
+ Primitive5.form,
688
604
  {
689
605
  ...rest,
690
606
  ref,
691
- onSubmit: composeEventHandlers5(onSubmit, handleSubmit)
607
+ onSubmit: composeEventHandlers4(onSubmit, handleSubmit)
692
608
  }
693
609
  );
694
610
  }
695
611
  );
696
612
 
697
613
  // src/primitives/composer/ComposerInput.tsx
698
- import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
614
+ import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
699
615
  import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
700
616
  import { Slot } from "@radix-ui/react-slot";
701
617
  import {
702
- forwardRef as forwardRef8,
703
- useCallback,
704
- useEffect as useEffect3,
618
+ forwardRef as forwardRef6,
619
+ useCallback as useCallback6,
620
+ useEffect as useEffect4,
705
621
  useRef as useRef3
706
622
  } from "react";
707
623
  import TextareaAutosize from "react-textarea-autosize";
708
- import { jsx as jsx13 } from "react/jsx-runtime";
709
- var ComposerInput = forwardRef8(
624
+ import { jsx as jsx9 } from "react/jsx-runtime";
625
+ var ComposerInput = forwardRef6(
710
626
  ({ autoFocus = false, asChild, disabled, onChange, onKeyDown, ...rest }, forwardedRef) => {
711
- const { useThread, useViewport } = useAssistantContext();
627
+ const { useThread, useViewport } = useThreadContext();
712
628
  const { useComposer, type } = useComposerContext();
713
629
  const value = useComposer((c) => {
714
630
  if (!c.isEditing) return "";
@@ -734,7 +650,7 @@ var ComposerInput = forwardRef8(
734
650
  const textareaRef = useRef3(null);
735
651
  const ref = useComposedRefs3(forwardedRef, textareaRef);
736
652
  const autoFocusEnabled = autoFocus && !disabled;
737
- const focus = useCallback(() => {
653
+ const focus = useCallback6(() => {
738
654
  const textarea = textareaRef.current;
739
655
  if (!textarea || !autoFocusEnabled) return;
740
656
  textarea.focus();
@@ -743,25 +659,25 @@ var ComposerInput = forwardRef8(
743
659
  textareaRef.current.value.length
744
660
  );
745
661
  }, [autoFocusEnabled]);
746
- useEffect3(() => focus(), [focus]);
662
+ useEffect4(() => focus(), [focus]);
747
663
  useOnScrollToBottom(() => {
748
- if (type === "assistant") {
664
+ if (type === "new") {
749
665
  focus();
750
666
  }
751
667
  });
752
- return /* @__PURE__ */ jsx13(
668
+ return /* @__PURE__ */ jsx9(
753
669
  Component,
754
670
  {
755
671
  value,
756
672
  ...rest,
757
673
  ref,
758
674
  disabled,
759
- onChange: composeEventHandlers6(onChange, (e) => {
675
+ onChange: composeEventHandlers5(onChange, (e) => {
760
676
  const composerState = useComposer.getState();
761
677
  if (!composerState.isEditing) return;
762
678
  return composerState.setValue(e.target.value);
763
679
  }),
764
- onKeyDown: composeEventHandlers6(onKeyDown, handleKeyPress)
680
+ onKeyDown: composeEventHandlers5(onKeyDown, handleKeyPress)
765
681
  }
766
682
  );
767
683
  }
@@ -769,16 +685,16 @@ var ComposerInput = forwardRef8(
769
685
 
770
686
  // src/primitives/composer/ComposerSend.tsx
771
687
  import {
772
- Primitive as Primitive8
688
+ Primitive as Primitive6
773
689
  } from "@radix-ui/react-primitive";
774
- import { forwardRef as forwardRef9 } from "react";
775
- import { jsx as jsx14 } from "react/jsx-runtime";
776
- var ComposerSend = forwardRef9(
690
+ import { forwardRef as forwardRef7 } from "react";
691
+ import { jsx as jsx10 } from "react/jsx-runtime";
692
+ var ComposerSend = forwardRef7(
777
693
  ({ disabled, ...rest }, ref) => {
778
694
  const { useComposer } = useComposerContext();
779
695
  const hasValue = useComposer((c) => c.isEditing && c.value.length > 0);
780
- return /* @__PURE__ */ jsx14(
781
- Primitive8.button,
696
+ return /* @__PURE__ */ jsx10(
697
+ Primitive6.button,
782
698
  {
783
699
  type: "submit",
784
700
  ...rest,
@@ -790,28 +706,193 @@ var ComposerSend = forwardRef9(
790
706
  );
791
707
 
792
708
  // src/primitives/composer/ComposerCancel.tsx
793
- import { composeEventHandlers as composeEventHandlers7 } from "@radix-ui/primitive";
709
+ import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
794
710
  import {
795
- Primitive as Primitive9
711
+ Primitive as Primitive7
796
712
  } from "@radix-ui/react-primitive";
797
- import { forwardRef as forwardRef10 } from "react";
798
- import { jsx as jsx15 } from "react/jsx-runtime";
799
- var ComposerCancel = forwardRef10(({ onClick, ...rest }, ref) => {
713
+ import { forwardRef as forwardRef8 } from "react";
714
+ import { jsx as jsx11 } from "react/jsx-runtime";
715
+ var ComposerCancel = forwardRef8(({ onClick, ...rest }, ref) => {
800
716
  const { useComposer } = useComposerContext();
801
717
  const handleCancel = () => {
802
718
  useComposer.getState().cancel();
803
719
  };
804
- return /* @__PURE__ */ jsx15(
805
- Primitive9.button,
720
+ return /* @__PURE__ */ jsx11(
721
+ Primitive7.button,
806
722
  {
807
723
  type: "button",
808
724
  ...rest,
809
725
  ref,
810
- onClick: composeEventHandlers7(onClick, handleCancel)
726
+ onClick: composeEventHandlers6(onClick, handleCancel)
811
727
  }
812
728
  );
813
729
  });
814
730
 
731
+ // src/primitives/message/index.ts
732
+ var message_exports = {};
733
+ __export(message_exports, {
734
+ Content: () => MessageContent,
735
+ If: () => MessageIf,
736
+ InProgress: () => MessageInProgress,
737
+ Root: () => MessageRoot
738
+ });
739
+
740
+ // src/primitives/message/MessageRoot.tsx
741
+ import { composeEventHandlers as composeEventHandlers7 } from "@radix-ui/primitive";
742
+ import {
743
+ Primitive as Primitive8
744
+ } from "@radix-ui/react-primitive";
745
+ import { forwardRef as forwardRef9 } from "react";
746
+ import { jsx as jsx12 } from "react/jsx-runtime";
747
+ var MessageRoot = forwardRef9(
748
+ ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
749
+ const { useMessage } = useMessageContext();
750
+ const setIsHovering = useMessage((s) => s.setIsHovering);
751
+ const handleMouseEnter = () => {
752
+ setIsHovering(true);
753
+ };
754
+ const handleMouseLeave = () => {
755
+ setIsHovering(false);
756
+ };
757
+ return /* @__PURE__ */ jsx12(
758
+ Primitive8.div,
759
+ {
760
+ ...rest,
761
+ ref,
762
+ onMouseEnter: composeEventHandlers7(onMouseEnter, handleMouseEnter),
763
+ onMouseLeave: composeEventHandlers7(onMouseLeave, handleMouseLeave)
764
+ }
765
+ );
766
+ }
767
+ );
768
+
769
+ // src/context/providers/ContentPartProvider.tsx
770
+ import { useEffect as useEffect5, useState as useState2 } from "react";
771
+ import { create as create3 } from "zustand";
772
+
773
+ // src/context/ContentPartContext.ts
774
+ import { createContext as createContext3, useContext as useContext4 } from "react";
775
+ var ContentPartContext = createContext3(
776
+ null
777
+ );
778
+ var useContentPartContext = () => {
779
+ const context = useContext4(ContentPartContext);
780
+ if (!context)
781
+ throw new Error(
782
+ "This component can only be used inside a component passed to <MessagePrimitive.Content components={...} >."
783
+ );
784
+ return context;
785
+ };
786
+
787
+ // src/context/providers/ContentPartProvider.tsx
788
+ import { jsx as jsx13 } from "react/jsx-runtime";
789
+ var syncContentPart = ({ message }, useContentPart, partIndex) => {
790
+ const part = message.content[partIndex];
791
+ if (!part) return;
792
+ const messageStatus = message.role === "assistant" ? message.status : "done";
793
+ const status = partIndex === message.content.length - 1 ? messageStatus : "done";
794
+ useContentPart.setState({ part, status });
795
+ };
796
+ var useContentPartContext2 = (partIndex) => {
797
+ const { useMessage } = useMessageContext();
798
+ const [context] = useState2(() => {
799
+ const useContentPart = create3(() => ({
800
+ part: { type: "text", text: "" },
801
+ status: "done"
802
+ }));
803
+ syncContentPart(useMessage.getState(), useContentPart, partIndex);
804
+ return { useContentPart };
805
+ });
806
+ useEffect5(() => {
807
+ return useMessage.subscribe((message) => {
808
+ syncContentPart(message, context.useContentPart, partIndex);
809
+ });
810
+ }, [context, useMessage, partIndex]);
811
+ return context;
812
+ };
813
+ var ContentPartProvider = ({
814
+ partIndex,
815
+ children
816
+ }) => {
817
+ const context = useContentPartContext2(partIndex);
818
+ return /* @__PURE__ */ jsx13(ContentPartContext.Provider, { value: context, children });
819
+ };
820
+
821
+ // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
822
+ var ContentPartInProgressIndicator = () => {
823
+ const { useMessage } = useMessageContext();
824
+ const { useContentPart } = useContentPartContext();
825
+ const indicator = useCombinedStore(
826
+ [useMessage, useContentPart],
827
+ (m, c) => c.status === "in_progress" ? m.inProgressIndicator : null
828
+ );
829
+ return indicator;
830
+ };
831
+
832
+ // src/primitives/message/MessageContent.tsx
833
+ import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs3 } from "react/jsx-runtime";
834
+ var defaultComponents = {
835
+ Text: ({ part }) => /* @__PURE__ */ jsxs3(Fragment2, { children: [
836
+ part.text,
837
+ /* @__PURE__ */ jsx14(ContentPartInProgressIndicator, {})
838
+ ] }),
839
+ Image: () => null,
840
+ UI: ({ part }) => part.display,
841
+ tools: {
842
+ Fallback: () => null
843
+ }
844
+ };
845
+ var MessageContent = ({
846
+ components: {
847
+ Text = defaultComponents.Text,
848
+ Image = defaultComponents.Image,
849
+ UI = defaultComponents.UI,
850
+ tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
851
+ } = {}
852
+ }) => {
853
+ const { useMessage } = useMessageContext();
854
+ const message = useMessage((s) => s.message);
855
+ const content = message.content;
856
+ return /* @__PURE__ */ jsx14(Fragment2, { children: content.map((part, i) => {
857
+ const partIndex = i;
858
+ const type = part.type;
859
+ let component = null;
860
+ switch (type) {
861
+ case "text":
862
+ component = /* @__PURE__ */ jsx14(Text, { part });
863
+ break;
864
+ case "image":
865
+ component = /* @__PURE__ */ jsx14(Image, { part });
866
+ break;
867
+ case "ui":
868
+ component = /* @__PURE__ */ jsx14(UI, { part });
869
+ break;
870
+ case "tool-call": {
871
+ const Tool = by_name[part.name] || Fallback;
872
+ component = /* @__PURE__ */ jsx14(Tool, { part });
873
+ break;
874
+ }
875
+ default:
876
+ throw new Error(`Unknown content part type: ${type}`);
877
+ }
878
+ return /* @__PURE__ */ jsx14(ContentPartProvider, { partIndex, children: component }, partIndex);
879
+ }) });
880
+ };
881
+
882
+ // src/primitives/message/MessageInProgress.tsx
883
+ import {
884
+ Primitive as Primitive9
885
+ } from "@radix-ui/react-primitive";
886
+ import { forwardRef as forwardRef10, useMemo as useMemo3 } from "react";
887
+ import { jsx as jsx15 } from "react/jsx-runtime";
888
+ var MessageInProgress = forwardRef10((props, ref) => {
889
+ const { useMessage } = useMessageContext();
890
+ useMemo3(() => {
891
+ useMessage.getState().setInProgressIndicator(/* @__PURE__ */ jsx15(Primitive9.span, { ...props, ref }));
892
+ }, [useMessage, props, ref]);
893
+ return null;
894
+ });
895
+
815
896
  // src/primitives/branchPicker/index.ts
816
897
  var branchPicker_exports = {};
817
898
  __export(branchPicker_exports, {
@@ -822,23 +903,6 @@ __export(branchPicker_exports, {
822
903
  Root: () => BranchPickerRoot
823
904
  });
824
905
 
825
- // src/actions/useGoToNextBranch.tsx
826
- import { useCallback as useCallback2 } from "react";
827
- var useGoToNextBranch = () => {
828
- const { useThread } = useAssistantContext();
829
- const { useMessage, useComposer } = useMessageContext();
830
- const disabled = useCombinedStore(
831
- [useMessage, useComposer],
832
- (m, c) => c.isEditing || m.branches.indexOf(m.message.id) + 1 >= m.branches.length
833
- );
834
- const callback = useCallback2(() => {
835
- const { message, branches } = useMessage.getState();
836
- useThread.getState().switchToBranch(branches[branches.indexOf(message.id) + 1]);
837
- }, [useMessage, useThread]);
838
- if (disabled) return null;
839
- return callback;
840
- };
841
-
842
906
  // src/utils/createActionButton.tsx
843
907
  import { composeEventHandlers as composeEventHandlers8 } from "@radix-ui/primitive";
844
908
  import {
@@ -867,23 +931,6 @@ var createActionButton = (useActionButton) => {
867
931
  // src/primitives/branchPicker/BranchPickerNext.tsx
868
932
  var BranchPickerNext = createActionButton(useGoToNextBranch);
869
933
 
870
- // src/actions/useGoToPreviousBranch.tsx
871
- import { useCallback as useCallback3 } from "react";
872
- var useGoToPreviousBranch = () => {
873
- const { useThread } = useAssistantContext();
874
- const { useMessage, useComposer } = useMessageContext();
875
- const disabled = useCombinedStore(
876
- [useMessage, useComposer],
877
- (m, c) => c.isEditing || m.branches.indexOf(m.message.id) <= 0
878
- );
879
- const callback = useCallback3(() => {
880
- const { message, branches } = useMessage.getState();
881
- useThread.getState().switchToBranch(branches[branches.indexOf(message.id) - 1]);
882
- }, [useMessage, useThread]);
883
- if (disabled) return null;
884
- return callback;
885
- };
886
-
887
934
  // src/primitives/branchPicker/BranchPickerPrevious.tsx
888
935
  var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
889
936
 
@@ -929,7 +976,7 @@ import {
929
976
  import { forwardRef as forwardRef13 } from "react";
930
977
  import { jsx as jsx20 } from "react/jsx-runtime";
931
978
  var ActionBarRoot = forwardRef13(({ hideWhenRunning, autohide, autohideFloat, ...rest }, ref) => {
932
- const { useThread } = useAssistantContext();
979
+ const { useThread } = useThreadContext();
933
980
  const { useMessage } = useMessageContext();
934
981
  const hideAndfloatStatus = useCombinedStore(
935
982
  [useThread, useMessage],
@@ -954,142 +1001,166 @@ var ActionBarRoot = forwardRef13(({ hideWhenRunning, autohide, autohideFloat, ..
954
1001
  );
955
1002
  });
956
1003
 
957
- // src/actions/useCopyMessage.tsx
958
- import { useCallback as useCallback4 } from "react";
959
- var useCopyMessage = ({ copiedDuration = 3e3 }) => {
960
- const { useMessage, useComposer } = useMessageContext();
961
- const hasCopyableContent = useCombinedStore(
962
- [useMessage, useComposer],
963
- (m, c) => {
964
- return c.isEditing || m.message.content.some((c2) => c2.type === "text");
965
- }
966
- );
967
- const callback = useCallback4(() => {
968
- const { isEditing, value: composerValue } = useComposer.getState();
969
- const { message, setIsCopied } = useMessage.getState();
970
- const valueToCopy = isEditing ? composerValue : getMessageText(message);
971
- navigator.clipboard.writeText(valueToCopy);
972
- setIsCopied(true);
973
- setTimeout(() => setIsCopied(false), copiedDuration);
974
- }, [useComposer, useMessage, copiedDuration]);
975
- if (!hasCopyableContent) return null;
976
- return callback;
977
- };
978
-
979
1004
  // src/primitives/actionBar/ActionBarCopy.tsx
980
1005
  var ActionBarCopy = createActionButton(useCopyMessage);
981
1006
 
982
- // src/actions/useReloadMessage.tsx
983
- import { useCallback as useCallback5 } from "react";
984
- var useReloadMessage = () => {
985
- const { useThread, useViewport } = useAssistantContext();
986
- const { useMessage } = useMessageContext();
987
- const disabled = useCombinedStore(
988
- [useThread, useMessage],
989
- (t, m) => t.isRunning || m.message.role !== "assistant"
990
- );
991
- const callback = useCallback5(() => {
992
- const { parentId } = useMessage.getState();
993
- useThread.getState().startRun(parentId);
994
- useViewport.getState().scrollToBottom();
995
- }, [useMessage, useThread, useViewport]);
996
- if (disabled) return null;
997
- return callback;
998
- };
999
-
1000
1007
  // src/primitives/actionBar/ActionBarReload.tsx
1001
1008
  var ActionBarReload = createActionButton(useReloadMessage);
1002
1009
 
1003
- // src/actions/useBeginMessageEdit.tsx
1004
- import { useCallback as useCallback6 } from "react";
1005
- var useBeginMessageEdit = () => {
1006
- const { useMessage, useComposer } = useMessageContext();
1007
- const disabled = useCombinedStore(
1008
- [useMessage, useComposer],
1009
- (m, c) => m.message.role !== "user" || c.isEditing
1010
- );
1011
- const callback = useCallback6(() => {
1012
- const { edit } = useComposer.getState();
1013
- edit();
1014
- }, [useComposer]);
1015
- if (disabled) return null;
1016
- return callback;
1017
- };
1018
-
1019
1010
  // src/primitives/actionBar/ActionBarEdit.tsx
1020
1011
  var ActionBarEdit = createActionButton(useBeginMessageEdit);
1021
1012
 
1022
1013
  // src/primitives/contentPart/index.ts
1023
1014
  var contentPart_exports = {};
1024
1015
  __export(contentPart_exports, {
1025
- InProgressIndicator: () => ContentPartInProgressIndicator,
1026
- Provider: () => ContentPartProvider
1016
+ InProgressIndicator: () => ContentPartInProgressIndicator
1027
1017
  });
1028
1018
 
1029
- // src/adapters/vercel/VercelAIAssistantProvider.tsx
1030
- import { useMemo as useMemo6 } from "react";
1031
-
1032
- // src/adapters/vercel/useDummyAIAssistantContext.tsx
1033
- import { useState as useState3 } from "react";
1034
- import { create as create5 } from "zustand";
1019
+ // src/runtime/vercel-ai/rsc/useVercelRSCRuntime.tsx
1020
+ import { useEffect as useEffect7, useInsertionEffect, useState as useState3 } from "react";
1035
1021
 
1036
- // src/utils/context/stores/ViewportStore.tsx
1022
+ // src/runtime/vercel-ai/rsc/VercelRSCRuntime.tsx
1037
1023
  import { create as create4 } from "zustand";
1038
- var makeViewportStore = () => {
1039
- const scrollToBottomListeners = /* @__PURE__ */ new Set();
1040
- return create4(() => ({
1041
- isAtBottom: true,
1042
- scrollToBottom: () => {
1043
- for (const listener of scrollToBottomListeners) {
1044
- listener();
1045
- }
1046
- },
1047
- onScrollToBottom: (callback) => {
1048
- scrollToBottomListeners.add(callback);
1049
- return () => {
1050
- scrollToBottomListeners.delete(callback);
1051
- };
1052
- }
1053
- }));
1024
+
1025
+ // src/runtime/vercel-ai/rsc/useVercelRSCSync.tsx
1026
+ import { useEffect as useEffect6, useMemo as useMemo4 } from "react";
1027
+
1028
+ // src/runtime/vercel-ai/utils/ThreadMessageConverter.ts
1029
+ var ThreadMessageConverter = class {
1030
+ cache = /* @__PURE__ */ new WeakMap();
1031
+ convertMessages(converter, messages) {
1032
+ return messages.map((m) => {
1033
+ const cached = this.cache.get(m);
1034
+ const newMessage = converter(m, cached);
1035
+ this.cache.set(m, newMessage);
1036
+ return newMessage;
1037
+ });
1038
+ }
1054
1039
  };
1055
1040
 
1056
- // src/adapters/vercel/useDummyAIAssistantContext.tsx
1057
- var makeDummyThreadStore = () => {
1058
- return create5(() => ({
1059
- messages: [],
1060
- isRunning: false,
1061
- getBranches: () => {
1062
- return [];
1063
- },
1064
- switchToBranch: () => {
1065
- throw new Error("Not implemented");
1066
- },
1067
- append: () => {
1068
- throw new Error("Not implemented");
1069
- },
1070
- startRun: () => {
1071
- throw new Error("Not implemented");
1072
- },
1073
- cancelRun: () => {
1074
- throw new Error("Not implemented");
1041
+ // src/runtime/vercel-ai/rsc/getVercelRSCMessage.tsx
1042
+ var symbolInnerRSCMessage = Symbol("innerVercelRSCMessage");
1043
+ var getVercelRSCMessage = (message) => {
1044
+ return message[symbolInnerRSCMessage];
1045
+ };
1046
+
1047
+ // src/runtime/vercel-ai/rsc/useVercelRSCSync.tsx
1048
+ var vercelToThreadMessage = (converter, rawMessage) => {
1049
+ const message = converter(rawMessage);
1050
+ return {
1051
+ id: message.id,
1052
+ role: message.role,
1053
+ content: [{ type: "ui", display: message.display }],
1054
+ createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1055
+ ...{ status: "done" },
1056
+ [symbolInnerRSCMessage]: rawMessage
1057
+ };
1058
+ };
1059
+ var useVercelRSCSync = (adapter, updateData) => {
1060
+ const [converter, convertCallback] = useMemo4(() => {
1061
+ const rscConverter = adapter.convertMessage ?? ((m) => m);
1062
+ const convertCallback2 = (m, cache) => {
1063
+ if (cache) return cache;
1064
+ return vercelToThreadMessage(rscConverter, m);
1065
+ };
1066
+ return [new ThreadMessageConverter(), convertCallback2];
1067
+ }, [adapter.convertMessage]);
1068
+ useEffect6(() => {
1069
+ updateData(converter.convertMessages(convertCallback, adapter.messages));
1070
+ }, [updateData, converter, convertCallback, adapter.messages]);
1071
+ };
1072
+
1073
+ // src/runtime/vercel-ai/rsc/VercelRSCRuntime.tsx
1074
+ var EMPTY_BRANCHES = Object.freeze([]);
1075
+ var VercelRSCRuntime = class {
1076
+ constructor(adapter) {
1077
+ this.adapter = adapter;
1078
+ this.useAdapter = create4(() => ({
1079
+ adapter
1080
+ }));
1081
+ }
1082
+ useAdapter;
1083
+ _subscriptions = /* @__PURE__ */ new Set();
1084
+ isRunning = false;
1085
+ messages = [];
1086
+ withRunning = (callback) => {
1087
+ this.isRunning = true;
1088
+ return callback.finally(() => {
1089
+ this.isRunning = false;
1090
+ });
1091
+ };
1092
+ getBranches() {
1093
+ return EMPTY_BRANCHES;
1094
+ }
1095
+ switchToBranch() {
1096
+ throw new Error(
1097
+ "Branch switching is not supported by VercelRSCAssistantProvider."
1098
+ );
1099
+ }
1100
+ async append(message) {
1101
+ if (message.parentId !== (this.messages.at(-1)?.id ?? null)) {
1102
+ if (!this.adapter.edit)
1103
+ throw new Error(
1104
+ "Message editing is not enabled, please provide an edit callback to VercelRSCAssistantProvider."
1105
+ );
1106
+ await this.withRunning(this.adapter.edit(message));
1107
+ } else {
1108
+ await this.withRunning(this.adapter.append(message));
1075
1109
  }
1076
- }));
1110
+ }
1111
+ async startRun(parentId) {
1112
+ if (!this.adapter.reload)
1113
+ throw new Error(
1114
+ "Message reloading is not enabled, please provide a reload callback to VercelRSCAssistantProvider."
1115
+ );
1116
+ await this.withRunning(this.adapter.reload(parentId));
1117
+ }
1118
+ cancelRun() {
1119
+ if (process.env["NODE_ENV"] === "development") {
1120
+ console.warn(
1121
+ "Run cancellation is not supported by VercelRSCAssistantProvider."
1122
+ );
1123
+ }
1124
+ }
1125
+ subscribe(callback) {
1126
+ this._subscriptions.add(callback);
1127
+ return () => this._subscriptions.delete(callback);
1128
+ }
1129
+ onAdapterUpdated() {
1130
+ if (this.useAdapter.getState().adapter !== this.adapter) {
1131
+ this.useAdapter.setState({ adapter: this.adapter });
1132
+ }
1133
+ }
1134
+ updateData = (messages) => {
1135
+ this.messages = messages;
1136
+ for (const callback of this._subscriptions) callback();
1137
+ };
1138
+ unstable_synchronizer = () => {
1139
+ const { adapter } = this.useAdapter();
1140
+ useVercelRSCSync(adapter, this.updateData);
1141
+ return null;
1142
+ };
1077
1143
  };
1078
- var useDummyAIAssistantContext = () => {
1079
- const [context] = useState3(() => {
1080
- const useThread = makeDummyThreadStore();
1081
- const useViewport = makeViewportStore();
1082
- const useComposer = makeThreadComposerStore(useThread);
1083
- return { useThread, useViewport, useComposer };
1144
+
1145
+ // src/runtime/vercel-ai/rsc/useVercelRSCRuntime.tsx
1146
+ var useVercelRSCRuntime = (adapter) => {
1147
+ const [runtime] = useState3(() => new VercelRSCRuntime(adapter));
1148
+ useInsertionEffect(() => {
1149
+ runtime.adapter = adapter;
1150
+ });
1151
+ useEffect7(() => {
1152
+ runtime.onAdapterUpdated();
1084
1153
  });
1085
- return context;
1154
+ return runtime;
1086
1155
  };
1087
1156
 
1088
- // src/adapters/vercel/useVercelAIThreadState.tsx
1089
- import { useCallbackRef as useCallbackRef3 } from "@radix-ui/react-use-callback-ref";
1090
- import { useCallback as useCallback7, useMemo as useMemo5, useRef as useRef4, useState as useState4 } from "react";
1157
+ // src/runtime/vercel-ai/ui/use-chat/useVercelUseChatRuntime.tsx
1158
+ import { useEffect as useEffect10, useInsertionEffect as useInsertionEffect2, useState as useState4 } from "react";
1159
+
1160
+ // src/runtime/vercel-ai/ui/VercelAIRuntime.tsx
1161
+ import { create as create5 } from "zustand";
1091
1162
 
1092
- // src/adapters/idUtils.tsx
1163
+ // src/runtime/utils/idUtils.tsx
1093
1164
  import { customAlphabet } from "nanoid/non-secure";
1094
1165
  var generateId = customAlphabet(
1095
1166
  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
@@ -1098,7 +1169,7 @@ var generateId = customAlphabet(
1098
1169
  var optimisticPrefix = "__optimistic__";
1099
1170
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1100
1171
 
1101
- // src/adapters/MessageRepository.tsx
1172
+ // src/runtime/utils/MessageRepository.tsx
1102
1173
  var findHead = (message) => {
1103
1174
  if (message.next) return findHead(message.next);
1104
1175
  return message;
@@ -1167,10 +1238,10 @@ var MessageRepository = class {
1167
1238
  level: prev ? prev.level + 1 : 0
1168
1239
  };
1169
1240
  this.messages.set(message.id, newItem);
1241
+ this.performOp(prev, newItem, "link");
1170
1242
  if (this.head === prev) {
1171
1243
  this.head = newItem;
1172
1244
  }
1173
- this.performOp(prev, newItem, "link");
1174
1245
  }
1175
1246
  appendOptimisticMessage(parentId, message) {
1176
1247
  let optimisticId;
@@ -1187,14 +1258,14 @@ var MessageRepository = class {
1187
1258
  }
1188
1259
  deleteMessage(messageId, replacementId) {
1189
1260
  const message = this.messages.get(messageId);
1190
- const replacement = replacementId ? this.messages.get(replacementId) : null;
1191
1261
  if (!message)
1192
1262
  throw new Error(
1193
1263
  "MessageRepository(deleteMessage): Optimistic message not found. This is likely an internal bug in assistant-ui."
1194
1264
  );
1265
+ const replacement = replacementId === void 0 ? message.prev : replacementId === null ? null : this.messages.get(replacementId);
1195
1266
  if (replacement === void 0)
1196
1267
  throw new Error(
1197
- "MessageRepository(deleteMessage): New message not found. This is likely an internal bug in assistant-ui."
1268
+ "MessageRepository(deleteMessage): Replacement not found. This is likely an internal bug in assistant-ui."
1198
1269
  );
1199
1270
  for (const child of message.children) {
1200
1271
  const childMessage = this.messages.get(child);
@@ -1204,11 +1275,11 @@ var MessageRepository = class {
1204
1275
  );
1205
1276
  this.performOp(replacement, childMessage, "relink");
1206
1277
  }
1278
+ this.performOp(null, message, "cut");
1207
1279
  this.messages.delete(messageId);
1208
1280
  if (this.head === message) {
1209
- this.head = replacement;
1281
+ this.head = replacement ? findHead(replacement) : null;
1210
1282
  }
1211
- this.performOp(null, message, "cut");
1212
1283
  }
1213
1284
  getBranches(messageId) {
1214
1285
  const message = this.messages.get(messageId);
@@ -1249,35 +1320,46 @@ var MessageRepository = class {
1249
1320
  }
1250
1321
  };
1251
1322
 
1252
- // src/adapters/ThreadMessageConverter.ts
1253
- var ThreadMessageConverter = class {
1254
- cache = /* @__PURE__ */ new WeakMap();
1255
- convertMessages(converter, messages) {
1256
- return messages.map((m) => {
1257
- const cached = this.cache.get(m);
1258
- const newMessage = converter(m, cached);
1259
- this.cache.set(m, newMessage);
1260
- return newMessage;
1261
- });
1262
- }
1323
+ // src/runtime/vercel-ai/ui/getVercelAIMessage.tsx
1324
+ var symbolInnerAIMessage = Symbol("innerVercelAIUIMessage");
1325
+ var getVercelAIMessage = (message) => {
1326
+ return message[symbolInnerAIMessage];
1263
1327
  };
1264
1328
 
1265
- // src/adapters/vercel/VercelThreadMessage.tsx
1266
- var symbolInnerMessage = Symbol("innerMessage");
1267
- var symbolInnerRSCMessage = Symbol("innerRSCMessage");
1268
- var getVercelMessage = (message) => {
1269
- return message[symbolInnerMessage];
1329
+ // src/runtime/vercel-ai/ui/utils/sliceMessagesUntil.tsx
1330
+ var sliceMessagesUntil = (messages, messageId) => {
1331
+ if (messageId == null) return [];
1332
+ const messageIdx = messages.findIndex((m) => m.id === messageId);
1333
+ if (messageIdx === -1)
1334
+ throw new Error(
1335
+ "useVercelAIThreadState: Message not found. This is liekly an internal bug in assistant-ui."
1336
+ );
1337
+ return messages.slice(0, messageIdx + 1);
1270
1338
  };
1271
- var getVercelRSCMessage = (message) => {
1272
- return message[symbolInnerRSCMessage];
1339
+
1340
+ // src/runtime/vercel-ai/ui/utils/useVercelAIComposerSync.tsx
1341
+ import { useEffect as useEffect8 } from "react";
1342
+ var useVercelAIComposerSync = (vercel) => {
1343
+ const { useComposer } = useThreadContext();
1344
+ useEffect8(() => {
1345
+ useComposer.setState({
1346
+ value: vercel.input,
1347
+ setValue: vercel.setInput
1348
+ });
1349
+ }, [useComposer, vercel.input, vercel.setInput]);
1273
1350
  };
1274
1351
 
1275
- // src/adapters/vercel/useVercelAIThreadState.tsx
1276
- var vercelToThreadMessage = (message, status) => {
1352
+ // src/runtime/vercel-ai/ui/utils/useVercelAIThreadSync.tsx
1353
+ import { useEffect as useEffect9, useMemo as useMemo5 } from "react";
1354
+ var getIsRunning = (vercel) => {
1355
+ if ("isLoading" in vercel) return vercel.isLoading;
1356
+ return vercel.status === "in_progress";
1357
+ };
1358
+ var vercelToThreadMessage2 = (message, status) => {
1277
1359
  const common = {
1278
1360
  id: message.id,
1279
1361
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1280
- [symbolInnerMessage]: message
1362
+ [symbolInnerAIMessage]: message
1281
1363
  };
1282
1364
  switch (message.role) {
1283
1365
  case "user":
@@ -1309,47 +1391,115 @@ var vercelToThreadMessage = (message, status) => {
1309
1391
  );
1310
1392
  }
1311
1393
  };
1312
- var sliceMessagesUntil = (messages, messageId) => {
1313
- if (messageId == null) return [];
1314
- const messageIdx = messages.findIndex((m) => m.id === messageId);
1315
- if (messageIdx === -1)
1316
- throw new Error(
1317
- "useVercelAIThreadState: Message not found. This is liekly an internal bug in assistant-ui."
1318
- );
1319
- return messages.slice(0, messageIdx + 1);
1320
- };
1321
- var hasUpcomingMessage = (isRunning, messages) => {
1322
- return isRunning && messages[messages.length - 1]?.role !== "assistant";
1323
- };
1324
- var getIsRunning = (vercel) => {
1325
- if ("isLoading" in vercel) return vercel.isLoading;
1326
- return vercel.status === "in_progress";
1327
- };
1328
- var useVercelAIThreadState = (vercel) => {
1329
- const [data] = useState4(() => new MessageRepository());
1394
+ var useVercelAIThreadSync = (vercel, updateData) => {
1330
1395
  const isRunning = getIsRunning(vercel);
1331
1396
  const converter = useMemo5(() => new ThreadMessageConverter(), []);
1332
- const assistantOptimisticIdRef = useRef4(null);
1333
- const messages = useMemo5(() => {
1397
+ useEffect9(() => {
1334
1398
  const lastMessageId = vercel.messages.at(-1)?.id;
1335
1399
  const convertCallback = (message, cache) => {
1336
1400
  const status = lastMessageId === message.id && isRunning ? "in_progress" : "done";
1337
1401
  if (cache && (cache.role === "user" || cache.status === status))
1338
1402
  return cache;
1339
- return vercelToThreadMessage(message, status);
1403
+ return vercelToThreadMessage2(message, status);
1340
1404
  };
1341
- const vm = converter.convertMessages(convertCallback, vercel.messages);
1405
+ const messages = converter.convertMessages(
1406
+ convertCallback,
1407
+ vercel.messages
1408
+ );
1409
+ updateData(isRunning, messages);
1410
+ }, [updateData, isRunning, vercel.messages, converter]);
1411
+ };
1412
+
1413
+ // src/runtime/vercel-ai/ui/VercelAIRuntime.tsx
1414
+ var hasUpcomingMessage = (isRunning, messages) => {
1415
+ return isRunning && messages[messages.length - 1]?.role !== "assistant";
1416
+ };
1417
+ var VercelAIRuntime = class {
1418
+ constructor(vercel) {
1419
+ this.vercel = vercel;
1420
+ this.useVercel = create5(() => ({
1421
+ vercel
1422
+ }));
1423
+ }
1424
+ _subscriptions = /* @__PURE__ */ new Set();
1425
+ repository = new MessageRepository();
1426
+ assistantOptimisticId = null;
1427
+ useVercel;
1428
+ messages = [];
1429
+ isRunning = false;
1430
+ getBranches(messageId) {
1431
+ return this.repository.getBranches(messageId);
1432
+ }
1433
+ switchToBranch(branchId) {
1434
+ this.repository.switchToBranch(branchId);
1435
+ this.updateVercelMessages(this.repository.getMessages());
1436
+ }
1437
+ async append(message) {
1438
+ if (message.content.length !== 1 || message.content[0]?.type !== "text")
1439
+ throw new Error("Only text content is supported by Vercel AI SDK.");
1440
+ const newMessages = sliceMessagesUntil(
1441
+ this.vercel.messages,
1442
+ message.parentId
1443
+ );
1444
+ this.vercel.setMessages(newMessages);
1445
+ await this.vercel.append({
1446
+ role: "user",
1447
+ content: message.content[0].text
1448
+ });
1449
+ }
1450
+ async startRun(parentId) {
1451
+ const reloadMaybe = "reload" in this.vercel ? this.vercel.reload : void 0;
1452
+ if (!reloadMaybe)
1453
+ throw new Error(
1454
+ "Reload is not supported by Vercel AI SDK's useAssistant."
1455
+ );
1456
+ const newMessages = sliceMessagesUntil(this.vercel.messages, parentId);
1457
+ this.vercel.setMessages(newMessages);
1458
+ await reloadMaybe();
1459
+ }
1460
+ cancelRun() {
1461
+ const previousMessage = this.vercel.messages.at(-1);
1462
+ this.vercel.stop();
1463
+ if (this.assistantOptimisticId) {
1464
+ this.repository.deleteMessage(this.assistantOptimisticId);
1465
+ this.assistantOptimisticId = null;
1466
+ }
1467
+ let messages = this.repository.getMessages();
1468
+ if (previousMessage?.role === "user" && previousMessage.id === messages.at(-1)?.id) {
1469
+ this.vercel.setInput(previousMessage.content);
1470
+ this.repository.deleteMessage(previousMessage.id);
1471
+ messages = this.repository.getMessages();
1472
+ }
1473
+ setTimeout(() => {
1474
+ this.updateVercelMessages(messages);
1475
+ }, 0);
1476
+ }
1477
+ subscribe(callback) {
1478
+ this._subscriptions.add(callback);
1479
+ return () => this._subscriptions.delete(callback);
1480
+ }
1481
+ updateVercelMessages = (messages) => {
1482
+ this.vercel.setMessages(
1483
+ messages.map(getVercelAIMessage).filter((m) => m != null)
1484
+ );
1485
+ };
1486
+ onVercelUpdated() {
1487
+ if (this.useVercel.getState().vercel !== this.vercel) {
1488
+ this.useVercel.setState({ vercel: this.vercel });
1489
+ }
1490
+ }
1491
+ updateData = (isRunning, vm) => {
1342
1492
  for (let i = 0; i < vm.length; i++) {
1343
1493
  const message = vm[i];
1344
1494
  const parent = vm[i - 1];
1345
- data.addOrUpdateMessage(parent?.id ?? null, message);
1495
+ this.repository.addOrUpdateMessage(parent?.id ?? null, message);
1346
1496
  }
1347
- if (assistantOptimisticIdRef.current) {
1348
- data.deleteMessage(assistantOptimisticIdRef.current, null);
1349
- assistantOptimisticIdRef.current = null;
1497
+ if (this.assistantOptimisticId) {
1498
+ this.repository.deleteMessage(this.assistantOptimisticId);
1499
+ this.assistantOptimisticId = null;
1350
1500
  }
1351
1501
  if (hasUpcomingMessage(isRunning, vm)) {
1352
- assistantOptimisticIdRef.current = data.appendOptimisticMessage(
1502
+ this.assistantOptimisticId = this.repository.appendOptimisticMessage(
1353
1503
  vm.at(-1)?.id ?? null,
1354
1504
  {
1355
1505
  role: "assistant",
@@ -1357,330 +1507,220 @@ var useVercelAIThreadState = (vercel) => {
1357
1507
  }
1358
1508
  );
1359
1509
  }
1360
- data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
1361
- return data.getMessages();
1362
- }, [converter, data, isRunning, vercel.messages]);
1363
- const getBranches2 = useCallback7(
1364
- (messageId) => {
1365
- return data.getBranches(messageId);
1366
- },
1367
- [data]
1368
- );
1369
- const switchToBranch2 = useCallbackRef3((messageId) => {
1370
- data.switchToBranch(messageId);
1371
- vercel.setMessages(
1372
- data.getMessages().map(getVercelMessage).filter((m) => m != null)
1510
+ this.repository.resetHead(
1511
+ this.assistantOptimisticId ?? vm.at(-1)?.id ?? null
1373
1512
  );
1513
+ this.messages = this.repository.getMessages();
1514
+ this.isRunning = isRunning;
1515
+ for (const callback of this._subscriptions) callback();
1516
+ };
1517
+ unstable_synchronizer = () => {
1518
+ const { vercel } = this.useVercel();
1519
+ useVercelAIThreadSync(vercel, this.updateData);
1520
+ useVercelAIComposerSync(vercel);
1521
+ return null;
1522
+ };
1523
+ };
1524
+
1525
+ // src/runtime/vercel-ai/ui/use-chat/useVercelUseChatRuntime.tsx
1526
+ var useVercelUseChatRuntime = (chatHelpers) => {
1527
+ const [runtime] = useState4(() => new VercelAIRuntime(chatHelpers));
1528
+ useInsertionEffect2(() => {
1529
+ runtime.vercel = chatHelpers;
1374
1530
  });
1375
- const startRun = useCallbackRef3(async (parentId) => {
1376
- const reloadMaybe = "reload" in vercel ? vercel.reload : void 0;
1377
- if (!reloadMaybe)
1378
- throw new Error(
1379
- "Reload is not supported by Vercel AI SDK's useAssistant."
1380
- );
1381
- const newMessages = sliceMessagesUntil(vercel.messages, parentId);
1382
- vercel.setMessages(newMessages);
1383
- await reloadMaybe();
1531
+ useEffect10(() => {
1532
+ runtime.onVercelUpdated();
1384
1533
  });
1385
- const append = useCallbackRef3(async (message) => {
1386
- if (message.content.length !== 1 || message.content[0]?.type !== "text")
1387
- throw new Error("Only text content is supported by Vercel AI SDK.");
1388
- const newMessages = sliceMessagesUntil(vercel.messages, message.parentId);
1389
- vercel.setMessages(newMessages);
1390
- await vercel.append({
1391
- role: "user",
1392
- content: message.content[0].text
1393
- });
1534
+ return runtime;
1535
+ };
1536
+
1537
+ // src/runtime/vercel-ai/ui/use-assistant/useVercelUseAssistantRuntime.tsx
1538
+ import { useEffect as useEffect11, useInsertionEffect as useInsertionEffect3, useState as useState5 } from "react";
1539
+ var useVercelUseAssistantRuntime = (assistantHelpers) => {
1540
+ const [runtime] = useState5(() => new VercelAIRuntime(assistantHelpers));
1541
+ useInsertionEffect3(() => {
1542
+ runtime.vercel = assistantHelpers;
1394
1543
  });
1395
- const cancelRun2 = useCallbackRef3(() => {
1396
- const lastMessage = vercel.messages.at(-1);
1397
- vercel.stop();
1398
- if (lastMessage?.role === "user") {
1399
- vercel.setInput(lastMessage.content);
1400
- }
1544
+ useEffect11(() => {
1545
+ runtime.onVercelUpdated();
1401
1546
  });
1402
- return useMemo5(
1403
- () => ({
1404
- isRunning,
1405
- messages,
1406
- getBranches: getBranches2,
1407
- switchToBranch: switchToBranch2,
1408
- append,
1409
- startRun,
1410
- cancelRun: cancelRun2
1411
- }),
1412
- [
1413
- isRunning,
1414
- messages,
1415
- getBranches2,
1416
- switchToBranch2,
1417
- append,
1418
- startRun,
1419
- cancelRun2
1420
- ]
1421
- );
1547
+ return runtime;
1422
1548
  };
1423
1549
 
1424
- // src/adapters/vercel/VercelAIAssistantProvider.tsx
1425
- import { jsx as jsx21 } from "react/jsx-runtime";
1426
- var VercelAIAssistantProvider = ({
1427
- children,
1428
- ...rest
1429
- }) => {
1430
- const context = useDummyAIAssistantContext();
1431
- const vercel = "chat" in rest ? rest.chat : rest.assistant;
1432
- const threadState = useVercelAIThreadState(vercel);
1433
- useMemo6(() => {
1434
- context.useThread.setState(threadState, true);
1435
- }, [context, threadState]);
1436
- useMemo6(() => {
1437
- context.useComposer.setState({
1438
- value: vercel.input,
1439
- setValue: vercel.setInput
1440
- });
1441
- }, [context, vercel.input, vercel.setInput]);
1442
- return /* @__PURE__ */ jsx21(AssistantContext.Provider, { value: context, children });
1443
- };
1550
+ // src/context/providers/AssistantRuntimeProvider.tsx
1551
+ import { memo } from "react";
1444
1552
 
1445
- // src/adapters/vercel/VercelRSCAssistantProvider.tsx
1446
- import {
1447
- useCallback as useCallback8,
1448
- useMemo as useMemo7,
1449
- useState as useState5
1450
- } from "react";
1451
- import { jsx as jsx22 } from "react/jsx-runtime";
1452
- var vercelToThreadMessage2 = (converter, rawMessage) => {
1453
- const message = converter(rawMessage);
1454
- return {
1455
- id: message.id,
1456
- role: message.role,
1457
- content: [{ type: "ui", display: message.display }],
1458
- createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1459
- ...{ status: "done" },
1460
- [symbolInnerRSCMessage]: rawMessage
1461
- };
1462
- };
1463
- var EMPTY_BRANCHES = [];
1464
- var getBranches = () => {
1465
- return EMPTY_BRANCHES;
1466
- };
1467
- var switchToBranch = () => {
1468
- throw new Error(
1469
- "Branch switching is not supported by VercelRSCAssistantProvider."
1470
- );
1471
- };
1472
- var cancelRun = () => {
1473
- if (process.env["NODE_ENV"] === "development") {
1474
- console.warn(
1475
- "Run cancellation is not supported by VercelRSCAssistantProvider."
1476
- );
1477
- }
1478
- };
1479
- var VercelRSCAssistantProvider = ({
1480
- children,
1481
- convertMessage,
1482
- messages: vercelMessages,
1483
- append: appendCallback,
1484
- edit,
1485
- reload
1486
- }) => {
1487
- const context = useDummyAIAssistantContext();
1488
- const [isRunning, setIsRunning] = useState5(false);
1489
- const withRunning = useCallback8((callback) => {
1490
- setIsRunning(true);
1491
- return callback.finally(() => setIsRunning(false));
1492
- }, []);
1493
- const [converter, convertCallback] = useMemo7(() => {
1494
- const rscConverter = convertMessage ?? ((m) => m);
1495
- const convertCallback2 = (m, cache) => {
1496
- if (cache) return cache;
1497
- return vercelToThreadMessage2(rscConverter, m);
1498
- };
1499
- return [new ThreadMessageConverter(), convertCallback2];
1500
- }, [convertMessage]);
1501
- const messages = useMemo7(() => {
1502
- return converter.convertMessages(convertCallback, vercelMessages);
1503
- }, [converter, convertCallback, vercelMessages]);
1504
- const append = useCallback8(
1505
- async (message) => {
1506
- if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
1507
- if (!edit)
1508
- throw new Error(
1509
- "Message editing is not enabled, please provide an edit callback to VercelRSCAssistantProvider."
1510
- );
1511
- await withRunning(edit(message));
1512
- } else {
1513
- await withRunning(appendCallback(message));
1514
- }
1515
- },
1516
- [context, withRunning, appendCallback, edit]
1517
- );
1518
- const startRun = useCallback8(
1519
- async (parentId) => {
1520
- if (!reload)
1521
- throw new Error(
1522
- "Message reloading is not enabled, please provide a reload callback to VercelRSCAssistantProvider."
1523
- );
1524
- await withRunning(reload(parentId));
1525
- },
1526
- [withRunning, reload]
1527
- );
1528
- useMemo7(() => {
1529
- context.useThread.setState(
1530
- {
1531
- messages,
1532
- isRunning,
1533
- getBranches,
1534
- switchToBranch,
1535
- append,
1536
- startRun,
1537
- cancelRun
1538
- },
1539
- true
1540
- );
1541
- }, [context, messages, isRunning, append, startRun]);
1542
- return /* @__PURE__ */ jsx22(AssistantContext.Provider, { value: context, children });
1543
- };
1553
+ // src/context/providers/ThreadProvider.tsx
1554
+ import { useEffect as useEffect12, useInsertionEffect as useInsertionEffect4, useRef as useRef4, useState as useState6 } from "react";
1544
1555
 
1545
- // src/adapters/core/utils/useAssistantContext.tsx
1546
- import {
1547
- useEffect as useEffect4,
1548
- useInsertionEffect,
1549
- useRef as useRef5,
1550
- useState as useState6
1551
- } from "react";
1556
+ // src/context/stores/Composer.ts
1552
1557
  import { create as create6 } from "zustand";
1553
-
1554
- // src/adapters/core/utils/AssistantMessageRepository.tsx
1555
- var AssistantMessageRepository = class {
1556
- constructor(flushCallback) {
1557
- this.flushCallback = flushCallback;
1558
- }
1559
- repository = new MessageRepository();
1560
- getBranches(messageId) {
1561
- return this.repository.getBranches(messageId);
1562
- }
1563
- withModifications(callback) {
1564
- const res = callback(this.repository);
1565
- this.flushCallback(this.repository.getMessages());
1566
- return res;
1567
- }
1568
- };
1569
-
1570
- // src/adapters/core/utils/useAssistantContext.tsx
1571
- var makeThreadStore = (runtimeRef) => {
1572
- const repository = new AssistantMessageRepository((messages) => {
1573
- useThread.setState({ messages });
1574
- });
1575
- const useThread = create6(() => ({
1576
- messages: [],
1577
- isRunning: false,
1578
- getBranches: (messageId) => repository.getBranches(messageId),
1579
- switchToBranch: (branchId) => {
1580
- repository.withModifications((repository2) => {
1581
- repository2.switchToBranch(branchId);
1582
- });
1583
- },
1584
- startRun: async (parentId) => {
1585
- const optimisticId = repository.withModifications((repository2) => {
1586
- const optimisticId2 = repository2.appendOptimisticMessage(parentId, {
1587
- role: "assistant",
1588
- content: [{ type: "text", text: "" }]
1589
- });
1590
- repository2.resetHead(optimisticId2);
1591
- return optimisticId2;
1592
- });
1593
- const { id } = await runtimeRef.current.startRun(parentId);
1594
- repository.withModifications((repository2) => {
1595
- repository2.deleteMessage(optimisticId, id);
1596
- });
1597
- },
1598
- append: async (message) => {
1599
- const [parentOptimisticId, optimisticId] = repository.withModifications(
1600
- (repository2) => {
1601
- const parentOptimisticId2 = repository2.appendOptimisticMessage(
1602
- message.parentId,
1603
- {
1604
- role: "user",
1605
- content: message.content
1606
- }
1607
- );
1608
- const optimisticId2 = repository2.appendOptimisticMessage(
1609
- parentOptimisticId2,
1610
- {
1611
- role: "assistant",
1612
- content: [{ type: "text", text: "" }]
1613
- }
1614
- );
1615
- repository2.resetHead(optimisticId2);
1616
- return [parentOptimisticId2, optimisticId2];
1617
- }
1618
- );
1619
- const { parentId, id } = await runtimeRef.current.append(message);
1620
- repository.withModifications((repository2) => {
1621
- repository2.deleteMessage(parentOptimisticId, parentId);
1622
- repository2.deleteMessage(optimisticId, id);
1558
+ var makeComposerStore = (useThread) => create6()((set, get, store) => {
1559
+ return {
1560
+ ...makeBaseComposer(set, get, store),
1561
+ isEditing: true,
1562
+ send: () => {
1563
+ const { setValue, value } = get();
1564
+ setValue("");
1565
+ useThread.getState().append({
1566
+ parentId: useThread.getState().messages.at(-1)?.id ?? null,
1567
+ content: [{ type: "text", text: value }]
1623
1568
  });
1624
1569
  },
1570
+ cancel: () => {
1571
+ const thread = useThread.getState();
1572
+ if (!thread.isRunning) return false;
1573
+ useThread.getState().cancelRun();
1574
+ return true;
1575
+ }
1576
+ };
1577
+ });
1578
+
1579
+ // src/context/stores/Thread.ts
1580
+ import { create as create7 } from "zustand";
1581
+ var makeThreadStore = (runtimeRef) => {
1582
+ const useThread = create7(() => ({
1583
+ messages: runtimeRef.current.messages,
1584
+ isRunning: runtimeRef.current.isRunning,
1585
+ getBranches: (messageId) => runtimeRef.current.getBranches(messageId),
1586
+ switchToBranch: (branchId) => runtimeRef.current.switchToBranch(branchId),
1587
+ startRun: (parentId) => runtimeRef.current.startRun(parentId),
1588
+ append: (message) => runtimeRef.current.append(message),
1625
1589
  cancelRun: () => runtimeRef.current.cancelRun()
1626
1590
  }));
1627
- const onNewMessage = (parentId, message) => {
1628
- repository.withModifications((repository2) => {
1629
- repository2.addOrUpdateMessage(parentId, message);
1591
+ const onRuntimeUpdate = () => {
1592
+ useThread.setState({
1593
+ messages: runtimeRef.current.messages,
1594
+ isRunning: runtimeRef.current.isRunning
1630
1595
  });
1631
1596
  };
1632
- const onRunningChange = (isRunning) => {
1633
- useThread.setState({ isRunning });
1634
- };
1635
1597
  return {
1636
1598
  useThread,
1637
- onNewMessage,
1638
- onRunningChange
1599
+ onRuntimeUpdate
1639
1600
  };
1640
1601
  };
1641
- var useAssistantContext2 = (runtime) => {
1642
- const runtimeRef = useRef5(runtime);
1643
- useInsertionEffect(() => {
1602
+
1603
+ // src/context/stores/ThreadViewport.tsx
1604
+ import { create as create8 } from "zustand";
1605
+ var makeThreadViewportStore = () => {
1606
+ const scrollToBottomListeners = /* @__PURE__ */ new Set();
1607
+ return create8(() => ({
1608
+ isAtBottom: true,
1609
+ scrollToBottom: () => {
1610
+ for (const listener of scrollToBottomListeners) {
1611
+ listener();
1612
+ }
1613
+ },
1614
+ onScrollToBottom: (callback) => {
1615
+ scrollToBottomListeners.add(callback);
1616
+ return () => {
1617
+ scrollToBottomListeners.delete(callback);
1618
+ };
1619
+ }
1620
+ }));
1621
+ };
1622
+
1623
+ // src/context/providers/ThreadProvider.tsx
1624
+ import { jsx as jsx21, jsxs as jsxs4 } from "react/jsx-runtime";
1625
+ var ThreadProvider = ({
1626
+ children,
1627
+ runtime
1628
+ }) => {
1629
+ const runtimeRef = useRef4(runtime);
1630
+ useInsertionEffect4(() => {
1644
1631
  runtimeRef.current = runtime;
1645
1632
  });
1646
- const [{ context, onNewMessage, onRunningChange }] = useState6(() => {
1647
- const { useThread, onNewMessage: onNewMessage2, onRunningChange: onRunningChange2 } = makeThreadStore(runtimeRef);
1648
- const useViewport = makeViewportStore();
1649
- const useComposer = makeThreadComposerStore(useThread);
1633
+ const [{ context, onRuntimeUpdate }] = useState6(() => {
1634
+ const { useThread, onRuntimeUpdate: onRuntimeUpdate2 } = makeThreadStore(runtimeRef);
1635
+ const useViewport = makeThreadViewportStore();
1636
+ const useComposer = makeComposerStore(useThread);
1650
1637
  return {
1651
- context: { useViewport, useThread, useComposer },
1652
- onNewMessage: onNewMessage2,
1653
- onRunningChange: onRunningChange2
1638
+ context: {
1639
+ useViewport,
1640
+ useThread,
1641
+ useComposer
1642
+ },
1643
+ onRuntimeUpdate: onRuntimeUpdate2
1654
1644
  };
1655
1645
  });
1656
- useEffect4(() => {
1657
- return runtime.subscribeToMessageUpdates(onNewMessage);
1658
- }, [runtime, onNewMessage]);
1659
- useEffect4(() => {
1660
- return runtime.subscribeToStatusUpdates(onRunningChange);
1661
- }, [runtime, onRunningChange]);
1662
- return context;
1646
+ useEffect12(() => {
1647
+ onRuntimeUpdate();
1648
+ return runtime.subscribe(onRuntimeUpdate);
1649
+ }, [onRuntimeUpdate, runtime]);
1650
+ const RuntimeSynchronizer = runtime.unstable_synchronizer;
1651
+ return /* @__PURE__ */ jsxs4(ThreadContext.Provider, { value: context, children: [
1652
+ RuntimeSynchronizer && /* @__PURE__ */ jsx21(RuntimeSynchronizer, {}),
1653
+ children
1654
+ ] });
1655
+ };
1656
+
1657
+ // src/context/providers/AssistantRuntimeProvider.tsx
1658
+ import { jsx as jsx22 } from "react/jsx-runtime";
1659
+ var AssistantRuntimeProviderImpl = ({ children, runtime }) => {
1660
+ return /* @__PURE__ */ jsx22(ThreadProvider, { runtime, children });
1663
1661
  };
1662
+ var AssistantRuntimeProvider = memo(AssistantRuntimeProviderImpl);
1664
1663
 
1665
- // src/adapters/core/AssistantProvider.tsx
1664
+ // src/runtime/vercel-deprecated/VercelAIAssistantProvider.tsx
1666
1665
  import { jsx as jsx23 } from "react/jsx-runtime";
1667
- var AssistantProvider = ({ children, runtime }) => {
1668
- const context = useAssistantContext2(runtime);
1669
- return /* @__PURE__ */ jsx23(AssistantContext.Provider, { value: context, children });
1666
+ var VercelUseChatRuntimeProvider = ({
1667
+ chat,
1668
+ children
1669
+ }) => {
1670
+ const runtime = useVercelUseChatRuntime(chat);
1671
+ return /* @__PURE__ */ jsx23(AssistantRuntimeProvider, { runtime, children });
1672
+ };
1673
+ var VercelUseAssistantRuntimeProvider = ({
1674
+ assistant,
1675
+ children
1676
+ }) => {
1677
+ const runtime = useVercelUseAssistantRuntime(assistant);
1678
+ return /* @__PURE__ */ jsx23(AssistantRuntimeProvider, { runtime, children });
1679
+ };
1680
+ var VercelAIAssistantProvider = ({
1681
+ children,
1682
+ ...rest
1683
+ }) => {
1684
+ if ("chat" in rest) {
1685
+ return /* @__PURE__ */ jsx23(VercelUseChatRuntimeProvider, { chat: rest.chat, children });
1686
+ }
1687
+ return /* @__PURE__ */ jsx23(VercelUseAssistantRuntimeProvider, { assistant: rest.assistant, children });
1688
+ };
1689
+
1690
+ // src/runtime/vercel-deprecated/VercelRSCAssistantProvider.tsx
1691
+ import { jsx as jsx24 } from "react/jsx-runtime";
1692
+ var VercelRSCAssistantProvider = ({
1693
+ children,
1694
+ ...adapter
1695
+ }) => {
1696
+ const runtime = useVercelRSCRuntime(adapter);
1697
+ return /* @__PURE__ */ jsx24(AssistantRuntimeProvider, { runtime, children });
1670
1698
  };
1671
1699
 
1672
- // src/adapters/core/local/useLocalRuntime.tsx
1673
- import { useState as useState7 } from "react";
1700
+ // src/runtime/local/useLocalRuntime.tsx
1701
+ import { useInsertionEffect as useInsertionEffect5, useState as useState7 } from "react";
1674
1702
 
1675
- // src/adapters/core/local/LocalRuntime.tsx
1703
+ // src/runtime/local/LocalRuntime.tsx
1676
1704
  var LocalRuntime = class {
1677
1705
  constructor(adapter) {
1678
1706
  this.adapter = adapter;
1679
1707
  }
1680
- _messageUpdateCallbacks = /* @__PURE__ */ new Set();
1681
- _statusUpdateCallbacks = /* @__PURE__ */ new Set();
1708
+ _subscriptions = /* @__PURE__ */ new Set();
1682
1709
  abortController = null;
1683
1710
  repository = new MessageRepository();
1711
+ get messages() {
1712
+ return this.repository.getMessages();
1713
+ }
1714
+ get isRunning() {
1715
+ return this.abortController != null;
1716
+ }
1717
+ getBranches(messageId) {
1718
+ return this.repository.getBranches(messageId);
1719
+ }
1720
+ switchToBranch(branchId) {
1721
+ this.repository.switchToBranch(branchId);
1722
+ this.notifySubscribers();
1723
+ }
1684
1724
  async append(message) {
1685
1725
  const userMessageId = generateId();
1686
1726
  const userMessage = {
@@ -1689,9 +1729,8 @@ var LocalRuntime = class {
1689
1729
  content: message.content,
1690
1730
  createdAt: /* @__PURE__ */ new Date()
1691
1731
  };
1692
- this.addOrUpdateMessage(message.parentId, userMessage);
1693
- const { id } = await this.startRun(userMessageId);
1694
- return { parentId: userMessageId, id };
1732
+ this.repository.addOrUpdateMessage(message.parentId, userMessage);
1733
+ await this.startRun(userMessageId);
1695
1734
  }
1696
1735
  async startRun(parentId) {
1697
1736
  const id = generateId();
@@ -1704,63 +1743,56 @@ var LocalRuntime = class {
1704
1743
  content: [{ type: "text", text: "" }],
1705
1744
  createdAt: /* @__PURE__ */ new Date()
1706
1745
  };
1707
- this.addOrUpdateMessage(parentId, message);
1708
- void this.run(parentId, messages, message);
1709
- return { id };
1710
- }
1711
- addOrUpdateMessage(parentId, message) {
1712
- const clone = { ...message };
1713
- this.repository.addOrUpdateMessage(parentId, clone);
1714
- for (const callback of this._messageUpdateCallbacks)
1715
- callback(parentId, clone);
1716
- }
1717
- async run(parentId, messages, message) {
1718
- this.cancelRun();
1719
- for (const callback of this._statusUpdateCallbacks) callback(true);
1746
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1747
+ this.abortController?.abort();
1720
1748
  this.abortController = new AbortController();
1749
+ this.notifySubscribers();
1721
1750
  try {
1722
1751
  await this.adapter.run({
1723
1752
  messages,
1724
1753
  abortSignal: this.abortController.signal,
1725
1754
  onUpdate: ({ content }) => {
1726
1755
  message.content = content;
1727
- this.addOrUpdateMessage(parentId, message);
1756
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1757
+ this.notifySubscribers();
1728
1758
  }
1729
1759
  });
1730
1760
  message.status = "done";
1731
- this.addOrUpdateMessage(parentId, message);
1761
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1732
1762
  } catch (e) {
1733
1763
  message.status = "error";
1734
- this.addOrUpdateMessage(parentId, message);
1764
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1735
1765
  console.error(e);
1736
1766
  } finally {
1737
- this.cancelRun();
1767
+ this.abortController = null;
1768
+ this.notifySubscribers();
1738
1769
  }
1739
1770
  }
1740
1771
  cancelRun() {
1741
1772
  if (!this.abortController) return;
1742
1773
  this.abortController.abort();
1743
1774
  this.abortController = null;
1744
- for (const callback of this._statusUpdateCallbacks) callback(false);
1775
+ this.notifySubscribers();
1745
1776
  }
1746
- subscribeToMessageUpdates(callback) {
1747
- this._messageUpdateCallbacks.add(callback);
1748
- return () => this._messageUpdateCallbacks.delete(callback);
1777
+ notifySubscribers() {
1778
+ for (const callback of this._subscriptions) callback();
1749
1779
  }
1750
- subscribeToStatusUpdates(callback) {
1751
- this._statusUpdateCallbacks.add(callback);
1752
- return () => this._statusUpdateCallbacks.delete(callback);
1780
+ subscribe(callback) {
1781
+ this._subscriptions.add(callback);
1782
+ return () => this._subscriptions.delete(callback);
1753
1783
  }
1754
1784
  };
1755
1785
 
1756
- // src/adapters/core/local/useLocalRuntime.tsx
1786
+ // src/runtime/local/useLocalRuntime.tsx
1757
1787
  var useLocalRuntime = (adapter) => {
1758
1788
  const [runtime] = useState7(() => new LocalRuntime(adapter));
1759
- runtime.adapter = adapter;
1789
+ useInsertionEffect5(() => {
1790
+ runtime.adapter = adapter;
1791
+ });
1760
1792
  return runtime;
1761
1793
  };
1762
1794
 
1763
- // src/adapters/core/local/vercel/VercelModelAdapter.tsx
1795
+ // src/runtime/local/vercel/VercelModelAdapter.tsx
1764
1796
  import { streamText } from "ai";
1765
1797
  var VercelModelAdapter = class {
1766
1798
  constructor(model) {
@@ -1803,6 +1835,7 @@ var VercelModelAdapter = class {
1803
1835
  };
1804
1836
  export {
1805
1837
  actionBar_exports as ActionBarPrimitive,
1838
+ AssistantRuntimeProvider,
1806
1839
  branchPicker_exports as BranchPickerPrimitive,
1807
1840
  composer_exports as ComposerPrimitive,
1808
1841
  contentPart_exports as ContentPartPrimitive,
@@ -1810,15 +1843,20 @@ export {
1810
1843
  thread_exports as ThreadPrimitive,
1811
1844
  VercelAIAssistantProvider,
1812
1845
  VercelRSCAssistantProvider,
1813
- AssistantProvider as unstable_AssistantProvider,
1846
+ getVercelAIMessage,
1847
+ getVercelRSCMessage,
1814
1848
  VercelModelAdapter as unstable_VercelModelAdapter,
1815
- getVercelMessage as unstable_getVercelMessage,
1816
- getVercelRSCMessage as unstable_getVercelRSCMessage,
1849
+ useComposerContext as unstable_useComposerContext,
1850
+ useContentPartContext as unstable_useContentPartContext,
1817
1851
  useLocalRuntime as unstable_useLocalRuntime,
1818
1852
  useMessageContext as unstable_useMessageContext,
1853
+ useThreadContext as unstable_useThreadContext,
1819
1854
  useBeginMessageEdit,
1820
1855
  useCopyMessage,
1821
1856
  useGoToNextBranch,
1822
1857
  useGoToPreviousBranch,
1823
- useReloadMessage
1858
+ useReloadMessage,
1859
+ useVercelRSCRuntime,
1860
+ useVercelUseAssistantRuntime,
1861
+ useVercelUseChatRuntime
1824
1862
  };