@assistant-ui/react 0.0.5 → 0.0.6

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.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { FC, PropsWithChildren } from 'react';
3
3
  import { TextareaAutosizeProps } from 'react-textarea-autosize';
4
- import { Message } from 'ai';
5
4
  import { UseChatHelpers } from 'ai/react';
6
5
  import { UseBoundStore, StoreApi } from 'zustand';
7
6
 
@@ -84,9 +83,49 @@ declare namespace index$3 {
84
83
  export { ComposerCancel as Cancel, ComposerIf as If, ComposerInput as Input, ComposerRoot as Root, ComposerSend as Send };
85
84
  }
86
85
 
86
+ type BranchState = {
87
+ branchId: number;
88
+ branchCount: number;
89
+ };
90
+
91
+ type ComposerState = {
92
+ isEditing: boolean;
93
+ canCancel: boolean;
94
+ edit: () => void;
95
+ send: () => void;
96
+ cancel: () => void;
97
+ value: string;
98
+ setValue: (value: string) => void;
99
+ };
100
+ type ComposerStore = {
101
+ useComposer: UseBoundStore<StoreApi<ComposerState>>;
102
+ };
103
+
104
+ type TextContent = {
105
+ type: "text";
106
+ text: string;
107
+ };
108
+ type ImageContent = {
109
+ type: "image";
110
+ image: string;
111
+ };
112
+ type ThreadUserMessageContent = TextContent | ImageContent;
113
+ type ThreadAssistantMessageContent = TextContent | ImageContent;
114
+ type ThreadUserMessage = {
115
+ id: string;
116
+ role: "user";
117
+ content: ThreadUserMessageContent[];
118
+ };
119
+ type ThreadAssistantMessage = {
120
+ id: string;
121
+ role: "assistant";
122
+ content: ThreadAssistantMessageContent[];
123
+ };
124
+ type ThreadMessage = ThreadUserMessage | ThreadAssistantMessage;
125
+
87
126
  type MessageProviderProps = {
88
127
  children?: React.ReactNode;
89
- message: Message;
128
+ message: ThreadMessage;
90
129
  };
91
130
  declare const MessageProvider: FC<MessageProviderProps>;
92
131
 
@@ -177,32 +216,14 @@ declare namespace index {
177
216
  export { ActionBarCopy as Copy, ActionBarEdit as Edit, ActionBarReload as Reload, ActionBarRoot as Root };
178
217
  }
179
218
 
