@agen-ai/agent-runtime 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,12 +9,14 @@ its binding and conversation-local operations.
9
9
  The runtime depends only on `@agen-ai/agent-protocol`. It has no concept of tenants, SaaS
10
10
  workspaces, assigned users, database rows, persistence sequence, visibility, billing, host boots,
11
11
  leases, or storage policy. A host must authorize and select an instance before calling this SPI.
12
- The current coordinated deployment tuple is Agent Protocol V7, private host V15/catalog V9, and Workspaces event V9.
12
+ This source package implements Agent Protocol V8. Agent Protocol V8, private host V16/catalog V10, and Workspaces event V10.
13
+ This is intentionally one coordinated tuple rather than a deployable mixed-version graph.
13
14
 
14
15
  ## Entrypoints
15
16
 
16
17
  - `@agen-ai/agent-runtime` exports the public driver, instance, adapter, session, output,
17
- readiness, bounded-evidence, artifact-candidate, and registry APIs.
18
+ readiness, bounded-evidence, artifact-candidate, capability-bound interaction validation,
19
+ and registry APIs.
18
20
  - `@agen-ai/agent-runtime/testing` exports the deterministic fake provider and reusable
19
21
  conformance runner.
20
22
 
@@ -39,14 +41,31 @@ exactly once before returning the matching session. Capability-dependent operati
39
41
  `supported`/`unsupported` discriminants, and the runtime rejects handlers that disagree with the
40
42
  instance capability declaration.
41
43
 
44
+ V8 replaces interaction-extension booleans with cohesive capability-matched session ports:
45
+ configuration inventory and selection, typed operation inventory and invocation, managed-content
46
+ inventory, integration observation, collaboration spawn/control, and generated-resource access.
47
+ An unsupported declaration exposes exactly `{ kind: "unsupported" }`; a supported declaration must
48
+ expose exactly its typed handlers. Catalogs and results are parsed again at the runtime boundary,
49
+ bounded by the declaration, and correlated to the offered revision and caller-owned identity.
50
+
42
51
  Approval continuations are refusal-first. Before delegating to the candidate adapter, the
43
52
  validated session proves that the request is still pending and unexpired and that a selected
44
53
  `optionId` was offered by that exact request. Provider-emitted approval requests must correlate to
45
54
  a live item or exact proposed-plan artifact, and every option must fit an advertised
46
- persistence/scope mode.
55
+ persistence/scope mode. Item identities are monotonic throughout a turn, including every request
56
+ continuation: an adapter cannot restart an observed identity, change its kind, erase prior progress
57
+ through an unknown-status update, regress it from in-progress to pending, or revive it after a
58
+ terminal event or status. An `item.completed` event must carry `completed`, `failed`, or `canceled`
59
+ status. Completion-only snapshots remain valid when no earlier lifecycle event was observed.
47
60
 
48
61
  The host should serialize mutating operations for a given session. Separate session objects may
49
62
  run concurrently, so provider implementations must isolate their conversation-local state.
63
+
64
+ Materialization-scoped context usage remains monotonic only within one native provider process. A
65
+ provider that replaces that process emits a `process.started` lifecycle output as the explicit
66
+ boundary before reporting usage from the replacement. Validation then clears only the
67
+ `materialization` occupancy, cumulative counters, and compaction allowance; logical `session`
68
+ measurements remain continuous.
50
69
  `runTurn` and `resolveRequest` both preserve consumer backpressure: the provider does not resume
51
70
  until the consumer requests the next output. Each stream must end at a completed turn or exactly
52
71
  one newly pending request. If a consumer abandons a stream, a provider throws, or either stream
@@ -77,6 +96,14 @@ provider-delegated steering failures throw `AgentProviderDelegatedOperationError
77
96
  cause and explicit started-execution evidence so a host can retire the unusable session. Platform
78
97
  scheduling and provider-native queue modes are intentionally outside this SPI.
79
98
 
99
+ Configuration selection, operation invocation, and collaboration mutation use the same execution
100
+ receipt rule: stale or malformed input fails before provider delegation, while any failure after
101
+ the candidate reports execution start is wrapped as `AgentProviderDelegatedOperationError` and
102
+ makes the session unusable. The start boundary commits only after the host observer returns
103
+ successfully; an observer failure remains a pre-delegation error and leaves the session reusable.
104
+ Operation, collaboration, and generated-resource observations also
105
+ enforce correlation, immutable identity, declared bounds, and forward-only lifecycle transitions.
106
+
80
107
  ## Minimal driver
81
108
 
82
109
  ```ts
