@assistant-ui/react-ai-sdk 1.1.13 → 1.1.15

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.
@@ -1,11 +1,20 @@
1
1
  import type { UIMessage, useChat, CreateUIMessage } from "@ai-sdk/react";
2
- import { ExternalStoreAdapter, ThreadHistoryAdapter, AssistantRuntime, AppendMessage } from "@assistant-ui/react";
2
+ import { type ExternalStoreAdapter, type ThreadHistoryAdapter, type AssistantRuntime, type AppendMessage } from "@assistant-ui/react";
3
3
  export type CustomToCreateMessageFunction = <UI_MESSAGE extends UIMessage = UIMessage>(message: AppendMessage) => CreateUIMessage<UI_MESSAGE>;
4
4
  export type AISDKRuntimeAdapter = {
5
5
  adapters?: (NonNullable<ExternalStoreAdapter["adapters"]> & {
6
6
  history?: ThreadHistoryAdapter | undefined;
7
7
  }) | undefined;
8
8
  toCreateMessage?: CustomToCreateMessageFunction;
9
+ /**
10
+ * Whether to automatically cancel pending interactive tool calls when the user sends a new message.
11
+ *
12
+ * When enabled (default), the pending tool calls will be marked as failed with an error message
13
+ * indicating the user cancelled the tool call by sending a new message.
14
+ *
15
+ * @default true
16
+ */
17
+ cancelPendingToolCallsOnSend?: boolean | undefined;
9
18
  };
10
- export declare const useAISDKRuntime: <UI_MESSAGE extends UIMessage = UIMessage>(chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>, { adapters, toCreateMessage: customToCreateMessage, }?: AISDKRuntimeAdapter) => AssistantRuntime;
19
+ export declare const useAISDKRuntime: <UI_MESSAGE extends UIMessage = UIMessage>(chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>, { adapters, toCreateMessage: customToCreateMessage, cancelPendingToolCallsOnSend, }?: AISDKRuntimeAdapter) => AssistantRuntime;
11
20
  //# sourceMappingURL=useAISDKRuntime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAISDKRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useAISDKRuntime.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAEL,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAMhB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAI7B,MAAM,MAAM,6BAA6B,GAAG,CAC1C,UAAU,SAAS,SAAS,GAAG,SAAS,EAExC,OAAO,EAAE,aAAa,KACnB,eAAe,CAAC,UAAU,CAAC,CAAC;AAWjC,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EACL,CAAC,WAAW,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,GAAG;QAC/C,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;KAC5C,CAAC,GACF,SAAS,CAAC;IACd,eAAe,CAAC,EAAE,6BAA6B,CAAC;CACjD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EACtE,aAAa,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,EACnD,wDAGG,mBAAwB,qBA2I5B,CAAC"}