180
- type VercelAIAssistantProviderProps = {
219
+ type VercelAIChatAssistantProviderProps = {
181
220
  chat: UseChatHelpers;
182
221
  children: React.ReactNode;
183
222
  };
184
- declare const VercelAIAssistantProvider: FC<VercelAIAssistantProviderProps>;
185
-
186
- type ComposerState = {
187
- isEditing: boolean;
188
- canCancel: boolean;
189
- edit: () => void;
190
- send: () => void;
191
- cancel: () => void;
192
- value: string;
193
- setValue: (value: string) => void;
194
- };
195
- type ComposerStore = {
196
- useComposer: UseBoundStore<StoreApi<ComposerState>>;
197
- };
198
-
199
- type BranchState = {
200
- branchId: number;
201
- branchCount: number;
202
- };
223
+ declare const VercelAIChatAssistantProvider: FC<VercelAIChatAssistantProviderProps>;
203
224
 
204
225
  type MessageState = {
205
- message: Message;
226
+ message: ThreadMessage;
206
227
  branchState: BranchState;
207
228
  isLast: boolean;
208
229
  isCopied: boolean;
@@ -227,4 +248,4 @@ declare const useGoToNextBranch: () => (() => void) | null;
227
248
 
228
249
  declare const useGoToPreviousBranch: () => (() => void) | null;
229
250
 
230
- export { index as ActionBarPrimitive, index$1 as BranchPickerPrimitive, index$3 as ComposerPrimitive, index$2 as MessagePrimitive, index$4 as ThreadPrimitive, VercelAIAssistantProvider as VercelAIThreadProvider, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
251
+ export { index as ActionBarPrimitive, index$1 as BranchPickerPrimitive, index$3 as ComposerPrimitive, index$2 as MessagePrimitive, index$4 as ThreadPrimitive, VercelAIChatAssistantProvider as VercelAIAssistantProvider, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { FC, PropsWithChildren } from 'react';
3
3
  import { TextareaAutosizeProps } from 'react-textarea-autosize';
4
- import { Message } from 'ai';
5
4
  import { UseChatHelpers } from 'ai/react';
6
5
  import { UseBoundStore, StoreApi } from 'zustand';
7
6
 
@@ -84,9 +83,49 @@ declare namespace index$3 {
84
83
  export { ComposerCancel as Cancel, ComposerIf as If, ComposerInput as Input, ComposerRoot as Root, ComposerSend as Send };
85
84
  }
86
85
 
86
+ type BranchState = {
87
+ branchId: number;
88
+ branchCount: number;
89
+ };
90
+
91
+ type ComposerState = {
92
+ isEditing: boolean;
93
+ canCancel: boolean;
94
+ edit: () => void;
95
+ send: () => void;
96
+ cancel: () => void;
97
+ value: string;
98
+ setValue: (value: string) => void;
99
+ };
100
+ type ComposerStore = {
101
+ useComposer: UseBoundStore<StoreApi<ComposerState>>;
102
+ };
103
+
104
+ type TextContent = {
105
+ type: "text";
106
+ text: string;
107
+ };
108
+ type ImageContent = {
109
+ type: "image";
110
+ image: string;
111
+ };
112
+ type ThreadUserMessageContent = TextContent | ImageContent;
113
+ type ThreadAssistantMessageContent = TextContent | ImageContent;
114
+ type ThreadUserMessage = {
115
+ id: string;
116
+ role: "user";
117
+ content: ThreadUserMessageContent[];
118
+ };
119
+ type ThreadAssistantMessage = {
120
+ id: string;
121
+ role: "assistant";
122
+ content: ThreadAssistantMessageContent[];
123
+ };
124
+ type ThreadMessage = ThreadUserMessage | ThreadAssistantMessage;
125
+
87
126
  type MessageProviderProps = {
88
127
  children?: React.ReactNode;
89
- message: Message;
128
+ message: ThreadMessage;
90
129
  };
91
130
  declare const MessageProvider: FC<MessageProviderProps>;
92
131
 
@@ -177,32 +216,14 @@ declare namespace index {
177
216
  export { ActionBarCopy as Copy, ActionBarEdit as Edit, ActionBarReload as Reload, ActionBarRoot as Root };
178
217
  }
179
218
 
180
- type VercelAIAssistantProviderProps = {
219
+ type VercelAIChatAssistantProviderProps = {
181
220
  chat: UseChatHelpers;
182
221
  children: React.ReactNode;
183
222
  };
184
- declare const VercelAIAssistantProvider: FC<VercelAIAssistantProviderProps>;
185
-
186
- type ComposerState = {
187
- isEditing: boolean;
188
- canCancel: boolean;
189
- edit: () => void;
190
- send: () => void;
191
- cancel: () => void;
192
- value: string;
193
- setValue: (value: string) => void;
194
- };
195
- type ComposerStore = {
196
- useComposer: UseBoundStore<StoreApi<ComposerState>>;
197
- };
198
-
199
- type BranchState = {
200
- branchId: number;
201
- branchCount: number;
202
- };
223
+ declare const VercelAIChatAssistantProvider: FC<VercelAIChatAssistantProviderProps>;
203
224
 
204
225
  type MessageState = {
205
- message: Message;
226
+ message: ThreadMessage;
206
227
  branchState: BranchState;
207
228
  isLast: boolean;
208
229
  isCopied: boolean;
@@ -227,4 +248,4 @@ declare const useGoToNextBranch: () => (() => void) | null;
227
248
 
228
249
  declare const useGoToPreviousBranch: () => (() => void) | null;
229
250
 
230
- export { index as ActionBarPrimitive, index$1 as BranchPickerPrimitive, index$3 as ComposerPrimitive, index$2 as MessagePrimitive, index$4 as ThreadPrimitive, VercelAIAssistantProvider as VercelAIThreadProvider, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
251
+ export { index as ActionBarPrimitive, index$1 as BranchPickerPrimitive, index$3 as ComposerPrimitive, index$2 as MessagePrimitive, index$4 as ThreadPrimitive, VercelAIChatAssistantProvider as VercelAIAssistantProvider, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ __export(src_exports, {
35
35
  ComposerPrimitive: () => composer_exports,
36
36
  MessagePrimitive: () => message_exports,
37
37
  ThreadPrimitive: () => thread_exports,
38
- VercelAIThreadProvider: () => VercelAIAssistantProvider,
38
+ VercelAIAssistantProvider: () => VercelAIChatAssistantProvider,
39
39
  unstable_useMessageContext: () => useMessageContext,
40
40
  useBeginMessageEdit: () => useBeginMessageEdit,
41
41
  useCopyMessage: () => useCopyMessage,
@@ -177,7 +177,7 @@ var ThreadViewport = (0, import_react4.forwardRef)(({ onScroll, children, ...res
177
177
  );
178
178
  });
179
179
 
180
- // src/utils/hooks/useBranches.tsx
180
+ // src/vercel/useVercelAIBranches.tsx
181
181
  var import_react5 = require("react");
182
182
  var ROOT_ID = "__ROOT_ID__";
183
183
  var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
@@ -245,7 +245,7 @@ var sliceMessagesUntil = (messages, message) => {
245
245
  throw new Error("Unexpected: Message not found");
246
246
  return messages.slice(0, messageIdx);
247
247
  };
248
- var useChatWithBranches = (chat) => {
248
+ var useVercelAIBranches = (chat) => {
249
249
  const data = (0, import_react5.useRef)({
250
250
  parentMap: /* @__PURE__ */ new Map(),
251
251
  branchMap: /* @__PURE__ */ new Map(),
@@ -282,7 +282,12 @@ var useChatWithBranches = (chat) => {
282
282
  async (message, newMessage) => {
283
283
  const newMessages = sliceMessagesUntil(chat.messages, message);
284
284
  chat.setMessages(newMessages);
285
- await chat.append(newMessage);
285
+ if (newMessage.content[0]?.type !== "text")
286
+ throw new Error("Only text content is currently supported");
287
+ await chat.append({
288
+ role: "user",
289
+ content: newMessage.content[0].text
290
+ });
286
291
  },
287
292
  [chat.messages, chat.setMessages, chat.append]
288
293
  );
@@ -373,18 +378,25 @@ var useMessageContext2 = () => {
373
378
  const useComposer = (0, import_zustand.create)((set, get) => ({
374
379
  isEditing: false,
375
380
  canCancel: true,
376
- edit: () => set({
377
- isEditing: true,
378
- value: useMessage.getState().message.content
379
- }),
381
+ edit: () => {
382
+ const message = useMessage.getState().message;
383
+ if (message.role !== "user")
384
+ throw new Error("Editing is only supported for user messages");
385
+ if (message.content[0]?.type !== "text")
386
+ throw new Error("Editing is only supported for text-only messages");
387
+ return set({
388
+ isEditing: true,
389
+ value: message.content[0].text
390
+ });
391
+ },
380
392
  cancel: () => set({ isEditing: false }),
381
393
  send: () => {
382
394
  const message = useMessage.getState().message;
395
+ if (message.role !== "user")
396
+ throw new Error("Editing is only supported for user messages");
383
397
  useBranchObserver.getState().editAt(message, {
384
- ...message,
385
- id: void 0,
386
- // remove id to create a new message
387
- content: get().value
398
+ role: "user",
399
+ content: [{ type: "text", text: get().value }]
388
400
  });
389
401
  set({ isEditing: false });
390
402
  },
@@ -486,7 +498,9 @@ var MessageIf = ({ children, ...query }) => {
486
498
  var MessageContent = () => {
487
499
  const { useMessage } = useMessageContext();
488
500
  const content = useMessage((s) => s.message.content);
489
- return /* @__PURE__ */ React.createElement(React.Fragment, null, content);
501
+ if (content[0]?.type !== "text")
502
+ throw new Error("Unsupported message content type");
503
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, content[0].text);
490
504
  };
491
505
 
492
506
  // src/primitives/thread/ThreadMessages.tsx
@@ -515,7 +529,7 @@ var ThreadMessages = ({ components }) => {
515
529
  message: {
516
530
  id: UPCOMING_MESSAGE_ID,
517
531
  role: "assistant",
518
- content: "..."
532
+ content: [{ type: "text", text: "..." }]
519
533
  }
520
534
  },
521
535
  /* @__PURE__ */ React.createElement(AssistantMessage, null)
@@ -810,11 +824,10 @@ var useCopyMessage = ({ copiedDuration = 3e3 }) => {
810
824
  if (isEditing)
811
825
  return null;
812
826
  return () => {
813
- const {
814
- message: { content },
815
- setIsCopied
816
- } = useMessage.getState();
817
- navigator.clipboard.writeText(content);
827
+ const { message, setIsCopied } = useMessage.getState();
828
+ if (message.content[0]?.type !== "text")
829
+ throw new Error("Copying is only supported for text-only messages");
830
+ navigator.clipboard.writeText(message.content[0].text);
818
831
  setIsCopied(true);
819
832
  setTimeout(() => setIsCopied(false), copiedDuration);
820
833
  };
@@ -832,7 +845,10 @@ var useReloadMessage = () => {
832
845
  if (isLoading || !isAssistant)
833
846
  return null;
834
847
  return () => {
835
- useBranchObserver.getState().reloadAt(useMessage.getState().message);
848
+ const message = useMessage.getState().message;
849
+ if (message.role !== "assistant")
850
+ throw new Error("Reloading is only supported on assistant messages");
851
+ useBranchObserver.getState().reloadAt(message);
836
852
  };
837
853
  };
838
854
 
@@ -862,8 +878,6 @@ var useAIAssistantContext = () => {
862
878
  const [context] = (0, import_react17.useState)(() => {
863
879
  const useThread = (0, import_zustand2.create)()(() => ({
864
880
  messages: [],
865
- setMessages: () => {
866
- },
867
881
  isLoading: false,
868
882
  reload: async () => {
869
883
  },
@@ -883,9 +897,8 @@ var useAIAssistantContext = () => {
883
897
  },
884
898
  send: () => {
885
899
  useThread.getState().append({
886
- content: useComposer.getState().value,
887
900
  role: "user",
888
- createdAt: /* @__PURE__ */ new Date()
901
+ content: [{ type: "text", text: useComposer.getState().value }]
889
902
  });
890
903
  useComposer.getState().setValue("");
891
904
  },
@@ -909,36 +922,65 @@ var useAIAssistantContext = () => {
909
922
  });
910
923
  return context;
911
924
  };
912
- var VercelAIAssistantProvider = ({
913
- chat,
914
- children
915
- }) => {
925
+ var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
926
+ var vercelToThreadMessage = (message) => {
927
+ if (message.role !== "user" && message.role !== "assistant")
928
+ throw new Error("Unsupported role");
929
+ return {
930
+ id: message.id,
931
+ role: message.role,
932
+ content: [{ type: "text", text: message.content }]
933
+ };
934
+ };
935
+ var vercelToCachedThreadMessages = (messages) => {
936
+ return messages.map((m) => {
937
+ const cached = ThreadMessageCache.get(m);
938
+ if (cached)
939
+ return cached;
940
+ const newMessage = vercelToThreadMessage(m);
941
+ ThreadMessageCache.set(m, newMessage);
942
+ return newMessage;
943
+ });
944
+ };
945
+ var VercelAIChatAssistantProvider = ({ chat, children }) => {
916
946
  const context = useAIAssistantContext();
947
+ const messages = (0, import_react17.useMemo)(() => {
948
+ return vercelToCachedThreadMessages(chat.messages);
949
+ }, [chat.messages]);
950
+ const reload = (0, import_react17.useCallback)(async () => {
951
+ await chat.reload();
952
+ }, [chat.reload]);
953
+ const append = (0, import_react17.useCallback)(
954
+ async (message) => {
955
+ if (message.content[0]?.type !== "text") {
956
+ throw new Error("Only text content is currently supported");
957
+ }
958
+ await chat.append({
959
+ role: message.role,
960
+ content: message.content[0].text
961
+ });
962
+ },
963
+ [chat.append]
964
+ );
965
+ const stop = (0, import_react17.useCallback)(() => {
966
+ const lastMessage = chat.messages.at(-1);
967
+ chat.stop();
968
+ if (lastMessage?.role === "user") {
969
+ chat.setInput(lastMessage.content);
970
+ }
971
+ }, [chat.messages, chat.stop, chat.setInput]);
917
972
  (0, import_react17.useMemo)(() => {
918
973
  context.useThread.setState(
919
974
  {
920
- messages: chat.messages,
921
- setMessages: (value) => {
922
- chat.setMessages(value);
923
- },
975
+ messages,
924
976
  isLoading: chat.isLoading,
925
- reload: async () => {
926
- await chat.reload();
927
- },
928
- append: async (message) => {
929
- await chat.append(message);
930
- },
931
- stop: () => {
932
- const lastMessage = chat.messages.at(-1);
933
- chat.stop();
934
- if (lastMessage?.role === "user") {
935
- chat.setInput(lastMessage.content);
936
- }
937
- }
977
+ reload,
978
+ append,
979
+ stop
938
980
  },
939
981
  true
940
982
  );
941
- }, [context, chat]);
983
+ }, [context, messages, reload, append, stop, chat.isLoading]);
942
984
  (0, import_react17.useMemo)(() => {
943
985
  context.useComposer.setState({
944
986
  canCancel: chat.isLoading,
@@ -946,17 +988,9 @@ var VercelAIAssistantProvider = ({
946
988
  setValue: chat.setInput
947
989
  });
948
990
  }, [context, chat.isLoading, chat.input, chat.setInput]);
949
- const branches = useChatWithBranches(chat);
991
+ const branches = useVercelAIBranches(chat);
950
992
  (0, import_react17.useMemo)(() => {
951
- context.useBranchObserver.setState(
952
- {
953
- getBranchState: (message) => branches.getBranchState(message),
954
- switchToBranch: (message, branchId) => branches.switchToBranch(message, branchId),
955
- editAt: async (message, newMessage) => branches.editAt(message, newMessage),
956
- reloadAt: async (message) => branches.reloadAt(message)
957
- },
958
- true
959
- );
993
+ context.useBranchObserver.setState(branches, true);
960
994
  }, [context, branches]);
961
995
  return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
962
996
  };
@@ -967,7 +1001,7 @@ var VercelAIAssistantProvider = ({
967
1001
  ComposerPrimitive,
968
1002
  MessagePrimitive,
969
1003
  ThreadPrimitive,
970
- VercelAIThreadProvider,
1004
+ VercelAIAssistantProvider,
971
1005
  unstable_useMessageContext,
972
1006
  useBeginMessageEdit,
973
1007
  useCopyMessage,
package/dist/index.mjs CHANGED
@@ -140,7 +140,7 @@ var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef)
140
140
  );
141
141
  });
142
142
 
143
- // src/utils/hooks/useBranches.tsx
143
+ // src/vercel/useVercelAIBranches.tsx
144
144
  import { useCallback, useMemo, useRef as useRef3 } from "react";
145
145
  var ROOT_ID = "__ROOT_ID__";
146
146
  var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
@@ -208,7 +208,7 @@ var sliceMessagesUntil = (messages, message) => {
208
208
  throw new Error("Unexpected: Message not found");
209
209
  return messages.slice(0, messageIdx);
210
210
  };
211
- var useChatWithBranches = (chat) => {
211
+ var useVercelAIBranches = (chat) => {
212
212
  const data = useRef3({
213
213
  parentMap: /* @__PURE__ */ new Map(),
214
214
  branchMap: /* @__PURE__ */ new Map(),
@@ -245,7 +245,12 @@ var useChatWithBranches = (chat) => {
245
245
  async (message, newMessage) => {
246
246
  const newMessages = sliceMessagesUntil(chat.messages, message);
247
247
  chat.setMessages(newMessages);
248
- await chat.append(newMessage);
248
+ if (newMessage.content[0]?.type !== "text")
249
+ throw new Error("Only text content is currently supported");
250
+ await chat.append({
251
+ role: "user",
252
+ content: newMessage.content[0].text
253
+ });
249
254
  },
250
255
  [chat.messages, chat.setMessages, chat.append]
251
256
  );
@@ -336,18 +341,25 @@ var useMessageContext2 = () => {
336
341
  const useComposer = create((set, get) => ({
337
342
  isEditing: false,
338
343
  canCancel: true,
339
- edit: () => set({
340
- isEditing: true,
341
- value: useMessage.getState().message.content
342
- }),
344
+ edit: () => {
345
+ const message = useMessage.getState().message;
346
+ if (message.role !== "user")
347
+ throw new Error("Editing is only supported for user messages");
348
+ if (message.content[0]?.type !== "text")
349
+ throw new Error("Editing is only supported for text-only messages");
350
+ return set({
351
+ isEditing: true,
352
+ value: message.content[0].text
353
+ });
354
+ },
343
355
  cancel: () => set({ isEditing: false }),
344
356
  send: () => {
345
357
  const message = useMessage.getState().message;
358
+ if (message.role !== "user")
359
+ throw new Error("Editing is only supported for user messages");
346
360
  useBranchObserver.getState().editAt(message, {
347
- ...message,
348
- id: void 0,
349
- // remove id to create a new message
350
- content: get().value
361
+ role: "user",
362
+ content: [{ type: "text", text: get().value }]
351
363
  });
352
364
  set({ isEditing: false });
353
365
  },
@@ -451,7 +463,9 @@ var MessageIf = ({ children, ...query }) => {
451
463
  var MessageContent = () => {
452
464
  const { useMessage } = useMessageContext();
453
465
  const content = useMessage((s) => s.message.content);
454
- return /* @__PURE__ */ React.createElement(React.Fragment, null, content);
466
+ if (content[0]?.type !== "text")
467
+ throw new Error("Unsupported message content type");
468
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, content[0].text);
455
469
  };
456
470
 
457
471
  // src/primitives/thread/ThreadMessages.tsx
@@ -480,7 +494,7 @@ var ThreadMessages = ({ components }) => {
480
494
  message: {
481
495
  id: UPCOMING_MESSAGE_ID,
482
496
  role: "assistant",
483
- content: "..."
497
+ content: [{ type: "text", text: "..." }]
484
498
  }
485
499
  },
486
500
  /* @__PURE__ */ React.createElement(AssistantMessage, null)
@@ -793,11 +807,10 @@ var useCopyMessage = ({ copiedDuration = 3e3 }) => {
793
807
  if (isEditing)
794
808
  return null;
795
809
  return () => {
796
- const {
797
- message: { content },
798
- setIsCopied
799
- } = useMessage.getState();
800
- navigator.clipboard.writeText(content);
810
+ const { message, setIsCopied } = useMessage.getState();
811
+ if (message.content[0]?.type !== "text")
812
+ throw new Error("Copying is only supported for text-only messages");
813
+ navigator.clipboard.writeText(message.content[0].text);
801
814
  setIsCopied(true);
802
815
  setTimeout(() => setIsCopied(false), copiedDuration);
803
816
  };
@@ -815,7 +828,10 @@ var useReloadMessage = () => {
815
828
  if (isLoading || !isAssistant)
816
829
  return null;
817
830
  return () => {
818
- useBranchObserver.getState().reloadAt(useMessage.getState().message);
831
+ const message = useMessage.getState().message;
832
+ if (message.role !== "assistant")
833
+ throw new Error("Reloading is only supported on assistant messages");
834
+ useBranchObserver.getState().reloadAt(message);
819
835
  };
820
836
  };
821
837
 
@@ -839,14 +855,12 @@ var useBeginMessageEdit = () => {
839
855
  var ActionBarEdit = createActionButton(useBeginMessageEdit);
840
856
 
841
857
  // src/vercel/VercelAIAssistantProvider.tsx
842
- import { useMemo as useMemo4, useState as useState3 } from "react";
858
+ import { useCallback as useCallback2, useMemo as useMemo4, useState as useState3 } from "react";
843
859
  import { create as create2 } from "zustand";
844
860
  var useAIAssistantContext = () => {
845
861
  const [context] = useState3(() => {
846
862
  const useThread = create2()(() => ({
847
863
  messages: [],
848
- setMessages: () => {
849
- },
850
864
  isLoading: false,
851
865
  reload: async () => {
852
866
  },
@@ -866,9 +880,8 @@ var useAIAssistantContext = () => {
866
880
  },
867
881
  send: () => {
868
882
  useThread.getState().append({
869
- content: useComposer.getState().value,
870
883
  role: "user",
871
- createdAt: /* @__PURE__ */ new Date()
884
+ content: [{ type: "text", text: useComposer.getState().value }]
872
885
  });
873
886
  useComposer.getState().setValue("");
874
887
  },
@@ -892,36 +905,65 @@ var useAIAssistantContext = () => {
892
905
  });
893
906
  return context;
894
907
  };
895
- var VercelAIAssistantProvider = ({
896
- chat,
897
- children
898
- }) => {
908
+ var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
909
+ var vercelToThreadMessage = (message) => {
910
+ if (message.role !== "user" && message.role !== "assistant")
911
+ throw new Error("Unsupported role");
912
+ return {
913
+ id: message.id,
914
+ role: message.role,
915
+ content: [{ type: "text", text: message.content }]
916
+ };
917
+ };
918
+ var vercelToCachedThreadMessages = (messages) => {
919
+ return messages.map((m) => {
920
+ const cached = ThreadMessageCache.get(m);
921
+ if (cached)
922
+ return cached;
923
+ const newMessage = vercelToThreadMessage(m);
924
+ ThreadMessageCache.set(m, newMessage);
925
+ return newMessage;
926
+ });
927
+ };
928
+ var VercelAIChatAssistantProvider = ({ chat, children }) => {
899
929
  const context = useAIAssistantContext();
930
+ const messages = useMemo4(() => {
931
+ return vercelToCachedThreadMessages(chat.messages);
932
+ }, [chat.messages]);
933
+ const reload = useCallback2(async () => {
934
+ await chat.reload();
935
+ }, [chat.reload]);
936
+ const append = useCallback2(
937
+ async (message) => {
938
+ if (message.content[0]?.type !== "text") {
939
+ throw new Error("Only text content is currently supported");
940
+ }
941
+ await chat.append({
942
+ role: message.role,
943
+ content: message.content[0].text
944
+ });
945
+ },
946
+ [chat.append]
947
+ );
948
+ const stop = useCallback2(() => {
949
+ const lastMessage = chat.messages.at(-1);
950
+ chat.stop();
951
+ if (lastMessage?.role === "user") {
952
+ chat.setInput(lastMessage.content);
953
+ }
954
+ }, [chat.messages, chat.stop, chat.setInput]);
900
955
  useMemo4(() => {
901
956
  context.useThread.setState(
902
957
  {
903
- messages: chat.messages,
904
- setMessages: (value) => {
905
- chat.setMessages(value);
906
- },
958
+ messages,
907
959
  isLoading: chat.isLoading,
908
- reload: async () => {
909
- await chat.reload();
910
- },
911
- append: async (message) => {
912
- await chat.append(message);
913
- },
914
- stop: () => {
915
- const lastMessage = chat.messages.at(-1);
916
- chat.stop();
917
- if (lastMessage?.role === "user") {
918
- chat.setInput(lastMessage.content);
919
- }
920
- }
960
+ reload,
961
+ append,
962
+ stop
921
963
  },
922
964
  true
923
965
  );
924
- }, [context, chat]);
966
+ }, [context, messages, reload, append, stop, chat.isLoading]);
925
967
  useMemo4(() => {
926
968
  context.useComposer.setState({
927
969
  canCancel: chat.isLoading,
@@ -929,17 +971,9 @@ var VercelAIAssistantProvider = ({
929
971
  setValue: chat.setInput
930
972
  });
931
973
  }, [context, chat.isLoading, chat.input, chat.setInput]);
932
- const branches = useChatWithBranches(chat);
974
+ const branches = useVercelAIBranches(chat);
933
975
  useMemo4(() => {
934
- context.useBranchObserver.setState(
935
- {
936
- getBranchState: (message) => branches.getBranchState(message),
937
- switchToBranch: (message, branchId) => branches.switchToBranch(message, branchId),
938
- editAt: async (message, newMessage) => branches.editAt(message, newMessage),
939
- reloadAt: async (message) => branches.reloadAt(message)
940
- },
941
- true
942
- );
976
+ context.useBranchObserver.setState(branches, true);
943
977
  }, [context, branches]);
944
978
  return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
945
979
  };
@@ -949,7 +983,7 @@ export {
949
983
  composer_exports as ComposerPrimitive,
950
984
  message_exports as MessagePrimitive,
951
985
  thread_exports as ThreadPrimitive,
952
- VercelAIAssistantProvider as VercelAIThreadProvider,
986
+ VercelAIChatAssistantProvider as VercelAIAssistantProvider,
953
987
  useMessageContext as unstable_useMessageContext,
954
988
  useBeginMessageEdit,
955
989
  useCopyMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": {