@assistant-ui/ai-sdk 0.0.11 → 0.0.12
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/converters/convertMessage.d.ts +8 -6
- package/dist/converters/convertMessage.d.ts.map +1 -1
- package/dist/converters/convertMessage.js +48 -22
- package/dist/converters/convertMessage.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.native.d.ts +1 -1
- package/dist/index.native.d.ts.map +1 -1
- package/dist/index.native.js +1 -1
- package/dist/model-context/injectInteractableContext.d.ts +3 -0
- package/dist/model-context/injectInteractableContext.d.ts.map +1 -1
- package/dist/model-context/injectInteractableContext.js +3 -0
- package/dist/model-context/injectInteractableContext.js.map +1 -1
- package/dist/model-context/injectQuoteContext.d.ts +1 -0
- package/dist/model-context/injectQuoteContext.d.ts.map +1 -1
- package/dist/model-context/injectQuoteContext.js +1 -0
- package/dist/model-context/injectQuoteContext.js.map +1 -1
- package/dist/runtime/AISDKChat.js +1 -1
- package/dist/runtime/AISDKThreads.d.ts +5 -0
- package/dist/runtime/AISDKThreads.d.ts.map +1 -1
- package/dist/runtime/AISDKThreads.js +37 -4
- package/dist/runtime/AISDKThreads.js.map +1 -1
- package/dist/runtime/DynamicChatTransport.d.ts +49 -0
- package/dist/runtime/DynamicChatTransport.d.ts.map +1 -0
- package/dist/runtime/DynamicChatTransport.js +147 -0
- package/dist/runtime/DynamicChatTransport.js.map +1 -0
- package/dist/runtime/getResumableAdapter.d.ts +5 -0
- package/dist/runtime/getResumableAdapter.d.ts.map +1 -0
- package/dist/runtime/getResumableAdapter.js +12 -0
- package/dist/runtime/getResumableAdapter.js.map +1 -0
- package/dist/runtime/sdkIdentity.js +1 -1
- package/dist/runtime/toolHistoryCodec.d.ts +20 -0
- package/dist/runtime/toolHistoryCodec.d.ts.map +1 -0
- package/dist/runtime/toolHistoryCodec.js +107 -0
- package/dist/runtime/toolHistoryCodec.js.map +1 -0
- package/dist/runtime/useAISDKRuntime.d.ts +4 -1
- package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
- package/dist/runtime/useAISDKRuntime.js +154 -155
- package/dist/runtime/useAISDKRuntime.js.map +1 -1
- package/dist/runtime/useChatRuntime.d.ts +14 -2
- package/dist/runtime/useChatRuntime.d.ts.map +1 -1
- package/dist/runtime/useChatRuntime.js +12 -3
- package/dist/runtime/useChatRuntime.js.map +1 -1
- package/dist/runtime/useChatThread.d.ts +3 -2
- package/dist/runtime/useChatThread.d.ts.map +1 -1
- package/dist/runtime/useChatThread.js +56 -36
- package/dist/runtime/useChatThread.js.map +1 -1
- package/dist/runtime/useDynamicChatTransport.d.ts +4 -0
- package/dist/runtime/useDynamicChatTransport.d.ts.map +1 -0
- package/dist/runtime/useDynamicChatTransport.js +64 -0
- package/dist/runtime/useDynamicChatTransport.js.map +1 -0
- package/dist/runtime/useExternalHistory.d.ts.map +1 -1
- package/dist/runtime/useExternalHistory.js +11 -109
- package/dist/runtime/useExternalHistory.js.map +1 -1
- package/dist/runtime/useResourceCleanup.js +1 -1
- package/dist/runtime/useStreamingTiming.js +2 -2
- package/dist/runtime/useStreamingTiming.js.map +1 -1
- package/dist/tools/generativeTools.d.ts +2 -1
- package/dist/tools/generativeTools.d.ts.map +1 -1
- package/dist/tools/generativeTools.js +5 -5
- package/dist/tools/generativeTools.js.map +1 -1
- package/dist/usage.js +1 -1
- package/dist/utils/sliceMessagesUntil.d.ts.map +1 -1
- package/dist/utils/sliceMessagesUntil.js +1 -2
- package/dist/utils/sliceMessagesUntil.js.map +1 -1
- package/package.json +11 -10
- package/src/converters/convertMessage.test.ts +120 -2
- package/src/converters/convertMessage.tool-args-status.test.tsx +185 -0
- package/src/converters/convertMessage.ts +60 -19
- package/src/converters/toCreateMessage.test.ts +27 -0
- package/src/index.native.ts +1 -1
- package/src/index.ts +1 -1
- package/src/model-context/injectInteractableContext.ts +3 -0
- package/src/model-context/injectQuoteContext.ts +1 -0
- package/src/runtime/AISDKChat.integration.test.tsx +57 -2
- package/src/runtime/AISDKThreads.cloud.test.ts +3 -0
- package/src/runtime/AISDKThreads.test.ts +181 -0
- package/src/runtime/AISDKThreads.ts +31 -4
- package/src/runtime/DynamicChatTransport.test.ts +203 -0
- package/src/runtime/DynamicChatTransport.ts +273 -0
- package/src/runtime/__tests__/controlled-transport.ts +3 -0
- package/src/runtime/getResumableAdapter.ts +16 -0
- package/src/runtime/toolHistoryCodec.test.ts +161 -0
- package/src/runtime/toolHistoryCodec.ts +207 -0
- package/src/runtime/useAISDKRuntime.approval.test.tsx +12 -0
- package/src/runtime/useAISDKRuntime.reload.test.tsx +219 -0
- package/src/runtime/useAISDKRuntime.test.ts +538 -5
- package/src/runtime/useAISDKRuntime.ts +161 -51
- package/src/runtime/useChatRuntime.integration.test.tsx +319 -4
- package/src/runtime/useChatRuntime.local-storage.test.tsx +123 -0
- package/src/runtime/useChatRuntime.test.ts +107 -1
- package/src/runtime/useChatRuntime.ts +26 -4
- package/src/runtime/useChatThread.binding.test.tsx +143 -0
- package/src/runtime/useChatThread.ts +98 -81
- package/src/runtime/useDynamicChatTransport.ts +26 -0
- package/src/runtime/useExternalHistory.test.ts +111 -0
- package/src/runtime/useExternalHistory.ts +14 -210
- package/src/runtime/useStreamingTiming.ts +2 -2
- package/src/tools/generativeTools.test.ts +1 -1
- package/src/tools/generativeTools.ts +5 -6
- package/src/utils/sliceMessagesUntil.test.ts +2 -6
- package/src/utils/sliceMessagesUntil.ts +1 -5
- package/dist/converters/modelContentEnvelope.d.ts +0 -14
- package/dist/converters/modelContentEnvelope.d.ts.map +0 -1
- package/dist/converters/modelContentEnvelope.js +0 -22
- package/dist/converters/modelContentEnvelope.js.map +0 -1
- package/dist/converters/toolOutputConversion.d.ts +0 -26
- package/dist/converters/toolOutputConversion.d.ts.map +0 -1
- package/dist/converters/toolOutputConversion.js +0 -31
- package/dist/converters/toolOutputConversion.js.map +0 -1
- package/dist/tools/frontendTools.d.ts +0 -30
- package/dist/tools/frontendTools.d.ts.map +0 -1
- package/dist/tools/frontendTools.js +0 -33
- package/dist/tools/frontendTools.js.map +0 -1
- package/src/converters/modelContentEnvelope.ts +0 -41
- package/src/converters/toolOutputConversion.ts +0 -26
- package/src/tools/frontendTools.test.ts +0 -205
- package/src/tools/frontendTools.ts +0 -83
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { aiSDKV6FormatAdapter } from "../adapters/aiSDKFormatAdapter.js";
|
|
3
3
|
import { vercelAttachmentAdapter } from "../adapters/vercelAttachmentAdapter.js";
|
|
4
4
|
import { aiSDKExtras } from "../aiSDKExtras.js";
|
|
5
|
-
import { wrapModelContentEnvelope } from "../converters/modelContentEnvelope.js";
|
|
6
5
|
import { AISDKMessageConverter } from "../converters/convertMessage.js";
|
|
7
6
|
import { toCreateMessage } from "../converters/toCreateMessage.js";
|
|
8
7
|
import { sliceMessagesUntil } from "../utils/sliceMessagesUntil.js";
|
|
@@ -13,8 +12,8 @@ import { MessageRepository, appendToolInteraction, consumeSuggestionResult } fro
|
|
|
13
12
|
import { generateId, getToolName, isToolUIPart } from "ai";
|
|
14
13
|
import { useExternalStoreRuntime, useRuntimeAdapters } from "@assistant-ui/core/react";
|
|
15
14
|
import { getExternalStoreMessages, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
16
|
-
import {
|
|
17
|
-
import { useCallback, useEffect, useInsertionEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
15
|
+
import { wrapModelContentEnvelope } from "assistant-stream/internal";
|
|
16
|
+
import { useCallback, useEffect, useInsertionEffect, useMemo, useRef, useState, useSyncExternalStore } from "@assistant-ui/tap/react-shim";
|
|
18
17
|
import { useReplaySafeEffect } from "@assistant-ui/store/internal";
|
|
19
18
|
//#region src/runtime/useAISDKRuntime.ts
|
|
20
19
|
const toUIMessage = (createMessage, fallbackRole) => ({
|
|
@@ -36,109 +35,83 @@ const toVoiceTranscriptUIMessage = (message) => ({
|
|
|
36
35
|
});
|
|
37
36
|
const EMPTY_SUGGESTIONS = [];
|
|
38
37
|
const useGeneratedSuggestions = (suggestionAdapter, messages, isRunning) => {
|
|
39
|
-
const $ = c(13);
|
|
40
38
|
const [suggestions, setSuggestions] = useState(EMPTY_SUGGESTIONS);
|
|
41
39
|
const controllerRef = useRef(null);
|
|
42
40
|
const wasRunningRef = useRef(false);
|
|
43
41
|
const messagesRef = useRef(messages);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
messagesRef.current = messages;
|
|
49
|
-
};
|
|
50
|
-
t1 = [messages];
|
|
51
|
-
$[0] = messages;
|
|
52
|
-
$[1] = t0;
|
|
53
|
-
$[2] = t1;
|
|
54
|
-
} else {
|
|
55
|
-
t0 = $[1];
|
|
56
|
-
t1 = $[2];
|
|
57
|
-
}
|
|
58
|
-
useInsertionEffect(t0, t1);
|
|
42
|
+
useInsertionEffect(() => {
|
|
43
|
+
messagesRef.current = messages;
|
|
44
|
+
}, [messages]);
|
|
45
|
+
const adapterKey = suggestionAdapter?.key;
|
|
59
46
|
const adapterRef = useRef(suggestionAdapter);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if ($[6] !== isRunning) {
|
|
78
|
-
t4 = () => {
|
|
79
|
-
const clearSuggestions = () => {
|
|
80
|
-
controllerRef.current?.abort();
|
|
81
|
-
controllerRef.current = null;
|
|
82
|
-
setSuggestions(_temp);
|
|
83
|
-
};
|
|
84
|
-
const adapter = adapterRef.current;
|
|
85
|
-
if (!adapter) {
|
|
86
|
-
clearSuggestions();
|
|
87
|
-
wasRunningRef.current = isRunning;
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
if (isRunning) {
|
|
91
|
-
if (!wasRunningRef.current) clearSuggestions();
|
|
92
|
-
wasRunningRef.current = true;
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
if (!wasRunningRef.current) return;
|
|
96
|
-
wasRunningRef.current = false;
|
|
97
|
-
const currentMessages = messagesRef.current;
|
|
98
|
-
const last = currentMessages.at(-1);
|
|
99
|
-
if (last?.role !== "assistant") return;
|
|
100
|
-
if (last.status?.type === "requires-action") return;
|
|
101
|
-
const controller = new AbortController();
|
|
102
|
-
controllerRef.current = controller;
|
|
103
|
-
const { signal } = controller;
|
|
104
|
-
(async () => {
|
|
105
|
-
try {
|
|
106
|
-
const promiseOrGenerator = adapter.generate({
|
|
107
|
-
messages: currentMessages,
|
|
108
|
-
signal
|
|
109
|
-
});
|
|
110
|
-
await consumeSuggestionResult(promiseOrGenerator, {
|
|
111
|
-
signal,
|
|
112
|
-
onUpdate: setSuggestions
|
|
113
|
-
});
|
|
114
|
-
} catch {}
|
|
115
|
-
})();
|
|
47
|
+
const lastAdapterKeyRef = useRef(adapterKey);
|
|
48
|
+
const adapterReplacedRef = useRef(false);
|
|
49
|
+
useInsertionEffect(() => {
|
|
50
|
+
const previousAdapter = adapterRef.current;
|
|
51
|
+
adapterRef.current = suggestionAdapter;
|
|
52
|
+
const adapterReplaced = previousAdapter !== void 0 && suggestionAdapter !== void 0 && lastAdapterKeyRef.current !== adapterKey;
|
|
53
|
+
adapterReplacedRef.current ||= adapterReplaced;
|
|
54
|
+
if (suggestionAdapter === void 0 || adapterReplaced) controllerRef.current?.abort();
|
|
55
|
+
lastAdapterKeyRef.current = adapterKey;
|
|
56
|
+
}, [adapterKey, suggestionAdapter]);
|
|
57
|
+
const hasAdapter = suggestionAdapter !== void 0;
|
|
58
|
+
const adapterPresentRef = useRef(hasAdapter);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
const clearSuggestions = () => {
|
|
61
|
+
controllerRef.current?.abort();
|
|
62
|
+
controllerRef.current = null;
|
|
63
|
+
setSuggestions((prev) => prev.length === 0 ? prev : EMPTY_SUGGESTIONS);
|
|
116
64
|
};
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
65
|
+
const adapter = adapterRef.current;
|
|
66
|
+
const adapterRestored = hasAdapter && !adapterPresentRef.current;
|
|
67
|
+
adapterPresentRef.current = hasAdapter;
|
|
68
|
+
const adapterReplaced_0 = adapterReplacedRef.current;
|
|
69
|
+
adapterReplacedRef.current = false;
|
|
70
|
+
if (!adapter) {
|
|
71
|
+
clearSuggestions();
|
|
72
|
+
wasRunningRef.current = isRunning;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (adapterReplaced_0) clearSuggestions();
|
|
76
|
+
if (isRunning) {
|
|
77
|
+
if (!wasRunningRef.current) clearSuggestions();
|
|
78
|
+
wasRunningRef.current = true;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (!wasRunningRef.current && !adapterReplaced_0 && !adapterRestored) return;
|
|
82
|
+
wasRunningRef.current = false;
|
|
83
|
+
const currentMessages = messagesRef.current;
|
|
84
|
+
const last = currentMessages.at(-1);
|
|
85
|
+
if (last?.role !== "assistant") return;
|
|
86
|
+
if (last.status?.type === "requires-action") return;
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
controllerRef.current = controller;
|
|
89
|
+
const { signal } = controller;
|
|
90
|
+
(async () => {
|
|
91
|
+
try {
|
|
92
|
+
const promiseOrGenerator = adapter.generate({
|
|
93
|
+
messages: currentMessages,
|
|
94
|
+
signal
|
|
95
|
+
});
|
|
96
|
+
await consumeSuggestionResult(promiseOrGenerator, {
|
|
97
|
+
signal,
|
|
98
|
+
onUpdate: (nextSuggestions) => {
|
|
99
|
+
if (controllerRef.current !== controller) return;
|
|
100
|
+
setSuggestions(nextSuggestions);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} catch {}
|
|
104
|
+
})();
|
|
105
|
+
}, [
|
|
106
|
+
adapterKey,
|
|
107
|
+
hasAdapter,
|
|
108
|
+
isRunning
|
|
109
|
+
]);
|
|
110
|
+
useReplaySafeEffect(() => {
|
|
111
|
+
return () => {
|
|
132
112
|
controllerRef.current?.abort();
|
|
133
113
|
};
|
|
134
|
-
|
|
135
|
-
$[11] = t6;
|
|
136
|
-
$[12] = t7;
|
|
137
|
-
} else {
|
|
138
|
-
t6 = $[11];
|
|
139
|
-
t7 = $[12];
|
|
140
|
-
}
|
|
141
|
-
useReplaySafeEffect(t6, t7);
|
|
114
|
+
}, []);
|
|
142
115
|
return suggestions;
|
|
143
116
|
};
|
|
144
117
|
const NO_CANCELLED_MESSAGE_IDS = /* @__PURE__ */ new Set();
|
|
@@ -147,7 +120,19 @@ const NO_SUPERSEDED_APPROVAL_PROJECTION = Object.freeze({
|
|
|
147
120
|
statusMessageIds: Object.freeze(/* @__PURE__ */ new Set())
|
|
148
121
|
});
|
|
149
122
|
const NO_TOOL_APPROVAL_RESPONSES = /* @__PURE__ */ new Map();
|
|
150
|
-
const
|
|
123
|
+
const chatRuntimeStates = /* @__PURE__ */ new WeakMap();
|
|
124
|
+
const getChatRuntimeState = (owner) => {
|
|
125
|
+
if (owner === void 0) return void 0;
|
|
126
|
+
let state = chatRuntimeStates.get(owner);
|
|
127
|
+
if (state === void 0) {
|
|
128
|
+
state = {
|
|
129
|
+
approvals: /* @__PURE__ */ new Map(),
|
|
130
|
+
cancelledMessageIds: NO_CANCELLED_MESSAGE_IDS
|
|
131
|
+
};
|
|
132
|
+
chatRuntimeStates.set(owner, state);
|
|
133
|
+
}
|
|
134
|
+
return state;
|
|
135
|
+
};
|
|
151
136
|
const toApprovalResponses = (owned) => owned && owned.size > 0 ? new Map([...owned].map(([id, entry]) => [id, entry.response])) : NO_TOOL_APPROVAL_RESPONSES;
|
|
152
137
|
/**
|
|
153
138
|
* The answers live on the owner, but each mounted runtime renders them from
|
|
@@ -155,17 +140,17 @@ const toApprovalResponses = (owned) => owned && owned.size > 0 ? new Map([...own
|
|
|
155
140
|
* may already be unmounted (a rollback resolving after a remount), and another
|
|
156
141
|
* runtime may be mounted over the same owner.
|
|
157
142
|
*/
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
const listeners =
|
|
161
|
-
|
|
143
|
+
const chatRuntimeListeners = /* @__PURE__ */ new WeakMap();
|
|
144
|
+
const subscribeToChatRuntimeState = (owner, listener) => {
|
|
145
|
+
const listeners = chatRuntimeListeners.get(owner) ?? /* @__PURE__ */ new Set();
|
|
146
|
+
chatRuntimeListeners.set(owner, listeners);
|
|
162
147
|
listeners.add(listener);
|
|
163
148
|
return () => {
|
|
164
149
|
listeners.delete(listener);
|
|
165
150
|
};
|
|
166
151
|
};
|
|
167
|
-
const
|
|
168
|
-
for (const listener of [...
|
|
152
|
+
const notifyChatRuntimeState = (owner) => {
|
|
153
|
+
for (const listener of [...chatRuntimeListeners.get(owner) ?? []]) listener();
|
|
169
154
|
};
|
|
170
155
|
const getSupersededApprovalProjection = (messages, hostApprovalIds, joinStrategy, isRunning) => {
|
|
171
156
|
const approvalIds = /* @__PURE__ */ new Set();
|
|
@@ -176,7 +161,7 @@ const getSupersededApprovalProjection = (messages, hostApprovalIds, joinStrategy
|
|
|
176
161
|
let previousWasVoice = false;
|
|
177
162
|
const flush = () => {
|
|
178
163
|
const hasOpenToolPart = lastAssistant === messages[lastIndex] && lastAssistant?.parts?.some((part) => {
|
|
179
|
-
if (!isToolUIPart(part) || part.state === "output-available" || part.state === "output-error" || part.state === "output-denied") return false;
|
|
164
|
+
if (typeof part?.type !== "string" || !isToolUIPart(part) || part.state === "output-available" || part.state === "output-error" || part.state === "output-denied") return false;
|
|
180
165
|
const approval = part.approval;
|
|
181
166
|
const resolution = approval?.resolution ?? (approval?.descriptor)?.resolution;
|
|
182
167
|
return resolution !== "cancelled" && resolution !== "expired";
|
|
@@ -196,7 +181,7 @@ const getSupersededApprovalProjection = (messages, hostApprovalIds, joinStrategy
|
|
|
196
181
|
previousWasVoice = isVoice;
|
|
197
182
|
}
|
|
198
183
|
for (const part of message.parts ?? []) {
|
|
199
|
-
if (!isToolUIPart(part) || part.state !== "approval-requested") continue;
|
|
184
|
+
if (typeof part?.type !== "string" || !isToolUIPart(part) || part.state !== "approval-requested") continue;
|
|
200
185
|
const approval = part.approval;
|
|
201
186
|
if (!approval) continue;
|
|
202
187
|
const approvalId = approval.id;
|
|
@@ -217,7 +202,7 @@ const getSupersededApprovalProjection = (messages, hostApprovalIds, joinStrategy
|
|
|
217
202
|
};
|
|
218
203
|
};
|
|
219
204
|
const findRawToolMessageIndex = (messages, messageId, toolCallId, joinStrategy) => {
|
|
220
|
-
const containsToolCall = (message) => message.parts?.some((part) => isToolUIPart(part) && part.toolCallId === toolCallId) === true;
|
|
205
|
+
const containsToolCall = (message) => message.parts?.some((part) => typeof part?.type === "string" && isToolUIPart(part) && part.toolCallId === toolCallId) === true;
|
|
221
206
|
const messageIndex = messages.findIndex((message) => message.id === messageId);
|
|
222
207
|
if (messageIndex === -1) return -1;
|
|
223
208
|
if (containsToolCall(messages[messageIndex])) return messageIndex;
|
|
@@ -243,11 +228,9 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
243
228
|
const [toolStatuses, setToolStatuses] = useState({});
|
|
244
229
|
const [cancelledMessages, setCancelledMessages] = useState(null);
|
|
245
230
|
const approvalOwner = adapter.unstable_hostApprovalOwner;
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
return created;
|
|
250
|
-
})() : void 0;
|
|
231
|
+
const chatRuntimeState = getChatRuntimeState(approvalOwner);
|
|
232
|
+
const ownedApprovals = chatRuntimeState?.approvals;
|
|
233
|
+
const ownedCancelledMessageIds = useSyncExternalStore(useCallback((listener) => approvalOwner ? subscribeToChatRuntimeState(approvalOwner, listener) : () => {}, [approvalOwner]), useCallback(() => chatRuntimeState?.cancelledMessageIds ?? NO_CANCELLED_MESSAGE_IDS, [chatRuntimeState]), () => NO_CANCELLED_MESSAGE_IDS);
|
|
251
234
|
const [toolApprovalResponses, setToolApprovalResponses] = useState(() => toApprovalResponses(ownedApprovals));
|
|
252
235
|
const [toolArtifactEpoch, setToolArtifactEpoch] = useState(0);
|
|
253
236
|
const [toolInteractionEpoch, setToolInteractionEpoch] = useState(0);
|
|
@@ -266,7 +249,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
266
249
|
return prev.size === next.size && [...next].every(([id_1, response]) => prev.get(id_1) === response) ? prev : next;
|
|
267
250
|
});
|
|
268
251
|
};
|
|
269
|
-
const unsubscribe =
|
|
252
|
+
const unsubscribe = subscribeToChatRuntimeState(approvalOwner, sync);
|
|
270
253
|
sync();
|
|
271
254
|
return unsubscribe;
|
|
272
255
|
}, [approvalOwner, ownedApprovals]);
|
|
@@ -298,7 +281,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
298
281
|
const messageTiming = useStreamingTiming$1(chatHelpers.messages, isRunning);
|
|
299
282
|
const lastMessage = chatHelpers.messages.at(-1);
|
|
300
283
|
const optimisticMessageId = isRunning && lastMessage?.role === "assistant" ? lastMessage.id : void 0;
|
|
301
|
-
const cancelledMessageIds = cancelledMessages?.chatId === chatHelpers.id ? cancelledMessages.ids : NO_CANCELLED_MESSAGE_IDS;
|
|
284
|
+
const cancelledMessageIds = chatRuntimeState ? ownedCancelledMessageIds : cancelledMessages?.chatId === chatHelpers.id ? cancelledMessages.ids : NO_CANCELLED_MESSAGE_IDS;
|
|
302
285
|
const supportsRichToolApprovalResponses = customOnRespondToToolApproval != null;
|
|
303
286
|
const supersededApprovalProjectionRef = useRef(NO_SUPERSEDED_APPROVAL_PROJECTION);
|
|
304
287
|
const supersededApprovalProjection = useMemo(() => {
|
|
@@ -323,16 +306,24 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
323
306
|
return AISDKMessageConverter.toThreadMessages(sourceMessages, false, metadata);
|
|
324
307
|
}, [supportsRichToolApprovalResponses]);
|
|
325
308
|
const retractCancellation = useCallback((chatId, messageId) => {
|
|
309
|
+
if (chatRuntimeState !== void 0 && approvalOwner !== void 0) {
|
|
310
|
+
if (!chatRuntimeState.cancelledMessageIds.has(messageId)) return;
|
|
311
|
+
const ids = new Set(chatRuntimeState.cancelledMessageIds);
|
|
312
|
+
ids.delete(messageId);
|
|
313
|
+
chatRuntimeState.cancelledMessageIds = ids;
|
|
314
|
+
notifyChatRuntimeState(approvalOwner);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
326
317
|
setCancelledMessages((prev_0) => {
|
|
327
318
|
if (prev_0?.chatId !== chatId || !prev_0.ids.has(messageId)) return prev_0;
|
|
328
|
-
const
|
|
329
|
-
|
|
319
|
+
const ids_0 = new Set(prev_0.ids);
|
|
320
|
+
ids_0.delete(messageId);
|
|
330
321
|
return {
|
|
331
322
|
chatId,
|
|
332
|
-
ids
|
|
323
|
+
ids: ids_0
|
|
333
324
|
};
|
|
334
325
|
});
|
|
335
|
-
}, []);
|
|
326
|
+
}, [approvalOwner, chatRuntimeState]);
|
|
336
327
|
const resumedMessageId = providerIsRunning && lastMessage?.role === "assistant" ? lastMessage.id : void 0;
|
|
337
328
|
useEffect(() => {
|
|
338
329
|
const wasProviderRunning = wasProviderRunningRef.current;
|
|
@@ -412,7 +403,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
412
403
|
if (message.role !== "assistant") return message;
|
|
413
404
|
let messageChanged = false;
|
|
414
405
|
const parts = message.parts?.map((part) => {
|
|
415
|
-
if (!isToolUIPart(part)) return part;
|
|
406
|
+
if (typeof part?.type !== "string" || !isToolUIPart(part)) return part;
|
|
416
407
|
if (part.state === "output-available" || part.state === "output-error" || part.state === "output-denied") return part;
|
|
417
408
|
messageChanged = true;
|
|
418
409
|
const { approval: _approval, ...rest } = part;
|
|
@@ -441,7 +432,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
441
432
|
}));
|
|
442
433
|
const respondViaHost = async (onRespond, response_0) => {
|
|
443
434
|
const { approvalId: approvalId_0 } = response_0;
|
|
444
|
-
const requested = chatHelpers.messages.flatMap((message_0) => message_0.parts.flatMap((part_0) => isToolUIPart(part_0) ? [{
|
|
435
|
+
const requested = chatHelpers.messages.flatMap((message_0) => message_0.parts.flatMap((part_0) => typeof part_0?.type === "string" && isToolUIPart(part_0) ? [{
|
|
445
436
|
messageId: message_0.id,
|
|
446
437
|
part: part_0
|
|
447
438
|
}] : [])).find(({ part: part_1 }) => part_1.state === "approval-requested" && part_1.approval?.id === approvalId_0);
|
|
@@ -455,7 +446,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
455
446
|
if (applied) startedWith?.set(approvalId_0, { response: response_0 });
|
|
456
447
|
else startedWith?.delete(approvalId_0);
|
|
457
448
|
if (startedOwner) {
|
|
458
|
-
|
|
449
|
+
notifyChatRuntimeState(startedOwner);
|
|
459
450
|
return;
|
|
460
451
|
}
|
|
461
452
|
if (lastApprovalOwnerRef.current !== startedOwner) return;
|
|
@@ -485,6 +476,11 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
485
476
|
const remainsApplied = startedWith?.has(approvalId_0) ?? startedResponses.has(approvalId_0);
|
|
486
477
|
if (isApplied && remainsApplied) await persistToolApprovalResponses(requested.messageId);
|
|
487
478
|
};
|
|
479
|
+
const lastAISDKMessageId = (threadMessageId) => {
|
|
480
|
+
if (threadMessageId == null) return null;
|
|
481
|
+
const threadMessage = runtimeRef.current.thread.getState().messages.find((message_1) => message_1.id === threadMessageId);
|
|
482
|
+
return (threadMessage && getVercelAIMessages(threadMessage).at(-1)?.id) ?? threadMessageId;
|
|
483
|
+
};
|
|
488
484
|
const hasSeededRepositoryRef = useRef(false);
|
|
489
485
|
const shouldFeedRepository = exportedMessageRepository != null && !hasSeededRepositoryRef.current && messages.length === 0;
|
|
490
486
|
const runtime = useExternalStoreRuntime({
|
|
@@ -495,7 +491,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
495
491
|
setToolStatuses,
|
|
496
492
|
setMessages: (messages_2) => chatHelpers.setMessages(messages_2.map(getVercelAIMessages).filter(Boolean).flat()),
|
|
497
493
|
onImport: (messages_3) => chatHelpers.setMessages(messages_3.map(getVercelAIMessages).filter(Boolean).flat()),
|
|
498
|
-
onVoiceTranscript: (
|
|
494
|
+
onVoiceTranscript: (message_2) => chatHelpers.setMessages((current) => [...current, toVoiceTranscriptUIMessage(message_2)]),
|
|
499
495
|
onExportExternalState: () => {
|
|
500
496
|
const exported = runtimeRef.current.thread.export();
|
|
501
497
|
const expandedMessages = [];
|
|
@@ -521,12 +517,15 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
521
517
|
runtimeRef.current.thread.import(exportedRepo);
|
|
522
518
|
},
|
|
523
519
|
onCancel: async () => {
|
|
524
|
-
const
|
|
525
|
-
const cancelledId = isRunning &&
|
|
520
|
+
const message_3 = chatHelpers.messages.at(-1);
|
|
521
|
+
const cancelledId = isRunning && message_3?.role === "assistant" ? message_3.id : void 0;
|
|
526
522
|
if (cancelledId) {
|
|
527
523
|
const liveIds = new Set(chatHelpers.messages.map((m) => m.id));
|
|
528
|
-
|
|
529
|
-
|
|
524
|
+
if (chatRuntimeState !== void 0 && approvalOwner !== void 0) {
|
|
525
|
+
chatRuntimeState.cancelledMessageIds = /* @__PURE__ */ new Set([...[...chatRuntimeState.cancelledMessageIds].filter((id_5) => liveIds.has(id_5)), cancelledId]);
|
|
526
|
+
notifyChatRuntimeState(approvalOwner);
|
|
527
|
+
} else setCancelledMessages((prev_1) => {
|
|
528
|
+
const kept = prev_1?.chatId === chatHelpers.id ? [...prev_1.ids].filter((id_6) => liveIds.has(id_6)) : [];
|
|
530
529
|
return {
|
|
531
530
|
chatId: chatHelpers.id,
|
|
532
531
|
ids: /* @__PURE__ */ new Set([...kept, cancelledId])
|
|
@@ -542,29 +541,30 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
542
541
|
}
|
|
543
542
|
}
|
|
544
543
|
},
|
|
545
|
-
onNew: async (
|
|
546
|
-
const createMessage = (customToCreateMessage ?? toCreateMessage)(
|
|
547
|
-
if (!(
|
|
548
|
-
chatHelpers.setMessages((current_0) => [...current_0, toUIMessage(createMessage,
|
|
544
|
+
onNew: async (message_4) => {
|
|
545
|
+
const createMessage = (customToCreateMessage ?? toCreateMessage)(message_4);
|
|
546
|
+
if (!(message_4.startRun ?? message_4.role === "user")) {
|
|
547
|
+
chatHelpers.setMessages((current_0) => [...current_0, toUIMessage(createMessage, message_4.role)]);
|
|
549
548
|
return;
|
|
550
549
|
}
|
|
551
|
-
lastRunConfigRef.current =
|
|
550
|
+
lastRunConfigRef.current = message_4.runConfig;
|
|
552
551
|
await completePendingToolCalls();
|
|
553
|
-
await chatHelpers.sendMessage(createMessage, { metadata:
|
|
552
|
+
await chatHelpers.sendMessage(createMessage, { metadata: message_4.runConfig });
|
|
554
553
|
},
|
|
555
|
-
onEdit: async (
|
|
556
|
-
const createMessage_0 = (customToCreateMessage ?? toCreateMessage)(
|
|
557
|
-
|
|
558
|
-
|
|
554
|
+
onEdit: async (message_5) => {
|
|
555
|
+
const createMessage_0 = (customToCreateMessage ?? toCreateMessage)(message_5);
|
|
556
|
+
const parentId_0 = lastAISDKMessageId(message_5.parentId);
|
|
557
|
+
if (!(message_5.startRun ?? message_5.role === "user")) {
|
|
558
|
+
chatHelpers.setMessages((current_1) => [...sliceMessagesUntil(current_1, parentId_0), toUIMessage(createMessage_0, message_5.role)]);
|
|
559
559
|
return;
|
|
560
560
|
}
|
|
561
|
-
lastRunConfigRef.current =
|
|
562
|
-
chatHelpers.setMessages((current_2) => sliceMessagesUntil(current_2,
|
|
563
|
-
await chatHelpers.sendMessage(createMessage_0, { metadata:
|
|
561
|
+
lastRunConfigRef.current = message_5.runConfig;
|
|
562
|
+
chatHelpers.setMessages((current_2) => sliceMessagesUntil(current_2, parentId_0));
|
|
563
|
+
await chatHelpers.sendMessage(createMessage_0, { metadata: message_5.runConfig });
|
|
564
564
|
},
|
|
565
565
|
onDelete: async (messageId_0) => {
|
|
566
566
|
const threadMessages = runtimeRef.current.thread.getState().messages;
|
|
567
|
-
const messageIndex = threadMessages.findIndex((
|
|
567
|
+
const messageIndex = threadMessages.findIndex((message_6) => message_6.id === messageId_0);
|
|
568
568
|
if (messageIndex === -1) return;
|
|
569
569
|
await deleteHistoryMessage(messageId_0);
|
|
570
570
|
let removedToolArtifact = false;
|
|
@@ -583,15 +583,17 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
583
583
|
if (removedToolArtifact) markToolArtifactsChanged();
|
|
584
584
|
if (removedToolInteractions) markToolInteractionsChanged();
|
|
585
585
|
if (removedToolApprovalResponse || removedHostApprovalId) {
|
|
586
|
-
if (approvalOwner)
|
|
586
|
+
if (approvalOwner) notifyChatRuntimeState(approvalOwner);
|
|
587
587
|
setToolApprovalResponses(new Map(toolApprovalResponsesRef.current));
|
|
588
588
|
}
|
|
589
|
-
const deleteIds = new Set(getExternalStoreMessages(threadMessages[messageIndex]).map((
|
|
590
|
-
chatHelpers.setMessages((current_3) => current_3.filter((
|
|
589
|
+
const deleteIds = new Set(getExternalStoreMessages(threadMessages[messageIndex]).map((message_7) => message_7.id));
|
|
590
|
+
chatHelpers.setMessages((current_3) => current_3.filter((message_8) => !deleteIds.has(message_8.id)));
|
|
591
591
|
},
|
|
592
|
-
onReload: async (
|
|
592
|
+
onReload: async (parentId_1, config) => {
|
|
593
593
|
lastRunConfigRef.current = config.runConfig;
|
|
594
|
-
const newMessages = sliceMessagesUntil(chatHelpers.messages,
|
|
594
|
+
const newMessages = sliceMessagesUntil(chatHelpers.messages, lastAISDKMessageId(parentId_1));
|
|
595
|
+
const reloaded = chatHelpers.messages[newMessages.length];
|
|
596
|
+
if (reloaded?.role === "assistant") newMessages.push(reloaded);
|
|
595
597
|
chatHelpers.setMessages(newMessages);
|
|
596
598
|
await chatHelpers.regenerate({ metadata: config.runConfig });
|
|
597
599
|
},
|
|
@@ -605,15 +607,15 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
605
607
|
const output = !isError && modelContent !== void 0 ? wrapModelContentEnvelope(result_0, modelContent) : result_0;
|
|
606
608
|
if (targetIndex >= 0 && targetIndex !== chatHelpers.messages.length - 1) {
|
|
607
609
|
const target = chatHelpers.messages[targetIndex];
|
|
608
|
-
const targetPart = target.parts.find((part_3) => isToolUIPart(part_3) && part_3.toolCallId === toolCallId);
|
|
610
|
+
const targetPart = target.parts.find((part_3) => typeof part_3?.type === "string" && isToolUIPart(part_3) && part_3.toolCallId === toolCallId);
|
|
609
611
|
if (targetPart?.state === "output-error" || targetPart?.state === "output-denied" || targetPart?.state === "output-available" && !targetPart.preliminary) return Promise.resolve();
|
|
610
612
|
const targetMessageId = target.id;
|
|
611
|
-
chatHelpers.setMessages((current_4) => current_4.map((
|
|
612
|
-
if (
|
|
613
|
+
chatHelpers.setMessages((current_4) => current_4.map((message_9) => {
|
|
614
|
+
if (message_9.id !== targetMessageId) return message_9;
|
|
613
615
|
return {
|
|
614
|
-
...
|
|
615
|
-
parts:
|
|
616
|
-
if (!isToolUIPart(part_4) || part_4.toolCallId !== toolCallId) return part_4;
|
|
616
|
+
...message_9,
|
|
617
|
+
parts: message_9.parts.map((part_4) => {
|
|
618
|
+
if (typeof part_4?.type !== "string" || !isToolUIPart(part_4) || part_4.toolCallId !== toolCallId) return part_4;
|
|
617
619
|
const { preliminary: _preliminary, ...finalPart } = part_4;
|
|
618
620
|
return {
|
|
619
621
|
...finalPart,
|
|
@@ -682,9 +684,6 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
682
684
|
}, [exportedMessageRepository, chatHelpers.messages.length]);
|
|
683
685
|
return runtime;
|
|
684
686
|
};
|
|
685
|
-
function _temp(prev) {
|
|
686
|
-
return prev.length === 0 ? prev : EMPTY_SUGGESTIONS;
|
|
687
|
-
}
|
|
688
687
|
//#endregion
|
|
689
688
|
export { useAISDKRuntime };
|
|
690
689
|
|