@assistant-ui/react 0.0.17 → 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.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
  ".": {