@assistant-ui/react 0.0.16 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -38,6 +38,11 @@ __export(src_exports, {
38
38
  ThreadPrimitive: () => thread_exports,
39
39
  VercelAIAssistantProvider: () => VercelAIAssistantProvider,
40
40
  VercelRSCAssistantProvider: () => VercelRSCAssistantProvider,
41
+ unstable_AssistantProvider: () => AssistantProvider,
42
+ unstable_VercelModelAdapter: () => VercelModelAdapter,
43
+ unstable_getVercelMessage: () => getVercelMessage,
44
+ unstable_getVercelRSCMessage: () => getVercelRSCMessage,
45
+ unstable_useLocalRuntime: () => useLocalRuntime,
41
46
  unstable_useMessageContext: () => useMessageContext,
42
47
  useBeginMessageEdit: () => useBeginMessageEdit,
43
48
  useCopyMessage: () => useCopyMessage,
@@ -110,15 +115,15 @@ var import_react_primitive2 = require("@radix-ui/react-primitive");
110
115
  var import_react5 = require("react");
111
116
 
112
117
  // src/utils/hooks/useOnResizeContent.tsx
118
+ var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
113
119
  var import_react3 = require("react");
114
120
  var useOnResizeContent = (ref, callback) => {
115
- const callbackRef = (0, import_react3.useRef)(callback);
116
- callbackRef.current = callback;
121
+ const callbackRef = (0, import_react_use_callback_ref.useCallbackRef)(callback);
117
122
  (0, import_react3.useEffect)(() => {
118
123
  const el = ref.current;
119
124
  if (!el) return;
120
125
  const resizeObserver = new ResizeObserver(() => {
121
- callbackRef.current();
126
+ callbackRef();
122
127
  });
123
128
  const mutationObserver = new MutationObserver((mutations) => {
124
129
  for (const mutation of mutations) {
@@ -133,7 +138,7 @@ var useOnResizeContent = (ref, callback) => {
133
138
  }
134
139
  }
135
140
  }
136
- callbackRef.current();
141
+ callbackRef();
137
142
  });
138
143
  resizeObserver.observe(el);
139
144
  mutationObserver.observe(el, { childList: true });
@@ -144,20 +149,20 @@ var useOnResizeContent = (ref, callback) => {
144
149
  resizeObserver.disconnect();
145
150
  mutationObserver.disconnect();
146
151
  };
147
- }, [ref.current]);
152
+ }, [ref.current, callbackRef]);
148
153
  };
149
154
 
150
155
  // src/utils/hooks/useOnScrollToBottom.tsx
156
+ var import_react_use_callback_ref2 = require("@radix-ui/react-use-callback-ref");
151
157
  var import_react4 = require("react");
152
158
  var useOnScrollToBottom = (callback) => {
153
- const callbackRef = (0, import_react4.useRef)(callback);
154
- callbackRef.current = callback;
159
+ const callbackRef = (0, import_react_use_callback_ref2.useCallbackRef)(callback);
155
160
  const { useViewport } = useAssistantContext();
156
161
  (0, import_react4.useEffect)(() => {
157
162
  return useViewport.getState().onScrollToBottom(() => {
158
- callbackRef.current();
163
+ callbackRef();
159
164
  });
160
- }, [useViewport]);
165
+ }, [useViewport, callbackRef]);
161
166
  };
162
167
 
163
168
  // src/primitives/thread/ThreadViewport.tsx
@@ -253,7 +258,7 @@ var message_exports = {};
253
258
  __export(message_exports, {
254
259
  Content: () => MessageContent,
255
260
  If: () => MessageIf,
256
- Loading: () => MessageLoading,
261
+ InProgress: () => MessageInProgress,
257
262
  Provider: () => MessageProvider,
258
263
  Root: () => MessageRoot
259
264
  });
