@tanstack/ai 0.45.1 → 0.47.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.
Files changed (82) hide show
  1. package/dist/esm/activities/chat/index.d.ts +36 -11
  2. package/dist/esm/activities/chat/index.js +462 -66
  3. package/dist/esm/activities/chat/index.js.map +1 -1
  4. package/dist/esm/activities/chat/messages.d.ts +1 -0
  5. package/dist/esm/activities/chat/messages.js +12 -7
  6. package/dist/esm/activities/chat/messages.js.map +1 -1
  7. package/dist/esm/activities/chat/middleware/builder.d.ts +7 -2
  8. package/dist/esm/activities/chat/middleware/builder.js.map +1 -1
  9. package/dist/esm/activities/chat/middleware/compose.d.ts +10 -3
  10. package/dist/esm/activities/chat/middleware/compose.js +55 -0
  11. package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
  12. package/dist/esm/activities/chat/middleware/define.d.ts +6 -3
  13. package/dist/esm/activities/chat/middleware/define.js.map +1 -1
  14. package/dist/esm/activities/chat/middleware/generic-interrupts.d.ts +13 -0
  15. package/dist/esm/activities/chat/middleware/generic-interrupts.js +8 -0
  16. package/dist/esm/activities/chat/middleware/generic-interrupts.js.map +1 -0
  17. package/dist/esm/activities/chat/middleware/index.d.ts +4 -1
  18. package/dist/esm/activities/chat/middleware/types.d.ts +54 -3
  19. package/dist/esm/activities/chat/middleware/types.js +16 -0
  20. package/dist/esm/activities/chat/middleware/types.js.map +1 -0
  21. package/dist/esm/activities/chat/stream/processor.js +18 -5
  22. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  23. package/dist/esm/activities/chat/tools/unique-tool-names.d.ts +20 -0
  24. package/dist/esm/activities/chat/tools/unique-tool-names.js +57 -0
  25. package/dist/esm/activities/chat/tools/unique-tool-names.js.map +1 -0
  26. package/dist/esm/adapter-internals.d.ts +7 -0
  27. package/dist/esm/adapter-internals.js +5 -1
  28. package/dist/esm/client.d.ts +4 -0
  29. package/dist/esm/client.js +3 -1
  30. package/dist/esm/client.js.map +1 -1
  31. package/dist/esm/generic-interrupt-continuation.d.ts +45 -0
  32. package/dist/esm/generic-interrupt-continuation.js +80 -0
  33. package/dist/esm/generic-interrupt-continuation.js.map +1 -0
  34. package/dist/esm/index.d.ts +9 -1
  35. package/dist/esm/index.js +7 -2
  36. package/dist/esm/interrupt-definition.d.ts +113 -0
  37. package/dist/esm/interrupt-definition.js +169 -0
  38. package/dist/esm/interrupt-definition.js.map +1 -0
  39. package/dist/esm/interrupt-resume.d.ts +3 -0
  40. package/dist/esm/interrupt-resume.js +77 -16
  41. package/dist/esm/interrupt-resume.js.map +1 -1
  42. package/dist/esm/interrupts.d.ts +12 -3
  43. package/dist/esm/interrupts.js.map +1 -1
  44. package/dist/esm/middlewares/usage-attributes.d.ts +2 -2
  45. package/dist/esm/middlewares/usage-attributes.js +9 -2
  46. package/dist/esm/middlewares/usage-attributes.js.map +1 -1
  47. package/dist/esm/stream-to-response.d.ts +26 -0
  48. package/dist/esm/stream-to-response.js +1 -1
  49. package/dist/esm/stream-to-response.js.map +1 -1
  50. package/dist/esm/stream-to-websocket.d.ts +123 -0
  51. package/dist/esm/stream-to-websocket.js +249 -0
  52. package/dist/esm/stream-to-websocket.js.map +1 -0
  53. package/dist/esm/types.d.ts +19 -10
  54. package/dist/esm/utilities/chat-params.js +10 -1
  55. package/dist/esm/utilities/chat-params.js.map +1 -1
  56. package/package.json +2 -2
  57. package/skills/ai-core/media-generation/SKILL.md +13 -9
  58. package/skills/ai-core/middleware/SKILL.md +53 -44
  59. package/skills/ai-core/structured-outputs/SKILL.md +59 -55
  60. package/skills/ai-core/tool-calling/SKILL.md +54 -1
  61. package/src/activities/chat/index.ts +1076 -194
  62. package/src/activities/chat/messages.ts +11 -3
  63. package/src/activities/chat/middleware/builder.ts +29 -4
  64. package/src/activities/chat/middleware/compose.ts +95 -5
  65. package/src/activities/chat/middleware/define.ts +13 -3
  66. package/src/activities/chat/middleware/generic-interrupts.ts +26 -0
  67. package/src/activities/chat/middleware/index.ts +15 -0
  68. package/src/activities/chat/middleware/types.ts +127 -2
  69. package/src/activities/chat/stream/processor.ts +21 -0
  70. package/src/activities/chat/tools/unique-tool-names.ts +73 -0
  71. package/src/adapter-internals.ts +24 -0
  72. package/src/client.ts +20 -0
  73. package/src/generic-interrupt-continuation.ts +162 -0
  74. package/src/index.ts +51 -0
  75. package/src/interrupt-definition.ts +581 -0
  76. package/src/interrupt-resume.ts +156 -25
  77. package/src/interrupts.ts +13 -3
  78. package/src/middlewares/usage-attributes.ts +12 -2
  79. package/src/stream-to-response.ts +2 -2
  80. package/src/stream-to-websocket.ts +418 -0
  81. package/src/types.ts +21 -8
  82. package/src/utilities/chat-params.ts +16 -3
