@assistant-ui/ai-sdk 0.0.8 → 0.0.10
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/LICENSE +1 -1
- package/dist/converters/convertMessage.d.ts +2 -0
- package/dist/converters/convertMessage.d.ts.map +1 -1
- package/dist/converters/convertMessage.js +15 -4
- package/dist/converters/convertMessage.js.map +1 -1
- package/dist/converters/toCreateMessage.d.ts.map +1 -1
- package/dist/converters/toCreateMessage.js +2 -1
- package/dist/converters/toCreateMessage.js.map +1 -1
- package/dist/runtime/AISDKChat.d.ts.map +1 -1
- package/dist/runtime/AISDKChat.js.map +1 -1
- package/dist/runtime/AISDKThreads.js.map +1 -1
- package/dist/runtime/sdkIdentity.js +1 -1
- package/dist/runtime/useAISDKRuntime.d.ts +8 -1
- package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
- package/dist/runtime/useAISDKRuntime.js +212 -34
- package/dist/runtime/useAISDKRuntime.js.map +1 -1
- package/dist/runtime/useChatRuntime.js +1 -1
- package/dist/runtime/useChatRuntime.js.map +1 -1
- package/dist/runtime/useChatThread.d.ts.map +1 -1
- package/dist/runtime/useChatThread.js +40 -10
- package/dist/runtime/useChatThread.js.map +1 -1
- package/dist/runtime/useExternalHistory.d.ts.map +1 -1
- package/dist/runtime/useExternalHistory.js +2 -1
- package/dist/runtime/useExternalHistory.js.map +1 -1
- package/dist/runtime/useResourceCleanup.js.map +1 -1
- package/dist/runtime/useStreamingTiming.js.map +1 -1
- package/dist/transport/AssistantChatTransport.d.ts.map +1 -1
- package/dist/transport/AssistantChatTransport.js +9 -2
- package/dist/transport/AssistantChatTransport.js.map +1 -1
- package/dist/transport/resumable.js.map +1 -1
- package/dist/usage.js.map +1 -1
- package/package.json +15 -12
- package/src/converters/convertMessage.test.ts +99 -0
- package/src/converters/convertMessage.ts +27 -2
- package/src/converters/toCreateMessage.test.ts +13 -0
- package/src/converters/toCreateMessage.ts +1 -0
- package/src/runtime/AISDKChat.ts +0 -4
- package/src/runtime/AISDKThreads.test.ts +26 -0
- package/src/runtime/useAISDKRuntime.approval.integration.test.tsx +1588 -19
- package/src/runtime/useAISDKRuntime.approval.test.tsx +27 -0
- package/src/runtime/useAISDKRuntime.fast-refresh.test.tsx +182 -0
- package/src/runtime/useAISDKRuntime.ts +397 -28
- package/src/runtime/useChatRuntime.fast-refresh.test.tsx +94 -0
- package/src/runtime/useChatRuntime.integration.test.tsx +134 -112
- package/src/runtime/useChatRuntime.test.ts +7 -7
- package/src/runtime/useChatThread.test.ts +166 -2
- package/src/runtime/useChatThread.transport.test.tsx +5 -2
- package/src/runtime/useChatThread.ts +56 -17
- package/src/runtime/useExternalHistory.ts +12 -1
- package/src/transport/AssistantChatTransport.test.ts +164 -0
- package/src/transport/AssistantChatTransport.ts +22 -2
|
@@ -15,6 +15,7 @@ import { useExternalStoreRuntime, useRuntimeAdapters } from "@assistant-ui/core/
|
|
|
15
15
|
import { getExternalStoreMessages, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
16
16
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
17
17
|
import { useCallback, useEffect, useInsertionEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
18
|
+
import { useReplaySafeEffect } from "@assistant-ui/store/internal";
|
|
18
19
|
//#region src/runtime/useAISDKRuntime.ts
|
|
19
20
|
const toUIMessage = (createMessage, fallbackRole) => ({
|
|
20
21
|
...createMessage,
|
|
@@ -137,11 +138,97 @@ const useGeneratedSuggestions = (suggestionAdapter, messages, isRunning) => {
|
|
|
137
138
|
t6 = $[11];
|
|
138
139
|
t7 = $[12];
|
|
139
140
|
}
|
|
140
|
-
|
|
141
|
+
useReplaySafeEffect(t6, t7);
|
|
141
142
|
return suggestions;
|
|
142
143
|
};
|
|
143
144
|
const NO_CANCELLED_MESSAGE_IDS = /* @__PURE__ */ new Set();
|
|
145
|
+
const NO_SUPERSEDED_APPROVAL_PROJECTION = Object.freeze({
|
|
146
|
+
approvalIds: Object.freeze(/* @__PURE__ */ new Set()),
|
|
147
|
+
statusMessageIds: Object.freeze(/* @__PURE__ */ new Set())
|
|
148
|
+
});
|
|
144
149
|
const NO_TOOL_APPROVAL_RESPONSES = /* @__PURE__ */ new Map();
|
|
150
|
+
const hostToolApprovalsByChat = /* @__PURE__ */ new WeakMap();
|
|
151
|
+
const toApprovalResponses = (owned) => owned && owned.size > 0 ? new Map([...owned].map(([id, entry]) => [id, entry.response])) : NO_TOOL_APPROVAL_RESPONSES;
|
|
152
|
+
/**
|
|
153
|
+
* The answers live on the owner, but each mounted runtime renders them from
|
|
154
|
+
* its own state, so a write has to be announced: the runtime that performed it
|
|
155
|
+
* may already be unmounted (a rollback resolving after a remount), and another
|
|
156
|
+
* runtime may be mounted over the same owner.
|
|
157
|
+
*/
|
|
158
|
+
const hostApprovalListenersByChat = /* @__PURE__ */ new WeakMap();
|
|
159
|
+
const subscribeToHostApprovals = (owner, listener) => {
|
|
160
|
+
const listeners = hostApprovalListenersByChat.get(owner) ?? /* @__PURE__ */ new Set();
|
|
161
|
+
hostApprovalListenersByChat.set(owner, listeners);
|
|
162
|
+
listeners.add(listener);
|
|
163
|
+
return () => {
|
|
164
|
+
listeners.delete(listener);
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
const notifyHostApprovals = (owner) => {
|
|
168
|
+
for (const listener of [...hostApprovalListenersByChat.get(owner) ?? []]) listener();
|
|
169
|
+
};
|
|
170
|
+
const getSupersededApprovalProjection = (messages, hostApprovalIds, joinStrategy, isRunning) => {
|
|
171
|
+
const approvalIds = /* @__PURE__ */ new Set();
|
|
172
|
+
const statusMessageIds = /* @__PURE__ */ new Set();
|
|
173
|
+
const lastIndex = messages.length - 1;
|
|
174
|
+
let lastAssistant;
|
|
175
|
+
let hasSupersededApproval = false;
|
|
176
|
+
let previousWasVoice = false;
|
|
177
|
+
const flush = () => {
|
|
178
|
+
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;
|
|
180
|
+
const approval = part.approval;
|
|
181
|
+
const resolution = approval?.resolution ?? (approval?.descriptor)?.resolution;
|
|
182
|
+
return resolution !== "cancelled" && resolution !== "expired";
|
|
183
|
+
});
|
|
184
|
+
if (lastAssistant && hasSupersededApproval && !hasOpenToolPart && !(isRunning && lastAssistant === messages[lastIndex])) statusMessageIds.add(lastAssistant.id);
|
|
185
|
+
lastAssistant = void 0;
|
|
186
|
+
hasSupersededApproval = false;
|
|
187
|
+
previousWasVoice = false;
|
|
188
|
+
};
|
|
189
|
+
for (let index = 0; index < messages.length; index++) {
|
|
190
|
+
const message = messages[index];
|
|
191
|
+
if (message.role !== "assistant") flush();
|
|
192
|
+
else {
|
|
193
|
+
const isVoice = message.metadata?.modality === "voice";
|
|
194
|
+
if (isVoice || previousWasVoice || joinStrategy === "none") flush();
|
|
195
|
+
lastAssistant = message;
|
|
196
|
+
previousWasVoice = isVoice;
|
|
197
|
+
}
|
|
198
|
+
for (const part of message.parts ?? []) {
|
|
199
|
+
if (!isToolUIPart(part) || part.state !== "approval-requested") continue;
|
|
200
|
+
const approval = part.approval;
|
|
201
|
+
if (!approval) continue;
|
|
202
|
+
const approvalId = approval.id;
|
|
203
|
+
if (hostApprovalIds.has(approvalId)) continue;
|
|
204
|
+
const resolution = approval.resolution ?? approval.descriptor?.resolution;
|
|
205
|
+
if (resolution === "cancelled" || resolution === "expired") continue;
|
|
206
|
+
if (index !== lastIndex) {
|
|
207
|
+
approvalIds.add(approvalId);
|
|
208
|
+
if (message.role === "assistant") hasSupersededApproval = true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
flush();
|
|
213
|
+
if (approvalIds.size === 0 && statusMessageIds.size === 0) return NO_SUPERSEDED_APPROVAL_PROJECTION;
|
|
214
|
+
return {
|
|
215
|
+
approvalIds,
|
|
216
|
+
statusMessageIds
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
const findRawToolMessageIndex = (messages, messageId, toolCallId, joinStrategy) => {
|
|
220
|
+
const containsToolCall = (message) => message.parts?.some((part) => isToolUIPart(part) && part.toolCallId === toolCallId) === true;
|
|
221
|
+
const messageIndex = messages.findIndex((message) => message.id === messageId);
|
|
222
|
+
if (messageIndex === -1) return -1;
|
|
223
|
+
if (containsToolCall(messages[messageIndex])) return messageIndex;
|
|
224
|
+
if (joinStrategy === "none" || messages[messageIndex]?.role !== "assistant") return -1;
|
|
225
|
+
let start = messageIndex;
|
|
226
|
+
while (start > 0 && messages[start - 1]?.role === "assistant") start--;
|
|
227
|
+
let end = messageIndex;
|
|
228
|
+
while (end + 1 < messages.length && messages[end + 1]?.role === "assistant") end++;
|
|
229
|
+
for (let index = start; index <= end; index++) if (containsToolCall(messages[index])) return index;
|
|
230
|
+
return -1;
|
|
231
|
+
};
|
|
145
232
|
const toChatError = (error) => {
|
|
146
233
|
const code = error.code;
|
|
147
234
|
return {
|
|
@@ -155,11 +242,42 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
155
242
|
const contextAdapters = useRuntimeAdapters();
|
|
156
243
|
const [toolStatuses, setToolStatuses] = useState({});
|
|
157
244
|
const [cancelledMessages, setCancelledMessages] = useState(null);
|
|
158
|
-
const
|
|
245
|
+
const approvalOwner = adapter.unstable_hostApprovalOwner;
|
|
246
|
+
const ownedApprovals = approvalOwner ? hostToolApprovalsByChat.get(approvalOwner) ?? (() => {
|
|
247
|
+
const created = /* @__PURE__ */ new Map();
|
|
248
|
+
hostToolApprovalsByChat.set(approvalOwner, created);
|
|
249
|
+
return created;
|
|
250
|
+
})() : void 0;
|
|
251
|
+
const [toolApprovalResponses, setToolApprovalResponses] = useState(() => toApprovalResponses(ownedApprovals));
|
|
159
252
|
const [toolArtifactEpoch, setToolArtifactEpoch] = useState(0);
|
|
160
253
|
const [toolInteractionEpoch, setToolInteractionEpoch] = useState(0);
|
|
161
|
-
const
|
|
162
|
-
const
|
|
254
|
+
const toolApprovalResponsesRef = useRef(new Map(toApprovalResponses(ownedApprovals)));
|
|
255
|
+
const ownedApprovalIdsRef = useRef(new Set(ownedApprovals?.keys()));
|
|
256
|
+
const hostApprovalIdsRef = useRef(new Set(ownedApprovals?.keys()));
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
if (!approvalOwner || !ownedApprovals) return void 0;
|
|
259
|
+
const sync = () => {
|
|
260
|
+
for (const id of ownedApprovalIdsRef.current) toolApprovalResponsesRef.current.delete(id);
|
|
261
|
+
for (const [id_0, entry] of ownedApprovals) toolApprovalResponsesRef.current.set(id_0, entry.response);
|
|
262
|
+
ownedApprovalIdsRef.current = new Set(ownedApprovals.keys());
|
|
263
|
+
hostApprovalIdsRef.current = new Set(toolApprovalResponsesRef.current.keys());
|
|
264
|
+
setToolApprovalResponses((prev) => {
|
|
265
|
+
const next = new Map(toolApprovalResponsesRef.current);
|
|
266
|
+
return prev.size === next.size && [...next].every(([id_1, response]) => prev.get(id_1) === response) ? prev : next;
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
const unsubscribe = subscribeToHostApprovals(approvalOwner, sync);
|
|
270
|
+
sync();
|
|
271
|
+
return unsubscribe;
|
|
272
|
+
}, [approvalOwner, ownedApprovals]);
|
|
273
|
+
const lastApprovalOwnerRef = useRef(approvalOwner);
|
|
274
|
+
if (lastApprovalOwnerRef.current !== approvalOwner) {
|
|
275
|
+
lastApprovalOwnerRef.current = approvalOwner;
|
|
276
|
+
hostApprovalIdsRef.current = new Set(ownedApprovals?.keys());
|
|
277
|
+
toolApprovalResponsesRef.current = new Map(toApprovalResponses(ownedApprovals));
|
|
278
|
+
ownedApprovalIdsRef.current = new Set(ownedApprovals?.keys());
|
|
279
|
+
setToolApprovalResponses(new Map(toolApprovalResponsesRef.current));
|
|
280
|
+
}
|
|
163
281
|
const toolArgsKeyOrderCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
164
282
|
const toolLastInputCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
165
283
|
const toolArgsTextCacheRef = useRef(/* @__PURE__ */ new WeakMap());
|
|
@@ -182,6 +300,19 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
182
300
|
const optimisticMessageId = isRunning && lastMessage?.role === "assistant" ? lastMessage.id : void 0;
|
|
183
301
|
const cancelledMessageIds = cancelledMessages?.chatId === chatHelpers.id ? cancelledMessages.ids : NO_CANCELLED_MESSAGE_IDS;
|
|
184
302
|
const supportsRichToolApprovalResponses = customOnRespondToToolApproval != null;
|
|
303
|
+
const supersededApprovalProjectionRef = useRef(NO_SUPERSEDED_APPROVAL_PROJECTION);
|
|
304
|
+
const supersededApprovalProjection = useMemo(() => {
|
|
305
|
+
const projection = getSupersededApprovalProjection(chatHelpers.messages, hostApprovalIdsRef.current, joinStrategy, isRunning);
|
|
306
|
+
const previous = supersededApprovalProjectionRef.current;
|
|
307
|
+
if (projection.approvalIds.size === previous.approvalIds.size && projection.statusMessageIds.size === previous.statusMessageIds.size && [...projection.approvalIds].every((id_3) => previous.approvalIds.has(id_3)) && [...projection.statusMessageIds].every((id_2) => previous.statusMessageIds.has(id_2))) return previous;
|
|
308
|
+
supersededApprovalProjectionRef.current = projection;
|
|
309
|
+
return projection;
|
|
310
|
+
}, [
|
|
311
|
+
chatHelpers.messages,
|
|
312
|
+
joinStrategy,
|
|
313
|
+
isRunning,
|
|
314
|
+
toolApprovalResponses
|
|
315
|
+
]);
|
|
185
316
|
const toThreadMessages = useCallback((sourceMessages) => {
|
|
186
317
|
const metadata = {
|
|
187
318
|
supportsRichToolApprovalResponses,
|
|
@@ -192,9 +323,9 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
192
323
|
return AISDKMessageConverter.toThreadMessages(sourceMessages, false, metadata);
|
|
193
324
|
}, [supportsRichToolApprovalResponses]);
|
|
194
325
|
const retractCancellation = useCallback((chatId, messageId) => {
|
|
195
|
-
setCancelledMessages((
|
|
196
|
-
if (
|
|
197
|
-
const ids = new Set(
|
|
326
|
+
setCancelledMessages((prev_0) => {
|
|
327
|
+
if (prev_0?.chatId !== chatId || !prev_0.ids.has(messageId)) return prev_0;
|
|
328
|
+
const ids = new Set(prev_0.ids);
|
|
198
329
|
ids.delete(messageId);
|
|
199
330
|
return {
|
|
200
331
|
chatId,
|
|
@@ -228,6 +359,8 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
228
359
|
toolArtifacts: toolArtifactsRef.current,
|
|
229
360
|
toolInteractions: toolInteractionsRef.current,
|
|
230
361
|
supportsRichToolApprovalResponses,
|
|
362
|
+
cancelledToolApprovalIds: supersededApprovalProjection.approvalIds,
|
|
363
|
+
cancelledStatusMessageIds: supersededApprovalProjection.statusMessageIds,
|
|
231
364
|
...optimisticMessageId && { optimisticMessageId },
|
|
232
365
|
...chatHelpers.error && { error: toChatError(chatHelpers.error) },
|
|
233
366
|
...cancelledMessageIds.size > 0 && { cancelledMessageIds },
|
|
@@ -240,6 +373,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
240
373
|
cancelledMessageIds,
|
|
241
374
|
toolApprovalResponses,
|
|
242
375
|
supportsRichToolApprovalResponses,
|
|
376
|
+
supersededApprovalProjection,
|
|
243
377
|
toolArtifactEpoch,
|
|
244
378
|
toolInteractionEpoch
|
|
245
379
|
])
|
|
@@ -256,6 +390,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
256
390
|
const { isLoading, deleteMessage: deleteHistoryMessage, persistToolInteractions, persistToolApprovalResponses } = useExternalHistory(runtimeRef, adapters?.history ?? contextAdapters?.history, toThreadMessages, aiSDKV6FormatAdapter, (messages_0) => {
|
|
257
391
|
chatHelpers.setMessages(messages_0);
|
|
258
392
|
}, toolArtifactsRef.current, markToolArtifactsChanged, toolInteractionsRef.current, markToolInteractionsChanged, toolApprovalResponsesRef.current, () => {
|
|
393
|
+
for (const [id_4, entry_0] of ownedApprovals ?? []) toolApprovalResponsesRef.current.set(id_4, entry_0.response);
|
|
259
394
|
hostApprovalIdsRef.current = new Set(toolApprovalResponsesRef.current.keys());
|
|
260
395
|
setToolApprovalResponses(new Map(toolApprovalResponsesRef.current));
|
|
261
396
|
});
|
|
@@ -273,7 +408,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
273
408
|
if (!cancelPendingToolCallsOnSend) return;
|
|
274
409
|
chatHelpers.setMessages((messages_1) => {
|
|
275
410
|
let hasChanges = false;
|
|
276
|
-
const
|
|
411
|
+
const next_0 = messages_1.map((message) => {
|
|
277
412
|
if (message.role !== "assistant") return message;
|
|
278
413
|
let messageChanged = false;
|
|
279
414
|
const parts = message.parts?.map((part) => {
|
|
@@ -295,7 +430,7 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
295
430
|
};
|
|
296
431
|
});
|
|
297
432
|
if (!hasChanges) return messages_1;
|
|
298
|
-
return
|
|
433
|
+
return next_0;
|
|
299
434
|
});
|
|
300
435
|
};
|
|
301
436
|
const respondViaAISDK = ({ approvalId, approved, reason }) => Promise.resolve(chatHelpers.addToolApprovalResponse({
|
|
@@ -304,38 +439,51 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
304
439
|
...reason != null && { reason },
|
|
305
440
|
options: { metadata: lastRunConfigRef.current }
|
|
306
441
|
}));
|
|
307
|
-
const respondViaHost = async (onRespond,
|
|
308
|
-
const { approvalId: approvalId_0 } =
|
|
442
|
+
const respondViaHost = async (onRespond, response_0) => {
|
|
443
|
+
const { approvalId: approvalId_0 } = response_0;
|
|
309
444
|
const requested = chatHelpers.messages.flatMap((message_0) => message_0.parts.flatMap((part_0) => isToolUIPart(part_0) ? [{
|
|
310
445
|
messageId: message_0.id,
|
|
311
446
|
part: part_0
|
|
312
|
-
}] : [])).find(({ part: part_1 }) => part_1.state === "approval-requested" && part_1.approval
|
|
447
|
+
}] : [])).find(({ part: part_1 }) => part_1.state === "approval-requested" && part_1.approval?.id === approvalId_0);
|
|
313
448
|
if (!requested || hostApprovalIdsRef.current.has(approvalId_0)) throw new Error(`Tool approval ${approvalId_0} is not waiting for a response.`);
|
|
449
|
+
const startedWith = ownedApprovals;
|
|
450
|
+
const startedOwner = approvalOwner;
|
|
451
|
+
const startedResponses = toolApprovalResponsesRef.current;
|
|
452
|
+
let isApplied = false;
|
|
314
453
|
const applyResponse = (applied) => {
|
|
454
|
+
isApplied = applied;
|
|
455
|
+
if (applied) startedWith?.set(approvalId_0, { response: response_0 });
|
|
456
|
+
else startedWith?.delete(approvalId_0);
|
|
457
|
+
if (startedOwner) {
|
|
458
|
+
notifyHostApprovals(startedOwner);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
if (lastApprovalOwnerRef.current !== startedOwner) return;
|
|
315
462
|
if (applied) hostApprovalIdsRef.current.add(approvalId_0);
|
|
316
463
|
else hostApprovalIdsRef.current.delete(approvalId_0);
|
|
317
|
-
if (applied) toolApprovalResponsesRef.current.set(approvalId_0,
|
|
464
|
+
if (applied) toolApprovalResponsesRef.current.set(approvalId_0, response_0);
|
|
318
465
|
else toolApprovalResponsesRef.current.delete(approvalId_0);
|
|
319
466
|
setToolApprovalResponses(new Map(toolApprovalResponsesRef.current));
|
|
320
467
|
};
|
|
321
468
|
applyResponse(true);
|
|
322
469
|
try {
|
|
323
|
-
await onRespond(
|
|
470
|
+
await onRespond(response_0, {
|
|
324
471
|
toolCallId: requested.part.toolCallId,
|
|
325
472
|
toolName: getToolName(requested.part),
|
|
326
473
|
respondViaAISDK: async () => {
|
|
327
474
|
try {
|
|
328
|
-
await respondViaAISDK(
|
|
475
|
+
await respondViaAISDK(response_0);
|
|
329
476
|
} finally {
|
|
330
477
|
applyResponse(false);
|
|
331
478
|
}
|
|
332
479
|
}
|
|
333
480
|
});
|
|
334
481
|
} catch (error_0) {
|
|
335
|
-
if (
|
|
482
|
+
if (isApplied) applyResponse(false);
|
|
336
483
|
throw error_0;
|
|
337
484
|
}
|
|
338
|
-
|
|
485
|
+
const remainsApplied = startedWith?.has(approvalId_0) ?? startedResponses.has(approvalId_0);
|
|
486
|
+
if (isApplied && remainsApplied) await persistToolApprovalResponses(requested.messageId);
|
|
339
487
|
};
|
|
340
488
|
const hasSeededRepositoryRef = useRef(false);
|
|
341
489
|
const shouldFeedRepository = exportedMessageRepository != null && !hasSeededRepositoryRef.current && messages.length === 0;
|
|
@@ -377,8 +525,8 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
377
525
|
const cancelledId = isRunning && message_2?.role === "assistant" ? message_2.id : void 0;
|
|
378
526
|
if (cancelledId) {
|
|
379
527
|
const liveIds = new Set(chatHelpers.messages.map((m) => m.id));
|
|
380
|
-
setCancelledMessages((
|
|
381
|
-
const kept =
|
|
528
|
+
setCancelledMessages((prev_1) => {
|
|
529
|
+
const kept = prev_1?.chatId === chatHelpers.id ? [...prev_1.ids].filter((id_5) => liveIds.has(id_5)) : [];
|
|
382
530
|
return {
|
|
383
531
|
chatId: chatHelpers.id,
|
|
384
532
|
ids: /* @__PURE__ */ new Set([...kept, cancelledId])
|
|
@@ -427,13 +575,17 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
427
575
|
removedToolArtifact = toolArtifactsRef.current.delete(part_2.toolCallId) || removedToolArtifact;
|
|
428
576
|
removedToolInteractions = toolInteractionsRef.current.delete(part_2.toolCallId) || removedToolInteractions;
|
|
429
577
|
if (part_2.approval) {
|
|
578
|
+
ownedApprovals?.delete(part_2.approval.id);
|
|
430
579
|
removedToolApprovalResponse = toolApprovalResponsesRef.current.delete(part_2.approval.id) || removedToolApprovalResponse;
|
|
431
580
|
removedHostApprovalId = hostApprovalIdsRef.current.delete(part_2.approval.id) || removedHostApprovalId;
|
|
432
581
|
}
|
|
433
582
|
}
|
|
434
583
|
if (removedToolArtifact) markToolArtifactsChanged();
|
|
435
584
|
if (removedToolInteractions) markToolInteractionsChanged();
|
|
436
|
-
if (removedToolApprovalResponse || removedHostApprovalId)
|
|
585
|
+
if (removedToolApprovalResponse || removedHostApprovalId) {
|
|
586
|
+
if (approvalOwner) notifyHostApprovals(approvalOwner);
|
|
587
|
+
setToolApprovalResponses(new Map(toolApprovalResponsesRef.current));
|
|
588
|
+
}
|
|
437
589
|
const deleteIds = new Set(getExternalStoreMessages(threadMessages[messageIndex]).map((message_6) => message_6.id));
|
|
438
590
|
chatHelpers.setMessages((current_3) => current_3.filter((message_7) => !deleteIds.has(message_7.id)));
|
|
439
591
|
},
|
|
@@ -443,34 +595,60 @@ const useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
443
595
|
chatHelpers.setMessages(newMessages);
|
|
444
596
|
await chatHelpers.regenerate({ metadata: config.runConfig });
|
|
445
597
|
},
|
|
446
|
-
onAddToolResult: ({ toolCallId, toolName, result: result_0, isError, artifact, modelContent }) => {
|
|
598
|
+
onAddToolResult: ({ messageId: messageId_1, toolCallId, toolName, result: result_0, isError, artifact, modelContent }) => {
|
|
447
599
|
if (artifact !== void 0) {
|
|
448
600
|
toolArtifactsRef.current.set(toolCallId, artifact);
|
|
449
601
|
markToolArtifactsChanged();
|
|
450
602
|
}
|
|
603
|
+
const targetIndex = findRawToolMessageIndex(chatHelpers.messages, messageId_1, toolCallId, joinStrategy);
|
|
604
|
+
const errorText = typeof result_0 === "string" ? result_0 : JSON.stringify(result_0);
|
|
605
|
+
const output = !isError && modelContent !== void 0 ? wrapModelContentEnvelope(result_0, modelContent) : result_0;
|
|
606
|
+
if (targetIndex >= 0 && targetIndex !== chatHelpers.messages.length - 1) {
|
|
607
|
+
const target = chatHelpers.messages[targetIndex];
|
|
608
|
+
const targetPart = target.parts.find((part_3) => isToolUIPart(part_3) && part_3.toolCallId === toolCallId);
|
|
609
|
+
if (targetPart?.state === "output-error" || targetPart?.state === "output-denied" || targetPart?.state === "output-available" && !targetPart.preliminary) return Promise.resolve();
|
|
610
|
+
const targetMessageId = target.id;
|
|
611
|
+
chatHelpers.setMessages((current_4) => current_4.map((message_8) => {
|
|
612
|
+
if (message_8.id !== targetMessageId) return message_8;
|
|
613
|
+
return {
|
|
614
|
+
...message_8,
|
|
615
|
+
parts: message_8.parts.map((part_4) => {
|
|
616
|
+
if (!isToolUIPart(part_4) || part_4.toolCallId !== toolCallId) return part_4;
|
|
617
|
+
const { preliminary: _preliminary, ...finalPart } = part_4;
|
|
618
|
+
return {
|
|
619
|
+
...finalPart,
|
|
620
|
+
state: isError ? "output-error" : "output-available",
|
|
621
|
+
output: isError ? void 0 : output,
|
|
622
|
+
errorText: isError ? errorText : void 0
|
|
623
|
+
};
|
|
624
|
+
})
|
|
625
|
+
};
|
|
626
|
+
}));
|
|
627
|
+
return Promise.resolve();
|
|
628
|
+
}
|
|
451
629
|
const options = { metadata: lastRunConfigRef.current };
|
|
452
630
|
if (isError) return Promise.resolve(chatHelpers.addToolOutput({
|
|
453
631
|
state: "output-error",
|
|
454
632
|
tool: toolName ?? toolCallId,
|
|
455
633
|
toolCallId,
|
|
456
|
-
errorText
|
|
634
|
+
errorText,
|
|
457
635
|
options
|
|
458
636
|
}));
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
637
|
+
return Promise.resolve(chatHelpers.addToolOutput({
|
|
638
|
+
tool: toolName,
|
|
639
|
+
toolCallId,
|
|
640
|
+
output,
|
|
641
|
+
options
|
|
642
|
+
}));
|
|
643
|
+
},
|
|
644
|
+
onRespondToToolApproval: (response_1) => {
|
|
645
|
+
if (supersededApprovalProjection.approvalIds.has(response_1.approvalId)) return Promise.reject(/* @__PURE__ */ new Error(`Tool approval ${response_1.approvalId} is not waiting for a response.`));
|
|
646
|
+
return customOnRespondToToolApproval ? respondViaHost(customOnRespondToToolApproval, response_1) : respondViaAISDK(response_1);
|
|
468
647
|
},
|
|
469
|
-
|
|
470
|
-
unstable_onRecordToolInteraction: ({ messageId: messageId_1, toolCallId: toolCallId_0, interaction }) => {
|
|
648
|
+
unstable_onRecordToolInteraction: ({ messageId: messageId_2, toolCallId: toolCallId_0, interaction }) => {
|
|
471
649
|
toolInteractionsRef.current.set(toolCallId_0, appendToolInteraction(toolInteractionsRef.current.get(toolCallId_0), interaction));
|
|
472
650
|
markToolInteractionsChanged();
|
|
473
|
-
return persistToolInteractions(
|
|
651
|
+
return persistToolInteractions(messageId_2);
|
|
474
652
|
},
|
|
475
653
|
...pickExternalStoreSharedOptions(adapter),
|
|
476
654
|
...adapter.unstable_messageRepositoryInstance && { unstable_messageRepositoryInstance: adapter.unstable_messageRepositoryInstance },
|