1
+ {"version":3,"file":"useAISDKRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useAISDKRuntime.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAMrB,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAI7B,MAAM,MAAM,6BAA6B,GAAG,CAC1C,UAAU,SAAS,SAAS,GAAG,SAAS,EAExC,OAAO,EAAE,aAAa,KACnB,eAAe,CAAC,UAAU,CAAC,CAAC;AAejC,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EACL,CAAC,WAAW,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,GAAG;QAC/C,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;KAC5C,CAAC,GACF,SAAS,CAAC;IACd,eAAe,CAAC,EAAE,6BAA6B,CAAC;IAChD;;;;;;;OAOG;IACH,4BAA4B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EACtE,aAAa,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,EACnD,sFAIG,mBAAwB,qBAkM5B,CAAC"}
@@ -18,10 +18,11 @@ import {
18
18
  import { useExternalHistory } from "./useExternalHistory.js";
19
19
  var useAISDKRuntime = (chatHelpers, {
20
20
  adapters,
21
- toCreateMessage: customToCreateMessage
21
+ toCreateMessage: customToCreateMessage,
22
+ cancelPendingToolCallsOnSend = true
22
23
  } = {}) => {
23
24
  const contextAdapters = useRuntimeAdapters();
24
- const isRunning = chatHelpers.status === "submitted" || chatHelpers.status == "streaming";
25
+ const isRunning = chatHelpers.status === "submitted" || chatHelpers.status === "streaming";
25
26
  const [toolStatuses, setToolStatuses] = useState({});
26
27
  const messages = AISDKMessageConverter.useThreadMessages({
27
28
  isRunning,
@@ -65,6 +66,41 @@ var useAISDKRuntime = (chatHelpers, {
65
66
  chatHelpers.setMessages(messages2);
66
67
  }
67
68
  );
69
+ const completePendingToolCalls = () => {
70
+ if (!cancelPendingToolCallsOnSend) return;
71
+ const pendingHumanTools = Object.entries(toolStatuses).filter(
72
+ (entry) => entry[1]?.type === "interrupt"
73
+ ).map(([toolCallId]) => ({ toolCallId }));
74
+ if (pendingHumanTools.length === 0) return;
75
+ setToolStatuses((prev) => {
76
+ const next = { ...prev };
77
+ pendingHumanTools.forEach(({ toolCallId }) => {
78
+ next[toolCallId] = {
79
+ type: "cancelled",
80
+ reason: "User cancelled tool call by sending a new message."
81
+ };
82
+ });
83
+ return next;
84
+ });
85
+ pendingHumanTools.forEach(({ toolCallId }) => {
86
+ chatHelpers.setMessages(
87
+ chatHelpers.messages.map((message) => {
88
+ if (message.id === toolCallId) {
89
+ return {
90
+ ...message,
91
+ content: [
92
+ {
93
+ type: "text",
94
+ text: "User cancelled tool call by sending a new message."
95
+ }
96
+ ]
97
+ };
98
+ }
99
+ return message;
100
+ })
101
+ );
102
+ });
103
+ };
68
104
  const runtime = useExternalStoreRuntime({
69
105
  isRunning,
70
106
  messages,
@@ -79,12 +115,14 @@ var useAISDKRuntime = (chatHelpers, {
79
115
  toolInvocations.abort();
80
116
  },
81
117
  onNew: async (message) => {
118
+ completePendingToolCalls();
82
119
  const createMessage = (customToCreateMessage ?? toCreateMessage)(message);
83
120
  await chatHelpers.sendMessage(createMessage, {
84
121
  metadata: message.runConfig
85
122
  });
86
123
  },
87
124
  onEdit: async (message) => {
125
+ completePendingToolCalls();
88
126
  const newMessages = sliceMessagesUntil(
89
127
  chatHelpers.messages,
90
128
  message.parentId
@@ -96,6 +134,7 @@ var useAISDKRuntime = (chatHelpers, {
96
134
  });
97
135
  },
98
136
  onReload: async (parentId, config) => {
137
+ completePendingToolCalls();
99
138
  const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);
100
139
  chatHelpers.setMessages(newMessages);
101
140
  await chatHelpers.regenerate({ metadata: config.runConfig });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/use-chat/useAISDKRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport type { UIMessage, useChat, CreateUIMessage } from \"@ai-sdk/react\";\nimport {\n useExternalStoreRuntime,\n ExternalStoreAdapter,\n ThreadHistoryAdapter,\n AssistantRuntime,\n ThreadMessage,\n MessageFormatAdapter,\n useRuntimeAdapters,\n INTERNAL,\n type ToolExecutionStatus,\n AppendMessage,\n} from \"@assistant-ui/react\";\nimport { sliceMessagesUntil } from \"../utils/sliceMessagesUntil\";\nimport { toCreateMessage } from \"../utils/toCreateMessage\";\n\nexport type CustomToCreateMessageFunction = <\n UI_MESSAGE extends UIMessage = UIMessage,\n>(\n message: AppendMessage,\n) => CreateUIMessage<UI_MESSAGE>;\n\nimport { vercelAttachmentAdapter } from \"../utils/vercelAttachmentAdapter\";\nimport { getVercelAIMessages } from \"../getVercelAIMessages\";\nimport { AISDKMessageConverter } from \"../utils/convertMessage\";\nimport {\n AISDKStorageFormat,\n aiSDKV5FormatAdapter,\n} from \"../adapters/aiSDKFormatAdapter\";\nimport { useExternalHistory } from \"./useExternalHistory\";\n\nexport type AISDKRuntimeAdapter = {\n adapters?:\n | (NonNullable<ExternalStoreAdapter[\"adapters\"]> & {\n history?: ThreadHistoryAdapter | undefined;\n })\n | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n};\n\nexport const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,\n {\n adapters,\n toCreateMessage: customToCreateMessage,\n }: AISDKRuntimeAdapter = {},\n) => {\n const contextAdapters = useRuntimeAdapters();\n const isRunning =\n chatHelpers.status === \"submitted\" || chatHelpers.status == \"streaming\";\n\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n\n const messages = AISDKMessageConverter.useThreadMessages({\n isRunning,\n messages: chatHelpers.messages,\n metadata: useMemo(\n () => ({\n toolStatuses,\n ...(chatHelpers.error && { error: chatHelpers.error.message }),\n }),\n [toolStatuses, chatHelpers.error],\n ),\n });\n\n const [runtimeRef] = useState(() => ({\n get current(): AssistantRuntime {\n return runtime;\n },\n }));\n\n const toolInvocations = INTERNAL.useToolInvocations({\n state: {\n messages,\n isRunning,\n },\n getTools: () => runtimeRef.current.thread.getModelContext().tools,\n onResult: (command: any) => {\n if (command.type === \"add-tool-result\") {\n chatHelpers.addToolResult({\n tool: command.toolName,\n toolCallId: command.toolCallId,\n output: command.result,\n });\n }\n },\n setToolStatuses,\n });\n\n const isLoading = useExternalHistory(\n runtimeRef,\n adapters?.history ?? contextAdapters?.history,\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n aiSDKV5FormatAdapter as MessageFormatAdapter<\n UI_MESSAGE,\n AISDKStorageFormat\n >,\n (messages) => {\n chatHelpers.setMessages(messages);\n },\n );\n\n const runtime = useExternalStoreRuntime({\n isRunning,\n messages,\n setMessages: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onImport: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onCancel: async () => {\n chatHelpers.stop();\n toolInvocations.abort();\n },\n onNew: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onEdit: async (message) => {\n const newMessages = sliceMessagesUntil(\n chatHelpers.messages,\n message.parentId,\n );\n chatHelpers.setMessages(newMessages);\n\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onReload: async (parentId: string | null, config) => {\n const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);\n chatHelpers.setMessages(newMessages);\n\n await chatHelpers.regenerate({ metadata: config.runConfig });\n },\n onAddToolResult: ({ toolCallId, result, isError }) => {\n if (isError) {\n chatHelpers.addToolOutput({\n state: \"output-error\",\n tool: toolCallId,\n toolCallId,\n errorText:\n typeof result === \"string\" ? result : JSON.stringify(result),\n });\n } else {\n chatHelpers.addToolOutput({\n state: \"output-available\",\n tool: toolCallId,\n toolCallId,\n output: result,\n });\n }\n },\n onResumeToolCall: (options) =>\n toolInvocations.resume(options.toolCallId, options.payload),\n adapters: {\n attachments: vercelAttachmentAdapter,\n ...contextAdapters,\n ...adapters,\n },\n isLoading,\n });\n\n return runtime;\n};\n"],"mappings":"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","names":["messages"]}
1
+ {"version":3,"sources":["../../../src/ui/use-chat/useAISDKRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport type { UIMessage, useChat, CreateUIMessage } from \"@ai-sdk/react\";\nimport {\n useExternalStoreRuntime,\n type ExternalStoreAdapter,\n type ThreadHistoryAdapter,\n type AssistantRuntime,\n type ThreadMessage,\n type MessageFormatAdapter,\n useRuntimeAdapters,\n INTERNAL,\n type ToolExecutionStatus,\n type AppendMessage,\n} from \"@assistant-ui/react\";\nimport { sliceMessagesUntil } from \"../utils/sliceMessagesUntil\";\nimport { toCreateMessage } from \"../utils/toCreateMessage\";\n\nexport type CustomToCreateMessageFunction = <\n UI_MESSAGE extends UIMessage = UIMessage,\n>(\n message: AppendMessage,\n) => CreateUIMessage<UI_MESSAGE>;\n\nimport { vercelAttachmentAdapter } from \"../utils/vercelAttachmentAdapter\";\nimport { getVercelAIMessages } from \"../getVercelAIMessages\";\nimport { AISDKMessageConverter } from \"../utils/convertMessage\";\nimport {\n type AISDKStorageFormat,\n aiSDKV5FormatAdapter,\n} from \"../adapters/aiSDKFormatAdapter\";\nimport { useExternalHistory } from \"./useExternalHistory\";\n\ntype PendingHumanTool = {\n readonly toolCallId: string;\n};\n\nexport type AISDKRuntimeAdapter = {\n adapters?:\n | (NonNullable<ExternalStoreAdapter[\"adapters\"]> & {\n history?: ThreadHistoryAdapter | undefined;\n })\n | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n /**\n * Whether to automatically cancel pending interactive tool calls when the user sends a new message.\n *\n * When enabled (default), the pending tool calls will be marked as failed with an error message\n * indicating the user cancelled the tool call by sending a new message.\n *\n * @default true\n */\n cancelPendingToolCallsOnSend?: boolean | undefined;\n};\n\nexport const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,\n {\n adapters,\n toCreateMessage: customToCreateMessage,\n cancelPendingToolCallsOnSend = true,\n }: AISDKRuntimeAdapter = {},\n) => {\n const contextAdapters = useRuntimeAdapters();\n const isRunning =\n chatHelpers.status === \"submitted\" || chatHelpers.status === \"streaming\";\n\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n\n const messages = AISDKMessageConverter.useThreadMessages({\n isRunning,\n messages: chatHelpers.messages,\n metadata: useMemo(\n () => ({\n toolStatuses,\n ...(chatHelpers.error && { error: chatHelpers.error.message }),\n }),\n [toolStatuses, chatHelpers.error],\n ),\n });\n\n const [runtimeRef] = useState(() => ({\n get current(): AssistantRuntime {\n return runtime;\n },\n }));\n\n const toolInvocations = INTERNAL.useToolInvocations({\n state: {\n messages,\n isRunning,\n },\n getTools: () => runtimeRef.current.thread.getModelContext().tools,\n onResult: (command) => {\n if (command.type === \"add-tool-result\") {\n chatHelpers.addToolResult({\n tool: command.toolName,\n toolCallId: command.toolCallId,\n output: command.result,\n });\n }\n },\n setToolStatuses,\n });\n\n const isLoading = useExternalHistory(\n runtimeRef,\n adapters?.history ?? contextAdapters?.history,\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n aiSDKV5FormatAdapter as MessageFormatAdapter<\n UI_MESSAGE,\n AISDKStorageFormat\n >,\n (messages) => {\n chatHelpers.setMessages(messages);\n },\n );\n\n const completePendingToolCalls = () => {\n if (!cancelPendingToolCallsOnSend) return;\n\n const pendingHumanTools: PendingHumanTool[] = Object.entries(toolStatuses)\n .filter(\n (\n entry,\n ): entry is [\n string,\n Extract<ToolExecutionStatus, { type: \"interrupt\" }>,\n ] => entry[1]?.type === \"interrupt\",\n )\n .map(([toolCallId]) => ({ toolCallId }));\n\n if (pendingHumanTools.length === 0) return;\n\n // Set tool statuses to cancelled so UI can show special state\n setToolStatuses((prev) => {\n const next = { ...prev };\n pendingHumanTools.forEach(({ toolCallId }) => {\n next[toolCallId] = {\n type: \"cancelled\",\n reason: \"User cancelled tool call by sending a new message.\",\n };\n });\n return next;\n });\n\n // Mark tools as errored in the message history\n pendingHumanTools.forEach(({ toolCallId }) => {\n chatHelpers.setMessages(\n chatHelpers.messages.map((message) => {\n if (message.id === toolCallId) {\n return {\n ...message,\n content: [\n {\n type: \"text\",\n text: \"User cancelled tool call by sending a new message.\",\n },\n ],\n };\n }\n return message;\n }),\n );\n });\n };\n\n const runtime = useExternalStoreRuntime({\n isRunning,\n messages,\n setMessages: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onImport: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onCancel: async () => {\n chatHelpers.stop();\n toolInvocations.abort();\n },\n onNew: async (message) => {\n completePendingToolCalls();\n\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onEdit: async (message) => {\n completePendingToolCalls();\n\n const newMessages = sliceMessagesUntil(\n chatHelpers.messages,\n message.parentId,\n );\n chatHelpers.setMessages(newMessages);\n\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onReload: async (parentId: string | null, config) => {\n completePendingToolCalls();\n\n const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);\n chatHelpers.setMessages(newMessages);\n\n await chatHelpers.regenerate({ metadata: config.runConfig });\n },\n onAddToolResult: ({ toolCallId, result, isError }) => {\n if (isError) {\n chatHelpers.addToolOutput({\n state: \"output-error\",\n tool: toolCallId,\n toolCallId,\n errorText:\n typeof result === \"string\" ? result : JSON.stringify(result),\n });\n } else {\n chatHelpers.addToolOutput({\n state: \"output-available\",\n tool: toolCallId,\n toolCallId,\n output: result,\n });\n }\n },\n onResumeToolCall: (options) =>\n toolInvocations.resume(options.toolCallId, options.payload),\n adapters: {\n attachments: vercelAttachmentAdapter,\n ...contextAdapters,\n ...adapters,\n },\n isLoading,\n });\n\n return runtime;\n};\n"],"mappings":"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","names":["messages"]}
@@ -8,6 +8,5 @@ export type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> = Ch
8
8
  adapters?: AISDKRuntimeAdapter["adapters"] | undefined;
9
9
  toCreateMessage?: CustomToCreateMessageFunction;
10
10
  };
11
- export declare const useChatThreadRuntime: <UI_MESSAGE extends UIMessage = UIMessage>(options?: UseChatRuntimeOptions<UI_MESSAGE>) => AssistantRuntime;
12
11
  export declare const useChatRuntime: <UI_MESSAGE extends UIMessage = UIMessage>({ cloud, ...options }?: UseChatRuntimeOptions<UI_MESSAGE>) => AssistantRuntime;
13
12
  //# sourceMappingURL=useChatRuntime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useChatRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useChatRuntime.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACL,gBAAgB,EAIjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,6BAA6B,EACnC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAG9B,MAAM,MAAM,qBAAqB,CAAC,UAAU,SAAS,SAAS,GAAG,SAAS,IACxE,QAAQ,CAAC,UAAU,CAAC,GAAG;IACrB,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IACvD,eAAe,CAAC,EAAE,6BAA6B,CAAC;CACjD,CAAC;AAEJ,eAAO,MAAM,oBAAoB,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EAC3E,UAAU,qBAAqB,CAAC,UAAU,CAAC,KAC1C,gBA0BF,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EAAE,wBAGtE,qBAAqB,CAAC,UAAU,CAAM,KAAG,gBAQ3C,CAAC"}
1
+ {"version":3,"file":"useChatRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useChatRuntime.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACL,gBAAgB,EAIjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,6BAA6B,EACnC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,QAAQ,EAAiB,MAAM,IAAI,CAAC;AAI7C,MAAM,MAAM,qBAAqB,CAAC,UAAU,SAAS,SAAS,GAAG,SAAS,IACxE,QAAQ,CAAC,UAAU,CAAC,GAAG;IACrB,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IACvD,eAAe,CAAC,EAAE,6BAA6B,CAAC;CACjD,CAAC;AA0DJ,eAAO,MAAM,cAAc,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EAAE,wBAGtE,qBAAqB,CAAC,UAAU,CAAM,KAAG,gBAS3C,CAAC"}
@@ -11,6 +11,23 @@ import {
11
11
  useAISDKRuntime
12
12
  } from "./useAISDKRuntime.js";
13
13
  import { AssistantChatTransport } from "./AssistantChatTransport.js";
14
+ import { useEffect, useMemo, useRef } from "react";
15
+ var useDynamicChatTransport = (transport) => {
16
+ const transportRef = useRef(transport);
17
+ useEffect(() => {
18
+ transportRef.current = transport;
19
+ });
20
+ const dynamicTransport = useMemo(
21
+ () => new Proxy(transportRef.current, {
22
+ get(_, prop) {
23
+ const res = transportRef.current[prop];
24
+ return typeof res === "function" ? res.bind(transportRef.current) : res;
25
+ }
26
+ }),
27
+ []
28
+ );
29
+ return dynamicTransport;
30
+ };
14
31
  var useChatThreadRuntime = (options) => {
15
32
  const {
16
33
  adapters,
@@ -18,7 +35,9 @@ var useChatThreadRuntime = (options) => {
18
35
  toCreateMessage,
19
36
  ...chatOptions
20
37
  } = options ?? {};
21
- const transport = transportOptions ?? new AssistantChatTransport();
38
+ const transport = useDynamicChatTransport(
39
+ transportOptions ?? new AssistantChatTransport()
40
+ );
22
41
  const id = useAssistantState(({ threadListItem }) => threadListItem.id);
23
42
  const chat = useChat({
24
43
  ...chatOptions,
@@ -43,11 +62,11 @@ var useChatRuntime = ({
43
62
  runtimeHook: function RuntimeHook() {
44
63
  return useChatThreadRuntime(options);
45
64
  },
46
- adapter: cloudAdapter
65
+ adapter: cloudAdapter,
66
+ allowNesting: true
47
67
  });
48
68
  };
49
69
  export {
50
- useChatRuntime,
51
- useChatThreadRuntime
70
+ useChatRuntime
52
71
  };
53
72
  //# sourceMappingURL=useChatRuntime.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/use-chat/useChatRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport { useChat, type UIMessage } from \"@ai-sdk/react\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport {\n AssistantRuntime,\n unstable_useCloudThreadListAdapter,\n unstable_useRemoteThreadListRuntime,\n useAssistantState,\n} from \"@assistant-ui/react\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport { ChatInit } from \"ai\";\nimport { AssistantChatTransport } from \"./AssistantChatTransport\";\n\nexport type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> & {\n cloud?: AssistantCloud | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n };\n\nexport const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n options?: UseChatRuntimeOptions<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n toCreateMessage,\n ...chatOptions\n } = options ?? {};\n const transport = transportOptions ?? new AssistantChatTransport();\n\n const id = useAssistantState(({ threadListItem }) => threadListItem.id);\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n });\n\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...(toCreateMessage && { toCreateMessage }),\n });\n\n if (transport instanceof AssistantChatTransport) {\n transport.setRuntime(runtime);\n }\n\n return runtime;\n};\n\nexport const useChatRuntime = <UI_MESSAGE extends UIMessage = UIMessage>({\n cloud,\n ...options\n}: UseChatRuntimeOptions<UI_MESSAGE> = {}): AssistantRuntime => {\n const cloudAdapter = unstable_useCloudThreadListAdapter({ cloud });\n return unstable_useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useChatThreadRuntime(options);\n },\n adapter: cloudAdapter,\n });\n};\n"],"mappings":";;;AAEA,SAAS,eAA+B;AAExC;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAGK;AAEP,SAAS,8BAA8B;AAShC,IAAM,uBAAuB,CAClC,YACqB;AACrB,QAAM;AAAA,IACJ;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,GAAG;AAAA,EACL,IAAI,WAAW,CAAC;AAChB,QAAM,YAAY,oBAAoB,IAAI,uBAAuB;AAEjE,QAAM,KAAK,kBAAkB,CAAC,EAAE,eAAe,MAAM,eAAe,EAAE;AACtE,QAAM,OAAO,QAAQ;AAAA,IACnB,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,UAAU,gBAAgB,MAAM;AAAA,IACpC;AAAA,IACA,GAAI,mBAAmB,EAAE,gBAAgB;AAAA,EAC3C,CAAC;AAED,MAAI,qBAAqB,wBAAwB;AAC/C,cAAU,WAAW,OAAO;AAAA,EAC9B;AAEA,SAAO;AACT;AAEO,IAAM,iBAAiB,CAA2C;AAAA,EACvE;AAAA,EACA,GAAG;AACL,IAAuC,CAAC,MAAwB;AAC9D,QAAM,eAAe,mCAAmC,EAAE,MAAM,CAAC;AACjE,SAAO,oCAAoC;AAAA,IACzC,aAAa,SAAS,cAAc;AAClC,aAAO,qBAAqB,OAAO;AAAA,IACrC;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../../src/ui/use-chat/useChatRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport { useChat, type UIMessage } from \"@ai-sdk/react\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport {\n AssistantRuntime,\n unstable_useCloudThreadListAdapter,\n unstable_useRemoteThreadListRuntime,\n useAssistantState,\n} from \"@assistant-ui/react\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport { ChatInit, ChatTransport } from \"ai\";\nimport { AssistantChatTransport } from \"./AssistantChatTransport\";\nimport { useEffect, useMemo, useRef } from \"react\";\n\nexport type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> & {\n cloud?: AssistantCloud | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n };\n\nconst useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): ChatTransport<UI_MESSAGE> => {\n const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n const dynamicTransport = useMemo(\n () =>\n new Proxy(transportRef.current, {\n get(_, prop) {\n const res =\n transportRef.current[prop as keyof ChatTransport<UI_MESSAGE>];\n return typeof res === \"function\"\n ? res.bind(transportRef.current)\n : res;\n },\n }),\n [],\n );\n return dynamicTransport;\n};\n\nconst useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n options?: UseChatRuntimeOptions<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n toCreateMessage,\n ...chatOptions\n } = options ?? {};\n\n const transport = useDynamicChatTransport(\n transportOptions ?? new AssistantChatTransport(),\n );\n\n const id = useAssistantState(({ threadListItem }) => threadListItem.id);\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n });\n\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...(toCreateMessage && { toCreateMessage }),\n });\n\n if (transport instanceof AssistantChatTransport) {\n transport.setRuntime(runtime);\n }\n\n return runtime;\n};\n\nexport const useChatRuntime = <UI_MESSAGE extends UIMessage = UIMessage>({\n cloud,\n ...options\n}: UseChatRuntimeOptions<UI_MESSAGE> = {}): AssistantRuntime => {\n const cloudAdapter = unstable_useCloudThreadListAdapter({ cloud });\n return unstable_useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useChatThreadRuntime(options);\n },\n adapter: cloudAdapter,\n allowNesting: true,\n });\n};\n"],"mappings":";;;AAEA,SAAS,eAA+B;AAExC;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAGK;AAEP,SAAS,8BAA8B;AACvC,SAAS,WAAW,SAAS,cAAc;AAS3C,IAAM,0BAA0B,CAC9B,cAC8B;AAC9B,QAAM,eAAe,OAAkC,SAAS;AAChE,YAAU,MAAM;AACd,iBAAa,UAAU;AAAA,EACzB,CAAC;AACD,QAAM,mBAAmB;AAAA,IACvB,MACE,IAAI,MAAM,aAAa,SAAS;AAAA,MAC9B,IAAI,GAAG,MAAM;AACX,cAAM,MACJ,aAAa,QAAQ,IAAuC;AAC9D,eAAO,OAAO,QAAQ,aAClB,IAAI,KAAK,aAAa,OAAO,IAC7B;AAAA,MACN;AAAA,IACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,IAAM,uBAAuB,CAC3B,YACqB;AACrB,QAAM;AAAA,IACJ;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,GAAG;AAAA,EACL,IAAI,WAAW,CAAC;AAEhB,QAAM,YAAY;AAAA,IAChB,oBAAoB,IAAI,uBAAuB;AAAA,EACjD;AAEA,QAAM,KAAK,kBAAkB,CAAC,EAAE,eAAe,MAAM,eAAe,EAAE;AACtE,QAAM,OAAO,QAAQ;AAAA,IACnB,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,UAAU,gBAAgB,MAAM;AAAA,IACpC;AAAA,IACA,GAAI,mBAAmB,EAAE,gBAAgB;AAAA,EAC3C,CAAC;AAED,MAAI,qBAAqB,wBAAwB;AAC/C,cAAU,WAAW,OAAO;AAAA,EAC9B;AAEA,SAAO;AACT;AAEO,IAAM,iBAAiB,CAA2C;AAAA,EACvE;AAAA,EACA,GAAG;AACL,IAAuC,CAAC,MAAwB;AAC9D,QAAM,eAAe,mCAAmC,EAAE,MAAM,CAAC;AACjE,SAAO,oCAAoC;AAAA,IACzC,aAAa,SAAS,cAAc;AAClC,aAAO,qBAAqB,OAAO;AAAA,IACrC;AAAA,IACA,SAAS;AAAA,IACT,cAAc;AAAA,EAChB,CAAC;AACH;","names":[]}
@@ -1,4 +1,4 @@
1
- import { UIMessage } from "ai";
1
+ import { type UIMessage } from "ai";
2
2
  import { type useExternalMessageConverter } from "@assistant-ui/react";
3
3
  export declare const AISDKMessageConverter: {
4
4
  useThreadMessages: ({ messages, isRunning, joinStrategy, metadata, }: {
@@ -1 +1 @@
1
- {"version":3,"file":"convertMessage.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/convertMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,SAAS,EAAE,MAAM,IAAI,CAAC;AAC7C,OAAO,EAOL,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAC;AAoK7B,eAAO,MAAM,qBAAqB;;;;;;;;0HA/I1B,sDACC;yHAGH,sDAEe;;;CA6MpB,CAAC"}
1
+ {"version":3,"file":"convertMessage.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/convertMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,IAAI,CAAC;AAClD,OAAO,EAOL,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAC;AAkL7B,eAAO,MAAM,qBAAqB;;;;;;;;0HA9JT,sDAErB;yHAGE,sDAEU;;;CA2Nf,CAAC"}
@@ -59,6 +59,13 @@ var convertParts = (message, metadata) => {
59
59
  type: "requires-action",
60
60
  reason: "interrupt"
61
61
  }
62
+ },
63
+ ...toolStatus?.type === "cancelled" && {
64
+ status: {
65
+ type: "incomplete",
66
+ reason: "cancelled",
67
+ error: toolStatus.reason
68
+ }
62
69
  }
63
70
  };
64
71
  }
@@ -93,6 +100,13 @@ var convertParts = (message, metadata) => {
93
100
  type: "requires-action",
94
101
  reason: "interrupt"
95
102
  }
103
+ },
104
+ ...toolStatus?.type === "cancelled" && {
105
+ status: {
106
+ type: "incomplete",
107
+ reason: "cancelled",
108
+ error: toolStatus.reason
109
+ }
96
110
  }
97
111
  };
98
112
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/utils/convertMessage.ts"],"sourcesContent":["import { isToolUIPart, UIMessage } from \"ai\";\nimport {\n unstable_createMessageConverter,\n type ReasoningMessagePart,\n type ToolCallMessagePart,\n type TextMessagePart,\n type DataMessagePart,\n type SourceMessagePart,\n type useExternalMessageConverter,\n} from \"@assistant-ui/react\";\n\nfunction stripClosingDelimiters(json: string) {\n return json.replace(/[}\\]\"]+$/, \"\");\n}\n\nconst convertParts = (\n message: UIMessage,\n metadata: useExternalMessageConverter.Metadata,\n) => {\n if (!message.parts || message.parts.length === 0) {\n return [];\n }\n\n return message.parts\n .filter((p) => p.type !== \"step-start\" && p.type !== \"file\")\n .map((part) => {\n const type = part.type;\n\n // Handle text parts\n if (type === \"text\") {\n return {\n type: \"text\",\n text: part.text,\n } satisfies TextMessagePart;\n }\n\n // Handle reasoning parts\n if (type === \"reasoning\") {\n return {\n type: \"reasoning\",\n text: part.text,\n } satisfies ReasoningMessagePart;\n }\n\n // Handle tool-* parts (AI SDK v5 tool calls)\n if (isToolUIPart(part)) {\n const toolName = type.replace(\"tool-\", \"\");\n const toolCallId = part.toolCallId;\n\n // Extract args and result based on state\n let args: any = {};\n let result: any = undefined;\n let isError = false;\n\n if (\n part.state === \"input-streaming\" ||\n part.state === \"input-available\"\n ) {\n args = part.input || {};\n } else if (part.state === \"output-available\") {\n args = part.input || {};\n result = part.output;\n } else if (part.state === \"output-error\") {\n args = part.input || {};\n isError = true;\n result = { error: part.errorText };\n }\n\n let argsText = JSON.stringify(args);\n if (part.state === \"input-streaming\") {\n // the argsText is not complete, so we need to strip the closing delimiters\n // these are added by the AI SDK in fix-json\n argsText = stripClosingDelimiters(argsText);\n }\n\n const toolStatus = metadata.toolStatuses?.[toolCallId];\n return {\n type: \"tool-call\",\n toolName,\n toolCallId,\n argsText,\n args,\n result,\n isError,\n ...(toolStatus?.type === \"interrupt\" && {\n interrupt: toolStatus.payload,\n status: {\n type: \"requires-action\" as const,\n reason: \"interrupt\",\n },\n }),\n } satisfies ToolCallMessagePart;\n }\n\n // Handle dynamic-tool parts\n if (type === \"dynamic-tool\") {\n const toolName = part.toolName;\n const toolCallId = part.toolCallId;\n\n // Extract args and result based on state\n let args: any = {};\n let result: any = undefined;\n let isError = false;\n\n if (\n part.state === \"input-streaming\" ||\n part.state === \"input-available\"\n ) {\n args = part.input || {};\n } else if (part.state === \"output-available\") {\n args = part.input || {};\n result = part.output;\n } else if (part.state === \"output-error\") {\n args = part.input || {};\n isError = true;\n result = { error: part.errorText };\n }\n\n const toolStatus = metadata.toolStatuses?.[toolCallId];\n return {\n type: \"tool-call\",\n toolName,\n toolCallId,\n argsText: JSON.stringify(args),\n args,\n result,\n isError,\n ...(toolStatus?.type === \"interrupt\" && {\n interrupt: toolStatus.payload,\n status: {\n type: \"requires-action\" as const,\n reason: \"interrupt\",\n },\n }),\n } satisfies ToolCallMessagePart;\n }\n\n // Handle source-url parts\n if (type === \"source-url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.sourceId,\n url: part.url,\n title: part.title || \"\",\n } satisfies SourceMessagePart;\n }\n\n // Handle source-document parts\n if (type === \"source-document\") {\n console.warn(\n `Source document part type ${type} is not yet supported in conversion`,\n );\n return null;\n }\n\n // Handle data-* parts (AI SDK v5 data parts)\n if (type.startsWith(\"data-\")) {\n const name = type.substring(5);\n return {\n type: \"data\",\n name,\n data: (part as any).data,\n } satisfies DataMessagePart;\n }\n\n // For unsupported types, we'll skip them instead of throwing\n console.warn(`Unsupported message part type: ${type}`);\n return null;\n })\n .filter(Boolean) as any[];\n};\n\nexport const AISDKMessageConverter = unstable_createMessageConverter(\n (message: UIMessage, metadata: useExternalMessageConverter.Metadata) => {\n // UIMessage doesn't have createdAt, so we'll use current date or undefined\n const createdAt = new Date();\n switch (message.role) {\n case \"user\":\n return {\n role: \"user\",\n id: message.id,\n createdAt,\n content: convertParts(message, metadata),\n attachments: message.parts\n ?.filter((p) => p.type === \"file\")\n .map((part, idx) => {\n return {\n id: idx.toString(),\n type: part.mediaType.startsWith(\"image/\") ? \"image\" : \"file\",\n name: part.filename ?? \"file\",\n content: [\n part.mediaType.startsWith(\"image/\")\n ? {\n type: \"image\",\n image: part.url,\n filename: part.filename!,\n }\n : {\n type: \"file\",\n filename: part.filename!,\n data: part.url,\n mimeType: part.mediaType,\n },\n ],\n contentType: part.mediaType ?? \"unknown/unknown\",\n status: { type: \"complete\" as const },\n };\n }),\n };\n\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n createdAt,\n content: convertParts(message, metadata),\n };\n\n case \"assistant\":\n return {\n role: \"assistant\",\n id: message.id,\n createdAt,\n content: convertParts(message, metadata),\n metadata: {\n unstable_annotations: (message as any).annotations,\n unstable_data: Array.isArray((message as any).data)\n ? (message as any).data\n : (message as any).data\n ? [(message as any).data]\n : undefined,\n custom: {},\n },\n };\n\n default:\n console.warn(`Unsupported message role: ${message.role}`);\n return [];\n }\n },\n);\n"],"mappings":";AAAA,SAAS,oBAA+B;AACxC;AAAA,EACE;AAAA,OAOK;AAEP,SAAS,uBAAuB,MAAc;AAC5C,SAAO,KAAK,QAAQ,YAAY,EAAE;AACpC;AAEA,IAAM,eAAe,CACnB,SACA,aACG;AACH,MAAI,CAAC,QAAQ,SAAS,QAAQ,MAAM,WAAW,GAAG;AAChD,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,QAAQ,MACZ,OAAO,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,SAAS,MAAM,EAC1D,IAAI,CAAC,SAAS;AACb,UAAM,OAAO,KAAK;AAGlB,QAAI,SAAS,QAAQ;AACnB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,KAAK;AAAA,MACb;AAAA,IACF;AAGA,QAAI,SAAS,aAAa;AACxB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,KAAK;AAAA,MACb;AAAA,IACF;AAGA,QAAI,aAAa,IAAI,GAAG;AACtB,YAAM,WAAW,KAAK,QAAQ,SAAS,EAAE;AACzC,YAAM,aAAa,KAAK;AAGxB,UAAI,OAAY,CAAC;AACjB,UAAI,SAAc;AAClB,UAAI,UAAU;AAEd,UACE,KAAK,UAAU,qBACf,KAAK,UAAU,mBACf;AACA,eAAO,KAAK,SAAS,CAAC;AAAA,MACxB,WAAW,KAAK,UAAU,oBAAoB;AAC5C,eAAO,KAAK,SAAS,CAAC;AACtB,iBAAS,KAAK;AAAA,MAChB,WAAW,KAAK,UAAU,gBAAgB;AACxC,eAAO,KAAK,SAAS,CAAC;AACtB,kBAAU;AACV,iBAAS,EAAE,OAAO,KAAK,UAAU;AAAA,MACnC;AAEA,UAAI,WAAW,KAAK,UAAU,IAAI;AAClC,UAAI,KAAK,UAAU,mBAAmB;AAGpC,mBAAW,uBAAuB,QAAQ;AAAA,MAC5C;AAEA,YAAM,aAAa,SAAS,eAAe,UAAU;AACrD,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAI,YAAY,SAAS,eAAe;AAAA,UACtC,WAAW,WAAW;AAAA,UACtB,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,SAAS,gBAAgB;AAC3B,YAAM,WAAW,KAAK;AACtB,YAAM,aAAa,KAAK;AAGxB,UAAI,OAAY,CAAC;AACjB,UAAI,SAAc;AAClB,UAAI,UAAU;AAEd,UACE,KAAK,UAAU,qBACf,KAAK,UAAU,mBACf;AACA,eAAO,KAAK,SAAS,CAAC;AAAA,MACxB,WAAW,KAAK,UAAU,oBAAoB;AAC5C,eAAO,KAAK,SAAS,CAAC;AACtB,iBAAS,KAAK;AAAA,MAChB,WAAW,KAAK,UAAU,gBAAgB;AACxC,eAAO,KAAK,SAAS,CAAC;AACtB,kBAAU;AACV,iBAAS,EAAE,OAAO,KAAK,UAAU;AAAA,MACnC;AAEA,YAAM,aAAa,SAAS,eAAe,UAAU;AACrD,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,UAAU,KAAK,UAAU,IAAI;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAI,YAAY,SAAS,eAAe;AAAA,UACtC,WAAW,WAAW;AAAA,UACtB,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,SAAS,cAAc;AACzB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,IAAI,KAAK;AAAA,QACT,KAAK,KAAK;AAAA,QACV,OAAO,KAAK,SAAS;AAAA,MACvB;AAAA,IACF;AAGA,QAAI,SAAS,mBAAmB;AAC9B,cAAQ;AAAA,QACN,6BAA6B,IAAI;AAAA,MACnC;AACA,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,YAAM,OAAO,KAAK,UAAU,CAAC;AAC7B,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,QACA,MAAO,KAAa;AAAA,MACtB;AAAA,IACF;AAGA,YAAQ,KAAK,kCAAkC,IAAI,EAAE;AACrD,WAAO;AAAA,EACT,CAAC,EACA,OAAO,OAAO;AACnB;AAEO,IAAM,wBAAwB;AAAA,EACnC,CAAC,SAAoB,aAAmD;AAEtE,UAAM,YAAY,oBAAI,KAAK;AAC3B,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,IAAI,QAAQ;AAAA,UACZ;AAAA,UACA,SAAS,aAAa,SAAS,QAAQ;AAAA,UACvC,aAAa,QAAQ,OACjB,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAChC,IAAI,CAAC,MAAM,QAAQ;AAClB,mBAAO;AAAA,cACL,IAAI,IAAI,SAAS;AAAA,cACjB,MAAM,KAAK,UAAU,WAAW,QAAQ,IAAI,UAAU;AAAA,cACtD,MAAM,KAAK,YAAY;AAAA,cACvB,SAAS;AAAA,gBACP,KAAK,UAAU,WAAW,QAAQ,IAC9B;AAAA,kBACE,MAAM;AAAA,kBACN,OAAO,KAAK;AAAA,kBACZ,UAAU,KAAK;AAAA,gBACjB,IACA;AAAA,kBACE,MAAM;AAAA,kBACN,UAAU,KAAK;AAAA,kBACf,MAAM,KAAK;AAAA,kBACX,UAAU,KAAK;AAAA,gBACjB;AAAA,cACN;AAAA,cACA,aAAa,KAAK,aAAa;AAAA,cAC/B,QAAQ,EAAE,MAAM,WAAoB;AAAA,YACtC;AAAA,UACF,CAAC;AAAA,QACL;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,IAAI,QAAQ;AAAA,UACZ;AAAA,UACA,SAAS,aAAa,SAAS,QAAQ;AAAA,QACzC;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,IAAI,QAAQ;AAAA,UACZ;AAAA,UACA,SAAS,aAAa,SAAS,QAAQ;AAAA,UACvC,UAAU;AAAA,YACR,sBAAuB,QAAgB;AAAA,YACvC,eAAe,MAAM,QAAS,QAAgB,IAAI,IAC7C,QAAgB,OAChB,QAAgB,OACf,CAAE,QAAgB,IAAI,IACtB;AAAA,YACN,QAAQ,CAAC;AAAA,UACX;AAAA,QACF;AAAA,MAEF;AACE,gBAAQ,KAAK,6BAA6B,QAAQ,IAAI,EAAE;AACxD,eAAO,CAAC;AAAA,IACZ;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/ui/utils/convertMessage.ts"],"sourcesContent":["import { isToolUIPart, type UIMessage } from \"ai\";\nimport {\n unstable_createMessageConverter,\n type ReasoningMessagePart,\n type ToolCallMessagePart,\n type TextMessagePart,\n type DataMessagePart,\n type SourceMessagePart,\n type useExternalMessageConverter,\n} from \"@assistant-ui/react\";\n\nfunction stripClosingDelimiters(json: string) {\n return json.replace(/[}\\]\"]+$/, \"\");\n}\n\nconst convertParts = (\n message: UIMessage,\n metadata: useExternalMessageConverter.Metadata,\n) => {\n if (!message.parts || message.parts.length === 0) {\n return [];\n }\n\n return message.parts\n .filter((p) => p.type !== \"step-start\" && p.type !== \"file\")\n .map((part) => {\n const type = part.type;\n\n // Handle text parts\n if (type === \"text\") {\n return {\n type: \"text\",\n text: part.text,\n } satisfies TextMessagePart;\n }\n\n // Handle reasoning parts\n if (type === \"reasoning\") {\n return {\n type: \"reasoning\",\n text: part.text,\n } satisfies ReasoningMessagePart;\n }\n\n // Handle tool-* parts (AI SDK v5 tool calls)\n if (isToolUIPart(part)) {\n const toolName = type.replace(\"tool-\", \"\");\n const toolCallId = part.toolCallId;\n\n // Extract args and result based on state\n let args: any = {};\n let result: any = undefined;\n let isError = false;\n\n if (\n part.state === \"input-streaming\" ||\n part.state === \"input-available\"\n ) {\n args = part.input || {};\n } else if (part.state === \"output-available\") {\n args = part.input || {};\n result = part.output;\n } else if (part.state === \"output-error\") {\n args = part.input || {};\n isError = true;\n result = { error: part.errorText };\n }\n\n let argsText = JSON.stringify(args);\n if (part.state === \"input-streaming\") {\n // the argsText is not complete, so we need to strip the closing delimiters\n // these are added by the AI SDK in fix-json\n argsText = stripClosingDelimiters(argsText);\n }\n\n const toolStatus = metadata.toolStatuses?.[toolCallId];\n return {\n type: \"tool-call\",\n toolName,\n toolCallId,\n argsText,\n args,\n result,\n isError,\n ...(toolStatus?.type === \"interrupt\" && {\n interrupt: toolStatus.payload,\n status: {\n type: \"requires-action\" as const,\n reason: \"interrupt\",\n },\n }),\n ...(toolStatus?.type === \"cancelled\" && {\n status: {\n type: \"incomplete\" as const,\n reason: \"cancelled\",\n error: toolStatus.reason,\n },\n }),\n } satisfies ToolCallMessagePart;\n }\n\n // Handle dynamic-tool parts\n if (type === \"dynamic-tool\") {\n const toolName = part.toolName;\n const toolCallId = part.toolCallId;\n\n // Extract args and result based on state\n let args: any = {};\n let result: any = undefined;\n let isError = false;\n\n if (\n part.state === \"input-streaming\" ||\n part.state === \"input-available\"\n ) {\n args = part.input || {};\n } else if (part.state === \"output-available\") {\n args = part.input || {};\n result = part.output;\n } else if (part.state === \"output-error\") {\n args = part.input || {};\n isError = true;\n result = { error: part.errorText };\n }\n\n const toolStatus = metadata.toolStatuses?.[toolCallId];\n return {\n type: \"tool-call\",\n toolName,\n toolCallId,\n argsText: JSON.stringify(args),\n args,\n result,\n isError,\n ...(toolStatus?.type === \"interrupt\" && {\n interrupt: toolStatus.payload,\n status: {\n type: \"requires-action\" as const,\n reason: \"interrupt\",\n },\n }),\n ...(toolStatus?.type === \"cancelled\" && {\n status: {\n type: \"incomplete\" as const,\n reason: \"cancelled\",\n error: toolStatus.reason,\n },\n }),\n } satisfies ToolCallMessagePart;\n }\n\n // Handle source-url parts\n if (type === \"source-url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.sourceId,\n url: part.url,\n title: part.title || \"\",\n } satisfies SourceMessagePart;\n }\n\n // Handle source-document parts\n if (type === \"source-document\") {\n console.warn(\n `Source document part type ${type} is not yet supported in conversion`,\n );\n return null;\n }\n\n // Handle data-* parts (AI SDK v5 data parts)\n if (type.startsWith(\"data-\")) {\n const name = type.substring(5);\n return {\n type: \"data\",\n name,\n data: (part as any).data,\n } satisfies DataMessagePart;\n }\n\n // For unsupported types, we'll skip them instead of throwing\n console.warn(`Unsupported message part type: ${type}`);\n return null;\n })\n .filter(Boolean) as any[];\n};\n\nexport const AISDKMessageConverter = unstable_createMessageConverter(\n (message: UIMessage, metadata: useExternalMessageConverter.Metadata) => {\n // UIMessage doesn't have createdAt, so we'll use current date or undefined\n const createdAt = new Date();\n switch (message.role) {\n case \"user\":\n return {\n role: \"user\",\n id: message.id,\n createdAt,\n content: convertParts(message, metadata),\n attachments: message.parts\n ?.filter((p) => p.type === \"file\")\n .map((part, idx) => {\n return {\n id: idx.toString(),\n type: part.mediaType.startsWith(\"image/\") ? \"image\" : \"file\",\n name: part.filename ?? \"file\",\n content: [\n part.mediaType.startsWith(\"image/\")\n ? {\n type: \"image\",\n image: part.url,\n filename: part.filename!,\n }\n : {\n type: \"file\",\n filename: part.filename!,\n data: part.url,\n mimeType: part.mediaType,\n },\n ],\n contentType: part.mediaType ?? \"unknown/unknown\",\n status: { type: \"complete\" as const },\n };\n }),\n };\n\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n createdAt,\n content: convertParts(message, metadata),\n };\n\n case \"assistant\":\n return {\n role: \"assistant\",\n id: message.id,\n createdAt,\n content: convertParts(message, metadata),\n metadata: {\n unstable_annotations: (message as any).annotations,\n unstable_data: Array.isArray((message as any).data)\n ? (message as any).data\n : (message as any).data\n ? [(message as any).data]\n : undefined,\n custom: {},\n },\n };\n\n default:\n console.warn(`Unsupported message role: ${message.role}`);\n return [];\n }\n },\n);\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-ai-sdk",
3
- "version": "1.1.13",
3
+ "version": "1.1.15",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -19,16 +19,16 @@
19
19
  "sideEffects": false,
20
20
  "dependencies": {
21
21
  "@ai-sdk/provider": "^2.0.0",
22
- "@ai-sdk/react": "^2.0.93",
23
- "ai": "^5.0.93",
22
+ "@ai-sdk/react": "^2.0.102",
24
23
  "@radix-ui/react-use-callback-ref": "^1.1.1",
25
- "assistant-stream": "^0.2.41",
26
24
  "@types/json-schema": "^7.0.15",
27
- "zod": "^4.1.12",
25
+ "ai": "^5.0.102",
26
+ "assistant-stream": "^0.2.42",
27
+ "zod": "^4.1.13",
28
28
  "zustand": "^5.0.8"
29
29
  },
30
30
  "peerDependencies": {
31
- "@assistant-ui/react": "^0.11.44",
31
+ "@assistant-ui/react": "^0.11.46",
32
32
  "@types/react": "*",
33
33
  "assistant-cloud": "*",
34
34
  "react": "^18 || ^19 || ^19.0.0-rc"
@@ -43,12 +43,12 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^24.10.1",
46
- "@types/react": "^19.2.5",
46
+ "@types/react": "^19.2.7",
47
47
  "eslint": "^9",
48
- "eslint-config-next": "16.0.3",
48
+ "eslint-config-next": "16.0.4",
49
49
  "react": "19.2.0",
50
50
  "tsx": "^4.20.6",
51
- "@assistant-ui/react": "0.11.44",
51
+ "@assistant-ui/react": "0.11.46",
52
52
  "@assistant-ui/x-buildutils": "0.0.1"
53
53
  },
54
54
  "publishConfig": {
@@ -57,7 +57,7 @@
57
57
  },
58
58
  "repository": {
59
59
  "type": "git",
60
- "url": "https://github.com/assistant-ui/assistant-ui/tree/main/packages/react-ai-sdk-v5"
60
+ "url": "https://github.com/assistant-ui/assistant-ui/tree/main/packages/react-ai-sdk"
61
61
  },
62
62
  "bugs": {
63
63
  "url": "https://github.com/assistant-ui/assistant-ui/issues"
@@ -4,15 +4,15 @@ import { useState, useMemo } from "react";
4
4
  import type { UIMessage, useChat, CreateUIMessage } from "@ai-sdk/react";
5
5
  import {
6
6
  useExternalStoreRuntime,
7
- ExternalStoreAdapter,
8
- ThreadHistoryAdapter,
9
- AssistantRuntime,
10
- ThreadMessage,
11
- MessageFormatAdapter,
7
+ type ExternalStoreAdapter,
8
+ type ThreadHistoryAdapter,
9
+ type AssistantRuntime,
10
+ type ThreadMessage,
11
+ type MessageFormatAdapter,
12
12
  useRuntimeAdapters,
13
13
  INTERNAL,
14
14
  type ToolExecutionStatus,
15
- AppendMessage,
15
+ type AppendMessage,
16
16
  } from "@assistant-ui/react";
17
17
  import { sliceMessagesUntil } from "../utils/sliceMessagesUntil";
18
18
  import { toCreateMessage } from "../utils/toCreateMessage";
@@ -27,11 +27,15 @@ import { vercelAttachmentAdapter } from "../utils/vercelAttachmentAdapter";
27
27
  import { getVercelAIMessages } from "../getVercelAIMessages";
28
28
  import { AISDKMessageConverter } from "../utils/convertMessage";
29
29
  import {
30
- AISDKStorageFormat,
30
+ type AISDKStorageFormat,
31
31
  aiSDKV5FormatAdapter,
32
32
  } from "../adapters/aiSDKFormatAdapter";
33
33
  import { useExternalHistory } from "./useExternalHistory";
34
34
 
35
+ type PendingHumanTool = {
36
+ readonly toolCallId: string;
37
+ };
38
+
35
39
  export type AISDKRuntimeAdapter = {
36
40
  adapters?:
37
41
  | (NonNullable<ExternalStoreAdapter["adapters"]> & {
@@ -39,6 +43,15 @@ export type AISDKRuntimeAdapter = {
39
43
  })
40
44
  | undefined;
41
45
  toCreateMessage?: CustomToCreateMessageFunction;
46
+ /**
47
+ * Whether to automatically cancel pending interactive tool calls when the user sends a new message.
48
+ *
49
+ * When enabled (default), the pending tool calls will be marked as failed with an error message
50
+ * indicating the user cancelled the tool call by sending a new message.
51
+ *
52
+ * @default true
53
+ */
54
+ cancelPendingToolCallsOnSend?: boolean | undefined;
42
55
  };
43
56
 
44
57
  export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
@@ -46,11 +59,12 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
46
59
  {
47
60
  adapters,
48
61
  toCreateMessage: customToCreateMessage,
62
+ cancelPendingToolCallsOnSend = true,
49
63
  }: AISDKRuntimeAdapter = {},
50
64
  ) => {
51
65
  const contextAdapters = useRuntimeAdapters();
52
66
  const isRunning =
53
- chatHelpers.status === "submitted" || chatHelpers.status == "streaming";
67
+ chatHelpers.status === "submitted" || chatHelpers.status === "streaming";
54
68
 
55
69
  const [toolStatuses, setToolStatuses] = useState<
56
70
  Record<string, ToolExecutionStatus>
@@ -80,7 +94,7 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
80
94
  isRunning,
81
95
  },
82
96
  getTools: () => runtimeRef.current.thread.getModelContext().tools,
83
- onResult: (command: any) => {
97
+ onResult: (command) => {
84
98
  if (command.type === "add-tool-result") {
85
99
  chatHelpers.addToolResult({
86
100
  tool: command.toolName,
@@ -107,6 +121,55 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
107
121
  },
108
122
  );
109
123
 
124
+ const completePendingToolCalls = () => {
125
+ if (!cancelPendingToolCallsOnSend) return;
126
+
127
+ const pendingHumanTools: PendingHumanTool[] = Object.entries(toolStatuses)
128
+ .filter(
129
+ (
130
+ entry,
131
+ ): entry is [
132
+ string,
133
+ Extract<ToolExecutionStatus, { type: "interrupt" }>,
134
+ ] => entry[1]?.type === "interrupt",
135
+ )
136
+ .map(([toolCallId]) => ({ toolCallId }));
137
+
138
+ if (pendingHumanTools.length === 0) return;
139
+
140
+ // Set tool statuses to cancelled so UI can show special state
141
+ setToolStatuses((prev) => {
142
+ const next = { ...prev };
143
+ pendingHumanTools.forEach(({ toolCallId }) => {
144
+ next[toolCallId] = {
145
+ type: "cancelled",
146
+ reason: "User cancelled tool call by sending a new message.",
147
+ };
148
+ });
149
+ return next;
150
+ });
151
+
152
+ // Mark tools as errored in the message history
153
+ pendingHumanTools.forEach(({ toolCallId }) => {
154
+ chatHelpers.setMessages(
155
+ chatHelpers.messages.map((message) => {
156
+ if (message.id === toolCallId) {
157
+ return {
158
+ ...message,
159
+ content: [
160
+ {
161
+ type: "text",
162
+ text: "User cancelled tool call by sending a new message.",
163
+ },
164
+ ],
165
+ };
166
+ }
167
+ return message;
168
+ }),
169
+ );
170
+ });
171
+ };
172
+
110
173
  const runtime = useExternalStoreRuntime({
111
174
  isRunning,
112
175
  messages,
@@ -129,6 +192,8 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
129
192
  toolInvocations.abort();
130
193
  },
131
194
  onNew: async (message) => {
195
+ completePendingToolCalls();
196
+
132
197
  const createMessage = (
133
198
  customToCreateMessage ?? toCreateMessage
134
199
  )<UI_MESSAGE>(message);
@@ -137,6 +202,8 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
137
202
  });
138
203
  },
139
204
  onEdit: async (message) => {
205
+ completePendingToolCalls();
206
+
140
207
  const newMessages = sliceMessagesUntil(
141
208
  chatHelpers.messages,
142
209
  message.parentId,
@@ -151,6 +218,8 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
151
218
  });
152
219
  },
153
220
  onReload: async (parentId: string | null, config) => {
221
+ completePendingToolCalls();
222
+
154
223
  const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);
155
224
  chatHelpers.setMessages(newMessages);
156
225
 
@@ -13,8 +13,9 @@ import {
13
13
  type AISDKRuntimeAdapter,
14
14
  type CustomToCreateMessageFunction,
15
15
  } from "./useAISDKRuntime";
16
- import { ChatInit } from "ai";
16
+ import { ChatInit, ChatTransport } from "ai";
17
17
  import { AssistantChatTransport } from "./AssistantChatTransport";
18
+ import { useEffect, useMemo, useRef } from "react";
18
19
 
19
20
  export type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =
20
21
  ChatInit<UI_MESSAGE> & {
@@ -23,7 +24,30 @@ export type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =
23
24
  toCreateMessage?: CustomToCreateMessageFunction;
24
25
  };
25
26
 
26
- export const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
27
+ const useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(
28
+ transport: ChatTransport<UI_MESSAGE>,
29
+ ): ChatTransport<UI_MESSAGE> => {
30
+ const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);
31
+ useEffect(() => {
32
+ transportRef.current = transport;
33
+ });
34
+ const dynamicTransport = useMemo(
35
+ () =>
36
+ new Proxy(transportRef.current, {
37
+ get(_, prop) {
38
+ const res =
39
+ transportRef.current[prop as keyof ChatTransport<UI_MESSAGE>];
40
+ return typeof res === "function"
41
+ ? res.bind(transportRef.current)
42
+ : res;
43
+ },
44
+ }),
45
+ [],
46
+ );
47
+ return dynamicTransport;
48
+ };
49
+
50
+ const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
27
51
  options?: UseChatRuntimeOptions<UI_MESSAGE>,
28
52
  ): AssistantRuntime => {
29
53
  const {
@@ -32,7 +56,10 @@ export const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
32
56
  toCreateMessage,
33
57
  ...chatOptions
34
58
  } = options ?? {};
35
- const transport = transportOptions ?? new AssistantChatTransport();
59
+
60
+ const transport = useDynamicChatTransport(
61
+ transportOptions ?? new AssistantChatTransport(),
62
+ );
36
63
 
37
64
  const id = useAssistantState(({ threadListItem }) => threadListItem.id);
38
65
  const chat = useChat({
@@ -63,5 +90,6 @@ export const useChatRuntime = <UI_MESSAGE extends UIMessage = UIMessage>({
63
90
  return useChatThreadRuntime(options);
64
91
  },
65
92
  adapter: cloudAdapter,
93
+ allowNesting: true,
66
94
  });
67
95
  };
@@ -1,4 +1,4 @@
1
- import { isToolUIPart, UIMessage } from "ai";
1
+ import { isToolUIPart, type UIMessage } from "ai";
2
2
  import {
3
3
  unstable_createMessageConverter,
4
4
  type ReasoningMessagePart,
@@ -89,6 +89,13 @@ const convertParts = (
89
89
  reason: "interrupt",
90
90
  },
91
91
  }),
92
+ ...(toolStatus?.type === "cancelled" && {
93
+ status: {
94
+ type: "incomplete" as const,
95
+ reason: "cancelled",
96
+ error: toolStatus.reason,
97
+ },
98
+ }),
92
99
  } satisfies ToolCallMessagePart;
93
100
  }
94
101
 
@@ -132,6 +139,13 @@ const convertParts = (
132
139
  reason: "interrupt",
133
140
  },
134
141
  }),
142
+ ...(toolStatus?.type === "cancelled" && {
143
+ status: {
144
+ type: "incomplete" as const,
145
+ reason: "cancelled",
146
+ error: toolStatus.reason,
147
+ },
148
+ }),
135
149
  } satisfies ToolCallMessagePart;
136
150
  }
137
151