@assistant-ui/react 0.0.19 → 0.0.21

Sign up to get free protection for your applications and to get access to all the features.
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
  };