@agen-ai/agent-runtime 0.3.1 → 0.4.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 (50) hide show
  1. package/README.md +288 -29
  2. package/dist/adapterValidation.d.ts +1 -1
  3. package/dist/adapterValidation.js +199 -92
  4. package/dist/artifacts.js +0 -1
  5. package/dist/contractErrors.d.ts +16 -3
  6. package/dist/contractErrors.js +42 -6
  7. package/dist/hostBindings/index.d.ts +4 -0
  8. package/dist/hostBindings/index.js +9 -0
  9. package/dist/hostBindings/lifetime.d.ts +25 -0
  10. package/dist/hostBindings/lifetime.js +147 -0
  11. package/dist/hostBindings/opening.d.ts +14 -0
  12. package/dist/hostBindings/opening.js +82 -0
  13. package/dist/hostBindings/schema.d.ts +9 -0
  14. package/dist/hostBindings/schema.js +169 -0
  15. package/dist/hostBindings/types.d.ts +71 -0
  16. package/dist/hostBindings/types.js +0 -0
  17. package/dist/hostBindings/validation.d.ts +14 -0
  18. package/dist/hostBindings/validation.js +107 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.js +7 -0
  21. package/dist/internal/objectShape.d.ts +2 -0
  22. package/dist/internal/objectShape.js +7 -0
  23. package/dist/outputValidation.js +3 -2
  24. package/dist/providerDriver.js +0 -1
  25. package/dist/providerInstanceRegistry.js +2 -1
  26. package/dist/sessionCleanup.d.ts +9 -0
  27. package/dist/sessionCleanup.js +17 -0
  28. package/dist/sessionInteractions/index.d.ts +2 -0
  29. package/dist/sessionInteractions/index.js +1 -0
  30. package/dist/sessionInteractions/lifetime.d.ts +52 -0
  31. package/dist/sessionInteractions/lifetime.js +251 -0
  32. package/dist/sessionInteractions/request.d.ts +42 -0
  33. package/dist/sessionInteractions/request.js +308 -0
  34. package/dist/sessionInteractions/types.d.ts +54 -0
  35. package/dist/sessionInteractions/types.js +10 -0
  36. package/dist/sessionInteractions/validation.d.ts +21 -0
  37. package/dist/sessionInteractions/validation.js +119 -0
  38. package/dist/sessionValidation.d.ts +15 -2
  39. package/dist/sessionValidation.js +155 -318
  40. package/dist/sessions.d.ts +31 -4
  41. package/dist/testing/conformance.d.ts +3 -3
  42. package/dist/testing/conformance.js +24 -31
  43. package/dist/testing/fakeProvider.js +59 -49
  44. package/dist/turnExecution/execution.d.ts +26 -0
  45. package/dist/turnExecution/execution.js +214 -0
  46. package/dist/turnExecution/receipts.d.ts +6 -0
  47. package/dist/turnExecution/receipts.js +39 -0
  48. package/dist/turnExecution/requests.d.ts +19 -0
  49. package/dist/turnExecution/requests.js +56 -0
  50. package/package.json +2 -2
