@assistant-ui/react 0.0.14 → 0.0.15

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