@assistant-ui/react 0.0.19 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -1027,10 +1027,15 @@ __export(contentPart_exports, {
1027
1027
  });
1028
1028
 
1029
1029
  // src/adapters/vercel/VercelAIAssistantProvider.tsx
1030
- import { useMemo as useMemo6 } from "react";
1030
+ import { useEffect as useEffect6 } from "react";
1031
1031
 
1032
- // src/adapters/vercel/useDummyAIAssistantContext.tsx
1033
- import { useState as useState3 } from "react";
1032
+ // src/adapters/core/AssistantProvider.tsx
1033
+ import {
1034
+ useEffect as useEffect4,
1035
+ useInsertionEffect,
1036
+ useRef as useRef4,
1037
+ useState as useState3
1038
+ } from "react";
1034
1039
  import { create as create5 } from "zustand";
1035
1040
 
1036
1041
  // src/utils/context/stores/ViewportStore.tsx
@@ -1053,41 +1058,79 @@ var makeViewportStore = () => {
1053
1058
  }));
1054
1059
  };
1055
1060
 
1056
- // src/adapters/vercel/useDummyAIAssistantContext.tsx
1057
- var makeDummyThreadStore = () => {
1058
- return create5(() => ({
1059
- messages: [],
1060
- isRunning: false,
1061
- getBranches: () => {
1062
- return [];
1063
- },
1064
- switchToBranch: () => {
1065
- throw new Error("Not implemented");
1066
- },
1067
- append: () => {
1068
- throw new Error("Not implemented");
1069
- },
1070
- startRun: () => {
1071
- throw new Error("Not implemented");
1072
- },
1073
- cancelRun: () => {
1074
- throw new Error("Not implemented");
1075
- }
1061
+ // src/adapters/core/AssistantProvider.tsx
1062
+ import { jsx as jsx21 } from "react/jsx-runtime";
1063
+ var makeThreadStore = (runtimeRef) => {
1064
+ const useThread = create5(() => ({
1065
+ messages: runtimeRef.current.messages,
1066
+ isRunning: runtimeRef.current.isRunning,
1067
+ getBranches: (messageId) => runtimeRef.current.getBranches(messageId),
1068
+ switchToBranch: (branchId) => runtimeRef.current.switchToBranch(branchId),
1069
+ startRun: (parentId) => runtimeRef.current.startRun(parentId),
1070
+ append: (message) => runtimeRef.current.append(message),
1071
+ cancelRun: () => runtimeRef.current.cancelRun()
1076
1072
  }));
1073
+ const onRuntimeUpdate = () => {
1074
+ useThread.setState({
1075
+ messages: runtimeRef.current.messages,
1076
+ isRunning: runtimeRef.current.isRunning
1077
+ });
1078
+ };
1079
+ return {
1080
+ useThread,
1081
+ onRuntimeUpdate
1082
+ };
1077
1083
  };
1078
- var useDummyAIAssistantContext = () => {
1079
- const [context] = useState3(() => {
1080
- const useThread = makeDummyThreadStore();
1084
+ var AssistantProvider = ({ children, runtime }) => {
1085
+ const runtimeRef = useRef4(runtime);
1086
+ useInsertionEffect(() => {
1087
+ runtimeRef.current = runtime;
1088
+ });
1089
+ const [{ context, onRuntimeUpdate }] = useState3(() => {
1090
+ const { useThread, onRuntimeUpdate: onRuntimeUpdate2 } = makeThreadStore(runtimeRef);
1081
1091
  const useViewport = makeViewportStore();
1082
1092
  const useComposer = makeThreadComposerStore(useThread);
1083
- return { useThread, useViewport, useComposer };
1093
+ return {
1094
+ context: {
1095
+ useViewport,
1096
+ useThread,
1097
+ useComposer
1098
+ },
1099
+ onRuntimeUpdate: onRuntimeUpdate2
1100
+ };
1084
1101
  });
1085
- return context;
1102
+ useEffect4(() => {
1103
+ onRuntimeUpdate();
1104
+ return runtime.subscribe(onRuntimeUpdate);
1105
+ }, [onRuntimeUpdate, runtime]);
1106
+ return /* @__PURE__ */ jsx21(AssistantContext.Provider, { value: context, children });
1107
+ };
1108
+
1109
+ // src/adapters/core/vercel-use-chat/useVercelUseChatRuntime.tsx
1110
+ import { useEffect as useEffect5, useInsertionEffect as useInsertionEffect2, useMemo as useMemo5, useState as useState4 } from "react";
1111
+
1112
+ // src/adapters/ThreadMessageConverter.ts
1113
+ var ThreadMessageConverter = class {
1114
+ cache = /* @__PURE__ */ new WeakMap();
1115
+ convertMessages(converter, messages) {
1116
+ return messages.map((m) => {
1117
+ const cached = this.cache.get(m);
1118
+ const newMessage = converter(m, cached);
1119
+ this.cache.set(m, newMessage);
1120
+ return newMessage;
1121
+ });
1122
+ }
1086
1123
  };
1087
1124
 
1088
- // src/adapters/vercel/useVercelAIThreadState.tsx
1089
- import { useCallbackRef as useCallbackRef3 } from "@radix-ui/react-use-callback-ref";
1090
- import { useCallback as useCallback7, useMemo as useMemo5, useRef as useRef4, useState as useState4 } from "react";
1125
+ // src/adapters/vercel/VercelThreadMessage.tsx
1126
+ var symbolInnerMessage = Symbol("innerMessage");
1127
+ var symbolInnerRSCMessage = Symbol("innerRSCMessage");
1128
+ var getVercelMessage = (message) => {
1129
+ return message[symbolInnerMessage];
1130
+ };
1131
+ var getVercelRSCMessage = (message) => {
1132
+ return message[symbolInnerRSCMessage];
1133
+ };
1091
1134
 
1092
1135
  // src/adapters/idUtils.tsx
1093
1136
  import { customAlphabet } from "nanoid/non-secure";
@@ -1249,30 +1292,104 @@ var MessageRepository = class {
1249
1292
  }
1250
1293
  };
1251
1294
 
1252
- // src/adapters/ThreadMessageConverter.ts
1253
- var ThreadMessageConverter = class {
1254
- cache = /* @__PURE__ */ new WeakMap();
1255
- convertMessages(converter, messages) {
1256
- return messages.map((m) => {
1257
- const cached = this.cache.get(m);
1258
- const newMessage = converter(m, cached);
1259
- this.cache.set(m, newMessage);
1260
- return newMessage;
1295
+ // src/adapters/core/vercel-use-chat/VercelUseChatRuntime.tsx
1296
+ var sliceMessagesUntil = (messages, messageId) => {
1297
+ if (messageId == null) return [];
1298
+ const messageIdx = messages.findIndex((m) => m.id === messageId);
1299
+ if (messageIdx === -1)
1300
+ throw new Error(
1301
+ "useVercelAIThreadState: Message not found. This is liekly an internal bug in assistant-ui."
1302
+ );
1303
+ return messages.slice(0, messageIdx + 1);
1304
+ };
1305
+ var hasUpcomingMessage = (isRunning, messages) => {
1306
+ return isRunning && messages[messages.length - 1]?.role !== "assistant";
1307
+ };
1308
+ var VercelUseChatRuntime = class {
1309
+ constructor(vercel) {
1310
+ this.vercel = vercel;
1311
+ }
1312
+ _subscriptions = /* @__PURE__ */ new Set();
1313
+ repository = new MessageRepository();
1314
+ assistantOptimisticId = null;
1315
+ messages = [];
1316
+ isRunning = false;
1317
+ getBranches(messageId) {
1318
+ return this.repository.getBranches(messageId);
1319
+ }
1320
+ switchToBranch(branchId) {
1321
+ this.repository.switchToBranch(branchId);
1322
+ this.vercel.setMessages(
1323
+ this.repository.getMessages().map(getVercelMessage).filter((m) => m != null)
1324
+ );
1325
+ }
1326
+ async append(message) {
1327
+ if (message.content.length !== 1 || message.content[0]?.type !== "text")
1328
+ throw new Error("Only text content is supported by Vercel AI SDK.");
1329
+ const newMessages = sliceMessagesUntil(
1330
+ this.vercel.messages,
1331
+ message.parentId
1332
+ );
1333
+ this.vercel.setMessages(newMessages);
1334
+ await this.vercel.append({
1335
+ role: "user",
1336
+ content: message.content[0].text
1261
1337
  });
1262
1338
  }
1339
+ async startRun(parentId) {
1340
+ const reloadMaybe = "reload" in this.vercel ? this.vercel.reload : void 0;
1341
+ if (!reloadMaybe)
1342
+ throw new Error(
1343
+ "Reload is not supported by Vercel AI SDK's useAssistant."
1344
+ );
1345
+ const newMessages = sliceMessagesUntil(this.vercel.messages, parentId);
1346
+ this.vercel.setMessages(newMessages);
1347
+ await reloadMaybe();
1348
+ }
1349
+ cancelRun() {
1350
+ const lastMessage = this.vercel.messages.at(-1);
1351
+ this.vercel.stop();
1352
+ if (lastMessage?.role === "user") {
1353
+ this.vercel.setInput(lastMessage.content);
1354
+ }
1355
+ }
1356
+ updateData(isRunning, vm) {
1357
+ for (let i = 0; i < vm.length; i++) {
1358
+ const message = vm[i];
1359
+ const parent = vm[i - 1];
1360
+ this.repository.addOrUpdateMessage(parent?.id ?? null, message);
1361
+ }
1362
+ if (this.assistantOptimisticId) {
1363
+ this.repository.deleteMessage(this.assistantOptimisticId, null);
1364
+ this.assistantOptimisticId = null;
1365
+ }
1366
+ if (hasUpcomingMessage(isRunning, vm)) {
1367
+ this.assistantOptimisticId = this.repository.appendOptimisticMessage(
1368
+ vm.at(-1)?.id ?? null,
1369
+ {
1370
+ role: "assistant",
1371
+ content: [{ type: "text", text: "" }]
1372
+ }
1373
+ );
1374
+ }
1375
+ this.repository.resetHead(
1376
+ this.assistantOptimisticId ?? vm.at(-1)?.id ?? null
1377
+ );
1378
+ this.messages = this.repository.getMessages();
1379
+ this.isRunning = isRunning;
1380
+ for (const callback of this._subscriptions) callback();
1381
+ }
1382
+ subscribe(callback) {
1383
+ this._subscriptions.add(callback);
1384
+ return () => this._subscriptions.delete(callback);
1385
+ }
1263
1386
  };
1264
1387
 
1265
- // src/adapters/vercel/VercelThreadMessage.tsx
1266
- var symbolInnerMessage = Symbol("innerMessage");
1267
- var symbolInnerRSCMessage = Symbol("innerRSCMessage");
1268
- var getVercelMessage = (message) => {
1269
- return message[symbolInnerMessage];
1270
- };
1271
- var getVercelRSCMessage = (message) => {
1272
- return message[symbolInnerRSCMessage];
1388
+ // src/adapters/core/vercel-use-chat/useVercelUseChatRuntime.tsx
1389
+ var getIsRunning = (vercel) => {
1390
+ if ("isLoading" in vercel) return vercel.isLoading;
1391
+ return vercel.status === "in_progress";
1273
1392
  };
1274
-
1275
- // src/adapters/vercel/useVercelAIThreadState.tsx
1276
1393
  var vercelToThreadMessage = (message, status) => {
1277
1394
  const common = {
1278
1395
  id: message.id,
@@ -1309,27 +1426,13 @@ var vercelToThreadMessage = (message, status) => {
1309
1426
  );
1310
1427
  }
1311
1428
  };
1312
- var sliceMessagesUntil = (messages, messageId) => {
1313
- if (messageId == null) return [];
1314
- const messageIdx = messages.findIndex((m) => m.id === messageId);
1315
- if (messageIdx === -1)
1316
- throw new Error(
1317
- "useVercelAIThreadState: Message not found. This is liekly an internal bug in assistant-ui."
1318
- );
1319
- return messages.slice(0, messageIdx + 1);
1320
- };
1321
- var hasUpcomingMessage = (isRunning, messages) => {
1322
- return isRunning && messages[messages.length - 1]?.role !== "assistant";
1323
- };
1324
- var getIsRunning = (vercel) => {
1325
- if ("isLoading" in vercel) return vercel.isLoading;
1326
- return vercel.status === "in_progress";
1327
- };
1328
- var useVercelAIThreadState = (vercel) => {
1329
- const [data] = useState4(() => new MessageRepository());
1429
+ var useVercelUseChatRuntime = (vercel) => {
1430
+ const [runtime] = useState4(() => new VercelUseChatRuntime(vercel));
1431
+ useInsertionEffect2(() => {
1432
+ runtime.vercel = vercel;
1433
+ });
1330
1434
  const isRunning = getIsRunning(vercel);
1331
1435
  const converter = useMemo5(() => new ThreadMessageConverter(), []);
1332
- const assistantOptimisticIdRef = useRef4(null);
1333
1436
  const messages = useMemo5(() => {
1334
1437
  const lastMessageId = vercel.messages.at(-1)?.id;
1335
1438
  const convertCallback = (message, cache) => {
@@ -1338,117 +1441,102 @@ var useVercelAIThreadState = (vercel) => {
1338
1441
  return cache;
1339
1442
  return vercelToThreadMessage(message, status);
1340
1443
  };
1341
- const vm = converter.convertMessages(convertCallback, vercel.messages);
1342
- for (let i = 0; i < vm.length; i++) {
1343
- const message = vm[i];
1344
- const parent = vm[i - 1];
1345
- data.addOrUpdateMessage(parent?.id ?? null, message);
1346
- }
1347
- if (assistantOptimisticIdRef.current) {
1348
- data.deleteMessage(assistantOptimisticIdRef.current, null);
1349
- assistantOptimisticIdRef.current = null;
1350
- }
1351
- if (hasUpcomingMessage(isRunning, vm)) {
1352
- assistantOptimisticIdRef.current = data.appendOptimisticMessage(
1353
- vm.at(-1)?.id ?? null,
1354
- {
1355
- role: "assistant",
1356
- content: [{ type: "text", text: "" }]
1357
- }
1358
- );
1359
- }
1360
- data.resetHead(assistantOptimisticIdRef.current ?? vm.at(-1)?.id ?? null);
1361
- return data.getMessages();
1362
- }, [converter, data, isRunning, vercel.messages]);
1363
- const getBranches2 = useCallback7(
1364
- (messageId) => {
1365
- return data.getBranches(messageId);
1366
- },
1367
- [data]
1368
- );
1369
- const switchToBranch2 = useCallbackRef3((messageId) => {
1370
- data.switchToBranch(messageId);
1371
- vercel.setMessages(
1372
- data.getMessages().map(getVercelMessage).filter((m) => m != null)
1373
- );
1374
- });
1375
- const startRun = useCallbackRef3(async (parentId) => {
1376
- const reloadMaybe = "reload" in vercel ? vercel.reload : void 0;
1377
- if (!reloadMaybe)
1378
- throw new Error(
1379
- "Reload is not supported by Vercel AI SDK's useAssistant."
1380
- );
1381
- const newMessages = sliceMessagesUntil(vercel.messages, parentId);
1382
- vercel.setMessages(newMessages);
1383
- await reloadMaybe();
1384
- });
1385
- const append = useCallbackRef3(async (message) => {
1386
- if (message.content.length !== 1 || message.content[0]?.type !== "text")
1387
- throw new Error("Only text content is supported by Vercel AI SDK.");
1388
- const newMessages = sliceMessagesUntil(vercel.messages, message.parentId);
1389
- vercel.setMessages(newMessages);
1390
- await vercel.append({
1391
- role: "user",
1392
- content: message.content[0].text
1393
- });
1394
- });
1395
- const cancelRun2 = useCallbackRef3(() => {
1396
- const lastMessage = vercel.messages.at(-1);
1397
- vercel.stop();
1398
- if (lastMessage?.role === "user") {
1399
- vercel.setInput(lastMessage.content);
1400
- }
1401
- });
1402
- return useMemo5(
1403
- () => ({
1404
- isRunning,
1405
- messages,
1406
- getBranches: getBranches2,
1407
- switchToBranch: switchToBranch2,
1408
- append,
1409
- startRun,
1410
- cancelRun: cancelRun2
1411
- }),
1412
- [
1413
- isRunning,
1414
- messages,
1415
- getBranches2,
1416
- switchToBranch2,
1417
- append,
1418
- startRun,
1419
- cancelRun2
1420
- ]
1421
- );
1444
+ return converter.convertMessages(convertCallback, vercel.messages);
1445
+ }, [isRunning, vercel.messages, converter]);
1446
+ useEffect5(() => {
1447
+ runtime.updateData(isRunning, messages);
1448
+ }, [runtime, isRunning, messages]);
1449
+ return runtime;
1422
1450
  };
1423
1451
 
1424
1452
  // src/adapters/vercel/VercelAIAssistantProvider.tsx
1425
- import { jsx as jsx21 } from "react/jsx-runtime";
1453
+ import { jsx as jsx22, jsxs as jsxs4 } from "react/jsx-runtime";
1426
1454
  var VercelAIAssistantProvider = ({
1427
1455
  children,
1428
1456
  ...rest
1429
1457
  }) => {
1430
- const context = useDummyAIAssistantContext();
1431
1458
  const vercel = "chat" in rest ? rest.chat : rest.assistant;
1432
- const threadState = useVercelAIThreadState(vercel);
1433
- useMemo6(() => {
1434
- context.useThread.setState(threadState, true);
1435
- }, [context, threadState]);
1436
- useMemo6(() => {
1437
- context.useComposer.setState({
1459
+ const runtime = useVercelUseChatRuntime(vercel);
1460
+ return /* @__PURE__ */ jsxs4(AssistantProvider, { runtime, children: [
1461
+ /* @__PURE__ */ jsx22(ComposerSync, { vercel }),
1462
+ children
1463
+ ] });
1464
+ };
1465
+ var ComposerSync = ({
1466
+ vercel
1467
+ }) => {
1468
+ const { useComposer } = useAssistantContext();
1469
+ useEffect6(() => {
1470
+ useComposer.setState({
1438
1471
  value: vercel.input,
1439
1472
  setValue: vercel.setInput
1440
1473
  });
1441
- }, [context, vercel.input, vercel.setInput]);
1442
- return /* @__PURE__ */ jsx21(AssistantContext.Provider, { value: context, children });
1474
+ }, [useComposer, vercel.input, vercel.setInput]);
1475
+ return null;
1443
1476
  };
1444
1477
 
1445
- // src/adapters/vercel/VercelRSCAssistantProvider.tsx
1446
- import {
1447
- useCallback as useCallback8,
1448
- useMemo as useMemo7,
1449
- useState as useState5
1450
- } from "react";
1451
- import { jsx as jsx22 } from "react/jsx-runtime";
1478
+ // src/adapters/core/vercel-rsc/useVercelRSCRuntime.tsx
1479
+ import { useEffect as useEffect7, useInsertionEffect as useInsertionEffect3, useMemo as useMemo6, useState as useState5 } from "react";
1480
+
1481
+ // src/adapters/core/vercel-rsc/VercelRSCRuntime.tsx
1482
+ var EMPTY_BRANCHES = Object.freeze([]);
1483
+ var VercelRSCRuntime = class {
1484
+ constructor(adapter) {
1485
+ this.adapter = adapter;
1486
+ }
1487
+ _subscriptions = /* @__PURE__ */ new Set();
1488
+ isRunning = false;
1489
+ messages = [];
1490
+ withRunning = (callback) => {
1491
+ this.isRunning = true;
1492
+ return callback.finally(() => {
1493
+ this.isRunning = false;
1494
+ });
1495
+ };
1496
+ getBranches() {
1497
+ return EMPTY_BRANCHES;
1498
+ }
1499
+ switchToBranch() {
1500
+ throw new Error(
1501
+ "Branch switching is not supported by VercelRSCAssistantProvider."
1502
+ );
1503
+ }
1504
+ async append(message) {
1505
+ if (message.parentId !== (this.messages.at(-1)?.id ?? null)) {
1506
+ if (!this.adapter.edit)
1507
+ throw new Error(
1508
+ "Message editing is not enabled, please provide an edit callback to VercelRSCAssistantProvider."
1509
+ );
1510
+ await this.withRunning(this.adapter.edit(message));
1511
+ } else {
1512
+ await this.withRunning(this.adapter.append(message));
1513
+ }
1514
+ }
1515
+ async startRun(parentId) {
1516
+ if (!this.adapter.reload)
1517
+ throw new Error(
1518
+ "Message reloading is not enabled, please provide a reload callback to VercelRSCAssistantProvider."
1519
+ );
1520
+ await this.withRunning(this.adapter.reload(parentId));
1521
+ }
1522
+ cancelRun() {
1523
+ if (process.env["NODE_ENV"] === "development") {
1524
+ console.warn(
1525
+ "Run cancellation is not supported by VercelRSCAssistantProvider."
1526
+ );
1527
+ }
1528
+ }
1529
+ updateData(messages) {
1530
+ this.messages = messages;
1531
+ for (const callback of this._subscriptions) callback();
1532
+ }
1533
+ subscribe(callback) {
1534
+ this._subscriptions.add(callback);
1535
+ return () => this._subscriptions.delete(callback);
1536
+ }
1537
+ };
1538
+
1539
+ // src/adapters/core/vercel-rsc/useVercelRSCRuntime.tsx
1452
1540
  var vercelToThreadMessage2 = (converter, rawMessage) => {
1453
1541
  const message = converter(rawMessage);
1454
1542
  return {
@@ -1460,227 +1548,61 @@ var vercelToThreadMessage2 = (converter, rawMessage) => {
1460
1548
  [symbolInnerRSCMessage]: rawMessage
1461
1549
  };
1462
1550
  };
1463
- var EMPTY_BRANCHES = [];
1464
- var getBranches = () => {
1465
- return EMPTY_BRANCHES;
1466
- };
1467
- var switchToBranch = () => {
1468
- throw new Error(
1469
- "Branch switching is not supported by VercelRSCAssistantProvider."
1470
- );
1471
- };
1472
- var cancelRun = () => {
1473
- if (process.env["NODE_ENV"] === "development") {
1474
- console.warn(
1475
- "Run cancellation is not supported by VercelRSCAssistantProvider."
1476
- );
1477
- }
1478
- };
1479
- var VercelRSCAssistantProvider = ({
1480
- children,
1481
- convertMessage,
1482
- messages: vercelMessages,
1483
- append: appendCallback,
1484
- edit,
1485
- reload
1486
- }) => {
1487
- const context = useDummyAIAssistantContext();
1488
- const [isRunning, setIsRunning] = useState5(false);
1489
- const withRunning = useCallback8((callback) => {
1490
- setIsRunning(true);
1491
- return callback.finally(() => setIsRunning(false));
1492
- }, []);
1493
- const [converter, convertCallback] = useMemo7(() => {
1494
- const rscConverter = convertMessage ?? ((m) => m);
1551
+ var useVercelRSCRuntime = (adapter) => {
1552
+ const [runtime] = useState5(() => new VercelRSCRuntime(adapter));
1553
+ useInsertionEffect3(() => {
1554
+ runtime.adapter = adapter;
1555
+ });
1556
+ const [converter, convertCallback] = useMemo6(() => {
1557
+ const rscConverter = adapter.convertMessage ?? ((m) => m);
1495
1558
  const convertCallback2 = (m, cache) => {
1496
1559
  if (cache) return cache;
1497
1560
  return vercelToThreadMessage2(rscConverter, m);
1498
1561
  };
1499
1562
  return [new ThreadMessageConverter(), convertCallback2];
1500
- }, [convertMessage]);
1501
- const messages = useMemo7(() => {
1502
- return converter.convertMessages(convertCallback, vercelMessages);
1503
- }, [converter, convertCallback, vercelMessages]);
1504
- const append = useCallback8(
1505
- async (message) => {
1506
- if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
1507
- if (!edit)
1508
- throw new Error(
1509
- "Message editing is not enabled, please provide an edit callback to VercelRSCAssistantProvider."
1510
- );
1511
- await withRunning(edit(message));
1512
- } else {
1513
- await withRunning(appendCallback(message));
1514
- }
1515
- },
1516
- [context, withRunning, appendCallback, edit]
1517
- );
1518
- const startRun = useCallback8(
1519
- async (parentId) => {
1520
- if (!reload)
1521
- throw new Error(
1522
- "Message reloading is not enabled, please provide a reload callback to VercelRSCAssistantProvider."
1523
- );
1524
- await withRunning(reload(parentId));
1525
- },
1526
- [withRunning, reload]
1527
- );
1528
- useMemo7(() => {
1529
- context.useThread.setState(
1530
- {
1531
- messages,
1532
- isRunning,
1533
- getBranches,
1534
- switchToBranch,
1535
- append,
1536
- startRun,
1537
- cancelRun
1538
- },
1539
- true
1563
+ }, [adapter.convertMessage]);
1564
+ useEffect7(() => {
1565
+ runtime.updateData(
1566
+ converter.convertMessages(convertCallback, adapter.messages)
1540
1567
  );
1541
- }, [context, messages, isRunning, append, startRun]);
1542
- return /* @__PURE__ */ jsx22(AssistantContext.Provider, { value: context, children });
1543
- };
1544
-
1545
- // src/adapters/core/utils/useAssistantContext.tsx
1546
- import {
1547
- useEffect as useEffect4,
1548
- useInsertionEffect,
1549
- useRef as useRef5,
1550
- useState as useState6
1551
- } from "react";
1552
- import { create as create6 } from "zustand";
1553
-
1554
- // src/adapters/core/utils/AssistantMessageRepository.tsx
1555
- var AssistantMessageRepository = class {
1556
- constructor(flushCallback) {
1557
- this.flushCallback = flushCallback;
1558
- }
1559
- repository = new MessageRepository();
1560
- getBranches(messageId) {
1561
- return this.repository.getBranches(messageId);
1562
- }
1563
- withModifications(callback) {
1564
- const res = callback(this.repository);
1565
- this.flushCallback(this.repository.getMessages());
1566
- return res;
1567
- }
1568
- };
1569
-
1570
- // src/adapters/core/utils/useAssistantContext.tsx
1571
- var makeThreadStore = (runtimeRef) => {
1572
- const repository = new AssistantMessageRepository((messages) => {
1573
- useThread.setState({ messages });
1574
- });
1575
- const useThread = create6(() => ({
1576
- messages: [],
1577
- isRunning: false,
1578
- getBranches: (messageId) => repository.getBranches(messageId),
1579
- switchToBranch: (branchId) => {
1580
- repository.withModifications((repository2) => {
1581
- repository2.switchToBranch(branchId);
1582
- });
1583
- },
1584
- startRun: async (parentId) => {
1585
- const optimisticId = repository.withModifications((repository2) => {
1586
- const optimisticId2 = repository2.appendOptimisticMessage(parentId, {
1587
- role: "assistant",
1588
- content: [{ type: "text", text: "" }]
1589
- });
1590
- repository2.resetHead(optimisticId2);
1591
- return optimisticId2;
1592
- });
1593
- const { id } = await runtimeRef.current.startRun(parentId);
1594
- repository.withModifications((repository2) => {
1595
- repository2.deleteMessage(optimisticId, id);
1596
- });
1597
- },
1598
- append: async (message) => {
1599
- const [parentOptimisticId, optimisticId] = repository.withModifications(
1600
- (repository2) => {
1601
- const parentOptimisticId2 = repository2.appendOptimisticMessage(
1602
- message.parentId,
1603
- {
1604
- role: "user",
1605
- content: message.content
1606
- }
1607
- );
1608
- const optimisticId2 = repository2.appendOptimisticMessage(
1609
- parentOptimisticId2,
1610
- {
1611
- role: "assistant",
1612
- content: [{ type: "text", text: "" }]
1613
- }
1614
- );
1615
- repository2.resetHead(optimisticId2);
1616
- return [parentOptimisticId2, optimisticId2];
1617
- }
1618
- );
1619
- const { parentId, id } = await runtimeRef.current.append(message);
1620
- repository.withModifications((repository2) => {
1621
- repository2.deleteMessage(parentOptimisticId, parentId);
1622
- repository2.deleteMessage(optimisticId, id);
1623
- });
1624
- },
1625
- cancelRun: () => runtimeRef.current.cancelRun()
1626
- }));
1627
- const onNewMessage = (parentId, message) => {
1628
- repository.withModifications((repository2) => {
1629
- repository2.addOrUpdateMessage(parentId, message);
1630
- });
1631
- };
1632
- const onRunningChange = (isRunning) => {
1633
- useThread.setState({ isRunning });
1634
- };
1635
- return {
1636
- useThread,
1637
- onNewMessage,
1638
- onRunningChange
1639
- };
1640
- };
1641
- var useAssistantContext2 = (runtime) => {
1642
- const runtimeRef = useRef5(runtime);
1643
- useInsertionEffect(() => {
1644
- runtimeRef.current = runtime;
1645
- });
1646
- const [{ context, onNewMessage, onRunningChange }] = useState6(() => {
1647
- const { useThread, onNewMessage: onNewMessage2, onRunningChange: onRunningChange2 } = makeThreadStore(runtimeRef);
1648
- const useViewport = makeViewportStore();
1649
- const useComposer = makeThreadComposerStore(useThread);
1650
- return {
1651
- context: { useViewport, useThread, useComposer },
1652
- onNewMessage: onNewMessage2,
1653
- onRunningChange: onRunningChange2
1654
- };
1655
- });
1656
- useEffect4(() => {
1657
- return runtime.subscribeToMessageUpdates(onNewMessage);
1658
- }, [runtime, onNewMessage]);
1659
- useEffect4(() => {
1660
- return runtime.subscribeToStatusUpdates(onRunningChange);
1661
- }, [runtime, onRunningChange]);
1662
- return context;
1568
+ }, [runtime, converter, convertCallback, adapter.messages]);
1569
+ return runtime;
1663
1570
  };
1664
1571
 
1665
- // src/adapters/core/AssistantProvider.tsx
1572
+ // src/adapters/vercel/VercelRSCAssistantProvider.tsx
1666
1573
  import { jsx as jsx23 } from "react/jsx-runtime";
1667
- var AssistantProvider = ({ children, runtime }) => {
1668
- const context = useAssistantContext2(runtime);
1669
- return /* @__PURE__ */ jsx23(AssistantContext.Provider, { value: context, children });
1574
+ var VercelRSCAssistantProvider = ({
1575
+ children,
1576
+ ...adapter
1577
+ }) => {
1578
+ const runtime = useVercelRSCRuntime(adapter);
1579
+ return /* @__PURE__ */ jsx23(AssistantProvider, { runtime, children });
1670
1580
  };
1671
1581
 
1672
1582
  // src/adapters/core/local/useLocalRuntime.tsx
1673
- import { useState as useState7 } from "react";
1583
+ import { useInsertionEffect as useInsertionEffect4, useState as useState6 } from "react";
1674
1584
 
1675
1585
  // src/adapters/core/local/LocalRuntime.tsx
1676
1586
  var LocalRuntime = class {
1677
1587
  constructor(adapter) {
1678
1588
  this.adapter = adapter;
1679
1589
  }
1680
- _messageUpdateCallbacks = /* @__PURE__ */ new Set();
1681
- _statusUpdateCallbacks = /* @__PURE__ */ new Set();
1590
+ _subscriptions = /* @__PURE__ */ new Set();
1682
1591
  abortController = null;
1683
1592
  repository = new MessageRepository();
1593
+ get messages() {
1594
+ return this.repository.getMessages();
1595
+ }
1596
+ get isRunning() {
1597
+ return this.abortController != null;
1598
+ }
1599
+ getBranches(messageId) {
1600
+ return this.repository.getBranches(messageId);
1601
+ }
1602
+ switchToBranch(branchId) {
1603
+ this.repository.switchToBranch(branchId);
1604
+ this.notifySubscribers();
1605
+ }
1684
1606
  async append(message) {
1685
1607
  const userMessageId = generateId();
1686
1608
  const userMessage = {
@@ -1689,9 +1611,8 @@ var LocalRuntime = class {
1689
1611
  content: message.content,
1690
1612
  createdAt: /* @__PURE__ */ new Date()
1691
1613
  };
1692
- this.addOrUpdateMessage(message.parentId, userMessage);
1693
- const { id } = await this.startRun(userMessageId);
1694
- return { parentId: userMessageId, id };
1614
+ this.repository.addOrUpdateMessage(message.parentId, userMessage);
1615
+ await this.startRun(userMessageId);
1695
1616
  }
1696
1617
  async startRun(parentId) {
1697
1618
  const id = generateId();
@@ -1704,59 +1625,52 @@ var LocalRuntime = class {
1704
1625
  content: [{ type: "text", text: "" }],
1705
1626
  createdAt: /* @__PURE__ */ new Date()
1706
1627
  };
1707
- this.addOrUpdateMessage(parentId, message);
1708
- void this.run(parentId, messages, message);
1709
- return { id };
1710
- }
1711
- addOrUpdateMessage(parentId, message) {
1712
- const clone = { ...message };
1713
- this.repository.addOrUpdateMessage(parentId, clone);
1714
- for (const callback of this._messageUpdateCallbacks)
1715
- callback(parentId, clone);
1716
- }
1717
- async run(parentId, messages, message) {
1718
- this.cancelRun();
1719
- for (const callback of this._statusUpdateCallbacks) callback(true);
1628
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1629
+ this.abortController?.abort();
1720
1630
  this.abortController = new AbortController();
1631
+ this.notifySubscribers();
1721
1632
  try {
1722
1633
  await this.adapter.run({
1723
1634
  messages,
1724
1635
  abortSignal: this.abortController.signal,
1725
1636
  onUpdate: ({ content }) => {
1726
1637
  message.content = content;
1727
- this.addOrUpdateMessage(parentId, message);
1638
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1639
+ this.notifySubscribers();
1728
1640
  }
1729
1641
  });
1730
1642
  message.status = "done";
1731
- this.addOrUpdateMessage(parentId, message);
1643
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1732
1644
  } catch (e) {
1733
1645
  message.status = "error";
1734
- this.addOrUpdateMessage(parentId, message);
1646
+ this.repository.addOrUpdateMessage(parentId, { ...message });
1735
1647
  console.error(e);
1736
1648
  } finally {
1737
- this.cancelRun();
1649
+ this.abortController = null;
1650
+ this.notifySubscribers();
1738
1651
  }
1739
1652
  }
1740
1653
  cancelRun() {
1741
1654
  if (!this.abortController) return;
1742
1655
  this.abortController.abort();
1743
1656
  this.abortController = null;
1744
- for (const callback of this._statusUpdateCallbacks) callback(false);
1657
+ this.notifySubscribers();
1745
1658
  }
1746
- subscribeToMessageUpdates(callback) {
1747
- this._messageUpdateCallbacks.add(callback);
1748
- return () => this._messageUpdateCallbacks.delete(callback);
1659
+ notifySubscribers() {
1660
+ for (const callback of this._subscriptions) callback();
1749
1661
  }
1750
- subscribeToStatusUpdates(callback) {
1751
- this._statusUpdateCallbacks.add(callback);
1752
- return () => this._statusUpdateCallbacks.delete(callback);
1662
+ subscribe(callback) {
1663
+ this._subscriptions.add(callback);
1664
+ return () => this._subscriptions.delete(callback);
1753
1665
  }
1754
1666
  };
1755
1667
 
1756
1668
  // src/adapters/core/local/useLocalRuntime.tsx
1757
1669
  var useLocalRuntime = (adapter) => {
1758
- const [runtime] = useState7(() => new LocalRuntime(adapter));
1759
- runtime.adapter = adapter;
1670
+ const [runtime] = useState6(() => new LocalRuntime(adapter));
1671
+ useInsertionEffect4(() => {
1672
+ runtime.adapter = adapter;
1673
+ });
1760
1674
  return runtime;
1761
1675
  };
1762
1676