@@ -0,0 +1,82 @@
1
+ import { AgentProviderSessionCleanupError } from "../contractErrors.js";
2
+ import { associateAgentSessionCleanupError, isAgentProviderSessionCleanupErrorFor } from "../sessionCleanup.js";
3
+ import { createAgentHostBindingCleanupError } from "./lifetime.js";
4
+ async function invokeAgentSessionOpening(input) {
5
+ if (input.interactions) return invokeInteractiveSessionOpening({ ...input, interactions: input.interactions });
6
+ try {
7
+ return await input.open(input.candidateInput);
8
+ } catch (error) {
9
+ if (!isAgentProviderSessionCleanupErrorFor(error, input.candidateInput) || error.providerKey !== input.providerKey) throw error;
10
+ input.lease?.stop();
11
+ const ownership = {
12
+ providerKey: input.providerKey,
13
+ errors: [error],
14
+ async retryCleanup() {
15
+ await error.retryCleanup();
16
+ await input.lease?.release();
17
+ }
18
+ };
19
+ const retained = input.lease ? createAgentHostBindingCleanupError({ ...ownership, lease: input.lease }) : new AgentProviderSessionCleanupError(ownership);
20
+ throw associateAgentSessionCleanupError(retained, input.openingInput);
21
+ }
22
+ }
23
+ async function invokeInteractiveSessionOpening(input) {
24
+ let actual;
25
+ try {
26
+ input.interactions.requireUsable();
27
+ actual = Promise.resolve(input.open(input.candidateInput));
28
+ } catch (cause) {
29
+ actual = Promise.reject(cause);
30
+ }
31
+ void actual.catch(() => {
32
+ });
33
+ try {
34
+ const candidate = await Promise.race([actual, input.interactions.failure.then((cause) => {
35
+ throw cause;
36
+ })]);
37
+ input.interactions.requireUsable();
38
+ return candidate;
39
+ } catch (error) {
40
+ input.interactions.stop();
41
+ input.lease?.stop();
42
+ let providerClosed = false;
43
+ let nativeCleanup;
44
+ let nativeCleanupRetained = false;
45
+ const cleanup = async () => {
46
+ let candidate;
47
+ try {
48
+ candidate = await actual;
49
+ } catch (cause) {
50
+ if (isAgentProviderSessionCleanupErrorFor(cause, input.candidateInput) && cause.providerKey === input.providerKey) {
51
+ nativeCleanup = cause;
52
+ if (!nativeCleanupRetained) {
53
+ nativeCleanupRetained = true;
54
+ throw cause;
55
+ }
56
+ }
57
+ }
58
+ if (!providerClosed) {
59
+ if (nativeCleanup) await nativeCleanup.retryCleanup();
60
+ else if (candidate) await candidate.close({ reason: "contract_rejected" });
61
+ providerClosed = true;
62
+ }
63
+ await input.interactions.join();
64
+ await input.lease?.release();
65
+ };
66
+ try {
67
+ await input.interactions.close(cleanup, false);
68
+ } catch (cleanupError) {
69
+ const ownership = {
70
+ providerKey: input.providerKey,
71
+ errors: [error, cleanupError],
72
+ retryCleanup: () => input.interactions.close(cleanup, false)
73
+ };
74
+ const retained = input.lease ? createAgentHostBindingCleanupError({ ...ownership, lease: input.lease }) : new AgentProviderSessionCleanupError(ownership);
75
+ throw associateAgentSessionCleanupError(retained, input.openingInput);
76
+ }
77
+ throw error;
78
+ }
79
+ }
80
+ export {
81
+ invokeAgentSessionOpening
82
+ };
@@ -0,0 +1,9 @@
1
+ import { type AgentJsonValue } from "@agen-ai/agent-protocol";
2
+ import type { AgentHostToolInputSchema, AgentHostToolSchema } from "./types.js";
3
+ export declare const AGENT_HOST_TOOL_SCHEMA_DIALECT: "https://json-schema.org/draft/2020-12/schema";
4
+ export declare function dataRecord(value: unknown): Record<string, unknown>;
5
+ export declare function dataArray(value: unknown, maximum: number): readonly unknown[];
6
+ export declare function exactKeys(value: Record<string, unknown>, allowed: readonly string[], required?: readonly string[]): void;
7
+ export declare function parseAgentHostToolInputSchema(input: unknown): AgentHostToolInputSchema;
8
+ export declare function matchesAgentHostToolSchema(schema: AgentHostToolSchema, value: AgentJsonValue): boolean;
9
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1,169 @@
1
+ import { agentProtocolSerializedJsonBytes } from "@agen-ai/agent-protocol";
2
+ const AGENT_HOST_TOOL_SCHEMA_DIALECT = "https://json-schema.org/draft/2020-12/schema";
3
+ function dataRecord(value) {
4
+ if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) {
5
+ throw new TypeError("Host binding data must be a plain object.");
6
+ }
7
+ const keys = Reflect.ownKeys(value);
8
+ if (keys.length > 100) throw new TypeError("Host binding objects cannot exceed 100 properties.");
9
+ const result = /* @__PURE__ */ Object.create(null);
10
+ for (const key of keys) {
11
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
12
+ if (typeof key !== "string" || !descriptor || !("value" in descriptor) || !descriptor.enumerable || ["__proto__", "constructor", "prototype"].includes(key)) {
13
+ throw new TypeError("Host binding data must contain only ordinary data properties.");
14
+ }
15
+ result[key] = descriptor.value;
16
+ }
17
+ return result;
18
+ }
19
+ function dataArray(value, maximum) {
20
+ if (!Array.isArray(value) || value.length > maximum || Reflect.ownKeys(value).length !== value.length + 1) {
21
+ throw new TypeError("Host binding arrays must be bounded and dense.");
22
+ }
23
+ const result = [];
24
+ for (let index = 0; index < value.length; index += 1) {
25
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
26
+ if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
27
+ throw new TypeError("Host binding arrays must contain ordinary data values.");
28
+ }
29
+ result.push(descriptor.value);
30
+ }
31
+ return result;
32
+ }
33
+ function exactKeys(value, allowed, required = []) {
34
+ if (Object.keys(value).some((key) => !allowed.includes(key)) || required.some((key) => !Object.hasOwn(value, key))) {
35
+ throw new TypeError("Host binding data has unexpected or missing fields.");
36
+ }
37
+ }
38
+ function integerBound(value, maximum) {
39
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > maximum) {
40
+ throw new TypeError("Tool schema limits must be bounded nonnegative integers.");
41
+ }
42
+ return value;
43
+ }
44
+ function parseAgentHostToolInputSchema(input) {
45
+ let nodes = 0;
46
+ const active = /* @__PURE__ */ new WeakSet();
47
+ const visit = (value, depth) => {
48
+ if (++nodes > 256 || depth > 8 || !value || typeof value !== "object" || active.has(value)) {
49
+ throw new TypeError("Tool schemas must be bounded and acyclic.");
50
+ }
51
+ active.add(value);
52
+ try {
53
+ const source = dataRecord(value);
54
+ if (depth === 0 && (source.$schema !== AGENT_HOST_TOOL_SCHEMA_DIALECT || source.type !== "object")) {
55
+ throw new TypeError("Tool inputs require an object schema using JSON Schema 2020-12.");
56
+ }
57
+ const keys = ["type", "description", ...depth === 0 ? ["$schema"] : []];
58
+ const result = { type: source.type };
59
+ if (depth === 0) result.$schema = AGENT_HOST_TOOL_SCHEMA_DIALECT;
60
+ if (source.description !== void 0) {
61
+ if (typeof source.description !== "string" || source.description.length > 2e3) {
62
+ throw new TypeError("Tool schema descriptions must be bounded strings.");
63
+ }
64
+ result.description = source.description;
65
+ }
66
+ switch (source.type) {
67
+ case "object": {
68
+ exactKeys(source, [...keys, "properties", "required", "additionalProperties"], ["properties", "additionalProperties"]);
69
+ if (source.additionalProperties !== false) throw new TypeError("Tool objects must reject additional properties.");
70
+ const properties = dataRecord(source.properties);
71
+ if (Object.keys(properties).length > 100) throw new TypeError("Tool objects have too many properties.");
72
+ const parsedProperties = /* @__PURE__ */ Object.create(null);
73
+ for (const [key, property] of Object.entries(properties)) {
74
+ if (key.length < 1 || key.length > 128) throw new TypeError("Tool property names must be bounded.");
75
+ parsedProperties[key] = visit(property, depth + 1);
76
+ }
77
+ result.properties = Object.freeze(parsedProperties);
78
+ result.additionalProperties = false;
79
+ if (source.required !== void 0) {
80
+ const required = dataArray(source.required, 100);
81
+ if (new Set(required).size !== required.length || required.some((key) => typeof key !== "string" || !Object.hasOwn(properties, key))) {
82
+ throw new TypeError("Required tool properties must be unique declared keys.");
83
+ }
84
+ result.required = Object.freeze([...required]);
85
+ }
86
+ break;
87
+ }
88
+ case "array": {
89
+ exactKeys(source, [...keys, "items", "minItems", "maxItems"], ["items", "maxItems"]);
90
+ const maximum = integerBound(source.maxItems, 100);
91
+ result.maxItems = maximum;
92
+ if (source.minItems !== void 0) result.minItems = integerBound(source.minItems, maximum);
93
+ result.items = visit(source.items, depth + 1);
94
+ break;
95
+ }
96
+ case "string": {
97
+ exactKeys(source, [...keys, "enum", "minLength", "maxLength"], ["maxLength"]);
98
+ const maximum = integerBound(source.maxLength, 16e3);
99
+ const minimum = source.minLength === void 0 ? 0 : integerBound(source.minLength, maximum);
100
+ result.maxLength = maximum;
101
+ if (source.minLength !== void 0) result.minLength = minimum;
102
+ if (source.enum !== void 0) {
103
+ const values = dataArray(source.enum, 100);
104
+ if (values.length === 0 || new Set(values).size !== values.length || values.some((entry) => typeof entry !== "string" || [...entry].length < minimum || [...entry].length > maximum)) {
105
+ throw new TypeError("Tool string enums must contain unique strings within their limits.");
106
+ }
107
+ result.enum = Object.freeze([...values]);
108
+ }
109
+ break;
110
+ }
111
+ case "integer":
112
+ case "number": {
113
+ exactKeys(source, [...keys, "minimum", "maximum"]);
114
+ for (const key of ["minimum", "maximum"]) {
115
+ const bound = source[key];
116
+ if (bound === void 0) continue;
117
+ if (typeof bound !== "number" || !Number.isFinite(bound) || source.type === "integer" && !Number.isSafeInteger(bound)) {
118
+ throw new TypeError("Tool numeric limits must be finite and type-correct.");
119
+ }
120
+ result[key] = bound;
121
+ }
122
+ if (typeof source.minimum === "number" && typeof source.maximum === "number" && source.minimum > source.maximum) {
123
+ throw new TypeError("Tool numeric limits must be ordered.");
124
+ }
125
+ break;
126
+ }
127
+ case "boolean":
128
+ case "null":
129
+ exactKeys(source, keys);
130
+ break;
131
+ default:
132
+ throw new TypeError("Tool schema type is unsupported.");
133
+ }
134
+ return Object.freeze(result);
135
+ } finally {
136
+ active.delete(value);
137
+ }
138
+ };
139
+ const schema = visit(input, 0);
140
+ if (agentProtocolSerializedJsonBytes(schema) > 8192) {
141
+ throw new TypeError("Tool schemas cannot exceed 8 KiB.");
142
+ }
143
+ return schema;
144
+ }
145
+ function matchesAgentHostToolSchema(schema, value) {
146
+ switch (schema.type) {
147
+ case "object":
148
+ return value !== null && typeof value === "object" && !Array.isArray(value) && (schema.required ?? []).every((key) => Object.hasOwn(value, key)) && Object.entries(value).every(([key, entry]) => Object.hasOwn(schema.properties, key) && matchesAgentHostToolSchema(schema.properties[key], entry));
149
+ case "array":
150
+ return Array.isArray(value) && value.length >= (schema.minItems ?? 0) && value.length <= schema.maxItems && value.every((entry) => matchesAgentHostToolSchema(schema.items, entry));
151
+ case "string":
152
+ return typeof value === "string" && [...value].length >= (schema.minLength ?? 0) && [...value].length <= schema.maxLength && (schema.enum === void 0 || schema.enum.includes(value));
153
+ case "number":
154
+ case "integer":
155
+ return typeof value === "number" && Number.isFinite(value) && (schema.type !== "integer" || Number.isSafeInteger(value)) && (schema.minimum === void 0 || value >= schema.minimum) && (schema.maximum === void 0 || value <= schema.maximum);
156
+ case "boolean":
157
+ return typeof value === "boolean";
158
+ case "null":
159
+ return value === null;
160
+ }
161
+ }
162
+ export {
163
+ AGENT_HOST_TOOL_SCHEMA_DIALECT,
164
+ dataArray,
165
+ dataRecord,
166
+ exactKeys,
167
+ matchesAgentHostToolSchema,
168
+ parseAgentHostToolInputSchema
169
+ };
@@ -0,0 +1,71 @@
1
+ import type { AgentError, AgentJsonValue } from "@agen-ai/agent-protocol";
2
+ import type { MaybePromise } from "../foundation.js";
3
+ export type AgentHostInstructionPlacement = "system" | "developer" | "tool_context";
4
+ export type AgentSessionHostBindingSupport = Readonly<{
5
+ kind: "unsupported";
6
+ }> | Readonly<{
7
+ kind: "supported";
8
+ toolTransport: "callback" | "mcp";
9
+ instructionPlacements: readonly AgentHostInstructionPlacement[];
10
+ }>;
11
+ interface AgentHostToolSchemaDescription {
12
+ readonly description?: string;
13
+ }
14
+ export interface AgentHostToolObjectSchema extends AgentHostToolSchemaDescription {
15
+ readonly type: "object";
16
+ readonly properties: Readonly<Record<string, AgentHostToolSchema>>;
17
+ readonly required?: readonly string[];
18
+ readonly additionalProperties: false;
19
+ }
20
+ export interface AgentHostToolInputSchema extends AgentHostToolObjectSchema {
21
+ readonly $schema: "https://json-schema.org/draft/2020-12/schema";
22
+ }
23
+ export type AgentHostToolSchema = AgentHostToolSchemaDescription & (AgentHostToolObjectSchema | Readonly<{
24
+ type: "array";
25
+ items: AgentHostToolSchema;
26
+ minItems?: number;
27
+ maxItems: number;
28
+ }> | Readonly<{
29
+ type: "string";
30
+ enum?: readonly string[];
31
+ minLength?: number;
32
+ maxLength: number;
33
+ }> | Readonly<{
34
+ type: "integer" | "number";
35
+ minimum?: number;
36
+ maximum?: number;
37
+ }> | Readonly<{
38
+ type: "boolean";
39
+ }> | Readonly<{
40
+ type: "null";
41
+ }>);
42
+ export interface AgentHostToolDefinition {
43
+ readonly name: string;
44
+ readonly description: string;
45
+ readonly inputSchema: AgentHostToolInputSchema;
46
+ }
47
+ export type AgentHostToolResult = Readonly<{
48
+ kind: "success";
49
+ value: AgentJsonValue;
50
+ }> | Readonly<{
51
+ kind: "error";
52
+ error: AgentError;
53
+ }>;
54
+ export interface AgentHostToolInvocation {
55
+ readonly invocationId: string;
56
+ readonly toolName: string;
57
+ readonly arguments: Readonly<Record<string, AgentJsonValue>>;
58
+ readonly signal?: AbortSignal;
59
+ }
60
+ export interface AgentSessionHostBinding {
61
+ readonly bindingId: string;
62
+ readonly tools: readonly AgentHostToolDefinition[];
63
+ readonly instructions?: Readonly<{
64
+ placement: AgentHostInstructionPlacement;
65
+ text: string;
66
+ }>;
67
+ readonly invoke: (input: AgentHostToolInvocation) => MaybePromise<AgentHostToolResult>;
68
+ readonly release: () => MaybePromise<void>;
69
+ }
70
+ export {};
71
+ //# sourceMappingURL=types.d.ts.map
File without changes
@@ -0,0 +1,14 @@
1
+ import type { AgentHostToolInvocation, AgentHostToolResult, AgentSessionHostBinding, AgentSessionHostBindingSupport } from "./types.js";
2
+ export declare function validateAgentSessionHostBindingSupport(value: unknown): AgentSessionHostBindingSupport;
3
+ export declare function hostBindingEnvelope(value: unknown): AgentSessionHostBinding;
4
+ export declare function validateAgentSessionHostBinding(input: Readonly<{
5
+ binding: AgentSessionHostBinding;
6
+ support: AgentSessionHostBindingSupport;
7
+ }>): AgentSessionHostBinding;
8
+ /** Validate transport data against an already validated binding without claiming its lifetime. */
9
+ export declare function validateAgentHostToolInvocation(input: Readonly<{
10
+ binding: Pick<AgentSessionHostBinding, "tools">;
11
+ invocation: AgentHostToolInvocation;
12
+ }>): AgentHostToolInvocation;
13
+ export declare function validateAgentHostToolResult(value: unknown): AgentHostToolResult;
14
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1,107 @@
1
+ import { agentProtocolSerializedJsonBytes, parseAgentError, parseAgentJsonValue } from "@agen-ai/agent-protocol";
2
+ import { parseAgentBoundedText, parseAgentProviderTechnicalId } from "../foundation.js";
3
+ import { dataArray, dataRecord, exactKeys, matchesAgentHostToolSchema, parseAgentHostToolInputSchema } from "./schema.js";
4
+ const placements = ["system", "developer", "tool_context"];
5
+ function validateAgentSessionHostBindingSupport(value) {
6
+ if (value === void 0) return Object.freeze({ kind: "unsupported" });
7
+ const source = dataRecord(value);
8
+ if (source.kind === "unsupported") {
9
+ exactKeys(source, ["kind"]);
10
+ return Object.freeze({ kind: "unsupported" });
11
+ }
12
+ exactKeys(source, ["kind", "toolTransport", "instructionPlacements"], ["kind", "toolTransport", "instructionPlacements"]);
13
+ const instructions = dataArray(source.instructionPlacements, 3);
14
+ if (source.kind !== "supported" || !["callback", "mcp"].includes(source.toolTransport) || new Set(instructions).size !== instructions.length || instructions.some((placement) => !placements.includes(placement))) {
15
+ throw new TypeError("Host binding support has an invalid declaration.");
16
+ }
17
+ return Object.freeze({
18
+ kind: "supported",
19
+ toolTransport: source.toolTransport,
20
+ instructionPlacements: Object.freeze([...instructions])
21
+ });
22
+ }
23
+ function hostBindingEnvelope(value) {
24
+ const source = dataRecord(value);
25
+ parseAgentProviderTechnicalId(source.bindingId, "host binding ID");
26
+ if (typeof source.invoke !== "function" || typeof source.release !== "function") {
27
+ throw new TypeError("Host bindings require invocation and release callbacks.");
28
+ }
29
+ return value;
30
+ }
31
+ function validateAgentSessionHostBinding(input) {
32
+ const binding = hostBindingEnvelope(input.binding);
33
+ const source = dataRecord(binding);
34
+ exactKeys(source, ["bindingId", "tools", "instructions", "invoke", "release"], ["bindingId", "tools", "invoke", "release"]);
35
+ const support = validateAgentSessionHostBindingSupport(input.support);
36
+ if (support.kind === "unsupported") throw new TypeError("Session host bindings are unsupported.");
37
+ const names = /* @__PURE__ */ new Set();
38
+ const tools = dataArray(source.tools, 32).map((value) => {
39
+ const tool = dataRecord(value);
40
+ exactKeys(tool, ["name", "description", "inputSchema"], ["name", "description", "inputSchema"]);
41
+ if (typeof tool.name !== "string" || !/^[A-Za-z][A-Za-z0-9_]{0,63}$/u.test(tool.name) || names.has(tool.name)) {
42
+ throw new TypeError("Tool names must be unique canonical identifiers.");
43
+ }
44
+ names.add(tool.name);
45
+ return Object.freeze({
46
+ name: tool.name,
47
+ description: parseAgentBoundedText(tool.description, "tool description", 2e3),
48
+ inputSchema: parseAgentHostToolInputSchema(tool.inputSchema)
49
+ });
50
+ });
51
+ if (tools.length === 0) throw new TypeError("Host bindings require at least one tool.");
52
+ let instructions;
53
+ if (source.instructions !== void 0) {
54
+ const instruction = dataRecord(source.instructions);
55
+ exactKeys(instruction, ["placement", "text"], ["placement", "text"]);
56
+ if (!support.instructionPlacements.includes(instruction.placement)) {
57
+ throw new TypeError("Host instruction placement is unsupported.");
58
+ }
59
+ const text = parseAgentBoundedText(instruction.text, "host instructions", 16e3);
60
+ if (new TextEncoder().encode(text).byteLength > 16384) throw new TypeError("Host instructions exceed 16 KiB.");
61
+ instructions = Object.freeze({ placement: instruction.placement, text });
62
+ }
63
+ const metadata = {
64
+ bindingId: binding.bindingId,
65
+ tools: Object.freeze(tools),
66
+ ...instructions === void 0 ? {} : { instructions }
67
+ };
68
+ if (agentProtocolSerializedJsonBytes(metadata) > 65536) {
69
+ throw new TypeError("Host binding metadata exceeds 64 KiB.");
70
+ }
71
+ return Object.freeze({ ...metadata, invoke: binding.invoke.bind(binding), release: binding.release.bind(binding) });
72
+ }
73
+ function validateAgentHostToolInvocation(input) {
74
+ const call = dataRecord(input.invocation);
75
+ exactKeys(call, ["invocationId", "toolName", "arguments", "signal"], ["invocationId", "toolName", "arguments"]);
76
+ if (call.signal !== void 0 && !(call.signal instanceof AbortSignal)) throw new TypeError("Tool cancellation requires an AbortSignal.");
77
+ const invocationId = parseAgentProviderTechnicalId(call.invocationId, "host tool invocation ID");
78
+ const tool = input.binding.tools.find((entry) => entry.name === call.toolName);
79
+ const args = parseAgentJsonValue(call.arguments);
80
+ if (!tool || !matchesAgentHostToolSchema(tool.inputSchema, args)) throw new TypeError("Tool arguments do not match its schema.");
81
+ return Object.freeze({
82
+ invocationId,
83
+ toolName: tool.name,
84
+ arguments: args,
85
+ ...call.signal === void 0 ? {} : { signal: call.signal }
86
+ });
87
+ }
88
+ function validateAgentHostToolResult(value) {
89
+ const parsed = parseAgentJsonValue(value);
90
+ const source = dataRecord(parsed);
91
+ if (source.kind === "success") {
92
+ exactKeys(source, ["kind", "value"], ["kind", "value"]);
93
+ return Object.freeze({ kind: "success", value: source.value });
94
+ }
95
+ if (source.kind === "error") {
96
+ exactKeys(source, ["kind", "error"], ["kind", "error"]);
97
+ return Object.freeze({ kind: "error", error: parseAgentError(source.error) });
98
+ }
99
+ throw new TypeError("Host tool results require success or error disposition.");
100
+ }
101
+ export {
102
+ hostBindingEnvelope,
103
+ validateAgentHostToolInvocation,
104
+ validateAgentHostToolResult,
105
+ validateAgentSessionHostBinding,
106
+ validateAgentSessionHostBindingSupport
107
+ };
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export * from "./artifacts.js";
5
5
  export * from "./contractErrors.js";
