@tanstack/ai 0.42.0 → 0.43.0
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 +15 -1
- package/dist/esm/activities/chat/adapter.js +23 -16
- package/dist/esm/activities/chat/adapter.js.map +1 -1
- package/dist/esm/activities/chat/agent-loop-strategies.d.ts +5 -36
- package/dist/esm/activities/chat/agent-loop-strategies.js +75 -21
- package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -1
- package/dist/esm/activities/chat/cancel.d.ts +40 -0
- package/dist/esm/activities/chat/cancel.js +54 -0
- package/dist/esm/activities/chat/cancel.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +28 -21
- package/dist/esm/activities/chat/index.js +2100 -1813
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/mcp/manager.d.ts +2 -2
- package/dist/esm/activities/chat/mcp/manager.js +90 -77
- package/dist/esm/activities/chat/mcp/manager.js.map +1 -1
- package/dist/esm/activities/chat/mcp/types.d.ts +2 -2
- package/dist/esm/activities/chat/messages.js +397 -346
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/middleware/builder.js +17 -15
- package/dist/esm/activities/chat/middleware/builder.js.map +1 -1
- package/dist/esm/activities/chat/middleware/capabilities.js +78 -43
- package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -1
- package/dist/esm/activities/chat/middleware/compose.d.ts +94 -1
- package/dist/esm/activities/chat/middleware/compose.js +623 -531
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
- package/dist/esm/activities/chat/middleware/define.js +12 -5
- package/dist/esm/activities/chat/middleware/define.js.map +1 -1
- package/dist/esm/activities/chat/middleware/index.d.ts +5 -1
- package/dist/esm/activities/chat/middleware/locks.d.ts +50 -0
- package/dist/esm/activities/chat/middleware/locks.js +71 -0
- package/dist/esm/activities/chat/middleware/locks.js.map +1 -0
- package/dist/esm/activities/chat/middleware/pending-turn.d.ts +15 -0
- package/dist/esm/activities/chat/middleware/pending-turn.js +35 -0
- package/dist/esm/activities/chat/middleware/pending-turn.js.map +1 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.d.ts +23 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.js +42 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.js.map +1 -0
- package/dist/esm/activities/chat/middleware/run-store.d.ts +283 -0
- package/dist/esm/activities/chat/middleware/run-store.js +176 -0
- package/dist/esm/activities/chat/middleware/run-store.js.map +1 -0
- package/dist/esm/activities/chat/middleware/sandbox-runtime.js +14 -8
- package/dist/esm/activities/chat/middleware/sandbox-runtime.js.map +1 -1
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +79 -70
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +59 -2
- package/dist/esm/activities/chat/middleware/validate.js +23 -28
- package/dist/esm/activities/chat/middleware/validate.js.map +1 -1
- package/dist/esm/activities/chat/stream/json-parser.js +39 -25
- package/dist/esm/activities/chat/stream/json-parser.js.map +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.js +275 -234
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +24 -4
- package/dist/esm/activities/chat/stream/processor.js +1341 -1542
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/stream/strategies.js +69 -53
- package/dist/esm/activities/chat/stream/strategies.js.map +1 -1
- package/dist/esm/activities/chat/tools/approval-schema.d.ts +19 -0
- package/dist/esm/activities/chat/tools/approval-schema.js +117 -0
- package/dist/esm/activities/chat/tools/approval-schema.js.map +1 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js +164 -191
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
- package/dist/esm/activities/chat/tools/lazy-tools.js +24 -12
- package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -1
- package/dist/esm/activities/chat/tools/schema-converter.js +293 -146
- package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +18 -2
- package/dist/esm/activities/chat/tools/tool-calls.js +522 -531
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +75 -16
- package/dist/esm/activities/chat/tools/tool-definition.js +95 -23
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/activities/error-payload.js +85 -47
- package/dist/esm/activities/error-payload.js.map +1 -1
- package/dist/esm/activities/generateAudio/adapter.js +22 -15
- package/dist/esm/activities/generateAudio/adapter.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.d.ts +4 -0
- package/dist/esm/activities/generateAudio/index.js +141 -105
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateImage/adapter.js +22 -15
- package/dist/esm/activities/generateImage/adapter.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +4 -0
- package/dist/esm/activities/generateImage/index.js +155 -111
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/adapter.js +22 -15
- package/dist/esm/activities/generateSpeech/adapter.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +4 -0
- package/dist/esm/activities/generateSpeech/index.js +159 -110
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/adapter.js +22 -15
- package/dist/esm/activities/generateTranscription/adapter.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +4 -0
- package/dist/esm/activities/generateTranscription/index.js +159 -100
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/adapter.js +36 -29
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +143 -19
- package/dist/esm/activities/generateVideo/index.js +456 -279
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/snap.js +60 -48
- package/dist/esm/activities/generateVideo/snap.js.map +1 -1
- package/dist/esm/activities/index.js +8 -34
- package/dist/esm/activities/middleware/index.d.ts +1 -1
- package/dist/esm/activities/middleware/run.d.ts +10 -0
- package/dist/esm/activities/middleware/run.js +53 -29
- package/dist/esm/activities/middleware/run.js.map +1 -1
- package/dist/esm/activities/middleware/types.d.ts +44 -6
- package/dist/esm/activities/stream-generation-result.d.ts +4 -1
- package/dist/esm/activities/stream-generation-result.js +79 -44
- package/dist/esm/activities/stream-generation-result.js.map +1 -1
- package/dist/esm/activities/summarize/adapter.js +22 -15
- package/dist/esm/activities/summarize/adapter.js.map +1 -1
- package/dist/esm/activities/summarize/chat-stream-summarize.js +252 -202
- package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
- package/dist/esm/activities/summarize/index.d.ts +27 -0
- package/dist/esm/activities/summarize/index.js +268 -102
- package/dist/esm/activities/summarize/index.js.map +1 -1
- package/dist/esm/adapter-internals.d.ts +2 -1
- package/dist/esm/adapter-internals.js +4 -11
- package/dist/esm/client.d.ts +25 -3
- package/dist/esm/client.js +131 -64
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/custom-events.d.ts +76 -0
- package/dist/esm/custom-events.js +37 -0
- package/dist/esm/custom-events.js.map +1 -0
- package/dist/esm/delivery-detach.d.ts +50 -0
- package/dist/esm/delivery-detach.js +71 -0
- package/dist/esm/delivery-detach.js.map +1 -0
- package/dist/esm/delivery-disconnect.d.ts +62 -0
- package/dist/esm/delivery-disconnect.js +81 -0
- package/dist/esm/delivery-disconnect.js.map +1 -0
- package/dist/esm/extend-adapter.js +19 -17
- package/dist/esm/extend-adapter.js.map +1 -1
- package/dist/esm/index.d.ts +24 -6
- package/dist/esm/index.js +30 -98
- package/dist/esm/interrupt-resume.d.ts +71 -0
- package/dist/esm/interrupt-resume.js +438 -0
- package/dist/esm/interrupt-resume.js.map +1 -0
- package/dist/esm/interrupt-serialization.d.ts +12 -0
- package/dist/esm/interrupt-serialization.js +178 -0
- package/dist/esm/interrupt-serialization.js.map +1 -0
- package/dist/esm/interrupts.d.ts +84 -0
- package/dist/esm/interrupts.js +31 -0
- package/dist/esm/interrupts.js.map +1 -0
- package/dist/esm/locks.d.ts +10 -0
- package/dist/esm/locks.js +2 -0
- package/dist/esm/logger/console-logger.js +101 -78
- package/dist/esm/logger/console-logger.js.map +1 -1
- package/dist/esm/logger/internal-logger.js +104 -89
- package/dist/esm/logger/internal-logger.js.map +1 -1
- package/dist/esm/logger/resolve.js +54 -49
- package/dist/esm/logger/resolve.js.map +1 -1
- package/dist/esm/logger/types.d.ts +1 -1
- package/dist/esm/middlewares/content-guard.js +142 -148
- package/dist/esm/middlewares/content-guard.js.map +1 -1
- package/dist/esm/middlewares/index.js +2 -6
- package/dist/esm/middlewares/otel.js +598 -732
- package/dist/esm/middlewares/otel.js.map +1 -1
- package/dist/esm/middlewares/usage-attributes.js +47 -40
- package/dist/esm/middlewares/usage-attributes.js.map +1 -1
- package/dist/esm/realtime/event-emitter.js +24 -25
- package/dist/esm/realtime/event-emitter.js.map +1 -1
- package/dist/esm/realtime/index.d.ts +5 -9
- package/dist/esm/realtime/index.js +29 -6
- package/dist/esm/realtime/index.js.map +1 -1
- package/dist/esm/scope.d.ts +47 -0
- package/dist/esm/stream-durability.d.ts +171 -0
- package/dist/esm/stream-durability.js +295 -0
- package/dist/esm/stream-durability.js.map +1 -0
- package/dist/esm/stream-to-response.d.ts +178 -13
- package/dist/esm/stream-to-response.js +663 -115
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/strip-to-spec-middleware.js +30 -16
- package/dist/esm/strip-to-spec-middleware.js.map +1 -1
- package/dist/esm/system-prompts.js +27 -21
- package/dist/esm/system-prompts.js.map +1 -1
- package/dist/esm/tool-registry.js +72 -45
- package/dist/esm/tool-registry.js.map +1 -1
- package/dist/esm/tools/provider-tool.js +14 -5
- package/dist/esm/tools/provider-tool.js.map +1 -1
- package/dist/esm/types.d.ts +321 -42
- package/dist/esm/types.js +2 -0
- package/dist/esm/utilities/ag-ui-wire.js +79 -93
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/chat-params.d.ts +26 -4
- package/dist/esm/utilities/chat-params.js +218 -92
- package/dist/esm/utilities/chat-params.js.map +1 -1
- package/dist/esm/utilities/errors.js +28 -18
- package/dist/esm/utilities/errors.js.map +1 -1
- package/dist/esm/utilities/media-prompt.js +46 -41
- package/dist/esm/utilities/media-prompt.js.map +1 -1
- package/dist/esm/utilities/numbers.js +13 -10
- package/dist/esm/utilities/numbers.js.map +1 -1
- package/dist/esm/utilities/provider-executed.js +20 -11
- package/dist/esm/utilities/provider-executed.js.map +1 -1
- package/dist/esm/utilities/sampling-keys.js +31 -19
- package/dist/esm/utilities/sampling-keys.js.map +1 -1
- package/dist/esm/utilities/tool-result.js +42 -30
- package/dist/esm/utilities/tool-result.js.map +1 -1
- package/dist/esm/utilities/usage.js +27 -9
- package/dist/esm/utilities/usage.js.map +1 -1
- package/dist/esm/utils.js +26 -18
- package/dist/esm/utils.js.map +1 -1
- package/package.json +10 -6
- package/skills/ai-core/SKILL.md +69 -18
- package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
- package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
- package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
- package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
- package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
- package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
- package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
- package/skills/ai-core/chat-experience/SKILL.md +98 -11
- package/skills/ai-core/client-persistence/SKILL.md +277 -0
- package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
- package/skills/ai-core/debug-logging/SKILL.md +1 -1
- package/skills/ai-core/locks/SKILL.md +143 -0
- package/skills/ai-core/media-generation/SKILL.md +144 -12
- package/skills/ai-core/middleware/SKILL.md +258 -33
- package/skills/ai-core/structured-outputs/SKILL.md +1 -1
- package/skills/ai-core/tool-calling/SKILL.md +54 -61
- package/src/activities/chat/agent-loop-strategies.ts +5 -39
- package/src/activities/chat/cancel.ts +81 -0
- package/src/activities/chat/index.ts +1091 -200
- package/src/activities/chat/mcp/manager.ts +4 -4
- package/src/activities/chat/mcp/types.ts +2 -2
- package/src/activities/chat/messages.ts +5 -3
- package/src/activities/chat/middleware/builder.ts +1 -1
- package/src/activities/chat/middleware/compose.ts +186 -9
- package/src/activities/chat/middleware/index.ts +26 -0
- package/src/activities/chat/middleware/locks.ts +102 -0
- package/src/activities/chat/middleware/pending-turn.ts +47 -0
- package/src/activities/chat/middleware/run-disconnect.ts +62 -0
- package/src/activities/chat/middleware/run-store.ts +412 -0
- package/src/activities/chat/middleware/types.ts +62 -1
- package/src/activities/chat/stream/processor.ts +189 -5
- package/src/activities/chat/tools/approval-schema.ts +205 -0
- package/src/activities/chat/tools/tool-calls.ts +106 -13
- package/src/activities/chat/tools/tool-definition.ts +210 -39
- package/src/activities/generateAudio/index.ts +20 -3
- package/src/activities/generateImage/index.ts +20 -3
- package/src/activities/generateSpeech/index.ts +25 -3
- package/src/activities/generateTranscription/index.ts +26 -3
- package/src/activities/generateVideo/index.ts +345 -82
- package/src/activities/middleware/index.ts +2 -0
- package/src/activities/middleware/run.ts +31 -0
- package/src/activities/middleware/types.ts +49 -5
- package/src/activities/stream-generation-result.ts +30 -2
- package/src/activities/summarize/chat-stream-summarize.ts +5 -0
- package/src/activities/summarize/index.ts +200 -10
- package/src/adapter-internals.ts +10 -1
- package/src/client.ts +244 -0
- package/src/custom-events.ts +107 -0
- package/src/delivery-detach.ts +72 -0
- package/src/delivery-disconnect.ts +84 -0
- package/src/index.ts +138 -1
- package/src/interrupt-resume.ts +824 -0
- package/src/interrupt-serialization.ts +183 -0
- package/src/interrupts.ts +146 -0
- package/src/locks.ts +17 -0
- package/src/logger/types.ts +1 -1
- package/src/middlewares/otel.ts +1 -0
- package/src/realtime/index.ts +5 -9
- package/src/scope.ts +47 -0
- package/src/stream-durability.ts +598 -0
- package/src/stream-to-response.ts +1051 -95
- package/src/strip-to-spec-middleware.ts +3 -3
- package/src/types.ts +405 -45
- package/src/utilities/chat-params.ts +245 -55
- package/dist/esm/activities/index.js.map +0 -1
- package/dist/esm/adapter-internals.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/middlewares/index.js.map +0 -1
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { canonicalInterruptJson, digestInterruptJson } from "./interrupt-serialization.js";
|
|
2
|
+
import { canonicalizeInterruptResolutions } from "./interrupts.js";
|
|
3
|
+
import { isStandardSchema, validateWithStandardSchema } from "./activities/chat/tools/schema-converter.js";
|
|
4
|
+
import { hashSchemaInput, normalizeApprovalSchema } from "./activities/chat/tools/approval-schema.js";
|
|
5
|
+
//#region src/interrupt-resume.ts
|
|
6
|
+
/**
|
|
7
|
+
* The `Interrupt.metadata` key under which this package's resume binding
|
|
8
|
+
* travels.
|
|
9
|
+
*
|
|
10
|
+
* Exported so anything that produces an interrupt this package must later
|
|
11
|
+
* resume — an application middleware raising a generic pause, a future
|
|
12
|
+
* workflow-to-AG-UI projection — attaches the binding through
|
|
13
|
+
* {@link withInterruptBinding} rather than copying the string. Everything
|
|
14
|
+
* outside this key is the plain AG-UI envelope and is left untouched.
|
|
15
|
+
*/
|
|
16
|
+
var INTERRUPT_BINDING_METADATA_KEY = "tanstack:interruptBinding";
|
|
17
|
+
var interruptBindingMetadataKey = INTERRUPT_BINDING_METADATA_KEY;
|
|
18
|
+
var InterruptResumeValidationError = class extends Error {
|
|
19
|
+
errors;
|
|
20
|
+
name = "InterruptResumeValidationError";
|
|
21
|
+
constructor(errors) {
|
|
22
|
+
super(errors.map((error) => error.message).join(" "));
|
|
23
|
+
this.errors = errors;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
function objectValue(value) {
|
|
27
|
+
return value && typeof value === "object" ? value : null;
|
|
28
|
+
}
|
|
29
|
+
function stringField(value, key) {
|
|
30
|
+
return typeof value[key] === "string" ? value[key] : void 0;
|
|
31
|
+
}
|
|
32
|
+
function normalizeIssuePath(path) {
|
|
33
|
+
if (!path) return void 0;
|
|
34
|
+
return path.map((segment) => {
|
|
35
|
+
if (typeof segment === "string" || typeof segment === "number") return segment;
|
|
36
|
+
const key = objectValue(segment)?.key;
|
|
37
|
+
return typeof key === "number" ? key : String(key ?? segment);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function interruptItemError(input, interruptId, code, message, options) {
|
|
41
|
+
return {
|
|
42
|
+
scope: "item",
|
|
43
|
+
threadId: input.threadId,
|
|
44
|
+
interruptedRunId: input.interruptedRunId,
|
|
45
|
+
generation: input.generation,
|
|
46
|
+
interruptId,
|
|
47
|
+
code,
|
|
48
|
+
message,
|
|
49
|
+
source: options?.source ?? "client",
|
|
50
|
+
retryable: options?.retryable ?? false,
|
|
51
|
+
...options?.path ? { path: options.path } : {}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function validateSchemaValue(input) {
|
|
55
|
+
if (isStandardSchema(input.schema)) {
|
|
56
|
+
const result = await validateWithStandardSchema(input.schema, input.value);
|
|
57
|
+
if (!result.success) for (const issue of result.issues) input.onIssue(issue.message, normalizeIssuePath(issue.path));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function runtimeTool(tools, name) {
|
|
62
|
+
return tools.find((tool) => tool.name === name);
|
|
63
|
+
}
|
|
64
|
+
function descriptorResponseSchema(record) {
|
|
65
|
+
return objectValue(record.payload)?.responseSchema;
|
|
66
|
+
}
|
|
67
|
+
function schemaHash(schema) {
|
|
68
|
+
return digestInterruptJson(canonicalInterruptJson(schema));
|
|
69
|
+
}
|
|
70
|
+
async function pushSchemaIssues(input) {
|
|
71
|
+
try {
|
|
72
|
+
await validateSchemaValue({
|
|
73
|
+
schema: input.schema,
|
|
74
|
+
value: input.value,
|
|
75
|
+
onIssue: (message, path) => {
|
|
76
|
+
input.errors.push(interruptItemError(input.request, input.interruptId, input.code, `${input.label}: ${message}`, { path }));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
} catch (error) {
|
|
80
|
+
input.errors.push(interruptItemError(input.request, input.interruptId, "invalid-response-schema", `${input.label} could not be validated: ${error instanceof Error ? error.message : String(error)}`, { source: "server" }));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function validateDescriptorSchema(input, record, binding, errors) {
|
|
84
|
+
const schema = descriptorResponseSchema(record);
|
|
85
|
+
if (schema === void 0 || schemaHash(schema) !== binding.responseSchemaHash) errors.push(interruptItemError(input, record.interruptId, "invalid-response-schema", `Interrupt ${record.interruptId} response schema no longer matches its binding.`, { source: "server" }));
|
|
86
|
+
return schema;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validate and translate a complete interrupt batch before any tool executes.
|
|
90
|
+
* Used by ephemeral chat resume; a durable layer may share the same validator.
|
|
91
|
+
*/
|
|
92
|
+
async function validateInterruptResumeBatch(input) {
|
|
93
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
94
|
+
const batchErrors = [];
|
|
95
|
+
const group = (interruptId) => {
|
|
96
|
+
const existing = grouped.get(interruptId);
|
|
97
|
+
if (existing) return existing;
|
|
98
|
+
const created = [];
|
|
99
|
+
grouped.set(interruptId, created);
|
|
100
|
+
return created;
|
|
101
|
+
};
|
|
102
|
+
const pendingById = new Map(input.pending.map((record) => [record.interruptId, record]));
|
|
103
|
+
const resumeById = /* @__PURE__ */ new Map();
|
|
104
|
+
const counts = /* @__PURE__ */ new Map();
|
|
105
|
+
for (const entry of input.resume ?? []) {
|
|
106
|
+
counts.set(entry.interruptId, (counts.get(entry.interruptId) ?? 0) + 1);
|
|
107
|
+
if (!resumeById.has(entry.interruptId)) resumeById.set(entry.interruptId, entry);
|
|
108
|
+
}
|
|
109
|
+
for (const [interruptId, count] of counts) if (count > 1) group(interruptId).push(interruptItemError(input, interruptId, "conflict", `Interrupt ${interruptId} has duplicate resume entries.`));
|
|
110
|
+
let incomplete = false;
|
|
111
|
+
for (const record of input.pending) {
|
|
112
|
+
const errors = group(record.interruptId);
|
|
113
|
+
const entry = resumeById.get(record.interruptId);
|
|
114
|
+
const binding = record.binding;
|
|
115
|
+
if (!entry) {
|
|
116
|
+
incomplete = true;
|
|
117
|
+
errors.push(interruptItemError(input, record.interruptId, "unknown-interrupt", `Missing resume entry for interrupt ${record.interruptId}.`));
|
|
118
|
+
}
|
|
119
|
+
if (binding.interruptedRunId !== input.interruptedRunId || binding.generation !== input.generation || binding.interruptId !== record.interruptId) errors.push(interruptItemError(input, record.interruptId, "stale", `Interrupt ${record.interruptId} has stale correlation metadata.`, { source: "server" }));
|
|
120
|
+
if (binding.expiresAt !== void 0 && Date.parse(binding.expiresAt) <= (input.now ?? Date.now())) errors.push(interruptItemError(input, record.interruptId, "expired", `Interrupt ${record.interruptId} has expired.`, { source: "server" }));
|
|
121
|
+
const responseSchema = validateDescriptorSchema(input, record, binding, errors);
|
|
122
|
+
if (!entry) continue;
|
|
123
|
+
const entryStatus = entry.status;
|
|
124
|
+
if (entryStatus !== "resolved" && entryStatus !== "cancelled") {
|
|
125
|
+
errors.push(interruptItemError(input, record.interruptId, "invalid-payload", `Interrupt ${record.interruptId} has invalid status ${String(entryStatus)}.`));
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (binding.kind === "generic") {
|
|
129
|
+
if (entry.status === "cancelled") {
|
|
130
|
+
if (entry.payload !== void 0) errors.push(interruptItemError(input, record.interruptId, "invalid-payload", `Cancelled interrupt ${record.interruptId} must not include a payload.`));
|
|
131
|
+
} else if (responseSchema !== void 0) await pushSchemaIssues({
|
|
132
|
+
request: input,
|
|
133
|
+
errors,
|
|
134
|
+
interruptId: record.interruptId,
|
|
135
|
+
schema: responseSchema,
|
|
136
|
+
value: entry.payload,
|
|
137
|
+
code: "invalid-payload",
|
|
138
|
+
label: `Interrupt ${record.interruptId} payload is invalid`
|
|
139
|
+
});
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const tool = runtimeTool(input.tools, binding.toolName);
|
|
143
|
+
if (!tool) {
|
|
144
|
+
errors.push(interruptItemError(input, record.interruptId, "stale", `Tool ${binding.toolName} is unavailable for interrupt ${record.interruptId}.`, { source: "server" }));
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
let approval;
|
|
148
|
+
let schemaDrifted = false;
|
|
149
|
+
if (binding.kind === "client-tool-execution") {
|
|
150
|
+
if (hashSchemaInput(tool.outputSchema) !== binding.outputSchemaHash) {
|
|
151
|
+
errors.push(interruptItemError(input, record.interruptId, "stale", `Tool ${binding.toolName} output schema has changed.`, { source: "server" }));
|
|
152
|
+
schemaDrifted = true;
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
try {
|
|
156
|
+
approval = normalizeApprovalSchema(tool.approvalSchema, tool.inputSchema);
|
|
157
|
+
} catch {
|
|
158
|
+
errors.push(interruptItemError(input, record.interruptId, "stale", `Tool ${binding.toolName} approval schema is unavailable.`, { source: "server" }));
|
|
159
|
+
schemaDrifted = true;
|
|
160
|
+
}
|
|
161
|
+
if (approval !== void 0 && (hashSchemaInput(tool.inputSchema) !== binding.inputSchemaHash || approval.approvalSchemaHash !== binding.approvalSchemaHash || approval.responseSchemaHash !== binding.responseSchemaHash)) {
|
|
162
|
+
errors.push(interruptItemError(input, record.interruptId, "stale", `Tool ${binding.toolName} approval schema has changed.`, { source: "server" }));
|
|
163
|
+
schemaDrifted = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (entry.status === "cancelled") {
|
|
167
|
+
if (entry.payload !== void 0) errors.push(interruptItemError(input, record.interruptId, "invalid-payload", `Cancelled interrupt ${record.interruptId} must not include a payload.`));
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (schemaDrifted) continue;
|
|
171
|
+
if (binding.kind === "client-tool-execution") {
|
|
172
|
+
if (responseSchema !== void 0) await pushSchemaIssues({
|
|
173
|
+
request: input,
|
|
174
|
+
errors,
|
|
175
|
+
interruptId: record.interruptId,
|
|
176
|
+
schema: responseSchema,
|
|
177
|
+
value: entry.payload,
|
|
178
|
+
code: "invalid-tool-output",
|
|
179
|
+
label: `Tool ${binding.toolName} output is invalid`
|
|
180
|
+
});
|
|
181
|
+
if (tool.outputSchema !== void 0) await pushSchemaIssues({
|
|
182
|
+
request: input,
|
|
183
|
+
errors,
|
|
184
|
+
interruptId: record.interruptId,
|
|
185
|
+
schema: tool.outputSchema,
|
|
186
|
+
value: entry.payload,
|
|
187
|
+
code: "invalid-tool-output",
|
|
188
|
+
label: `Tool ${binding.toolName} output is invalid`
|
|
189
|
+
});
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (approval === void 0) continue;
|
|
193
|
+
const envelope = objectValue(entry.payload);
|
|
194
|
+
const approved = typeof entry.payload === "boolean" ? entry.payload : typeof envelope?.approved === "boolean" ? envelope.approved : void 0;
|
|
195
|
+
if (approved === void 0) {
|
|
196
|
+
errors.push(interruptItemError(input, record.interruptId, "invalid-payload", `Approval ${record.interruptId} must be a boolean or decision envelope.`));
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (envelope) await pushSchemaIssues({
|
|
200
|
+
request: input,
|
|
201
|
+
errors,
|
|
202
|
+
interruptId: record.interruptId,
|
|
203
|
+
schema: approval.responseSchema,
|
|
204
|
+
value: entry.payload,
|
|
205
|
+
code: "invalid-payload",
|
|
206
|
+
label: `Approval ${record.interruptId} envelope is invalid`
|
|
207
|
+
});
|
|
208
|
+
if (approved && envelope?.editedArgs !== void 0) if (tool.inputSchema === void 0) errors.push(interruptItemError(input, record.interruptId, "invalid-edited-args", `Approval ${record.interruptId} cannot edit arguments without an input schema.`));
|
|
209
|
+
else await pushSchemaIssues({
|
|
210
|
+
request: input,
|
|
211
|
+
errors,
|
|
212
|
+
interruptId: record.interruptId,
|
|
213
|
+
schema: tool.inputSchema,
|
|
214
|
+
value: envelope.editedArgs,
|
|
215
|
+
code: "invalid-edited-args",
|
|
216
|
+
label: `Approval ${record.interruptId} edited arguments are invalid`
|
|
217
|
+
});
|
|
218
|
+
const branch = approved ? approval.branches.approve : approval.branches.reject;
|
|
219
|
+
if (branch) if (!envelope) errors.push(interruptItemError(input, record.interruptId, "invalid-payload", `Approval ${record.interruptId} requires a payload for the ${approved ? "approve" : "reject"} decision.`));
|
|
220
|
+
else await pushSchemaIssues({
|
|
221
|
+
request: input,
|
|
222
|
+
errors,
|
|
223
|
+
interruptId: record.interruptId,
|
|
224
|
+
schema: branch.source,
|
|
225
|
+
value: envelope.payload,
|
|
226
|
+
code: "invalid-payload",
|
|
227
|
+
label: `Approval ${record.interruptId} payload is invalid`
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
for (const entry of input.resume ?? []) if (!pendingById.has(entry.interruptId)) {
|
|
231
|
+
incomplete = true;
|
|
232
|
+
group(entry.interruptId).push(interruptItemError(input, entry.interruptId, "unknown-interrupt", `Resume entry references unknown interrupt ${entry.interruptId}.`));
|
|
233
|
+
}
|
|
234
|
+
if (incomplete) batchErrors.push({
|
|
235
|
+
scope: "batch",
|
|
236
|
+
threadId: input.threadId,
|
|
237
|
+
interruptedRunId: input.interruptedRunId,
|
|
238
|
+
generation: input.generation,
|
|
239
|
+
code: "incomplete-batch",
|
|
240
|
+
message: "Resume entries must resolve or cancel the complete interrupt batch.",
|
|
241
|
+
source: "client",
|
|
242
|
+
retryable: false,
|
|
243
|
+
interruptIds: input.pending.map((record) => record.interruptId)
|
|
244
|
+
});
|
|
245
|
+
const itemErrors = [...grouped.entries()].sort(([left], [right]) => left.localeCompare(right)).flatMap(([, errors]) => errors);
|
|
246
|
+
if (itemErrors.length > 0) {
|
|
247
|
+
batchErrors.push({
|
|
248
|
+
scope: "batch",
|
|
249
|
+
threadId: input.threadId,
|
|
250
|
+
interruptedRunId: input.interruptedRunId,
|
|
251
|
+
generation: input.generation,
|
|
252
|
+
code: "item-validation-failed",
|
|
253
|
+
message: "One or more interrupt resolutions are invalid.",
|
|
254
|
+
source: "client",
|
|
255
|
+
retryable: false,
|
|
256
|
+
interruptIds: input.pending.map((record) => record.interruptId)
|
|
257
|
+
});
|
|
258
|
+
return { errors: [...itemErrors, ...batchErrors] };
|
|
259
|
+
}
|
|
260
|
+
const canonical = canonicalizeInterruptResolutions(input.resume ?? []);
|
|
261
|
+
const approvals = /* @__PURE__ */ new Map();
|
|
262
|
+
const clientToolResults = /* @__PURE__ */ new Map();
|
|
263
|
+
const genericInterrupts = /* @__PURE__ */ new Map();
|
|
264
|
+
const deniedToolResults = /* @__PURE__ */ new Map();
|
|
265
|
+
const cancelledToolCallIds = /* @__PURE__ */ new Set();
|
|
266
|
+
for (const record of input.pending) {
|
|
267
|
+
const entry = resumeById.get(record.interruptId);
|
|
268
|
+
if (!entry) continue;
|
|
269
|
+
const binding = record.binding;
|
|
270
|
+
if (binding.kind === "generic") {
|
|
271
|
+
genericInterrupts.set(record.interruptId, entry.status === "resolved" ? {
|
|
272
|
+
interruptId: record.interruptId,
|
|
273
|
+
status: "resolved",
|
|
274
|
+
payload: entry.payload
|
|
275
|
+
} : {
|
|
276
|
+
interruptId: record.interruptId,
|
|
277
|
+
status: "cancelled"
|
|
278
|
+
});
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (entry.status === "cancelled") {
|
|
282
|
+
cancelledToolCallIds.add(binding.toolCallId);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (binding.kind === "client-tool-execution") {
|
|
286
|
+
clientToolResults.set(binding.toolCallId, entry.payload);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const envelope = objectValue(entry.payload);
|
|
290
|
+
const resolution = typeof entry.payload === "boolean" ? entry.payload : envelope?.approved === true ? {
|
|
291
|
+
approved: true,
|
|
292
|
+
...envelope.editedArgs !== void 0 ? { editedArgs: envelope.editedArgs } : {},
|
|
293
|
+
...envelope.payload !== void 0 ? { payload: envelope.payload } : {}
|
|
294
|
+
} : {
|
|
295
|
+
approved: false,
|
|
296
|
+
...envelope?.payload !== void 0 ? { payload: envelope.payload } : {}
|
|
297
|
+
};
|
|
298
|
+
approvals.set(binding.toolCallId, resolution);
|
|
299
|
+
if (resolution === false || typeof resolution === "object" && !resolution.approved) deniedToolResults.set(binding.toolCallId, typeof resolution === "object" ? resolution.payload : void 0);
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
errors: [],
|
|
303
|
+
resolutions: canonical.resolutions,
|
|
304
|
+
canonicalResolutions: canonical.canonicalResolutions,
|
|
305
|
+
fingerprint: canonical.fingerprint,
|
|
306
|
+
resumeToolState: {
|
|
307
|
+
approvals,
|
|
308
|
+
clientToolResults,
|
|
309
|
+
genericInterrupts,
|
|
310
|
+
deniedToolResults,
|
|
311
|
+
cancelledToolCallIds
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Is this a binding written by a version of the protocol we understand?
|
|
317
|
+
*
|
|
318
|
+
* A missing `v` is read as {@link INTERRUPT_BINDING_VERSION} so bindings
|
|
319
|
+
* written before the field existed still resume. A `v` we don't recognise is
|
|
320
|
+
* rejected outright — a newer or foreign producer's binding must not be
|
|
321
|
+
* duck-typed into ours.
|
|
322
|
+
*/
|
|
323
|
+
function isSupportedBindingVersion(raw) {
|
|
324
|
+
const version = raw["v"];
|
|
325
|
+
if (version === void 0) return true;
|
|
326
|
+
return version === 1;
|
|
327
|
+
}
|
|
328
|
+
function readUnopenedInterruptBinding(descriptor) {
|
|
329
|
+
const metadata = objectValue(descriptor.metadata);
|
|
330
|
+
const raw = metadata ? objectValue(metadata[interruptBindingMetadataKey]) : null;
|
|
331
|
+
if (!raw || stringField(raw, "interruptId") !== descriptor.id) return void 0;
|
|
332
|
+
if (!isSupportedBindingVersion(raw)) return void 0;
|
|
333
|
+
const kind = stringField(raw, "kind");
|
|
334
|
+
const interruptId = stringField(raw, "interruptId");
|
|
335
|
+
const responseSchemaHash = stringField(raw, "responseSchemaHash");
|
|
336
|
+
const expiresAt = stringField(raw, "expiresAt");
|
|
337
|
+
if (!interruptId || !responseSchemaHash) return void 0;
|
|
338
|
+
const v = 1;
|
|
339
|
+
if (kind === "generic") return {
|
|
340
|
+
v,
|
|
341
|
+
kind,
|
|
342
|
+
interruptId,
|
|
343
|
+
responseSchemaHash,
|
|
344
|
+
...expiresAt ? { expiresAt } : {}
|
|
345
|
+
};
|
|
346
|
+
const toolName = stringField(raw, "toolName");
|
|
347
|
+
const toolCallId = stringField(raw, "toolCallId");
|
|
348
|
+
if (!toolName || !toolCallId) return void 0;
|
|
349
|
+
if (kind === "client-tool-execution") {
|
|
350
|
+
const outputSchemaHash = stringField(raw, "outputSchemaHash");
|
|
351
|
+
if (!outputSchemaHash) return void 0;
|
|
352
|
+
return {
|
|
353
|
+
v,
|
|
354
|
+
kind,
|
|
355
|
+
interruptId,
|
|
356
|
+
toolName,
|
|
357
|
+
toolCallId,
|
|
358
|
+
outputSchemaHash,
|
|
359
|
+
responseSchemaHash,
|
|
360
|
+
...expiresAt ? { expiresAt } : {}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
if (kind === "tool-approval") {
|
|
364
|
+
const inputSchemaHash = stringField(raw, "inputSchemaHash");
|
|
365
|
+
const approvalSchemaHash = stringField(raw, "approvalSchemaHash");
|
|
366
|
+
if (!inputSchemaHash || !approvalSchemaHash) return void 0;
|
|
367
|
+
return {
|
|
368
|
+
v,
|
|
369
|
+
kind,
|
|
370
|
+
interruptId,
|
|
371
|
+
toolName,
|
|
372
|
+
toolCallId,
|
|
373
|
+
originalArgs: raw.originalArgs,
|
|
374
|
+
inputSchemaHash,
|
|
375
|
+
approvalSchemaHash,
|
|
376
|
+
responseSchemaHash,
|
|
377
|
+
...expiresAt ? { expiresAt } : {}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Attach a resume binding to an interrupt descriptor, under
|
|
383
|
+
* {@link INTERRUPT_BINDING_METADATA_KEY}.
|
|
384
|
+
*
|
|
385
|
+
* This is the supported way to make an interrupt resumable by this package.
|
|
386
|
+
* The descriptor keeps its AG-UI shape; only `metadata` gains the namespaced
|
|
387
|
+
* key. Pass the unopened form (no `interruptedRunId` / `generation`) when
|
|
388
|
+
* emitting from inside a run — those fields are stamped as the run finishes.
|
|
389
|
+
*/
|
|
390
|
+
function withInterruptBinding(descriptor, binding) {
|
|
391
|
+
return {
|
|
392
|
+
...descriptor,
|
|
393
|
+
metadata: {
|
|
394
|
+
...descriptor.metadata,
|
|
395
|
+
[interruptBindingMetadataKey]: {
|
|
396
|
+
...binding,
|
|
397
|
+
v: 1,
|
|
398
|
+
interruptId: descriptor.id
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Read the opened resume binding off a descriptor, or `undefined` when the
|
|
405
|
+
* descriptor carries no binding of a version we understand.
|
|
406
|
+
*
|
|
407
|
+
* `undefined` means "this interrupt is not ours to resume" — it is not a
|
|
408
|
+
* failure to recover from by inventing a binding.
|
|
409
|
+
*/
|
|
410
|
+
function readInterruptBinding(descriptor) {
|
|
411
|
+
const unopened = readUnopenedInterruptBinding(descriptor);
|
|
412
|
+
if (!unopened) return void 0;
|
|
413
|
+
const metadata = objectValue(descriptor.metadata);
|
|
414
|
+
const raw = metadata ? objectValue(metadata[interruptBindingMetadataKey]) : null;
|
|
415
|
+
if (!raw) return void 0;
|
|
416
|
+
const interruptedRunId = stringField(raw, "interruptedRunId");
|
|
417
|
+
const generation = raw["generation"];
|
|
418
|
+
if (!interruptedRunId || typeof generation !== "number" || !Number.isInteger(generation) || generation < 0) return;
|
|
419
|
+
return {
|
|
420
|
+
...unopened,
|
|
421
|
+
interruptedRunId,
|
|
422
|
+
generation
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function withoutInterruptBinding(descriptor) {
|
|
426
|
+
const metadata = objectValue(descriptor.metadata);
|
|
427
|
+
if (!metadata || !(interruptBindingMetadataKey in metadata)) return descriptor;
|
|
428
|
+
const publicMetadata = { ...metadata };
|
|
429
|
+
delete publicMetadata[interruptBindingMetadataKey];
|
|
430
|
+
return {
|
|
431
|
+
...descriptor,
|
|
432
|
+
metadata: publicMetadata
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
//#endregion
|
|
436
|
+
export { INTERRUPT_BINDING_METADATA_KEY, InterruptResumeValidationError, interruptItemError, readInterruptBinding, readUnopenedInterruptBinding, validateInterruptResumeBatch, withInterruptBinding, withoutInterruptBinding };
|
|
437
|
+
|
|
438
|
+
//# sourceMappingURL=interrupt-resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interrupt-resume.js","names":[],"sources":["../../src/interrupt-resume.ts"],"sourcesContent":["import {\n INTERRUPT_BINDING_VERSION,\n canonicalizeInterruptResolutions,\n} from './interrupts'\nimport {\n canonicalInterruptJson,\n digestInterruptJson,\n} from './interrupt-serialization'\nimport {\n hashSchemaInput,\n normalizeApprovalSchema,\n} from './activities/chat/tools/approval-schema'\nimport {\n isStandardSchema,\n validateWithStandardSchema,\n} from './activities/chat/tools/schema-converter'\nimport type {\n InterruptBinding,\n InterruptSubmissionError,\n ItemInterruptErrorCode,\n ToolApprovalResolution,\n UnopenedInterruptBinding,\n} from './interrupts'\nimport type {\n ChatMiddlewareConfig,\n ChatResumeToolState,\n} from './activities/chat/middleware/types'\nimport type { Interrupt, RunAgentResumeItem } from './types'\n\n/**\n * The `Interrupt.metadata` key under which this package's resume binding\n * travels.\n *\n * Exported so anything that produces an interrupt this package must later\n * resume — an application middleware raising a generic pause, a future\n * workflow-to-AG-UI projection — attaches the binding through\n * {@link withInterruptBinding} rather than copying the string. Everything\n * outside this key is the plain AG-UI envelope and is left untouched.\n */\nexport const INTERRUPT_BINDING_METADATA_KEY = 'tanstack:interruptBinding'\n\nconst interruptBindingMetadataKey = INTERRUPT_BINDING_METADATA_KEY\n\n/** The persistence-neutral shape required to validate an interrupt resume. */\nexport interface PendingInterruptResumeRecord {\n interruptId: string\n payload: unknown\n binding: InterruptBinding\n}\n\nexport interface ValidateInterruptResumeBatchInput {\n threadId: string\n interruptedRunId: string\n generation: number\n pending: ReadonlyArray<PendingInterruptResumeRecord>\n resume?: ReadonlyArray<RunAgentResumeItem>\n tools: ChatMiddlewareConfig['tools']\n now?: number\n}\n\nexport interface ValidatedInterruptResumeBatch {\n errors: ReadonlyArray<InterruptSubmissionError>\n resolutions?: ReadonlyArray<RunAgentResumeItem>\n canonicalResolutions?: string\n fingerprint?: string\n resumeToolState?: ChatResumeToolState\n}\n\nexport class InterruptResumeValidationError extends Error {\n override readonly name = 'InterruptResumeValidationError'\n\n constructor(readonly errors: ReadonlyArray<InterruptSubmissionError>) {\n super(errors.map((error) => error.message).join(' '))\n }\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object'\n ? (value as Record<string, unknown>)\n : null\n}\n\nfunction stringField(\n value: Record<string, unknown>,\n key: string,\n): string | undefined {\n return typeof value[key] === 'string' ? value[key] : undefined\n}\n\nfunction normalizeIssuePath(\n path: ReadonlyArray<unknown> | undefined,\n): ReadonlyArray<string | number> | undefined {\n if (!path) return undefined\n return path.map((segment) => {\n if (typeof segment === 'string' || typeof segment === 'number') {\n return segment\n }\n const record = objectValue(segment)\n const key = record?.key\n return typeof key === 'number' ? key : String(key ?? segment)\n })\n}\n\nexport function interruptItemError(\n input: Pick<\n ValidateInterruptResumeBatchInput,\n 'threadId' | 'interruptedRunId' | 'generation'\n >,\n interruptId: string,\n code: ItemInterruptErrorCode,\n message: string,\n options?: {\n path?: ReadonlyArray<string | number>\n source?: 'client' | 'server'\n retryable?: boolean\n },\n): InterruptSubmissionError {\n return {\n scope: 'item',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n interruptId,\n code,\n message,\n source: options?.source ?? 'client',\n retryable: options?.retryable ?? false,\n ...(options?.path ? { path: options.path } : {}),\n }\n}\n\nasync function validateSchemaValue(input: {\n schema: unknown\n value: unknown\n onIssue: (message: string, path?: ReadonlyArray<string | number>) => void\n}): Promise<void> {\n if (isStandardSchema(input.schema)) {\n const result = await validateWithStandardSchema<unknown>(\n input.schema,\n input.value,\n )\n if (!result.success) {\n for (const issue of result.issues) {\n input.onIssue(issue.message, normalizeIssuePath(issue.path))\n }\n }\n return\n }\n\n // A non-Standard-Schema value (a raw JSON Schema, e.g. a generic interrupt's\n // wire responseSchema) is not validated by the library. The application\n // validates the resume value itself if it needs to; otherwise it flows\n // through as-is.\n}\n\ntype RuntimeTool = ChatMiddlewareConfig['tools'][number] & {\n approvalSchema?: Parameters<typeof normalizeApprovalSchema>[0]\n}\n\nfunction runtimeTool(\n tools: ChatMiddlewareConfig['tools'],\n name: string,\n): RuntimeTool | undefined {\n return tools.find((tool) => tool.name === name) as RuntimeTool | undefined\n}\n\nfunction descriptorResponseSchema(\n record: PendingInterruptResumeRecord,\n): unknown {\n return objectValue(record.payload)?.responseSchema\n}\n\nfunction schemaHash(schema: unknown): string {\n return digestInterruptJson(canonicalInterruptJson(schema))\n}\n\nasync function pushSchemaIssues(input: {\n request: ValidateInterruptResumeBatchInput\n errors: Array<InterruptSubmissionError>\n interruptId: string\n schema: unknown\n value: unknown\n code: ItemInterruptErrorCode\n label: string\n}): Promise<void> {\n try {\n await validateSchemaValue({\n schema: input.schema,\n value: input.value,\n onIssue: (message, path) => {\n input.errors.push(\n interruptItemError(\n input.request,\n input.interruptId,\n input.code,\n `${input.label}: ${message}`,\n { path },\n ),\n )\n },\n })\n } catch (error) {\n input.errors.push(\n interruptItemError(\n input.request,\n input.interruptId,\n 'invalid-response-schema',\n `${input.label} could not be validated: ${error instanceof Error ? error.message : String(error)}`,\n { source: 'server' },\n ),\n )\n }\n}\n\nfunction validateDescriptorSchema(\n input: ValidateInterruptResumeBatchInput,\n record: PendingInterruptResumeRecord,\n binding: InterruptBinding,\n errors: Array<InterruptSubmissionError>,\n): unknown {\n const schema = descriptorResponseSchema(record)\n if (\n schema === undefined ||\n schemaHash(schema) !== binding.responseSchemaHash\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-response-schema',\n `Interrupt ${record.interruptId} response schema no longer matches its binding.`,\n { source: 'server' },\n ),\n )\n }\n return schema\n}\n\n/**\n * Validate and translate a complete interrupt batch before any tool executes.\n * Used by ephemeral chat resume; a durable layer may share the same validator.\n */\nexport async function validateInterruptResumeBatch(\n input: ValidateInterruptResumeBatchInput,\n): Promise<ValidatedInterruptResumeBatch> {\n const grouped = new Map<string, Array<InterruptSubmissionError>>()\n const batchErrors: Array<InterruptSubmissionError> = []\n const group = (interruptId: string): Array<InterruptSubmissionError> => {\n const existing = grouped.get(interruptId)\n if (existing) return existing\n const created: Array<InterruptSubmissionError> = []\n grouped.set(interruptId, created)\n return created\n }\n const pendingById = new Map(\n input.pending.map((record) => [record.interruptId, record]),\n )\n const resumeById = new Map<string, RunAgentResumeItem>()\n const counts = new Map<string, number>()\n for (const entry of input.resume ?? []) {\n counts.set(entry.interruptId, (counts.get(entry.interruptId) ?? 0) + 1)\n if (!resumeById.has(entry.interruptId))\n resumeById.set(entry.interruptId, entry)\n }\n\n for (const [interruptId, count] of counts) {\n if (count > 1) {\n group(interruptId).push(\n interruptItemError(\n input,\n interruptId,\n 'conflict',\n `Interrupt ${interruptId} has duplicate resume entries.`,\n ),\n )\n }\n }\n\n let incomplete = false\n for (const record of input.pending) {\n const errors = group(record.interruptId)\n const entry = resumeById.get(record.interruptId)\n const binding = record.binding\n if (!entry) {\n incomplete = true\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'unknown-interrupt',\n `Missing resume entry for interrupt ${record.interruptId}.`,\n ),\n )\n }\n if (\n binding.interruptedRunId !== input.interruptedRunId ||\n binding.generation !== input.generation ||\n binding.interruptId !== record.interruptId\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Interrupt ${record.interruptId} has stale correlation metadata.`,\n { source: 'server' },\n ),\n )\n }\n if (\n binding.expiresAt !== undefined &&\n Date.parse(binding.expiresAt) <= (input.now ?? Date.now())\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'expired',\n `Interrupt ${record.interruptId} has expired.`,\n { source: 'server' },\n ),\n )\n }\n\n const responseSchema = validateDescriptorSchema(\n input,\n record,\n binding,\n errors,\n )\n if (!entry) continue\n const entryStatus: unknown = entry.status\n if (entryStatus !== 'resolved' && entryStatus !== 'cancelled') {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} has invalid status ${String(entryStatus)}.`,\n ),\n )\n continue\n }\n if (binding.kind === 'generic') {\n if (entry.status === 'cancelled') {\n if (entry.payload !== undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Cancelled interrupt ${record.interruptId} must not include a payload.`,\n ),\n )\n }\n } else if (responseSchema !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Interrupt ${record.interruptId} payload is invalid`,\n })\n }\n continue\n }\n\n const tool = runtimeTool(input.tools, binding.toolName)\n if (!tool) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} is unavailable for interrupt ${record.interruptId}.`,\n { source: 'server' },\n ),\n )\n continue\n }\n\n let approval: ReturnType<typeof normalizeApprovalSchema> | undefined\n let schemaDrifted = false\n if (binding.kind === 'client-tool-execution') {\n if (hashSchemaInput(tool.outputSchema) !== binding.outputSchemaHash) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} output schema has changed.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n } else {\n try {\n approval = normalizeApprovalSchema(\n tool.approvalSchema,\n tool.inputSchema,\n )\n } catch {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} approval schema is unavailable.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n if (\n approval !== undefined &&\n (hashSchemaInput(tool.inputSchema) !== binding.inputSchemaHash ||\n approval.approvalSchemaHash !== binding.approvalSchemaHash ||\n approval.responseSchemaHash !== binding.responseSchemaHash)\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} approval schema has changed.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n }\n\n if (entry.status === 'cancelled') {\n if (entry.payload !== undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Cancelled interrupt ${record.interruptId} must not include a payload.`,\n ),\n )\n }\n continue\n }\n if (schemaDrifted) continue\n\n if (binding.kind === 'client-tool-execution') {\n if (responseSchema !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: responseSchema,\n value: entry.payload,\n code: 'invalid-tool-output',\n label: `Tool ${binding.toolName} output is invalid`,\n })\n }\n if (tool.outputSchema !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: tool.outputSchema,\n value: entry.payload,\n code: 'invalid-tool-output',\n label: `Tool ${binding.toolName} output is invalid`,\n })\n }\n continue\n }\n\n if (approval === undefined) continue\n const envelope = objectValue(entry.payload)\n const approved =\n typeof entry.payload === 'boolean'\n ? entry.payload\n : typeof envelope?.approved === 'boolean'\n ? envelope.approved\n : undefined\n if (approved === undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Approval ${record.interruptId} must be a boolean or decision envelope.`,\n ),\n )\n continue\n }\n if (envelope) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: approval.responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Approval ${record.interruptId} envelope is invalid`,\n })\n }\n if (approved && envelope?.editedArgs !== undefined) {\n if (tool.inputSchema === undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-edited-args',\n `Approval ${record.interruptId} cannot edit arguments without an input schema.`,\n ),\n )\n } else {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: tool.inputSchema,\n value: envelope.editedArgs,\n code: 'invalid-edited-args',\n label: `Approval ${record.interruptId} edited arguments are invalid`,\n })\n }\n }\n const branch = approved\n ? approval.branches.approve\n : approval.branches.reject\n if (branch) {\n if (!envelope) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Approval ${record.interruptId} requires a payload for the ${approved ? 'approve' : 'reject'} decision.`,\n ),\n )\n } else {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: branch.source,\n value: envelope.payload,\n code: 'invalid-payload',\n label: `Approval ${record.interruptId} payload is invalid`,\n })\n }\n }\n }\n\n for (const entry of input.resume ?? []) {\n if (!pendingById.has(entry.interruptId)) {\n incomplete = true\n group(entry.interruptId).push(\n interruptItemError(\n input,\n entry.interruptId,\n 'unknown-interrupt',\n `Resume entry references unknown interrupt ${entry.interruptId}.`,\n ),\n )\n }\n }\n\n if (incomplete) {\n batchErrors.push({\n scope: 'batch',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n code: 'incomplete-batch',\n message:\n 'Resume entries must resolve or cancel the complete interrupt batch.',\n source: 'client',\n retryable: false,\n interruptIds: input.pending.map((record) => record.interruptId),\n })\n }\n\n const itemErrors = [...grouped.entries()]\n .sort(([left], [right]) => left.localeCompare(right))\n .flatMap(([, errors]) => errors)\n if (itemErrors.length > 0) {\n batchErrors.push({\n scope: 'batch',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n code: 'item-validation-failed',\n message: 'One or more interrupt resolutions are invalid.',\n source: 'client',\n retryable: false,\n interruptIds: input.pending.map((record) => record.interruptId),\n })\n return { errors: [...itemErrors, ...batchErrors] }\n }\n\n const canonical = canonicalizeInterruptResolutions(input.resume ?? [])\n const approvals = new Map<string, ToolApprovalResolution>()\n const clientToolResults = new Map<string, unknown>()\n const genericInterrupts = new Map<\n string,\n | { interruptId: string; status: 'resolved'; payload: unknown }\n | { interruptId: string; status: 'cancelled' }\n >()\n const deniedToolResults = new Map<string, unknown>()\n const cancelledToolCallIds = new Set<string>()\n\n for (const record of input.pending) {\n const entry = resumeById.get(record.interruptId)\n if (!entry) continue\n const binding = record.binding\n if (binding.kind === 'generic') {\n genericInterrupts.set(\n record.interruptId,\n entry.status === 'resolved'\n ? {\n interruptId: record.interruptId,\n status: 'resolved',\n payload: entry.payload,\n }\n : { interruptId: record.interruptId, status: 'cancelled' },\n )\n continue\n }\n if (entry.status === 'cancelled') {\n cancelledToolCallIds.add(binding.toolCallId)\n continue\n }\n if (binding.kind === 'client-tool-execution') {\n clientToolResults.set(binding.toolCallId, entry.payload)\n continue\n }\n const envelope = objectValue(entry.payload)\n const resolution: ToolApprovalResolution =\n typeof entry.payload === 'boolean'\n ? entry.payload\n : envelope?.approved === true\n ? {\n approved: true,\n ...(envelope.editedArgs !== undefined\n ? { editedArgs: envelope.editedArgs }\n : {}),\n ...(envelope.payload !== undefined\n ? { payload: envelope.payload }\n : {}),\n }\n : {\n approved: false,\n ...(envelope?.payload !== undefined\n ? { payload: envelope.payload }\n : {}),\n }\n approvals.set(binding.toolCallId, resolution)\n if (\n resolution === false ||\n (typeof resolution === 'object' && !resolution.approved)\n ) {\n deniedToolResults.set(\n binding.toolCallId,\n typeof resolution === 'object' ? resolution.payload : undefined,\n )\n }\n }\n\n return {\n errors: [],\n resolutions: canonical.resolutions,\n canonicalResolutions: canonical.canonicalResolutions,\n fingerprint: canonical.fingerprint,\n resumeToolState: {\n approvals,\n clientToolResults,\n genericInterrupts,\n deniedToolResults,\n cancelledToolCallIds,\n },\n }\n}\n\n/**\n * Is this a binding written by a version of the protocol we understand?\n *\n * A missing `v` is read as {@link INTERRUPT_BINDING_VERSION} so bindings\n * written before the field existed still resume. A `v` we don't recognise is\n * rejected outright — a newer or foreign producer's binding must not be\n * duck-typed into ours.\n */\nfunction isSupportedBindingVersion(raw: Record<string, unknown>): boolean {\n const version = raw['v']\n if (version === undefined) return true\n return version === INTERRUPT_BINDING_VERSION\n}\n\nexport function readUnopenedInterruptBinding(\n descriptor: Interrupt,\n): UnopenedInterruptBinding | undefined {\n const metadata = objectValue(descriptor.metadata)\n const raw = metadata\n ? objectValue(metadata[interruptBindingMetadataKey])\n : null\n if (!raw || stringField(raw, 'interruptId') !== descriptor.id)\n return undefined\n if (!isSupportedBindingVersion(raw)) return undefined\n const kind = stringField(raw, 'kind')\n const interruptId = stringField(raw, 'interruptId')\n const responseSchemaHash = stringField(raw, 'responseSchemaHash')\n const expiresAt = stringField(raw, 'expiresAt')\n if (!interruptId || !responseSchemaHash) return undefined\n const v = INTERRUPT_BINDING_VERSION\n if (kind === 'generic') {\n return {\n v,\n kind,\n interruptId,\n responseSchemaHash,\n ...(expiresAt ? { expiresAt } : {}),\n }\n }\n const toolName = stringField(raw, 'toolName')\n const toolCallId = stringField(raw, 'toolCallId')\n if (!toolName || !toolCallId) return undefined\n if (kind === 'client-tool-execution') {\n const outputSchemaHash = stringField(raw, 'outputSchemaHash')\n if (!outputSchemaHash) return undefined\n return {\n v,\n kind,\n interruptId,\n toolName,\n toolCallId,\n outputSchemaHash,\n responseSchemaHash,\n ...(expiresAt ? { expiresAt } : {}),\n }\n }\n if (kind === 'tool-approval') {\n const inputSchemaHash = stringField(raw, 'inputSchemaHash')\n const approvalSchemaHash = stringField(raw, 'approvalSchemaHash')\n if (!inputSchemaHash || !approvalSchemaHash) return undefined\n return {\n v,\n kind,\n interruptId,\n toolName,\n toolCallId,\n originalArgs: raw.originalArgs,\n inputSchemaHash,\n approvalSchemaHash,\n responseSchemaHash,\n ...(expiresAt ? { expiresAt } : {}),\n }\n }\n return undefined\n}\n\n/**\n * Attach a resume binding to an interrupt descriptor, under\n * {@link INTERRUPT_BINDING_METADATA_KEY}.\n *\n * This is the supported way to make an interrupt resumable by this package.\n * The descriptor keeps its AG-UI shape; only `metadata` gains the namespaced\n * key. Pass the unopened form (no `interruptedRunId` / `generation`) when\n * emitting from inside a run — those fields are stamped as the run finishes.\n */\nexport function withInterruptBinding(\n descriptor: Interrupt,\n binding: UnopenedInterruptBinding | InterruptBinding,\n): Interrupt {\n return {\n ...descriptor,\n metadata: {\n ...descriptor.metadata,\n [interruptBindingMetadataKey]: {\n ...binding,\n v: INTERRUPT_BINDING_VERSION,\n interruptId: descriptor.id,\n },\n },\n }\n}\n\n/**\n * Read the opened resume binding off a descriptor, or `undefined` when the\n * descriptor carries no binding of a version we understand.\n *\n * `undefined` means \"this interrupt is not ours to resume\" — it is not a\n * failure to recover from by inventing a binding.\n */\nexport function readInterruptBinding(\n descriptor: Interrupt,\n): InterruptBinding | undefined {\n const unopened = readUnopenedInterruptBinding(descriptor)\n if (!unopened) return undefined\n const metadata = objectValue(descriptor.metadata)\n const raw = metadata\n ? objectValue(metadata[interruptBindingMetadataKey])\n : null\n if (!raw) return undefined\n const interruptedRunId = stringField(raw, 'interruptedRunId')\n const generation = raw['generation']\n if (\n !interruptedRunId ||\n typeof generation !== 'number' ||\n !Number.isInteger(generation) ||\n generation < 0\n ) {\n return undefined\n }\n return { ...unopened, interruptedRunId, generation }\n}\n\nexport function withoutInterruptBinding(descriptor: Interrupt): Interrupt {\n const metadata = objectValue(descriptor.metadata)\n if (!metadata || !(interruptBindingMetadataKey in metadata)) return descriptor\n const publicMetadata = { ...metadata }\n delete publicMetadata[interruptBindingMetadataKey]\n return { ...descriptor, metadata: publicMetadata }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A hash function for interrupt bindings and resolution fingerprints. Receives
|
|
3
|
+
* canonical JSON text and returns an opaque string. Must be deterministic; the
|
|
4
|
+
* server compares hashes it computed against the ones in a binding, so the same
|
|
5
|
+
* function has to run wherever a given binding is produced and checked.
|
|
6
|
+
*/
|
|
7
|
+
export type InterruptHash = (canonicalJson: string) => string;
|
|
8
|
+
/** The built-in default: SHA-256, prefixed so the algorithm is self-describing. */
|
|
9
|
+
export declare function defaultInterruptHash(canonicalJson: string): string;
|
|
10
|
+
export declare function canonicalInterruptJson(value: unknown): string;
|
|
11
|
+
export declare function digestInterruptJson(canonicalJson: string, hash?: InterruptHash): string;
|
|
12
|
+
export declare function cloneAndDeepFreezeJson<T>(value: T): T;
|