@@ -333,11 +338,11 @@ var useMessageContext2 = () => {
333
338
  parentId: null,
334
339
  branches: [],
335
340
  isLast: false,
336
- loadingIndicator: null,
341
+ inProgressIndicator: null,
337
342
  isCopied: false,
338
343
  isHovering: false,
339
- setLoadingIndicator: (value) => {
340
- set({ loadingIndicator: value });
344
+ setInProgressIndicator: (value) => {
345
+ set({ inProgressIndicator: value });
341
346
  },
342
347
  setIsCopied: (value) => {
343
348
  set({ isCopied: value });
@@ -478,15 +483,15 @@ var useContentPartContext = () => {
478
483
  return context;
479
484
  };
480
485
 
481
- // src/primitives/contentPart/ContentPartLoadingIndicator.tsx
482
- var ContentPartLoadingIndicator = () => {
486
+ // src/primitives/contentPart/ContentPartInProgressIndicator.tsx
487
+ var ContentPartInProgressIndicator = () => {
483
488
  const { useMessage } = useMessageContext();
484
489
  const { useContentPart } = useContentPartContext();
485
- const loadingIndicator = useCombinedStore(
490
+ const indicator = useCombinedStore(
486
491
  [useMessage, useContentPart],
487
- (m, c) => c.isLoading ? m.loadingIndicator : null
492
+ (m, c) => c.status === "in_progress" ? m.inProgressIndicator : null
488
493
  );
489
- return loadingIndicator;
494
+ return indicator;
490
495
  };
491
496
 
492
497
  // src/primitives/contentPart/ContentPartProvider.tsx
@@ -497,7 +502,7 @@ var useContentPartContext2 = () => {
497
502
  const [context] = (0, import_react13.useState)(() => {
498
503
  const useContentPart = (0, import_zustand3.create)(() => ({
499
504
  part: null,
500
- isLoading: false
505
+ status: "done"
501
506
  }));
502
507
  return { useContentPart };
503
508
  });
@@ -505,7 +510,7 @@ var useContentPartContext2 = () => {
505
510
  };
506
511
  var ContentPartProvider = ({
507
512
  part,
508
- isLoading,
513
+ status,
509
514
  children
510
515
  }) => {
511
516
  const context = useContentPartContext2();
@@ -513,11 +518,11 @@ var ContentPartProvider = ({
513
518
  context.useContentPart.setState(
514
519
  {
515
520
  part,
516
- isLoading
521
+ status
517
522
  },
518
523
  true
519
524
  );
520
- }, [context, part, isLoading]);
525
+ }, [context, part, status]);
521
526
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ContentPartContext.Provider, { value: context, children });
522
527
  };
523
528
 
@@ -526,7 +531,7 @@ var import_jsx_runtime7 = require("react/jsx-runtime");
526
531
  var defaultComponents = {
527
532
  Text: ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
528
533
  part.text,
529
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ContentPartLoadingIndicator, {})
534
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ContentPartInProgressIndicator, {})
530
535
  ] }),
531
536
  Image: () => null,
532
537
  UI: ({ part }) => part.display,