6
6
  export * from "./evidence.js";
7
7
  export * from "./foundation.js";
8
+ export * from "./hostBindings/index.js";
8
9
  export * from "./interactionValidation.js";
9
10
  export * from "./outputs.js";
10
11
  export * from "./providerCatalog.js";
@@ -12,5 +13,7 @@ export * from "./providerDriver.js";
12
13
  export * from "./providerInstanceRegistry.js";
13
14
  export * from "./readiness.js";
14
15
  export * from "./sessions.js";
16
+ export * from "./sessionInteractions/index.js";
17
+ export { createAgentProviderSessionCleanupError, isAgentProviderSessionCleanupErrorFor } from "./sessionCleanup.js";
15
18
  export * from "./text.js";
16
19
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ export * from "./artifacts.js";
5
5
  export * from "./contractErrors.js";
6
6
  export * from "./evidence.js";
7
7
  export * from "./foundation.js";
8
+ export * from "./hostBindings/index.js";
8
9
  export * from "./interactionValidation.js";
9
10
  export * from "./outputs.js";
10
11
  export * from "./providerCatalog.js";
@@ -12,4 +13,10 @@ export * from "./providerDriver.js";
12
13
  export * from "./providerInstanceRegistry.js";
13
14
  export * from "./readiness.js";
