@assistant-ui/ai-sdk 0.0.6 → 0.0.8
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/README.md +1 -1
- package/dist/adapters/aiSDKFormatAdapter.d.ts +2 -2
- package/dist/adapters/aiSDKFormatAdapter.d.ts.map +1 -0
- package/dist/adapters/vercelAttachmentAdapter.d.ts +2 -5
- package/dist/adapters/vercelAttachmentAdapter.d.ts.map +1 -1
- package/dist/adapters/vercelAttachmentAdapter.js +3 -3
- package/dist/adapters/vercelAttachmentAdapter.js.map +1 -1
- package/dist/aiSDKExtras.d.ts +6 -9
- package/dist/aiSDKExtras.d.ts.map +1 -1
- package/dist/converters/convertMessage.d.ts +34 -25
- package/dist/converters/convertMessage.d.ts.map +1 -1
- package/dist/converters/convertMessage.js +78 -8
- package/dist/converters/convertMessage.js.map +1 -1
- package/dist/converters/modelContentEnvelope.d.ts +10 -12
- package/dist/converters/modelContentEnvelope.d.ts.map +1 -1
- package/dist/converters/toCreateMessage.d.ts +3 -6
- package/dist/converters/toCreateMessage.d.ts.map +1 -1
- package/dist/converters/toolOutputConversion.d.ts +22 -25
- package/dist/converters/toolOutputConversion.d.ts.map +1 -1
- package/dist/hooks.d.ts +4 -7
- package/dist/hooks.d.ts.map +1 -1
- package/dist/index.d.ts +17 -14
- package/dist/index.d.ts.map +1 -0
- package/dist/index.native.d.ts +15 -12
- package/dist/index.native.d.ts.map +1 -0
- package/dist/model-context/injectInteractableContext.d.ts +3 -6
- package/dist/model-context/injectInteractableContext.d.ts.map +1 -1
- package/dist/model-context/injectQuoteContext.d.ts +2 -5
- package/dist/model-context/injectQuoteContext.d.ts.map +1 -1
- package/dist/runtime/AISDKChat.d.ts +4 -7
- package/dist/runtime/AISDKChat.d.ts.map +1 -1
- package/dist/runtime/AISDKChat.js +1 -1
- package/dist/runtime/AISDKThreads.d.ts +29 -32
- package/dist/runtime/AISDKThreads.d.ts.map +1 -1
- package/dist/runtime/AISDKThreads.js +26 -33
- package/dist/runtime/AISDKThreads.js.map +1 -1
- package/dist/runtime/sdkIdentity.d.ts +2 -5
- package/dist/runtime/sdkIdentity.d.ts.map +1 -1
- package/dist/runtime/sdkIdentity.js +1 -1
- package/dist/runtime/useAISDKRuntime.d.ts +72 -61
- package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
- package/dist/runtime/useAISDKRuntime.js +170 -56
- package/dist/runtime/useAISDKRuntime.js.map +1 -1
- package/dist/runtime/useChatRuntime.d.ts +8 -11
- package/dist/runtime/useChatRuntime.d.ts.map +1 -1
- package/dist/runtime/useChatRuntime.js +14 -10
- package/dist/runtime/useChatRuntime.js.map +1 -1
- package/dist/runtime/useChatThread.d.ts +100 -81
- package/dist/runtime/useChatThread.d.ts.map +1 -1
- package/dist/runtime/useChatThread.js +33 -13
- package/dist/runtime/useChatThread.js.map +1 -1
- package/dist/runtime/useExternalHistory.d.ts +8 -9
- package/dist/runtime/useExternalHistory.d.ts.map +1 -1
- package/dist/runtime/useExternalHistory.js +236 -58
- package/dist/runtime/useExternalHistory.js.map +1 -1
- package/dist/runtime/useResourceCleanup.d.ts +1 -4
- package/dist/runtime/useResourceCleanup.d.ts.map +1 -1
- package/dist/runtime/useResourceCleanup.js +38 -14
- package/dist/runtime/useResourceCleanup.js.map +1 -1
- package/dist/runtime/useStreamingTiming.d.ts +5 -8
- package/dist/runtime/useStreamingTiming.d.ts.map +1 -1
- package/dist/runtime/useStreamingTiming.js +1 -1
- package/dist/tools/frontendTools.d.ts +24 -27
- package/dist/tools/frontendTools.d.ts.map +1 -1
- package/dist/tools/generativeTools.d.ts +29 -32
- package/dist/tools/generativeTools.d.ts.map +1 -1
- package/dist/tools/mcp-stdio.node.d.ts +2 -2
- package/dist/tools/mcp-stdio.node.d.ts.map +1 -0
- package/dist/tools/mcp-stdio.unsupported.d.ts +2 -5
- package/dist/tools/mcp-stdio.unsupported.d.ts.map +1 -1
- package/dist/transport/AssistantChatTransport.d.ts +17 -20
- package/dist/transport/AssistantChatTransport.d.ts.map +1 -1
- package/dist/transport/resumable.d.ts +29 -32
- package/dist/transport/resumable.d.ts.map +1 -1
- package/dist/usage.d.ts +12 -15
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js.map +1 -1
- package/dist/utils/getVercelAIMessages.d.ts +3 -6
- package/dist/utils/getVercelAIMessages.d.ts.map +1 -1
- package/dist/utils/sliceMessagesUntil.d.ts +2 -5
- package/dist/utils/sliceMessagesUntil.d.ts.map +1 -1
- package/package.json +16 -14
- package/src/adapters/vercelAttachmentAdapter.test.ts +23 -0
- package/src/adapters/vercelAttachmentAdapter.ts +2 -2
- package/src/converters/convertMessage.test.ts +616 -3
- package/src/converters/convertMessage.ts +187 -12
- package/src/index.native.ts +1 -1
- package/src/index.ts +1 -1
- package/src/runtime/AISDKChat.test.ts +4 -5
- package/src/runtime/AISDKThreads.cloud.test.ts +60 -2
- package/src/runtime/AISDKThreads.test.ts +88 -51
- package/src/runtime/AISDKThreads.ts +4 -13
- package/src/runtime/useAISDKRuntime.approval.integration.test.tsx +338 -0
- package/src/runtime/useAISDKRuntime.approval.test.tsx +476 -4
- package/src/runtime/useAISDKRuntime.test.ts +282 -8
- package/src/runtime/useAISDKRuntime.ts +274 -46
- package/src/runtime/useAISDKRuntime.voice.test.tsx +319 -0
- package/src/runtime/useChatRuntime.integration.test.tsx +56 -0
- package/src/runtime/useChatRuntime.test.ts +77 -5
- package/src/runtime/useChatRuntime.ts +6 -2
- package/src/runtime/useChatThread.transport.test.tsx +149 -0
- package/src/runtime/useChatThread.ts +77 -10
- package/src/runtime/useExternalHistory.test.ts +989 -3
- package/src/runtime/useExternalHistory.ts +390 -24
- package/src/runtime/useResourceCleanup.ts +41 -15
- package/src/tools/generativeTools.test.ts +7 -1
- package/src/usage.ts +1 -1
|
@@ -1,64 +1,75 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { UIMessage, useChat, CreateUIMessage } from "@ai-sdk/react";
|
|
2
|
+
import { type JoinStrategy } from "@assistant-ui/core/react";
|
|
3
|
+
import type { SuggestionAdapter } from "@assistant-ui/core";
|
|
4
|
+
import type { ExternalStoreAdapter, ExternalStoreSharedOptions, ThreadHistoryAdapter, AssistantRuntime, MessageFormatRepository, AppendMessage, RespondToToolApprovalOptions } from "@assistant-ui/core";
|
|
3
5
|
import { MessageRepository } from "@assistant-ui/core/internal";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
6
|
+
export type CustomToCreateMessageFunction = <UI_MESSAGE extends UIMessage = UIMessage>(message: AppendMessage) => CreateUIMessage<UI_MESSAGE>;
|
|
7
|
+
export type AISDKRuntimeAdapter<UI_MESSAGE extends UIMessage = UIMessage> = ExternalStoreSharedOptions & {
|
|
8
|
+
adapters?: (NonNullable<ExternalStoreAdapter["adapters"]> & {
|
|
9
|
+
history?: ThreadHistoryAdapter | undefined;
|
|
10
|
+
suggestion?: SuggestionAdapter | undefined;
|
|
11
|
+
}) | undefined;
|
|
12
|
+
toCreateMessage?: CustomToCreateMessageFunction;
|
|
13
|
+
unstable_messageRepositoryInstance?: MessageRepository | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Whether to automatically cancel pending interactive tool calls when the user sends a new message.
|
|
16
|
+
*
|
|
17
|
+
* When enabled (default), the pending tool calls will be marked as failed with an error message
|
|
18
|
+
* indicating the user cancelled the tool call by sending a new message.
|
|
19
|
+
*
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
22
|
+
cancelPendingToolCallsOnSend?: boolean | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Called when `runtime.thread.resumeRun(config)` is invoked.
|
|
25
|
+
*
|
|
26
|
+
* When omitted, `resumeRun` throws `"Runtime does not support resuming runs."`.
|
|
27
|
+
* Provide this to bridge resume invocations into a custom replay channel
|
|
28
|
+
* (for example, an SSE reconnect endpoint keyed by turn id).
|
|
29
|
+
*/
|
|
30
|
+
onResume?: ExternalStoreAdapter["onResume"];
|
|
31
|
+
/**
|
|
32
|
+
* Called when `runtime.thread.resumeToolCall(options)` is invoked for a tool call the in-process tracker does not own.
|
|
33
|
+
*
|
|
34
|
+
* When omitted, `resumeToolCall` throws `"Tool call ${toolCallId} is not waiting for resume."`.
|
|
35
|
+
* Provide this to bridge resume-tool-call invocations into a custom handler.
|
|
36
|
+
*/
|
|
37
|
+
onResumeToolCall?: ExternalStoreAdapter["onResumeToolCall"];
|
|
38
|
+
/**
|
|
39
|
+
* Answers tool approval requests through a host-owned channel instead of the AI SDK's `addToolApprovalResponse`.
|
|
40
|
+
*
|
|
41
|
+
* Called for every approval request in the thread with the complete response, including option and free-form answers. Hand requests the host does not own to `respondViaAISDK`, which is what runs when this option is omitted. The answer applies to the approval when the handler starts and is removed if it throws. It is never written into the `useChat` messages, so `sendAutomaticallyWhen` cannot forward it. With a history adapter, the answer is stored with its message once the handler resolves and returns on reload, and a second response to the same request rejects; without one it lasts as long as this runtime, and a runtime mounted again over the same chat shows the request open until the resumed run records its resolution in the chat.
|
|
42
|
+
*
|
|
43
|
+
* While a handler is set, an approval's `display`, `allowFreeform`, `dismissible` and `options` reach the renderer, because the handler can receive answers the AI SDK cannot carry. A stream declares them through the `approvalDescriptor` of its `tool-approval-request` chunk, the one approval field the AI SDK keeps opaque; the converter reads the request and answer fields from that descriptor when the approval itself lacks them.
|
|
44
|
+
*/
|
|
45
|
+
onRespondToToolApproval?: ((response: RespondToToolApprovalOptions, context: {
|
|
46
|
+
toolCallId: string;
|
|
47
|
+
toolName: string;
|
|
48
|
+
/** Sends this response through the AI SDK's `addToolApprovalResponse`, which carries only `approved` and `reason`. */
|
|
49
|
+
respondViaAISDK: () => Promise<void>;
|
|
50
|
+
}) => Promise<void> | void) | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* How consecutive assistant messages are rendered.
|
|
53
|
+
*
|
|
54
|
+
* `"concat-content"` (the default) merges them into a single thread message.
|
|
55
|
+
* `"none"` keeps each assistant message as its own thread message, which is
|
|
56
|
+
* useful when a backend persists proactive or consecutive assistant messages
|
|
57
|
+
* as separate entries.
|
|
58
|
+
*/
|
|
59
|
+
joinStrategy?: JoinStrategy | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* A branch-aware AI SDK message tree seeded once when `useChat` is empty.
|
|
62
|
+
* After that seed, live updates come only from `useChat`. A later empty
|
|
63
|
+
* chat or a new object identity does not reload the tree.
|
|
64
|
+
*/
|
|
65
|
+
messageRepository?: MessageFormatRepository<UI_MESSAGE>;
|
|
66
|
+
/**
|
|
67
|
+
* Called after an explicit `switchToBranch` (for example a BranchPicker
|
|
68
|
+
* click). Complements `setMessages` and does not enable switching by itself.
|
|
69
|
+
*
|
|
70
|
+
* @deprecated This API is still under active development and might change without notice.
|
|
71
|
+
*/
|
|
72
|
+
unstable_onBranchChange?: ExternalStoreAdapter["unstable_onBranchChange"];
|
|
60
73
|
};
|
|
61
|
-
declare const useAISDKRuntime: <UI_MESSAGE extends UIMessage = UIMessage>(chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>, adapter?: AISDKRuntimeAdapter<UI_MESSAGE>) => AssistantRuntime;
|
|
62
|
-
//#endregion
|
|
63
|
-
export { AISDKRuntimeAdapter, CustomToCreateMessageFunction, useAISDKRuntime };
|
|
74
|
+
export declare const useAISDKRuntime: <UI_MESSAGE extends UIMessage = UIMessage>(chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>, adapter?: AISDKRuntimeAdapter<UI_MESSAGE>) => AssistantRuntime;
|
|
64
75
|
//# sourceMappingURL=useAISDKRuntime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAISDKRuntime.d.ts","
|
|
1
|
+
{"version":3,"file":"useAISDKRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/useAISDKRuntime.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EACP,eAAe,EAEhB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EACV,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,gBAAgB,EAIhB,uBAAuB,EACvB,aAAa,EAGb,4BAA4B,EAE7B,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAGL,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AAuBrC,MAAM,MAAM,6BAA6B,GAAG,CAC1C,UAAU,SAAS,SAAS,GAAG,SAAS,EAExC,OAAO,EAAE,aAAa,KACnB,eAAe,CAAC,UAAU,CAAC,CAAC;AA6BjC,MAAM,MAAM,mBAAmB,CAAC,UAAU,SAAS,SAAS,GAAG,SAAS,IACtE,0BAA0B,GAAG;IAC3B,QAAQ,CAAC,EACL,CAAC,WAAW,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,GAAG;QAC/C,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;QAC3C,UAAU,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;KAC5C,CAAC,GACF,SAAS,CAAC;IACd,eAAe,CAAC,EAAE,6BAA6B,CAAC;IAChD,kCAAkC,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACnE;;;;;;;OAOG;IACH,4BAA4B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnD;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAC5C;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;IAC5D;;;;;;OAMG;IACH,uBAAuB,CAAC,EACpB,CAAC,CACC,QAAQ,EAAE,4BAA4B,EACtC,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,sHAAsH;QACtH,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;KACtC,KACE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAC1B,SAAS,CAAC;IACd;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,uBAAuB,CAAC,UAAU,CAAC,CAAC;IACxD;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,oBAAoB,CAAC,yBAAyB,CAAC,CAAC;CAC3E,CAAC;AAqGJ,eAAO,MAAM,eAAe,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EACtE,aAAa,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,EACnD,UAAS,mBAAmB,CAAC,UAAU,CAAM,qBAonB9C,CAAC"}
|
|
@@ -1,26 +1,38 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { sliceMessagesUntil } from "../utils/sliceMessagesUntil.js";
|
|
4
|
-
import { toCreateMessage } from "../converters/toCreateMessage.js";
|
|
2
|
+
import { aiSDKV6FormatAdapter } from "../adapters/aiSDKFormatAdapter.js";
|
|
5
3
|
import { vercelAttachmentAdapter } from "../adapters/vercelAttachmentAdapter.js";
|
|
6
|
-
import {
|
|
4
|
+
import { aiSDKExtras } from "../aiSDKExtras.js";
|
|
7
5
|
import { wrapModelContentEnvelope } from "../converters/modelContentEnvelope.js";
|
|
8
6
|
import { AISDKMessageConverter } from "../converters/convertMessage.js";
|
|
9
|
-
import {
|
|
7
|
+
import { toCreateMessage } from "../converters/toCreateMessage.js";
|
|
8
|
+
import { sliceMessagesUntil } from "../utils/sliceMessagesUntil.js";
|
|
9
|
+
import { getVercelAIMessages } from "../utils/getVercelAIMessages.js";
|
|
10
10
|
import { toExportedMessageRepository, useExternalHistory } from "./useExternalHistory.js";
|
|
11
11
|
import { useStreamingTiming as useStreamingTiming$1 } from "./useStreamingTiming.js";
|
|
12
|
+
import { MessageRepository, appendToolInteraction, consumeSuggestionResult } from "@assistant-ui/core/internal";
|
|
13
|
+
import { generateId, getToolName, isToolUIPart } from "ai";
|
|
12
14
|
import { useExternalStoreRuntime, useRuntimeAdapters } from "@assistant-ui/core/react";
|
|
15
|
+
import { getExternalStoreMessages, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
13
16
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
14
17
|
import { useCallback, useEffect, useInsertionEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
15
|
-
import { generateId, isToolUIPart } from "ai";
|
|
16
|
-
import { getExternalStoreMessages, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
17
|
-
import { MessageRepository, consumeSuggestionResult } from "@assistant-ui/core/internal";
|
|
18
18
|
//#region src/runtime/useAISDKRuntime.ts
|
|
19
19
|
const toUIMessage = (createMessage, fallbackRole) => ({
|
|
20
20
|
...createMessage,
|
|
21
21
|
id: createMessage.id ?? generateId(),
|
|
22
22
|
role: createMessage.role ?? fallbackRole
|
|
23
23
|
});
|
|
24
|
+
const toVoiceTranscriptUIMessage = (message) => ({
|
|
25
|
+
id: message.id,
|
|
26
|
+
role: message.role,
|
|
27
|
+
parts: message.content.filter((part) => part.type === "text").map((part) => ({
|
|
28
|
+
type: "text",
|
|
29
|
+
text: part.text
|
|
30
|
+
})),
|
|
31
|
+
metadata: {
|
|
32
|
+
...message.metadata.modality && { modality: message.metadata.modality },
|
|
33
|
+
...Object.keys(message.metadata.custom).length > 0 && { custom: message.metadata.custom }
|
|
34
|
+
}
|
|
35
|
+
});
|
|
24
36
|
const EMPTY_SUGGESTIONS = [];
|
|
25
37
|
const useGeneratedSuggestions = (suggestionAdapter, messages, isRunning) => {
|
|
26
38
|
const $ = c(13);
|
|
@@ -129,6 +141,7 @@ const useGeneratedSuggestions = (suggestionAdapter, messages, isRunning) => {
|
|
|
129
141
|
return suggestions;
|
|
130
142
|
};
|
|
131
143
|
const NO_CANCELLED_MESSAGE_IDS = /* @__PURE__ */ new Set();
|
|
144
|
+
const NO_TOOL_APPROVAL_RESPONSES = /* @__PURE__ */ new Map();
|
|
132
145
|
const toChatError = (error) => {
|
|
133
146
|
const code = error.code;
|
|
134
147
|
return {
|
|
@@ -137,15 +150,29 @@ const toChatError = (error) => {
|
|
|
137
150
|
};
|
|
138
151
|
};
|
|
139
152
|
const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
140
|
-
const { adapters, toCreateMessage: customToCreateMessage, cancelPendingToolCallsOnSend = true, onResume, onResumeToolCall, joinStrategy, messageRepository, unstable_onBranchChange } = adapter;
|
|
153
|
+
const { adapters, toCreateMessage: customToCreateMessage, cancelPendingToolCallsOnSend = true, onResume, onResumeToolCall, onRespondToToolApproval: customOnRespondToToolApproval, joinStrategy, messageRepository, unstable_onBranchChange } = adapter;
|
|
141
154
|
const suggestionAdapter = adapters?.suggestion;
|
|
142
155
|
const contextAdapters = useRuntimeAdapters();
|
|
143
156
|
const [toolStatuses, setToolStatuses] = useState({});
|
|
144
157
|
const [cancelledMessages, setCancelledMessages] = useState(null);
|
|
158
|
+
const [toolApprovalResponses, setToolApprovalResponses] = useState(NO_TOOL_APPROVAL_RESPONSES);
|
|
159
|
+
const [toolArtifactEpoch, setToolArtifactEpoch] = useState(0);
|
|
160
|
+
const [toolInteractionEpoch, setToolInteractionEpoch] = useState(0);
|
|
161
|
+
const hostApprovalIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
162
|
+
const toolApprovalResponsesRef = useRef(/* @__PURE__ */ new Map());
|
|
145
163
|
const toolArgsKeyOrderCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
146
164
|
const toolLastInputCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
165
|
+
const toolArgsTextCacheRef = useRef(/* @__PURE__ */ new WeakMap());
|
|
147
166
|
const mcpAppMetadataCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
167
|
+
const toolArtifactsRef = useRef(/* @__PURE__ */ new Map());
|
|
168
|
+
const toolInteractionsRef = useRef(/* @__PURE__ */ new Map());
|
|
148
169
|
const lastRunConfigRef = useRef(void 0);
|
|
170
|
+
const markToolArtifactsChanged = useCallback(() => {
|
|
171
|
+
setToolArtifactEpoch((epoch) => epoch + 1);
|
|
172
|
+
}, []);
|
|
173
|
+
const markToolInteractionsChanged = useCallback(() => {
|
|
174
|
+
setToolInteractionEpoch((epoch_0) => epoch_0 + 1);
|
|
175
|
+
}, []);
|
|
149
176
|
const hasExecutingTools = Object.values(toolStatuses).some((s) => s?.type === "executing");
|
|
150
177
|
const providerIsRunning = chatHelpers.status === "submitted" || chatHelpers.status === "streaming";
|
|
151
178
|
const isRunning = providerIsRunning || hasExecutingTools;
|
|
@@ -154,6 +181,16 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
154
181
|
const lastMessage = chatHelpers.messages.at(-1);
|
|
155
182
|
const optimisticMessageId = isRunning && lastMessage?.role === "assistant" ? lastMessage.id : void 0;
|
|
156
183
|
const cancelledMessageIds = cancelledMessages?.chatId === chatHelpers.id ? cancelledMessages.ids : NO_CANCELLED_MESSAGE_IDS;
|
|
184
|
+
const supportsRichToolApprovalResponses = customOnRespondToToolApproval != null;
|
|
185
|
+
const toThreadMessages = useCallback((sourceMessages) => {
|
|
186
|
+
const metadata = {
|
|
187
|
+
supportsRichToolApprovalResponses,
|
|
188
|
+
toolArtifacts: toolArtifactsRef.current,
|
|
189
|
+
toolInteractions: toolInteractionsRef.current,
|
|
190
|
+
toolApprovalResponses: toolApprovalResponsesRef.current
|
|
191
|
+
};
|
|
192
|
+
return AISDKMessageConverter.toThreadMessages(sourceMessages, false, metadata);
|
|
193
|
+
}, [supportsRichToolApprovalResponses]);
|
|
157
194
|
const retractCancellation = useCallback((chatId, messageId) => {
|
|
158
195
|
setCancelledMessages((prev) => {
|
|
159
196
|
if (prev?.chatId !== chatId || !prev.ids.has(messageId)) return prev;
|
|
@@ -185,30 +222,42 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
185
222
|
toolStatuses,
|
|
186
223
|
messageTiming,
|
|
187
224
|
toolArgsKeyOrderCache: toolArgsKeyOrderCacheRef.current,
|
|
225
|
+
toolArgsTextCache: toolArgsTextCacheRef.current,
|
|
188
226
|
toolLastInputCache: toolLastInputCacheRef.current,
|
|
189
227
|
mcpAppMetadataCache: mcpAppMetadataCacheRef.current,
|
|
228
|
+
toolArtifacts: toolArtifactsRef.current,
|
|
229
|
+
toolInteractions: toolInteractionsRef.current,
|
|
230
|
+
supportsRichToolApprovalResponses,
|
|
190
231
|
...optimisticMessageId && { optimisticMessageId },
|
|
191
232
|
...chatHelpers.error && { error: toChatError(chatHelpers.error) },
|
|
192
|
-
...cancelledMessageIds.size > 0 && { cancelledMessageIds }
|
|
233
|
+
...cancelledMessageIds.size > 0 && { cancelledMessageIds },
|
|
234
|
+
...toolApprovalResponses.size > 0 && { toolApprovalResponses }
|
|
193
235
|
}), [
|
|
194
236
|
toolStatuses,
|
|
195
237
|
messageTiming,
|
|
196
238
|
optimisticMessageId,
|
|
197
239
|
chatHelpers.error,
|
|
198
|
-
cancelledMessageIds
|
|
240
|
+
cancelledMessageIds,
|
|
241
|
+
toolApprovalResponses,
|
|
242
|
+
supportsRichToolApprovalResponses,
|
|
243
|
+
toolArtifactEpoch,
|
|
244
|
+
toolInteractionEpoch
|
|
199
245
|
])
|
|
200
246
|
});
|
|
201
247
|
const exportedMessageRepository = useMemo(() => {
|
|
202
248
|
if (!messageRepository) return void 0;
|
|
203
|
-
const converted = toExportedMessageRepository(
|
|
249
|
+
const converted = toExportedMessageRepository(toThreadMessages, messageRepository);
|
|
204
250
|
return converted.messages.length > 0 ? converted : void 0;
|
|
205
|
-
}, [messageRepository]);
|
|
251
|
+
}, [messageRepository, toThreadMessages]);
|
|
206
252
|
const generatedSuggestions = useGeneratedSuggestions(suggestionAdapter, messages, isRunning);
|
|
207
253
|
const [runtimeRef] = useState(() => ({ get current() {
|
|
208
254
|
return runtime;
|
|
209
255
|
} }));
|
|
210
|
-
const { isLoading, deleteMessage: deleteHistoryMessage } = useExternalHistory(runtimeRef, adapters?.history ?? contextAdapters?.history,
|
|
256
|
+
const { isLoading, deleteMessage: deleteHistoryMessage, persistToolInteractions, persistToolApprovalResponses } = useExternalHistory(runtimeRef, adapters?.history ?? contextAdapters?.history, toThreadMessages, aiSDKV6FormatAdapter, (messages_0) => {
|
|
211
257
|
chatHelpers.setMessages(messages_0);
|
|
258
|
+
}, toolArtifactsRef.current, markToolArtifactsChanged, toolInteractionsRef.current, markToolInteractionsChanged, toolApprovalResponsesRef.current, () => {
|
|
259
|
+
hostApprovalIdsRef.current = new Set(toolApprovalResponsesRef.current.keys());
|
|
260
|
+
setToolApprovalResponses(new Map(toolApprovalResponsesRef.current));
|
|
212
261
|
});
|
|
213
262
|
const { id: chatId_0, messages: chatMessages, status: chatStatus, error } = chatHelpers;
|
|
214
263
|
const extras = useMemo(() => aiSDKExtras.provide({
|
|
@@ -223,36 +272,82 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
223
272
|
const completePendingToolCalls = async () => {
|
|
224
273
|
if (!cancelPendingToolCallsOnSend) return;
|
|
225
274
|
chatHelpers.setMessages((messages_1) => {
|
|
226
|
-
const lastMessage_0 = messages_1.at(-1);
|
|
227
|
-
if (lastMessage_0?.role !== "assistant") return messages_1;
|
|
228
275
|
let hasChanges = false;
|
|
229
|
-
const
|
|
230
|
-
if (
|
|
231
|
-
|
|
276
|
+
const next = messages_1.map((message) => {
|
|
277
|
+
if (message.role !== "assistant") return message;
|
|
278
|
+
let messageChanged = false;
|
|
279
|
+
const parts = message.parts?.map((part) => {
|
|
280
|
+
if (!isToolUIPart(part)) return part;
|
|
281
|
+
if (part.state === "output-available" || part.state === "output-error" || part.state === "output-denied") return part;
|
|
282
|
+
messageChanged = true;
|
|
283
|
+
const { approval: _approval, ...rest } = part;
|
|
284
|
+
return {
|
|
285
|
+
...rest,
|
|
286
|
+
state: "output-error",
|
|
287
|
+
errorText: "User cancelled tool call by sending a new message."
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
if (!messageChanged) return message;
|
|
232
291
|
hasChanges = true;
|
|
233
|
-
const { approval: _approval, ...rest } = part;
|
|
234
292
|
return {
|
|
235
|
-
...
|
|
236
|
-
|
|
237
|
-
errorText: "User cancelled tool call by sending a new message."
|
|
293
|
+
...message,
|
|
294
|
+
parts
|
|
238
295
|
};
|
|
239
296
|
});
|
|
240
297
|
if (!hasChanges) return messages_1;
|
|
241
|
-
return
|
|
242
|
-
...lastMessage_0,
|
|
243
|
-
parts
|
|
244
|
-
}];
|
|
298
|
+
return next;
|
|
245
299
|
});
|
|
246
300
|
};
|
|
301
|
+
const respondViaAISDK = ({ approvalId, approved, reason }) => Promise.resolve(chatHelpers.addToolApprovalResponse({
|
|
302
|
+
id: approvalId,
|
|
303
|
+
approved,
|
|
304
|
+
...reason != null && { reason },
|
|
305
|
+
options: { metadata: lastRunConfigRef.current }
|
|
306
|
+
}));
|
|
307
|
+
const respondViaHost = async (onRespond, response) => {
|
|
308
|
+
const { approvalId: approvalId_0 } = response;
|
|
309
|
+
const requested = chatHelpers.messages.flatMap((message_0) => message_0.parts.flatMap((part_0) => isToolUIPart(part_0) ? [{
|
|
310
|
+
messageId: message_0.id,
|
|
311
|
+
part: part_0
|
|
312
|
+
}] : [])).find(({ part: part_1 }) => part_1.state === "approval-requested" && part_1.approval.id === approvalId_0);
|
|
313
|
+
if (!requested || hostApprovalIdsRef.current.has(approvalId_0)) throw new Error(`Tool approval ${approvalId_0} is not waiting for a response.`);
|
|
314
|
+
const applyResponse = (applied) => {
|
|
315
|
+
if (applied) hostApprovalIdsRef.current.add(approvalId_0);
|
|
316
|
+
else hostApprovalIdsRef.current.delete(approvalId_0);
|
|
317
|
+
if (applied) toolApprovalResponsesRef.current.set(approvalId_0, response);
|
|
318
|
+
else toolApprovalResponsesRef.current.delete(approvalId_0);
|
|
319
|
+
setToolApprovalResponses(new Map(toolApprovalResponsesRef.current));
|
|
320
|
+
};
|
|
321
|
+
applyResponse(true);
|
|
322
|
+
try {
|
|
323
|
+
await onRespond(response, {
|
|
324
|
+
toolCallId: requested.part.toolCallId,
|
|
325
|
+
toolName: getToolName(requested.part),
|
|
326
|
+
respondViaAISDK: async () => {
|
|
327
|
+
try {
|
|
328
|
+
await respondViaAISDK(response);
|
|
329
|
+
} finally {
|
|
330
|
+
applyResponse(false);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
} catch (error_0) {
|
|
335
|
+
if (hostApprovalIdsRef.current.has(approvalId_0)) applyResponse(false);
|
|
336
|
+
throw error_0;
|
|
337
|
+
}
|
|
338
|
+
if (hostApprovalIdsRef.current.has(approvalId_0)) await persistToolApprovalResponses(requested.messageId);
|
|
339
|
+
};
|
|
247
340
|
const hasSeededRepositoryRef = useRef(false);
|
|
248
341
|
const shouldFeedRepository = exportedMessageRepository != null && !hasSeededRepositoryRef.current && messages.length === 0;
|
|
249
342
|
const runtime = useExternalStoreRuntime({
|
|
343
|
+
unstable_persistsHistory: true,
|
|
250
344
|
isRunning: providerIsRunning,
|
|
251
345
|
...shouldFeedRepository ? { messageRepository: exportedMessageRepository } : { messages },
|
|
252
346
|
unstable_enableToolInvocations: true,
|
|
253
347
|
setToolStatuses,
|
|
254
348
|
setMessages: (messages_2) => chatHelpers.setMessages(messages_2.map(getVercelAIMessages).filter(Boolean).flat()),
|
|
255
349
|
onImport: (messages_3) => chatHelpers.setMessages(messages_3.map(getVercelAIMessages).filter(Boolean).flat()),
|
|
350
|
+
onVoiceTranscript: (message_1) => chatHelpers.setMessages((current) => [...current, toVoiceTranscriptUIMessage(message_1)]),
|
|
256
351
|
onExportExternalState: () => {
|
|
257
352
|
const exported = runtimeRef.current.thread.export();
|
|
258
353
|
const expandedMessages = [];
|
|
@@ -274,12 +369,12 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
274
369
|
return result;
|
|
275
370
|
},
|
|
276
371
|
onLoadExternalState: (repo) => {
|
|
277
|
-
const exportedRepo = toExportedMessageRepository(
|
|
372
|
+
const exportedRepo = toExportedMessageRepository(toThreadMessages, repo);
|
|
278
373
|
runtimeRef.current.thread.import(exportedRepo);
|
|
279
374
|
},
|
|
280
375
|
onCancel: async () => {
|
|
281
|
-
const
|
|
282
|
-
const cancelledId = isRunning &&
|
|
376
|
+
const message_2 = chatHelpers.messages.at(-1);
|
|
377
|
+
const cancelledId = isRunning && message_2?.role === "assistant" ? message_2.id : void 0;
|
|
283
378
|
if (cancelledId) {
|
|
284
379
|
const liveIds = new Set(chatHelpers.messages.map((m) => m.id));
|
|
285
380
|
setCancelledMessages((prev_0) => {
|
|
@@ -292,40 +387,55 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
292
387
|
}
|
|
293
388
|
try {
|
|
294
389
|
await chatHelpers.stop();
|
|
295
|
-
} catch (
|
|
296
|
-
if (!(
|
|
390
|
+
} catch (error_1) {
|
|
391
|
+
if (!(error_1 instanceof Error && error_1.name === "AbortError")) {
|
|
297
392
|
if (cancelledId) retractCancellation(chatHelpers.id, cancelledId);
|
|
298
|
-
throw
|
|
393
|
+
throw error_1;
|
|
299
394
|
}
|
|
300
395
|
}
|
|
301
396
|
},
|
|
302
|
-
onNew: async (
|
|
303
|
-
const createMessage = (customToCreateMessage ?? toCreateMessage)(
|
|
304
|
-
if (!(
|
|
305
|
-
chatHelpers.setMessages((
|
|
397
|
+
onNew: async (message_3) => {
|
|
398
|
+
const createMessage = (customToCreateMessage ?? toCreateMessage)(message_3);
|
|
399
|
+
if (!(message_3.startRun ?? message_3.role === "user")) {
|
|
400
|
+
chatHelpers.setMessages((current_0) => [...current_0, toUIMessage(createMessage, message_3.role)]);
|
|
306
401
|
return;
|
|
307
402
|
}
|
|
308
|
-
lastRunConfigRef.current =
|
|
403
|
+
lastRunConfigRef.current = message_3.runConfig;
|
|
309
404
|
await completePendingToolCalls();
|
|
310
|
-
await chatHelpers.sendMessage(createMessage, { metadata:
|
|
405
|
+
await chatHelpers.sendMessage(createMessage, { metadata: message_3.runConfig });
|
|
311
406
|
},
|
|
312
|
-
onEdit: async (
|
|
313
|
-
const createMessage_0 = (customToCreateMessage ?? toCreateMessage)(
|
|
314
|
-
if (!(
|
|
315
|
-
chatHelpers.setMessages((
|
|
407
|
+
onEdit: async (message_4) => {
|
|
408
|
+
const createMessage_0 = (customToCreateMessage ?? toCreateMessage)(message_4);
|
|
409
|
+
if (!(message_4.startRun ?? message_4.role === "user")) {
|
|
410
|
+
chatHelpers.setMessages((current_1) => [...sliceMessagesUntil(current_1, message_4.parentId), toUIMessage(createMessage_0, message_4.role)]);
|
|
316
411
|
return;
|
|
317
412
|
}
|
|
318
|
-
lastRunConfigRef.current =
|
|
319
|
-
chatHelpers.setMessages((
|
|
320
|
-
await chatHelpers.sendMessage(createMessage_0, { metadata:
|
|
413
|
+
lastRunConfigRef.current = message_4.runConfig;
|
|
414
|
+
chatHelpers.setMessages((current_2) => sliceMessagesUntil(current_2, message_4.parentId));
|
|
415
|
+
await chatHelpers.sendMessage(createMessage_0, { metadata: message_4.runConfig });
|
|
321
416
|
},
|
|
322
417
|
onDelete: async (messageId_0) => {
|
|
323
418
|
const threadMessages = runtimeRef.current.thread.getState().messages;
|
|
324
|
-
const messageIndex = threadMessages.findIndex((
|
|
419
|
+
const messageIndex = threadMessages.findIndex((message_5) => message_5.id === messageId_0);
|
|
325
420
|
if (messageIndex === -1) return;
|
|
326
421
|
await deleteHistoryMessage(messageId_0);
|
|
327
|
-
|
|
328
|
-
|
|
422
|
+
let removedToolArtifact = false;
|
|
423
|
+
let removedToolInteractions = false;
|
|
424
|
+
let removedToolApprovalResponse = false;
|
|
425
|
+
let removedHostApprovalId = false;
|
|
426
|
+
for (const part_2 of threadMessages[messageIndex].content) if (part_2.type === "tool-call") {
|
|
427
|
+
removedToolArtifact = toolArtifactsRef.current.delete(part_2.toolCallId) || removedToolArtifact;
|
|
428
|
+
removedToolInteractions = toolInteractionsRef.current.delete(part_2.toolCallId) || removedToolInteractions;
|
|
429
|
+
if (part_2.approval) {
|
|
430
|
+
removedToolApprovalResponse = toolApprovalResponsesRef.current.delete(part_2.approval.id) || removedToolApprovalResponse;
|
|
431
|
+
removedHostApprovalId = hostApprovalIdsRef.current.delete(part_2.approval.id) || removedHostApprovalId;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (removedToolArtifact) markToolArtifactsChanged();
|
|
435
|
+
if (removedToolInteractions) markToolInteractionsChanged();
|
|
436
|
+
if (removedToolApprovalResponse || removedHostApprovalId) setToolApprovalResponses(new Map(toolApprovalResponsesRef.current));
|
|
437
|
+
const deleteIds = new Set(getExternalStoreMessages(threadMessages[messageIndex]).map((message_6) => message_6.id));
|
|
438
|
+
chatHelpers.setMessages((current_3) => current_3.filter((message_7) => !deleteIds.has(message_7.id)));
|
|
329
439
|
},
|
|
330
440
|
onReload: async (parentId_0, config) => {
|
|
331
441
|
lastRunConfigRef.current = config.runConfig;
|
|
@@ -333,7 +443,11 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
333
443
|
chatHelpers.setMessages(newMessages);
|
|
334
444
|
await chatHelpers.regenerate({ metadata: config.runConfig });
|
|
335
445
|
},
|
|
336
|
-
onAddToolResult: ({ toolCallId, toolName, result: result_0, isError, modelContent }) => {
|
|
446
|
+
onAddToolResult: ({ toolCallId, toolName, result: result_0, isError, artifact, modelContent }) => {
|
|
447
|
+
if (artifact !== void 0) {
|
|
448
|
+
toolArtifactsRef.current.set(toolCallId, artifact);
|
|
449
|
+
markToolArtifactsChanged();
|
|
450
|
+
}
|
|
337
451
|
const options = { metadata: lastRunConfigRef.current };
|
|
338
452
|
if (isError) return Promise.resolve(chatHelpers.addToolOutput({
|
|
339
453
|
state: "output-error",
|
|
@@ -352,12 +466,12 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
352
466
|
}));
|
|
353
467
|
}
|
|
354
468
|
},
|
|
355
|
-
onRespondToToolApproval: (
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
469
|
+
onRespondToToolApproval: customOnRespondToToolApproval ? (response_0) => respondViaHost(customOnRespondToToolApproval, response_0) : respondViaAISDK,
|
|
470
|
+
unstable_onRecordToolInteraction: ({ messageId: messageId_1, toolCallId: toolCallId_0, interaction }) => {
|
|
471
|
+
toolInteractionsRef.current.set(toolCallId_0, appendToolInteraction(toolInteractionsRef.current.get(toolCallId_0), interaction));
|
|
472
|
+
markToolInteractionsChanged();
|
|
473
|
+
return persistToolInteractions(messageId_1);
|
|
474
|
+
},
|
|
361
475
|
...pickExternalStoreSharedOptions(adapter),
|
|
362
476
|
...adapter.unstable_messageRepositoryInstance && { unstable_messageRepositoryInstance: adapter.unstable_messageRepositoryInstance },
|
|
363
477
|
...suggestionAdapter ? { suggestions: generatedSuggestions } : {},
|