@assistant-ui/react 0.0.6 → 0.0.7

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