@assistant-ui/react 0.0.14 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +174 -171
  2. package/dist/index.mjs +176 -172
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -75,7 +75,7 @@ var useAssistantContext = () => {
75
75
  const context = (0, import_react2.useContext)(AssistantContext);
76
76
  if (!context)
77
77
  throw new Error(
78
- "This component must be used within a AssistantProvider"
78
+ "This component must be used within a AssistantProvider."
79
79
  );
80
80
  return context;
81
81
  };
@@ -84,14 +84,10 @@ var useAssistantContext = () => {
84
84
  var useThreadIf = (props) => {
85
85
  const { useThread } = useAssistantContext();
86
86
  return useThread((thread) => {
87
- if (props.empty === true && thread.messages.length !== 0)
88
- return false;
89
- if (props.empty === false && thread.messages.length === 0)
90
- return false;
91
- if (props.running === true && !thread.isRunning)
92
- return false;
93
- if (props.running === false && thread.isRunning)
94
- return false;
87
+ if (props.empty === true && thread.messages.length !== 0) return false;
88
+ if (props.empty === false && thread.messages.length === 0) return false;
89
+ if (props.running === true && !thread.isRunning) return false;
90
+ if (props.running === false && thread.isRunning) return false;
95
91
  return true;
96
92
  });
97
93
  };
@@ -119,8 +115,7 @@ var useOnResizeContent = (ref, callback) => {
119
115
  callbackRef.current = callback;
120
116
  (0, import_react3.useLayoutEffect)(() => {
121
117
  const el = ref.current;
122
- if (!el)
123
- return;
118
+ if (!el) return;
124
119
  const resizeObserver = new ResizeObserver(() => {
125
120
  callbackRef.current();
126
121
  });
@@ -175,16 +170,14 @@ var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScrol
175
170
  const lastScrollTop = (0, import_react5.useRef)(0);
176
171
  const scrollToBottom = () => {
177
172
  const div = messagesEndRef.current;
178
- if (!div || !autoScroll)
179
- return;
173
+ if (!div || !autoScroll) return;
180
174
  const behavior = firstRenderRef.current ? "instant" : "auto";
181
175
  firstRenderRef.current = false;
182
176
  useViewport.setState({ isAtBottom: true });
183
177
  div.scrollIntoView({ behavior });
184
178
  };
185
179
  useOnResizeContent(divRef, () => {
186
- if (!useViewport.getState().isAtBottom)
187
- return;
180
+ if (!useViewport.getState().isAtBottom) return;
188
181
  scrollToBottom();
189
182
  });
190
183
  useOnScrollToBottom(() => {
@@ -192,8 +185,7 @@ var ThreadViewport = (0, import_react5.forwardRef)(({ autoScroll = true, onScrol
192
185
  });
193
186
  const handleScroll = () => {
194
187
  const div = divRef.current;
195
- if (!div)
196
- return;
188
+ if (!div) return;
197
189
  const isAtBottom = useViewport.getState().isAtBottom;
198
190
  const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
199
191
  if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
@@ -225,7 +217,7 @@ var MessageContext = (0, import_react6.createContext)(null);
225
217
  var useMessageContext = () => {
226
218
  const context = (0, import_react6.useContext)(MessageContext);
227
219
  if (!context)
228
- throw new Error("This component must be used within a MessageProvider");
220
+ throw new Error("This component must be used within a MessageProvider.");
229
221
  return context;
230
222
  };
231
223
 
@@ -243,10 +235,8 @@ var useComposerContext = () => {
243
235
  var useComposerIf = (props) => {
244
236
  const { useComposer } = useComposerContext();
245
237
  return useComposer((composer) => {
246
- if (props.editing === true && !composer.isEditing)
247
- return false;
248
- if (props.editing === false && composer.isEditing)
249
- return false;
238
+ if (props.editing === true && !composer.isEditing) return false;
239
+ if (props.editing === false && composer.isEditing) return false;
250
240
  return true;
251
241
  });
252
242
  };
@@ -268,6 +258,14 @@ __export(message_exports, {
268
258
  var import_react8 = require("react");
269
259
  var import_zustand2 = require("zustand");
270
260
 
261
+ // src/utils/context/getMessageText.tsx
262
+ var getMessageText = (message) => {
263
+ const textParts = message.content.filter(
264
+ (part) => part.type === "text"
265
+ );
266
+ return textParts.map((part) => part.text).join("\n\n");
267
+ };
268
+
271
269
  // src/utils/context/stores/ComposerStore.ts
272
270
  var import_zustand = require("zustand");
273
271
  var makeBaseComposer = (set) => ({
@@ -292,8 +290,7 @@ var makeMessageComposerStore = ({
292
290
  onSend(value);
293
291
  },
294
292
  cancel: () => {
295
- if (!get().isEditing)
296
- return false;
293
+ if (!get().isEditing) return false;
297
294
  set({ isEditing: false });
298
295
  return true;
299
296
  }
@@ -312,8 +309,7 @@ var makeThreadComposerStore = (useThread) => (0, import_zustand.create)()((set,
312
309
  },
313
310
  cancel: () => {
314
311
  const thread = useThread.getState();
315
- if (!thread.isRunning)
316
- return false;
312
+ if (!thread.isRunning) return false;
317
313
  useThread.getState().cancelRun();
318
314
  return true;
319
315
  }
@@ -328,30 +324,36 @@ var getIsLast = (thread, message) => {
328
324
  var useMessageContext2 = () => {
329
325
  const { useThread } = useAssistantContext();
330
326
  const [context] = (0, import_react8.useState)(() => {
331
- const useMessage = (0, import_zustand2.create)(() => ({
327
+ const useMessage = (0, import_zustand2.create)((set) => ({
332
328
  message: null,
333
329
  parentId: null,
334
330
  branches: [],
335
331
  isLast: false,
336
332
  isCopied: false,
337
333
  isHovering: false,
338
- setIsCopied: () => {
334
+ setIsCopied: (value) => {
335
+ set({ isCopied: value });
339
336
  },
340
- setIsHovering: () => {
337
+ setIsHovering: (value) => {
338
+ set({ isHovering: value });
341
339
  }
342
340
  }));
343
341
  const useComposer = makeMessageComposerStore({
344
342
  onEdit: () => {
345
343
  const message = useMessage.getState().message;
346
344
  if (message.role !== "user")
347
- throw new Error("Editing is only supported for user messages");
348
- const text = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
345
+ throw new Error(
346
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
347
+ );
348
+ const text = getMessageText(message);
349
349
  return text;
350
350
  },
351
351
  onSend: (text) => {
352
352
  const { message, parentId } = useMessage.getState();
353
353
  if (message.role !== "user")
354
- throw new Error("Editing is only supported for user messages");
354
+ throw new Error(
355
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
356
+ );
355
357
  const nonTextParts = message.content.filter(
356
358
  (part) => part.type !== "text" && part.type !== "ui"
357
359
  );
@@ -374,23 +376,14 @@ var MessageProvider = ({
374
376
  const context = useMessageContext2();
375
377
  const isLast = useThread((thread) => getIsLast(thread, message));
376
378
  const branches = useThread((thread) => thread.getBranches(message.id));
377
- const [isCopied, setIsCopied] = (0, import_react8.useState)(false);
378
- const [isHovering, setIsHovering] = (0, import_react8.useState)(false);
379
379
  (0, import_react8.useMemo)(() => {
380
- context.useMessage.setState(
381
- {
382
- message,
383
- parentId,
384
- branches,
385
- isLast,
386
- isCopied,
387
- isHovering,
388
- setIsCopied,
389
- setIsHovering
390
- },
391
- true
392
- );
393
- }, [context, message, parentId, branches, isLast, isCopied, isHovering]);
380
+ context.useMessage.setState({
381
+ message,
382
+ parentId,
383
+ branches,
384
+ isLast
385
+ });
386
+ }, [context, message, parentId, branches, isLast]);
394
387
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MessageContext.Provider, { value: context, children });
395
388
  };
396
389
 
@@ -425,18 +418,12 @@ var MessageRoot = (0, import_react9.forwardRef)(
425
418
  var useMessageIf = (props) => {
426
419
  const { useMessage } = useMessageContext();
427
420
  return useMessage(({ message, branches, isLast, isCopied, isHovering }) => {
428
- if (props.hasBranches === true && branches.length < 2)
429
- return false;
430
- if (props.user && message.role !== "user")
431
- return false;
432
- if (props.assistant && message.role !== "assistant")
433
- return false;
434
- if (props.lastOrHover === true && !isHovering && !isLast)
435
- return false;
436
- if (props.copied === true && !isCopied)
437
- return false;
438
- if (props.copied === false && isCopied)
439
- return false;
421
+ if (props.hasBranches === true && branches.length < 2) return false;
422
+ if (props.user && message.role !== "user") return false;
423
+ if (props.assistant && message.role !== "assistant") return false;
424
+ if (props.lastOrHover === true && !isHovering && !isLast) return false;
425
+ if (props.copied === true && !isCopied) return false;
426
+ if (props.copied === false && isCopied) return false;
440
427
  return true;
441
428
  });
442
429
  };
@@ -498,8 +485,7 @@ var ThreadMessages = ({ components }) => {
498
485
  const thread = useThread();
499
486
  const messages = thread.messages;
500
487
  const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
501
- if (messages.length === 0)
502
- return null;
488
+ if (messages.length === 0) return null;
503
489
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: messages.map((message, idx) => {
504
490
  const parentId = messages[idx - 1]?.id ?? null;
505
491
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
@@ -593,8 +579,7 @@ var ComposerRoot = (0, import_react12.forwardRef)(
593
579
  const ref = (0, import_react_compose_refs2.useComposedRefs)(forwardedRef, formRef);
594
580
  const handleSubmit = (e) => {
595
581
  const composerState = useComposer.getState();
596
- if (!composerState.isEditing)
597
- return;
582
+ if (!composerState.isEditing) return;
598
583
  e.preventDefault();
599
584
  composerState.send();
600
585
  useViewport.getState().scrollToBottom();
@@ -622,14 +607,12 @@ var ComposerInput = (0, import_react13.forwardRef)(
622
607
  const { useThread, useViewport } = useAssistantContext();
623
608
  const { useComposer, type } = useComposerContext();
624
609
  const value = useComposer((c) => {
625
- if (!c.isEditing)
626
- return "";
610
+ if (!c.isEditing) return "";
627
611
  return c.value;
628
612
  });
629
613
  const Component = asChild ? import_react_slot.Slot : import_react_textarea_autosize.default;
630
614
  const handleKeyPress = (e) => {
631
- if (disabled)
632
- return;
615
+ if (disabled) return;
633
616
  const composer = useComposer.getState();
634
617
  if (e.key === "Escape") {
635
618
  if (useComposer.getState().cancel()) {
@@ -649,8 +632,7 @@ var ComposerInput = (0, import_react13.forwardRef)(
649
632
  const autoFocusEnabled = autoFocus && !disabled;
650
633
  const focus = (0, import_react13.useCallback)(() => {
651
634
  const textarea = textareaRef.current;
652
- if (!textarea || !autoFocusEnabled)
653
- return;
635
+ if (!textarea || !autoFocusEnabled) return;
654
636
  textarea.focus();
655
637
  textarea.setSelectionRange(
656
638
  textareaRef.current.value.length,
@@ -672,8 +654,7 @@ var ComposerInput = (0, import_react13.forwardRef)(
672
654
  disabled,
673
655
  onChange: (0, import_primitive6.composeEventHandlers)(onChange, (e) => {
674
656
  const composerState = useComposer.getState();
675
- if (!composerState.isEditing)
676
- return;
657
+ if (!composerState.isEditing) return;
677
658
  return composerState.setValue(e.target.value);
678
659
  }),
679
660
  onKeyDown: (0, import_primitive6.composeEventHandlers)(onKeyDown, handleKeyPress)
@@ -767,8 +748,7 @@ var useGoToNextBranch = () => {
767
748
  [useMessage, useComposer],
768
749
  (m, c) => c.isEditing || m.branches.indexOf(m.message.id) + 1 >= m.branches.length
769
750
  );
770
- if (disabled)
771
- return null;
751
+ if (disabled) return null;
772
752
  return () => {
773
753
  const { message, branches } = useMessage.getState();
774
754
  useThread.getState().switchToBranch(branches[branches.indexOf(message.id) + 1]);
@@ -809,8 +789,7 @@ var useGoToPreviousBranch = () => {
809
789
  [useMessage, useComposer],
810
790
  (m, c) => c.isEditing || m.branches.indexOf(m.message.id) <= 0
811
791
  );
812
- if (disabled)
813
- return null;
792
+ if (disabled) return null;
814
793
  return () => {
815
794
  const { message, branches } = useMessage.getState();
816
795
  useThread.getState().switchToBranch(
@@ -866,20 +845,16 @@ var ActionBarRoot = (0, import_react20.forwardRef)(({ hideWhenRunning, autohide,
866
845
  const hideAndfloatStatus = useCombinedStore(
867
846
  [useThread, useMessage],
868
847
  (t, m) => {
869
- if (hideWhenRunning && t.isRunning)
870
- return "hidden" /* Hidden */;
848
+ if (hideWhenRunning && t.isRunning) return "hidden" /* Hidden */;
871
849
  const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
872
- if (!autohideEnabled)
873
- return "normal" /* Normal */;
874
- if (!m.isHovering)
875
- return "hidden" /* Hidden */;
850
+ if (!autohideEnabled) return "normal" /* Normal */;
851
+ if (!m.isHovering) return "hidden" /* Hidden */;
876
852
  if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
877
853
  return "floating" /* Floating */;
878
854
  return "normal" /* Normal */;
879
855
  }
880
856
  );
881
- if (hideAndfloatStatus === "hidden" /* Hidden */)
882
- return null;
857
+ if (hideAndfloatStatus === "hidden" /* Hidden */) return null;
883
858
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
884
859
  import_react_primitive11.Primitive.div,
885
860
  {
@@ -893,14 +868,18 @@ var ActionBarRoot = (0, import_react20.forwardRef)(({ hideWhenRunning, autohide,
893
868
  // src/actions/useCopyMessage.tsx
894
869
  var useCopyMessage = ({ copiedDuration = 3e3 }) => {
895
870
  const { useMessage, useComposer } = useMessageContext();
896
- const isEditing = useComposer((s) => s.isEditing);
897
- if (isEditing)
898
- return null;
871
+ const hasCopyableContent = useCombinedStore(
872
+ [useMessage, useComposer],
873
+ (m, c) => {
874
+ return c.isEditing || m.message.content.some((c2) => c2.type === "text");
875
+ }
876
+ );
877
+ if (!hasCopyableContent) return null;
899
878
  return () => {
879
+ const { isEditing, value: composerValue } = useComposer.getState();
900
880
  const { message, setIsCopied } = useMessage.getState();
901
- if (message.content[0]?.type !== "text")
902
- throw new Error("Copying is only supported for text-only messages");
903
- navigator.clipboard.writeText(message.content[0].text);
881
+ const valueToCopy = isEditing ? composerValue : getMessageText(message);
882
+ navigator.clipboard.writeText(valueToCopy);
904
883
  setIsCopied(true);
905
884
  setTimeout(() => setIsCopied(false), copiedDuration);
906
885
  };
@@ -917,12 +896,9 @@ var useReloadMessage = () => {
917
896
  [useThread, useMessage],
918
897
  (t, m) => t.isRunning || m.message.role !== "assistant"
919
898
  );
920
- if (disabled)
921
- return null;
899
+ if (disabled) return null;
922
900
  return () => {
923
- const { message, parentId } = useMessage.getState();
924
- if (message.role !== "assistant")
925
- throw new Error("Reloading is only supported on assistant messages");
901
+ const { parentId } = useMessage.getState();
926
902
  useThread.getState().startRun(parentId);
927
903
  useViewport.getState().scrollToBottom();
928
904
  };
@@ -938,8 +914,7 @@ var useBeginMessageEdit = () => {
938
914
  [useMessage, useComposer],
939
915
  (m, c) => m.message.role !== "user" || c.isEditing
940
916
  );
941
- if (disabled)
942
- return null;
917
+ if (disabled) return null;
943
918
  return () => {
944
919
  const { edit } = useComposer.getState();
945
920
  edit();
@@ -987,13 +962,13 @@ var makeDummyThreadStore = () => {
987
962
  switchToBranch: () => {
988
963
  throw new Error("Not implemented");
989
964
  },
990
- append: async () => {
965
+ append: () => {
991
966
  throw new Error("Not implemented");
992
967
  },
993
- cancelRun: () => {
968
+ startRun: () => {
994
969
  throw new Error("Not implemented");
995
970
  },
996
- startRun: async () => {
971
+ cancelRun: () => {
997
972
  throw new Error("Not implemented");
998
973
  }
999
974
  }));
@@ -1021,8 +996,7 @@ var optimisticPrefix = "__optimistic__";
1021
996
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1022
997
  var isOptimisticId = (id) => id.startsWith(optimisticPrefix);
1023
998
  var findHead = (message) => {
1024
- if (message.next)
1025
- return findHead(message.next);
999
+ if (message.next) return findHead(message.next);
1026
1000
  return message;
1027
1001
  };
1028
1002
  var MessageRepository = class {
@@ -1037,28 +1011,21 @@ var MessageRepository = class {
1037
1011
  }
1038
1012
  return messages;
1039
1013
  }
1040
- // TODO previousId is confusing
1041
- // TODO previousId does not fix children
1042
- // TODO cut / link operations
1043
- addOrUpdateMessage(parentId, message, previousId = message.id) {
1014
+ addOrUpdateMessage(parentId, message) {
1044
1015
  const item = this.messages.get(message.id);
1045
1016
  if (item) {
1046
- if (item.prev?.current.id !== parentId) {
1047
- if ((item.prev?.current.id ?? null) !== parentId) {
1048
- this.deleteMessage(message.id);
1049
- } else {
1050
- item.current = message;
1051
- if (previousId !== message.id) {
1052
- this.messages.delete(previousId);
1053
- this.messages.set(message.id, item);
1054
- }
1055
- return;
1056
- }
1017
+ if ((item.prev?.current.id ?? null) !== parentId) {
1018
+ this.deleteMessage(message.id);
1019
+ } else {
1020
+ item.current = message;
1021
+ return;
1057
1022
  }
1058
1023
  }
1059
1024
  const prev = parentId ? this.messages.get(parentId) : null;
1060
1025
  if (prev === void 0)
1061
- throw new Error("Unexpected: Parent message not found");
1026
+ throw new Error(
1027
+ "MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui."
1028
+ );
1062
1029
  const newItem = {
1063
1030
  prev,
1064
1031
  current: message,
@@ -1080,7 +1047,9 @@ var MessageRepository = class {
1080
1047
  deleteMessage(messageId) {
1081
1048
  const message = this.messages.get(messageId);
1082
1049
  if (!message)
1083
- throw new Error("Unexpected: Message not found");
1050
+ throw new Error(
1051
+ "MessageRepository(deleteMessage): Message not found. This is likely an internal bug in assistant-ui."
1052
+ );
1084
1053
  if (message.children.length > 0) {
1085
1054
  for (const child of message.children) {
1086
1055
  this.deleteMessage(child);
@@ -1095,7 +1064,9 @@ var MessageRepository = class {
1095
1064
  const childId = message.prev.children.at(-1);
1096
1065
  const child = childId ? this.messages.get(childId) : null;
1097
1066
  if (child === void 0)
1098
- throw new Error("Unexpected: Child message not found");
1067
+ throw new Error(
1068
+ "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
1069
+ );
1099
1070
  message.prev.next = child;
1100
1071
  }
1101
1072
  } else {
@@ -1112,17 +1083,6 @@ var MessageRepository = class {
1112
1083
  } while (this.messages.has(optimisticId));
1113
1084
  return optimisticId;
1114
1085
  }
1115
- commitOptimisticAppend(message) {
1116
- const optimisticIdUser = this.getOptimisticId();
1117
- this.addOrUpdateMessage(message.parentId, {
1118
- id: optimisticIdUser,
1119
- role: "user",
1120
- content: message.content,
1121
- createdAt: /* @__PURE__ */ new Date()
1122
- });
1123
- const optimisticIdAssistant = this.commitOptimisticRun(optimisticIdUser);
1124
- return [optimisticIdUser, optimisticIdAssistant];
1125
- }
1126
1086
  commitOptimisticRun(parentId) {
1127
1087
  const optimisticId = this.getOptimisticId();
1128
1088
  this.addOrUpdateMessage(parentId, {
@@ -1141,7 +1101,9 @@ var MessageRepository = class {
1141
1101
  getBranches(messageId) {
1142
1102
  const message = this.messages.get(messageId);
1143
1103
  if (!message)
1144
- throw new Error("Unexpected: Message not found");
1104
+ throw new Error(
1105
+ "MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui."
1106
+ );
1145
1107
  if (message.prev) {
1146
1108
  return message.prev.children;
1147
1109
  }
@@ -1150,7 +1112,9 @@ var MessageRepository = class {
1150
1112
  switchToBranch(messageId) {
1151
1113
  const message = this.messages.get(messageId);
1152
1114
  if (!message)
1153
- throw new Error("Unexpected: Branch not found");
1115
+ throw new Error(
1116
+ "MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui."
1117
+ );
1154
1118
  if (message.prev) {
1155
1119
  message.prev.next = message;
1156
1120
  }
@@ -1160,7 +1124,9 @@ var MessageRepository = class {
1160
1124
  if (messageId) {
1161
1125
  const message = this.messages.get(messageId);
1162
1126
  if (!message)
1163
- throw new Error("Unexpected: Branch not found");
1127
+ throw new Error(
1128
+ "MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui."
1129
+ );
1164
1130
  this.head = message;
1165
1131
  for (let current = message; current; current = current.prev) {
1166
1132
  if (current.prev) {
@@ -1182,8 +1148,7 @@ var ThreadMessageConverter = class {
1182
1148
  convertMessages(messages) {
1183
1149
  return messages.map((m) => {
1184
1150
  const cached = this.cache.get(m);
1185
- if (cached)
1186
- return cached;
1151
+ if (cached) return cached;
1187
1152
  const newMessage = this.converter(m);
1188
1153
  this.cache.set(m, newMessage);
1189
1154
  return newMessage;
@@ -1194,32 +1159,42 @@ var ThreadMessageConverter = class {
1194
1159
  // src/adapters/vercel/useVercelAIThreadState.tsx
1195
1160
  var vercelToThreadMessage = (message) => {
1196
1161
  if (message.role !== "user" && message.role !== "assistant")
1197
- throw new Error("Unsupported role");
1162
+ throw new Error(
1163
+ `You have a message with an unsupported role. The role ${message.role} is not supported.`
1164
+ );
1198
1165
  return {
1199
1166
  id: message.id,
1200
1167
  role: message.role,
1201
- content: [{ type: "text", text: message.content }],
1168
+ content: [
1169
+ ...message.content ? [{ type: "text", text: message.content }] : [],
1170
+ ...message.toolInvocations?.map((t) => ({
1171
+ type: "tool-call",
1172
+ name: t.toolName,
1173
+ args: t.args,
1174
+ result: "result" in t ? t.result : void 0
1175
+ })) ?? []
1176
+ ],
1177
+ // ignore type mismatch for now
1202
1178
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1203
1179
  innerMessage: message
1204
1180
  };
1205
1181
  };
1206
1182
  var converter = new ThreadMessageConverter(vercelToThreadMessage);
1207
1183
  var sliceMessagesUntil = (messages, messageId) => {
1208
- if (messageId == null)
1209
- return [];
1210
- if (isOptimisticId(messageId))
1211
- return messages;
1184
+ if (messageId == null) return [];
1185
+ if (isOptimisticId(messageId)) return messages;
1212
1186
  const messageIdx = messages.findIndex((m) => m.id === messageId);
1213
1187
  if (messageIdx === -1)
1214
- throw new Error("Unexpected: Message not found");
1188
+ throw new Error(
1189
+ "useVercelAIThreadState: Message not found. This is liekly an internal bug in assistant-ui."
1190
+ );
1215
1191
  return messages.slice(0, messageIdx + 1);
1216
1192
  };
1217
1193
  var hasUpcomingMessage = (isRunning, messages) => {
1218
1194
  return isRunning && messages[messages.length - 1]?.role !== "assistant";
1219
1195
  };
1220
1196
  var getIsRunning = (vercel) => {
1221
- if ("isLoading" in vercel)
1222
- return vercel.isLoading;
1197
+ if ("isLoading" in vercel) return vercel.isLoading;
1223
1198
  return vercel.status === "in_progress";
1224
1199
  };
1225
1200
  var useVercelAIThreadState = (vercel) => {
@@ -1247,13 +1222,13 @@ var useVercelAIThreadState = (vercel) => {
1247
1222
  data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
1248
1223
  return data.getMessages();
1249
1224
  }, [data, isRunning, vercel.messages]);
1250
- const getBranches = (0, import_react22.useCallback)(
1225
+ const getBranches2 = (0, import_react22.useCallback)(
1251
1226
  (messageId) => {
1252
1227
  return data.getBranches(messageId);
1253
1228
  },
1254
1229
  [data]
1255
1230
  );
1256
- const switchToBranch = (0, import_react22.useCallback)(
1231
+ const switchToBranch2 = (0, import_react22.useCallback)(
1257
1232
  (messageId) => {
1258
1233
  data.switchToBranch(messageId);
1259
1234
  vercelRef.current.setMessages(
@@ -1265,7 +1240,9 @@ var useVercelAIThreadState = (vercel) => {
1265
1240
  const startRun = (0, import_react22.useCallback)(async (parentId) => {
1266
1241
  const reloadMaybe = "reload" in vercelRef.current ? vercelRef.current.reload : void 0;
1267
1242
  if (!reloadMaybe)
1268
- throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
1243
+ throw new Error(
1244
+ "Reload is not supported by Vercel AI SDK's useAssistant."
1245
+ );
1269
1246
  const newMessages = sliceMessagesUntil(
1270
1247
  vercelRef.current.messages,
1271
1248
  parentId
@@ -1275,7 +1252,7 @@ var useVercelAIThreadState = (vercel) => {
1275
1252
  }, []);
1276
1253
  const append = (0, import_react22.useCallback)(async (message) => {
1277
1254
  if (message.content.length !== 1 || message.content[0]?.type !== "text")
1278
- throw new Error("Only text content is supported by Vercel AI SDK");
1255
+ throw new Error("Only text content is supported by Vercel AI SDK.");
1279
1256
  const newMessages = sliceMessagesUntil(
1280
1257
  vercelRef.current.messages,
1281
1258
  message.parentId
@@ -1286,7 +1263,7 @@ var useVercelAIThreadState = (vercel) => {
1286
1263
  content: message.content[0].text
1287
1264
  });
1288
1265
  }, []);
1289
- const cancelRun = (0, import_react22.useCallback)(() => {
1266
+ const cancelRun2 = (0, import_react22.useCallback)(() => {
1290
1267
  const lastMessage = vercelRef.current.messages.at(-1);
1291
1268
  vercelRef.current.stop();
1292
1269
  if (lastMessage?.role === "user") {
@@ -1297,20 +1274,20 @@ var useVercelAIThreadState = (vercel) => {
1297
1274
  () => ({
1298
1275
  isRunning,
1299
1276
  messages,
1300
- getBranches,
1301
- switchToBranch,
1277
+ getBranches: getBranches2,
1278
+ switchToBranch: switchToBranch2,
1302
1279
  append,
1303
1280
  startRun,
1304
- cancelRun
1281
+ cancelRun: cancelRun2
1305
1282
  }),
1306
1283
  [
1307
1284
  isRunning,
1308
1285
  messages,
1309
- getBranches,
1310
- switchToBranch,
1286
+ getBranches2,
1287
+ switchToBranch2,
1311
1288
  append,
1312
1289
  startRun,
1313
- cancelRun
1290
+ cancelRun2
1314
1291
  ]
1315
1292
  );
1316
1293
  };
@@ -1340,8 +1317,6 @@ var VercelAIAssistantProvider = ({
1340
1317
  var import_react24 = require("react");
1341
1318
  var import_jsx_runtime20 = require("react/jsx-runtime");
1342
1319
  var vercelToThreadMessage2 = (message) => {
1343
- if (message.role !== "user" && message.role !== "assistant")
1344
- throw new Error("Unsupported role");
1345
1320
  return {
1346
1321
  id: message.id,
1347
1322
  role: message.role,
@@ -1349,6 +1324,22 @@ var vercelToThreadMessage2 = (message) => {
1349
1324
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
1350
1325
  };
1351
1326
  };
1327
+ var EMPTY_BRANCHES = [];
1328
+ var getBranches = () => {
1329
+ return EMPTY_BRANCHES;
1330
+ };
1331
+ var switchToBranch = () => {
1332
+ throw new Error(
1333
+ "Branch switching is not supported by VercelRSCAssistantProvider."
1334
+ );
1335
+ };
1336
+ var cancelRun = () => {
1337
+ if (process.env["NODE_ENV"] === "development") {
1338
+ console.warn(
1339
+ "Run cancellation is not supported by VercelRSCAssistantProvider."
1340
+ );
1341
+ }
1342
+ };
1352
1343
  var VercelRSCAssistantProvider = ({
1353
1344
  children,
1354
1345
  convertMessage,
@@ -1358,6 +1349,11 @@ var VercelRSCAssistantProvider = ({
1358
1349
  reload
1359
1350
  }) => {
1360
1351
  const context = useDummyAIAssistantContext();
1352
+ const [isRunning, setIsRunning] = (0, import_react24.useState)(false);
1353
+ const withRunning = (0, import_react24.useCallback)((callback) => {
1354
+ setIsRunning(true);
1355
+ return callback.finally(() => setIsRunning(false));
1356
+ }, []);
1361
1357
  const converter2 = (0, import_react24.useMemo)(() => {
1362
1358
  const rscConverter = convertMessage ?? ((m) => m);
1363
1359
  return new ThreadMessageConverter((m) => {
@@ -1372,32 +1368,39 @@ var VercelRSCAssistantProvider = ({
1372
1368
  if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
1373
1369
  if (!edit)
1374
1370
  throw new Error(
1375
- "Unexpected: Message editing is not supported, no edit callback was provided to VercelRSCAssistantProvider."
1371
+ "Message editing is not enabled, please provide an edit callback to VercelRSCAssistantProvider."
1376
1372
  );
1377
- await edit(message);
1373
+ await withRunning(edit(message));
1378
1374
  } else {
1379
- await appendCallback(message);
1375
+ await withRunning(appendCallback(message));
1380
1376
  }
1381
1377
  },
1382
- [context, appendCallback, edit]
1378
+ [context, withRunning, appendCallback, edit]
1383
1379
  );
1384
1380
  const startRun = (0, import_react24.useCallback)(
1385
1381
  async (parentId) => {
1386
1382
  if (!reload)
1387
1383
  throw new Error(
1388
- "Unexpected: Message reloading is not supported, no reload callback was provided to VercelRSCAssistantProvider."
1384
+ "Message reloading is not enabled, please provide a reload callback to VercelRSCAssistantProvider."
1389
1385
  );
1390
- await reload(parentId);
1386
+ await withRunning(reload(parentId));
1391
1387
  },
1392
- [reload]
1388
+ [withRunning, reload]
1393
1389
  );
1394
1390
  (0, import_react24.useMemo)(() => {
1395
- context.useThread.setState({
1396
- messages,
1397
- append,
1398
- startRun
1399
- });
1400
- }, [context, messages, append, startRun]);
1391
+ context.useThread.setState(
1392
+ {
1393
+ messages,
1394
+ isRunning,
1395
+ getBranches,
1396
+ switchToBranch,
1397
+ append,
1398
+ startRun,
1399
+ cancelRun
1400
+ },
1401
+ true
1402
+ );
1403
+ }, [context, messages, isRunning, append, startRun]);
1401
1404
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AssistantContext.Provider, { value: context, children });
1402
1405
  };
1403
1406
  // Annotate the CommonJS export names for ESM import in node: