@assistant-ui/react 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.d.mts CHANGED
@@ -3,7 +3,7 @@ import { FC, ReactNode, PropsWithChildren, ComponentType } from 'react';
3
3
  import { TextareaAutosizeProps } from 'react-textarea-autosize';
4
4
  import { UseChatHelpers, UseAssistantHelpers } from 'ai/react';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
- import { Message } from 'ai';
6
+ import { LanguageModel, Message } from 'ai';
7
7
  import { UseBoundStore, StoreApi } from 'zustand';
8
8
 
9
9
  declare const ThreadRoot: react.ForwardRefExoticComponent<Pick<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -133,7 +133,7 @@ type ToolCallContentPart = {
133
133
  result?: object;
134
134
  };
135
135
  type UserContentPart = TextContentPart | ImageContentPart | UIContentPart;
136
- type AssistantContentPart = TextContentPart | ImageContentPart | UIContentPart | ToolCallContentPart;
136
+ type AssistantContentPart = TextContentPart | UIContentPart | ToolCallContentPart;
137
137
  type AppendContentPart = TextContentPart | ImageContentPart;
138
138
  type BaseMessage = {
139
139
  id: string;
@@ -312,6 +312,70 @@ type RSCMessageConverter<T> = {
312
312
  type VercelRSCAssistantProviderProps<T = VercelRSCMessage> = VercelRSCAssistantProviderBaseProps<T> & (T extends VercelRSCMessage ? object : RSCMessageConverter<T>);
313
313
  declare const VercelRSCAssistantProvider: <T extends WeakKey = VercelRSCMessage>({ children, convertMessage, messages: vercelMessages, append: appendCallback, edit, reload, }: VercelRSCAssistantProviderProps<T>) => react_jsx_runtime.JSX.Element;
314
314
 
315
+ type MessageUpdateCallback = (parentId: string | null, message: ThreadMessage) => void;
316
+ type StatusUpdateCallback = (isRunning: boolean) => void;
317
+ type Unsubscribe = () => void;
318
+ type ThreadRuntime = {
319
+ append(message: AppendMessage): Promise<{
320
+ parentId: string;
321
+ id: string;
322
+ }>;
323
+ startRun(parentId: string | null): Promise<{
324
+ id: string;
325
+ }>;
326
+ cancelRun(): void;
327
+ subscribeToMessageUpdates(callback: MessageUpdateCallback): Unsubscribe;
328
+ subscribeToStatusUpdates(callback: StatusUpdateCallback): Unsubscribe;
329
+ };
330
+
331
+ type AssistantProviderProps = {
332
+ runtime: ThreadRuntime;
333
+ };
334
+ declare const AssistantProvider: FC<PropsWithChildren<AssistantProviderProps>>;
335
+
336
+ type ChatModelRunResult = {
337
+ content: AssistantContentPart[];
338
+ };
339
+ type ChatModelRunOptions = {
340
+ messages: ThreadMessage[];
341
+ abortSignal: AbortSignal;
342
+ onUpdate: (result: ChatModelRunResult) => void;
343
+ };
344
+ type ChatModelAdapter = {
345
+ run: (options: ChatModelRunOptions) => Promise<ChatModelRunResult>;
346
+ };
347
+
348
+ declare class LocalRuntime implements ThreadRuntime {
349
+ adapter: ChatModelAdapter;
350
+ private _messageUpdateCallbacks;
351
+ private _statusUpdateCallbacks;
352
+ private abortController;
353
+ private repository;
354
+ constructor(adapter: ChatModelAdapter);
355
+ append(message: AppendMessage): Promise<{
356
+ parentId: string;
357
+ id: string;
358
+ }>;
359
+ startRun(parentId: string | null): Promise<{
360
+ id: string;
361
+ }>;
362
+ private addOrUpdateMessage;
363
+ private run;
364
+ cancelRun(): void;
365
+ subscribeToMessageUpdates(callback: MessageUpdateCallback): Unsubscribe;
366
+ subscribeToStatusUpdates(callback: StatusUpdateCallback): Unsubscribe;
367
+ }
368
+
369
+ declare const useLocalRuntime: (adapter: ChatModelAdapter) => LocalRuntime;
370
+
371
+ declare class VercelModelAdapter implements ChatModelAdapter {
372
+ private readonly model;
373
+ constructor(model: LanguageModel);
374
+ run({ messages, abortSignal, onUpdate }: ChatModelRunOptions): Promise<{
375
+ content: AssistantContentPart[];
376
+ }>;
377
+ }
378
+
315
379
  declare const getVercelMessage: (message: ThreadMessage) => Message | undefined;
316
380
  declare const getVercelRSCMessage: <T>(message: ThreadMessage) => T | undefined;
317
381
 
@@ -346,4 +410,4 @@ declare const useGoToNextBranch: () => (() => void) | null;
346
410
 
347
411
  declare const useGoToPreviousBranch: () => (() => void) | null;
348
412
 
349
- export { index$1 as ActionBarPrimitive, type AppendContentPart, type AppendMessage, index$2 as BranchPickerPrimitive, index$4 as ComposerPrimitive, index as ContentPartPrimitive, type ImageContentPart, index$3 as MessagePrimitive, type VercelRSCMessage as RSCMessage, type TextContentPart, index$5 as ThreadPrimitive, VercelAIAssistantProvider, type VercelAIAssistantProviderProps, VercelRSCAssistantProvider, type VercelRSCAssistantProviderProps, getVercelMessage as unstable_getVercelMessage, getVercelRSCMessage as unstable_getVercelRSCMessage, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
413
+ export { index$1 as ActionBarPrimitive, type AppendContentPart, type AppendMessage, index$2 as BranchPickerPrimitive, index$4 as ComposerPrimitive, index as ContentPartPrimitive, type ImageContentPart, index$3 as MessagePrimitive, type VercelRSCMessage as RSCMessage, type TextContentPart, index$5 as ThreadPrimitive, VercelAIAssistantProvider, type VercelAIAssistantProviderProps, VercelRSCAssistantProvider, type VercelRSCAssistantProviderProps, AssistantProvider as unstable_AssistantProvider, type ChatModelAdapter as unstable_ChatModelAdapter, type ChatModelRunOptions as unstable_ChatModelRunOptions, VercelModelAdapter as unstable_VercelModelAdapter, getVercelMessage as unstable_getVercelMessage, getVercelRSCMessage as unstable_getVercelRSCMessage, useLocalRuntime as unstable_useLocalRuntime, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { FC, ReactNode, PropsWithChildren, ComponentType } from 'react';
3
3
  import { TextareaAutosizeProps } from 'react-textarea-autosize';
4
4
  import { UseChatHelpers, UseAssistantHelpers } from 'ai/react';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
- import { Message } from 'ai';
6
+ import { LanguageModel, Message } from 'ai';
7
7
  import { UseBoundStore, StoreApi } from 'zustand';
8
8
 
9
9
  declare const ThreadRoot: react.ForwardRefExoticComponent<Pick<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
@@ -133,7 +133,7 @@ type ToolCallContentPart = {
133
133
  result?: object;
134
134
  };
135
135
  type UserContentPart = TextContentPart | ImageContentPart | UIContentPart;
136
- type AssistantContentPart = TextContentPart | ImageContentPart | UIContentPart | ToolCallContentPart;
136
+ type AssistantContentPart = TextContentPart | UIContentPart | ToolCallContentPart;
137
137
  type AppendContentPart = TextContentPart | ImageContentPart;
138
138
  type BaseMessage = {
139
139
  id: string;
@@ -312,6 +312,70 @@ type RSCMessageConverter<T> = {
312
312
  type VercelRSCAssistantProviderProps<T = VercelRSCMessage> = VercelRSCAssistantProviderBaseProps<T> & (T extends VercelRSCMessage ? object : RSCMessageConverter<T>);
313
313
  declare const VercelRSCAssistantProvider: <T extends WeakKey = VercelRSCMessage>({ children, convertMessage, messages: vercelMessages, append: appendCallback, edit, reload, }: VercelRSCAssistantProviderProps<T>) => react_jsx_runtime.JSX.Element;
314
314
 
315
+ type MessageUpdateCallback = (parentId: string | null, message: ThreadMessage) => void;
316
+ type StatusUpdateCallback = (isRunning: boolean) => void;
317
+ type Unsubscribe = () => void;
318
+ type ThreadRuntime = {
319
+ append(message: AppendMessage): Promise<{
320
+ parentId: string;
321
+ id: string;
322
+ }>;
323
+ startRun(parentId: string | null): Promise<{
324
+ id: string;
325
+ }>;
326
+ cancelRun(): void;
327
+ subscribeToMessageUpdates(callback: MessageUpdateCallback): Unsubscribe;
328
+ subscribeToStatusUpdates(callback: StatusUpdateCallback): Unsubscribe;
329
+ };
330
+
331
+ type AssistantProviderProps = {
332
+ runtime: ThreadRuntime;
333
+ };
334
+ declare const AssistantProvider: FC<PropsWithChildren<AssistantProviderProps>>;
335
+
336
+ type ChatModelRunResult = {
337
+ content: AssistantContentPart[];
338
+ };
339
+ type ChatModelRunOptions = {
340
+ messages: ThreadMessage[];
341
+ abortSignal: AbortSignal;
342
+ onUpdate: (result: ChatModelRunResult) => void;
343
+ };
344
+ type ChatModelAdapter = {
345
+ run: (options: ChatModelRunOptions) => Promise<ChatModelRunResult>;
346
+ };
347
+
348
+ declare class LocalRuntime implements ThreadRuntime {
349
+ adapter: ChatModelAdapter;
350
+ private _messageUpdateCallbacks;
351
+ private _statusUpdateCallbacks;
352
+ private abortController;
353
+ private repository;
354
+ constructor(adapter: ChatModelAdapter);
355
+ append(message: AppendMessage): Promise<{
356
+ parentId: string;
357
+ id: string;
358
+ }>;
359
+ startRun(parentId: string | null): Promise<{
360
+ id: string;
361
+ }>;
362
+ private addOrUpdateMessage;
363
+ private run;
364
+ cancelRun(): void;
365
+ subscribeToMessageUpdates(callback: MessageUpdateCallback): Unsubscribe;
366
+ subscribeToStatusUpdates(callback: StatusUpdateCallback): Unsubscribe;
367
+ }
368
+
369
+ declare const useLocalRuntime: (adapter: ChatModelAdapter) => LocalRuntime;
370
+
371
+ declare class VercelModelAdapter implements ChatModelAdapter {
372
+ private readonly model;
373
+ constructor(model: LanguageModel);
374
+ run({ messages, abortSignal, onUpdate }: ChatModelRunOptions): Promise<{
375
+ content: AssistantContentPart[];
376
+ }>;
377
+ }
378
+
315
379
  declare const getVercelMessage: (message: ThreadMessage) => Message | undefined;
316
380
  declare const getVercelRSCMessage: <T>(message: ThreadMessage) => T | undefined;
317
381
 
@@ -346,4 +410,4 @@ declare const useGoToNextBranch: () => (() => void) | null;
346
410
 
347
411
  declare const useGoToPreviousBranch: () => (() => void) | null;
348
412
 
349
- export { index$1 as ActionBarPrimitive, type AppendContentPart, type AppendMessage, index$2 as BranchPickerPrimitive, index$4 as ComposerPrimitive, index as ContentPartPrimitive, type ImageContentPart, index$3 as MessagePrimitive, type VercelRSCMessage as RSCMessage, type TextContentPart, index$5 as ThreadPrimitive, VercelAIAssistantProvider, type VercelAIAssistantProviderProps, VercelRSCAssistantProvider, type VercelRSCAssistantProviderProps, getVercelMessage as unstable_getVercelMessage, getVercelRSCMessage as unstable_getVercelRSCMessage, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
413
+ export { index$1 as ActionBarPrimitive, type AppendContentPart, type AppendMessage, index$2 as BranchPickerPrimitive, index$4 as ComposerPrimitive, index as ContentPartPrimitive, type ImageContentPart, index$3 as MessagePrimitive, type VercelRSCMessage as RSCMessage, type TextContentPart, index$5 as ThreadPrimitive, VercelAIAssistantProvider, type VercelAIAssistantProviderProps, VercelRSCAssistantProvider, type VercelRSCAssistantProviderProps, AssistantProvider as unstable_AssistantProvider, type ChatModelAdapter as unstable_ChatModelAdapter, type ChatModelRunOptions as unstable_ChatModelRunOptions, VercelModelAdapter as unstable_VercelModelAdapter, getVercelMessage as unstable_getVercelMessage, getVercelRSCMessage as unstable_getVercelRSCMessage, useLocalRuntime as unstable_useLocalRuntime, useMessageContext as unstable_useMessageContext, useBeginMessageEdit, useCopyMessage, useGoToNextBranch, useGoToPreviousBranch, useReloadMessage };
package/dist/index.js CHANGED
@@ -38,8 +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,
41
43
  unstable_getVercelMessage: () => getVercelMessage,
42
44
  unstable_getVercelRSCMessage: () => getVercelRSCMessage,
45
+ unstable_useLocalRuntime: () => useLocalRuntime,
43
46
  unstable_useMessageContext: () => useMessageContext,
44
47
  useBeginMessageEdit: () => useBeginMessageEdit,
45
48
  useCopyMessage: () => useCopyMessage,
@@ -1090,7 +1093,7 @@ var useDummyAIAssistantContext = () => {
1090
1093
  var import_react_use_callback_ref3 = require("@radix-ui/react-use-callback-ref");
1091
1094
  var import_react25 = require("react");
1092
1095
 
1093
- // src/adapters/MessageRepository.tsx
1096
+ // src/adapters/idUtils.tsx
1094
1097
  var import_non_secure = require("nanoid/non-secure");
1095
1098
  var generateId = (0, import_non_secure.customAlphabet)(
1096
1099
  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
@@ -1098,6 +1101,8 @@ var generateId = (0, import_non_secure.customAlphabet)(
1098
1101
  );
1099
1102
  var optimisticPrefix = "__optimistic__";
1100
1103
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1104
+
1105
+ // src/adapters/MessageRepository.tsx
1101
1106
  var findHead = (message) => {
1102
1107
  if (message.next) return findHead(message.next);
1103
1108
  return message;
@@ -1109,15 +1114,6 @@ var MessageRepository = class {
1109
1114
  root = {
1110
1115
  children: []
1111
1116
  };
1112
- getFallbackChild(p) {
1113
- const childId = p.children.at(-1);
1114
- const child = childId ? this.messages.get(childId) : null;
1115
- if (child === void 0)
1116
- throw new Error(
1117
- "MessageRepository(getFallbackChild): Child message not found. This is likely an internal bug in assistant-ui."
1118
- );
1119
- return child;
1120
- }
1121
1117
  performOp(newParent, child, operation) {
1122
1118
  const parentOrRoot = child.prev ?? this.root;
1123
1119
  const newParentOrRoot = newParent ?? this.root;
@@ -1127,7 +1123,14 @@ var MessageRepository = class {
1127
1123
  (m) => m !== child.current.id
1128
1124
  );
1129
1125
  if (child.prev?.next === child) {
1130
- 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;
1131
1134
  }
1132
1135
  }
1133
1136
  if (operation !== "cut") {
@@ -1186,14 +1189,14 @@ var MessageRepository = class {
1186
1189
  });
1187
1190
  return optimisticId;
1188
1191
  }
1189
- deleteMessage(messageId, newParentId) {
1192
+ deleteMessage(messageId, replacementId) {
1190
1193
  const message = this.messages.get(messageId);
1191
- const newParent = newParentId ? this.messages.get(newParentId) : null;
1194
+ const replacement = replacementId ? this.messages.get(replacementId) : null;
1192
1195
  if (!message)
1193
1196
  throw new Error(
1194
1197
  "MessageRepository(deleteMessage): Optimistic message not found. This is likely an internal bug in assistant-ui."
1195
1198
  );
1196
- if (newParent === void 0)
1199
+ if (replacement === void 0)
1197
1200
  throw new Error(
1198
1201
  "MessageRepository(deleteMessage): New message not found. This is likely an internal bug in assistant-ui."
1199
1202
  );
@@ -1203,11 +1206,11 @@ var MessageRepository = class {
1203
1206
  throw new Error(
1204
1207
  "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
1205
1208
  );
1206
- this.performOp(newParent, childMessage, "relink");
1209
+ this.performOp(replacement, childMessage, "relink");
1207
1210
  }
1208
1211
  this.messages.delete(messageId);
1209
1212
  if (this.head === message) {
1210
- this.head = this.getFallbackChild(message.prev ?? this.root);
1213
+ this.head = replacement;
1211
1214
  }
1212
1215
  this.performOp(null, message, "cut");
1213
1216
  }
@@ -1250,17 +1253,13 @@ var MessageRepository = class {
1250
1253
  }
1251
1254
  };
1252
1255
 
1253
- // src/adapters/ThreadMessageConverter.tsx
1256
+ // src/adapters/ThreadMessageConverter.ts
1254
1257
  var ThreadMessageConverter = class {
1255
- constructor(converter) {
1256
- this.converter = converter;
1257
- }
1258
1258
  cache = /* @__PURE__ */ new WeakMap();
1259
- convertMessages(messages) {
1259
+ convertMessages(converter, messages) {
1260
1260
  return messages.map((m) => {
1261
1261
  const cached = this.cache.get(m);
1262
- if (cached) return cached;
1263
- const newMessage = this.converter(m);
1262
+ const newMessage = converter(m, cached);
1264
1263
  this.cache.set(m, newMessage);
1265
1264
  return newMessage;
1266
1265
  });
@@ -1333,16 +1332,17 @@ var getIsRunning = (vercel) => {
1333
1332
  var useVercelAIThreadState = (vercel) => {
1334
1333
  const [data] = (0, import_react25.useState)(() => new MessageRepository());
1335
1334
  const isRunning = getIsRunning(vercel);
1336
- const convertCallback = (0, import_react_use_callback_ref3.useCallbackRef)((message) => {
1337
- return vercelToThreadMessage(
1338
- message,
1339
- vercel.messages.at(-1) === message && isRunning ? "in_progress" : "done"
1340
- );
1341
- });
1342
- const converter = new ThreadMessageConverter(convertCallback);
1335
+ const converter = (0, import_react25.useMemo)(() => new ThreadMessageConverter(), []);
1343
1336
  const assistantOptimisticIdRef = (0, import_react25.useRef)(null);
1344
1337
  const messages = (0, import_react25.useMemo)(() => {
1345
- 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);
1346
1346
  for (let i = 0; i < vm.length; i++) {
1347
1347
  const message = vm[i];
1348
1348
  const parent = vm[i - 1];
@@ -1490,15 +1490,17 @@ var VercelRSCAssistantProvider = ({
1490
1490
  setIsRunning(true);
1491
1491
  return callback.finally(() => setIsRunning(false));
1492
1492
  }, []);
1493
- const converter = (0, import_react27.useMemo)(() => {
1493
+ const [converter, convertCallback] = (0, import_react27.useMemo)(() => {
1494
1494
  const rscConverter = convertMessage ?? ((m) => m);
1495
- return new ThreadMessageConverter((m) => {
1495
+ const convertCallback2 = (m, cache) => {
1496
+ if (cache) return cache;
1496
1497
  return vercelToThreadMessage2(rscConverter, m);
1497
- });
1498
+ };
1499
+ return [new ThreadMessageConverter(), convertCallback2];
1498
1500
  }, [convertMessage]);
1499
1501
  const messages = (0, import_react27.useMemo)(() => {
1500
- return converter.convertMessages(vercelMessages);
1501
- }, [converter, vercelMessages]);
1502
+ return converter.convertMessages(convertCallback, vercelMessages);
1503
+ }, [converter, convertCallback, vercelMessages]);
1502
1504
  const append = (0, import_react27.useCallback)(
1503
1505
  async (message) => {
1504
1506
  if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
@@ -1539,6 +1541,259 @@ var VercelRSCAssistantProvider = ({
1539
1541
  }, [context, messages, isRunning, append, startRun]);
1540
1542
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(AssistantContext.Provider, { value: context, children });
1541
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
+ };
1542
1797
  // Annotate the CommonJS export names for ESM import in node:
1543
1798
  0 && (module.exports = {
1544
1799
  ActionBarPrimitive,
@@ -1549,8 +1804,11 @@ var VercelRSCAssistantProvider = ({
1549
1804
  ThreadPrimitive,
1550
1805
  VercelAIAssistantProvider,
1551
1806
  VercelRSCAssistantProvider,
1807
+ unstable_AssistantProvider,
1808
+ unstable_VercelModelAdapter,
1552
1809
  unstable_getVercelMessage,
1553
1810
  unstable_getVercelRSCMessage,
1811
+ unstable_useLocalRuntime,
1554
1812
  unstable_useMessageContext,
1555
1813
  useBeginMessageEdit,
1556
1814
  useCopyMessage,
package/dist/index.mjs CHANGED
@@ -1076,7 +1076,7 @@ var useDummyAIAssistantContext = () => {
1076
1076
  import { useCallbackRef as useCallbackRef3 } from "@radix-ui/react-use-callback-ref";
1077
1077
  import { useCallback as useCallback2, useMemo as useMemo5, useRef as useRef4, useState as useState4 } from "react";
1078
1078
 
1079
- // src/adapters/MessageRepository.tsx
1079
+ // src/adapters/idUtils.tsx
1080
1080
  import { customAlphabet } from "nanoid/non-secure";
1081
1081
  var generateId = customAlphabet(
1082
1082
  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
@@ -1084,6 +1084,8 @@ var generateId = customAlphabet(
1084
1084
  );
1085
1085
  var optimisticPrefix = "__optimistic__";
1086
1086
  var generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
1087
+
1088
+ // src/adapters/MessageRepository.tsx
1087
1089
  var findHead = (message) => {
1088
1090
  if (message.next) return findHead(message.next);
1089
1091
  return message;
@@ -1095,15 +1097,6 @@ var MessageRepository = class {
1095
1097
  root = {
1096
1098
  children: []
1097
1099
  };
1098
- getFallbackChild(p) {
1099
- const childId = p.children.at(-1);
1100
- const child = childId ? this.messages.get(childId) : null;
1101
- if (child === void 0)
1102
- throw new Error(
1103
- "MessageRepository(getFallbackChild): Child message not found. This is likely an internal bug in assistant-ui."
1104
- );
1105
- return child;
1106
- }
1107
1100
  performOp(newParent, child, operation) {
1108
1101
  const parentOrRoot = child.prev ?? this.root;
1109
1102
  const newParentOrRoot = newParent ?? this.root;
@@ -1113,7 +1106,14 @@ var MessageRepository = class {
1113
1106
  (m) => m !== child.current.id
1114
1107
  );
1115
1108
  if (child.prev?.next === child) {
1116
- child.prev.next = this.getFallbackChild(child.prev);
1109
+ const fallbackId = child.prev.children.at(-1);
1110
+ const fallback = fallbackId ? this.messages.get(fallbackId) : null;
1111
+ if (fallback === void 0) {
1112
+ throw new Error(
1113
+ "MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui."
1114
+ );
1115
+ }
1116
+ child.prev.next = fallback;
1117
1117
  }
1118
1118
  }
1119
1119
  if (operation !== "cut") {
@@ -1172,14 +1172,14 @@ var MessageRepository = class {
1172
1172
  });
1173
1173
  return optimisticId;
1174
1174
  }
1175
- deleteMessage(messageId, newParentId) {
1175
+ deleteMessage(messageId, replacementId) {
1176
1176
  const message = this.messages.get(messageId);
1177
- const newParent = newParentId ? this.messages.get(newParentId) : null;
1177
+ const replacement = replacementId ? this.messages.get(replacementId) : null;
1178
1178
  if (!message)
1179
1179
  throw new Error(
1180
1180
  "MessageRepository(deleteMessage): Optimistic message not found. This is likely an internal bug in assistant-ui."
1181
1181
  );
1182
- if (newParent === void 0)
1182
+ if (replacement === void 0)
1183
1183
  throw new Error(
1184
1184
  "MessageRepository(deleteMessage): New message not found. This is likely an internal bug in assistant-ui."
1185
1185
  );
@@ -1189,11 +1189,11 @@ var MessageRepository = class {
1189
1189
  throw new Error(
1190
1190
  "MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui."
1191
1191
  );
1192
- this.performOp(newParent, childMessage, "relink");
1192
+ this.performOp(replacement, childMessage, "relink");
1193
1193
  }
1194
1194
  this.messages.delete(messageId);
1195
1195
  if (this.head === message) {
1196
- this.head = this.getFallbackChild(message.prev ?? this.root);
1196
+ this.head = replacement;
1197
1197
  }
1198
1198
  this.performOp(null, message, "cut");
1199
1199
  }
@@ -1236,17 +1236,13 @@ var MessageRepository = class {
1236
1236
  }
1237
1237
  };
1238
1238
 
1239
- // src/adapters/ThreadMessageConverter.tsx
1239
+ // src/adapters/ThreadMessageConverter.ts
1240
1240
  var ThreadMessageConverter = class {
1241
- constructor(converter) {
1242
- this.converter = converter;
1243
- }
1244
1241
  cache = /* @__PURE__ */ new WeakMap();
1245
- convertMessages(messages) {
1242
+ convertMessages(converter, messages) {
1246
1243
  return messages.map((m) => {
1247
1244
  const cached = this.cache.get(m);
1248
- if (cached) return cached;
1249
- const newMessage = this.converter(m);
1245
+ const newMessage = converter(m, cached);
1250
1246
  this.cache.set(m, newMessage);
1251
1247
  return newMessage;
1252
1248
  });
@@ -1319,16 +1315,17 @@ var getIsRunning = (vercel) => {
1319
1315
  var useVercelAIThreadState = (vercel) => {
1320
1316
  const [data] = useState4(() => new MessageRepository());
1321
1317
  const isRunning = getIsRunning(vercel);
1322
- const convertCallback = useCallbackRef3((message) => {
1323
- return vercelToThreadMessage(
1324
- message,
1325
- vercel.messages.at(-1) === message && isRunning ? "in_progress" : "done"
1326
- );
1327
- });
1328
- const converter = new ThreadMessageConverter(convertCallback);
1318
+ const converter = useMemo5(() => new ThreadMessageConverter(), []);
1329
1319
  const assistantOptimisticIdRef = useRef4(null);
1330
1320
  const messages = useMemo5(() => {
1331
- const vm = converter.convertMessages(vercel.messages);
1321
+ const lastMessageId = vercel.messages.at(-1)?.id;
1322
+ const convertCallback = (message, cache) => {
1323
+ const status = lastMessageId === message.id && isRunning ? "in_progress" : "done";
1324
+ if (cache && (cache.role === "user" || cache.status === status))
1325
+ return cache;
1326
+ return vercelToThreadMessage(message, status);
1327
+ };
1328
+ const vm = converter.convertMessages(convertCallback, vercel.messages);
1332
1329
  for (let i = 0; i < vm.length; i++) {
1333
1330
  const message = vm[i];
1334
1331
  const parent = vm[i - 1];
@@ -1480,15 +1477,17 @@ var VercelRSCAssistantProvider = ({
1480
1477
  setIsRunning(true);
1481
1478
  return callback.finally(() => setIsRunning(false));
1482
1479
  }, []);
1483
- const converter = useMemo7(() => {
1480
+ const [converter, convertCallback] = useMemo7(() => {
1484
1481
  const rscConverter = convertMessage ?? ((m) => m);
1485
- return new ThreadMessageConverter((m) => {
1482
+ const convertCallback2 = (m, cache) => {
1483
+ if (cache) return cache;
1486
1484
  return vercelToThreadMessage2(rscConverter, m);
1487
- });
1485
+ };
1486
+ return [new ThreadMessageConverter(), convertCallback2];
1488
1487
  }, [convertMessage]);
1489
1488
  const messages = useMemo7(() => {
1490
- return converter.convertMessages(vercelMessages);
1491
- }, [converter, vercelMessages]);
1489
+ return converter.convertMessages(convertCallback, vercelMessages);
1490
+ }, [converter, convertCallback, vercelMessages]);
1492
1491
  const append = useCallback3(
1493
1492
  async (message) => {
1494
1493
  if (message.parentId !== (context.useThread.getState().messages.at(-1)?.id ?? null)) {
@@ -1529,6 +1528,259 @@ var VercelRSCAssistantProvider = ({
1529
1528
  }, [context, messages, isRunning, append, startRun]);
1530
1529
  return /* @__PURE__ */ jsx22(AssistantContext.Provider, { value: context, children });
1531
1530
  };
1531
+
1532
+ // src/adapters/core/utils/useAssistantContext.tsx
1533
+ import { useEffect as useEffect4, useRef as useRef5, useState as useState6 } from "react";
1534
+ import { create as create6 } from "zustand";
1535
+
1536
+ // src/adapters/core/utils/AssistantMessageRepository.tsx
1537
+ var AssistantMessageRepository = class {
1538
+ constructor(flushCallback) {
1539
+ this.flushCallback = flushCallback;
1540
+ }
1541
+ repository = new MessageRepository();
1542
+ getBranches(messageId) {
1543
+ return this.repository.getBranches(messageId);
1544
+ }
1545
+ withModifications(callback) {
1546
+ const res = callback(this.repository);
1547
+ this.flushCallback(this.repository.getMessages());
1548
+ return res;
1549
+ }
1550
+ };
1551
+
1552
+ // src/adapters/core/utils/useAssistantContext.tsx
1553
+ var makeThreadStore = (runtimeRef) => {
1554
+ const repository = new AssistantMessageRepository((messages) => {
1555
+ useThread.setState({ messages });
1556
+ });
1557
+ const useThread = create6(() => ({
1558
+ messages: [],
1559
+ isRunning: false,
1560
+ getBranches: (messageId) => repository.getBranches(messageId),
1561
+ switchToBranch: (branchId) => {
1562
+ repository.withModifications((repository2) => {
1563
+ repository2.switchToBranch(branchId);
1564
+ });
1565
+ },
1566
+ startRun: async (parentId) => {
1567
+ const optimisticId = repository.withModifications((repository2) => {
1568
+ const optimisticId2 = repository2.appendOptimisticMessage(parentId, {
1569
+ role: "assistant",
1570
+ content: [{ type: "text", text: "" }]
1571
+ });
1572
+ repository2.resetHead(optimisticId2);
1573
+ return optimisticId2;
1574
+ });
1575
+ const { id } = await runtimeRef.current.startRun(parentId);
1576
+ repository.withModifications((repository2) => {
1577
+ repository2.deleteMessage(optimisticId, id);
1578
+ });
1579
+ },
1580
+ append: async (message) => {
1581
+ const [parentOptimisticId, optimisticId] = repository.withModifications(
1582
+ (repository2) => {
1583
+ const parentOptimisticId2 = repository2.appendOptimisticMessage(
1584
+ message.parentId,
1585
+ {
1586
+ role: "user",
1587
+ content: message.content
1588
+ }
1589
+ );
1590
+ const optimisticId2 = repository2.appendOptimisticMessage(
1591
+ parentOptimisticId2,
1592
+ {
1593
+ role: "assistant",
1594
+ content: [{ type: "text", text: "" }]
1595
+ }
1596
+ );
1597
+ repository2.resetHead(optimisticId2);
1598
+ return [parentOptimisticId2, optimisticId2];
1599
+ }
1600
+ );
1601
+ const { parentId, id } = await runtimeRef.current.append(message);
1602
+ repository.withModifications((repository2) => {
1603
+ repository2.deleteMessage(parentOptimisticId, parentId);
1604
+ repository2.deleteMessage(optimisticId, id);
1605
+ });
1606
+ },
1607
+ cancelRun: () => runtimeRef.current.cancelRun()
1608
+ }));
1609
+ const onNewMessage = (parentId, message) => {
1610
+ repository.withModifications((repository2) => {
1611
+ repository2.addOrUpdateMessage(parentId, message);
1612
+ });
1613
+ };
1614
+ const onRunningChange = (isRunning) => {
1615
+ useThread.setState({ isRunning });
1616
+ };
1617
+ return {
1618
+ useThread,
1619
+ onNewMessage,
1620
+ onRunningChange
1621
+ };
1622
+ };
1623
+ var useAssistantContext2 = (runtime) => {
1624
+ const runtimeRef = useRef5(runtime);
1625
+ runtimeRef.current = runtime;
1626
+ const [{ context, onNewMessage, onRunningChange }] = useState6(() => {
1627
+ const { useThread, onNewMessage: onNewMessage2, onRunningChange: onRunningChange2 } = makeThreadStore(runtimeRef);
1628
+ const useViewport = makeViewportStore();
1629
+ const useComposer = makeThreadComposerStore(useThread);
1630
+ return {
1631
+ context: { useViewport, useThread, useComposer },
1632
+ onNewMessage: onNewMessage2,
1633
+ onRunningChange: onRunningChange2
1634
+ };
1635
+ });
1636
+ useEffect4(() => {
1637
+ return runtime.subscribeToMessageUpdates(onNewMessage);
1638
+ }, [runtime, onNewMessage]);
1639
+ useEffect4(() => {
1640
+ return runtime.subscribeToStatusUpdates(onRunningChange);
1641
+ }, [runtime, onRunningChange]);
1642
+ return context;
1643
+ };
1644
+
1645
+ // src/adapters/core/AssistantProvider.tsx
1646
+ import { jsx as jsx23 } from "react/jsx-runtime";
1647
+ var AssistantProvider = ({ children, runtime }) => {
1648
+ const context = useAssistantContext2(runtime);
1649
+ return /* @__PURE__ */ jsx23(AssistantContext.Provider, { value: context, children });
1650
+ };
1651
+
1652
+ // src/adapters/core/local/useLocalRuntime.tsx
1653
+ import { useState as useState7 } from "react";
1654
+
1655
+ // src/adapters/core/local/LocalRuntime.tsx
1656
+ var LocalRuntime = class {
1657
+ constructor(adapter) {
1658
+ this.adapter = adapter;
1659
+ }
1660
+ _messageUpdateCallbacks = /* @__PURE__ */ new Set();
1661
+ _statusUpdateCallbacks = /* @__PURE__ */ new Set();
1662
+ abortController = null;
1663
+ repository = new MessageRepository();
1664
+ async append(message) {
1665
+ const userMessageId = generateId();
1666
+ const userMessage = {
1667
+ id: userMessageId,
1668
+ role: "user",
1669
+ content: message.content,
1670
+ createdAt: /* @__PURE__ */ new Date()
1671
+ };
1672
+ this.addOrUpdateMessage(message.parentId, userMessage);
1673
+ const { id } = await this.startRun(userMessageId);
1674
+ return { parentId: userMessageId, id };
1675
+ }
1676
+ async startRun(parentId) {
1677
+ const id = generateId();
1678
+ this.repository.resetHead(parentId);
1679
+ const messages = this.repository.getMessages();
1680
+ const message = {
1681
+ id,
1682
+ role: "assistant",
1683
+ status: "in_progress",
1684
+ content: [{ type: "text", text: "" }],
1685
+ createdAt: /* @__PURE__ */ new Date()
1686
+ };
1687
+ this.addOrUpdateMessage(parentId, message);
1688
+ void this.run(parentId, messages, message);
1689
+ return { id };
1690
+ }
1691
+ addOrUpdateMessage(parentId, message) {
1692
+ const clone = { ...message };
1693
+ this.repository.addOrUpdateMessage(parentId, clone);
1694
+ for (const callback of this._messageUpdateCallbacks)
1695
+ callback(parentId, clone);
1696
+ }
1697
+ async run(parentId, messages, message) {
1698
+ this.cancelRun();
1699
+ for (const callback of this._statusUpdateCallbacks) callback(true);
1700
+ this.abortController = new AbortController();
1701
+ try {
1702
+ await this.adapter.run({
1703
+ messages,
1704
+ abortSignal: this.abortController.signal,
1705
+ onUpdate: ({ content }) => {
1706
+ message.content = content;
1707
+ this.addOrUpdateMessage(parentId, message);
1708
+ }
1709
+ });
1710
+ message.status = "done";
1711
+ this.addOrUpdateMessage(parentId, message);
1712
+ } catch (e) {
1713
+ message.status = "error";
1714
+ this.addOrUpdateMessage(parentId, message);
1715
+ console.error(e);
1716
+ } finally {
1717
+ this.cancelRun();
1718
+ }
1719
+ }
1720
+ cancelRun() {
1721
+ if (!this.abortController) return;
1722
+ this.abortController.abort();
1723
+ this.abortController = null;
1724
+ for (const callback of this._statusUpdateCallbacks) callback(false);
1725
+ }
1726
+ subscribeToMessageUpdates(callback) {
1727
+ this._messageUpdateCallbacks.add(callback);
1728
+ return () => this._messageUpdateCallbacks.delete(callback);
1729
+ }
1730
+ subscribeToStatusUpdates(callback) {
1731
+ this._statusUpdateCallbacks.add(callback);
1732
+ return () => this._statusUpdateCallbacks.delete(callback);
1733
+ }
1734
+ };
1735
+
1736
+ // src/adapters/core/local/useLocalRuntime.tsx
1737
+ var useLocalRuntime = (adapter) => {
1738
+ const [runtime] = useState7(() => new LocalRuntime(adapter));
1739
+ runtime.adapter = adapter;
1740
+ return runtime;
1741
+ };
1742
+
1743
+ // src/adapters/core/local/vercel/VercelModelAdapter.tsx
1744
+ import { streamText } from "ai";
1745
+ var VercelModelAdapter = class {
1746
+ constructor(model) {
1747
+ this.model = model;
1748
+ }
1749
+ async run({ messages, abortSignal, onUpdate }) {
1750
+ const { fullStream } = await streamText({
1751
+ model: this.model,
1752
+ abortSignal,
1753
+ messages: messages.map((m) => ({
1754
+ role: m.role,
1755
+ content: m.content.filter((c) => c.type !== "ui")
1756
+ }))
1757
+ });
1758
+ const content = [];
1759
+ for await (const aiPart of fullStream) {
1760
+ switch (aiPart.type) {
1761
+ case "text-delta": {
1762
+ let part = content.at(-1);
1763
+ if (!part || part.type !== "text") {
1764
+ part = { type: "text", text: "" };
1765
+ content.push(part);
1766
+ }
1767
+ part.text += aiPart.textDelta;
1768
+ break;
1769
+ }
1770
+ case "tool-call": {
1771
+ content.push({
1772
+ type: "tool-call",
1773
+ name: aiPart.toolName,
1774
+ args: aiPart.args
1775
+ });
1776
+ break;
1777
+ }
1778
+ }
1779
+ onUpdate({ content });
1780
+ }
1781
+ return { content };
1782
+ }
1783
+ };
1532
1784
  export {
1533
1785
  actionBar_exports as ActionBarPrimitive,
1534
1786
  branchPicker_exports as BranchPickerPrimitive,
@@ -1538,8 +1790,11 @@ export {
1538
1790
  thread_exports as ThreadPrimitive,
1539
1791
  VercelAIAssistantProvider,
1540
1792
  VercelRSCAssistantProvider,
1793
+ AssistantProvider as unstable_AssistantProvider,
1794
+ VercelModelAdapter as unstable_VercelModelAdapter,
1541
1795
  getVercelMessage as unstable_getVercelMessage,
1542
1796
  getVercelRSCMessage as unstable_getVercelRSCMessage,
1797
+ useLocalRuntime as unstable_useLocalRuntime,
1543
1798
  useMessageContext as unstable_useMessageContext,
1544
1799
  useBeginMessageEdit,
1545
1800
  useCopyMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": {