@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
@@ -13,6 +13,11 @@ import {
13
13
  throwIfAgentOperationAborted
14
14
  } from "./foundation.js";
15
15
  import { containsAgentControlCharacter } from "./internal/controlCharacters.js";
16
+ import { withAgentSessionHostBinding } from "./hostBindings/lifetime.js";
17
+ import { invokeAgentSessionOpening } from "./hostBindings/opening.js";
18
+ import { validateAgentSessionHostBindingSupport } from "./hostBindings/validation.js";
19
+ import { createSessionInteractionOwner } from "./sessionInteractions/lifetime.js";
20
+ import { validateSessionInteractionSupport } from "./sessionInteractions/validation.js";
16
21
  import {
17
22
  validateAgentProviderOperationResult,
18
23
  validateAgentProviderOutputForContext
@@ -22,6 +27,7 @@ import {
22
27
  openIdentityCreatingAgentProviderSession,
23
28
  validateAgentProviderSession
24
29
  } from "./sessionValidation.js";
30
+ const validatedAdapters = /* @__PURE__ */ new WeakMap();
25
31
  function parseWorkingDirectory(value) {
26
32
  if (value.length < 1 || value.length > 4096 || !path.isAbsolute(value) || path.normalize(value) !== value || containsAgentControlCharacter(value)) {
27
33
  throw new TypeError(
@@ -40,8 +46,9 @@ function assertAuthenticationOutputKind(providerKey, output) {
40
46
  "Authentication may emit only authentication, lifecycle, or evidence output."
41
47
  );
42
48
  }
43
- function validateAgentProviderAdapter(capabilityInput, adapter) {
49
+ function validateAgentProviderAdapter(capabilityInput, adapterInput) {
44
50
  const capabilities = parseAgentCapabilities(capabilityInput);
51
+ const adapter = validatedAdapters.get(adapterInput) ?? adapterInput;
45
52
  if (adapter === null || typeof adapter !== "object" || typeof adapter.createSession !== "function" || adapter.resumption === null || typeof adapter.resumption !== "object" || !["supported", "unsupported"].includes(adapter.resumption.kind) || adapter.resumption.kind === "supported" && typeof adapter.resumption.resumeSession !== "function" || adapter.branching === null || typeof adapter.branching !== "object" || !["through_turn", "unsupported"].includes(adapter.branching.kind) || adapter.branching.kind === "through_turn" && typeof adapter.branching.branchSession !== "function" || adapter.authentication === null || typeof adapter.authentication !== "object" || !["supported", "unsupported"].includes(adapter.authentication.kind) || adapter.authentication.kind === "supported" && (typeof adapter.authentication.start !== "function" || typeof adapter.authentication.cancel !== "function")) {
46
53
  throwAgentProviderContractError(
47
54
  capabilities.providerKey,
@@ -57,83 +64,153 @@ function validateAgentProviderAdapter(capabilityInput, adapter) {
57
64
  );
58
65
  }
59
66
  const declaredResumption = adapter.resumption;
67
+ const sessionInteractions = validateSessionInteractionSupport(capabilities, adapter);
68
+ let hostBinding;
69
+ try {
70
+ hostBinding = validateAgentSessionHostBindingSupport(adapter.hostBinding);
71
+ } catch {
72
+ return throwAgentProviderContractError(
73
+ capabilities.providerKey,
74
+ "invalid_adapter",
75
+ "Provider declared invalid session host binding support."
76
+ );
77
+ }
60
78
  const resumption = declaredResumption.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
61
79
  kind: "supported",
62
- resumeSession: async (resumeInput) => {
63
- throwIfAgentOperationAborted(resumeInput.signal);
64
- const parsed = parseAgentSessionOpenInput({
65
- operation: "resume",
66
- sessionId: resumeInput.sessionId,
67
- binding: resumeInput.binding,
68
- configuration: resumeInput.configuration
69
- });
70
- if (parsed.operation !== "resume") {
71
- throw new TypeError("Expected a resume session input.");
72
- }
73
- assertAgentSessionConfigurationSupported(
74
- capabilities,
75
- parsed.configuration
76
- );
77
- const workingDirectory = parseWorkingDirectory(
78
- resumeInput.workingDirectory
79
- );
80
- const binding = parsed.binding;
81
- const candidate = await declaredResumption.resumeSession({
82
- sessionId: parsed.sessionId,
83
- workingDirectory,
84
- binding,
85
- configuration: parsed.configuration,
86
- ...resumeInput.signal === void 0 ? {} : { signal: resumeInput.signal }
87
- });
88
- try {
89
- return validateAgentProviderSession({
80
+ resumeSession: async (resumeInput) => withAgentSessionHostBinding({
81
+ providerKey: capabilities.providerKey,
82
+ binding: resumeInput.hostBinding,
83
+ openingInput: resumeInput,
84
+ support: hostBinding,
85
+ open: async (lease) => {
86
+ throwIfAgentOperationAborted(resumeInput.signal);
87
+ const parsed = parseAgentSessionOpenInput({
88
+ operation: "resume",
89
+ sessionId: resumeInput.sessionId,
90
+ binding: resumeInput.binding,
91
+ configuration: resumeInput.configuration
92
+ });
93
+ if (parsed.operation !== "resume") {
94
+ throw new TypeError("Expected a resume session input.");
95
+ }
96
+ assertAgentSessionConfigurationSupported(
90
97
  capabilities,
98
+ parsed.configuration
99
+ );
100
+ const workingDirectory = parseWorkingDirectory(
101
+ resumeInput.workingDirectory
102
+ );
103
+ const binding = parsed.binding;
104
+ const interactions = createSessionInteractionOwner({
105
+ providerKey: capabilities.providerKey,
91
106
  sessionId: parsed.sessionId,
92
- candidate,
93
- expectedBinding: binding
107
+ operation: "resume",
108
+ support: sessionInteractions,
109
+ ...resumeInput.interactions === void 0 ? {} : { context: resumeInput.interactions },
110
+ ...resumeInput.signal === void 0 ? {} : { signal: resumeInput.signal }
111
+ });
112
+ const candidate = await invokeAgentSessionOpening({
113
+ providerKey: capabilities.providerKey,
114
+ openingInput: resumeInput,
115
+ lease,
116
+ ...interactions === void 0 ? {} : { interactions },
117
+ open: (context) => declaredResumption.resumeSession(context),
118
+ candidateInput: {
119
+ sessionId: parsed.sessionId,
120
+ workingDirectory,
121
+ binding,
122
+ configuration: parsed.configuration,
123
+ ...lease === void 0 ? {} : { hostBinding: lease.binding },
124
+ ...interactions === void 0 ? {} : { interactions: interactions.facade },
125
+ ...(interactions?.openingSignal ?? resumeInput.signal) === void 0 ? {} : { signal: interactions?.openingSignal ?? resumeInput.signal }
126
+ }
94
127
  });
95
- } catch (error) {
96
- return closeRejectedAgentProviderSession(candidate, error);
128
+ try {
129
+ const session = validateAgentProviderSession({
130
+ capabilities,
131
+ sessionId: parsed.sessionId,
132
+ candidate,
133
+ expectedBinding: binding,
134
+ ...interactions === void 0 ? {} : { sessionInteractionOwner: interactions },
135
+ ...lease === void 0 ? {} : { hostBindingLease: lease }
136
+ });
137
+ interactions?.adopt();
138
+ return session;
139
+ } catch (error) {
140
+ return closeRejectedAgentProviderSession(
141
+ candidate,
142
+ error,
143
+ lease === void 0 ? void 0 : { providerKey: capabilities.providerKey, lease },
144
+ { providerKey: capabilities.providerKey, input: resumeInput },
145
+ interactions
146
+ );
147
+ }
97
148
  }
98
- }
149
+ })
99
150
  });
100
151
  const declaredBranching = adapter.branching;
101
152
  const branching = declaredBranching.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
102
153
  kind: "through_turn",
103
- branchSession: async (branchInput) => {
104
- throwIfAgentOperationAborted(branchInput.signal);
105
- const parsed = parseAgentSessionOpenInput({
106
- operation: "branch",
107
- sessionId: branchInput.sessionId,
108
- source: branchInput.source,
109
- configuration: branchInput.configuration
110
- });
111
- if (parsed.operation !== "branch") {
112
- throw new TypeError("Expected a branch session input.");
113
- }
114
- assertAgentSessionConfigurationSupported(
115
- capabilities,
116
- parsed.configuration
117
- );
118
- const workingDirectory = parseWorkingDirectory(
119
- branchInput.workingDirectory
120
- );
121
- const sourceBinding = parsed.source.binding;
122
- return openIdentityCreatingAgentProviderSession({
123
- capabilities,
124
- sessionId: parsed.sessionId,
125
- observer: branchInput.onBindingCreated,
126
- sourceBinding,
127
- open: (observer) => declaredBranching.branchSession({
154
+ branchSession: async (branchInput) => withAgentSessionHostBinding({
155
+ providerKey: capabilities.providerKey,
156
+ binding: branchInput.hostBinding,
157
+ openingInput: branchInput,
158
+ support: hostBinding,
159
+ open: async (lease) => {
160
+ throwIfAgentOperationAborted(branchInput.signal);
161
+ const parsed = parseAgentSessionOpenInput({
162
+ operation: "branch",
163
+ sessionId: branchInput.sessionId,
164
+ source: branchInput.source,
165
+ configuration: branchInput.configuration
166
+ });
167
+ if (parsed.operation !== "branch") {
168
+ throw new TypeError("Expected a branch session input.");
169
+ }
170
+ assertAgentSessionConfigurationSupported(
171
+ capabilities,
172
+ parsed.configuration
173
+ );
174
+ const workingDirectory = parseWorkingDirectory(
175
+ branchInput.workingDirectory
176
+ );
177
+ const sourceBinding = parsed.source.binding;
178
+ const interactions = createSessionInteractionOwner({
179
+ providerKey: capabilities.providerKey,
128
180
  sessionId: parsed.sessionId,
129
- workingDirectory,
130
- source: parsed.source,
131
- configuration: parsed.configuration,
132
- onBindingCreated: observer,
181
+ operation: "branch",
182
+ support: sessionInteractions,
183
+ ...branchInput.interactions === void 0 ? {} : { context: branchInput.interactions },
133
184
  ...branchInput.signal === void 0 ? {} : { signal: branchInput.signal }
134
- })
135
- });
136
- }
185
+ });
186
+ return openIdentityCreatingAgentProviderSession({
187
+ capabilities,
188
+ sessionId: parsed.sessionId,
189
+ observer: branchInput.onBindingCreated,
190
+ sourceBinding,
191
+ openingInput: branchInput,
192
+ ...interactions === void 0 ? {} : { sessionInteractionOwner: interactions },
193
+ ...lease === void 0 ? {} : { hostBindingLease: lease },
194
+ open: (observer) => invokeAgentSessionOpening({
195
+ providerKey: capabilities.providerKey,
196
+ openingInput: branchInput,
197
+ lease,
198
+ ...interactions === void 0 ? {} : { interactions },
199
+ open: (context) => declaredBranching.branchSession(context),
200
+ candidateInput: {
201
+ sessionId: parsed.sessionId,
202
+ workingDirectory,
203
+ source: parsed.source,
204
+ configuration: parsed.configuration,
205
+ onBindingCreated: observer,
206
+ ...lease === void 0 ? {} : { hostBinding: lease.binding },
207
+ ...interactions === void 0 ? {} : { interactions: interactions.facade },
208
+ ...(interactions?.openingSignal ?? branchInput.signal) === void 0 ? {} : { signal: interactions?.openingSignal ?? branchInput.signal }
209
+ }
210
+ })
211
+ });
212
+ }
213
+ })
137
214
  });
138
215
  const declaredAuthentication = adapter.authentication;
139
216
  const authenticationFlows = capabilities.authentication.kind === "supported" ? capabilities.authentication.flows : [];
@@ -204,38 +281,68 @@ function validateAgentProviderAdapter(capabilityInput, adapter) {
204
281
  return result;
205
282
  }
206
283
  });
207
- return Object.freeze({
208
- createSession: async (createInput) => {
209
- throwIfAgentOperationAborted(createInput.signal);
210
- const parsed = parseAgentSessionOpenInput({
211
- operation: "create",
212
- sessionId: createInput.sessionId,
213
- configuration: createInput.configuration
214
- });
215
- assertAgentSessionConfigurationSupported(
216
- capabilities,
217
- parsed.configuration
218
- );
219
- const workingDirectory = parseWorkingDirectory(
220
- createInput.workingDirectory
221
- );
222
- return openIdentityCreatingAgentProviderSession({
223
- capabilities,
224
- sessionId: parsed.sessionId,
225
- observer: createInput.onBindingCreated,
226
- open: (observer) => adapter.createSession({
284
+ const validated = Object.freeze({
285
+ hostBinding,
286
+ sessionInteractions,
287
+ createSession: async (createInput) => withAgentSessionHostBinding({
288
+ providerKey: capabilities.providerKey,
289
+ binding: createInput.hostBinding,
290
+ openingInput: createInput,
291
+ support: hostBinding,
292
+ open: async (lease) => {
293
+ throwIfAgentOperationAborted(createInput.signal);
294
+ const parsed = parseAgentSessionOpenInput({
295
+ operation: "create",
296
+ sessionId: createInput.sessionId,
297
+ configuration: createInput.configuration
298
+ });
299
+ assertAgentSessionConfigurationSupported(
300
+ capabilities,
301
+ parsed.configuration
302
+ );
303
+ const workingDirectory = parseWorkingDirectory(
304
+ createInput.workingDirectory
305
+ );
306
+ const interactions = createSessionInteractionOwner({
307
+ providerKey: capabilities.providerKey,
227
308
  sessionId: parsed.sessionId,
228
- workingDirectory,
229
- configuration: parsed.configuration,
230
- onBindingCreated: observer,
309
+ operation: "create",
310
+ support: sessionInteractions,
311
+ ...createInput.interactions === void 0 ? {} : { context: createInput.interactions },
231
312
  ...createInput.signal === void 0 ? {} : { signal: createInput.signal }
232
- })
233
- });
234
- },
313
+ });
314
+ return openIdentityCreatingAgentProviderSession({
315
+ capabilities,
316
+ sessionId: parsed.sessionId,
317
+ observer: createInput.onBindingCreated,
318
+ openingInput: createInput,
319
+ ...interactions === void 0 ? {} : { sessionInteractionOwner: interactions },
320
+ ...lease === void 0 ? {} : { hostBindingLease: lease },
321
+ open: (observer) => invokeAgentSessionOpening({
322
+ providerKey: capabilities.providerKey,
323
+ openingInput: createInput,
324
+ lease,
325
+ ...interactions === void 0 ? {} : { interactions },
326
+ open: (context) => adapter.createSession(context),
327
+ candidateInput: {
328
+ sessionId: parsed.sessionId,
329
+ workingDirectory,
330
+ configuration: parsed.configuration,
331
+ onBindingCreated: observer,
332
+ ...lease === void 0 ? {} : { hostBinding: lease.binding },
333
+ ...interactions === void 0 ? {} : { interactions: interactions.facade },
334
+ ...(interactions?.openingSignal ?? createInput.signal) === void 0 ? {} : { signal: interactions?.openingSignal ?? createInput.signal }
335
+ }
336
+ })
337
+ });
338
+ }
339
+ }),
235
340
  resumption,
236
341
  branching,
237
342
  authentication
238
343
  });
344
+ validatedAdapters.set(validated, adapter);
345
+ return validated;
239
346
  }
240
347
  export {
241
348
  validateAgentProviderAdapter
package/dist/artifacts.js CHANGED
@@ -18,7 +18,6 @@ class AgentArtifactCandidateError extends TypeError {
18
18
  this.code = code;
19
19
  this.name = "AgentArtifactCandidateError";
20
20
  }
21
- code;
22
21
  }
23
22
  function candidateError(code) {
24
23
  throw new AgentArtifactCandidateError(code);
@@ -1,11 +1,24 @@
1
1
  import type { AgentProviderKey } from "@agen-ai/agent-protocol";
2
- export declare const AGENT_PROVIDER_CONTRACT_ERROR_CODES: readonly ["capability_port_mismatch", "invalid_adapter", "invalid_session", "invalid_binding", "binding_callback_missing", "binding_callback_repeated", "binding_callback_mismatch", "resume_binding_mismatch", "branch_binding_reused", "session_closed", "session_unusable", "concurrent_turn", "active_turn_mismatch", "invalid_operation_result", "invalid_inventory", "invalid_collaboration_transition", "input_operation_mismatch", "output_session_mismatch", "output_turn_mismatch", "output_authentication_attempt_mismatch", "output_operation_mismatch", "output_collaboration_mismatch", "output_resource_mismatch", "output_capability_mismatch", "input_capability_mismatch", "invalid_turn_sequence", "request_resolution_mismatch", "configuration_key_unsupported", "configuration_value_unsupported", "request_pending"];
2
+ import type { MaybePromise } from "./foundation.js";
3
+ export declare const AGENT_PROVIDER_CONTRACT_ERROR_CODES: readonly ["capability_port_mismatch", "invalid_adapter", "invalid_session", "invalid_binding", "binding_callback_missing", "binding_callback_repeated", "binding_callback_mismatch", "resume_binding_mismatch", "branch_binding_reused", "session_closed", "session_unusable", "concurrent_turn", "active_turn_mismatch", "invalid_operation_result", "invalid_inventory", "invalid_collaboration_transition", "input_operation_mismatch", "output_session_mismatch", "output_turn_mismatch", "output_authentication_attempt_mismatch", "output_operation_mismatch", "output_collaboration_mismatch", "output_resource_mismatch", "output_capability_mismatch", "input_capability_mismatch", "invalid_turn_sequence", "request_resolution_mismatch", "configuration_key_unsupported", "configuration_value_unsupported", "request_pending", "invalid_host_binding", "host_binding_unsupported", "host_binding_reused", "host_binding_closed", "host_tool_name_conflict", "host_tool_input_invalid", "host_tool_result_invalid", "host_tool_capacity_exhausted", "invalid_session_interaction", "session_interactions_unsupported"];
3
4
  export type AgentProviderContractErrorCode = (typeof AGENT_PROVIDER_CONTRACT_ERROR_CODES)[number];
4
- export type AgentProviderDelegatedOperation = "steer_turn" | "invoke_operation" | "apply_configuration" | "spawn_collaboration" | "control_collaboration";
5
+ export type AgentProviderDelegatedOperation = "resolve_request" | "steer_turn" | "invoke_operation" | "apply_configuration" | "spawn_collaboration" | "control_collaboration";
5
6
  export declare class AgentProviderContractError extends Error {
6
7
  readonly providerKey: AgentProviderKey;
7
8
  readonly code: AgentProviderContractErrorCode;
8
- constructor(providerKey: AgentProviderKey, code: AgentProviderContractErrorCode, message: string);
9
+ constructor(providerKey: AgentProviderKey, code: AgentProviderContractErrorCode, message: string, options?: ErrorOptions);
10
+ }
11
+ export declare class AgentProviderSessionCleanupError extends AggregateError {
12
+ readonly providerKey: AgentProviderKey;
13
+ readonly retryCleanup: () => Promise<void>;
14
+ constructor(input: Readonly<{
15
+ providerKey: AgentProviderKey;
16
+ errors: readonly unknown[];
17
+ retryCleanup: () => MaybePromise<void>;
18
+ }>);
19
+ }
20
+ export declare class AgentProviderHostBindingCleanupError extends AgentProviderSessionCleanupError {
21
+ constructor(input: ConstructorParameters<typeof AgentProviderSessionCleanupError>[0]);
9
22
  }
10
23
  export declare class AgentProviderDelegatedOperationError extends Error {
11
24
  readonly providerKey: AgentProviderKey;
@@ -28,17 +28,53 @@ const AGENT_PROVIDER_CONTRACT_ERROR_CODES = [
28
28
  "request_resolution_mismatch",
29
29
  "configuration_key_unsupported",
30
30
  "configuration_value_unsupported",
31
- "request_pending"
31
+ "request_pending",
32
+ "invalid_host_binding",
33
+ "host_binding_unsupported",
34
+ "host_binding_reused",
35
+ "host_binding_closed",
36
+ "host_tool_name_conflict",
37
+ "host_tool_input_invalid",
38
+ "host_tool_result_invalid",
39
+ "host_tool_capacity_exhausted",
40
+ "invalid_session_interaction",
41
+ "session_interactions_unsupported"
32
42
  ];
33
43
  class AgentProviderContractError extends Error {
34
- constructor(providerKey, code, message) {
35
- super(message);
44
+ constructor(providerKey, code, message, options) {
45
+ super(message, options);
36
46
  this.providerKey = providerKey;
37
47
  this.code = code;
38
48
  this.name = "AgentProviderContractError";
39
49
  }
50
+ }
51
+ class AgentProviderSessionCleanupError extends AggregateError {
40
52
  providerKey;
41
- code;
53
+ retryCleanup;
54
+ constructor(input) {
55
+ super(input.errors, "Provider session cleanup remains incomplete.");
56
+ this.name = "AgentProviderSessionCleanupError";
57
+ this.providerKey = input.providerKey;
58
+ let completed = false;
59
+ let pending = null;
60
+ this.retryCleanup = () => {
61
+ if (completed) return Promise.resolve();
62
+ if (pending) return pending;
63
+ pending = Promise.resolve().then(() => input.retryCleanup()).then(() => {
64
+ completed = true;
65
+ }).finally(() => {
66
+ pending = null;
67
+ });
68
+ return pending;
69
+ };
70
+ }
71
+ }
72
+ class AgentProviderHostBindingCleanupError extends AgentProviderSessionCleanupError {
73
+ constructor(input) {
74
+ super(input);
75
+ this.name = "AgentProviderHostBindingCleanupError";
76
+ this.message = "Provider session host binding cleanup remains incomplete.";
77
+ }
42
78
  }
43
79
  class AgentProviderDelegatedOperationError extends Error {
44
80
  constructor(providerKey, operation, cause) {
@@ -50,8 +86,6 @@ class AgentProviderDelegatedOperationError extends Error {
50
86
  this.operation = operation;
51
87
  this.name = "AgentProviderDelegatedOperationError";
52
88
  }
53
- providerKey;
54
- operation;
55
89
  providerExecution = "started";
56
90
  }
57
91
  function throwAgentProviderContractError(providerKey, code, message) {
@@ -61,5 +95,7 @@ export {
61
95
  AGENT_PROVIDER_CONTRACT_ERROR_CODES,
62
96
  AgentProviderContractError,
63
97
  AgentProviderDelegatedOperationError,
98
+ AgentProviderHostBindingCleanupError,
99
+ AgentProviderSessionCleanupError,
64
100
  throwAgentProviderContractError
65
101
  };
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export { validateAgentSessionHostBinding, validateAgentHostToolInvocation, validateAgentHostToolResult } from "./validation.js";
3
+ export { AGENT_HOST_TOOL_SCHEMA_DIALECT } from "./schema.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,9 @@
1
+ export * from "./types.js";
2
+ import { validateAgentSessionHostBinding, validateAgentHostToolInvocation, validateAgentHostToolResult } from "./validation.js";
3
+ import { AGENT_HOST_TOOL_SCHEMA_DIALECT } from "./schema.js";
4
+ export {
5
+ AGENT_HOST_TOOL_SCHEMA_DIALECT,
6
+ validateAgentHostToolInvocation,
7
+ validateAgentHostToolResult,
8
+ validateAgentSessionHostBinding
9
+ };
@@ -0,0 +1,25 @@
1
+ import { type AgentProviderKey } from "@agen-ai/agent-protocol";
2
+ import { AgentProviderHostBindingCleanupError } from "../contractErrors.js";
3
+ import { type MaybePromise } from "../foundation.js";
4
+ import type { AgentProviderSession } from "../sessions.js";
5
+ import type { AgentSessionHostBinding, AgentSessionHostBindingSupport } from "./types.js";
6
+ export interface AgentHostBindingLease {
7
+ readonly binding: AgentSessionHostBinding;
8
+ readonly initialize: (support: AgentSessionHostBindingSupport) => void;
9
+ readonly stop: () => void;
10
+ readonly release: () => Promise<void>;
11
+ }
12
+ export declare function createAgentHostBindingCleanupError(input: Readonly<{
13
+ providerKey: AgentProviderKey;
14
+ lease: AgentHostBindingLease;
15
+ errors: readonly unknown[];
16
+ retryCleanup: () => MaybePromise<void>;
17
+ }>): AgentProviderHostBindingCleanupError;
18
+ export declare function withAgentSessionHostBinding(input: Readonly<{
19
+ providerKey: AgentProviderKey;
20
+ binding?: AgentSessionHostBinding;
21
+ openingInput?: object;
22
+ support: AgentSessionHostBindingSupport;
23
+ open: (lease?: AgentHostBindingLease) => MaybePromise<AgentProviderSession>;
24
+ }>): Promise<AgentProviderSession>;
25
+ //# sourceMappingURL=lifetime.d.ts.map
@@ -0,0 +1,147 @@
1
+ import { AgentProviderContractError, AgentProviderHostBindingCleanupError } from "../contractErrors.js";
2
+ import { throwIfAgentOperationAborted } from "../foundation.js";
3
+ import { associateAgentSessionCleanupError } from "../sessionCleanup.js";
4
+ import { dataRecord } from "./schema.js";
5
+ import { hostBindingEnvelope, validateAgentHostToolInvocation, validateAgentHostToolResult, validateAgentSessionHostBinding } from "./validation.js";
6
+ const claimedBindings = /* @__PURE__ */ new WeakSet();
7
+ const cleanupLeases = /* @__PURE__ */ new WeakMap();
8
+ function createAgentHostBindingCleanupError(input) {
9
+ const error = new AgentProviderHostBindingCleanupError(input);
10
+ cleanupLeases.set(error, input.lease);
11
+ return error;
12
+ }
13
+ function claimBinding(providerKey, input) {
14
+ const fail = (code, message) => {
15
+ throw new AgentProviderContractError(providerKey, code, message);
16
+ };
17
+ let original;
18
+ try {
19
+ original = hostBindingEnvelope(input);
20
+ } catch {
21
+ return fail("invalid_host_binding", "Host binding requires a valid identity and callable ownership ports.");
22
+ }
23
+ if (claimedBindings.has(original)) fail("host_binding_reused", "Host binding is already claimed by a session opening.");
24
+ claimedBindings.add(original);
25
+ const releaseCallback = original.release.bind(original);
26
+ const lifetime = new AbortController();
27
+ const invocations = /* @__PURE__ */ new Map();
28
+ let facade;
29
+ let released = false;
30
+ let releasePromise = null;
31
+ const stop = () => {
32
+ lifetime.abort(new DOMException("The host binding was closed.", "AbortError"));
33
+ };
34
+ const release = () => {
35
+ if (released) return Promise.resolve();
36
+ if (releasePromise) return releasePromise;
37
+ stop();
38
+ releasePromise = Promise.resolve().then(async () => {
39
+ await Promise.allSettled(invocations.values());
40
+ await releaseCallback();
41
+ released = true;
42
+ }).finally(() => {
43
+ releasePromise = null;
44
+ });
45
+ return releasePromise;
46
+ };
47
+ const initialize = (support) => {
48
+ if (support.kind === "unsupported") return fail("host_binding_unsupported", "Provider does not support session host bindings.");
49
+ let validated;
50
+ try {
51
+ if (original.instructions !== void 0) {
52
+ const instructions = dataRecord(original.instructions);
53
+ if (!support.instructionPlacements.includes(instructions.placement)) {
54
+ fail("host_binding_unsupported", "Provider does not support the requested instruction placement.");
55
+ }
56
+ }
57
+ validated = validateAgentSessionHostBinding({ binding: original, support });
58
+ } catch (error) {
59
+ if (error instanceof AgentProviderContractError) throw error;
60
+ return fail("invalid_host_binding", "Host binding metadata is invalid.");
61
+ }
62
+ const invoke = (input2) => {
63
+ if (lifetime.signal.aborted) fail("host_binding_closed", "Host binding no longer accepts invocations.");
64
+ let invocation;
65
+ try {
66
+ invocation = validateAgentHostToolInvocation({ binding: validated, invocation: input2 });
67
+ } catch {
68
+ return fail("host_tool_input_invalid", "Host tool invocation has invalid arguments.");
69
+ }
70
+ const { invocationId } = invocation;
71
+ throwIfAgentOperationAborted(input2.signal);
72
+ if (invocations.has(invocationId)) fail("host_tool_input_invalid", "Host tool invocation is already active.");
73
+ if (invocations.size >= 16) fail("host_tool_capacity_exhausted", "Host binding has reached its invocation limit.");
74
+ const signal = input2.signal === void 0 ? lifetime.signal : AbortSignal.any([lifetime.signal, input2.signal]);
75
+ const promise = Promise.resolve().then(async () => {
76
+ let result;
77
+ try {
78
+ throwIfAgentOperationAborted(signal);
79
+ result = await validated.invoke({ ...invocation, signal });
80
+ } catch {
81
+ return Object.freeze({ kind: "error", error: Object.freeze({
82
+ category: "unknown",
83
+ code: "host_tool_failed",
84
+ message: "The host tool did not return a result.",
85
+ recovery: Object.freeze({ kind: "unknown" })
86
+ }) });
87
+ }
88
+ try {
89
+ return validateAgentHostToolResult(result);
90
+ } catch {
91
+ return fail("host_tool_result_invalid", "Host tool returned an invalid or oversized result.");
92
+ }
93
+ }).finally(() => {
94
+ invocations.delete(invocationId);
95
+ });
96
+ invocations.set(invocationId, promise);
97
+ return promise;
98
+ };
99
+ facade = Object.freeze({
100
+ ...validated,
101
+ invoke,
102
+ release: () => fail("invalid_host_binding", "Only the session owner may release a host binding.")
103
+ });
104
+ };
105
+ return {
106
+ get binding() {
107
+ if (!facade) return fail("invalid_host_binding", "Host binding has not been initialized.");
108
+ return facade;
109
+ },
110
+ initialize,
111
+ stop,
112
+ release
113
+ };
114
+ }
115
+ async function withAgentSessionHostBinding(input) {
116
+ let lease;
117
+ try {
118
+ if (input.binding !== void 0) {
119
+ lease = claimBinding(input.providerKey, input.binding);
120
+ lease.initialize(input.support);
121
+ }
122
+ return await input.open(lease);
123
+ } catch (error) {
124
+ if (lease && error instanceof AgentProviderHostBindingCleanupError && cleanupLeases.get(error) === lease) {
125
+ throw input.openingInput ? associateAgentSessionCleanupError(error, input.openingInput) : error;
126
+ }
127
+ if (lease) {
128
+ lease.stop();
129
+ try {
130
+ await lease.release();
131
+ } catch (cleanupError) {
132
+ const retained = createAgentHostBindingCleanupError({
133
+ providerKey: input.providerKey,
134
+ lease,
135
+ errors: [error, cleanupError],
136
+ retryCleanup: lease.release
137
+ });
138
+ throw input.openingInput ? associateAgentSessionCleanupError(retained, input.openingInput) : retained;
139
+ }
140
+ }
141
+ throw error;
142
+ }
143
+ }
144
+ export {
145
+ createAgentHostBindingCleanupError,
146
+ withAgentSessionHostBinding
147
+ };
@@ -0,0 +1,14 @@
1
+ import type { AgentProviderKey } from "@agen-ai/agent-protocol";
2
+ import type { MaybePromise } from "../foundation.js";
3
+ import type { AgentProviderSession, AgentProviderSessionContext } from "../sessions.js";
4
+ import type { SessionInteractionOwner } from "../sessionInteractions/lifetime.js";
5
+ import { type AgentHostBindingLease } from "./lifetime.js";
6
+ export declare function invokeAgentSessionOpening<Input extends AgentProviderSessionContext>(input: Readonly<{
7
+ providerKey: AgentProviderKey;
8
+ openingInput: object;
9
+ candidateInput: Input;
10
+ lease: AgentHostBindingLease | undefined;
11
+ interactions?: SessionInteractionOwner;
12
+ open: (context: Input) => MaybePromise<AgentProviderSession>;
13
+ }>): Promise<AgentProviderSession>;
14
+ //# sourceMappingURL=opening.d.ts.map