@@ -136,13 +163,13 @@ turn/request ordering, request resolution, steering, interruption, configuration
136
163
  close, and idempotent disposal. Unsupported operations must remain explicit discriminants and
137
164
  must not expose handlers.
138
165
 
139
- The package is at `0.2.1` while the public SPI is being proven with external adapters. Minor
140
- releases may include breaking changes during this beta period, and those changes will be called out
141
- in the release notes.
166
+ The package is at `0.2.3` while the public SPI is being proven with external adapters. Pre-1.0
167
+ releases may include breaking changes during this beta period, and those changes are called out in
168
+ the release notes.
142
169
 
143
- The public runtime implements Agent Protocol V7. Its package version remains independent of private
144
- host, catalog, persistence, and member-projection versions. Version `0.2.0` directly replaces the
145
- V6/`0.1.0` API; see the repository `MIGRATING-TO-0.2.md` guide.
170
+ The public runtime implements Agent Protocol V8. Its package version remains independent of private
171
+ host, catalog, persistence, and member-projection versions. V8 directly replaces V7; there is no
172
+ runtime shim or dual-protocol session surface.
146
173
 
147
174
  Run the clean packed-consumer proof before any release:
148
175
 
@@ -1,31 +1,26 @@
1
1
  import { throwAgentProviderContractError } from "./contractErrors.js";
