@tanstack/ai-client 0.23.3 → 0.25.1
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 +10 -1
- package/dist/esm/chat-client.d.ts +17 -13
- package/dist/esm/chat-client.js +49 -18
- package/dist/esm/chat-client.js.map +1 -1
- package/dist/esm/connection-adapters.d.ts +49 -0
- package/dist/esm/connection-adapters.js +269 -29
- package/dist/esm/connection-adapters.js.map +1 -1
- package/dist/esm/devtools.d.ts +0 -1
- package/dist/esm/devtools.js +4 -10
- package/dist/esm/devtools.js.map +1 -1
- package/dist/esm/generation-client.d.ts +5 -11
- package/dist/esm/generation-client.js +18 -5
- package/dist/esm/generation-client.js.map +1 -1
- package/dist/esm/generation-types.d.ts +15 -45
- package/dist/esm/generation-types.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/interrupt-manager.d.ts +15 -10
- package/dist/esm/interrupt-manager.js +176 -83
- package/dist/esm/interrupt-manager.js.map +1 -1
- package/dist/esm/types.d.ts +66 -48
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/video-generation-client.d.ts +5 -11
- package/dist/esm/video-generation-client.js +18 -5
- package/dist/esm/video-generation-client.js.map +1 -1
- package/package.json +3 -3
- package/src/chat-client.ts +148 -53
- package/src/connection-adapters.ts +505 -47
- package/src/devtools.ts +6 -22
- package/src/generation-client.ts +36 -24
- package/src/generation-types.ts +15 -47
- package/src/index.ts +6 -0
- package/src/interrupt-manager.ts +386 -145
- package/src/types.ts +133 -50
- package/src/video-generation-client.ts +33 -20
package/dist/esm/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type { McpAppBridge, CreateMcpAppBridgeOptions } from './mcp-app-bridge.j
|
|
|
8
8
|
export { RealtimeClient } from './realtime-client.js';
|
|
9
9
|
export { GenerationClient } from './generation-client.js';
|
|
10
10
|
export { VideoGenerationClient } from './video-generation-client.js';
|
|
11
|
-
export type { UIMessage, MessagePart, TextPart, ToolCallPart, ToolResultPart, ThinkingPart, StructuredOutputPart, ChatClientPersistence, ChatPersistedState, ChatPersistenceOption, ChatStorageAdapter, ChatClientOptions, ChatPendingInterrupt, BoundInterruptBase, BoundInterrupts, ChatInterrupt, ChatInterruptState, GenericAGUIInterrupt, UnboundInterrupt, InterruptItemStatus, ToolApprovalInterrupt, ClientContextOptionFromTools, ChatResumeState, ChatRequestBody, InferChatMessages, InferredClientContext, ChatClientState, ConnectionStatus, ChatFetcher, ChatFetcherInput, ChatFetcherOptions, ChatTransport, DistributedOmit, MultimodalContent, QueuedMessage, WhenBusy, QueueBusyReason, QueueConfig, QueueStrategy, QueueOption, SendMessageOptions, } from './types.js';
|
|
11
|
+
export type { UIMessage, MessagePart, TextPart, ToolCallPart, ToolResultPart, ThinkingPart, StructuredOutputPart, ChatClientPersistence, ChatPersistedState, ChatPersistenceOption, ChatPersistenceOptions, ChatStorageAdapter, ChatClientOptions, ChatPendingInterrupt, BoundInterruptBase, BoundInterrupts, ChatInterrupt, ChatInterruptState, GenericAGUIInterrupt, GenericInterrupt, RegisteredGenericInterrupt, ResolvableChatInterrupt, UnboundInterrupt, InterruptItemStatus, ToolApprovalInterrupt, ClientContextOptionFromTools, ChatResumeState, ChatRequestBody, InferChatMessages, InferredClientContext, ChatClientState, ConnectionStatus, ChatFetcher, ChatFetcherInput, ChatFetcherOptions, ChatTransport, DistributedOmit, MultimodalContent, QueuedMessage, WhenBusy, QueueBusyReason, QueueConfig, QueueStrategy, QueueOption, SendMessageOptions, } from './types.js';
|
|
12
12
|
export type { InferGenerationOutput, InferGenerationOutputFromReturn, GenerationClientState, GenerationPersistenceOptions, GenerationClientOptions, GenerationFetcher, GenerationFetcherOptions, GenerationTransport, VideoGenerationClientOptions, VideoStatusInfo, VideoGenerateResult, ImageGenerateInput, AudioGenerateInput, SpeechGenerateInput, TranscriptionGenerateInput, SummarizeGenerateInput, VideoGenerateInput, GenerationRestoredResult, } from './generation-types.js';
|
|
13
13
|
export { GENERATION_EVENTS } from './generation-types.js';
|
|
14
14
|
export { reconstructImageResult, reconstructAudioResult, reconstructSpeechResult, reconstructTranscriptionResult, reconstructSummarizeResult, } from './generation-reconstruct.js';
|
|
@@ -20,6 +20,6 @@ export { createAIDevtoolsGenerationPreview, type AIDevtoolsClientMetadata, type
|
|
|
20
20
|
export type { ExtractToolNames, ExtractToolInput, ExtractToolOutput, } from './tool-types.js';
|
|
21
21
|
export type { AnyClientTool, Interrupt, PersistedArtifactActivity, PersistedArtifactRef, PersistedArtifactRole, RunAgentResumeItem, RunFinishedOutcome, } from '@tanstack/ai/client';
|
|
22
22
|
export type { RealtimeAdapter, RealtimeConnection, RealtimeClientOptions, RealtimeClientState, RealtimeStateChangeCallback, } from './realtime-types.js';
|
|
23
|
-
export { fetchServerSentEvents, fetchHttpStream, xhrServerSentEvents, xhrHttpStream, stream, rpcStream, StreamTruncatedError, DurableStreamIncompleteError, StreamReconnectLimitError, type ConnectConnectionAdapter, type ConnectionAdapter, type GenerationHydrationResult, type FetchConnectionOptions, type ReconnectOptions, type ResumableConnectConnectionAdapter, type RunAgentInputContext, type StreamConnectionHandlers, type SubscribeConnectionAdapter, type XhrConnectionOptions, } from './connection-adapters.js';
|
|
23
|
+
export { fetchServerSentEvents, fetchHttpStream, xhrServerSentEvents, xhrHttpStream, stream, rpcStream, webSocket, StreamTruncatedError, DurableStreamIncompleteError, StreamReconnectLimitError, type ConnectConnectionAdapter, type ConnectionAdapter, type GenerationHydrationResult, type FetchConnectionOptions, type ReconnectOptions, type ResumableConnectConnectionAdapter, type RunAgentInputContext, type StreamConnectionHandlers, type SubscribeConnectionAdapter, type WebSocketConnectionOptions, type XhrConnectionOptions, } from './connection-adapters.js';
|
|
24
24
|
export { uiMessageToModelMessages, modelMessageToUIMessage, modelMessagesToUIMessages, convertMessagesToModelMessages, normalizeToUIMessage, generateMessageId, } from '@tanstack/ai/client';
|
|
25
25
|
export { StreamProcessor, ImmediateStrategy, PunctuationStrategy, BatchStrategy, WordBoundaryStrategy, CompositeStrategy, parsePartialJSON, PartialJSONParser, defaultJSONParser, type ChunkStrategy, type StreamProcessorOptions, type StreamProcessorEvents, type InternalToolCallState, type ToolCallState, type ToolResultState, type JSONParser, type ChunkRecording, type ProcessorResult, type ProcessorState, } from '@tanstack/ai/client';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AudioRecorder } from "./audio-recorder.js";
|
|
2
2
|
import { UnsupportedResponseStreamError } from "./response-stream.js";
|
|
3
|
-
import { DurableStreamIncompleteError, StreamReconnectLimitError, StreamTruncatedError, fetchHttpStream, fetchServerSentEvents, rpcStream, stream, xhrHttpStream, xhrServerSentEvents } from "./connection-adapters.js";
|
|
3
|
+
import { DurableStreamIncompleteError, StreamReconnectLimitError, StreamTruncatedError, fetchHttpStream, fetchServerSentEvents, rpcStream, stream, webSocket, xhrHttpStream, xhrServerSentEvents } from "./connection-adapters.js";
|
|
4
4
|
import { InterruptManager } from "./interrupt-manager.js";
|
|
5
5
|
import { ChatClient } from "./chat-client.js";
|
|
6
6
|
import { createMcpAppBridge } from "./mcp-app-bridge.js";
|
|
@@ -13,4 +13,4 @@ import { clientTools, createChatClientOptions } from "./types.js";
|
|
|
13
13
|
import { StorageUnavailableError, indexedDBPersistence, localStoragePersistence, sessionStoragePersistence } from "./storage-adapters.js";
|
|
14
14
|
import { createAIDevtoolsGenerationPreview } from "./devtools.js";
|
|
15
15
|
import { BatchStrategy, CompositeStrategy, ImmediateStrategy, PartialJSONParser, PunctuationStrategy, StreamProcessor, WordBoundaryStrategy, convertMessagesToModelMessages, defaultJSONParser, generateMessageId, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, parsePartialJSON, uiMessageToModelMessages } from "@tanstack/ai/client";
|
|
16
|
-
export { AudioRecorder, BatchStrategy, ChatClient, CompositeStrategy, DurableStreamIncompleteError, GENERATION_EVENTS, GenerationClient, ImmediateStrategy, InterruptManager, PartialJSONParser, PunctuationStrategy, RealtimeClient, StorageUnavailableError, StreamProcessor, StreamReconnectLimitError, StreamTruncatedError, UnsupportedResponseStreamError, VideoGenerationClient, WordBoundaryStrategy, clientTools, convertMessagesToModelMessages, createAIDevtoolsGenerationPreview, createChatClientOptions, createMcpAppBridge, defaultJSONParser, fetchHttpStream, fetchServerSentEvents, generateMessageId, indexedDBPersistence, localStoragePersistence, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, parsePartialJSON, reconstructAudioResult, reconstructImageResult, reconstructSpeechResult, reconstructSummarizeResult, reconstructTranscriptionResult, rpcStream, sessionStoragePersistence, stream, uiMessageToModelMessages, xhrHttpStream, xhrServerSentEvents };
|
|
16
|
+
export { AudioRecorder, BatchStrategy, ChatClient, CompositeStrategy, DurableStreamIncompleteError, GENERATION_EVENTS, GenerationClient, ImmediateStrategy, InterruptManager, PartialJSONParser, PunctuationStrategy, RealtimeClient, StorageUnavailableError, StreamProcessor, StreamReconnectLimitError, StreamTruncatedError, UnsupportedResponseStreamError, VideoGenerationClient, WordBoundaryStrategy, clientTools, convertMessagesToModelMessages, createAIDevtoolsGenerationPreview, createChatClientOptions, createMcpAppBridge, defaultJSONParser, fetchHttpStream, fetchServerSentEvents, generateMessageId, indexedDBPersistence, localStoragePersistence, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, parsePartialJSON, reconstructAudioResult, reconstructImageResult, reconstructSpeechResult, reconstructSummarizeResult, reconstructTranscriptionResult, rpcStream, sessionStoragePersistence, stream, uiMessageToModelMessages, webSocket, xhrHttpStream, xhrServerSentEvents };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AnyClientTool, BatchInterruptError, Interrupt, RunAgentResumeItem } from '@tanstack/ai/client';
|
|
2
|
-
import { BoundInterrupts,
|
|
1
|
+
import { AnyClientTool, BatchInterruptError, Interrupt, InterruptDefinition, RunAgentResumeItem } from '@tanstack/ai/client';
|
|
2
|
+
import { BoundInterrupts, ChatInterruptState, ResolvableChatInterrupt } from './types.js';
|
|
3
3
|
export interface InterruptManagerHydration {
|
|
4
4
|
threadId: string;
|
|
5
5
|
interruptedRunId: string;
|
|
@@ -14,12 +14,14 @@ export interface InterruptManagerSubmission {
|
|
|
14
14
|
canonicalResolutions: string;
|
|
15
15
|
fingerprint: string;
|
|
16
16
|
}
|
|
17
|
-
export
|
|
17
|
+
export type InterruptManagerChangeSource = 'hydrate' | 'live';
|
|
18
|
+
export interface InterruptManagerOptions<TTools extends ReadonlyArray<AnyClientTool>, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> {
|
|
18
19
|
tools?: TTools;
|
|
20
|
+
interrupts?: TInterrupts;
|
|
19
21
|
submit: (submission: InterruptManagerSubmission) => Promise<void>;
|
|
20
|
-
onChange?: () => void;
|
|
22
|
+
onChange?: (source: InterruptManagerChangeSource) => void;
|
|
21
23
|
}
|
|
22
|
-
export declare class InterruptManager<TTools extends ReadonlyArray<AnyClientTool> = ReadonlyArray<AnyClientTool>> {
|
|
24
|
+
export declare class InterruptManager<TTools extends ReadonlyArray<AnyClientTool> = ReadonlyArray<AnyClientTool>, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> {
|
|
23
25
|
private readonly options;
|
|
24
26
|
private hydration;
|
|
25
27
|
private items;
|
|
@@ -31,19 +33,22 @@ export declare class InterruptManager<TTools extends ReadonlyArray<AnyClientTool
|
|
|
31
33
|
private retrySubmission;
|
|
32
34
|
private resuming;
|
|
33
35
|
private tools;
|
|
34
|
-
|
|
36
|
+
private readonly interruptDefinitions;
|
|
37
|
+
constructor(options: InterruptManagerOptions<TTools, TInterrupts>);
|
|
35
38
|
updateTools(tools: TTools): void;
|
|
36
|
-
hydrate(hydration: InterruptManagerHydration): void;
|
|
37
|
-
getInterrupts(): BoundInterrupts<TTools>;
|
|
38
|
-
getState(): ChatInterruptState<TTools>;
|
|
39
|
+
hydrate(hydration: InterruptManagerHydration, source?: InterruptManagerChangeSource): void;
|
|
40
|
+
getInterrupts(): BoundInterrupts<TTools, TInterrupts>;
|
|
41
|
+
getState(): ChatInterruptState<TTools, TInterrupts>;
|
|
39
42
|
getDescriptors(): ReadonlyArray<Interrupt>;
|
|
43
|
+
hasValidatedFirstPartyGenericBatch(): boolean;
|
|
40
44
|
reset(options?: {
|
|
41
45
|
preserveRootErrors?: boolean;
|
|
46
|
+
source?: InterruptManagerChangeSource;
|
|
42
47
|
}): void;
|
|
43
48
|
getInterruptErrors(): ReadonlyArray<BatchInterruptError>;
|
|
44
49
|
getResuming(): boolean;
|
|
45
50
|
resolve(approved: boolean): void;
|
|
46
|
-
resolve(resolver: (interrupt:
|
|
51
|
+
resolve(resolver: (interrupt: ResolvableChatInterrupt<TTools, TInterrupts>) => undefined): void;
|
|
47
52
|
cancel(): void;
|
|
48
53
|
retry(): void;
|
|
49
54
|
resolveClientToolOutput(toolCallId: string, output: unknown): boolean;
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import { INTERRUPT_BINDING_METADATA_KEY, INTERRUPT_BINDING_VERSION, canonicalInterruptJson, canonicalizeInterruptResolutions, cloneAndDeepFreezeJson, digestInterruptJson, hashSchemaInput, isStandardSchema, normalizeApprovalSchema } from "@tanstack/ai/client";
|
|
1
|
+
import { INTERRUPT_BINDING_METADATA_KEY, INTERRUPT_BINDING_VERSION, canonicalInterruptJson, canonicalizeInterruptResolutions, cloneAndDeepFreezeJson, digestInterruptJson, genericInterruptContinuationFromDescriptor, hashInterruptDefinitionSchema, hashSchemaInput, isStandardSchema, normalizeApprovalSchema, readInterruptBinding, wrapGenericInterruptContinuation } from "@tanstack/ai/client";
|
|
2
2
|
//#region src/interrupt-manager.ts
|
|
3
|
+
function isClientOwnedInterrupt(item) {
|
|
4
|
+
return item.resumable;
|
|
5
|
+
}
|
|
6
|
+
function resolutionWithContinuation(item, resolution) {
|
|
7
|
+
const continuation = genericInterruptContinuationFromDescriptor(item.descriptor);
|
|
8
|
+
if (!continuation) return resolution;
|
|
9
|
+
return {
|
|
10
|
+
...resolution,
|
|
11
|
+
metadata: wrapGenericInterruptContinuation(continuation)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function isRootResolvableInterrupt(interrupt) {
|
|
15
|
+
return "cancel" in interrupt && "clearResolution" in interrupt;
|
|
16
|
+
}
|
|
3
17
|
var itemErrorCodes = /* @__PURE__ */ new Set([
|
|
4
18
|
"invalid-payload",
|
|
5
19
|
"invalid-edited-args",
|
|
@@ -45,51 +59,24 @@ function isLegacyClientToolMetadata(value) {
|
|
|
45
59
|
function isLegacyInterruptMetadata(interrupt) {
|
|
46
60
|
return isLegacyApprovalMetadata(interrupt.metadata) || isLegacyClientToolMetadata(interrupt.metadata);
|
|
47
61
|
}
|
|
48
|
-
function
|
|
49
|
-
return (
|
|
62
|
+
function getDescriptorBinding(interrupt) {
|
|
63
|
+
return readInterruptBinding(interrupt);
|
|
50
64
|
}
|
|
51
|
-
function
|
|
52
|
-
if (!isUnknownObject(
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
interruptId: String(value["interruptId"]),
|
|
58
|
-
interruptedRunId: String(value["interruptedRunId"]),
|
|
59
|
-
generation: Number(value["generation"]),
|
|
60
|
-
responseSchemaHash: String(value["responseSchemaHash"]),
|
|
61
|
-
...expiresAt !== void 0 ? { expiresAt } : {}
|
|
62
|
-
};
|
|
63
|
-
if (value["kind"] === "client-tool-execution" && typeof value["toolName"] === "string" && typeof value["toolCallId"] === "string" && typeof value["outputSchemaHash"] === "string") return {
|
|
64
|
-
v: INTERRUPT_BINDING_VERSION,
|
|
65
|
-
kind: "client-tool-execution",
|
|
66
|
-
interruptId: String(value["interruptId"]),
|
|
67
|
-
interruptedRunId: String(value["interruptedRunId"]),
|
|
68
|
-
generation: Number(value["generation"]),
|
|
69
|
-
toolName: value["toolName"],
|
|
70
|
-
toolCallId: value["toolCallId"],
|
|
71
|
-
outputSchemaHash: value["outputSchemaHash"],
|
|
72
|
-
responseSchemaHash: String(value["responseSchemaHash"]),
|
|
73
|
-
...expiresAt !== void 0 ? { expiresAt } : {}
|
|
74
|
-
};
|
|
75
|
-
if (value["kind"] === "tool-approval" && typeof value["toolName"] === "string" && typeof value["toolCallId"] === "string" && typeof value["inputSchemaHash"] === "string" && typeof value["approvalSchemaHash"] === "string" && "originalArgs" in value) return {
|
|
76
|
-
v: INTERRUPT_BINDING_VERSION,
|
|
77
|
-
kind: "tool-approval",
|
|
78
|
-
interruptId: String(value["interruptId"]),
|
|
79
|
-
interruptedRunId: String(value["interruptedRunId"]),
|
|
80
|
-
generation: Number(value["generation"]),
|
|
81
|
-
toolName: value["toolName"],
|
|
82
|
-
toolCallId: value["toolCallId"],
|
|
83
|
-
originalArgs: value["originalArgs"],
|
|
84
|
-
inputSchemaHash: value["inputSchemaHash"],
|
|
85
|
-
approvalSchemaHash: value["approvalSchemaHash"],
|
|
86
|
-
responseSchemaHash: String(value["responseSchemaHash"]),
|
|
87
|
-
...expiresAt !== void 0 ? { expiresAt } : {}
|
|
88
|
-
};
|
|
65
|
+
function hasReservedFirstPartyBindingMarker(interrupt) {
|
|
66
|
+
if (!isUnknownObject(interrupt.metadata)) return false;
|
|
67
|
+
const binding = interrupt.metadata[INTERRUPT_BINDING_METADATA_KEY];
|
|
68
|
+
if (!isUnknownObject(binding)) return false;
|
|
69
|
+
if (binding["v"] !== void 0 && binding["v"] !== INTERRUPT_BINDING_VERSION) return false;
|
|
70
|
+
return binding["kind"] === "generic" || binding["kind"] === "tool-approval" || binding["kind"] === "client-tool-execution" || "definitionId" in binding || "key" in binding || "batchIndex" in binding || "payloadSchemaHash" in binding;
|
|
89
71
|
}
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
72
|
+
function hasFirstPartyGenericMarker(interrupt) {
|
|
73
|
+
if (!isUnknownObject(interrupt.metadata)) return false;
|
|
74
|
+
const binding = interrupt.metadata[INTERRUPT_BINDING_METADATA_KEY];
|
|
75
|
+
if (!isUnknownObject(binding) || binding["kind"] !== "generic") return false;
|
|
76
|
+
return "definitionId" in binding || "key" in binding || "batchIndex" in binding || "payloadSchemaHash" in binding;
|
|
77
|
+
}
|
|
78
|
+
function getInterruptPayload(interrupt) {
|
|
79
|
+
return interrupt.metadata?.["tanstack:interruptPayload"];
|
|
93
80
|
}
|
|
94
81
|
/**
|
|
95
82
|
* Only used to route *legacy* (pre-binding) descriptors, which have no binding
|
|
@@ -106,6 +93,14 @@ function responseSchemaHash(interrupt) {
|
|
|
106
93
|
return;
|
|
107
94
|
}
|
|
108
95
|
}
|
|
96
|
+
function definitionSchemaHash(schema) {
|
|
97
|
+
if (schema === void 0) return void 0;
|
|
98
|
+
try {
|
|
99
|
+
return hashInterruptDefinitionSchema(schema);
|
|
100
|
+
} catch {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
109
104
|
function isPromiseLike(value) {
|
|
110
105
|
return value !== null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
111
106
|
}
|
|
@@ -179,17 +174,18 @@ function submissionErrorMatchesActiveBatch(error, submission) {
|
|
|
179
174
|
return error.scope === "item" ? interruptIds.includes(error.interruptId) : haveSameInterruptIds(error.interruptIds, interruptIds);
|
|
180
175
|
}
|
|
181
176
|
function genericBinding(interrupt, hydration, candidate) {
|
|
177
|
+
const schemaHash = responseSchemaHash(interrupt) ?? candidate?.responseSchemaHash;
|
|
182
178
|
return cloneAndDeepFreezeJson({
|
|
183
179
|
v: INTERRUPT_BINDING_VERSION,
|
|
184
180
|
kind: "generic",
|
|
185
181
|
interruptId: interrupt.id,
|
|
186
182
|
interruptedRunId: hydration.interruptedRunId,
|
|
187
183
|
generation: hydration.generation,
|
|
188
|
-
responseSchemaHash:
|
|
184
|
+
...schemaHash !== void 0 ? { responseSchemaHash: schemaHash } : {},
|
|
189
185
|
...interrupt.expiresAt !== void 0 ? { expiresAt: interrupt.expiresAt } : {}
|
|
190
186
|
});
|
|
191
187
|
}
|
|
192
|
-
function baseSnapshot(item, hydration
|
|
188
|
+
function baseSnapshot(item, hydration) {
|
|
193
189
|
const descriptor = cloneAndDeepFreezeJson(item.descriptor);
|
|
194
190
|
const errors = item.error === void 0 ? Object.freeze([]) : Object.freeze([cloneAndDeepFreezeJson(item.error)]);
|
|
195
191
|
const error = errors[0];
|
|
@@ -207,9 +203,7 @@ function baseSnapshot(item, hydration, cancel, clearResolution) {
|
|
|
207
203
|
status: item.status,
|
|
208
204
|
errors,
|
|
209
205
|
...error !== void 0 ? { error } : {},
|
|
210
|
-
canResolve: item.canResolve
|
|
211
|
-
cancel,
|
|
212
|
-
clearResolution
|
|
206
|
+
canResolve: item.canResolve
|
|
213
207
|
};
|
|
214
208
|
}
|
|
215
209
|
var InterruptManager = class {
|
|
@@ -229,26 +223,38 @@ var InterruptManager = class {
|
|
|
229
223
|
retrySubmission;
|
|
230
224
|
resuming = false;
|
|
231
225
|
tools;
|
|
226
|
+
interruptDefinitions;
|
|
232
227
|
constructor(options) {
|
|
233
228
|
this.options = options;
|
|
234
229
|
this.tools = options.tools;
|
|
230
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
231
|
+
for (const definition of options.interrupts ?? []) {
|
|
232
|
+
if (definitions.has(definition.id)) throw new Error(`Duplicate interrupt definition id: ${definition.id}`);
|
|
233
|
+
definitions.set(definition.id, definition);
|
|
234
|
+
}
|
|
235
|
+
this.interruptDefinitions = definitions;
|
|
235
236
|
}
|
|
236
237
|
updateTools(tools) {
|
|
237
238
|
this.tools = tools;
|
|
238
239
|
}
|
|
239
|
-
hydrate(hydration) {
|
|
240
|
+
hydrate(hydration, source = "live") {
|
|
240
241
|
this.hydration = {
|
|
241
242
|
threadId: hydration.threadId,
|
|
242
243
|
interruptedRunId: hydration.interruptedRunId,
|
|
243
244
|
generation: hydration.generation,
|
|
244
245
|
interrupts: cloneAndDeepFreezeJson(hydration.interrupts)
|
|
245
246
|
};
|
|
246
|
-
|
|
247
|
+
const firstPartyIndexes = /* @__PURE__ */ new Map();
|
|
248
|
+
for (const interrupt of hydration.interrupts) {
|
|
249
|
+
const binding = getDescriptorBinding(interrupt);
|
|
250
|
+
if (binding?.kind === "generic" && binding.definitionId !== void 0 && binding.key !== void 0 && binding.batchIndex !== void 0) firstPartyIndexes.set(binding.batchIndex, (firstPartyIndexes.get(binding.batchIndex) ?? 0) + 1);
|
|
251
|
+
}
|
|
252
|
+
this.items = hydration.interrupts.map((interrupt) => this.hydrateInterrupt(interrupt, hydration, firstPartyIndexes));
|
|
247
253
|
this.rootErrors = Object.freeze([]);
|
|
248
254
|
this.submissionRootErrors = Object.freeze([]);
|
|
249
255
|
this.retrySubmission = void 0;
|
|
250
256
|
this.resuming = false;
|
|
251
|
-
this.publish();
|
|
257
|
+
this.publish(source);
|
|
252
258
|
}
|
|
253
259
|
getInterrupts() {
|
|
254
260
|
return this.snapshot;
|
|
@@ -259,6 +265,9 @@ var InterruptManager = class {
|
|
|
259
265
|
getDescriptors() {
|
|
260
266
|
return this.hydration?.interrupts ?? Object.freeze([]);
|
|
261
267
|
}
|
|
268
|
+
hasValidatedFirstPartyGenericBatch() {
|
|
269
|
+
return this.items.some((item) => item.kind === "generic" && item.definition !== void 0);
|
|
270
|
+
}
|
|
262
271
|
reset(options) {
|
|
263
272
|
this.hydration = void 0;
|
|
264
273
|
this.items = [];
|
|
@@ -275,7 +284,7 @@ var InterruptManager = class {
|
|
|
275
284
|
interruptErrors: this.rootErrors,
|
|
276
285
|
resuming: false
|
|
277
286
|
});
|
|
278
|
-
this.options.onChange?.();
|
|
287
|
+
this.options.onChange?.(options?.source ?? "live");
|
|
279
288
|
}
|
|
280
289
|
getInterruptErrors() {
|
|
281
290
|
return this.rootErrors;
|
|
@@ -295,11 +304,12 @@ var InterruptManager = class {
|
|
|
295
304
|
this.assertRootMutable();
|
|
296
305
|
this.invalidateRetry();
|
|
297
306
|
for (const item of this.items) {
|
|
307
|
+
if (!isClientOwnedInterrupt(item)) continue;
|
|
298
308
|
item.validationGeneration++;
|
|
299
|
-
item.resolution = Object.freeze({
|
|
309
|
+
item.resolution = Object.freeze(resolutionWithContinuation(item, {
|
|
300
310
|
interruptId: item.descriptor.id,
|
|
301
311
|
status: "cancelled"
|
|
302
|
-
});
|
|
312
|
+
}));
|
|
303
313
|
item.status = "staged";
|
|
304
314
|
item.error = void 0;
|
|
305
315
|
}
|
|
@@ -327,19 +337,44 @@ var InterruptManager = class {
|
|
|
327
337
|
this.resolveItem(item.descriptor.id, { approved });
|
|
328
338
|
return true;
|
|
329
339
|
}
|
|
330
|
-
hydrateInterrupt(descriptor, hydration) {
|
|
340
|
+
hydrateInterrupt(descriptor, hydration, firstPartyIndexes) {
|
|
331
341
|
const interrupt = cloneAndDeepFreezeJson(descriptor);
|
|
332
342
|
const candidate = getDescriptorBinding(interrupt);
|
|
333
|
-
|
|
343
|
+
const legacyResumable = candidate === void 0 && isLegacyInterruptMetadata(interrupt);
|
|
344
|
+
if (candidate === void 0 && !legacyResumable) {
|
|
345
|
+
if (hasReservedFirstPartyBindingMarker(interrupt)) return {
|
|
346
|
+
descriptor: interrupt,
|
|
347
|
+
binding: genericBinding(interrupt, hydration, void 0),
|
|
348
|
+
kind: "generic",
|
|
349
|
+
status: "error",
|
|
350
|
+
canResolve: false,
|
|
351
|
+
resumable: false,
|
|
352
|
+
error: this.itemError(interrupt.id, "stale", "The interrupt binding is invalid or incomplete."),
|
|
353
|
+
validationGeneration: 0
|
|
354
|
+
};
|
|
355
|
+
return {
|
|
356
|
+
descriptor: interrupt,
|
|
357
|
+
binding: void 0,
|
|
358
|
+
kind: "unbound",
|
|
359
|
+
status: "pending",
|
|
360
|
+
canResolve: false,
|
|
361
|
+
resumable: false,
|
|
362
|
+
validationGeneration: 0
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
const correlated = candidate !== void 0 && candidate.interruptId === interrupt.id && candidate.interruptedRunId === hydration.interruptedRunId && candidate.generation === hydration.generation && responseSchemaHash(interrupt) === candidate.responseSchemaHash;
|
|
366
|
+
const structurallyCorrelated = candidate !== void 0 && candidate.interruptId === interrupt.id && candidate.interruptedRunId === hydration.interruptedRunId && candidate.generation === hydration.generation && candidate.responseSchemaHash === (responseSchemaHash(interrupt) ?? candidate.responseSchemaHash);
|
|
367
|
+
if (candidate !== void 0 && hasFirstPartyGenericMarker(interrupt) && (!structurallyCorrelated || candidate.kind !== "generic" || candidate.definitionId === void 0 || candidate.key === void 0 || candidate.batchIndex === void 0)) return {
|
|
334
368
|
descriptor: interrupt,
|
|
335
|
-
binding:
|
|
336
|
-
kind: "
|
|
337
|
-
status: "
|
|
369
|
+
binding: genericBinding(interrupt, hydration, candidate),
|
|
370
|
+
kind: "generic",
|
|
371
|
+
status: "error",
|
|
338
372
|
canResolve: false,
|
|
373
|
+
resumable: false,
|
|
374
|
+
error: this.itemError(interrupt.id, "stale", "The interrupt binding does not match this interrupted run."),
|
|
339
375
|
validationGeneration: 0
|
|
340
376
|
};
|
|
341
|
-
|
|
342
|
-
if (correlated && candidate.kind === "tool-approval") {
|
|
377
|
+
if (structurallyCorrelated && candidate.kind === "tool-approval") {
|
|
343
378
|
const tool = this.tools?.find((configured) => configured.name === candidate.toolName);
|
|
344
379
|
if (tool?.needsApproval === true && interrupt.toolCallId === candidate.toolCallId) try {
|
|
345
380
|
const approval = normalizeApprovalSchema(tool.approvalSchema, tool.inputSchema);
|
|
@@ -349,12 +384,13 @@ var InterruptManager = class {
|
|
|
349
384
|
kind: "tool-approval",
|
|
350
385
|
status: "pending",
|
|
351
386
|
canResolve: true,
|
|
387
|
+
resumable: true,
|
|
352
388
|
tool,
|
|
353
389
|
validationGeneration: 0
|
|
354
390
|
};
|
|
355
391
|
} catch {}
|
|
356
392
|
}
|
|
357
|
-
if (
|
|
393
|
+
if (structurallyCorrelated && candidate.kind === "client-tool-execution") {
|
|
358
394
|
const tool = this.tools?.find((configured) => configured.name === candidate.toolName);
|
|
359
395
|
if (tool !== void 0 && interrupt.toolCallId === candidate.toolCallId && hashSchemaInput(tool.outputSchema) === candidate.outputSchemaHash) return {
|
|
360
396
|
descriptor: interrupt,
|
|
@@ -362,23 +398,53 @@ var InterruptManager = class {
|
|
|
362
398
|
kind: "client-tool-execution",
|
|
363
399
|
status: "pending",
|
|
364
400
|
canResolve: true,
|
|
401
|
+
resumable: true,
|
|
365
402
|
tool,
|
|
366
403
|
validationGeneration: 0
|
|
367
404
|
};
|
|
368
405
|
}
|
|
406
|
+
if (candidate !== void 0 && candidate.kind === "generic" && candidate.definitionId !== void 0 && candidate.key !== void 0 && candidate.batchIndex !== void 0 && candidate.key.length > 0 && firstPartyIndexes.get(candidate.batchIndex) !== 1) return {
|
|
407
|
+
descriptor: interrupt,
|
|
408
|
+
binding: cloneAndDeepFreezeJson(candidate),
|
|
409
|
+
kind: "generic",
|
|
410
|
+
status: "error",
|
|
411
|
+
canResolve: false,
|
|
412
|
+
resumable: false,
|
|
413
|
+
error: this.itemError(interrupt.id, "stale", "Generic interrupt batch contains a duplicate batchIndex."),
|
|
414
|
+
validationGeneration: 0
|
|
415
|
+
};
|
|
416
|
+
if (correlated && candidate.kind === "generic" && candidate.definitionId !== void 0 && candidate.key !== void 0 && candidate.batchIndex !== void 0 && candidate.key.length > 0 && firstPartyIndexes.get(candidate.batchIndex) === 1) {
|
|
417
|
+
const definition = this.interruptDefinitions.get(candidate.definitionId);
|
|
418
|
+
if (definition !== void 0 && definitionSchemaHash(definition.responseSchema) === candidate.responseSchemaHash && (definition.payloadSchema === void 0 ? candidate.payloadSchemaHash === void 0 : candidate.payloadSchemaHash === definitionSchemaHash(definition.payloadSchema))) {
|
|
419
|
+
const rawPayload = getInterruptPayload(interrupt);
|
|
420
|
+
return {
|
|
421
|
+
descriptor: interrupt,
|
|
422
|
+
binding: cloneAndDeepFreezeJson(candidate),
|
|
423
|
+
definition,
|
|
424
|
+
kind: "generic",
|
|
425
|
+
status: "pending",
|
|
426
|
+
canResolve: true,
|
|
427
|
+
resumable: true,
|
|
428
|
+
...rawPayload === void 0 ? {} : { payload: cloneAndDeepFreezeJson(rawPayload) },
|
|
429
|
+
validationGeneration: 0
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const resumable = legacyResumable || candidate !== void 0 && candidate.interruptId === interrupt.id && candidate.interruptedRunId === hydration.interruptedRunId && candidate.generation === hydration.generation && (candidate.kind !== "generic" || responseSchemaHash(interrupt) === void 0 || candidate.responseSchemaHash === responseSchemaHash(interrupt));
|
|
369
434
|
return {
|
|
370
435
|
descriptor: interrupt,
|
|
371
436
|
binding: genericBinding(interrupt, hydration, candidate),
|
|
372
437
|
kind: "generic",
|
|
373
438
|
status: "pending",
|
|
374
|
-
canResolve:
|
|
439
|
+
canResolve: resumable,
|
|
440
|
+
resumable,
|
|
375
441
|
validationGeneration: 0
|
|
376
442
|
};
|
|
377
443
|
}
|
|
378
444
|
buildSnapshot(transaction) {
|
|
379
445
|
const hydration = this.requireHydration();
|
|
380
446
|
const next = this.items.filter((item) => item.kind !== "client-tool-execution" && item.status !== "submitting").map((item) => {
|
|
381
|
-
const base = baseSnapshot(item, hydration
|
|
447
|
+
const base = baseSnapshot(item, hydration);
|
|
382
448
|
if (item.kind === "unbound" || item.binding === void 0) {
|
|
383
449
|
const snapshot = {
|
|
384
450
|
...base,
|
|
@@ -396,6 +462,8 @@ var InterruptManager = class {
|
|
|
396
462
|
toolName: item.binding.toolName,
|
|
397
463
|
toolCallId: item.binding.toolCallId,
|
|
398
464
|
originalArgs: cloneAndDeepFreezeJson(item.binding.originalArgs),
|
|
465
|
+
cancel: () => this.cancelItem(item.descriptor.id, transaction),
|
|
466
|
+
clearResolution: () => this.clearItem(item.descriptor.id, transaction),
|
|
399
467
|
resolveInterrupt: (approved, options) => {
|
|
400
468
|
const details = isUnknownObject(options) ? options : void 0;
|
|
401
469
|
this.resolveItem(item.descriptor.id, {
|
|
@@ -413,19 +481,35 @@ var InterruptManager = class {
|
|
|
413
481
|
interruptId: item.descriptor.id,
|
|
414
482
|
interruptedRunId: hydration.interruptedRunId,
|
|
415
483
|
generation: hydration.generation,
|
|
416
|
-
|
|
484
|
+
...typeof item.binding.responseSchemaHash === "string" ? { responseSchemaHash: item.binding.responseSchemaHash } : {}
|
|
417
485
|
});
|
|
486
|
+
if (item.definition !== void 0 && item.binding.kind === "generic") {
|
|
487
|
+
const snapshot = {
|
|
488
|
+
...base,
|
|
489
|
+
kind: "generic",
|
|
490
|
+
definitionId: item.definition.id,
|
|
491
|
+
key: item.binding.key ?? "",
|
|
492
|
+
payload: item.payload,
|
|
493
|
+
binding: boundGeneric,
|
|
494
|
+
cancel: () => this.cancelItem(item.descriptor.id, transaction),
|
|
495
|
+
clearResolution: () => this.clearItem(item.descriptor.id, transaction),
|
|
496
|
+
resolveInterrupt: (response) => this.resolveItem(item.descriptor.id, response, transaction)
|
|
497
|
+
};
|
|
498
|
+
return Object.freeze(snapshot);
|
|
499
|
+
}
|
|
418
500
|
const snapshot = {
|
|
419
501
|
...base,
|
|
420
502
|
kind: "generic",
|
|
421
503
|
binding: boundGeneric,
|
|
504
|
+
cancel: () => this.cancelItem(item.descriptor.id, transaction),
|
|
505
|
+
clearResolution: () => this.clearItem(item.descriptor.id, transaction),
|
|
422
506
|
resolveInterrupt: (payload) => this.resolveItem(item.descriptor.id, payload, transaction)
|
|
423
507
|
};
|
|
424
508
|
return Object.freeze(snapshot);
|
|
425
509
|
});
|
|
426
510
|
return Object.freeze(next);
|
|
427
511
|
}
|
|
428
|
-
publish() {
|
|
512
|
+
publish(source = "live") {
|
|
429
513
|
if (!this.hydration) {
|
|
430
514
|
this.snapshot = Object.freeze([]);
|
|
431
515
|
this.state = Object.freeze({
|
|
@@ -434,7 +518,7 @@ var InterruptManager = class {
|
|
|
434
518
|
interruptErrors: this.rootErrors,
|
|
435
519
|
resuming: this.resuming
|
|
436
520
|
});
|
|
437
|
-
this.options.onChange?.();
|
|
521
|
+
this.options.onChange?.(source);
|
|
438
522
|
return;
|
|
439
523
|
}
|
|
440
524
|
this.snapshot = this.buildSnapshot();
|
|
@@ -444,7 +528,7 @@ var InterruptManager = class {
|
|
|
444
528
|
interruptErrors: this.rootErrors,
|
|
445
529
|
resuming: this.resuming
|
|
446
530
|
});
|
|
447
|
-
this.options.onChange?.();
|
|
531
|
+
this.options.onChange?.(source);
|
|
448
532
|
}
|
|
449
533
|
resolveItem(interruptId, payload, transaction) {
|
|
450
534
|
this.assertItemMutable(transaction);
|
|
@@ -481,10 +565,10 @@ var InterruptManager = class {
|
|
|
481
565
|
const item = this.findItem(interruptId);
|
|
482
566
|
this.invalidateRetry();
|
|
483
567
|
item.validationGeneration++;
|
|
484
|
-
item.resolution = Object.freeze({
|
|
568
|
+
item.resolution = Object.freeze(resolutionWithContinuation(item, {
|
|
485
569
|
interruptId,
|
|
486
570
|
status: "cancelled"
|
|
487
|
-
});
|
|
571
|
+
}));
|
|
488
572
|
item.status = "staged";
|
|
489
573
|
item.error = void 0;
|
|
490
574
|
if (!transaction) {
|
|
@@ -503,7 +587,8 @@ var InterruptManager = class {
|
|
|
503
587
|
if (!transaction) this.publish();
|
|
504
588
|
}
|
|
505
589
|
maybeSubmit() {
|
|
506
|
-
const
|
|
590
|
+
const hasGeneric = this.items.some((item) => item.kind === "generic");
|
|
591
|
+
const ours = this.items.filter((item) => isClientOwnedInterrupt(item) && !(hasGeneric && item.kind === "client-tool-execution"));
|
|
507
592
|
if (ours.length === 0 || ours.some((item) => item.resolution === void 0 || item.status !== "staged")) return;
|
|
508
593
|
const hydration = this.requireHydration();
|
|
509
594
|
const canonical = canonicalizeInterruptResolutions(ours.map((item) => item.resolution).filter((item) => item !== void 0));
|
|
@@ -536,11 +621,11 @@ var InterruptManager = class {
|
|
|
536
621
|
if (!transaction) this.publish();
|
|
537
622
|
return;
|
|
538
623
|
}
|
|
539
|
-
item.resolution = cloneAndDeepFreezeJson({
|
|
624
|
+
item.resolution = cloneAndDeepFreezeJson(resolutionWithContinuation(item, {
|
|
540
625
|
interruptId: item.descriptor.id,
|
|
541
626
|
status: "resolved",
|
|
542
627
|
payload: result.payload
|
|
543
|
-
});
|
|
628
|
+
}));
|
|
544
629
|
item.status = "staged";
|
|
545
630
|
item.error = void 0;
|
|
546
631
|
if (!transaction) {
|
|
@@ -549,7 +634,15 @@ var InterruptManager = class {
|
|
|
549
634
|
}
|
|
550
635
|
}
|
|
551
636
|
validateCandidate(item, payload) {
|
|
552
|
-
if (item.kind === "generic")
|
|
637
|
+
if (item.kind === "generic") {
|
|
638
|
+
const validation = validateWithSchema(item.definition?.responseSchema ?? item.descriptor.responseSchema, payload, "invalid-payload");
|
|
639
|
+
if (item.definition === void 0) return validation;
|
|
640
|
+
const preserveInput = (result) => "valid" in result ? {
|
|
641
|
+
valid: true,
|
|
642
|
+
payload
|
|
643
|
+
} : result;
|
|
644
|
+
return isPromiseLike(validation) ? Promise.resolve(validation).then(preserveInput) : preserveInput(validation);
|
|
645
|
+
}
|
|
553
646
|
if (item.kind === "client-tool-execution") return validateWithSchema(item.tool?.outputSchema, payload, "invalid-tool-output");
|
|
554
647
|
return this.validateApprovalCandidate(item, payload);
|
|
555
648
|
}
|
|
@@ -608,7 +701,7 @@ var InterruptManager = class {
|
|
|
608
701
|
return item.kind === "client-tool-execution" ? "invalid-tool-output" : "invalid-payload";
|
|
609
702
|
}
|
|
610
703
|
resolveBooleanBulk(approved) {
|
|
611
|
-
const resolvable = this.items.filter((item) => item.kind !== "client-tool-execution");
|
|
704
|
+
const resolvable = this.items.filter((item) => isClientOwnedInterrupt(item) && item.kind !== "client-tool-execution");
|
|
612
705
|
if (!resolvable.every((item) => item.kind === "tool-approval" && this.approvalBranchSchema(item.tool, approved) === void 0) || resolvable.length === 0) {
|
|
613
706
|
this.addRootError("unsupported-bulk-operation", "Boolean bulk resolution requires payloadless tool approvals.", false);
|
|
614
707
|
return;
|
|
@@ -636,7 +729,7 @@ var InterruptManager = class {
|
|
|
636
729
|
}));
|
|
637
730
|
const token = { active: true };
|
|
638
731
|
this.activeTransaction = token;
|
|
639
|
-
const stable = this.buildSnapshot(token);
|
|
732
|
+
const stable = this.buildSnapshot(token).filter(isRootResolvableInterrupt);
|
|
640
733
|
let failure;
|
|
641
734
|
try {
|
|
642
735
|
for (const interrupt of stable) {
|
|
@@ -649,7 +742,7 @@ var InterruptManager = class {
|
|
|
649
742
|
break;
|
|
650
743
|
}
|
|
651
744
|
}
|
|
652
|
-
if (failure === void 0 && this.items.some((item) => item.kind !== "client-tool-execution" && (item.resolution === void 0 || item.status !== "staged"))) failure = {
|
|
745
|
+
if (failure === void 0 && this.items.some((item) => isClientOwnedInterrupt(item) && item.kind !== "client-tool-execution" && (item.resolution === void 0 || item.status !== "staged"))) failure = {
|
|
653
746
|
code: "incomplete-batch",
|
|
654
747
|
message: "Interrupt transaction did not resolve every item."
|
|
655
748
|
};
|
|
@@ -696,7 +789,7 @@ var InterruptManager = class {
|
|
|
696
789
|
submitBatch(submission) {
|
|
697
790
|
this.resuming = true;
|
|
698
791
|
this.retrySubmission = void 0;
|
|
699
|
-
for (const item of this.items) item.status = "submitting";
|
|
792
|
+
for (const item of this.items) if (isClientOwnedInterrupt(item)) item.status = "submitting";
|
|
700
793
|
this.publish();
|
|
701
794
|
this.performSubmission(submission);
|
|
702
795
|
}
|
|
@@ -716,7 +809,7 @@ var InterruptManager = class {
|
|
|
716
809
|
const message = error instanceof Error ? error.message : String(error);
|
|
717
810
|
this.addRootError("transport", message, true, "transport");
|
|
718
811
|
this.retrySubmission = submission;
|
|
719
|
-
for (const item of this.items) item.status = "error";
|
|
812
|
+
for (const item of this.items) if (isClientOwnedInterrupt(item)) item.status = "error";
|
|
720
813
|
return;
|
|
721
814
|
}
|
|
722
815
|
const correlatedErrors = errors.filter((submissionError) => submissionErrorMatchesActiveBatch(submissionError, submission));
|
|
@@ -728,7 +821,7 @@ var InterruptManager = class {
|
|
|
728
821
|
if (submissionError.code === "stale" || submissionError.code === "expired" || submissionError.code === "conflict") nonRetryable = true;
|
|
729
822
|
retryable ||= submissionError.retryable;
|
|
730
823
|
if (submissionError.scope === "item") {
|
|
731
|
-
const item = this.items.find((candidate) => candidate.descriptor.id === submissionError.interruptId);
|
|
824
|
+
const item = this.items.find((candidate) => isClientOwnedInterrupt(candidate) && candidate.descriptor.id === submissionError.interruptId);
|
|
732
825
|
if (item) {
|
|
733
826
|
item.status = "error";
|
|
734
827
|
item.error = cloneAndDeepFreezeJson(submissionError);
|
|
@@ -738,7 +831,7 @@ var InterruptManager = class {
|
|
|
738
831
|
const mergedBatchErrors = mergeSubmissionBatchErrors(this.rootErrors, this.submissionRootErrors, batchErrors);
|
|
739
832
|
this.rootErrors = mergedBatchErrors.rootErrors;
|
|
740
833
|
this.submissionRootErrors = mergedBatchErrors.submissionRootErrors;
|
|
741
|
-
for (const item of this.items) if (item.status === "submitting") item.status = "error";
|
|
834
|
+
for (const item of this.items) if (isClientOwnedInterrupt(item) && item.status === "submitting") item.status = "error";
|
|
742
835
|
this.retrySubmission = retryable && !nonRetryable ? submission : void 0;
|
|
743
836
|
}
|
|
744
837
|
addRootError(code, message, retryable, source = "client") {
|
|
@@ -749,7 +842,7 @@ var InterruptManager = class {
|
|
|
749
842
|
message,
|
|
750
843
|
source,
|
|
751
844
|
retryable,
|
|
752
|
-
interruptIds: Object.freeze(this.items.map((item) => item.descriptor.id)),
|
|
845
|
+
interruptIds: Object.freeze(this.items.filter(isClientOwnedInterrupt).map((item) => item.descriptor.id)),
|
|
753
846
|
threadId: hydration.threadId,
|
|
754
847
|
interruptedRunId: hydration.interruptedRunId,
|
|
755
848
|
generation: hydration.generation
|