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