@assistant-ui/react 0.0.16 → 0.0.18

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.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,