14
15
  export * from "./sessions.js";
16
+ export * from "./sessionInteractions/index.js";
17
+ import { createAgentProviderSessionCleanupError, isAgentProviderSessionCleanupErrorFor } from "./sessionCleanup.js";
15
18
  export * from "./text.js";
19
+ export {
20
+ createAgentProviderSessionCleanupError,
21
+ isAgentProviderSessionCleanupErrorFor
22
+ };
@@ -0,0 +1,2 @@
1
+ export declare function hasExactOwnKeys(candidate: object, expectedKeys: readonly string[]): boolean;
2
+ //# sourceMappingURL=objectShape.d.ts.map
@@ -0,0 +1,7 @@
1
+ function hasExactOwnKeys(candidate, expectedKeys) {
2
+ const ownKeys = Reflect.ownKeys(candidate);
3
+ return ownKeys.length === expectedKeys.length && ownKeys.every((key) => typeof key === "string" && expectedKeys.includes(key));
4
+ }
5
+ export {
6
+ hasExactOwnKeys
7
+ };
@@ -56,8 +56,8 @@ function isApprovalRequestCapabilitySupported(capabilities, event) {
56
56
  if (request.requestKind !== "approval") return false;
57
57
  const capability = capabilities.requests.approval;
58
58
  return capability.kind === "supported" && request.options.every(
59
- (option) => capability.modes.some(
60
- (mode) => mode.persistence === option.persistence && mode.scopeKinds.includes(option.scope.kind)
59
+ ({ consequence }) => consequence.kind === "provider_managed_remembrance" ? capability.providerManagedRemembrance : capability.modes.some(
60
+ (mode) => mode.persistence === consequence.persistence && mode.scopeKinds.includes(consequence.scope.kind)
61
61
  )
62
62
  );
63
63
  }
@@ -123,6 +123,7 @@ function isEventCapabilitySupported(capabilities, event) {
123
123
  case "turn.state_changed":
124
124
  case "turn.completed":
125
125
  case "progress.updated":
126
+ case "runtime.retrying":
126
127
  case "runtime.warning":
127
128
  case "runtime.error":
128
129
  case "provider.diagnostic":
@@ -11,7 +11,6 @@ class AgentProviderConfigurationError extends Error {
11
11
  this.providerKey = providerKey;
12
12
  this.name = "AgentProviderConfigurationError";
13
13
  }
14
- providerKey;
15
14
  }
16
15
  function defineAgentProviderDriver(definition) {
17
16
  const providerKey = parseAgentProviderKey(definition.providerKey);
@@ -213,7 +213,8 @@ async function materializeInstances(input) {
213
213
  providerKey: definition.providerKey,
214
214
  instanceId: definition.instanceId,
215
215
  cleanupFailureInstanceIds,
216
- message: error instanceof AgentProviderConfigurationError ? `Agent provider configuration is invalid for ${definition.instanceId}.` : `Agent provider instance ${definition.instanceId} could not be materialized.`
216
+ message: error instanceof AgentProviderConfigurationError ? `Agent provider configuration is invalid for ${definition.instanceId}.` : `Agent provider instance ${definition.instanceId} could not be materialized.`,
217
+ cause: error
217
218
  });
218
219
  }
