@assistant-ui/react 0.0.6 → 0.0.7

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,7 @@
1
1
  import * as react from 'react';
2
- import { FC, PropsWithChildren } from 'react';
2
+ import { FC, PropsWithChildren, ReactNode, ComponentType } from 'react';
3
3
  import { TextareaAutosizeProps } from 'react-textarea-autosize';
4
- import { UseChatHelpers } from 'ai/react';
4
+ import { UseChatHelpers, UseAssistantHelpers } from 'ai/react';
5
5
  import { UseBoundStore, StoreApi } from 'zustand';
6
6
 
7
7
  declare const ThreadRoot: react.ForwardRefExoticComponent<Pick<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -101,16 +101,26 @@ type ComposerStore = {
101
101
  useComposer: UseBoundStore<StoreApi<ComposerState>>;
102
102
  };
103
103
 
104
- type TextContent = {
104
+ type ThreadMessageTextPart = {
105
105
  type: "text";
106
106
  text: string;
107
107
  };
108
- type ImageContent = {
108
+ type ThreadMessageImagePart = {
109
109
  type: "image";
110
110
  image: string;
111
111
  };
112
- type ThreadUserMessageContent = TextContent | ImageContent;
113
- type ThreadAssistantMessageContent = TextContent | ImageContent;
112
+ type ThreadMessageUIPart = {
113
+ type: "ui";
114
+ display: ReactNode;
115
+ };
116
+ type ThreadMessageToolCallPart = {
117
+ type: "tool-call";
118
+ name: string;
119
+ args: object;
120
+ result?: object;
121
+ };
122
+ type ThreadUserMessageContent = ThreadMessageTextPart | ThreadMessageImagePart | ThreadMessageUIPart;
123
+ type ThreadAssistantMessageContent = ThreadMessageTextPart | ThreadMessageImagePart | ThreadMessageUIPart | ThreadMessageToolCallPart;
114
124
  type ThreadUserMessage = {
115
125
  id: string;
116
126
  role: "user";
@@ -122,6 +132,7 @@ type ThreadAssistantMessage = {
122
132
  content: ThreadAssistantMessageContent[];
123
133
  };
124
134
  type ThreadMessage = ThreadUserMessage | ThreadAssistantMessage;
135
+ type CreateThreadMessage = Omit<ThreadUserMessage, "id">;
125
136
 
126
137
  type MessageProviderProps = {
127
138
  children?: React.ReactNode;
@@ -147,7 +158,28 @@ type MessageIfProps = RequireAtLeastOne<MessageIfFilters> & {
147
158
  };
148
159
  declare const MessageIf: FC<MessageIfProps>;
149
160
 
150
- declare const MessageContent: FC;
161
+ type MessageContentProps = {
162
+ components?: {
163
+ Text?: ComponentType<{
164
+ part: ThreadMessageTextPart;
165
+ }>;
166
+ Image?: ComponentType<{
167
+ part: ThreadMessageImagePart;
168
+ }>;
169
+ UI?: ComponentType<{
170
+ part: ThreadMessageUIPart;
171
+ }>;
172
+ tools?: {
173
+ by_name?: Record<string, ComponentType<{
174
+ part: ThreadMessageToolCallPart;
175
+ }>>;
176
+ Fallback?: ComponentType<{
177
+ part: ThreadMessageToolCallPart;
178
+ }>;
179
+ };
180
+ };
181
+ };
182
+ declare const MessageContent: FC<MessageContentProps>;
151
183
 
152
184
  declare namespace index$2 {
153
185
  export { MessageContent as Content, MessageIf as If, MessageProvider as Provider, MessageRoot as Root };
@@ -216,11 +248,23 @@ declare namespace index {
216
248
  export { ActionBarCopy as Copy, ActionBarEdit as Edit, ActionBarReload as Reload, ActionBarRoot as Root };
217
249
  }
218
250
 
219
- type VercelAIChatAssistantProviderProps = {
251
+ type VercelAIAssistantProviderProps$1 = PropsWithChildren<{
220
252
  chat: UseChatHelpers;
221
- children: React.ReactNode;
253
+ } | {
254
+ assistant: UseAssistantHelpers;
255
+ }>;
256
+ declare const VercelAIAssistantProvider: FC<VercelAIAssistantProviderProps$1>;
257
+
258
+ type RSCMessage = {
259
+ id: string;
260
+ role: "user" | "assistant";
261
+ display: ReactNode;
222
262
  };
223
- declare const VercelAIChatAssistantProvider: FC<VercelAIChatAssistantProviderProps>;
263
+ type VercelAIAssistantProviderProps = PropsWithChildren<{
264
+ messages: RSCMessage[];
265
+ append: (message: CreateThreadMessage) => Promise<void>;
266
+ }>;
267
+ declare const VercelRSCAssistantProvider: FC<VercelAIAssistantProviderProps>;
224
268
 
225
269
  type MessageState = {
226
270
  message: ThreadMessage;
@@ -248,4 +292,4 @@ declare const useGoToNextBranch: () => (() => void) | null;
248
292
 
249
293
  declare const useGoToPreviousBranch: () => (() => void) | null;
250
294
 
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 };
295
+ export { index as ActionBarPrimitive, index$1 as BranchPickerPrimitive, index$3 as ComposerPrimitive, index$2 as MessagePrimitive, index$4 as ThreadPrimitive, VercelAIAssistantProvider, VercelRSCAssistantProvider as unstable_VercelRSCAssistantProvider, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
- import { FC, PropsWithChildren } from 'react';
2
+ import { FC, PropsWithChildren, ReactNode, ComponentType } from 'react';
3
3
  import { TextareaAutosizeProps } from 'react-textarea-autosize';
4
- import { UseChatHelpers } from 'ai/react';
4
+ import { UseChatHelpers, UseAssistantHelpers } from 'ai/react';
5
5
  import { UseBoundStore, StoreApi } from 'zustand';
6
6
 
7
7
  declare const ThreadRoot: react.ForwardRefExoticComponent<Pick<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -101,16 +101,26 @@ type ComposerStore = {
101
101
  useComposer: UseBoundStore<StoreApi<ComposerState>>;
102
102
  };
103
103
 
104
- type TextContent = {
104
+ type ThreadMessageTextPart = {
105
105
  type: "text";
106
106
  text: string;
107
107
  };
108
- type ImageContent = {
108
+ type ThreadMessageImagePart = {
109
109
  type: "image";
110
110
  image: string;
111
111
  };
112
- type ThreadUserMessageContent = TextContent | ImageContent;
113
- type ThreadAssistantMessageContent = TextContent | ImageContent;
112
+ type ThreadMessageUIPart = {
113
+ type: "ui";
114
+ display: ReactNode;
115
+ };
116
+ type ThreadMessageToolCallPart = {
117
+ type: "tool-call";
118
+ name: string;
119
+ args: object;
120
+ result?: object;
121
+ };
122
+ type ThreadUserMessageContent = ThreadMessageTextPart | ThreadMessageImagePart | ThreadMessageUIPart;
123
+ type ThreadAssistantMessageContent = ThreadMessageTextPart | ThreadMessageImagePart | ThreadMessageUIPart | ThreadMessageToolCallPart;
114
124
  type ThreadUserMessage = {
115
125
  id: string;
116
126
  role: "user";
@@ -122,6 +132,7 @@ type ThreadAssistantMessage = {
122
132
  content: ThreadAssistantMessageContent[];
123
133
  };
124
134
  type ThreadMessage = ThreadUserMessage | ThreadAssistantMessage;
135
+ type CreateThreadMessage = Omit<ThreadUserMessage, "id">;
125
136
 
126
137
  type MessageProviderProps = {
127
138
  children?: React.ReactNode;
@@ -147,7 +158,28 @@ type MessageIfProps = RequireAtLeastOne<MessageIfFilters> & {
147
158
  };
148
159
  declare const MessageIf: FC<MessageIfProps>;
149
160
 
150
- declare const MessageContent: FC;
161
+ type MessageContentProps = {
162
+ components?: {
163
+ Text?: ComponentType<{
164
+ part: ThreadMessageTextPart;
165
+ }>;
166
+ Image?: ComponentType<{
167
+ part: ThreadMessageImagePart;
168
+ }>;
169
+ UI?: ComponentType<{
170
+ part: ThreadMessageUIPart;
171
+ }>;
172
+ tools?: {
173
+ by_name?: Record<string, ComponentType<{
174
+ part: ThreadMessageToolCallPart;
175
+ }>>;
176
+ Fallback?: ComponentType<{
177
+ part: ThreadMessageToolCallPart;
178
+ }>;
179
+ };
180
+ };
181
+ };
182
+ declare const MessageContent: FC<MessageContentProps>;
151
183
 
152
184
  declare namespace index$2 {
153
185
  export { MessageContent as Content, MessageIf as If, MessageProvider as Provider, MessageRoot as Root };
@@ -216,11 +248,23 @@ declare namespace index {
216
248
  export { ActionBarCopy as Copy, ActionBarEdit as Edit, ActionBarReload as Reload, ActionBarRoot as Root };
217
249
  }
218
250
 
219
- type VercelAIChatAssistantProviderProps = {
251
+ type VercelAIAssistantProviderProps$1 = PropsWithChildren<{
220
252
  chat: UseChatHelpers;
221
- children: React.ReactNode;
253
+ } | {
254
+ assistant: UseAssistantHelpers;
255
+ }>;
256
+ declare const VercelAIAssistantProvider: FC<VercelAIAssistantProviderProps$1>;
257
+
258
+ type RSCMessage = {
259
+ id: string;
260
+ role: "user" | "assistant";
261
+ display: ReactNode;
222
262
  };
223
- declare const VercelAIChatAssistantProvider: FC<VercelAIChatAssistantProviderProps>;
263
+ type VercelAIAssistantProviderProps = PropsWithChildren<{
264
+ messages: RSCMessage[];
265
+ append: (message: CreateThreadMessage) => Promise<void>;
266
+ }>;
267
+ declare const VercelRSCAssistantProvider: FC<VercelAIAssistantProviderProps>;
224
268
 
225
269
  type MessageState = {
226
270
  message: ThreadMessage;
@@ -248,4 +292,4 @@ declare const useGoToNextBranch: () => (() => void) | null;
248
292
 
249
293
  declare const useGoToPreviousBranch: () => (() => void) | null;
250
294
 
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 };
295
+ export { index as ActionBarPrimitive, index$1 as BranchPickerPrimitive, index$3 as ComposerPrimitive, index$2 as MessagePrimitive, index$4 as ThreadPrimitive, VercelAIAssistantProvider, VercelRSCAssistantProvider as unstable_VercelRSCAssistantProvider, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
package/dist/index.js CHANGED
@@ -35,7 +35,8 @@ __export(src_exports, {
35
35
  ComposerPrimitive: () => composer_exports,
36
36
  MessagePrimitive: () => message_exports,
37
37
  ThreadPrimitive: () => thread_exports,
38
- VercelAIAssistantProvider: () => VercelAIChatAssistantProvider,
38
+ VercelAIAssistantProvider: () => VercelAIAssistantProvider,
39
+ unstable_VercelRSCAssistantProvider: () => VercelRSCAssistantProvider,
39
40
  unstable_useMessageContext: () => useMessageContext,
40
41
  useBeginMessageEdit: () => useBeginMessageEdit,
41
42
  useCopyMessage: () => useCopyMessage,
@@ -102,10 +103,10 @@ var ThreadEmpty = ({ children }) => {
102
103
  };
103
104
 
104
105
  // src/primitives/thread/ThreadViewport.tsx
105
- var import_react4 = require("react");
106
- var import_react_primitive2 = require("@radix-ui/react-primitive");
107
- var import_react_compose_refs = require("@radix-ui/react-compose-refs");
108
106
  var import_primitive = require("@radix-ui/primitive");
107
+ var import_react_compose_refs = require("@radix-ui/react-compose-refs");
108
+ var import_react_primitive2 = require("@radix-ui/react-primitive");
109
+ var import_react4 = require("react");
109
110
 
110
111
  // src/utils/hooks/useOnResizeContent.tsx
111
112
  var import_react3 = require("react");
@@ -138,10 +139,8 @@ var useOnResizeContent = (ref, callback) => {
138
139
  mutationObserver.observe(el, { childList: true });
139
140
  for (const child of el.children) {
140
141
  resizeObserver.observe(child);
141
- console.log("observing child", child);
142
142
  }
143
143
  return () => {
144
- console.log("disconnecting");
145
144
  resizeObserver.disconnect();
146
145
  mutationObserver.disconnect();
147
146
  };
@@ -165,7 +164,6 @@ var ThreadViewport = (0, import_react4.forwardRef)(({ onScroll, children, ...res
165
164
  return;
166
165
  setIsAtBottom(div.scrollHeight - div.scrollTop <= div.clientHeight + 50);
167
166
  };
168
- console.log(isAtBottom);
169
167
  return /* @__PURE__ */ React.createElement(
170
168
  import_react_primitive2.Primitive.div,
171
169
  {
@@ -270,13 +268,16 @@ var useVercelAIBranches = (chat) => {
270
268
  },
271
269
  [data, chat.messages, chat.setMessages]
272
270
  );
271
+ const reloadMaybe = "reload" in chat ? chat.reload : void 0;
273
272
  const reloadAt = (0, import_react5.useCallback)(
274
273
  async (message) => {
274
+ if (!reloadMaybe)
275
+ throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
275
276
  const newMessages = sliceMessagesUntil(chat.messages, message);
276
277
  chat.setMessages(newMessages);
277
- await chat.reload();
278
+ await reloadMaybe();
278
279
  },
279
- [chat.messages, chat.setMessages, chat.reload]
280
+ [chat.messages, chat.setMessages, reloadMaybe]
280
281
  );
281
282
  const editAt = (0, import_react5.useCallback)(
282
283
  async (message, newMessage) => {
@@ -495,12 +496,41 @@ var MessageIf = ({ children, ...query }) => {
495
496
  };
496
497
 
497
498
  // src/primitives/message/MessageContent.tsx
498
- var MessageContent = () => {
499
+ var defaultComponents = {
500
+ Text: ({ part }) => /* @__PURE__ */ React.createElement(React.Fragment, null, part.text),
501
+ Image: () => null,
502
+ UI: ({ part }) => part.display,
503
+ tools: {
504
+ Fallback: () => null
505
+ }
506
+ };
507
+ var MessageContent = ({
508
+ components: {
509
+ Text = defaultComponents.Text,
510
+ Image = defaultComponents.Image,
511
+ UI = defaultComponents.UI,
512
+ tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
513
+ } = {}
514
+ }) => {
499
515
  const { useMessage } = useMessageContext();
500
516
  const content = useMessage((s) => s.message.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);
517
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, content.map((part, i) => {
518
+ const key = i;
519
+ switch (part.type) {
520
+ case "text":
521
+ return /* @__PURE__ */ React.createElement(Text, { key, part });
522
+ case "image":
523
+ return /* @__PURE__ */ React.createElement(Image, { key, part });
524
+ case "ui":
525
+ return /* @__PURE__ */ React.createElement(UI, { key, part });
526
+ case "tool-call": {
527
+ const Tool = by_name[part.name] || Fallback;
528
+ return /* @__PURE__ */ React.createElement(Tool, { key, part });
529
+ }
530
+ default:
531
+ return null;
532
+ }
533
+ }));
504
534
  };
505
535
 
506
536
  // src/primitives/thread/ThreadMessages.tsx
@@ -872,25 +902,32 @@ var useBeginMessageEdit = () => {
872
902
  var ActionBarEdit = createActionButton(useBeginMessageEdit);
873
903
 
874
904
  // src/vercel/VercelAIAssistantProvider.tsx
905
+ var import_react18 = require("react");
906
+
907
+ // src/vercel/useDummyAIAssistantContext.tsx
875
908
  var import_react17 = require("react");
876
909
  var import_zustand2 = require("zustand");
877
- var useAIAssistantContext = () => {
910
+ var useDummyAIAssistantContext = () => {
878
911
  const [context] = (0, import_react17.useState)(() => {
879
912
  const useThread = (0, import_zustand2.create)()(() => ({
880
913
  messages: [],
881
914
  isLoading: false,
882
915
  reload: async () => {
916
+ throw new Error("Not implemented");
883
917
  },
884
918
  append: async () => {
919
+ throw new Error("Not implemented");
885
920
  },
886
921
  stop: () => {
922
+ throw new Error("Not implemented");
887
923
  }
888
924
  }));
889
925
  const useComposer = (0, import_zustand2.create)()(() => ({
890
926
  isEditing: true,
891
927
  canCancel: false,
892
928
  value: "",
893
- setValue: () => {
929
+ setValue: (value) => {
930
+ useComposer.setState({ value });
894
931
  },
895
932
  edit: () => {
896
933
  throw new Error("Not implemented");
@@ -909,19 +946,24 @@ var useAIAssistantContext = () => {
909
946
  const useBranchObserver = (0, import_zustand2.create)()(() => ({
910
947
  getBranchState: () => ({
911
948
  branchId: 0,
912
- branchCount: 0
949
+ branchCount: 1
913
950
  }),
914
951
  switchToBranch: () => {
952
+ throw new Error("Not implemented");
915
953
  },
916
954
  editAt: async () => {
955
+ throw new Error("Not implemented");
917
956
  },
918
957
  reloadAt: async () => {
958
+ throw new Error("Not implemented");
919
959
  }
920
960
  }));
921
961
  return { useThread, useComposer, useBranchObserver };
922
962
  });
923
963
  return context;
924
964
  };
965
+
966
+ // src/vercel/VercelAIAssistantProvider.tsx
925
967
  var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
926
968
  var vercelToThreadMessage = (message) => {
927
969
  if (message.role !== "user" && message.role !== "assistant")
@@ -942,58 +984,118 @@ var vercelToCachedThreadMessages = (messages) => {
942
984
  return newMessage;
943
985
  });
944
986
  };
945
- var VercelAIChatAssistantProvider = ({ chat, children }) => {
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)(
987
+ var VercelAIAssistantProvider = ({
988
+ children,
989
+ ...rest
990
+ }) => {
991
+ const context = useDummyAIAssistantContext();
992
+ const vercel = "chat" in rest ? rest.chat : rest.assistant;
993
+ const messages = (0, import_react18.useMemo)(() => {
994
+ return vercelToCachedThreadMessages(vercel.messages);
995
+ }, [vercel.messages]);
996
+ const maybeReload = "reload" in vercel ? vercel.reload : null;
997
+ const reload = (0, import_react18.useCallback)(async () => {
998
+ if (!maybeReload)
999
+ throw new Error("Reload not supported");
1000
+ await maybeReload();
1001
+ }, [maybeReload]);
1002
+ const append = (0, import_react18.useCallback)(
954
1003
  async (message) => {
955
1004
  if (message.content[0]?.type !== "text") {
956
1005
  throw new Error("Only text content is currently supported");
957
1006
  }
958
- await chat.append({
1007
+ await vercel.append({
959
1008
  role: message.role,
960
1009
  content: message.content[0].text
961
1010
  });
962
1011
  },
963
- [chat.append]
1012
+ [vercel.append]
964
1013
  );
965
- const stop = (0, import_react17.useCallback)(() => {
966
- const lastMessage = chat.messages.at(-1);
967
- chat.stop();
1014
+ const stop = (0, import_react18.useCallback)(() => {
1015
+ const lastMessage = vercel.messages.at(-1);
1016
+ vercel.stop();
968
1017
  if (lastMessage?.role === "user") {
969
- chat.setInput(lastMessage.content);
1018
+ vercel.setInput(lastMessage.content);
970
1019
  }
971
- }, [chat.messages, chat.stop, chat.setInput]);
972
- (0, import_react17.useMemo)(() => {
1020
+ }, [vercel.messages, vercel.stop, vercel.setInput]);
1021
+ const isLoading = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
1022
+ (0, import_react18.useMemo)(() => {
973
1023
  context.useThread.setState(
974
1024
  {
975
1025
  messages,
976
- isLoading: chat.isLoading,
1026
+ isLoading,
977
1027
  reload,
978
1028
  append,
979
1029
  stop
980
1030
  },
981
1031
  true
982
1032
  );
983
- }, [context, messages, reload, append, stop, chat.isLoading]);
984
- (0, import_react17.useMemo)(() => {
1033
+ }, [context, messages, reload, append, stop, isLoading]);
1034
+ (0, import_react18.useMemo)(() => {
985
1035
  context.useComposer.setState({
986
- canCancel: chat.isLoading,
987
- value: chat.input,
988
- setValue: chat.setInput
1036
+ canCancel: isLoading,
1037
+ value: vercel.input,
1038
+ setValue: vercel.setInput
989
1039
  });
990
- }, [context, chat.isLoading, chat.input, chat.setInput]);
991
- const branches = useVercelAIBranches(chat);
992
- (0, import_react17.useMemo)(() => {
1040
+ }, [context, isLoading, vercel.input, vercel.setInput]);
1041
+ const branches = useVercelAIBranches(vercel);
1042
+ (0, import_react18.useMemo)(() => {
993
1043
  context.useBranchObserver.setState(branches, true);
994
1044
  }, [context, branches]);
995
1045
  return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
996
1046
  };
1047
+
1048
+ // src/vercel/VercelRSCAssistantProvider.tsx
1049
+ var import_react19 = require("react");
1050
+ var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
1051
+ var vercelToThreadMessage2 = (message) => {
1052
+ if (message.role !== "user" && message.role !== "assistant")
1053
+ throw new Error("Unsupported role");
1054
+ return {
1055
+ id: message.id,
1056
+ role: message.role,
1057
+ content: [{ type: "ui", display: message.display }]
1058
+ };
1059
+ };
1060
+ var vercelToCachedThreadMessages2 = (messages) => {
1061
+ return messages.map((m) => {
1062
+ const cached = ThreadMessageCache2.get(m);
1063
+ if (cached)
1064
+ return cached;
1065
+ const newMessage = vercelToThreadMessage2(m);
1066
+ ThreadMessageCache2.set(m, newMessage);
1067
+ return newMessage;
1068
+ });
1069
+ };
1070
+ var VercelRSCAssistantProvider = ({
1071
+ children,
1072
+ messages: vercelMessages,
1073
+ append: vercelAppend
1074
+ }) => {
1075
+ const context = useDummyAIAssistantContext();
1076
+ const messages = (0, import_react19.useMemo)(() => {
1077
+ return vercelToCachedThreadMessages2(vercelMessages);
1078
+ }, [vercelMessages]);
1079
+ const append = (0, import_react19.useCallback)(
1080
+ async (message) => {
1081
+ if (message.content[0]?.type !== "text") {
1082
+ throw new Error("Only text content is currently supported");
1083
+ }
1084
+ await vercelAppend({
1085
+ role: message.role,
1086
+ content: [{ type: "text", text: message.content[0].text }]
1087
+ });
1088
+ },
1089
+ [vercelAppend]
1090
+ );
1091
+ (0, import_react19.useMemo)(() => {
1092
+ context.useThread.setState({
1093
+ messages,
1094
+ append
1095
+ });
1096
+ }, [context, messages, append]);
1097
+ return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
1098
+ };
997
1099
  // Annotate the CommonJS export names for ESM import in node:
998
1100
  0 && (module.exports = {
999
1101
  ActionBarPrimitive,
@@ -1002,6 +1104,7 @@ var VercelAIChatAssistantProvider = ({ chat, children }) => {
1002
1104
  MessagePrimitive,
1003
1105
  ThreadPrimitive,
1004
1106
  VercelAIAssistantProvider,
1107
+ unstable_VercelRSCAssistantProvider,
1005
1108
  unstable_useMessageContext,
1006
1109
  useBeginMessageEdit,
1007
1110
  useCopyMessage,
package/dist/index.mjs CHANGED
@@ -63,12 +63,12 @@ var ThreadEmpty = ({ children }) => {
63
63
  };
64
64
 
65
65
  // src/primitives/thread/ThreadViewport.tsx
66
- import { forwardRef as forwardRef2, useRef as useRef2, useState } from "react";
66
+ import { composeEventHandlers } from "@radix-ui/primitive";
67
+ import { useComposedRefs } from "@radix-ui/react-compose-refs";
67
68
  import {
68
69
  Primitive as Primitive2
69
70
  } from "@radix-ui/react-primitive";
70
- import { useComposedRefs } from "@radix-ui/react-compose-refs";
71
- import { composeEventHandlers } from "@radix-ui/primitive";
71
+ import { forwardRef as forwardRef2, useRef as useRef2, useState } from "react";
72
72
 
73
73
  // src/utils/hooks/useOnResizeContent.tsx
74
74
  import { useLayoutEffect, useRef } from "react";
@@ -101,10 +101,8 @@ var useOnResizeContent = (ref, callback) => {
101
101
  mutationObserver.observe(el, { childList: true });
102
102
  for (const child of el.children) {
103
103
  resizeObserver.observe(child);
104
- console.log("observing child", child);
105
104
  }
106
105
  return () => {
107
- console.log("disconnecting");
108
106
  resizeObserver.disconnect();
109
107
  mutationObserver.disconnect();
110
108
  };
@@ -128,7 +126,6 @@ var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef)
128
126
  return;
129
127
  setIsAtBottom(div.scrollHeight - div.scrollTop <= div.clientHeight + 50);
130
128
  };
131
- console.log(isAtBottom);
132
129
  return /* @__PURE__ */ React.createElement(
133
130
  Primitive2.div,
134
131
  {
@@ -233,13 +230,16 @@ var useVercelAIBranches = (chat) => {
233
230
  },
234
231
  [data, chat.messages, chat.setMessages]
235
232
  );
233
+ const reloadMaybe = "reload" in chat ? chat.reload : void 0;
236
234
  const reloadAt = useCallback(
237
235
  async (message) => {
236
+ if (!reloadMaybe)
237
+ throw new Error("Reload not supported by Vercel AI SDK's useAssistant");
238
238
  const newMessages = sliceMessagesUntil(chat.messages, message);
239
239
  chat.setMessages(newMessages);
240
- await chat.reload();
240
+ await reloadMaybe();
241
241
  },
242
- [chat.messages, chat.setMessages, chat.reload]
242
+ [chat.messages, chat.setMessages, reloadMaybe]
243
243
  );
244
244
  const editAt = useCallback(
245
245
  async (message, newMessage) => {
@@ -460,12 +460,41 @@ var MessageIf = ({ children, ...query }) => {
460
460
  };
461
461
 
462
462
  // src/primitives/message/MessageContent.tsx
463
- var MessageContent = () => {
463
+ var defaultComponents = {
464
+ Text: ({ part }) => /* @__PURE__ */ React.createElement(React.Fragment, null, part.text),
465
+ Image: () => null,
466
+ UI: ({ part }) => part.display,
467
+ tools: {
468
+ Fallback: () => null
469
+ }
470
+ };
471
+ var MessageContent = ({
472
+ components: {
473
+ Text = defaultComponents.Text,
474
+ Image = defaultComponents.Image,
475
+ UI = defaultComponents.UI,
476
+ tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
477
+ } = {}
478
+ }) => {
464
479
  const { useMessage } = useMessageContext();
465
480
  const content = useMessage((s) => s.message.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);
481
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, content.map((part, i) => {
482
+ const key = i;
483
+ switch (part.type) {
484
+ case "text":
485
+ return /* @__PURE__ */ React.createElement(Text, { key, part });
486
+ case "image":
487
+ return /* @__PURE__ */ React.createElement(Image, { key, part });
488
+ case "ui":
489
+ return /* @__PURE__ */ React.createElement(UI, { key, part });
490
+ case "tool-call": {
491
+ const Tool = by_name[part.name] || Fallback;
492
+ return /* @__PURE__ */ React.createElement(Tool, { key, part });
493
+ }
494
+ default:
495
+ return null;
496
+ }
497
+ }));
469
498
  };
470
499
 
471
500
  // src/primitives/thread/ThreadMessages.tsx
@@ -855,25 +884,32 @@ var useBeginMessageEdit = () => {
855
884
  var ActionBarEdit = createActionButton(useBeginMessageEdit);
856
885
 
857
886
  // src/vercel/VercelAIAssistantProvider.tsx
858
- import { useCallback as useCallback2, useMemo as useMemo4, useState as useState3 } from "react";
887
+ import { useCallback as useCallback2, useMemo as useMemo4 } from "react";
888
+
889
+ // src/vercel/useDummyAIAssistantContext.tsx
890
+ import { useState as useState3 } from "react";
859
891
  import { create as create2 } from "zustand";
860
- var useAIAssistantContext = () => {
892
+ var useDummyAIAssistantContext = () => {
861
893
  const [context] = useState3(() => {
862
894
  const useThread = create2()(() => ({
863
895
  messages: [],
864
896
  isLoading: false,
865
897
  reload: async () => {
898
+ throw new Error("Not implemented");
866
899
  },
867
900
  append: async () => {
901
+ throw new Error("Not implemented");
868
902
  },
869
903
  stop: () => {
904
+ throw new Error("Not implemented");
870
905
  }
871
906
  }));
872
907
  const useComposer = create2()(() => ({
873
908
  isEditing: true,
874
909
  canCancel: false,
875
910
  value: "",
876
- setValue: () => {
911
+ setValue: (value) => {
912
+ useComposer.setState({ value });
877
913
  },
878
914
  edit: () => {
879
915
  throw new Error("Not implemented");
@@ -892,19 +928,24 @@ var useAIAssistantContext = () => {
892
928
  const useBranchObserver = create2()(() => ({
893
929
  getBranchState: () => ({
894
930
  branchId: 0,
895
- branchCount: 0
931
+ branchCount: 1
896
932
  }),
897
933
  switchToBranch: () => {
934
+ throw new Error("Not implemented");
898
935
  },
899
936
  editAt: async () => {
937
+ throw new Error("Not implemented");
900
938
  },
901
939
  reloadAt: async () => {
940
+ throw new Error("Not implemented");
902
941
  }
903
942
  }));
904
943
  return { useThread, useComposer, useBranchObserver };
905
944
  });
906
945
  return context;
907
946
  };
947
+
948
+ // src/vercel/VercelAIAssistantProvider.tsx
908
949
  var ThreadMessageCache = /* @__PURE__ */ new WeakMap();
909
950
  var vercelToThreadMessage = (message) => {
910
951
  if (message.role !== "user" && message.role !== "assistant")
@@ -925,65 +966,129 @@ var vercelToCachedThreadMessages = (messages) => {
925
966
  return newMessage;
926
967
  });
927
968
  };
928
- var VercelAIChatAssistantProvider = ({ chat, children }) => {
929
- const context = useAIAssistantContext();
969
+ var VercelAIAssistantProvider = ({
970
+ children,
971
+ ...rest
972
+ }) => {
973
+ const context = useDummyAIAssistantContext();
974
+ const vercel = "chat" in rest ? rest.chat : rest.assistant;
930
975
  const messages = useMemo4(() => {
931
- return vercelToCachedThreadMessages(chat.messages);
932
- }, [chat.messages]);
976
+ return vercelToCachedThreadMessages(vercel.messages);
977
+ }, [vercel.messages]);
978
+ const maybeReload = "reload" in vercel ? vercel.reload : null;
933
979
  const reload = useCallback2(async () => {
934
- await chat.reload();
935
- }, [chat.reload]);
980
+ if (!maybeReload)
981
+ throw new Error("Reload not supported");
982
+ await maybeReload();
983
+ }, [maybeReload]);
936
984
  const append = useCallback2(
937
985
  async (message) => {
938
986
  if (message.content[0]?.type !== "text") {
939
987
  throw new Error("Only text content is currently supported");
940
988
  }
941
- await chat.append({
989
+ await vercel.append({
942
990
  role: message.role,
943
991
  content: message.content[0].text
944
992
  });
945
993
  },
946
- [chat.append]
994
+ [vercel.append]
947
995
  );
948
996
  const stop = useCallback2(() => {
949
- const lastMessage = chat.messages.at(-1);
950
- chat.stop();
997
+ const lastMessage = vercel.messages.at(-1);
998
+ vercel.stop();
951
999
  if (lastMessage?.role === "user") {
952
- chat.setInput(lastMessage.content);
1000
+ vercel.setInput(lastMessage.content);
953
1001
  }
954
- }, [chat.messages, chat.stop, chat.setInput]);
1002
+ }, [vercel.messages, vercel.stop, vercel.setInput]);
1003
+ const isLoading = "isLoading" in vercel ? vercel.isLoading : vercel.status === "in_progress";
955
1004
  useMemo4(() => {
956
1005
  context.useThread.setState(
957
1006
  {
958
1007
  messages,
959
- isLoading: chat.isLoading,
1008
+ isLoading,
960
1009
  reload,
961
1010
  append,
962
1011
  stop
963
1012
  },
964
1013
  true
965
1014
  );
966
- }, [context, messages, reload, append, stop, chat.isLoading]);
1015
+ }, [context, messages, reload, append, stop, isLoading]);
967
1016
  useMemo4(() => {
968
1017
  context.useComposer.setState({
969
- canCancel: chat.isLoading,
970
- value: chat.input,
971
- setValue: chat.setInput
1018
+ canCancel: isLoading,
1019
+ value: vercel.input,
1020
+ setValue: vercel.setInput
972
1021
  });
973
- }, [context, chat.isLoading, chat.input, chat.setInput]);
974
- const branches = useVercelAIBranches(chat);
1022
+ }, [context, isLoading, vercel.input, vercel.setInput]);
1023
+ const branches = useVercelAIBranches(vercel);
975
1024
  useMemo4(() => {
976
1025
  context.useBranchObserver.setState(branches, true);
977
1026
  }, [context, branches]);
978
1027
  return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
979
1028
  };
1029
+
1030
+ // src/vercel/VercelRSCAssistantProvider.tsx
1031
+ import {
1032
+ useCallback as useCallback3,
1033
+ useMemo as useMemo5
1034
+ } from "react";
1035
+ var ThreadMessageCache2 = /* @__PURE__ */ new WeakMap();
1036
+ var vercelToThreadMessage2 = (message) => {
1037
+ if (message.role !== "user" && message.role !== "assistant")
1038
+ throw new Error("Unsupported role");
1039
+ return {
1040
+ id: message.id,
1041
+ role: message.role,
1042
+ content: [{ type: "ui", display: message.display }]
1043
+ };
1044
+ };
1045
+ var vercelToCachedThreadMessages2 = (messages) => {
1046
+ return messages.map((m) => {
1047
+ const cached = ThreadMessageCache2.get(m);
1048
+ if (cached)
1049
+ return cached;
1050
+ const newMessage = vercelToThreadMessage2(m);
1051
+ ThreadMessageCache2.set(m, newMessage);
1052
+ return newMessage;
1053
+ });
1054
+ };
1055
+ var VercelRSCAssistantProvider = ({
1056
+ children,
1057
+ messages: vercelMessages,
1058
+ append: vercelAppend
1059
+ }) => {
1060
+ const context = useDummyAIAssistantContext();
1061
+ const messages = useMemo5(() => {
1062
+ return vercelToCachedThreadMessages2(vercelMessages);
1063
+ }, [vercelMessages]);
1064
+ const append = useCallback3(
1065
+ async (message) => {
1066
+ if (message.content[0]?.type !== "text") {
1067
+ throw new Error("Only text content is currently supported");
1068
+ }
1069
+ await vercelAppend({
1070
+ role: message.role,
1071
+ content: [{ type: "text", text: message.content[0].text }]
1072
+ });
1073
+ },
1074
+ [vercelAppend]
1075
+ );
1076
+ useMemo5(() => {
1077
+ context.useThread.setState({
1078
+ messages,
1079
+ append
1080
+ });
1081
+ }, [context, messages, append]);
1082
+ return /* @__PURE__ */ React.createElement(AssistantContext.Provider, { value: context }, children);
1083
+ };
980
1084
  export {
981
1085
  actionBar_exports as ActionBarPrimitive,
982
1086
  branchPicker_exports as BranchPickerPrimitive,
983
1087
  composer_exports as ComposerPrimitive,
984
1088
  message_exports as MessagePrimitive,
985
1089
  thread_exports as ThreadPrimitive,
986
- VercelAIChatAssistantProvider as VercelAIAssistantProvider,
1090
+ VercelAIAssistantProvider,
1091
+ VercelRSCAssistantProvider as unstable_VercelRSCAssistantProvider,
987
1092
  useMessageContext as unstable_useMessageContext,
988
1093
  useBeginMessageEdit,
989
1094
  useCopyMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": {
@@ -28,7 +28,7 @@
28
28
  "@radix-ui/react-compose-refs": "^1.0.1",
29
29
  "@radix-ui/react-primitive": "^1.0.3",
30
30
  "@radix-ui/react-slot": "^1.0.2",
31
- "ai": "^3.1.10",
31
+ "ai": "^3.1.12",
32
32
  "react-textarea-autosize": "^8.5.3",
33
33
  "zustand": "^4.5.2"
34
34
  },