@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.mjs CHANGED
@@ -35,7 +35,7 @@ var useAssistantContext = () => {
35
35
  const context = useContext(AssistantContext);
36
36
  if (!context)
37
37
  throw new Error(
38
- "This component must be used within a AssistantProvider"
38
+ "This component must be used within a AssistantProvider."
39
39
  );
40
40
  return context;
41
41
  };
@@ -44,14 +44,10 @@ var useAssistantContext = () => {
44
44
  var useThreadIf = (props) => {
45
45
  const { useThread } = useAssistantContext();
46
46
  return useThread((thread) => {
47
- if (props.empty === true && thread.messages.length !== 0)
48
- return false;
49
- if (props.empty === false && thread.messages.length === 0)
50
- return false;
51
- if (props.running === true && !thread.isRunning)
52
- return false;
53
- if (props.running === false && thread.isRunning)
54
- return false;
47
+ if (props.empty === true && thread.messages.length !== 0) return false;
48
+ if (props.empty === false && thread.messages.length === 0) return false;
49
+ if (props.running === true && !thread.isRunning) return false;
50
+ if (props.running === false && thread.isRunning) return false;
55
51
  return true;
56
52
  });
57
53
  };
@@ -81,8 +77,7 @@ var useOnResizeContent = (ref, callback) => {
81
77
  callbackRef.current = callback;
82
78
  useLayoutEffect(() => {
83
79
  const el = ref.current;
84
- if (!el)
85
- return;
80
+ if (!el) return;
86
81
  const resizeObserver = new ResizeObserver(() => {
87
82
  callbackRef.current();
88
83
  });
@@ -137,16 +132,14 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re
137
132
  const lastScrollTop = useRef3(0);
138
133
  const scrollToBottom = () => {
139
134
  const div = messagesEndRef.current;
140
- if (!div || !autoScroll)
141
- return;
135
+ if (!div || !autoScroll) return;
142
136
  const behavior = firstRenderRef.current ? "instant" : "auto";
143
137
  firstRenderRef.current = false;
144
138
  useViewport.setState({ isAtBottom: true });
145
139
  div.scrollIntoView({ behavior });
146
140
  };
147
141
  useOnResizeContent(divRef, () => {
148
- if (!useViewport.getState().isAtBottom)
149
- return;
142
+ if (!useViewport.getState().isAtBottom) return;
150
143
  scrollToBottom();
151
144
  });
152
145
  useOnScrollToBottom(() => {
@@ -154,8 +147,7 @@ var ThreadViewport = forwardRef2(({ autoScroll = true, onScroll, children, ...re
154
147
  });
155
148
  const handleScroll = () => {
156
149
  const div = divRef.current;
157
- if (!div)
158
- return;
150
+ if (!div) return;
159
151
  const isAtBottom = useViewport.getState().isAtBottom;
160
152
  const newIsAtBottom = div.scrollHeight - div.scrollTop <= div.clientHeight;
161
153
  if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {
@@ -187,7 +179,7 @@ var MessageContext = createContext2(null);
187
179
  var useMessageContext = () => {
188
180
  const context = useContext2(MessageContext);
189
181
  if (!context)
190
- throw new Error("This component must be used within a MessageProvider");
182
+ throw new Error("This component must be used within a MessageProvider.");
191
183
  return context;
192
184
  };
193
185
 
@@ -205,10 +197,8 @@ var useComposerContext = () => {
205
197
  var useComposerIf = (props) => {
206
198
  const { useComposer } = useComposerContext();
207
199
  return useComposer((composer) => {
208
- if (props.editing === true && !composer.isEditing)
209
- return false;
210
- if (props.editing === false && composer.isEditing)
211
- return false;
200
+ if (props.editing === true && !composer.isEditing) return false;
201
+ if (props.editing === false && composer.isEditing) return false;
212
202
  return true;
213
203
  });
214
204
  };
@@ -230,6 +220,14 @@ __export(message_exports, {
230
220
  import { useMemo, useState } from "react";
231
221
  import { create as create2 } from "zustand";
232
222
 
223
+ // src/utils/context/getMessageText.tsx
224
+ var getMessageText = (message) => {
225
+ const textParts = message.content.filter(
226
+ (part) => part.type === "text"
227
+ );
228
+ return textParts.map((part) => part.text).join("\n\n");
229
+ };
230
+
233
231
  // src/utils/context/stores/ComposerStore.ts
234
232
  import {
235
233
  create
@@ -256,8 +254,7 @@ var makeMessageComposerStore = ({
256
254
  onSend(value);
257
255
  },
258
256
  cancel: () => {
259
- if (!get().isEditing)
260
- return false;
257
+ if (!get().isEditing) return false;
261
258
  set({ isEditing: false });
262
259
  return true;
263
260
  }
@@ -276,8 +273,7 @@ var makeThreadComposerStore = (useThread) => create()((set, get, store) => {
276
273
  },
277
274
  cancel: () => {
278
275
  const thread = useThread.getState();
279
- if (!thread.isRunning)
280
- return false;
276
+ if (!thread.isRunning) return false;
281
277
  useThread.getState().cancelRun();
282
278
  return true;
283
279
  }
@@ -292,30 +288,36 @@ var getIsLast = (thread, message) => {
292
288
  var useMessageContext2 = () => {
293
289
  const { useThread } = useAssistantContext();
294
290
  const [context] = useState(() => {
295
- const useMessage = create2(() => ({
291
+ const useMessage = create2((set) => ({
296
292
  message: null,
297
293
  parentId: null,
298
294
  branches: [],
299
295
  isLast: false,
300
296
  isCopied: false,
301
297
  isHovering: false,
302
- setIsCopied: () => {
298
+ setIsCopied: (value) => {
299
+ set({ isCopied: value });
303
300
  },
304
- setIsHovering: () => {
301
+ setIsHovering: (value) => {
302
+ set({ isHovering: value });
305
303
  }
306
304
  }));
307
305
  const useComposer = makeMessageComposerStore({
308
306
  onEdit: () => {
309
307
  const message = useMessage.getState().message;
310
308
  if (message.role !== "user")
311
- throw new Error("Editing is only supported for user messages");
312
- const text = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
309
+ throw new Error(
310
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
311
+ );
312
+ const text = getMessageText(message);
313
313
  return text;
314
314
  },
315
315
  onSend: (text) => {
316
316
  const { message, parentId } = useMessage.getState();
317
317
  if (message.role !== "user")
318
- throw new Error("Editing is only supported for user messages");
318
+ throw new Error(
319
+ "Tried to edit a non-user message. Editing is only supported for user messages. This is likely an internal bug in assistant-ui."
320
+ );
319
321
  const nonTextParts = message.content.filter(
320
322
  (part) => part.type !== "text" && part.type !== "ui"
321
323
  );
@@ -338,23 +340,14 @@ var MessageProvider = ({
338
340
  const context = useMessageContext2();
339
341
  const isLast = useThread((thread) => getIsLast(thread, message));
340
342
  const branches = useThread((thread) => thread.getBranches(message.id));
341
- const [isCopied, setIsCopied] = useState(false);
342
- const [isHovering, setIsHovering] = useState(false);
343
343
  useMemo(() => {
344
- context.useMessage.setState(
345
- {
346
- message,
347
- parentId,
348
- branches,
349
- isLast,
350
- isCopied,
351
- isHovering,
352
- setIsCopied,
353
- setIsHovering
354
- },
355
- true
356
- );
357
- }, [context, message, parentId, branches, isLast, isCopied, isHovering]);
344
+ context.useMessage.setState({
345
+ message,
346
+ parentId,
347
+ branches,
348
+ isLast
349
+ });
350
+ }, [context, message, parentId, branches, isLast]);
358
351
  return /* @__PURE__ */ jsx4(MessageContext.Provider, { value: context, children });
359
352
  };
360
353
 
@@ -391,18 +384,12 @@ var MessageRoot = forwardRef3(
391
384
  var useMessageIf = (props) => {
392
385
  const { useMessage } = useMessageContext();
393
386
  return useMessage(({ message, branches, isLast, isCopied, isHovering }) => {
394
- if (props.hasBranches === true && branches.length < 2)
395
- return false;
396
- if (props.user && message.role !== "user")
397
- return false;
398
- if (props.assistant && message.role !== "assistant")
399
- return false;
400
- if (props.lastOrHover === true && !isHovering && !isLast)
401
- return false;
402
- if (props.copied === true && !isCopied)
403
- return false;
404
- if (props.copied === false && isCopied)
405
- return false;
387
+ if (props.hasBranches === true && branches.length < 2) return false;
388
+ if (props.user && message.role !== "user") return false;
389
+ if (props.assistant && message.role !== "assistant") return false;
390
+ if (props.lastOrHover === true && !isHovering && !isLast) return false;
391
+ if (props.copied === true && !isCopied) return false;
392
+ if (props.copied === false && isCopied) return false;
406
393
  return true;
407
394
  });
408
395
  };
@@ -464,8 +451,7 @@ var ThreadMessages = ({ components }) => {
464
451
  const thread = useThread();
465
452
  const messages = thread.messages;
466
453
  const { UserMessage, EditComposer, AssistantMessage } = getComponents(components);
467
- if (messages.length === 0)
468
- return null;
454
+ if (messages.length === 0) return null;
469
455
  return /* @__PURE__ */ jsx7(Fragment2, { children: messages.map((message, idx) => {
470
456
  const parentId = messages[idx - 1]?.id ?? null;
471
457
  return /* @__PURE__ */ jsxs2(
@@ -565,8 +551,7 @@ var ComposerRoot = forwardRef6(
565
551
  const ref = useComposedRefs2(forwardedRef, formRef);
566
552
  const handleSubmit = (e) => {
567
553
  const composerState = useComposer.getState();
568
- if (!composerState.isEditing)
569
- return;
554
+ if (!composerState.isEditing) return;
570
555
  e.preventDefault();
571
556
  composerState.send();
572
557
  useViewport.getState().scrollToBottom();
@@ -599,14 +584,12 @@ var ComposerInput = forwardRef7(
599
584
  const { useThread, useViewport } = useAssistantContext();
600
585
  const { useComposer, type } = useComposerContext();
601
586
  const value = useComposer((c) => {
602
- if (!c.isEditing)
603
- return "";
587
+ if (!c.isEditing) return "";
604
588
  return c.value;
605
589
  });
606
590
  const Component = asChild ? Slot : TextareaAutosize;
607
591
  const handleKeyPress = (e) => {
608
- if (disabled)
609
- return;
592
+ if (disabled) return;
610
593
  const composer = useComposer.getState();
611
594
  if (e.key === "Escape") {
612
595
  if (useComposer.getState().cancel()) {
@@ -626,8 +609,7 @@ var ComposerInput = forwardRef7(
626
609
  const autoFocusEnabled = autoFocus && !disabled;
627
610
  const focus = useCallback(() => {
628
611
  const textarea = textareaRef.current;
629
- if (!textarea || !autoFocusEnabled)
630
- return;
612
+ if (!textarea || !autoFocusEnabled) return;
631
613
  textarea.focus();
632
614
  textarea.setSelectionRange(
633
615
  textareaRef.current.value.length,
@@ -649,8 +631,7 @@ var ComposerInput = forwardRef7(
649
631
  disabled,
650
632
  onChange: composeEventHandlers6(onChange, (e) => {
651
633
  const composerState = useComposer.getState();
652
- if (!composerState.isEditing)
653
- return;
634
+ if (!composerState.isEditing) return;
654
635
  return composerState.setValue(e.target.value);
655
636
  }),
656
637
  onKeyDown: composeEventHandlers6(onKeyDown, handleKeyPress)
@@ -748,8 +729,7 @@ var useGoToNextBranch = () => {
748
729
  [useMessage, useComposer],
749
730
  (m, c) => c.isEditing || m.branches.indexOf(m.message.id) + 1 >= m.branches.length
750
731
  );
751
- if (disabled)
752
- return null;
732
+ if (disabled) return null;
753
733
  return () => {
754
734
  const { message, branches } = useMessage.getState();
755
735
  useThread.getState().switchToBranch(branches[branches.indexOf(message.id) + 1]);
@@ -792,8 +772,7 @@ var useGoToPreviousBranch = () => {
792
772
  [useMessage, useComposer],
793
773
  (m, c) => c.isEditing || m.branches.indexOf(m.message.id) <= 0
794
774
  );
795
- if (disabled)
796
- return null;
775
+ if (disabled) return null;
797
776
  return () => {
798
777
  const { message, branches } = useMessage.getState();
799
778
  useThread.getState().switchToBranch(
@@ -853,20 +832,16 @@ var ActionBarRoot = forwardRef12(({ hideWhenRunning, autohide, autohideFloat, ..
853
832
  const hideAndfloatStatus = useCombinedStore(
854
833
  [useThread, useMessage],
855
834
  (t, m) => {
856
- if (hideWhenRunning && t.isRunning)
857
- return "hidden" /* Hidden */;
835
+ if (hideWhenRunning && t.isRunning) return "hidden" /* Hidden */;
858
836
  const autohideEnabled = autohide === "always" || autohide === "not-last" && !m.isLast;
859
- if (!autohideEnabled)
860
- return "normal" /* Normal */;
861
- if (!m.isHovering)
862
- return "hidden" /* Hidden */;
837
+ if (!autohideEnabled) return "normal" /* Normal */;
838
+ if (!m.isHovering) return "hidden" /* Hidden */;
863
839
  if (autohideFloat === "always" || autohideFloat === "single-branch" && m.branches.length <= 1)
864
840
  return "floating" /* Floating */;
865
841
  return "normal" /* Normal */;
866
842
  }
867
843
  );
868
- if (hideAndfloatStatus === "hidden" /* Hidden */)
869
- return null;
844
+ if (hideAndfloatStatus === "hidden" /* Hidden */) return null;
870
845
  return /* @__PURE__ */ jsx18(
871
846
  Primitive11.div,
872
847
  {
@@ -880,14 +855,18 @@ var ActionBarRoot = forwardRef12(({ hideWhenRunning, autohide, autohideFloat, ..
880
855
  // src/actions/useCopyMessage.tsx
881
856
  var useCopyMessage = ({ copiedDuration = 3e3 }) => {
882
857
  const { useMessage, useComposer } = useMessageContext();
883
- const isEditing = useComposer((s) => s.isEditing);
884
- if (isEditing)
885
- return null;
858
+ const hasCopyableContent = useCombinedStore(
859
+ [useMessage, useComposer],
860
+ (m, c) => {
861
+ return c.isEditing || m.message.content.some((c2) => c2.type === "text");
862
+ }
863
+ );
864
+ if (!hasCopyableContent) return null;
886
865
  return () => {
866
+ const { isEditing, value: composerValue } = useComposer.getState();
887
867
  const { message, setIsCopied } = useMessage.getState();
888
- if (message.content[0]?.type !== "text")
889
- throw new Error("Copying is only supported for text-only messages");
890
- navigator.clipboard.writeText(message.content[0].text);
868
+ const valueToCopy = isEditing ? composerValue : getMessageText(message);
869
+ navigator.clipboard.writeText(valueToCopy);
891
870
  setIsCopied(true);
892
871
  setTimeout(() => setIsCopied(false), copiedDuration);
893
872
  };
@@ -904,12 +883,9 @@ var useReloadMessage = () => {
904
883
  [useThread, useMessage],
905
884
  (t, m) => t.isRunning || m.message.role !== "assistant"
906
885
  );
907
- if (disabled)
908
- return null;
886
+ if (disabled) return null;
909
887
  return () => {
910
- const { message, parentId } = useMessage.getState();
911
- if (message.role !== "assistant")
912
- throw new Error("Reloading is only supported on assistant messages");
888
+ const { parentId } = useMessage.getState();
913
889
  useThread.getState().startRun(parentId);
914
890
  useViewport.getState().scrollToBottom();
915
891
  };
@@ -925,8 +901,7 @@ var useBeginMessageEdit = () => {
925
901
  [useMessage, useComposer],
926
902
  (m, c) => m.message.role !== "user" || c.isEditing
927
903
  );
928
- if (disabled)
929
- return null;
904
+ if (disabled) return null;
930
905
  return () => {
931
906
  const { edit } = useComposer.getState();
932
907
  edit();
@@ -974,13 +949,13 @@ var makeDummyThreadStore = () => {
974
949
  switchToBranch: () => {
975
950
  throw new Error("Not implemented");
976
951
  },
977
- append: async () => {
952
+ append: () => {
978
953
  throw new Error("Not implemented");
979
954
  },
980
- cancelRun: () => {
955
+ startRun: () => {
981
956
  throw new Error("Not implemented");
982
957
  },
983
- startRun: async () => {
958
+ cancelRun: () => {
984
959
  throw new Error("Not implemented");
985
960
  }
986
961
  }));
@@ -1008,8 +983,7 @@ var optimisticPrefix = "__optimistic__";
1008
983
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1009
984
  var isOptimisticId = (id) => id.startsWith(optimisticPrefix);
1010
985
  var findHead = (message) => {
1011
- if (message.next)
1012
- return findHead(message.next);
986
+ if (message.next) return findHead(message.next);
1013
987
  return message;
1014
988
  };
1015
989
  var MessageRepository = class {
@@ -1024,28 +998,21 @@ var MessageRepository = class {
1024
998
  }
1025
999
  return messages;
1026
1000
  }
1027
- // TODO previousId is confusing
1028
- // TODO previousId does not fix children
1029
- // TODO cut / link operations
1030
- addOrUpdateMessage(parentId, message, previousId = message.id) {
1001
+ addOrUpdateMessage(parentId, message) {
1031
1002
  const item = this.messages.get(message.id);
1032
1003
  if (item) {
1033
- if (item.prev?.current.id !== parentId) {
1034
- if ((item.prev?.current.id ?? null) !== parentId) {
1035
- this.deleteMessage(message.id);
1036
- } else {
1037
- item.current = message;
1038
- if (previousId !== message.id) {
1039
- this.messages.delete(previousId);
1040
- this.messages.set(message.id, item);
1041
- }
1042
- return;
1043
- }
1004
+ if ((item.prev?.current.id ?? null) !== parentId) {
1005
+ this.deleteMessage(message.id);
1006
+ } else {
1007
+ item.current = message;
1008
+ return;
1044
1009
  }
1045
1010
  }
1046
1011
  const prev = parentId ? this.messages.get(parentId) : null;
1047
1012
  if (prev === void 0)
1048
- throw new Error("Unexpected: Parent message not found");
1013
+ throw new Error(
1014
+ "MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui."
1015
+ );
1049
1016
  const newItem = {
1050
1017
  prev,
1051
1018
  current: message,
@@ -1067,7 +1034,9 @@ var MessageRepository = class {
1067
1034
  deleteMessage(messageId) {
1068
1035
  const message = this.messages.get(messageId);
1069
1036
  if (!message)
1070
- throw new Error("Unexpected: Message not found");
1037
+ throw new Error(
1038
+ "MessageRepository(deleteMessage): Message not found. This is likely an internal bug in assistant-ui."
1039
+ );
1071
1040
  if (message.children.length > 0) {
1072
1041
  for (const child of message.children) {
1073
1042
  this.deleteMessage(child);
@@ -1082,7 +1051,9 @@ var MessageRepository = class {
1082
1051
  const childId = message.prev.children.at(-1);
1083
1052
  const child = childId ? this.messages.get(childId) : null;
1084
1053
  if (child === void 0)
1085
- throw new Error("Unexpected: Child message not found");
1054
+ throw new Error(
1055
+ "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
1056
+ );
1086
1057
  message.prev.next = child;
1087
1058
  }
1088
1059
  } else {
@@ -1099,17 +1070,6 @@ var MessageRepository = class {
1099
1070
  } while (this.messages.has(optimisticId));
1100
1071
  return optimisticId;
1101
1072
  }
1102
- commitOptimisticAppend(message) {
1103
- const optimisticIdUser = this.getOptimisticId();
1104
- this.addOrUpdateMessage(message.parentId, {
1105
- id: optimisticIdUser,
1106
- role: "user",
1107
- content: message.content,
1108
- createdAt: /* @__PURE__ */ new Date()
1109
- });
1110
- const optimisticIdAssistant = this.commitOptimisticRun(optimisticIdUser);
1111
- return [optimisticIdUser, optimisticIdAssistant];
1112
- }
1113
1073
  commitOptimisticRun(parentId) {
1114
1074
  const optimisticId = this.getOptimisticId();
1115
1075
  this.addOrUpdateMessage(parentId, {
@@ -1128,7 +1088,9 @@ var MessageRepository = class {
1128
1088
  getBranches(messageId) {
1129
1089
  const message = this.messages.get(messageId);
1130
1090
  if (!message)
1131
- throw new Error("Unexpected: Message not found");
1091
+ throw new Error(
1092
+ "MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui."
1093
+ );
1132
1094
  if (message.prev) {
1133
1095
  return message.prev.children;
1134
1096
  }
@@ -1137,7 +1099,9 @@ var MessageRepository = class {
1137
1099
  switchToBranch(messageId) {
1138
1100
  const message = this.messages.get(messageId);
1139
1101
  if (!message)
1140
- throw new Error("Unexpected: Branch not found");
1102
+ throw new Error(
1103
+ "MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui."
1104
+ );
1141
1105
  if (message.prev) {
1142
1106
  message.prev.next = message;
1143
1107
  }
@@ -1147,7 +1111,9 @@ var MessageRepository = class {
1147
1111
  if (messageId) {
1148
1112
  const message = this.messages.get(messageId);
1149
1113
  if (!message)
1150
- throw new Error("Unexpected: Branch not found");
1114
+ throw new Error(
1115
+ "MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui."
1116
+ );
1151
1117
  this.head = message;
1152
1118
  for (let current = message; current; current = current.prev) {
1153
1119
  if (current.prev) {
@@ -1169,8 +1135,7 @@ var ThreadMessageConverter = class {
1169
1135
  convertMessages(messages) {
1170
1136
  return messages.map((m) => {
1171
1137
  const cached = this.cache.get(m);
1172
- if (cached)
1173
- return cached;
1138
+ if (cached) return cached;
1174
1139
  const newMessage = this.converter(m);
1175
1140
  this.cache.set(m, newMessage);
1176
1141
  return newMessage;
@@ -1181,32 +1146,42 @@ var ThreadMessageConverter = class {
1181
1146
  // src/adapters/vercel/useVercelAIThreadState.tsx
1182
1147
  var vercelToThreadMessage = (message) => {
1183
1148
  if (message.role !== "user" && message.role !== "assistant")
1184
- throw new Error("Unsupported role");
1149
+ throw new Error(
1150
+ `You have a message with an unsupported role. The role ${message.role} is not supported.`
1151
+ );
1185
1152
  return {
1186
1153
  id: message.id,
1187
1154
  role: message.role,
1188
- content: [{ type: "text", text: message.content }],
1155
+ content: [
1156
+ ...message.content ? [{ type: "text", text: message.content }] : [],
1157
+ ...message.toolInvocations?.map((t) => ({
1158
+ type: "tool-call",
1159
+ name: t.toolName,
1160
+ args: t.args,
1161
+ result: "result" in t ? t.result : void 0
1162
+ })) ?? []
1163
+ ],
1164
+ // ignore type mismatch for now
1189
1165
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1190
1166
  innerMessage: message
1191
1167
  };
1192
1168
  };
1193
1169
  var converter = new ThreadMessageConverter(vercelToThreadMessage);
1194
1170
  var sliceMessagesUntil = (messages, messageId) => {
1195
- if (messageId == null)
1196
- return [];
1197
- if (isOptimisticId(messageId))
1198
- return messages;
1171
+ if (messageId == null) return [];
1172
+ if (isOptimisticId(messageId)) return messages;
1199
1173
  const messageIdx = messages.findIndex((m) => m.id === messageId);
1200
1174
  if (messageIdx === -1)
1201
- throw new Error("Unexpected: Message not found");
1175
+ throw new Error(
1176
+ "useVercelAIThreadState: Message not found. This is liekly an internal bug in assistant-ui."
1177
+ );
1202
1178
  return messages.slice(0, messageIdx + 1);
1203
1179
  };
1204
1180
  var hasUpcomingMessage = (isRunning, messages) => {
1205
1181
  return isRunning && messages[messages.length - 1]?.role !== "assistant";
1206
1182
  };
1207
1183
  var getIsRunning = (vercel) => {
1208
- if ("isLoading" in vercel)
1209
- return vercel.isLoading;
1184
+ if ("isLoading" in vercel) return vercel.isLoading;
1210
1185
  return vercel.status === "in_progress";
1211
1186
  };
1212
1187
  var useVercelAIThreadState = (vercel) => {
@@ -1234,13 +1209,13 @@ var useVercelAIThreadState = (vercel) => {
1234
1209
  data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
1235
1210
  return data.getMessages();
1236
1211
  }, [data, isRunning, vercel.messages]);
1237
- const getBranches = useCallback2(
1212
+ const getBranches2 = useCallback2(
1238
1213
  (messageId) => {
1239
1214
  return data.getBranches(messageId);
1240
1215
  },
1241
1216
  [data]
1242
1217
  );
1243
- const switchToBranch = useCallback2(
1218
+ const switchToBranch2 = useCallback2(
1244
1219
  (messageId) => {
1245
1220
  data.switchToBranch(messageId);
1246
1221
  vercelRef.current.setMessages(
@@ -1252,7 +1227,9 @@ var useVercelAIThreadState = (vercel) => {
1252
1227
  const startRun = useCallback2(async (parentId) => {
1253
1228
  const reloadMaybe = "reload" in vercelRef.current ? vercelRef.current.reload : void 0;
1254
1229
  if (!reloadMaybe)
1255
- throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
1230
+ throw new Error(
1231
+ "Reload is not supported by Vercel AI SDK's useAssistant."
1232
+ );
1256
1233
  const newMessages = sliceMessagesUntil(
1257
1234
  vercelRef.current.messages,
1258
1235
  parentId
@@ -1262,7 +1239,7 @@ var useVercelAIThreadState = (vercel) => {
1262
1239
  }, []);
1263
1240
  const append = useCallback2(async (message) => {
1264
1241
  if (message.content.length !== 1 || message.content[0]?.type !== "text")
1265
- throw new Error("Only text content is supported by Vercel AI SDK");
1242
+ throw new Error("Only text content is supported by Vercel AI SDK.");
1266
1243
  const newMessages = sliceMessagesUntil(
1267
1244
  vercelRef.current.messages,
1268
1245
  message.parentId
@@ -1273,7 +1250,7 @@ var useVercelAIThreadState = (vercel) => {
1273
1250
  content: message.content[0].text
1274
1251
  });
1275
1252
  }, []);
1276
- const cancelRun = useCallback2(() => {
1253
+ const cancelRun2 = useCallback2(() => {
1277
1254
  const lastMessage = vercelRef.current.messages.at(-1);
1278
1255
  vercelRef.current.stop();
1279
1256
  if (lastMessage?.role === "user") {
@@ -1284,20 +1261,20 @@ var useVercelAIThreadState = (vercel) => {
1284
1261
  () => ({
1285
1262
  isRunning,
1286
1263
  messages,
1287
- getBranches,
1288
- switchToBranch,
1264
+ getBranches: getBranches2,
1265
+ switchToBranch: switchToBranch2,
1289
1266
  append,
1290
1267
  startRun,
1291
- cancelRun
1268
+ cancelRun: cancelRun2
1292
1269
  }),
1293
1270
  [
1294
1271
  isRunning,
1295
1272
  messages,
1296
- getBranches,
1297
- switchToBranch,
1273
+ getBranches2,
1274
+ switchToBranch2,
1298
1275
  append,
1299
1276
  startRun,
1300
- cancelRun
1277
+ cancelRun2
1301
1278
  ]
1302
1279
  );
1303
1280
  };
@@ -1326,12 +1303,11 @@ var VercelAIAssistantProvider = ({
1326
1303
  // src/adapters/vercel/VercelRSCAssistantProvider.tsx
1327
1304
  import {
1328
1305
  useCallback as useCallback3,
1329
- useMemo as useMemo5
1306
+ useMemo as useMemo5,
1307
+ useState as useState4
1330
1308
  } from "react";
1331
1309
  import { jsx as jsx20 } from "react/jsx-runtime";
1332
1310
  var vercelToThreadMessage2 = (message) => {
1333
- if (message.role !== "user" && message.role !== "assistant")
1334
- throw new Error("Unsupported role");
1335
1311
  return {
1336
1312
  id: message.id,
1337
1313
  role: message.role,
@@ -1339,6 +1315,22 @@ var vercelToThreadMessage2 = (message) => {
1339
1315
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
1340
1316
  };
1341
1317
  };
1318
+ var EMPTY_BRANCHES = [];
1319
+ var getBranches = () => {
1320
+ return EMPTY_BRANCHES;
1321
+ };
1322
+ var switchToBranch = () => {
1323
+ throw new Error(
1324
+ "Branch switching is not supported by VercelRSCAssistantProvider."
1325
+ );
1326
+ };
1327
+ var cancelRun = () => {
1328
+ if (process.env["NODE_ENV"] === "development") {
1329
+ console.warn(
1330
+ "Run cancellation is not supported by VercelRSCAssistantProvider."
1331
+ );
1332
+ }
1333
+ };
1342
1334
  var VercelRSCAssistantProvider = ({
1343
1335
  children,
1344
1336
  convertMessage,
@@ -1348,6 +1340,11 @@ var VercelRSCAssistantProvider = ({
1348
1340
  reload
1349
1341
  }) => {
1350
1342
  const context = useDummyAIAssistantContext();
1343
+ const [isRunning, setIsRunning] = useState4(false);
1344
+ const withRunning = useCallback3((callback) => {
1345
+ setIsRunning(true);
1346
+ return callback.finally(() => setIsRunning(false));
1347
+ }, []);
1351
1348
  const converter2 = useMemo5(() => {
1352
1349
  const rscConverter = convertMessage ?? ((m) => m);
1353
1350
  return new ThreadMessageConverter((m) => {
@@ -1362,32 +1359,39 @@ var VercelRSCAssistantProvider = ({
1362
1359
  if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
1363
1360
  if (!edit)
1364
1361
  throw new Error(
1365
- "Unexpected: Message editing is not supported, no edit callback was provided to VercelRSCAssistantProvider."
1362
+ "Message editing is not enabled, please provide an edit callback to VercelRSCAssistantProvider."
1366
1363
  );
1367
- await edit(message);
1364
+ await withRunning(edit(message));
1368
1365
  } else {
1369
- await appendCallback(message);
1366
+ await withRunning(appendCallback(message));
1370
1367
  }
1371
1368
  },
1372
- [context, appendCallback, edit]
1369
+ [context, withRunning, appendCallback, edit]
1373
1370
  );
1374
1371
  const startRun = useCallback3(
1375
1372
  async (parentId) => {
1376
1373
  if (!reload)
1377
1374
  throw new Error(
1378
- "Unexpected: Message reloading is not supported, no reload callback was provided to VercelRSCAssistantProvider."
1375
+ "Message reloading is not enabled, please provide a reload callback to VercelRSCAssistantProvider."
1379
1376
  );
1380
- await reload(parentId);
1377
+ await withRunning(reload(parentId));
1381
1378
  },
1382
- [reload]
1379
+ [withRunning, reload]
1383
1380
  );
1384
1381
  useMemo5(() => {
1385
- context.useThread.setState({
1386
- messages,
1387
- append,
1388
- startRun
1389
- });
1390
- }, [context, messages, append, startRun]);
1382
+ context.useThread.setState(
1383
+ {
1384
+ messages,
1385
+ isRunning,
1386
+ getBranches,
1387
+ switchToBranch,
1388
+ append,
1389
+ startRun,
1390
+ cancelRun
1391
+ },
1392
+ true
1393
+ );
1394
+ }, [context, messages, isRunning, append, startRun]);
1391
1395
  return /* @__PURE__ */ jsx20(AssistantContext.Provider, { value: context, children });
1392
1396
  };
1393
1397
  export {