219
220
  let managed;
@@ -0,0 +1,9 @@
1
+ import { AgentProviderSessionCleanupError } from "./contractErrors.js";
2
+ import type { AgentProviderSessionContext } from "./sessions.js";
3
+ /** Retain provider cleanup for the exact input received by a create/resume/branch port. */
4
+ export declare function createAgentProviderSessionCleanupError(input: ConstructorParameters<typeof AgentProviderSessionCleanupError>[0] & Readonly<{
5
+ openingInput: AgentProviderSessionContext;
6
+ }>): AgentProviderSessionCleanupError;
7
+ export declare function associateAgentSessionCleanupError<Error extends AgentProviderSessionCleanupError>(error: Error, openingInput: object): Error;
8
+ export declare function isAgentProviderSessionCleanupErrorFor(error: unknown, openingInput: object): error is AgentProviderSessionCleanupError;
9
+ //# sourceMappingURL=sessionCleanup.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { AgentProviderSessionCleanupError } from "./contractErrors.js";
2
+ const openingOwners = /* @__PURE__ */ new WeakMap();
3
+ function createAgentProviderSessionCleanupError(input) {
4
+ return associateAgentSessionCleanupError(new AgentProviderSessionCleanupError(input), input.openingInput);
5
+ }
6
+ function associateAgentSessionCleanupError(error, openingInput) {
7
+ openingOwners.set(error, openingInput);
8
+ return error;
9
+ }
10
+ function isAgentProviderSessionCleanupErrorFor(error, openingInput) {
11
+ return error instanceof AgentProviderSessionCleanupError && openingOwners.get(error) === openingInput;
12
+ }
13
+ export {
14
+ associateAgentSessionCleanupError,
15
+ createAgentProviderSessionCleanupError,
16
+ isAgentProviderSessionCleanupErrorFor
17
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./types.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export * from "./types.js";
@@ -0,0 +1,52 @@
1
+ import type { AgentError, AgentProviderKey, AgentSessionId } from "@agen-ai/agent-protocol";
2
+ import type { MaybePromise } from "../foundation.js";
3
+ import type { AgentSessionInteractionContext, AgentSessionInteractionOpeningOperation, AgentSessionInteractionSupport, AgentSessionInteractionTerminal } from "./types.js";
4
+ import { SessionInteractionRequest } from "./request.js";
5
+ import { type ValidatedSessionInteractionContext } from "./validation.js";
6
+ export declare function sessionInteractionError(code: string, message: string, uncertain?: boolean): AgentError;
7
+ export declare function waitForInteractionWork<Result>(work: Promise<Result>, timeoutMs: number): Promise<Result>;
8
+ export declare class SessionInteractionOwner {
9
+ readonly providerKey: AgentProviderKey;
10
+ readonly sessionId: AgentSessionId;
11
+ readonly facade: AgentSessionInteractionContext;
12
+ readonly openingSignal: AbortSignal;
13
+ readonly limits: ValidatedSessionInteractionContext["limits"];
14
+ readonly failure: Promise<unknown>;
15
+ private readonly controller;
16
+ private readonly requests;
17
+ private readonly work;
18
+ private state;
19
+ private retainedBytes;
20
+ private fatal;
21
+ private fenceCause;
22
+ private resolveFailure;
23
+ private removeOpeningAbort;
24
+ private automaticClose;
25
+ private cleanupAttempt;
26
+ private cleanupDeadline;
27
+ private cleanupComplete;
28
+ private cleanupFailure;
29
+ private adopted;
30
+ private readonly context;
31
+ constructor(providerKey: AgentProviderKey, sessionId: AgentSessionId, context: AgentSessionInteractionContext, signal?: AbortSignal);
32
+ track<Result>(promise: Promise<Result>): Promise<Result>;
33
+ get accepting(): boolean;
34
+ requireUsable(): void;
35
+ private offer;
36
+ installClose(close: () => Promise<void>): void;
37
+ adopt(): void;
38
+ fence(cause: unknown, source: SessionInteractionRequest): void;
39
+ fail(cause: unknown): void;
40
+ stop(terminal?: AgentSessionInteractionTerminal): void;
41
+ join(): Promise<void>;
42
+ close(cleanup: () => MaybePromise<void>, explicit: boolean): Promise<void>;
43
+ }
44
+ export declare function createSessionInteractionOwner(input: Readonly<{
45
+ providerKey: AgentProviderKey;
46
+ sessionId: AgentSessionId;
47
+ operation: AgentSessionInteractionOpeningOperation;
48
+ support: AgentSessionInteractionSupport;
49
+ context?: AgentSessionInteractionContext;
50
+ signal?: AbortSignal;
51
+ }>): SessionInteractionOwner | undefined;
52
+ //# sourceMappingURL=lifetime.d.ts.map