@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.
@@ -1,17 +1,33 @@
1
1
  import {
2
+ AGENT_COLLABORATION_GRAPH_LIMITS,
2
3
  matchesAgentSessionBinding,
4
+ parseAgentCollaborationControlInput,
5
+ parseAgentCollaborationSpawnInput,
6
+ parseAgentConfigurationSelectionFor,
7
+ parseAgentGeneratedResourceId,
8
+ parseAgentOperationInvocation,
9
+ parseAgentOperationInvocationFor,
3
10
  parseAgentRequestResolution,
4
11
  parseAgentRequestResolutionFor,
5
12
  parseAgentSessionBinding,
6
- parseAgentSessionConfiguration,
7
13
  parseAgentTurnId,
8
14
  parseAgentTurnInputContent,
9
15
  parseAgentTurnInterruptionInput,
10
16
  parseAgentTurnRunInput
11
17
  } from "@agen-ai/agent-protocol";
12
18
  import {
13
- assertAgentSessionConfigurationSupported
14
- } from "./configurationValidation.js";
19
+ createAgentArtifactCandidate
20
+ } from "./artifacts.js";
21
+ import {
22
+ validateAgentCollaborationNodeForCapabilities,
23
+ validateAgentConfigurationCatalogForCapabilities,
24
+ validateAgentGeneratedResourceForCapabilities,
25
+ validateAgentIntegrationCatalogForCapabilities,
26
+ validateAgentManagedContentCatalogForCapabilities,
27
+ validateAgentOperationCatalogForCapabilities,
28
+ validateAgentOperationResultForInvocation,
29
+ validateAgentOperationResultTransition
30
+ } from "./interactionValidation.js";
15
31
  import {
16
32
  AgentProviderDelegatedOperationError,
17
33
  throwAgentProviderContractError
@@ -24,15 +40,59 @@ import {
24
40
  validateAgentProviderOutputForContext
25
41
  } from "./outputValidation.js";
26
42
  import { validateAgentTurnSteeringResult } from "./steeringValidation.js";
43
+ function hasExactOwnKeys(candidate, expectedKeys) {
44
+ const ownKeys = Reflect.ownKeys(candidate);
45
+ if (ownKeys.some((key) => typeof key !== "string")) return false;
46
+ const actualKeys = ownKeys.sort();
47
+ const canonicalExpectedKeys = [...expectedKeys].sort();
48
+ return actualKeys.length === canonicalExpectedKeys.length && actualKeys.every((key, index) => key === canonicalExpectedKeys[index]);
49
+ }
27
50
  function validateSessionPorts(capabilities, session) {
28
- if (typeof session.runTurn !== "function" || typeof session.resolveRequest !== "function" || typeof session.close !== "function" || session.interruption === null || typeof session.interruption !== "object" || !["supported", "unsupported"].includes(session.interruption.kind) || session.steering === null || typeof session.steering !== "object" || !["supported", "unsupported"].includes(session.steering.kind) || session.configuration === null || typeof session.configuration !== "object" || !["managed", "selectable"].includes(session.configuration.kind)) {
51
+ if (!hasExactOwnKeys(session, [
52
+ "binding",
53
+ "runTurn",
54
+ "resolveRequest",
55
+ "interruption",
56
+ "steering",
57
+ "configuration",
58
+ "operations",
59
+ "managedContent",
60
+ "integrations",
61
+ "collaboration",
62
+ "generatedResources",
63
+ "close"
64
+ ]) || typeof session.runTurn !== "function" || typeof session.resolveRequest !== "function" || typeof session.close !== "function" || session.interruption === null || typeof session.interruption !== "object" || !["supported", "unsupported"].includes(session.interruption.kind) || session.steering === null || typeof session.steering !== "object" || !["supported", "unsupported"].includes(session.steering.kind) || session.configuration === null || typeof session.configuration !== "object" || !["managed", "selectable"].includes(session.configuration.kind) || session.operations === null || typeof session.operations !== "object" || !["supported", "unsupported"].includes(session.operations.kind) || session.managedContent === null || typeof session.managedContent !== "object" || !["supported", "unsupported"].includes(session.managedContent.kind) || session.integrations === null || typeof session.integrations !== "object" || !["supported", "unsupported"].includes(session.integrations.kind) || session.collaboration === null || typeof session.collaboration !== "object" || !["supported", "unsupported"].includes(session.collaboration.kind) || session.generatedResources === null || typeof session.generatedResources !== "object" || !["supported", "unsupported"].includes(session.generatedResources.kind)) {
29
65
  throwAgentProviderContractError(
30
66
  capabilities.providerKey,
31
67
  "invalid_session",
32
68
  `Provider ${capabilities.providerKey} returned an incomplete session.`
33
69
  );
34
70
  }
35
- if (session.interruption.kind === "supported" !== capabilities.turns.interrupt || session.steering.kind === "supported" !== (capabilities.turns.steer.kind === "supported") || session.configuration.kind !== capabilities.configuration.kind || session.interruption.kind === "supported" && typeof session.interruption.interruptTurn !== "function" || session.steering.kind === "supported" && typeof session.steering.steerTurn !== "function" || session.configuration.kind === "selectable" && typeof session.configuration.applyConfiguration !== "function") {
71
+ if (!hasExactOwnKeys(
72
+ session.interruption,
73
+ session.interruption.kind === "supported" ? ["kind", "interruptTurn"] : ["kind"]
74
+ ) || !hasExactOwnKeys(
75
+ session.steering,
76
+ session.steering.kind === "supported" ? ["kind", "steerTurn"] : ["kind"]
77
+ ) || !hasExactOwnKeys(
78
+ session.configuration,
79
+ session.configuration.kind === "selectable" ? ["kind", "listConfiguration", "applyConfigurationSelection"] : ["kind"]
80
+ ) || !hasExactOwnKeys(
81
+ session.operations,
82
+ session.operations.kind === "supported" ? ["kind", "listOperations", "invokeOperation"] : ["kind"]
83
+ ) || !hasExactOwnKeys(
84
+ session.managedContent,
85
+ session.managedContent.kind === "supported" ? ["kind", "listManagedContent"] : ["kind"]
86
+ ) || !hasExactOwnKeys(
87
+ session.integrations,
88
+ session.integrations.kind === "supported" ? ["kind", "observeIntegrations"] : ["kind"]
89
+ ) || !hasExactOwnKeys(
90
+ session.collaboration,
91
+ session.collaboration.kind === "supported" ? ["kind", "spawnCollaboration", "controlCollaboration"] : ["kind"]
92
+ ) || !hasExactOwnKeys(
93
+ session.generatedResources,
94
+ session.generatedResources.kind === "supported" ? ["kind", "getGeneratedResource"] : ["kind"]
95
+ ) || session.interruption.kind === "supported" !== capabilities.turns.interrupt || session.steering.kind === "supported" !== (capabilities.turns.steer.kind === "supported") || session.configuration.kind !== capabilities.configuration.kind || session.interruption.kind === "supported" && typeof session.interruption.interruptTurn !== "function" || session.steering.kind === "supported" && typeof session.steering.steerTurn !== "function" || session.configuration.kind === "selectable" && (typeof session.configuration.listConfiguration !== "function" || typeof session.configuration.applyConfigurationSelection !== "function") || session.operations.kind === "supported" !== (capabilities.operations.kind === "supported") || session.operations.kind === "supported" && (typeof session.operations.listOperations !== "function" || typeof session.operations.invokeOperation !== "function") || session.managedContent.kind === "supported" !== (capabilities.managedContent.kind === "supported") || session.managedContent.kind === "supported" && typeof session.managedContent.listManagedContent !== "function" || session.integrations.kind === "supported" !== (capabilities.integrations.kind === "supported") || session.integrations.kind === "supported" && typeof session.integrations.observeIntegrations !== "function" || session.collaboration.kind === "supported" !== (capabilities.collaboration.kind === "supported") || session.collaboration.kind === "supported" && (typeof session.collaboration.spawnCollaboration !== "function" || typeof session.collaboration.controlCollaboration !== "function") || session.generatedResources.kind === "supported" !== (capabilities.generatedResources.kind === "supported") || session.generatedResources.kind === "supported" && typeof session.generatedResources.getGeneratedResource !== "function") {
36
96
  throwAgentProviderContractError(
37
97
  capabilities.providerKey,
38
98
  "capability_port_mismatch",
@@ -40,6 +100,58 @@ function validateSessionPorts(capabilities, session) {
40
100
  );
41
101
  }
42
102
  }
103
+ const TERMINAL_COLLABORATION_STATUSES = /* @__PURE__ */ new Set([
104
+ "completed",
105
+ "failed",
106
+ "canceled"
107
+ ]);
108
+ function evaluateCollaborationGraphAdmission(input) {
109
+ const existing = input.nodes.get(input.candidate.collaborationId);
110
+ if (existing !== void 0) {
111
+ const parent2 = existing.parentCollaborationId === void 0 ? void 0 : input.nodes.get(existing.parentCollaborationId);
112
+ return parent2 === void 0 ? Object.freeze({ kind: "admitted" }) : Object.freeze({ kind: "admitted", parent: parent2 });
113
+ }
114
+ const reservation = input.reservations.get(input.candidate.collaborationId);
115
+ if (reservation !== void 0 && reservation.parentCollaborationId !== input.candidate.parentCollaborationId) {
116
+ return Object.freeze({ kind: "conflict" });
117
+ }
118
+ const parent = input.candidate.parentCollaborationId === void 0 ? void 0 : input.nodes.get(input.candidate.parentCollaborationId);
119
+ if (input.candidate.parentCollaborationId === void 0 && input.candidate.rootCollaborationId !== input.candidate.collaborationId || input.candidate.parentCollaborationId !== void 0 && (parent === void 0 || input.candidate.rootCollaborationId !== parent.rootCollaborationId || TERMINAL_COLLABORATION_STATUSES.has(parent.status) || parent.closedAt !== void 0)) {
120
+ return Object.freeze({ kind: "conflict" });
121
+ }
122
+ let depth = 1;
123
+ const visitedIds = /* @__PURE__ */ new Set([input.candidate.collaborationId]);
124
+ for (let ancestor = parent; ancestor !== void 0; ) {
125
+ if (visitedIds.has(ancestor.collaborationId)) {
126
+ return Object.freeze({ kind: "conflict" });
127
+ }
128
+ visitedIds.add(ancestor.collaborationId);
129
+ depth += 1;
130
+ if (ancestor.parentCollaborationId === void 0) break;
131
+ ancestor = input.nodes.get(ancestor.parentCollaborationId);
132
+ if (ancestor === void 0) {
133
+ return Object.freeze({ kind: "conflict" });
134
+ }
135
+ }
136
+ if (reservation !== void 0) {
137
+ return parent === void 0 ? Object.freeze({ kind: "admitted" }) : Object.freeze({ kind: "admitted", parent });
138
+ }
139
+ const unmaterializedReservations = [...input.reservations].filter(
140
+ ([collaborationId]) => !input.nodes.has(collaborationId)
141
+ );
142
+ const childCount = parent === void 0 ? 0 : [...input.nodes.values()].filter(
143
+ (node) => node.parentCollaborationId === parent.collaborationId
144
+ ).length + unmaterializedReservations.filter(
145
+ ([, retainedReservation]) => retainedReservation.parentCollaborationId === parent.collaborationId
146
+ ).length;
147
+ const activeCount = [...input.nodes.values()].filter(
148
+ (node) => !TERMINAL_COLLABORATION_STATUSES.has(node.status)
149
+ ).length + unmaterializedReservations.length;
150
+ if (input.nodes.size + unmaterializedReservations.length >= AGENT_COLLABORATION_GRAPH_LIMITS.maxNodes || childCount >= input.capability.maxChildrenPerNode || depth > input.capability.maxDepth || input.candidate.active && activeCount >= input.capability.maxActiveNodes) {
151
+ return Object.freeze({ kind: "capacity_exceeded" });
152
+ }
153
+ return parent === void 0 ? Object.freeze({ kind: "admitted" }) : Object.freeze({ kind: "admitted", parent });
154
+ }
43
155
  function invalidTurnSequence(providerKey, message) {
44
156
  return throwAgentProviderContractError(
45
157
  providerKey,
@@ -59,13 +171,61 @@ function completeTurnSequence(input) {
59
171
  }
60
172
  const FINAL_DIFF_TRAILING_EVENT_TYPES = [
61
173
  "artifact.referenced",
174
+ "collaboration.updated",
175
+ "operation.updated",
62
176
  "provider.diagnostic",
177
+ "resource.updated",
63
178
  "runtime.error",
64
179
  "runtime.warning",
65
180
  "turn.completed"
66
181
  ];
182
+ const TERMINAL_ITEM_STATUSES = /* @__PURE__ */ new Set([
183
+ "completed",
184
+ "failed",
185
+ "canceled"
186
+ ]);
187
+ function observeItemLifecycle(input) {
188
+ const { event, providerKey, state } = input;
189
+ const previous = state.observedItems.get(event.payload.itemId);
190
+ if (event.type === "item.completed" && !TERMINAL_ITEM_STATUSES.has(event.payload.status)) {
191
+ invalidTurnSequence(
192
+ providerKey,
193
+ "Provider completed an item without a terminal item status."
194
+ );
195
+ }
196
+ if (previous?.terminal) {
197
+ invalidTurnSequence(
198
+ providerKey,
199
+ "Provider emitted an item lifecycle event after the item became terminal."
200
+ );
201
+ }
202
+ if (previous?.itemKind !== void 0 && previous.itemKind !== event.payload.itemKind) {
203
+ invalidTurnSequence(
204
+ providerKey,
205
+ "Provider changed the kind of an existing item identity."
206
+ );
207
+ }
208
+ if (previous !== void 0 && event.type === "item.started") {
209
+ invalidTurnSequence(
210
+ providerKey,
211
+ "Provider started an item identity more than once."
212
+ );
213
+ }
214
+ if (previous?.inProgressObserved && event.payload.status === "pending") {
215
+ invalidTurnSequence(
216
+ providerKey,
217
+ "Provider regressed an in-progress item to pending."
218
+ );
219
+ }
220
+ state.observedItems.set(event.payload.itemId, {
221
+ itemKind: event.payload.itemKind,
222
+ status: event.payload.status,
223
+ inProgressObserved: previous?.inProgressObserved === true || event.payload.status === "in_progress",
224
+ terminal: event.type === "item.completed" || TERMINAL_ITEM_STATUSES.has(event.payload.status)
225
+ });
226
+ }
67
227
  function assertApprovalSubjectCorrelation(input) {
68
- const request = input.event.payload.request;
228
+ const { request } = input;
69
229
  if (request.requestKind !== "approval") return;
70
230
  if (request.subject.kind === "plan") {
71
231
  if (input.state.proposedPlans.get(request.subject.artifactId) !== request.requestId) {
@@ -76,14 +236,24 @@ function assertApprovalSubjectCorrelation(input) {
76
236
  }
77
237
  return;
78
238
  }
79
- const status = input.state.observedItems.get(request.subject.itemId);
80
- if (status !== "pending" && status !== "in_progress") {
239
+ const item = input.state.observedItems.get(request.subject.itemId);
240
+ const itemIsLive = item !== void 0 && !item.terminal && (item.status === "pending" || item.status === "in_progress" || item.status === "unknown" && item.inProgressObserved);
241
+ if (!itemIsLive) {
81
242
  invalidTurnSequence(
82
243
  input.providerKey,
83
244
  "Provider approval request does not identify a live item from this turn."
84
245
  );
85
246
  }
86
247
  }
248
+ function assertPendingApprovalSubjectCorrelations(input) {
249
+ for (const pending of input.pendingRequests.values()) {
250
+ assertApprovalSubjectCorrelation({
251
+ providerKey: input.providerKey,
252
+ request: pending.request,
253
+ state: input.state
254
+ });
255
+ }
256
+ }
87
257
  function observeContextUsage(input) {
88
258
  const previous = input.state.latestByScope.get(input.usage.measurementScope);
89
259
  if (previous !== void 0) {
@@ -123,6 +293,11 @@ function observeContextUsage(input) {
123
293
  input.state.latestByScope.set(input.usage.measurementScope, input.usage);
124
294
  input.state.compactionReadyScopes.delete(input.usage.measurementScope);
125
295
  }
296
+ function observeContextMaterializationBoundary(state) {
297
+ state.latestByScope.delete("materialization");
298
+ state.cumulativeByScope.delete("materialization");
299
+ state.compactionReadyScopes.delete("materialization");
300
+ }
126
301
  function observeTurnEvent(input) {
127
302
  const {
128
303
  contextUsageState,
@@ -175,7 +350,12 @@ function observeTurnEvent(input) {
175
350
  }
176
351
  }
177
352
  if (event.type === "item.started" || event.type === "item.updated" || event.type === "item.completed") {
178
- state.observedItems.set(event.payload.itemId, event.payload.status);
353
+ observeItemLifecycle({ providerKey, event, state });
354
+ assertPendingApprovalSubjectCorrelations({
355
+ providerKey,
356
+ pendingRequests,
357
+ state
358
+ });
179
359
  if (event.payload.itemKind === "context_compaction" && event.type === "item.completed" && event.payload.status === "completed") {
180
360
  for (const scope of ["session", "materialization"]) {
181
361
  contextUsageState.compactionReadyScopes.add(scope);
@@ -184,6 +364,11 @@ function observeTurnEvent(input) {
184
364
  }
185
365
  if (event.type === "turn.plan.proposed") {
186
366
  state.proposedPlans.set(event.payload.artifactId, event.payload.requestId);
367
+ assertPendingApprovalSubjectCorrelations({
368
+ providerKey,
369
+ pendingRequests,
370
+ state
371
+ });
187
372
  }
188
373
  if (event.type === "context.usage.updated") {
189
374
  observeContextUsage({
@@ -206,7 +391,11 @@ function observeTurnEvent(input) {
206
391
  "Provider reused a request ID within a session."
207
392
  );
208
393
  }
209
- assertApprovalSubjectCorrelation({ providerKey, event, state });
394
+ assertApprovalSubjectCorrelation({
395
+ providerKey,
396
+ request: event.payload.request,
397
+ state
398
+ });
210
399
  openedRequestIds.add(requestId);
211
400
  pendingRequests.set(requestId, {
212
401
  request: event.payload.request,
@@ -226,6 +415,98 @@ function observeTurnEvent(input) {
226
415
  completeTurnSequence({ providerKey, state, pendingRequests });
227
416
  }
228
417
  }
418
+ function observeTurnOutput(input) {
419
+ if (input.output.kind === "lifecycle" && input.output.lifecycle.type === "process.started") {
420
+ observeContextMaterializationBoundary(input.contextUsageState);
421
+ }
422
+ if (input.output.kind !== "event") return;
423
+ if (input.output.event.type === "operation.updated") {
424
+ const result = validateAgentOperationResultTransition({
425
+ providerKey: input.providerKey,
426
+ candidate: input.output.event.payload.result,
427
+ previous: input.interactionState.operationResults.get(
428
+ input.output.event.payload.result.invocationId
429
+ )
430
+ });
431
+ input.interactionState.operationResults.set(result.invocationId, result);
432
+ const invocation = input.interactionState.operationInvocations.get(
433
+ result.invocationId
434
+ );
435
+ if (invocation !== void 0) invocation.result = result;
436
+ }
437
+ if (input.output.event.type === "collaboration.updated") {
438
+ const node = validateAgentCollaborationNodeForCapabilities({
439
+ capabilities: input.capabilities,
440
+ candidate: input.output.event.payload.node,
441
+ previous: input.interactionState.collaborationNodes.get(
442
+ input.output.event.payload.node.collaborationId
443
+ )
444
+ });
445
+ const capability = input.capabilities.collaboration;
446
+ if (capability.kind !== "supported") {
447
+ throwAgentProviderContractError(
448
+ input.providerKey,
449
+ "output_capability_mismatch",
450
+ "Provider emitted collaboration state without declaring support."
451
+ );
452
+ }
453
+ const admission = evaluateCollaborationGraphAdmission({
454
+ capability,
455
+ candidate: {
456
+ collaborationId: node.collaborationId,
457
+ rootCollaborationId: node.rootCollaborationId,
458
+ ...node.parentCollaborationId === void 0 ? {} : { parentCollaborationId: node.parentCollaborationId },
459
+ active: !TERMINAL_COLLABORATION_STATUSES.has(node.status)
460
+ },
461
+ nodes: input.interactionState.collaborationNodes,
462
+ reservations: input.interactionState.collaborationSpawnReservations
463
+ });
464
+ if (admission.kind === "conflict") {
465
+ throwAgentProviderContractError(
466
+ input.providerKey,
467
+ "output_collaboration_mismatch",
468
+ "Provider emitted a collaboration node outside the canonical graph."
469
+ );
470
+ }
471
+ if (admission.kind === "capacity_exceeded") {
472
+ throwAgentProviderContractError(
473
+ input.providerKey,
474
+ "output_capability_mismatch",
475
+ "Provider emitted a collaboration graph outside its declared limits."
476
+ );
477
+ }
478
+ input.interactionState.collaborationNodes.set(node.collaborationId, node);
479
+ }
480
+ if (input.output.event.type === "resource.updated") {
481
+ const capability = input.capabilities.generatedResources;
482
+ const resourceId = input.output.event.payload.resource.resourceId;
483
+ if (capability.kind !== "supported" || !input.state.generatedResourceIds.has(resourceId) && input.state.generatedResourceIds.size >= capability.maxResourcesPerTurn) {
484
+ throwAgentProviderContractError(
485
+ input.providerKey,
486
+ "output_capability_mismatch",
487
+ "Provider exceeded its declared generated-resource count for the turn."
488
+ );
489
+ }
490
+ const resource = validateAgentGeneratedResourceForCapabilities({
491
+ capabilities: input.capabilities,
492
+ candidate: input.output.event.payload.resource,
493
+ expectedResourceId: input.output.event.payload.resource.resourceId,
494
+ previous: input.interactionState.generatedResources.get(
495
+ input.output.event.payload.resource.resourceId
496
+ )
497
+ });
498
+ input.state.generatedResourceIds.add(resource.resourceId);
499
+ input.interactionState.generatedResources.set(resource.resourceId, resource);
500
+ }
501
+ observeTurnEvent({
502
+ providerKey: input.providerKey,
503
+ event: input.output.event,
504
+ state: input.state,
505
+ pendingRequests: input.pendingRequests,
506
+ openedRequestIds: input.openedRequestIds,
507
+ contextUsageState: input.contextUsageState
508
+ });
509
+ }
229
510
  function assertStableTurnBoundary(input) {
230
511
  const terminal = input.state.terminal && !input.state.waiting;
231
512
  const waiting = !input.state.terminal && input.state.waiting && input.pendingRequests.size === 1;
@@ -261,14 +542,15 @@ function interruptionTerminalizesTurn(input) {
261
542
  }
262
543
  function observeTurnOperationOutputs(input) {
263
544
  for (const output of input.outputs ?? []) {
264
- if (output.kind !== "event") continue;
265
- observeTurnEvent({
545
+ observeTurnOutput({
266
546
  providerKey: input.providerKey,
267
- event: output.event,
547
+ output,
268
548
  state: input.state,
269
549
  pendingRequests: input.pendingRequests,
270
550
  openedRequestIds: input.openedRequestIds,
271
- contextUsageState: input.contextUsageState
551
+ contextUsageState: input.contextUsageState,
552
+ capabilities: input.capabilities,
553
+ interactionState: input.interactionState
272
554
  });
273
555
  }
274
556
  }
@@ -278,17 +560,9 @@ function reconstructWaitingTurn(input) {
278
560
  ([, pending]) => pending.turnId === input.turnId
279
561
  )
280
562
  );
281
- if (targetedPendingRequests.size === 0) return null;
563
+ if (targetedPendingRequests.size === 0 || input.state === void 0 || input.state.terminal || !input.state.waiting) return null;
282
564
  return {
283
- state: {
284
- fileChangeMode: input.fileChangeMode,
285
- observedItems: /* @__PURE__ */ new Map(),
286
- proposedPlans: /* @__PURE__ */ new Map(),
287
- started: true,
288
- terminal: false,
289
- waiting: true,
290
- finalDiffObserved: false
291
- },
565
+ state: input.state,
292
566
  pendingRequests: targetedPendingRequests
293
567
  };
294
568
  }
@@ -376,12 +650,22 @@ function validateAgentProviderSession(input) {
376
650
  }
377
651
  validateSessionPorts(capabilities, input.candidate);
378
652
  const pendingRequests = /* @__PURE__ */ new Map();
653
+ const waitingTurnStates = /* @__PURE__ */ new Map();
379
654
  const openedRequestIds = /* @__PURE__ */ new Set();
380
655
  const contextUsageState = {
381
656
  latestByScope: /* @__PURE__ */ new Map(),
382
657
  cumulativeByScope: /* @__PURE__ */ new Map(),
383
658
  compactionReadyScopes: /* @__PURE__ */ new Set()
384
659
  };
660
+ const interactionState = {
661
+ operationResults: /* @__PURE__ */ new Map(),
662
+ operationInvocations: /* @__PURE__ */ new Map(),
663
+ collaborationNodes: /* @__PURE__ */ new Map(),
664
+ collaborationSpawnReservations: /* @__PURE__ */ new Map(),
665
+ generatedResources: /* @__PURE__ */ new Map()
666
+ };
667
+ const collaborationNodes = interactionState.collaborationNodes;
668
+ const collaborationSpawnReservations = interactionState.collaborationSpawnReservations;
385
669
  let activeTurn = null;
386
670
  let closePromise = null;
387
671
  let closed = false;
@@ -421,6 +705,39 @@ function validateAgentProviderSession(input) {
421
705
  throw error;
422
706
  }
423
707
  };
708
+ const delegateProviderMutation = async (input2) => {
709
+ let executionStarted = false;
710
+ const onProviderExecutionStarted = () => {
711
+ if (executionStarted) {
712
+ throwAgentProviderContractError(
713
+ providerKey,
714
+ "invalid_operation_result",
715
+ "Provider reported operation execution more than once."
716
+ );
717
+ }
718
+ input2.observer?.();
719
+ executionStarted = true;
720
+ };
721
+ try {
722
+ const candidate = await input2.invoke(onProviderExecutionStarted);
723
+ if (!executionStarted) {
724
+ throwAgentProviderContractError(
725
+ providerKey,
726
+ "invalid_operation_result",
727
+ "Provider completed an operation without reporting execution start."
728
+ );
729
+ }
730
+ return input2.validate(candidate);
731
+ } catch (error) {
732
+ if (!executionStarted) throw error;
733
+ unusable = true;
734
+ throw new AgentProviderDelegatedOperationError(
735
+ providerKey,
736
+ input2.operation,
737
+ error
738
+ );
739
+ }
740
+ };
424
741
  const runTurn = async function* (turnInput) {
425
742
  requireUsable();
426
743
  throwIfAgentOperationAborted(turnInput.signal);
@@ -465,6 +782,7 @@ function validateAgentProviderSession(input) {
465
782
  fileChangeMode: capabilities.output.fileChanges,
466
783
  observedItems: /* @__PURE__ */ new Map(),
467
784
  proposedPlans: /* @__PURE__ */ new Map(),
785
+ generatedResourceIds: /* @__PURE__ */ new Set(),
468
786
  started: false,
469
787
  terminal: false,
470
788
  waiting: false,
@@ -483,16 +801,16 @@ function validateAgentProviderSession(input) {
483
801
  candidate,
484
802
  outputContext(parsedInput.turnId)
485
803
  );
486
- if (output.kind === "event") {
487
- observeTurnEvent({
488
- providerKey,
489
- event: output.event,
490
- state: currentTurn.state,
491
- pendingRequests: currentTurn.pendingRequests,
492
- openedRequestIds,
493
- contextUsageState
494
- });
495
- }
804
+ observeTurnOutput({
805
+ capabilities,
806
+ providerKey,
807
+ output,
808
+ state: currentTurn.state,
809
+ pendingRequests: currentTurn.pendingRequests,
810
+ openedRequestIds,
811
+ contextUsageState,
812
+ interactionState
813
+ });
496
814
  yield output;
497
815
  }
498
816
  while (currentTurn.inFlightOperations.size > 0) {
@@ -511,6 +829,9 @@ function validateAgentProviderSession(input) {
511
829
  });
512
830
  if (currentTurn.state.waiting) {
513
831
  replacePendingRequests(pendingRequests, currentTurn.pendingRequests);
832
+ waitingTurnStates.set(currentTurn.turnId, currentTurn.state);
833
+ } else {
834
+ waitingTurnStates.delete(currentTurn.turnId);
514
835
  }
515
836
  reachedStableBoundary = true;
516
837
  } finally {
@@ -555,18 +876,19 @@ function validateAgentProviderSession(input) {
555
876
  "Provider session already has an active turn."
556
877
  );
557
878
  }
879
+ const waitingTurnState = waitingTurnStates.get(pending.turnId);
880
+ if (waitingTurnState === void 0 || waitingTurnState.terminal || !waitingTurnState.waiting) {
881
+ throwAgentProviderContractError(
882
+ providerKey,
883
+ "request_resolution_mismatch",
884
+ "Provider request resolution does not identify a waiting turn."
885
+ );
886
+ }
887
+ waitingTurnState.waiting = false;
558
888
  const currentTurn = {
559
889
  turnId: pending.turnId,
560
890
  pendingRequests: nextPendingRequests,
561
- state: {
562
- fileChangeMode: capabilities.output.fileChanges,
563
- observedItems: /* @__PURE__ */ new Map(),
564
- proposedPlans: /* @__PURE__ */ new Map(),
565
- started: true,
566
- terminal: false,
567
- waiting: false,
568
- finalDiffObserved: false
569
- },
891
+ state: waitingTurnState,
570
892
  inFlightOperations: /* @__PURE__ */ new Set()
571
893
  };
572
894
  let reachedStableBoundary = false;
@@ -580,16 +902,16 @@ function validateAgentProviderSession(input) {
580
902
  candidate,
581
903
  outputContext(pending.turnId)
582
904
  );
583
- if (output.kind === "event") {
584
- observeTurnEvent({
585
- providerKey,
586
- event: output.event,
587
- state: currentTurn.state,
588
- pendingRequests: currentTurn.pendingRequests,
589
- openedRequestIds,
590
- contextUsageState
591
- });
592
- }
905
+ observeTurnOutput({
906
+ capabilities,
907
+ providerKey,
908
+ output,
909
+ state: currentTurn.state,
910
+ pendingRequests: currentTurn.pendingRequests,
911
+ openedRequestIds,
912
+ contextUsageState,
913
+ interactionState
914
+ });
593
915
  yield output;
594
916
  }
595
917
  while (currentTurn.inFlightOperations.size > 0) {
@@ -601,6 +923,11 @@ function validateAgentProviderSession(input) {
601
923
  pendingRequests: currentTurn.pendingRequests
602
924
  });
603
925
  replacePendingRequests(pendingRequests, currentTurn.pendingRequests);
926
+ if (currentTurn.state.waiting) {
927
+ waitingTurnStates.set(currentTurn.turnId, currentTurn.state);
928
+ } else {
929
+ waitingTurnStates.delete(currentTurn.turnId);
930
+ }
604
931
  reachedStableBoundary = true;
605
932
  } finally {
606
933
  if (!reachedStableBoundary) unusable = true;
@@ -622,7 +949,7 @@ function validateAgentProviderSession(input) {
622
949
  const targetedWaitingTurn = targetedActiveTurn === null ? reconstructWaitingTurn({
623
950
  pendingRequests,
624
951
  turnId: parsed.turnId,
625
- fileChangeMode: capabilities.output.fileChanges
952
+ state: waitingTurnStates.get(parsed.turnId)
626
953
  }) : null;
627
954
  const targetedTurn = targetedActiveTurn ?? targetedWaitingTurn;
628
955
  if (targetedTurn === null) {
@@ -654,15 +981,18 @@ function validateAgentProviderSession(input) {
654
981
  parsed.turnId
655
982
  );
656
983
  targetedTurn.state.waiting = false;
984
+ waitingTurnStates.delete(parsed.turnId);
657
985
  }
658
986
  try {
659
987
  observeTurnOperationOutputs({
988
+ capabilities,
660
989
  providerKey,
661
990
  outputs: result.outputs,
662
991
  state: targetedTurn.state,
663
992
  pendingRequests: targetedTurn.pendingRequests,
664
993
  openedRequestIds,
665
- contextUsageState
994
+ contextUsageState,
995
+ interactionState
666
996
  });
667
997
  if (terminalized && !targetedTurn.state.terminal) {
668
998
  completeTurnSequence({
@@ -735,22 +1065,433 @@ function validateAgentProviderSession(input) {
735
1065
  const declaredConfiguration = input.candidate.configuration;
736
1066
  const configuration = declaredConfiguration.kind === "managed" ? Object.freeze({ kind: "managed" }) : Object.freeze({
737
1067
  kind: "selectable",
738
- applyConfiguration: async (configurationInput) => {
1068
+ listConfiguration: async (listInput = {}) => {
739
1069
  requireUsable();
740
- throwIfAgentOperationAborted(configurationInput.signal);
741
- const configuration2 = parseAgentSessionConfiguration(
742
- configurationInput.configuration
1070
+ throwIfAgentOperationAborted(listInput.signal);
1071
+ return validateAgentConfigurationCatalogForCapabilities(
1072
+ capabilities,
1073
+ await declaredConfiguration.listConfiguration(
1074
+ listInput.signal === void 0 ? {} : { signal: listInput.signal }
1075
+ )
743
1076
  );
744
- assertAgentSessionConfigurationSupported(
1077
+ },
1078
+ applyConfigurationSelection: async (configurationInput) => {
1079
+ requireUsable();
1080
+ throwIfAgentOperationAborted(configurationInput.signal);
1081
+ const catalog = validateAgentConfigurationCatalogForCapabilities(
745
1082
  capabilities,
746
- configuration2
1083
+ await declaredConfiguration.listConfiguration(
1084
+ configurationInput.signal === void 0 ? {} : { signal: configurationInput.signal }
1085
+ )
747
1086
  );
748
- return delegateOperation(
749
- () => declaredConfiguration.applyConfiguration({
750
- configuration: configuration2,
1087
+ let selection;
1088
+ try {
1089
+ selection = parseAgentConfigurationSelectionFor(
1090
+ catalog,
1091
+ configurationInput.selection
1092
+ );
1093
+ } catch {
1094
+ return throwAgentProviderContractError(
1095
+ providerKey,
1096
+ "configuration_value_unsupported",
1097
+ "Configuration selection is stale or outside the offered catalog."
1098
+ );
1099
+ }
1100
+ return delegateProviderMutation({
1101
+ operation: "apply_configuration",
1102
+ observer: configurationInput.onProviderExecutionStarted,
1103
+ invoke: (onProviderExecutionStarted) => declaredConfiguration.applyConfigurationSelection({
1104
+ selection,
1105
+ onProviderExecutionStarted,
751
1106
  ...configurationInput.signal === void 0 ? {} : { signal: configurationInput.signal }
1107
+ }),
1108
+ validate: (candidate) => validateAgentProviderOperationResult(
1109
+ candidate,
1110
+ outputContext()
1111
+ )
1112
+ });
1113
+ }
1114
+ });
1115
+ const declaredOperations = input.candidate.operations;
1116
+ const operations = declaredOperations.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1117
+ kind: "supported",
1118
+ listOperations: async (listInput = {}) => {
1119
+ requireUsable();
1120
+ throwIfAgentOperationAborted(listInput.signal);
1121
+ return validateAgentOperationCatalogForCapabilities(
1122
+ capabilities,
1123
+ await declaredOperations.listOperations(
1124
+ listInput.signal === void 0 ? {} : { signal: listInput.signal }
1125
+ )
1126
+ );
1127
+ },
1128
+ invokeOperation: async (operationInput) => {
1129
+ requireUsable();
1130
+ throwIfAgentOperationAborted(operationInput.signal);
1131
+ let invocation;
1132
+ try {
1133
+ invocation = parseAgentOperationInvocation(operationInput.invocation);
1134
+ } catch {
1135
+ return throwAgentProviderContractError(
1136
+ providerKey,
1137
+ "input_operation_mismatch",
1138
+ "Operation invocation is invalid."
1139
+ );
1140
+ }
1141
+ const catalog = validateAgentOperationCatalogForCapabilities(
1142
+ capabilities,
1143
+ await declaredOperations.listOperations(
1144
+ operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1145
+ )
1146
+ );
1147
+ const descriptor = catalog.operations.find(
1148
+ (operation) => operation.operationId === invocation.operationId
1149
+ );
1150
+ if (descriptor === void 0) {
1151
+ return throwAgentProviderContractError(
1152
+ providerKey,
1153
+ "input_operation_mismatch",
1154
+ "Operation invocation does not identify an offered operation."
1155
+ );
1156
+ }
1157
+ try {
1158
+ invocation = parseAgentOperationInvocationFor(
1159
+ descriptor,
1160
+ invocation
1161
+ );
1162
+ } catch {
1163
+ return throwAgentProviderContractError(
1164
+ providerKey,
1165
+ "input_operation_mismatch",
1166
+ "Operation invocation is stale or outside the offered descriptor."
1167
+ );
1168
+ }
1169
+ const existing = interactionState.operationInvocations.get(
1170
+ invocation.invocationId
1171
+ );
1172
+ if (existing !== void 0) {
1173
+ if (JSON.stringify(existing.invocation) !== JSON.stringify(invocation)) {
1174
+ return throwAgentProviderContractError(
1175
+ providerKey,
1176
+ "input_operation_mismatch",
1177
+ "Operation invocation ID was reused with conflicting input."
1178
+ );
1179
+ }
1180
+ if (descriptor.idempotency === "required" && existing.result !== void 0) {
1181
+ return existing.result;
1182
+ }
1183
+ return throwAgentProviderContractError(
1184
+ providerKey,
1185
+ "input_operation_mismatch",
1186
+ "Operation invocation ID is already active or is not replayable."
1187
+ );
1188
+ }
1189
+ const trackedInvocation = {
1190
+ invocation
1191
+ };
1192
+ interactionState.operationInvocations.set(
1193
+ invocation.invocationId,
1194
+ trackedInvocation
1195
+ );
1196
+ try {
1197
+ const result = await delegateProviderMutation({
1198
+ operation: "invoke_operation",
1199
+ observer: operationInput.onProviderExecutionStarted,
1200
+ invoke: (onProviderExecutionStarted) => declaredOperations.invokeOperation({
1201
+ invocation,
1202
+ onProviderExecutionStarted,
1203
+ ...operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1204
+ }),
1205
+ validate: (candidate) => {
1206
+ const result2 = validateAgentOperationResultTransition({
1207
+ providerKey,
1208
+ candidate: validateAgentOperationResultForInvocation(
1209
+ providerKey,
1210
+ descriptor,
1211
+ invocation,
1212
+ candidate
1213
+ ),
1214
+ previous: interactionState.operationResults.get(
1215
+ invocation.invocationId
1216
+ )
1217
+ });
1218
+ interactionState.operationResults.set(
1219
+ result2.invocationId,
1220
+ result2
1221
+ );
1222
+ return result2;
1223
+ }
1224
+ });
1225
+ trackedInvocation.result = result;
1226
+ return result;
1227
+ } catch (error) {
1228
+ if (!(error instanceof AgentProviderDelegatedOperationError)) {
1229
+ interactionState.operationInvocations.delete(
1230
+ invocation.invocationId
1231
+ );
1232
+ }
1233
+ throw error;
1234
+ }
1235
+ }
1236
+ });
1237
+ const declaredManagedContent = input.candidate.managedContent;
1238
+ const managedContent = declaredManagedContent.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1239
+ kind: "supported",
1240
+ listManagedContent: async (listInput = {}) => {
1241
+ requireUsable();
1242
+ throwIfAgentOperationAborted(listInput.signal);
1243
+ return validateAgentManagedContentCatalogForCapabilities(
1244
+ capabilities,
1245
+ await declaredManagedContent.listManagedContent(
1246
+ listInput.signal === void 0 ? {} : { signal: listInput.signal }
1247
+ )
1248
+ );
1249
+ }
1250
+ });
1251
+ const declaredIntegrations = input.candidate.integrations;
1252
+ const integrations = declaredIntegrations.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1253
+ kind: "supported",
1254
+ observeIntegrations: async (listInput = {}) => {
1255
+ requireUsable();
1256
+ throwIfAgentOperationAborted(listInput.signal);
1257
+ return validateAgentIntegrationCatalogForCapabilities(
1258
+ capabilities,
1259
+ await declaredIntegrations.observeIntegrations(
1260
+ listInput.signal === void 0 ? {} : { signal: listInput.signal }
1261
+ )
1262
+ );
1263
+ }
1264
+ });
1265
+ const declaredCollaboration = input.candidate.collaboration;
1266
+ const collaboration = declaredCollaboration.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1267
+ kind: "supported",
1268
+ spawnCollaboration: async (collaborationInput) => {
1269
+ requireUsable();
1270
+ throwIfAgentOperationAborted(collaborationInput.signal);
1271
+ let spawn;
1272
+ try {
1273
+ spawn = parseAgentCollaborationSpawnInput(collaborationInput.spawn);
1274
+ } catch {
1275
+ return throwAgentProviderContractError(
1276
+ providerKey,
1277
+ "input_operation_mismatch",
1278
+ "Collaboration spawn input is invalid."
1279
+ );
1280
+ }
1281
+ const capability = capabilities.collaboration;
1282
+ if (capability.kind !== "supported" || !capability.controlActions.includes("spawn") || !capability.roles.includes(spawn.role) || collaborationNodes.has(spawn.collaborationId) || collaborationSpawnReservations.has(spawn.collaborationId)) {
1283
+ return throwAgentProviderContractError(
1284
+ providerKey,
1285
+ "input_capability_mismatch",
1286
+ "Collaboration spawn is outside the provider's declared capability."
1287
+ );
1288
+ }
1289
+ const observedParent = spawn.parentCollaborationId === void 0 ? void 0 : collaborationNodes.get(spawn.parentCollaborationId);
1290
+ const admission = evaluateCollaborationGraphAdmission({
1291
+ capability,
1292
+ candidate: {
1293
+ collaborationId: spawn.collaborationId,
1294
+ rootCollaborationId: observedParent?.rootCollaborationId ?? spawn.collaborationId,
1295
+ ...spawn.parentCollaborationId === void 0 ? {} : { parentCollaborationId: spawn.parentCollaborationId },
1296
+ active: true
1297
+ },
1298
+ nodes: collaborationNodes,
1299
+ reservations: collaborationSpawnReservations
1300
+ });
1301
+ if (admission.kind === "conflict") {
1302
+ return throwAgentProviderContractError(
1303
+ providerKey,
1304
+ "input_operation_mismatch",
1305
+ "Collaboration parent is unavailable in the canonical graph."
1306
+ );
1307
+ }
1308
+ if (admission.kind === "capacity_exceeded") {
1309
+ return throwAgentProviderContractError(
1310
+ providerKey,
1311
+ "input_capability_mismatch",
1312
+ "Collaboration graph limit would be exceeded."
1313
+ );
1314
+ }
1315
+ const parent = admission.parent;
1316
+ collaborationSpawnReservations.set(
1317
+ spawn.collaborationId,
1318
+ Object.freeze({
1319
+ ...spawn.parentCollaborationId === void 0 ? {} : { parentCollaborationId: spawn.parentCollaborationId }
752
1320
  })
753
1321
  );
1322
+ try {
1323
+ const node = await delegateProviderMutation({
1324
+ operation: "spawn_collaboration",
1325
+ observer: collaborationInput.onProviderExecutionStarted,
1326
+ invoke: (onProviderExecutionStarted) => declaredCollaboration.spawnCollaboration({
1327
+ spawn,
1328
+ onProviderExecutionStarted,
1329
+ ...collaborationInput.signal === void 0 ? {} : { signal: collaborationInput.signal }
1330
+ }),
1331
+ validate: (candidate) => {
1332
+ const node2 = validateAgentCollaborationNodeForCapabilities({
1333
+ capabilities,
1334
+ candidate
1335
+ });
1336
+ if (node2.collaborationId !== spawn.collaborationId || node2.parentCollaborationId !== spawn.parentCollaborationId || node2.role !== spawn.role || node2.title !== spawn.title || node2.objective !== spawn.objective || node2.createdAt !== spawn.createdAt || node2.rootCollaborationId !== (parent?.rootCollaborationId ?? spawn.collaborationId)) {
1337
+ return throwAgentProviderContractError(
1338
+ providerKey,
1339
+ "output_collaboration_mismatch",
1340
+ "Provider collaboration node does not match the spawn input."
1341
+ );
1342
+ }
1343
+ return node2;
1344
+ }
1345
+ });
1346
+ collaborationNodes.set(node.collaborationId, node);
1347
+ collaborationSpawnReservations.delete(spawn.collaborationId);
1348
+ return node;
1349
+ } catch (error) {
1350
+ if (!(error instanceof AgentProviderDelegatedOperationError)) {
1351
+ collaborationSpawnReservations.delete(spawn.collaborationId);
1352
+ }
1353
+ throw error;
1354
+ }
1355
+ },
1356
+ controlCollaboration: async (collaborationInput) => {
1357
+ requireUsable();
1358
+ throwIfAgentOperationAborted(collaborationInput.signal);
1359
+ let control;
1360
+ try {
1361
+ control = parseAgentCollaborationControlInput(
1362
+ collaborationInput.control
1363
+ );
1364
+ } catch {
1365
+ return throwAgentProviderContractError(
1366
+ providerKey,
1367
+ "input_operation_mismatch",
1368
+ "Collaboration control input is invalid."
1369
+ );
1370
+ }
1371
+ const capability = capabilities.collaboration;
1372
+ const previous = collaborationNodes.get(control.collaborationId);
1373
+ if (capability.kind !== "supported" || !capability.controlActions.includes(control.action) || previous === void 0) {
1374
+ return throwAgentProviderContractError(
1375
+ providerKey,
1376
+ "input_capability_mismatch",
1377
+ "Collaboration control is outside the observed graph or declared capability."
1378
+ );
1379
+ }
1380
+ const terminal = ["completed", "failed", "canceled"].includes(
1381
+ previous.status
1382
+ );
1383
+ if (control.action === "close" && previous.closedAt !== void 0) {
1384
+ return previous;
1385
+ }
1386
+ if (control.action === "close" && !terminal || control.action === "stop" && terminal || control.action === "steer" && terminal || control.action !== "inspect" && previous.closedAt !== void 0) {
1387
+ return throwAgentProviderContractError(
1388
+ providerKey,
1389
+ "input_capability_mismatch",
1390
+ "Collaboration control is unavailable in the current lifecycle state."
1391
+ );
1392
+ }
1393
+ const node = await delegateProviderMutation({
1394
+ operation: "control_collaboration",
1395
+ observer: collaborationInput.onProviderExecutionStarted,
1396
+ invoke: (onProviderExecutionStarted) => declaredCollaboration.controlCollaboration({
1397
+ control,
1398
+ onProviderExecutionStarted,
1399
+ ...collaborationInput.signal === void 0 ? {} : { signal: collaborationInput.signal }
1400
+ }),
1401
+ validate: (candidate) => {
1402
+ const validated = validateAgentCollaborationNodeForCapabilities({
1403
+ capabilities,
1404
+ candidate,
1405
+ previous
1406
+ });
1407
+ if (control.action === "stop" && validated.status !== "canceled" || control.action === "close" && (validated.status !== previous.status || validated.closedAt === void 0)) {
1408
+ return throwAgentProviderContractError(
1409
+ providerKey,
1410
+ "output_collaboration_mismatch",
1411
+ "Provider collaboration result does not settle the requested control action."
1412
+ );
1413
+ }
1414
+ return validated;
1415
+ }
1416
+ });
1417
+ collaborationNodes.set(node.collaborationId, node);
1418
+ return node;
1419
+ }
1420
+ });
1421
+ function validateGeneratedResourceInspection(candidate, resourceId) {
1422
+ if (candidate === null || typeof candidate !== "object" || !hasExactOwnKeys(candidate, [
1423
+ "descriptor",
1424
+ ..."candidate" in candidate ? ["candidate"] : []
1425
+ ])) {
1426
+ return throwAgentProviderContractError(
1427
+ providerKey,
1428
+ "output_resource_mismatch",
1429
+ "Provider returned an invalid generated-resource inspection."
1430
+ );
1431
+ }
1432
+ const rawInspection = candidate;
1433
+ const descriptor = validateAgentGeneratedResourceForCapabilities({
1434
+ capabilities,
1435
+ candidate: rawInspection.descriptor,
1436
+ expectedResourceId: resourceId,
1437
+ previous: interactionState.generatedResources.get(resourceId)
1438
+ });
1439
+ const hasCandidate = Object.prototype.hasOwnProperty.call(
1440
+ rawInspection,
1441
+ "candidate"
1442
+ );
1443
+ if (descriptor.status === "available" !== hasCandidate) {
1444
+ return throwAgentProviderContractError(
1445
+ providerKey,
1446
+ "output_resource_mismatch",
1447
+ "Exactly available generated resources must include owned artifact bytes."
1448
+ );
1449
+ }
1450
+ if (!hasCandidate) return Object.freeze({ descriptor });
1451
+ let artifactCandidate;
1452
+ try {
1453
+ artifactCandidate = createAgentArtifactCandidate(
1454
+ rawInspection.candidate
1455
+ );
1456
+ } catch {
1457
+ return throwAgentProviderContractError(
1458
+ providerKey,
1459
+ "output_resource_mismatch",
1460
+ "Provider returned invalid generated-resource artifact bytes."
1461
+ );
1462
+ }
1463
+ const artifact = artifactCandidate.descriptor;
1464
+ const expectedArtifactKind = descriptor.kind === "image" ? "image" : "file";
1465
+ if (artifactCandidate.delivery !== "required_before_reference" || artifact.artifactId !== descriptor.artifactId || artifact.kind !== expectedArtifactKind || artifact.displayName !== descriptor.displayName || artifact.mediaType !== descriptor.mediaType || artifact.byteSize !== descriptor.byteSize || artifact.digest?.algorithm !== "sha256" || artifact.digest?.value !== descriptor.sha256 || artifact.summary !== descriptor.summary) {
1466
+ return throwAgentProviderContractError(
1467
+ providerKey,
1468
+ "output_resource_mismatch",
1469
+ "Generated-resource metadata does not match its immutable artifact candidate."
1470
+ );
1471
+ }
1472
+ return Object.freeze({ descriptor, candidate: artifactCandidate });
1473
+ }
1474
+ const declaredGeneratedResources = input.candidate.generatedResources;
1475
+ const generatedResources = declaredGeneratedResources.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1476
+ kind: "supported",
1477
+ getGeneratedResource: async (resourceInput) => {
1478
+ requireUsable();
1479
+ throwIfAgentOperationAborted(resourceInput.signal);
1480
+ const resourceId = parseAgentGeneratedResourceId(
1481
+ resourceInput.resourceId
1482
+ );
1483
+ const inspection = validateGeneratedResourceInspection(
1484
+ await declaredGeneratedResources.getGeneratedResource({
1485
+ resourceId,
1486
+ ...resourceInput.signal === void 0 ? {} : { signal: resourceInput.signal }
1487
+ }),
1488
+ resourceId
1489
+ );
1490
+ interactionState.generatedResources.set(
1491
+ inspection.descriptor.resourceId,
1492
+ inspection.descriptor
1493
+ );
1494
+ return inspection;
754
1495
  }
755
1496
  });
756
1497
  const close = (closeInput) => {
@@ -782,6 +1523,11 @@ function validateAgentProviderSession(input) {
782
1523
  interruption,
783
1524
  steering,
784
1525
  configuration,
1526
+ operations,
1527
+ managedContent,
1528
+ integrations,
1529
+ collaboration,
1530
+ generatedResources,
785
1531
  close
786
1532
  });
787
1533
  }