2
2
  function assertAgentSessionConfigurationSupported(capabilities, configuration) {
3
- const entries = Object.entries(configuration.values);
4
3
  if (capabilities.configuration.kind === "managed") {
5
- if (entries.length === 0) return;
4
+ if (configuration.kind === "managed") return;
6
5
  throwAgentProviderContractError(
7
6
  capabilities.providerKey,
8
7
  "configuration_key_unsupported",
9
- "Managed provider configuration values must be empty."
8
+ "Managed providers require a managed session configuration."
10
9
  );
11
10
  }
12
- const fields = new Map(
13
- capabilities.configuration.fields.map((field) => [field.key, field])
14
- );
15
- for (const [key, value] of entries) {
16
- const field = fields.get(key);
17
- if (!field) {
18
- throwAgentProviderContractError(
19
- capabilities.providerKey,
20
- "configuration_key_unsupported",
21
- "Provider configuration contains a key not declared by its capabilities."
22
- );
23
- }
24
- if (typeof value !== "string" || !field.optionIds.includes(value)) {
11
+ if (configuration.kind !== "selected" || configuration.selections.length > capabilities.configuration.maxFields) {
12
+ throwAgentProviderContractError(
13
+ capabilities.providerKey,
14
+ "configuration_key_unsupported",
15
+ "Selectable providers require a bounded selected session configuration."
16
+ );
17
+ }
18
+ for (const selection of configuration.selections) {
19
+ if (!capabilities.configuration.fieldKinds.includes(selection.value.fieldKind)) {
25
20
  throwAgentProviderContractError(
26
21
  capabilities.providerKey,
27
22
  "configuration_value_unsupported",
28
- "Provider configuration contains an option not declared by its capabilities."
23
+ "Provider configuration contains a field kind outside its declared capability."
29
24
  );
30
25
  }
31
26
  }
@@ -1,7 +1,7 @@
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", "output_session_mismatch", "output_turn_mismatch", "output_authentication_attempt_mismatch", "output_capability_mismatch", "input_capability_mismatch", "invalid_turn_sequence", "request_resolution_mismatch", "configuration_key_unsupported", "configuration_value_unsupported", "request_pending"];
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"];
3
3
  export type AgentProviderContractErrorCode = (typeof AGENT_PROVIDER_CONTRACT_ERROR_CODES)[number];
4
- export type AgentProviderDelegatedOperation = "steer_turn";
4
+ export type AgentProviderDelegatedOperation = "steer_turn" | "invoke_operation" | "apply_configuration" | "spawn_collaboration" | "control_collaboration";
5
5
  export declare class AgentProviderContractError extends Error {
6
6
  readonly providerKey: AgentProviderKey;
7
7
  readonly code: AgentProviderContractErrorCode;
@@ -13,9 +13,15 @@ const AGENT_PROVIDER_CONTRACT_ERROR_CODES = [
13
13
  "concurrent_turn",
14
14
  "active_turn_mismatch",
15
15
  "invalid_operation_result",
16
+ "invalid_inventory",
17
+ "invalid_collaboration_transition",
18
+ "input_operation_mismatch",
16
19
  "output_session_mismatch",
17
20
  "output_turn_mismatch",
18
21
  "output_authentication_attempt_mismatch",
22
+ "output_operation_mismatch",
23
+ "output_collaboration_mismatch",
24
+ "output_resource_mismatch",
19
25
  "output_capability_mismatch",
20
26
  "input_capability_mismatch",
21
27
  "invalid_turn_sequence",
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from "./artifacts.js";
3
3
  export * from "./contractErrors.js";
4
4
  export * from "./evidence.js";
5
5
  export * from "./foundation.js";
6
+ export * from "./interactionValidation.js";
6
7
  export * from "./outputs.js";
7
8
  export * from "./providerCatalog.js";
8
9
  export * from "./providerDriver.js";
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export * from "./artifacts.js";
3
3
  export * from "./contractErrors.js";
4
4
  export * from "./evidence.js";
5
5
  export * from "./foundation.js";
6
+ export * from "./interactionValidation.js";
6
7
  export * from "./outputs.js";
7
8
  export * from "./providerCatalog.js";
8
9
  export * from "./providerDriver.js";
@@ -0,0 +1,23 @@
1
+ import { type AgentCapabilities, type AgentCollaborationNode, type AgentConfigurationCatalog, type AgentGeneratedResourceDescriptor, type AgentIntegrationCatalog, type AgentManagedContentCatalog, type AgentOperationCatalog, type AgentOperationInvocation, type AgentOperationDescriptor, type AgentOperationResult, type AgentProviderKey } from "@agen-ai/agent-protocol";
2
+ export declare function validateAgentOperationCatalogForCapabilities(capabilities: AgentCapabilities, candidate: unknown): AgentOperationCatalog;
3
+ export declare function validateAgentManagedContentCatalogForCapabilities(capabilities: AgentCapabilities, candidate: unknown): AgentManagedContentCatalog;
4
+ export declare function validateAgentConfigurationCatalogForCapabilities(capabilities: AgentCapabilities, candidate: unknown): AgentConfigurationCatalog;
5
+ export declare function validateAgentIntegrationCatalogForCapabilities(capabilities: AgentCapabilities, candidate: unknown): AgentIntegrationCatalog;
6
+ export declare function validateAgentOperationResultForInvocation(providerKey: AgentProviderKey, descriptor: AgentOperationDescriptor, invocation: AgentOperationInvocation, candidate: unknown): AgentOperationResult;
7
+ export declare function validateAgentOperationResultTransition(input: {
8
+ readonly providerKey: AgentProviderKey;
9
+ readonly candidate: AgentOperationResult;
10
+ readonly previous?: AgentOperationResult;
11
+ }): AgentOperationResult;
12
+ export declare function validateAgentCollaborationNodeForCapabilities(input: {
13
+ readonly capabilities: AgentCapabilities;
14
+ readonly candidate: unknown;
15
+ readonly previous?: AgentCollaborationNode;
16
+ }): AgentCollaborationNode;
17
+ export declare function validateAgentGeneratedResourceForCapabilities(input: {
18
+ readonly capabilities: AgentCapabilities;
19
+ readonly candidate: unknown;
20
+ readonly expectedResourceId: string;
21
+ readonly previous?: AgentGeneratedResourceDescriptor;
22
+ }): AgentGeneratedResourceDescriptor;
23
+ //# sourceMappingURL=interactionValidation.d.ts.map
@@ -0,0 +1,238 @@
1
+ import { isDeepStrictEqual } from "node:util";
2
+ import {
3
+ parseAgentCollaborationNode,
4
+ parseAgentConfigurationCatalog,
5
+ parseAgentGeneratedResourceDescriptor,
6
+ parseAgentIntegrationCatalog,
7
+ parseAgentManagedContentCatalog,
8
+ parseAgentOperationCatalog,
9
+ parseAgentOperationResultFor
10
+ } from "@agen-ai/agent-protocol";
11
+ import { throwAgentProviderContractError } from "./contractErrors.js";
12
+ function invalidInventory(providerKey, message) {
13
+ return throwAgentProviderContractError(providerKey, "invalid_inventory", message);
14
+ }
15
+ function validateAgentOperationCatalogForCapabilities(capabilities, candidate) {
16
+ let catalog;
17
+ try {
18
+ catalog = parseAgentOperationCatalog(candidate);
19
+ } catch {
20
+ return invalidInventory(capabilities.providerKey, "Provider returned an invalid operation catalog.");
21
+ }
22
+ const capability = capabilities.operations;
23
+ if (capability.kind !== "supported" || catalog.operations.length > capability.maxOperations || catalog.operations.some(
24
+ (operation) => !capability.operationKinds.includes(operation.kind) || !capability.executionModes.includes(operation.executionMode) || operation.fields.length > capability.maxFieldsPerOperation || operation.fields.some(
25
+ (field) => !capability.fieldKinds.includes(field.fieldKind)
26
+ )
27
+ )) {
28
+ return invalidInventory(
29
+ capabilities.providerKey,
30
+ "Operation catalog exceeds the provider's declared capability."
31
+ );
32
+ }
33
+ return catalog;
34
+ }
35
+ function validateAgentManagedContentCatalogForCapabilities(capabilities, candidate) {
36
+ let catalog;
37
+ try {
38
+ catalog = parseAgentManagedContentCatalog(candidate);
39
+ } catch {
40
+ return invalidInventory(capabilities.providerKey, "Provider returned an invalid managed-content catalog.");
41
+ }
42
+ const capability = capabilities.managedContent;
43
+ if (capability.kind !== "supported" || catalog.entries.length > capability.maxEntries || catalog.entries.some(
44
+ (entry) => !capability.contentKinds.includes(entry.kind)
45
+ )) {
46
+ return invalidInventory(
47
+ capabilities.providerKey,
48
+ "Managed-content catalog exceeds the provider's declared capability."
49
+ );
50
+ }
51
+ return catalog;
52
+ }
53
+ function validateAgentConfigurationCatalogForCapabilities(capabilities, candidate) {
54
+ let catalog;
55
+ try {
56
+ catalog = parseAgentConfigurationCatalog(candidate);
57
+ } catch {
58
+ return invalidInventory(capabilities.providerKey, "Provider returned an invalid configuration catalog.");
59
+ }
60
+ const capability = capabilities.configuration;
61
+ if (capability.kind !== "selectable" || catalog.fields.length > capability.maxFields || catalog.fields.some(
62
+ (field) => !capability.fieldKinds.includes(field.fieldKind)
63
+ )) {
64
+ return invalidInventory(
65
+ capabilities.providerKey,
66
+ "Configuration catalog exceeds the provider's declared capability."
67
+ );
68
+ }
69
+ return catalog;
70
+ }
71
+ function validateAgentIntegrationCatalogForCapabilities(capabilities, candidate) {
72
+ let catalog;
73
+ try {
74
+ catalog = parseAgentIntegrationCatalog(candidate);
75
+ } catch {
76
+ return invalidInventory(capabilities.providerKey, "Provider returned an invalid integration catalog.");
77
+ }
78
+ const capability = capabilities.integrations;
79
+ if (capability.kind !== "supported" || catalog.integrations.length > capability.maxIntegrations || catalog.integrations.some(
80
+ (integration) => !capability.integrationKinds.includes(integration.kind) || integration.servers.length > capability.maxServersPerIntegration || integration.servers.some(
81
+ (server) => server.tools.length > capability.maxToolsPerServer || server.resources.length > capability.maxResourcesPerServer
82
+ )
83
+ )) {
84
+ return invalidInventory(
85
+ capabilities.providerKey,
86
+ "Integration catalog exceeds the provider's declared capability."
87
+ );
88
+ }
89
+ return catalog;
90
+ }
91
+ function validateAgentOperationResultForInvocation(providerKey, descriptor, invocation, candidate) {
92
+ try {
93
+ return parseAgentOperationResultFor(descriptor, invocation, candidate);
94
+ } catch {
95
+ return throwAgentProviderContractError(
96
+ providerKey,
97
+ "invalid_operation_result",
98
+ "Provider returned an invalid or uncorrelated operation result."
99
+ );
100
+ }
101
+ }
102
+ const OPERATION_RESULT_TRANSITIONS = {
103
+ accepted: ["accepted", "waiting_for_request", "completed", "failed", "canceled"],
104
+ waiting_for_request: ["waiting_for_request", "accepted", "completed", "failed", "canceled"],
105
+ completed: ["completed"],
106
+ failed: ["failed"],
107
+ canceled: ["canceled"]
108
+ };
109
+ function validateAgentOperationResultTransition(input) {
110
+ if (input.previous !== void 0 && !OPERATION_RESULT_TRANSITIONS[input.previous.status].includes(
111
+ input.candidate.status
112
+ )) {
113
+ return throwAgentProviderContractError(
114
+ input.providerKey,
115
+ "invalid_operation_result",
116
+ "Provider returned an invalid operation lifecycle transition."
117
+ );
118
+ }
119
+ if (input.previous !== void 0 && ["completed", "failed", "canceled"].includes(input.previous.status) && JSON.stringify(input.previous) !== JSON.stringify(input.candidate)) {
120
+ return throwAgentProviderContractError(
121
+ input.providerKey,
122
+ "invalid_operation_result",
123
+ "Provider changed a terminal operation result."
124
+ );
125
+ }
126
+ return input.candidate;
127
+ }
128
+ const COLLABORATION_TRANSITIONS = {
129
+ queued: ["queued", "starting", "running", "waiting", "completed", "failed", "canceled"],
130
+ starting: ["starting", "running", "waiting", "completed", "failed", "canceled"],
131
+ running: ["running", "waiting", "completed", "failed", "canceled"],
132
+ waiting: ["waiting", "running", "completed", "failed", "canceled"],
133
+ completed: ["completed"],
134
+ failed: ["failed"],
135
+ canceled: ["canceled"]
136
+ };
137
+ function collaborationUsageIsMonotonic(previous, next) {
138
+ if (previous.kind === "unavailable") return true;
139
+ if (next.kind === "unavailable") return false;
140
+ const fields = [
141
+ "inputTokens",
142
+ "outputTokens",
143
+ "reasoningTokens",
144
+ "totalTokens",
145
+ "modelCalls"
146
+ ];
147
+ return fields.every(
148
+ (field) => previous[field] === void 0 || next[field] !== void 0 && next[field] >= previous[field]
149
+ );
150
+ }
151
+ function validateAgentCollaborationNodeForCapabilities(input) {
152
+ let node;
153
+ try {
154
+ node = parseAgentCollaborationNode(input.candidate);
155
+ } catch {
156
+ return throwAgentProviderContractError(
157
+ input.capabilities.providerKey,
158
+ "output_collaboration_mismatch",
159
+ "Provider returned an invalid collaboration node."
160
+ );
161
+ }
162
+ const capability = input.capabilities.collaboration;
163
+ if (capability.kind !== "supported" || !capability.roles.includes(node.role)) {
164
+ return throwAgentProviderContractError(
165
+ input.capabilities.providerKey,
166
+ "output_capability_mismatch",
167
+ "Provider returned collaboration state outside its declared capability."
168
+ );
169
+ }
170
+ if (input.previous !== void 0 && !COLLABORATION_TRANSITIONS[input.previous.status].includes(node.status)) {
171
+ return throwAgentProviderContractError(
172
+ input.capabilities.providerKey,
173
+ "invalid_collaboration_transition",
174
+ "Provider returned an invalid collaboration lifecycle transition."
175
+ );
176
+ }
177
+ if (input.previous !== void 0 && Date.parse(node.updatedAt) === Date.parse(input.previous.updatedAt) && !isDeepStrictEqual(node, input.previous)) {
178
+ return throwAgentProviderContractError(
179
+ input.capabilities.providerKey,
180
+ "invalid_collaboration_transition",
181
+ "Provider changed collaboration state without advancing its observation timestamp."
182
+ );
183
+ }
184
+ if (input.previous !== void 0 && (node.collaborationId !== input.previous.collaborationId || node.rootCollaborationId !== input.previous.rootCollaborationId || node.parentCollaborationId !== input.previous.parentCollaborationId || node.role !== input.previous.role || node.title !== input.previous.title || node.objective !== input.previous.objective || node.createdAt !== input.previous.createdAt || Date.parse(node.updatedAt) < Date.parse(input.previous.updatedAt) || !collaborationUsageIsMonotonic(input.previous.usage, node.usage) || input.previous.terminalAt !== void 0 && node.terminalAt !== input.previous.terminalAt || input.previous.closedAt !== void 0 && node.closedAt !== input.previous.closedAt || input.previous.outcome !== void 0 && !isDeepStrictEqual(node.outcome, input.previous.outcome) || input.previous.artifactIds !== void 0 && !isDeepStrictEqual(node.artifactIds, input.previous.artifactIds) || input.previous.resourceIds !== void 0 && !isDeepStrictEqual(node.resourceIds, input.previous.resourceIds))) {
185
+ return throwAgentProviderContractError(
186
+ input.capabilities.providerKey,
187
+ "output_collaboration_mismatch",
188
+ "Provider changed immutable collaboration identity."
189
+ );
190
+ }
191
+ return node;
192
+ }
193
+ function validateAgentGeneratedResourceForCapabilities(input) {
194
+ let resource;
195
+ try {
196
+ resource = parseAgentGeneratedResourceDescriptor(input.candidate);
197
+ } catch {
198
+ return throwAgentProviderContractError(
199
+ input.capabilities.providerKey,
200
+ "output_resource_mismatch",
201
+ "Provider returned an invalid generated resource."
202
+ );
203
+ }
204
+ const capability = input.capabilities.generatedResources;
205
+ if (capability.kind !== "supported" || resource.resourceId !== input.expectedResourceId || !capability.resourceKinds.includes(resource.kind) || resource.byteSize !== void 0 && resource.byteSize > capability.maxBytesPerResource) {
206
+ return throwAgentProviderContractError(
207
+ input.capabilities.providerKey,
208
+ "output_resource_mismatch",
209
+ "Provider returned a generated resource outside its declared capability or correlation."
210
+ );
211
+ }
212
+ if (input.previous !== void 0) {
213
+ const transitions = {
214
+ pending: ["pending", "available", "unavailable", "expired"],
215
+ available: ["available", "expired"],
216
+ unavailable: ["unavailable", "expired"],
217
+ expired: ["expired"]
218
+ };
219
+ if (resource.kind !== input.previous.kind || resource.displayName !== input.previous.displayName || !isDeepStrictEqual(resource.producer, input.previous.producer) || resource.createdAt !== input.previous.createdAt || !transitions[input.previous.status].includes(resource.status) || input.previous.status !== "pending" && input.previous.status === resource.status && !isDeepStrictEqual(resource, input.previous)) {
220
+ return throwAgentProviderContractError(
221
+ input.capabilities.providerKey,
222
+ "output_resource_mismatch",
223
+ "Provider changed immutable resource identity or returned an invalid lifecycle transition."
224
+ );
225
+ }
226
+ }
227
+ return resource;
228
+ }
229
+ export {
230
+ validateAgentCollaborationNodeForCapabilities,
231
+ validateAgentConfigurationCatalogForCapabilities,
232
+ validateAgentGeneratedResourceForCapabilities,
233
+ validateAgentIntegrationCatalogForCapabilities,
234
+ validateAgentManagedContentCatalogForCapabilities,
235
+ validateAgentOperationCatalogForCapabilities,
236
+ validateAgentOperationResultForInvocation,
237
+ validateAgentOperationResultTransition
238
+ };
@@ -1,4 +1,4 @@
1
- import { type AgentCapabilities, type AgentProviderKey, type AgentSessionId, type AgentTurnId } from "@agen-ai/agent-protocol";
1
+ import { type AgentCapabilities, type AgentCollaborationId, type AgentGeneratedResourceId, type AgentOperationInvocationId, type AgentProviderKey, type AgentSessionId, type AgentTurnId } from "@agen-ai/agent-protocol";
2
2
  import { type AgentProviderOutput } from "./outputs.js";
3
3
  import type { AgentProviderOperationResult } from "./sessions.js";
4
4
  export interface AgentProviderOutputValidationContext {
@@ -7,6 +7,9 @@ export interface AgentProviderOutputValidationContext {
7
7
  readonly sessionId?: AgentSessionId;
8
8
  readonly turnId?: AgentTurnId;
9
9
  readonly authenticationAttemptId?: string;
10
+ readonly operationInvocationId?: AgentOperationInvocationId;
11
+ readonly collaborationId?: AgentCollaborationId;
12
+ readonly generatedResourceId?: AgentGeneratedResourceId;
10
13
  }
11
14
  export declare function validateAgentProviderOutputForContext(candidate: AgentProviderOutput, context: AgentProviderOutputValidationContext): AgentProviderOutput;
12
15
  export declare function validateAgentProviderOperationResult(candidate: AgentProviderOperationResult, context: AgentProviderOutputValidationContext): AgentProviderOperationResult;
@@ -17,9 +17,9 @@ function isItemKindCapabilitySupported(capabilities, itemKind) {
17
17
  case "file_change":
18
18
  return capabilities.output.fileChanges === "structured";
19
19
  case "mcp_tool_call":
20
- return capabilities.interactionExtensions.mcp;
20
+ return capabilities.integrations.kind === "supported";
21
21
  case "collaboration_tool_call":
22
- return capabilities.interactionExtensions.subagents;
22
+ return capabilities.collaboration.kind === "supported";
23
23
  case "user_message":
24
24
  case "assistant_message":
25
25
  case "reasoning":
@@ -102,9 +102,20 @@ function isEventCapabilitySupported(capabilities, event) {
102
102
  return capabilities.output.artifactKinds.includes(
103
103
  event.payload.artifact.kind
104
104
  );
105
+ case "operation.updated":
106
+ return capabilities.operations.kind === "supported";
107
+ case "collaboration.updated":
108
+ return capabilities.collaboration.kind === "supported" && capabilities.collaboration.roles.includes(event.payload.node.role);
109
+ case "resource.updated":
110
+ return capabilities.generatedResources.kind === "supported" && capabilities.generatedResources.resourceKinds.includes(
111
+ event.payload.resource.kind
112
+ ) && (event.payload.resource.byteSize === void 0 || event.payload.resource.byteSize <= capabilities.generatedResources.maxBytesPerResource);
105
113
  case "request.opened":
106
- return event.payload.request.requestKind === "approval" ? isApprovalRequestCapabilitySupported(capabilities, event) : capabilities.requests.elicitation.kind === "structured" || capabilities.requests.elicitation.kind === "text" && event.payload.request.fields.every(
107
- (field) => field.kind === "text"
114
+ if (event.payload.request.requestKind === "approval") {
115
+ return isApprovalRequestCapabilitySupported(capabilities, event);
116
+ }
117
+ return capabilities.requests.elicitation.kind === "supported" && event.payload.request.fields.length <= capabilities.requests.elicitation.maxFields && event.payload.request.fields.every(
118
+ (field) => capabilities.requests.elicitation.kind === "supported" && capabilities.requests.elicitation.fieldKinds.includes(field.kind) && (field.sensitivity === "ordinary" || capabilities.requests.elicitation.sensitiveFields)
108
119
  );
109
120
  case "context.usage.updated":
110
121
  return isContextUsageCapabilitySupported(capabilities, event);
@@ -139,6 +150,33 @@ function assertOutputCapability(context, output) {
139
150
  `Provider ${context.providerKey} emitted ${output.event.type} without advertising support.`
140
151
  );
141
152
  }
153
+ if (output.kind === "event" && output.event.type === "operation.updated") {
154
+ if (context.operationInvocationId !== void 0 && output.event.payload.result.invocationId !== context.operationInvocationId) {
155
+ throwAgentProviderContractError(
156
+ context.providerKey,
157
+ "output_operation_mismatch",
158
+ `Provider ${context.providerKey} emitted an update for another operation invocation.`
159
+ );
160
+ }
161
+ }
162
+ if (output.kind === "event" && output.event.type === "collaboration.updated") {
163
+ if (context.collaborationId !== void 0 && output.event.payload.node.collaborationId !== context.collaborationId) {
164
+ throwAgentProviderContractError(
165
+ context.providerKey,
166
+ "output_collaboration_mismatch",
167
+ `Provider ${context.providerKey} emitted an update for another collaboration.`
168
+ );
169
+ }
170
+ }
171
+ if (output.kind === "event" && output.event.type === "resource.updated") {
172
+ if (context.generatedResourceId !== void 0 && output.event.payload.resource.resourceId !== context.generatedResourceId) {
173
+ throwAgentProviderContractError(
174
+ context.providerKey,
175
+ "output_resource_mismatch",
176
+ `Provider ${context.providerKey} emitted an update for another generated resource.`
177
+ );
178
+ }
179
+ }
142
180
  }
143
181
  function validateAgentProviderOutputForContext(candidate, context) {
144
182
  const output = validateAgentProviderOutput(candidate);