@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.
- package/dist/ui/use-chat/useAISDKRuntime.d.ts +11 -2
- package/dist/ui/use-chat/useAISDKRuntime.d.ts.map +1 -1
- package/dist/ui/use-chat/useAISDKRuntime.js +41 -2
- package/dist/ui/use-chat/useAISDKRuntime.js.map +1 -1
- package/dist/ui/use-chat/useChatRuntime.d.ts +0 -1
- package/dist/ui/use-chat/useChatRuntime.d.ts.map +1 -1
- package/dist/ui/use-chat/useChatRuntime.js +23 -4
- package/dist/ui/use-chat/useChatRuntime.js.map +1 -1
- package/dist/ui/utils/convertMessage.d.ts +1 -1
- package/dist/ui/utils/convertMessage.d.ts.map +1 -1
- package/dist/ui/utils/convertMessage.js +14 -0
- package/dist/ui/utils/convertMessage.js.map +1 -1
- package/package.json +10 -10
- package/src/ui/use-chat/useAISDKRuntime.tsx +78 -9
- package/src/ui/use-chat/useChatRuntime.tsx +31 -3
- package/src/ui/utils/convertMessage.ts +15 -1
|
@@ -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,
|
|
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
|
|
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":";;;AAEA,SAAS,UAAU,eAAe;AAElC;AAAA,EACE;AAAA,EAMA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAQhC,SAAS,+BAA+B;AACxC,SAAS,2BAA2B;AACpC,SAAS,6BAA6B;AACtC;AAAA,EAEE;AAAA,OACK;AACP,SAAS,0BAA0B;AAwB5B,IAAM,kBAAkB,CAC7B,aACA;AAAA,EACE;AAAA,EACA,iBAAiB;AAAA,EACjB,+BAA+B;AACjC,IAAyB,CAAC,MACvB;AACH,QAAM,kBAAkB,mBAAmB;AAC3C,QAAM,YACJ,YAAY,WAAW,eAAe,YAAY,WAAW;AAE/D,QAAM,CAAC,cAAc,eAAe,IAAI,SAEtC,CAAC,CAAC;AAEJ,QAAM,WAAW,sBAAsB,kBAAkB;AAAA,IACvD;AAAA,IACA,UAAU,YAAY;AAAA,IACtB,UAAU;AAAA,MACR,OAAO;AAAA,QACL;AAAA,QACA,GAAI,YAAY,SAAS,EAAE,OAAO,YAAY,MAAM,QAAQ;AAAA,MAC9D;AAAA,MACA,CAAC,cAAc,YAAY,KAAK;AAAA,IAClC;AAAA,EACF,CAAC;AAED,QAAM,CAAC,UAAU,IAAI,SAAS,OAAO;AAAA,IACnC,IAAI,UAA4B;AAC9B,aAAO;AAAA,IACT;AAAA,EACF,EAAE;AAEF,QAAM,kBAAkB,SAAS,mBAAmB;AAAA,IAClD,OAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU,MAAM,WAAW,QAAQ,OAAO,gBAAgB,EAAE;AAAA,IAC5D,UAAU,CAAC,YAAY;AACrB,UAAI,QAAQ,SAAS,mBAAmB;AACtC,oBAAY,cAAc;AAAA,UACxB,MAAM,QAAQ;AAAA,UACd,YAAY,QAAQ;AAAA,UACpB,QAAQ,QAAQ;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,UAAU,WAAW,iBAAiB;AAAA,IACtC,sBAAsB;AAAA,IAGtB;AAAA,IAIA,CAACA,cAAa;AACZ,kBAAY,YAAYA,SAAQ;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,2BAA2B,MAAM;AACrC,QAAI,CAAC,6BAA8B;AAEnC,UAAM,oBAAwC,OAAO,QAAQ,YAAY,EACtE;AAAA,MACC,CACE,UAIG,MAAM,CAAC,GAAG,SAAS;AAAA,IAC1B,EACC,IAAI,CAAC,CAAC,UAAU,OAAO,EAAE,WAAW,EAAE;AAEzC,QAAI,kBAAkB,WAAW,EAAG;AAGpC,oBAAgB,CAAC,SAAS;AACxB,YAAM,OAAO,EAAE,GAAG,KAAK;AACvB,wBAAkB,QAAQ,CAAC,EAAE,WAAW,MAAM;AAC5C,aAAK,UAAU,IAAI;AAAA,UACjB,MAAM;AAAA,UACN,QAAQ;AAAA,QACV;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT,CAAC;AAGD,sBAAkB,QAAQ,CAAC,EAAE,WAAW,MAAM;AAC5C,kBAAY;AAAA,QACV,YAAY,SAAS,IAAI,CAAC,YAAY;AACpC,cAAI,QAAQ,OAAO,YAAY;AAC7B,mBAAO;AAAA,cACL,GAAG;AAAA,cACH,SAAS;AAAA,gBACP;AAAA,kBACE,MAAM;AAAA,kBACN,MAAM;AAAA,gBACR;AAAA,cACF;AAAA,YACF;AAAA,UACF;AACA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,wBAAwB;AAAA,IACtC;AAAA,IACA;AAAA,IACA,aAAa,CAACA,cACZ,YAAY;AAAA,MACVA,UACG,IAAI,mBAA+B,EACnC,OAAO,OAAO,EACd,KAAK;AAAA,IACV;AAAA,IACF,UAAU,CAACA,cACT,YAAY;AAAA,MACVA,UACG,IAAI,mBAA+B,EACnC,OAAO,OAAO,EACd,KAAK;AAAA,IACV;AAAA,IACF,UAAU,YAAY;AACpB,kBAAY,KAAK;AACjB,sBAAgB,MAAM;AAAA,IACxB;AAAA,IACA,OAAO,OAAO,YAAY;AACxB,+BAAyB;AAEzB,YAAM,iBACJ,yBAAyB,iBACb,OAAO;AACrB,YAAM,YAAY,YAAY,eAAe;AAAA,QAC3C,UAAU,QAAQ;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,IACA,QAAQ,OAAO,YAAY;AACzB,+BAAyB;AAEzB,YAAM,cAAc;AAAA,QAClB,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV;AACA,kBAAY,YAAY,WAAW;AAEnC,YAAM,iBACJ,yBAAyB,iBACb,OAAO;AACrB,YAAM,YAAY,YAAY,eAAe;AAAA,QAC3C,UAAU,QAAQ;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,IACA,UAAU,OAAO,UAAyB,WAAW;AACnD,+BAAyB;AAEzB,YAAM,cAAc,mBAAmB,YAAY,UAAU,QAAQ;AACrE,kBAAY,YAAY,WAAW;AAEnC,YAAM,YAAY,WAAW,EAAE,UAAU,OAAO,UAAU,CAAC;AAAA,IAC7D;AAAA,IACA,iBAAiB,CAAC,EAAE,YAAY,QAAQ,QAAQ,MAAM;AACpD,UAAI,SAAS;AACX,oBAAY,cAAc;AAAA,UACxB,OAAO;AAAA,UACP,MAAM;AAAA,UACN;AAAA,UACA,WACE,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,MAAM;AAAA,QAC/D,CAAC;AAAA,MACH,OAAO;AACL,oBAAY,cAAc;AAAA,UACxB,OAAO;AAAA,UACP,MAAM;AAAA,UACN;AAAA,UACA,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,kBAAkB,CAAC,YACjB,gBAAgB,OAAO,QAAQ,YAAY,QAAQ,OAAO;AAAA,IAC5D,UAAU;AAAA,MACR,aAAa;AAAA,MACb,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AACT;","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,
|
|
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 =
|
|
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\
|
|
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 +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;
|
|
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":"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","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":";AAAA,SAAS,oBAAoC;AAC7C;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,QACA,GAAI,YAAY,SAAS,eAAe;AAAA,UACtC,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,QAAQ;AAAA,YACR,OAAO,WAAW;AAAA,UACpB;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,QACA,GAAI,YAAY,SAAS,eAAe;AAAA,UACtC,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,QAAQ;AAAA,YACR,OAAO,WAAW;AAAA,UACpB;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":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-ai-sdk",
|
|
3
|
-
"version": "1.1.
|
|
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.
|
|
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
|
-
"
|
|
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.
|
|
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.
|
|
46
|
+
"@types/react": "^19.2.7",
|
|
47
47
|
"eslint": "^9",
|
|
48
|
-
"eslint-config-next": "16.0.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|