@@ -542,13 +547,10 @@ var MessageContent = ({
542
547
  tools: { by_name = {}, Fallback = defaultComponents.tools.Fallback } = {}
543
548
  } = {}
544
549
  }) => {
545
- const { useThread } = useAssistantContext();
546
550
  const { useMessage } = useMessageContext();
547
- const content = useMessage((s) => s.message.content);
548
- const isLoading = useCombinedStore(
549
- [useThread, useMessage],
550
- (t, s) => s.isLast && t.isRunning
551
- );
551
+ const message = useMessage((s) => s.message);
552
+ const content = message.content;
553
+ const status = message.role === "assistant" ? message.status : "done";
552
554
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: content.map((part, i) => {
553
555
  const key = i;
554
556
  const type = part.type;
@@ -575,7 +577,7 @@ var MessageContent = ({
575
577
  ContentPartProvider,
576
578
  {
577
579
  part,
578
- isLoading: i === content.length - 1 && isLoading,
580
+ status: i === content.length - 1 ? status : "done",
579
581
  children: component
580
582
  },
581
583
  key
@@ -583,14 +585,14 @@ var MessageContent = ({
583
585
  }) });
584
586
  };
585
587
 
586
- // src/primitives/message/MessageLoading.tsx
588
+ // src/primitives/message/MessageInProgress.tsx
587
589
  var import_react_primitive4 = require("@radix-ui/react-primitive");
588
590
  var import_react14 = require("react");
589
591
  var import_jsx_runtime8 = require("react/jsx-runtime");
590
- var MessageLoading = (0, import_react14.forwardRef)((props, ref) => {
592
+ var MessageInProgress = (0, import_react14.forwardRef)((props, ref) => {
591
593
  const { useMessage } = useMessageContext();
592
594
  (0, import_react14.useMemo)(() => {
593
- useMessage.getState().setLoadingIndicator(/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_primitive4.Primitive.div, { ...props, ref }));
595
+ useMessage.getState().setInProgressIndicator(/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_primitive4.Primitive.div, { ...props, ref }));
594
596
  }, [useMessage, props, ref]);
595
597
  return null;
596
598
  });
@@ -892,7 +894,6 @@ var useGoToPreviousBranch = () => {
892
894
  const { message, branches } = useMessage.getState();
893
895
  useThread.getState().switchToBranch(
894
896
  branches[branches.indexOf(message.id) - 1]
895
- // TODO probably there's a more elegant way to do this
896
897
  );
897
898
  };
898
899
  };
@@ -1025,7 +1026,7 @@ var ActionBarEdit = createActionButton(useBeginMessageEdit);
1025
1026
  // src/primitives/contentPart/index.ts
1026
1027
  var contentPart_exports = {};
1027
1028
  __export(contentPart_exports, {
1028
- LoadingIndicator: () => ContentPartLoadingIndicator,
1029
+ InProgressIndicator: () => ContentPartInProgressIndicator,
1029
1030
  Provider: () => ContentPartProvider
1030
1031
  });
1031
1032
 
@@ -1089,9 +1090,10 @@ var useDummyAIAssistantContext = () => {
1089
1090
  };
1090
1091
 
1091
1092
  // src/adapters/vercel/useVercelAIThreadState.tsx
1093
+ var import_react_use_callback_ref3 = require("@radix-ui/react-use-callback-ref");
1092
1094
  var import_react25 = require("react");
1093
1095
 
1094
- // src/adapters/MessageRepository.tsx
1096
+ // src/adapters/idUtils.tsx
1095
1097
  var import_non_secure = require("nanoid/non-secure");
1096
1098
  var generateId = (0, import_non_secure.customAlphabet)(
1097
1099
  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
@@ -1099,7 +1101,8 @@ var generateId = (0, import_non_secure.customAlphabet)(
1099
1101
  );
1100
1102
  var optimisticPrefix = "__optimistic__";
1101
1103
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1102
- var isOptimisticId = (id) => id.startsWith(optimisticPrefix);
1104
+
1105
+ // src/adapters/MessageRepository.tsx
1103
1106
  var findHead = (message) => {
1104
1107
  if (message.next) return findHead(message.next);
1105
1108
  return message;
@@ -1111,15 +1114,6 @@ var MessageRepository = class {
1111
1114
  root = {
1112
1115
  children: []
1113
1116
  };
1114
- getFallbackChild(p) {
1115
- const childId = p.children.at(-1);
1116
- const child = childId ? this.messages.get(childId) : null;
1117
- if (child === void 0)
1118
- throw new Error(
1119
- "MessageRepository(getFallbackChild): Child message not found. This is likely an internal bug in assistant-ui."
1120
- );
1121
- return child;
1122
- }
1123
1117
  performOp(newParent, child, operation) {
1124
1118
  const parentOrRoot = child.prev ?? this.root;
1125
1119
  const newParentOrRoot = newParent ?? this.root;
@@ -1129,7 +1123,14 @@ var MessageRepository = class {
1129
1123
  (m) => m !== child.current.id
1130
1124
  );
1131
1125
  if (child.prev?.next === child) {
1132
- child.prev.next = this.getFallbackChild(child.prev);
1126
+ const fallbackId = child.prev.children.at(-1);
1127
+ const fallback = fallbackId ? this.messages.get(fallbackId) : null;
1128
+ if (fallback === void 0) {
1129
+ throw new Error(
1130
+ "MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui."
1131
+ );
1132
+ }
1133
+ child.prev.next = fallback;
1133
1134
  }
1134
1135
  }
1135
1136
  if (operation !== "cut") {
@@ -1183,18 +1184,19 @@ var MessageRepository = class {
1183
1184
  this.addOrUpdateMessage(parentId, {
1184
1185
  ...message,
1185
1186
  id: optimisticId,
1186
- createdAt: /* @__PURE__ */ new Date()
1187
+ createdAt: /* @__PURE__ */ new Date(),
1188
+ ...message.role === "assistant" ? { status: "in_progress" } : void 0
1187
1189
  });
1188
1190
  return optimisticId;
1189
1191
  }
1190
- deleteMessage(messageId, newParentId) {
1192
+ deleteMessage(messageId, replacementId) {
1191
1193
  const message = this.messages.get(messageId);
1192
- const newParent = newParentId ? this.messages.get(newParentId) : null;
1194
+ const replacement = replacementId ? this.messages.get(replacementId) : null;
1193
1195
  if (!message)
1194
1196
  throw new Error(
1195
1197
  "MessageRepository(deleteMessage): Optimistic message not found. This is likely an internal bug in assistant-ui."
1196
1198
  );
1197
- if (newParent === void 0)
1199
+ if (replacement === void 0)
1198
1200
  throw new Error(
1199
1201
  "MessageRepository(deleteMessage): New message not found. This is likely an internal bug in assistant-ui."
1200
1202
  );
@@ -1204,11 +1206,11 @@ var MessageRepository = class {
1204
1206
  throw new Error(
1205
1207
  "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
1206
1208
  );
1207
- this.performOp(newParent, childMessage, "relink");
1209
+ this.performOp(replacement, childMessage, "relink");
1208
1210
  }
1209
1211
  this.messages.delete(messageId);
1210
1212
  if (this.head === message) {
1211
- this.head = this.getFallbackChild(message.prev ?? this.root);
1213
+ this.head = replacement;
1212
1214
  }
1213
1215
  this.performOp(null, message, "cut");
1214
1216
  }
@@ -1251,50 +1253,68 @@ var MessageRepository = class {
1251
1253
  }
1252
1254
  };
1253
1255
 
1254
- // src/adapters/ThreadMessageConverter.tsx
1256
+ // src/adapters/ThreadMessageConverter.ts
1255
1257
  var ThreadMessageConverter = class {
1256
- constructor(converter2) {
1257
- this.converter = converter2;
1258
- }
1259
1258
  cache = /* @__PURE__ */ new WeakMap();
1260
- convertMessages(messages) {
1259
+ convertMessages(converter, messages) {
1261
1260
  return messages.map((m) => {
1262
1261
  const cached = this.cache.get(m);
1263
- if (cached) return cached;
1264
- const newMessage = this.converter(m);
1262
+ const newMessage = converter(m, cached);
1265
1263
  this.cache.set(m, newMessage);
1266
1264
  return newMessage;
1267
1265
  });
1268
1266
  }
1269
1267
  };
1270
1268
 
1269
+ // src/adapters/vercel/VercelThreadMessage.tsx
1270
+ var symbolInnerMessage = Symbol("innerMessage");
1271
+ var symbolInnerRSCMessage = Symbol("innerRSCMessage");
1272
+ var getVercelMessage = (message) => {
1273
+ return message[symbolInnerMessage];
1274
+ };
1275
+ var getVercelRSCMessage = (message) => {
1276
+ return message[symbolInnerRSCMessage];
1277
+ };
1278
+
1271
1279
  // src/adapters/vercel/useVercelAIThreadState.tsx
1272
- var vercelToThreadMessage = (message) => {
1273
- if (message.role !== "user" && message.role !== "assistant")
1274
- throw new Error(
1275
- `You have a message with an unsupported role. The role ${message.role} is not supported.`
1276
- );
1277
- return {
1280
+ var vercelToThreadMessage = (message, status) => {
1281
+ const common = {
1278
1282
  id: message.id,
1279
- role: message.role,
1280
- content: [
1281
- ...message.content ? [{ type: "text", text: message.content }] : [],
1282
- ...message.toolInvocations?.map((t) => ({
1283
- type: "tool-call",
1284
- name: t.toolName,
1285
- args: t.args,
1286
- result: "result" in t ? t.result : void 0
1287
- })) ?? []
1288
- ],
1289
- // ignore type mismatch for now
1290
1283
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1291
- innerMessage: message
1284
+ [symbolInnerMessage]: message
1292
1285
  };
1286
+ switch (message.role) {
1287
+ case "user":
1288
+ return {
1289
+ ...common,
1290
+ role: "user",
1291
+ content: [{ type: "text", text: message.content }]
1292
+ };
1293
+ case "assistant":
1294
+ return {
1295
+ ...common,
1296
+ role: "assistant",
1297
+ content: [
1298
+ ...message.content ? [{ type: "text", text: message.content }] : [],
1299
+ ...message.toolInvocations?.map(
1300
+ (t) => ({
1301
+ type: "tool-call",
1302
+ name: t.toolName,
1303
+ args: t.args,
1304
+ result: "result" in t ? t.result : void 0
1305
+ })
1306
+ ) ?? []
1307
+ ],
1308
+ status
1309
+ };
1310
+ default:
1311
+ throw new Error(
1312
+ `You have a message with an unsupported role. The role ${message.role} is not supported.`
1313
+ );
1314
+ }
1293
1315
  };
1294
- var converter = new ThreadMessageConverter(vercelToThreadMessage);
1295
1316
  var sliceMessagesUntil = (messages, messageId) => {
1296
1317
  if (messageId == null) return [];
1297
- if (isOptimisticId(messageId)) return messages;
1298
1318
  const messageIdx = messages.findIndex((m) => m.id === messageId);
1299
1319
  if (messageIdx === -1)
1300
1320
  throw new Error(
@@ -1311,12 +1331,18 @@ var getIsRunning = (vercel) => {
1311
1331
  };
1312
1332
  var useVercelAIThreadState = (vercel) => {
1313
1333
  const [data] = (0, import_react25.useState)(() => new MessageRepository());
1314
- const vercelRef = (0, import_react25.useRef)(vercel);
1315
- vercelRef.current = vercel;
1316
- const isRunning = getIsRunning(vercelRef.current);
1334
+ const isRunning = getIsRunning(vercel);
1335
+ const converter = (0, import_react25.useMemo)(() => new ThreadMessageConverter(), []);
1317
1336
  const assistantOptimisticIdRef = (0, import_react25.useRef)(null);
1318
1337
  const messages = (0, import_react25.useMemo)(() => {
1319
- const vm = converter.convertMessages(vercel.messages);
1338
+ const lastMessageId = vercel.messages.at(-1)?.id;
1339
+ const convertCallback = (message, cache) => {
1340
+ const status = lastMessageId === message.id && isRunning ? "in_progress" : "done";
1341
+ if (cache && (cache.role === "user" || cache.status === status))
1342
+ return cache;
1343
+ return vercelToThreadMessage(message, status);
1344
+ };
1345
+ const vm = converter.convertMessages(convertCallback, vercel.messages);
1320
1346
  for (let i = 0; i < vm.length; i++) {
1321
1347
  const message = vm[i];
1322
1348
  const parent = vm[i - 1];
@@ -1337,55 +1363,46 @@ var useVercelAIThreadState = (vercel) => {
1337
1363
  }
1338
1364
  data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
1339
1365
  return data.getMessages();
1340
- }, [data, isRunning, vercel.messages]);
1366
+ }, [converter, data, isRunning, vercel.messages]);
1341
1367
  const getBranches2 = (0, import_react25.useCallback)(
1342
1368
  (messageId) => {
1343
1369
  return data.getBranches(messageId);
1344
1370
  },
1345
1371
  [data]
1346
1372
  );
1347
- const switchToBranch2 = (0, import_react25.useCallback)(
1348
- (messageId) => {
1349
- data.switchToBranch(messageId);
1350
- vercelRef.current.setMessages(
1351
- data.getMessages().filter((m) => !isOptimisticId(m.id)).map((m) => m.innerMessage)
1352
- );
1353
- },
1354
- [data]
1355
- );
1356
- const startRun = (0, import_react25.useCallback)(async (parentId) => {
1357
- const reloadMaybe = "reload" in vercelRef.current ? vercelRef.current.reload : void 0;
1373
+ const switchToBranch2 = (0, import_react_use_callback_ref3.useCallbackRef)((messageId) => {
1374
+ data.switchToBranch(messageId);
1375
+ vercel.setMessages(
1376
+ data.getMessages().map(getVercelMessage).filter((m) => m != null)
1377
+ );
1378
+ });
1379
+ const startRun = (0, import_react_use_callback_ref3.useCallbackRef)(async (parentId) => {
1380
+ const reloadMaybe = "reload" in vercel ? vercel.reload : void 0;
1358
1381
  if (!reloadMaybe)
1359
1382
  throw new Error(
1360
1383
  "Reload is not supported by Vercel AI SDK's useAssistant."
1361
1384
  );
1362
- const newMessages = sliceMessagesUntil(
1363
- vercelRef.current.messages,
1364
- parentId
1365
- );
1366
- vercelRef.current.setMessages(newMessages);
1385
+ const newMessages = sliceMessagesUntil(vercel.messages, parentId);
1386
+ vercel.setMessages(newMessages);
1367
1387
  await reloadMaybe();
1368
- }, []);
1369
- const append = (0, import_react25.useCallback)(async (message) => {
1388
+ });
1389
+ const append = (0, import_react_use_callback_ref3.useCallbackRef)(async (message) => {
1370
1390
  if (message.content.length !== 1 || message.content[0]?.type !== "text")
1371
1391
  throw new Error("Only text content is supported by Vercel AI SDK.");
1372
- const newMessages = sliceMessagesUntil(
1373
- vercelRef.current.messages,
1374
- message.parentId
1375
- );
1376
- vercelRef.current.setMessages(newMessages);
1377
- await vercelRef.current.append({
1392
+ const newMessages = sliceMessagesUntil(vercel.messages, message.parentId);
1393
+ vercel.setMessages(newMessages);
1394
+ await vercel.append({
1378
1395
  role: "user",
1379
1396
  content: message.content[0].text
1380
1397
  });
1381
- }, []);
1382
- const cancelRun2 = (0, import_react25.useCallback)(() => {
1383
- const lastMessage = vercelRef.current.messages.at(-1);
1384
- vercelRef.current.stop();
1398
+ });
1399
+ const cancelRun2 = (0, import_react_use_callback_ref3.useCallbackRef)(() => {
1400
+ const lastMessage = vercel.messages.at(-1);
1401
+ vercel.stop();
1385
1402
  if (lastMessage?.role === "user") {
1386
- vercelRef.current.setInput(lastMessage.content);
1403
+ vercel.setInput(lastMessage.content);
1387
1404
  }
1388
- }, []);
1405
+ });
1389
1406
  return (0, import_react25.useMemo)(
1390
1407
  () => ({
1391
1408
  isRunning,
@@ -1432,12 +1449,15 @@ var VercelAIAssistantProvider = ({
1432
1449
  // src/adapters/vercel/VercelRSCAssistantProvider.tsx
1433
1450
  var import_react27 = require("react");
1434
1451
  var import_jsx_runtime22 = require("react/jsx-runtime");
1435
- var vercelToThreadMessage2 = (message) => {
1452
+ var vercelToThreadMessage2 = (converter, rawMessage) => {
1453
+ const message = converter(rawMessage);
1436
1454
  return {
1437
1455
  id: message.id,
1438
1456
  role: message.role,
1439
1457
  content: [{ type: "ui", display: message.display }],
1440
- createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
1458
+ createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
1459
+ ...{ status: "done" },
1460
+ [symbolInnerRSCMessage]: rawMessage
1441
1461
  };
1442
1462
  };
1443
1463
  var EMPTY_BRANCHES = [];
@@ -1470,15 +1490,17 @@ var VercelRSCAssistantProvider = ({
1470
1490
  setIsRunning(true);
1471
1491
  return callback.finally(() => setIsRunning(false));
1472
1492
  }, []);
1473
- const converter2 = (0, import_react27.useMemo)(() => {
1493
+ const [converter, convertCallback] = (0, import_react27.useMemo)(() => {
1474
1494
  const rscConverter = convertMessage ?? ((m) => m);
1475
- return new ThreadMessageConverter((m) => {
1476
- return vercelToThreadMessage2(rscConverter(m));
1477
- });
1495
+ const convertCallback2 = (m, cache) => {
1496
+ if (cache) return cache;
1497
+ return vercelToThreadMessage2(rscConverter, m);
1498
+ };
1499
+ return [new ThreadMessageConverter(), convertCallback2];
1478
1500
  }, [convertMessage]);
1479
1501
  const messages = (0, import_react27.useMemo)(() => {
1480
- return converter2.convertMessages(vercelMessages);
1481
- }, [converter2, vercelMessages]);
1502
+ return converter.convertMessages(convertCallback, vercelMessages);
1503
+ }, [converter, convertCallback, vercelMessages]);
1482
1504
  const append = (0, import_react27.useCallback)(
1483
1505
  async (message) => {
1484
1506
  if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
@@ -1519,6 +1541,259 @@ var VercelRSCAssistantProvider = ({
1519
1541
  }, [context, messages, isRunning, append, startRun]);
1520
1542
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(AssistantContext.Provider, { value: context, children });
1521
1543
  };
1544
+
1545
+ // src/adapters/core/utils/useAssistantContext.tsx
1546
+ var import_react28 = require("react");
1547
+ var import_zustand6 = require("zustand");
1548
+
1549
+ // src/adapters/core/utils/AssistantMessageRepository.tsx
1550
+ var AssistantMessageRepository = class {
1551
+ constructor(flushCallback) {
1552
+ this.flushCallback = flushCallback;
1553
+ }
1554
+ repository = new MessageRepository();
1555
+ getBranches(messageId) {
1556
+ return this.repository.getBranches(messageId);
1557
+ }
1558
+ withModifications(callback) {
1559
+ const res = callback(this.repository);
1560
+ this.flushCallback(this.repository.getMessages());
1561
+ return res;
1562
+ }
1563
+ };
1564
+
1565
+ // src/adapters/core/utils/useAssistantContext.tsx
1566
+ var makeThreadStore = (runtimeRef) => {
1567
+ const repository = new AssistantMessageRepository((messages) => {
1568
+ useThread.setState({ messages });
1569
+ });
1570
+ const useThread = (0, import_zustand6.create)(() => ({
1571
+ messages: [],
1572
+ isRunning: false,
1573
+ getBranches: (messageId) => repository.getBranches(messageId),
1574
+ switchToBranch: (branchId) => {
1575
+ repository.withModifications((repository2) => {
1576
+ repository2.switchToBranch(branchId);
1577
+ });
1578
+ },
1579
+ startRun: async (parentId) => {
1580
+ const optimisticId = repository.withModifications((repository2) => {
1581
+ const optimisticId2 = repository2.appendOptimisticMessage(parentId, {
1582
+ role: "assistant",
1583
+ content: [{ type: "text", text: "" }]
1584
+ });
1585
+ repository2.resetHead(optimisticId2);
1586
+ return optimisticId2;
1587
+ });
1588
+ const { id } = await runtimeRef.current.startRun(parentId);
1589
+ repository.withModifications((repository2) => {
1590
+ repository2.deleteMessage(optimisticId, id);
1591
+ });
1592
+ },
1593
+ append: async (message) => {
1594
+ const [parentOptimisticId, optimisticId] = repository.withModifications(
1595
+ (repository2) => {
1596
+ const parentOptimisticId2 = repository2.appendOptimisticMessage(
1597
+ message.parentId,
1598
+ {
1599
+ role: "user",
1600
+ content: message.content
1601
+ }
1602
+ );
1603
+ const optimisticId2 = repository2.appendOptimisticMessage(
1604
+ parentOptimisticId2,
1605
+ {
1606
+ role: "assistant",
1607
+ content: [{ type: "text", text: "" }]
1608
+ }
1609
+ );
1610
+ repository2.resetHead(optimisticId2);
1611
+ return [parentOptimisticId2, optimisticId2];
1612
+ }
1613
+ );
1614
+ const { parentId, id } = await runtimeRef.current.append(message);
1615
+ repository.withModifications((repository2) => {
1616
+ repository2.deleteMessage(parentOptimisticId, parentId);
1617
+ repository2.deleteMessage(optimisticId, id);
1618
+ });
1619
+ },
1620
+ cancelRun: () => runtimeRef.current.cancelRun()
1621
+ }));
1622
+ const onNewMessage = (parentId, message) => {
1623
+ repository.withModifications((repository2) => {
1624
+ repository2.addOrUpdateMessage(parentId, message);
1625
+ });
1626
+ };
1627
+ const onRunningChange = (isRunning) => {
1628
+ useThread.setState({ isRunning });
1629
+ };
1630
+ return {
1631
+ useThread,
1632
+ onNewMessage,
1633
+ onRunningChange
1634
+ };
1635
+ };
1636
+ var useAssistantContext2 = (runtime) => {
1637
+ const runtimeRef = (0, import_react28.useRef)(runtime);
1638
+ runtimeRef.current = runtime;
1639
+ const [{ context, onNewMessage, onRunningChange }] = (0, import_react28.useState)(() => {
1640
+ const { useThread, onNewMessage: onNewMessage2, onRunningChange: onRunningChange2 } = makeThreadStore(runtimeRef);
1641
+ const useViewport = makeViewportStore();
1642
+ const useComposer = makeThreadComposerStore(useThread);
1643
+ return {
1644
+ context: { useViewport, useThread, useComposer },
1645
+ onNewMessage: onNewMessage2,
1646
+ onRunningChange: onRunningChange2
1647
+ };
1648
+ });
1649
+ (0, import_react28.useEffect)(() => {
1650
+ return runtime.subscribeToMessageUpdates(onNewMessage);
1651
+ }, [runtime, onNewMessage]);
1652
+ (0, import_react28.useEffect)(() => {
1653
+ return runtime.subscribeToStatusUpdates(onRunningChange);
1654
+ }, [runtime, onRunningChange]);
1655
+ return context;
1656
+ };
1657
+
1658
+ // src/adapters/core/AssistantProvider.tsx
1659
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1660
+ var AssistantProvider = ({ children, runtime }) => {
1661
+ const context = useAssistantContext2(runtime);
1662
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AssistantContext.Provider, { value: context, children });
1663
+ };
1664
+
1665
+ // src/adapters/core/local/useLocalRuntime.tsx
1666
+ var import_react29 = require("react");
1667
+
1668
+ // src/adapters/core/local/LocalRuntime.tsx
1669
+ var LocalRuntime = class {
1670
+ constructor(adapter) {
1671
+ this.adapter = adapter;
1672
+ }
1673
+ _messageUpdateCallbacks = /* @__PURE__ */ new Set();
1674
+ _statusUpdateCallbacks = /* @__PURE__ */ new Set();
1675
+ abortController = null;
1676
+ repository = new MessageRepository();
1677
+ async append(message) {
1678
+ const userMessageId = generateId();
1679
+ const userMessage = {
1680
+ id: userMessageId,
1681
+ role: "user",
1682
+ content: message.content,
1683
+ createdAt: /* @__PURE__ */ new Date()
1684
+ };
1685
+ this.addOrUpdateMessage(message.parentId, userMessage);
1686
+ const { id } = await this.startRun(userMessageId);
1687
+ return { parentId: userMessageId, id };
1688
+ }
1689
+ async startRun(parentId) {
1690
+ const id = generateId();
1691
+ this.repository.resetHead(parentId);
1692
+ const messages = this.repository.getMessages();
1693
+ const message = {
1694
+ id,
1695
+ role: "assistant",
1696
+ status: "in_progress",
1697
+ content: [{ type: "text", text: "" }],
1698
+ createdAt: /* @__PURE__ */ new Date()
1699
+ };
1700
+ this.addOrUpdateMessage(parentId, message);
1701
+ void this.run(parentId, messages, message);
1702
+ return { id };
1703
+ }
1704
+ addOrUpdateMessage(parentId, message) {
1705
+ const clone = { ...message };
1706
+ this.repository.addOrUpdateMessage(parentId, clone);
1707
+ for (const callback of this._messageUpdateCallbacks)
1708
+ callback(parentId, clone);
1709
+ }
1710
+ async run(parentId, messages, message) {
1711
+ this.cancelRun();
1712
+ for (const callback of this._statusUpdateCallbacks) callback(true);
1713
+ this.abortController = new AbortController();
1714
+ try {
1715
+ await this.adapter.run({
1716
+ messages,
1717
+ abortSignal: this.abortController.signal,
1718
+ onUpdate: ({ content }) => {
1719
+ message.content = content;
1720
+ this.addOrUpdateMessage(parentId, message);
1721
+ }
1722
+ });
1723
+ message.status = "done";
1724
+ this.addOrUpdateMessage(parentId, message);
1725
+ } catch (e) {
1726
+ message.status = "error";
1727
+ this.addOrUpdateMessage(parentId, message);
1728
+ console.error(e);
1729
+ } finally {
1730
+ this.cancelRun();
1731
+ }
1732
+ }
1733
+ cancelRun() {
1734
+ if (!this.abortController) return;
1735
+ this.abortController.abort();
1736
+ this.abortController = null;
1737
+ for (const callback of this._statusUpdateCallbacks) callback(false);
1738
+ }
1739
+ subscribeToMessageUpdates(callback) {
1740
+ this._messageUpdateCallbacks.add(callback);
1741
+ return () => this._messageUpdateCallbacks.delete(callback);
1742
+ }
1743
+ subscribeToStatusUpdates(callback) {
1744
+ this._statusUpdateCallbacks.add(callback);
1745
+ return () => this._statusUpdateCallbacks.delete(callback);
1746
+ }
1747
+ };
1748
+
1749
+ // src/adapters/core/local/useLocalRuntime.tsx
1750
+ var useLocalRuntime = (adapter) => {
1751
+ const [runtime] = (0, import_react29.useState)(() => new LocalRuntime(adapter));
1752
+ runtime.adapter = adapter;
1753
+ return runtime;
1754
+ };
1755
+
1756
+ // src/adapters/core/local/vercel/VercelModelAdapter.tsx
1757
+ var import_ai = require("ai");
1758
+ var VercelModelAdapter = class {
1759
+ constructor(model) {
1760
+ this.model = model;
1761
+ }
1762
+ async run({ messages, abortSignal, onUpdate }) {
1763
+ const { fullStream } = await (0, import_ai.streamText)({
1764
+ model: this.model,
1765
+ abortSignal,
1766
+ messages: messages.map((m) => ({
1767
+ role: m.role,
1768
+ content: m.content.filter((c) => c.type !== "ui")
1769
+ }))
1770
+ });
1771
+ const content = [];
1772
+ for await (const aiPart of fullStream) {
1773
+ switch (aiPart.type) {
1774
+ case "text-delta": {
1775
+ let part = content.at(-1);
1776
+ if (!part || part.type !== "text") {
1777
+ part = { type: "text", text: "" };
1778
+ content.push(part);
1779
+ }
1780
+ part.text += aiPart.textDelta;
1781
+ break;
1782
+ }
1783
+ case "tool-call": {
1784
+ content.push({
1785
+ type: "tool-call",
1786
+ name: aiPart.toolName,
1787
+ args: aiPart.args
1788
+ });
1789
+ break;
1790
+ }
1791
+ }
1792
+ onUpdate({ content });
1793
+ }
1794
+ return { content };
1795
+ }
1796
+ };
1522
1797
  // Annotate the CommonJS export names for ESM import in node:
1523
1798
  0 && (module.exports = {
1524
1799
  ActionBarPrimitive,
@@ -1529,6 +1804,11 @@ var VercelRSCAssistantProvider = ({
1529
1804
  ThreadPrimitive,
1530
1805
  VercelAIAssistantProvider,
1531
1806
  VercelRSCAssistantProvider,
1807
+ unstable_AssistantProvider,
1808
+ unstable_VercelModelAdapter,
1809
+ unstable_getVercelMessage,
1810
+ unstable_getVercelRSCMessage,
1811
+ unstable_useLocalRuntime,
1532
1812
  unstable_useMessageContext,
1533
1813
  useBeginMessageEdit,
1534
1814
  useCopyMessage,