@@ -0,0 +1,169 @@
1
+ import { canonicalInterruptJson, cloneAndDeepFreezeJson, digestInterruptJson } from "./interrupt-serialization.js";
2
+ import "./interrupts.js";
3
+ import { isStandardJSONSchema, isStandardSchema } from "./activities/chat/tools/schema-converter.js";
4
+ //#region src/interrupt-definition.ts
5
+ var INTERRUPT_PAYLOAD_METADATA_KEY = "tanstack:interruptPayload";
6
+ var INTERRUPT_BINDING_KIND = "generic";
7
+ var definitionSchemaState = /* @__PURE__ */ new WeakMap();
8
+ function createInterruptBinding(request, fields = {}) {
9
+ const schemaState = definitionSchemaState.get(request.definition);
10
+ if (!schemaState) throw new TypeError("Interrupt definition schema state is unavailable.");
11
+ const { threadId, interruptedRunId, generation, batchIndex } = fields;
12
+ return {
13
+ descriptor: {
14
+ v: 1,
15
+ kind: INTERRUPT_BINDING_KIND,
16
+ definitionId: request.definition.id,
17
+ key: request.key,
18
+ ...threadId !== void 0 ? { threadId } : {},
19
+ ...interruptedRunId !== void 0 ? { interruptedRunId } : {},
20
+ ...generation !== void 0 ? { generation } : {},
21
+ ...batchIndex !== void 0 ? { batchIndex } : {},
22
+ ...schemaState.responseSchemaCanonicalJson ? { responseSchemaCanonicalJson: schemaState.responseSchemaCanonicalJson } : {},
23
+ ...schemaState.payloadSchemaCanonicalJson ? { payloadSchemaCanonicalJson: schemaState.payloadSchemaCanonicalJson } : {},
24
+ ...schemaState.payloadSchemaHash ? { payloadSchemaHash: schemaState.payloadSchemaHash } : {},
25
+ ...schemaState.responseSchemaHash ? { responseSchemaHash: schemaState.responseSchemaHash } : {}
26
+ },
27
+ ..."payload" in request && request.payload !== void 0 ? { payload: request.payload } : {}
28
+ };
29
+ }
30
+ var interruptRequestFactories = /* @__PURE__ */ new WeakMap();
31
+ var interruptRequestInputs = /* @__PURE__ */ new WeakMap();
32
+ /**
33
+ * Returns the schema input captured for a newly emitted request. This is
34
+ * internal because continuation state can cross a client boundary and must be
35
+ * parsed again when it returns to the server.
36
+ */
37
+ function getInterruptRequestInput(request) {
38
+ const input = interruptRequestInputs.get(request);
39
+ if (!input) throw new TypeError("Interrupt request input is unavailable.");
40
+ return input;
41
+ }
42
+ /**
43
+ * Rebuild a request from a persisted display payload that has already passed
44
+ * the definition's payload schema. This is internal because callers must not
45
+ * bypass public input validation for new requests.
46
+ */
47
+ function rehydrateInterruptRequest(definition, input) {
48
+ const factory = interruptRequestFactories.get(definition);
49
+ if (!factory) throw new TypeError("Interrupt definition request factory is unavailable.");
50
+ return factory(input, true);
51
+ }
52
+ function schemaJson(schema, name) {
53
+ if (!isStandardJSONSchema(schema)) throw new TypeError(`${name} must be a Standard Schema with a JSON Schema converter.`);
54
+ try {
55
+ const exported = schema["~standard"].jsonSchema.input({ target: "draft-07" });
56
+ if (exported === void 0) throw new TypeError("The exported schema is undefined.");
57
+ if (typeof exported === "function") throw new TypeError("The exported schema must not be a function.");
58
+ if (Array.isArray(exported)) throw new TypeError("The exported schema must be a plain JSON object.");
59
+ if (!exported || typeof exported !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(exported))) throw new TypeError("The exported schema must be a plain JSON object.");
60
+ const converted = {};
61
+ for (const [key, value] of Object.entries(exported)) if (key !== "$schema") converted[key] = value;
62
+ return {
63
+ json: converted,
64
+ canonicalJson: canonicalInterruptJson(converted)
65
+ };
66
+ } catch (error) {
67
+ throw new TypeError(`${name} could not export compatible JSON Schema: ${error instanceof Error ? error.message : String(error)}`);
68
+ }
69
+ }
70
+ /** Same hash the producer stamps on a first-party generic binding. */
71
+ function hashInterruptDefinitionSchema(schema) {
72
+ return digestInterruptJson(schemaJson(schema, "Interrupt schema").canonicalJson);
73
+ }
74
+ function validateJson(value, label) {
75
+ try {
76
+ canonicalInterruptJson(value);
77
+ } catch (error) {
78
+ throw new TypeError(`${label} must be JSON-compatible: ${error instanceof Error ? error.message : String(error)}`);
79
+ }
80
+ }
81
+ function validateNonEmptyString(value, label) {
82
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${label} must be a non-empty string.`);
83
+ return value;
84
+ }
85
+ function validateExpiresAt(value) {
86
+ if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) throw new TypeError("Interrupt expiresAt must be a valid date string.");
87
+ return value;
88
+ }
89
+ function isPromiseLike(value) {
90
+ return value !== null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
91
+ }
92
+ function parseInterruptPayload(schema, value) {
93
+ if (!isStandardSchema(schema)) return value;
94
+ const result = schema["~standard"].validate(value);
95
+ if (isPromiseLike(result)) throw new TypeError("Interrupt payloadSchema validation must be synchronous.");
96
+ if (result.issues !== void 0) throw new TypeError(`Interrupt payload is invalid: ${result.issues.map((issue) => issue.message).join(" ")}`);
97
+ return result.value;
98
+ }
99
+ function defineInterrupt(options) {
100
+ validateNonEmptyString(options.id, "Interrupt definition id");
101
+ const responseJson = options.responseSchema !== void 0 ? schemaJson(options.responseSchema, "responseSchema") : void 0;
102
+ const hasPayloadSchema = Object.prototype.hasOwnProperty.call(options, "payloadSchema");
103
+ const payloadJson = hasPayloadSchema ? schemaJson(options.payloadSchema, "payloadSchema") : void 0;
104
+ const schemaState = {
105
+ ...responseJson ? {
106
+ responseSchemaCanonicalJson: responseJson.canonicalJson,
107
+ responseSchemaHash: digestInterruptJson(responseJson.canonicalJson)
108
+ } : {},
109
+ ...payloadJson ? {
110
+ payloadSchemaCanonicalJson: payloadJson.canonicalJson,
111
+ payloadSchemaHash: digestInterruptJson(payloadJson.canonicalJson)
112
+ } : {}
113
+ };
114
+ const definition = {
115
+ id: options.id,
116
+ payloadSchema: options.payloadSchema,
117
+ responseSchema: options.responseSchema,
118
+ interrupt(input) {
119
+ return createRequest(input, false);
120
+ }
121
+ };
122
+ const parsePayload = (payload) => {
123
+ const payloadSchema = options.payloadSchema;
124
+ if (payloadSchema === void 0) throw new TypeError("This interrupt definition does not accept a payload.");
125
+ return parseInterruptPayload(payloadSchema, payload);
126
+ };
127
+ const createRequest = (input, payloadIsParsed) => {
128
+ for (const key of Object.keys(input)) if (![
129
+ "key",
130
+ "payload",
131
+ "reason",
132
+ "message",
133
+ "expiresAt"
134
+ ].includes(key)) throw new TypeError(`Interrupt input field ${key} is not allowed.`);
135
+ const key = validateNonEmptyString(input.key, "Interrupt key");
136
+ const reason = validateNonEmptyString(input.reason, "Interrupt reason");
137
+ const message = validateNonEmptyString(input.message, "Interrupt message");
138
+ if ("payload" in input) {
139
+ if (!hasPayloadSchema) throw new TypeError("This interrupt definition does not accept a payload.");
140
+ if (input.payload !== void 0) validateJson(input.payload, "Interrupt payload");
141
+ }
142
+ const parsedPayload = "payload" in input ? payloadIsParsed ? input.payload : parsePayload(input.payload) : void 0;
143
+ const payload = parsedPayload === void 0 ? void 0 : cloneAndDeepFreezeJson(parsedPayload);
144
+ const expiresAt = input.expiresAt === void 0 ? void 0 : validateExpiresAt(input.expiresAt);
145
+ const request = Object.freeze({
146
+ definition,
147
+ key,
148
+ ...hasPayloadSchema && payload !== void 0 ? { payload } : {},
149
+ reason,
150
+ message,
151
+ ...expiresAt !== void 0 ? { expiresAt } : {}
152
+ });
153
+ if (!payloadIsParsed) interruptRequestInputs.set(request, cloneAndDeepFreezeJson({
154
+ key,
155
+ reason,
156
+ message,
157
+ ...expiresAt !== void 0 ? { expiresAt } : {},
158
+ ...parsedPayload !== void 0 ? { payload: parsedPayload } : {}
159
+ }));
160
+ return request;
161
+ };
162
+ definitionSchemaState.set(definition, schemaState);
163
+ interruptRequestFactories.set(definition, createRequest);
164
+ return Object.freeze(definition);
165
+ }
166
+ //#endregion
167
+ export { INTERRUPT_BINDING_KIND, INTERRUPT_PAYLOAD_METADATA_KEY, createInterruptBinding, defineInterrupt, getInterruptRequestInput, hashInterruptDefinitionSchema, rehydrateInterruptRequest };
168
+
169
+ //# sourceMappingURL=interrupt-definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interrupt-definition.js","names":[],"sources":["../../src/interrupt-definition.ts"],"sourcesContent":["import type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n} from '@standard-schema/spec'\nimport {\n canonicalInterruptJson,\n cloneAndDeepFreezeJson,\n digestInterruptJson,\n} from './interrupt-serialization'\nimport {\n isStandardSchema,\n isStandardJSONSchema,\n} from './activities/chat/tools/schema-converter'\nimport { INTERRUPT_BINDING_VERSION } from './interrupts'\n\nexport const INTERRUPT_PAYLOAD_METADATA_KEY =\n 'tanstack:interruptPayload' as const\nexport const INTERRUPT_BINDING_KIND = 'generic' as const\n\ntype PortableSchema =\n | StandardJSONSchemaV1<any, any>\n | StandardSchemaV1<any, any>\n\ntype InferSchemaOutput<TSchema> =\n TSchema extends StandardSchemaV1<any, infer TOutput>\n ? TOutput\n : TSchema extends StandardJSONSchemaV1<any, infer TOutput>\n ? TOutput\n : never\ntype InferSchemaInput<TSchema> =\n TSchema extends StandardSchemaV1<infer TInput, any>\n ? TInput\n : TSchema extends StandardJSONSchemaV1<infer TInput, any>\n ? TInput\n : never\ntype DefinitionSchemaState = {\n responseSchemaCanonicalJson?: string\n responseSchemaHash?: string\n payloadSchemaCanonicalJson?: string\n payloadSchemaHash?: string\n}\nconst definitionSchemaState = new WeakMap<object, DefinitionSchemaState>()\n\nexport interface InterruptDefinitionOptions<\n TId extends string,\n TPayloadSchema extends PortableSchema | undefined,\n TResponseSchema extends PortableSchema | undefined,\n> {\n id: TId\n payloadSchema?: TPayloadSchema\n responseSchema?: TResponseSchema\n}\n\nexport interface InterruptBindingDescriptor {\n v: typeof INTERRUPT_BINDING_VERSION\n kind: typeof INTERRUPT_BINDING_KIND\n definitionId: string\n key: string\n threadId?: string\n interruptedRunId?: string\n generation?: number\n batchIndex?: number\n responseSchemaCanonicalJson?: string\n payloadSchemaCanonicalJson?: string\n payloadSchemaHash?: string\n responseSchemaHash?: string\n}\n\nexport interface InterruptPreEmissionData {\n descriptor: InterruptBindingDescriptor\n payload?: unknown\n}\n\ntype InterruptInput<\n TPayloadSchema extends PortableSchema | undefined,\n TPayload = unknown,\n> = {\n key: string\n reason: string\n message: string\n expiresAt?: string\n} & ([TPayloadSchema] extends [undefined] ? {} : { payload?: TPayload })\n\ntype GenericInterruptRequestBase<\n TDefinition extends InterruptDefinition<any, any, any, any>,\n> = {\n readonly definition: TDefinition\n readonly key: string\n readonly reason: string\n readonly message: string\n readonly expiresAt?: string\n}\n\ntype GenericInterruptRequestFor<\n TDefinition extends InterruptDefinition<any, any, any, any>,\n TPayloadSchema extends PortableSchema | undefined,\n TPayload,\n> = GenericInterruptRequestBase<TDefinition> &\n ([TPayloadSchema] extends [undefined]\n ? {}\n : { readonly payload: TPayload | undefined })\n\nexport type GenericInterruptRequest<\n TDefinition extends InterruptDefinition<any, any, any, any>,\n> = [TDefinition] extends [never]\n ? never\n : TDefinition extends InterruptDefinition<\n any,\n infer TPayloadSchema,\n any,\n infer TPayload\n >\n ? GenericInterruptRequestFor<TDefinition, TPayloadSchema, TPayload>\n : GenericInterruptRequestBase<TDefinition>\n\ntype InterruptInputKey = 'key' | 'reason' | 'message' | 'expiresAt' | 'payload'\ntype RejectUnexpectedInputKeys<TInput> =\n Exclude<keyof TInput, InterruptInputKey> extends never\n ? unknown\n : { [K in Exclude<keyof TInput, InterruptInputKey>]: never }\ntype RejectUnexpectedPayload<TInput> = 'payload' extends keyof TInput\n ? { payload: never }\n : unknown\ntype ValidInterruptInput<\n TInput,\n TPayloadSchema extends PortableSchema | undefined,\n TPayload = unknown,\n> =\n TInput extends InterruptInput<TPayloadSchema, TPayload>\n ? RejectUnexpectedInputKeys<TInput> &\n ([TPayloadSchema] extends [undefined]\n ? RejectUnexpectedPayload<TInput>\n : unknown)\n : never\n\n/**\n * Extracting a class method preserves the intentional bivariant assignment\n * behavior of the public `interrupt` callback without exposing a method\n * signature in an interface.\n */\ndeclare abstract class InterruptRequestMethodSignature<\n TId extends string,\n TPayloadSchema extends PortableSchema | undefined,\n TResponseSchema extends PortableSchema | undefined,\n TPayload,\n TPayloadInput,\n> {\n abstract call<TInput>(\n input: TInput & ValidInterruptInput<TInput, TPayloadSchema, TPayloadInput>,\n ): GenericInterruptRequestFor<\n InterruptDefinition<\n TId,\n TPayloadSchema,\n TResponseSchema,\n TPayload,\n TPayloadInput\n >,\n TPayloadSchema,\n TPayload\n >\n}\n\ntype InterruptRequestMethod<\n TId extends string,\n TPayloadSchema extends PortableSchema | undefined,\n TResponseSchema extends PortableSchema | undefined,\n TPayload,\n TPayloadInput,\n> = InterruptRequestMethodSignature<\n TId,\n TPayloadSchema,\n TResponseSchema,\n TPayload,\n TPayloadInput\n>['call']\n\ntype DefinedInterruptDefinition<\n TId extends string,\n TPayloadSchema extends PortableSchema | undefined,\n TResponseSchema extends PortableSchema | undefined,\n TPayload = unknown,\n TPayloadInput = TPayload,\n> = Omit<\n InterruptDefinition<\n TId,\n TPayloadSchema,\n TResponseSchema,\n TPayload,\n TPayloadInput\n >,\n 'interrupt'\n> & {\n interrupt: InterruptRequestMethod<\n TId,\n TPayloadSchema,\n TResponseSchema,\n TPayload,\n TPayloadInput\n >\n}\n\nexport interface InterruptDefinition<\n TId extends string,\n TPayloadSchema extends PortableSchema | undefined,\n TResponseSchema extends PortableSchema | undefined,\n TPayload = unknown,\n TPayloadInput = TPayload,\n> {\n readonly id: TId\n readonly payloadSchema: TPayloadSchema\n readonly responseSchema: TResponseSchema\n interrupt: InterruptRequestMethod<\n TId,\n TPayloadSchema,\n TResponseSchema,\n TPayload,\n TPayloadInput\n >\n}\n\nexport function createInterruptBinding(\n request: GenericInterruptRequest<InterruptDefinition<any, any, any, any>>,\n fields: Pick<\n InterruptBindingDescriptor,\n 'threadId' | 'interruptedRunId' | 'generation' | 'batchIndex'\n > = {},\n): InterruptPreEmissionData {\n const schemaState = definitionSchemaState.get(request.definition)\n if (!schemaState) {\n throw new TypeError('Interrupt definition schema state is unavailable.')\n }\n const { threadId, interruptedRunId, generation, batchIndex } = fields\n return {\n descriptor: {\n v: INTERRUPT_BINDING_VERSION,\n kind: INTERRUPT_BINDING_KIND,\n definitionId: request.definition.id,\n key: request.key,\n ...(threadId !== undefined ? { threadId } : {}),\n ...(interruptedRunId !== undefined ? { interruptedRunId } : {}),\n ...(generation !== undefined ? { generation } : {}),\n ...(batchIndex !== undefined ? { batchIndex } : {}),\n ...(schemaState.responseSchemaCanonicalJson\n ? {\n responseSchemaCanonicalJson:\n schemaState.responseSchemaCanonicalJson,\n }\n : {}),\n ...(schemaState.payloadSchemaCanonicalJson\n ? { payloadSchemaCanonicalJson: schemaState.payloadSchemaCanonicalJson }\n : {}),\n ...(schemaState.payloadSchemaHash\n ? { payloadSchemaHash: schemaState.payloadSchemaHash }\n : {}),\n ...(schemaState.responseSchemaHash\n ? { responseSchemaHash: schemaState.responseSchemaHash }\n : {}),\n },\n ...('payload' in request && request.payload !== undefined\n ? { payload: request.payload }\n : {}),\n }\n}\n\ntype ParsedInterruptInput = {\n key: string\n reason: string\n message: string\n expiresAt?: string\n payload?: unknown\n}\n\ntype InterruptRequestFactory = (\n input: ParsedInterruptInput,\n payloadIsParsed: boolean,\n) => GenericInterruptRequest<InterruptDefinition<any, any, any, any>>\n\nconst interruptRequestFactories = new WeakMap<object, InterruptRequestFactory>()\nconst interruptRequestInputs = new WeakMap<\n object,\n Readonly<ParsedInterruptInput>\n>()\n\n/**\n * Returns the schema input captured for a newly emitted request. This is\n * internal because continuation state can cross a client boundary and must be\n * parsed again when it returns to the server.\n */\nexport function getInterruptRequestInput(\n request: GenericInterruptRequest<InterruptDefinition<any, any, any, any>>,\n): Readonly<ParsedInterruptInput> {\n const input = interruptRequestInputs.get(request)\n if (!input) {\n throw new TypeError('Interrupt request input is unavailable.')\n }\n return input\n}\n\n/**\n * Rebuild a request from a persisted display payload that has already passed\n * the definition's payload schema. This is internal because callers must not\n * bypass public input validation for new requests.\n */\nexport function rehydrateInterruptRequest(\n definition: InterruptDefinition<any, any, any, any>,\n input: ParsedInterruptInput,\n): GenericInterruptRequest<InterruptDefinition<any, any, any, any>> {\n const factory = interruptRequestFactories.get(definition)\n if (!factory) {\n throw new TypeError('Interrupt definition request factory is unavailable.')\n }\n return factory(input, true)\n}\n\ninterface CanonicalSchemaJson {\n json: Record<string, unknown>\n canonicalJson: string\n}\n\nfunction schemaJson(schema: unknown, name: string): CanonicalSchemaJson {\n if (!isStandardJSONSchema(schema)) {\n throw new TypeError(\n `${name} must be a Standard Schema with a JSON Schema converter.`,\n )\n }\n try {\n const exported = schema['~standard'].jsonSchema.input({\n target: 'draft-07',\n })\n if (exported === undefined) {\n throw new TypeError('The exported schema is undefined.')\n }\n if (typeof exported === 'function') {\n throw new TypeError('The exported schema must not be a function.')\n }\n if (Array.isArray(exported)) {\n throw new TypeError('The exported schema must be a plain JSON object.')\n }\n if (\n !exported ||\n typeof exported !== 'object' ||\n ![Object.prototype, null].includes(Object.getPrototypeOf(exported))\n ) {\n throw new TypeError('The exported schema must be a plain JSON object.')\n }\n const converted: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(exported)) {\n if (key !== '$schema') converted[key] = value\n }\n const canonicalJson = canonicalInterruptJson(converted)\n return { json: converted, canonicalJson }\n } catch (error) {\n throw new TypeError(\n `${name} could not export compatible JSON Schema: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n}\n\n/** Same hash the producer stamps on a first-party generic binding. */\nexport function hashInterruptDefinitionSchema(schema: unknown): string {\n return digestInterruptJson(\n schemaJson(schema, 'Interrupt schema').canonicalJson,\n )\n}\n\nfunction validateJson(value: unknown, label: string): void {\n try {\n canonicalInterruptJson(value)\n } catch (error) {\n throw new TypeError(\n `${label} must be JSON-compatible: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n}\n\nfunction validateNonEmptyString(value: unknown, label: string): string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new TypeError(`${label} must be a non-empty string.`)\n }\n return value\n}\n\nfunction validateExpiresAt(value: unknown): string {\n if (typeof value !== 'string' || !Number.isFinite(Date.parse(value))) {\n throw new TypeError('Interrupt expiresAt must be a valid date string.')\n }\n return value\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n 'then' in value &&\n typeof value.then === 'function'\n )\n}\n\nfunction parseInterruptPayload(\n schema: PortableSchema,\n value: unknown,\n): unknown {\n if (!isStandardSchema(schema)) return value\n const result = schema['~standard'].validate(value)\n if (isPromiseLike(result)) {\n throw new TypeError(\n 'Interrupt payloadSchema validation must be synchronous.',\n )\n }\n if (result.issues !== undefined) {\n throw new TypeError(\n `Interrupt payload is invalid: ${result.issues.map((issue) => issue.message).join(' ')}`,\n )\n }\n return result.value\n}\n\nexport function defineInterrupt<\n const TId extends string,\n const TPayloadSchema extends PortableSchema,\n const TResponseSchema extends PortableSchema,\n>(options: {\n id: TId\n payloadSchema: TPayloadSchema\n responseSchema: TResponseSchema\n}): DefinedInterruptDefinition<\n TId,\n TPayloadSchema,\n TResponseSchema,\n InferSchemaOutput<TPayloadSchema>,\n InferSchemaInput<TPayloadSchema>\n>\nexport function defineInterrupt<\n const TId extends string,\n const TPayloadSchema extends PortableSchema,\n>(options: {\n id: TId\n payloadSchema: TPayloadSchema\n responseSchema?: never\n}): DefinedInterruptDefinition<\n TId,\n TPayloadSchema,\n undefined,\n InferSchemaOutput<TPayloadSchema>,\n InferSchemaInput<TPayloadSchema>\n>\nexport function defineInterrupt<\n const TId extends string,\n const TResponseSchema extends PortableSchema,\n>(options: {\n id: TId\n responseSchema: TResponseSchema\n payloadSchema?: never\n}): DefinedInterruptDefinition<\n TId,\n undefined,\n TResponseSchema,\n undefined,\n undefined\n>\nexport function defineInterrupt<\n const TId extends string,\n const TPayloadSchema extends PortableSchema | undefined,\n const TResponseSchema extends PortableSchema | undefined,\n>(\n options: InterruptDefinitionOptions<TId, TPayloadSchema, TResponseSchema>,\n): InterruptDefinition<\n TId,\n TPayloadSchema,\n TResponseSchema,\n InferSchemaOutput<TPayloadSchema>,\n InferSchemaInput<TPayloadSchema>\n> {\n validateNonEmptyString(options.id, 'Interrupt definition id')\n const hasResponseSchema = options.responseSchema !== undefined\n const responseJson = hasResponseSchema\n ? schemaJson(options.responseSchema, 'responseSchema')\n : undefined\n const hasPayloadSchema = Object.prototype.hasOwnProperty.call(\n options,\n 'payloadSchema',\n )\n const payloadJson = hasPayloadSchema\n ? schemaJson(options.payloadSchema, 'payloadSchema')\n : undefined\n const schemaState: DefinitionSchemaState = {\n ...(responseJson\n ? {\n responseSchemaCanonicalJson: responseJson.canonicalJson,\n responseSchemaHash: digestInterruptJson(responseJson.canonicalJson),\n }\n : {}),\n ...(payloadJson\n ? {\n payloadSchemaCanonicalJson: payloadJson.canonicalJson,\n payloadSchemaHash: digestInterruptJson(payloadJson.canonicalJson),\n }\n : {}),\n }\n const definition = {\n id: options.id,\n payloadSchema: options.payloadSchema,\n responseSchema: options.responseSchema,\n interrupt(input: InterruptInput<TPayloadSchema>) {\n return createRequest(input, false)\n },\n } as InterruptDefinition<\n TId,\n TPayloadSchema,\n TResponseSchema,\n InferSchemaOutput<TPayloadSchema>,\n InferSchemaInput<TPayloadSchema>\n >\n const parsePayload = (payload: unknown): unknown => {\n const payloadSchema = options.payloadSchema\n if (payloadSchema === undefined) {\n throw new TypeError(\n 'This interrupt definition does not accept a payload.',\n )\n }\n return parseInterruptPayload(payloadSchema, payload)\n }\n const createRequest: InterruptRequestFactory = (input, payloadIsParsed) => {\n for (const key of Object.keys(input)) {\n if (!['key', 'payload', 'reason', 'message', 'expiresAt'].includes(key)) {\n throw new TypeError(`Interrupt input field ${key} is not allowed.`)\n }\n }\n const key = validateNonEmptyString(input.key, 'Interrupt key')\n const reason = validateNonEmptyString(input.reason, 'Interrupt reason')\n const message = validateNonEmptyString(input.message, 'Interrupt message')\n if ('payload' in input) {\n if (!hasPayloadSchema) {\n throw new TypeError(\n 'This interrupt definition does not accept a payload.',\n )\n }\n if (input.payload !== undefined) {\n validateJson(input.payload, 'Interrupt payload')\n }\n }\n const parsedPayload =\n 'payload' in input\n ? payloadIsParsed\n ? input.payload\n : parsePayload(input.payload)\n : undefined\n const payload =\n parsedPayload === undefined\n ? undefined\n : cloneAndDeepFreezeJson(parsedPayload)\n const expiresAt =\n input.expiresAt === undefined\n ? undefined\n : validateExpiresAt(input.expiresAt)\n const request = Object.freeze({\n definition,\n key,\n ...(hasPayloadSchema && payload !== undefined ? { payload } : {}),\n reason,\n message,\n ...(expiresAt !== undefined ? { expiresAt } : {}),\n })\n if (!payloadIsParsed) {\n interruptRequestInputs.set(\n request,\n cloneAndDeepFreezeJson({\n key,\n reason,\n message,\n ...(expiresAt !== undefined ? { expiresAt } : {}),\n ...(parsedPayload !== undefined ? { payload: parsedPayload } : {}),\n }),\n )\n }\n return request\n }\n definitionSchemaState.set(definition, schemaState)\n interruptRequestFactories.set(definition, createRequest)\n return Object.freeze(definition)\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { InterruptBinding, InterruptSubmissionError, ItemInterruptErrorCode, UnopenedInterruptBinding } from './interrupts.js';
2
2
  import { ChatMiddlewareConfig, ChatResumeToolState } from './activities/chat/middleware/types.js';
3
+ import { GenericInterruptRequest, InterruptDefinition } from './interrupt-definition.js';
3
4
  import { Interrupt, RunAgentResumeItem } from './types.js';
4
5
  /**
5
6
  * The `Interrupt.metadata` key under which this package's resume binding
@@ -17,6 +18,8 @@ export interface PendingInterruptResumeRecord {
17
18
  interruptId: string;
18
19
  payload: unknown;
19
20
  binding: InterruptBinding;
21
+ /** Present for a first-party generic interrupt. */
22
+ genericRequest?: GenericInterruptRequest<InterruptDefinition<any, any, any, any>>;
20
23
  }
21
24
  export interface ValidateInterruptResumeBatchInput {
22
25
  threadId: string;
@@ -61,6 +61,17 @@ async function validateSchemaValue(input) {
61
61
  function runtimeTool(tools, name) {
62
62
  return tools.find((tool) => tool.name === name);
63
63
  }
64
+ async function parseSchemaValue(schema, value) {
65
+ if (!isStandardSchema(schema)) return {
66
+ success: true,
67
+ data: value
68
+ };
69
+ const result = await validateWithStandardSchema(schema, value);
70
+ return result.success ? {
71
+ success: true,
72
+ data: result.data
73
+ } : { success: false };
74
+ }
64
75
  function descriptorResponseSchema(record) {
65
76
  return objectValue(record.payload)?.responseSchema;
66
77
  }
@@ -82,7 +93,9 @@ async function pushSchemaIssues(input) {
82
93
  }
83
94
  function validateDescriptorSchema(input, record, binding, errors) {
84
95
  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" }));
96
+ const responseSchemaHash = binding.responseSchemaHash;
97
+ if (schema === void 0 && responseSchemaHash === void 0) return;
98
+ if (schema === void 0 || responseSchemaHash === void 0 || schemaHash(schema) !== responseSchemaHash) errors.push(interruptItemError(input, record.interruptId, "invalid-response-schema", `Interrupt ${record.interruptId} response schema no longer matches its binding.`, { source: "server" }));
86
99
  return schema;
87
100
  }
88
101
  /**
@@ -107,17 +120,24 @@ async function validateInterruptResumeBatch(input) {
107
120
  if (!resumeById.has(entry.interruptId)) resumeById.set(entry.interruptId, entry);
108
121
  }
109
122
  for (const [interruptId, count] of counts) if (count > 1) group(interruptId).push(interruptItemError(input, interruptId, "conflict", `Interrupt ${interruptId} has duplicate resume entries.`));
123
+ const pendingGenerics = input.pending.filter((record) => record.binding.kind === "generic");
124
+ const genericBatchSatisfied = pendingGenerics.length > 0 && pendingGenerics.every((record) => resumeById.has(record.interruptId));
110
125
  let incomplete = false;
111
126
  for (const record of input.pending) {
112
127
  const errors = group(record.interruptId);
113
128
  const entry = resumeById.get(record.interruptId);
114
129
  const binding = record.binding;
115
130
  if (!entry) {
131
+ if (genericBatchSatisfied && binding.kind === "client-tool-execution") continue;
116
132
  incomplete = true;
117
133
  errors.push(interruptItemError(input, record.interruptId, "unknown-interrupt", `Missing resume entry for interrupt ${record.interruptId}.`));
118
134
  }
119
135
  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" }));
136
+ if (binding.expiresAt !== void 0) {
137
+ const expiresAt = Date.parse(binding.expiresAt);
138
+ if (!Number.isFinite(expiresAt)) errors.push(interruptItemError(input, record.interruptId, "invalid-payload", `Interrupt ${record.interruptId} has an invalid expiresAt.`, { source: "server" }));
139
+ else if (expiresAt <= (input.now ?? Date.now())) errors.push(interruptItemError(input, record.interruptId, "expired", `Interrupt ${record.interruptId} has expired.`, { source: "server" }));
140
+ }
121
141
  const responseSchema = validateDescriptorSchema(input, record, binding, errors);
122
142
  if (!entry) continue;
123
143
  const entryStatus = entry.status;
@@ -126,9 +146,23 @@ async function validateInterruptResumeBatch(input) {
126
146
  continue;
127
147
  }
128
148
  if (binding.kind === "generic") {
149
+ const genericRequest = record.genericRequest;
150
+ if (genericRequest !== void 0) {
151
+ const batchIndex = binding.batchIndex;
152
+ if (binding.definitionId !== genericRequest.definition.id || binding.key !== genericRequest.key || binding.interruptId !== record.interruptId || batchIndex === void 0 || !Number.isInteger(batchIndex) || batchIndex < 0) errors.push(interruptItemError(input, record.interruptId, "stale", `Generic interrupt ${record.interruptId} has stale definition metadata.`, { source: "server" }));
153
+ }
129
154
  if (entry.status === "cancelled") {
130
155
  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({
156
+ } else if (genericRequest !== void 0) await pushSchemaIssues({
157
+ request: input,
158
+ errors,
159
+ interruptId: record.interruptId,
160
+ schema: genericRequest.definition.responseSchema,
161
+ value: entry.payload,
162
+ code: "invalid-payload",
163
+ label: `Interrupt ${record.interruptId} payload is invalid`
164
+ });
165
+ else if (responseSchema !== void 0) await pushSchemaIssues({
132
166
  request: input,
133
167
  errors,
134
168
  interruptId: record.interruptId,
@@ -272,13 +306,27 @@ async function validateInterruptResumeBatch(input) {
272
306
  if (!entry) continue;
273
307
  const binding = record.binding;
274
308
  if (binding.kind === "generic") {
275
- genericInterrupts.set(record.interruptId, entry.status === "resolved" ? {
309
+ if (entry.status !== "resolved") {
310
+ genericInterrupts.set(record.interruptId, {
311
+ interruptId: record.interruptId,
312
+ status: "cancelled"
313
+ });
314
+ continue;
315
+ }
316
+ if (record.genericRequest === void 0) {
317
+ genericInterrupts.set(record.interruptId, {
318
+ interruptId: record.interruptId,
319
+ status: "resolved",
320
+ payload: entry.payload
321
+ });
322
+ continue;
323
+ }
324
+ const parsed = await parseSchemaValue(record.genericRequest.definition.responseSchema, entry.payload);
325
+ if (!parsed.success) return { errors: [interruptItemError(input, record.interruptId, "invalid-payload", `Interrupt ${record.interruptId} payload is invalid.`)] };
326
+ genericInterrupts.set(record.interruptId, {
276
327
  interruptId: record.interruptId,
277
328
  status: "resolved",
278
- payload: entry.payload
279
- } : {
280
- interruptId: record.interruptId,
281
- status: "cancelled"
329
+ payload: parsed.data
282
330
  });
283
331
  continue;
284
332
  }
@@ -338,15 +386,28 @@ function readUnopenedInterruptBinding(descriptor) {
338
386
  const interruptId = stringField(raw, "interruptId");
339
387
  const responseSchemaHash = stringField(raw, "responseSchemaHash");
340
388
  const expiresAt = stringField(raw, "expiresAt");
341
- if (!interruptId || !responseSchemaHash) return void 0;
389
+ if (!interruptId || responseSchemaHash === "") return void 0;
390
+ if (expiresAt !== void 0 && !Number.isFinite(Date.parse(expiresAt))) return;
342
391
  const v = 1;
343
- if (kind === "generic") return {
344
- v,
345
- kind,
346
- interruptId,
347
- responseSchemaHash,
348
- ...expiresAt ? { expiresAt } : {}
349
- };
392
+ if (kind === "generic") {
393
+ const definitionId = stringField(raw, "definitionId");
394
+ const key = stringField(raw, "key");
395
+ const batchIndex = raw["batchIndex"];
396
+ const payloadSchemaHash = stringField(raw, "payloadSchemaHash");
397
+ if ((definitionId !== void 0 || key !== void 0 || batchIndex !== void 0 || payloadSchemaHash !== void 0) && (!definitionId || !key || typeof batchIndex !== "number" || !Number.isInteger(batchIndex) || batchIndex < 0)) return;
398
+ return {
399
+ v,
400
+ kind,
401
+ interruptId,
402
+ ...responseSchemaHash ? { responseSchemaHash } : {},
403
+ ...expiresAt ? { expiresAt } : {},
404
+ ...definitionId ? { definitionId } : {},
405
+ ...key ? { key } : {},
406
+ ...typeof batchIndex === "number" ? { batchIndex } : {},
407
+ ...payloadSchemaHash ? { payloadSchemaHash } : {}
408
+ };
409
+ }
410
+ if (!responseSchemaHash) return void 0;
350
411
  const toolName = stringField(raw, "toolName");
351
412
  const toolCallId = stringField(raw, "toolCallId");
352
413
  if (!toolName || !toolCallId) return void 0;
@@ -1 +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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"}
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 {\n GenericInterruptRequest,\n InterruptDefinition,\n} from './interrupt-definition'\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 /** Present for a first-party generic interrupt. */\n genericRequest?: GenericInterruptRequest<\n InterruptDefinition<any, any, any, any>\n >\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\nasync function parseSchemaValue(\n schema: unknown,\n value: unknown,\n): Promise<{ success: true; data: unknown } | { success: false }> {\n if (!isStandardSchema(schema)) return { success: true, data: value }\n const result = await validateWithStandardSchema<unknown>(schema, value)\n return result.success\n ? { success: true, data: result.data }\n : { success: false }\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 const responseSchemaHash = binding.responseSchemaHash\n if (schema === undefined && responseSchemaHash === undefined) {\n return undefined\n }\n if (\n schema === undefined ||\n responseSchemaHash === undefined ||\n schemaHash(schema) !== 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 const pendingGenerics = input.pending.filter(\n (record) => record.binding.kind === 'generic',\n )\n const genericBatchSatisfied =\n pendingGenerics.length > 0 &&\n pendingGenerics.every((record) => resumeById.has(record.interruptId))\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 // Client tools that share a generic interrupt batch wait for\n // `toolResume`. `continue` re-emits them; `cancel` / `stop` skip them.\n if (genericBatchSatisfied && binding.kind === 'client-tool-execution') {\n continue\n }\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 (binding.expiresAt !== undefined) {\n const expiresAt = Date.parse(binding.expiresAt)\n if (!Number.isFinite(expiresAt)) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} has an invalid expiresAt.`,\n { source: 'server' },\n ),\n )\n } else if (expiresAt <= (input.now ?? Date.now())) {\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\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 const genericRequest = record.genericRequest\n if (genericRequest !== undefined) {\n const batchIndex = binding.batchIndex\n if (\n binding.definitionId !== genericRequest.definition.id ||\n binding.key !== genericRequest.key ||\n binding.interruptId !== record.interruptId ||\n batchIndex === undefined ||\n !Number.isInteger(batchIndex) ||\n batchIndex < 0\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Generic interrupt ${record.interruptId} has stale definition metadata.`,\n { source: 'server' },\n ),\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 } else if (genericRequest !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: genericRequest.definition.responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Interrupt ${record.interruptId} payload is invalid`,\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 if (entry.status !== 'resolved') {\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'cancelled',\n })\n continue\n }\n if (record.genericRequest === undefined) {\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'resolved',\n payload: entry.payload,\n })\n continue\n }\n const parsed = await parseSchemaValue(\n record.genericRequest.definition.responseSchema,\n entry.payload,\n )\n if (!parsed.success) {\n return {\n errors: [\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} payload is invalid.`,\n ),\n ],\n }\n }\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'resolved',\n payload: parsed.data,\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 if (expiresAt !== undefined && !Number.isFinite(Date.parse(expiresAt))) {\n return undefined\n }\n const v = INTERRUPT_BINDING_VERSION\n if (kind === 'generic') {\n const definitionId = stringField(raw, 'definitionId')\n const key = stringField(raw, 'key')\n const batchIndex = raw['batchIndex']\n const payloadSchemaHash = stringField(raw, 'payloadSchemaHash')\n const hasFirstPartyFields =\n definitionId !== undefined ||\n key !== undefined ||\n batchIndex !== undefined ||\n payloadSchemaHash !== undefined\n if (\n hasFirstPartyFields &&\n (!definitionId ||\n !key ||\n typeof batchIndex !== 'number' ||\n !Number.isInteger(batchIndex) ||\n batchIndex < 0)\n ) {\n return undefined\n }\n return {\n v,\n kind,\n interruptId,\n ...(responseSchemaHash ? { responseSchemaHash } : {}),\n ...(expiresAt ? { expiresAt } : {}),\n ...(definitionId ? { definitionId } : {}),\n ...(key ? { key } : {}),\n ...(typeof batchIndex === 'number' ? { batchIndex } : {}),\n ...(payloadSchemaHash ? { payloadSchemaHash } : {}),\n }\n }\n if (!responseSchemaHash) return undefined\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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"}
@@ -48,23 +48,32 @@ interface InterruptBindingBase {
48
48
  interruptId: string;
49
49
  interruptedRunId: string;
50
50
  generation: number;
51
- responseSchemaHash: string;
52
51
  expiresAt?: string;
53
52
  }
54
- export type InterruptBinding = (InterruptBindingBase & {
53
+ interface ResponseSchemaInterruptBindingBase extends InterruptBindingBase {
54
+ responseSchemaHash: string;
55
+ }
56
+ export type InterruptBinding = (ResponseSchemaInterruptBindingBase & {
55
57
  kind: 'tool-approval';
56
58
  toolName: string;
57
59
  toolCallId: string;
58
60
  originalArgs: unknown;
59
61
  inputSchemaHash: string;
60
62
  approvalSchemaHash: string;
61
- }) | (InterruptBindingBase & {
63
+ }) | (ResponseSchemaInterruptBindingBase & {
62
64
  kind: 'client-tool-execution';
63
65
  toolName: string;
64
66
  toolCallId: string;
65
67
  outputSchemaHash: string;
66
68
  }) | (InterruptBindingBase & {
67
69
  kind: 'generic';
70
+ /** Omitted when the generic interrupt accepts an unvalidated response. */
71
+ responseSchemaHash?: string;
72
+ /** Present only for a first-party generic interrupt. */
73
+ definitionId?: string;
74
+ key?: string;
75
+ batchIndex?: number;
76
+ payloadSchemaHash?: string;
68
77
  });
69
78
  export type UnopenedInterruptBinding = InterruptBinding extends infer TBinding ? TBinding extends InterruptBinding ? Omit<TBinding, 'interruptedRunId' | 'generation'> : never : never;
70
79
  export type ToolApprovalResolution = boolean | {