@agen-ai/agent-runtime 0.2.2 → 0.2.4

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,7 +171,10 @@ 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"
@@ -305,6 +420,84 @@ function observeTurnOutput(input) {
305
420
  observeContextMaterializationBoundary(input.contextUsageState);
306
421
  }
307
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
+ }
308
501
  observeTurnEvent({
309
502
  providerKey: input.providerKey,
310
503
  event: input.output.event,
@@ -314,6 +507,45 @@ function observeTurnOutput(input) {
314
507
  contextUsageState: input.contextUsageState
315
508
  });
316
509
  }
510
+ const SESSION_OPERATION_OBSERVATION_EVENT_TYPES = /* @__PURE__ */ new Set([
511
+ "item.started",
512
+ "item.updated",
513
+ "item.completed",
514
+ "progress.updated",
515
+ "context.usage.updated",
516
+ "operation.updated",
517
+ "resource.updated",
518
+ "runtime.warning",
519
+ "runtime.error",
520
+ "provider.diagnostic"
521
+ ]);
522
+ function observeSessionOperationOutput(input) {
523
+ if (input.output.kind === "event") {
524
+ const event = input.output.event;
525
+ if (!SESSION_OPERATION_OBSERVATION_EVENT_TYPES.has(event.type)) {
526
+ invalidTurnSequence(
527
+ input.providerKey,
528
+ "Provider emitted turn-owned output from a session operation."
529
+ );
530
+ }
531
+ if ((event.type === "item.started" || event.type === "item.updated" || event.type === "item.completed") && event.payload.itemKind !== "context_compaction") {
532
+ invalidTurnSequence(
533
+ input.providerKey,
534
+ "Provider emitted a non-compaction item from a session operation."
535
+ );
536
+ }
537
+ }
538
+ observeTurnOutput({
539
+ capabilities: input.capabilities,
540
+ providerKey: input.providerKey,
541
+ output: input.output,
542
+ state: input.state,
543
+ pendingRequests: /* @__PURE__ */ new Map(),
544
+ openedRequestIds: /* @__PURE__ */ new Set(),
545
+ contextUsageState: input.contextUsageState,
546
+ interactionState: input.interactionState
547
+ });
548
+ }
317
549
  function assertStableTurnBoundary(input) {
318
550
  const terminal = input.state.terminal && !input.state.waiting;
319
551
  const waiting = !input.state.terminal && input.state.waiting && input.pendingRequests.size === 1;
@@ -355,7 +587,9 @@ function observeTurnOperationOutputs(input) {
355
587
  state: input.state,
356
588
  pendingRequests: input.pendingRequests,
357
589
  openedRequestIds: input.openedRequestIds,
358
- contextUsageState: input.contextUsageState
590
+ contextUsageState: input.contextUsageState,
591
+ capabilities: input.capabilities,
592
+ interactionState: input.interactionState
359
593
  });
360
594
  }
361
595
  }
@@ -462,6 +696,15 @@ function validateAgentProviderSession(input) {
462
696
  cumulativeByScope: /* @__PURE__ */ new Map(),
463
697
  compactionReadyScopes: /* @__PURE__ */ new Set()
464
698
  };
699
+ const interactionState = {
700
+ operationResults: /* @__PURE__ */ new Map(),
701
+ operationInvocations: /* @__PURE__ */ new Map(),
702
+ collaborationNodes: /* @__PURE__ */ new Map(),
703
+ collaborationSpawnReservations: /* @__PURE__ */ new Map(),
704
+ generatedResources: /* @__PURE__ */ new Map()
705
+ };
706
+ const collaborationNodes = interactionState.collaborationNodes;
707
+ const collaborationSpawnReservations = interactionState.collaborationSpawnReservations;
465
708
  let activeTurn = null;
466
709
  let closePromise = null;
467
710
  let closed = false;
@@ -501,6 +744,49 @@ function validateAgentProviderSession(input) {
501
744
  throw error;
502
745
  }
503
746
  };
747
+ const delegateProviderMutation = async (input2) => {
748
+ let executionStarted = false;
749
+ const onProviderExecutionStarted = () => {
750
+ if (executionStarted) {
751
+ throwAgentProviderContractError(
752
+ providerKey,
753
+ "invalid_operation_result",
754
+ "Provider reported operation execution more than once."
755
+ );
756
+ }
757
+ input2.observer?.();
758
+ executionStarted = true;
759
+ };
760
+ const onOutput = async (candidate) => {
761
+ if (!executionStarted) {
762
+ throwAgentProviderContractError(
763
+ providerKey,
764
+ "invalid_operation_result",
765
+ "Provider emitted operation output before reporting execution start."
766
+ );
767
+ }
768
+ await input2.observeOutput?.(candidate);
769
+ };
770
+ try {
771
+ const candidate = await input2.invoke(onProviderExecutionStarted, onOutput);
772
+ if (!executionStarted) {
773
+ throwAgentProviderContractError(
774
+ providerKey,
775
+ "invalid_operation_result",
776
+ "Provider completed an operation without reporting execution start."
777
+ );
778
+ }
779
+ return input2.validate(candidate);
780
+ } catch (error) {
781
+ if (!executionStarted) throw error;
782
+ unusable = true;
783
+ throw new AgentProviderDelegatedOperationError(
784
+ providerKey,
785
+ input2.operation,
786
+ error
787
+ );
788
+ }
789
+ };
504
790
  const runTurn = async function* (turnInput) {
505
791
  requireUsable();
506
792
  throwIfAgentOperationAborted(turnInput.signal);
@@ -545,6 +831,7 @@ function validateAgentProviderSession(input) {
545
831
  fileChangeMode: capabilities.output.fileChanges,
546
832
  observedItems: /* @__PURE__ */ new Map(),
547
833
  proposedPlans: /* @__PURE__ */ new Map(),
834
+ generatedResourceIds: /* @__PURE__ */ new Set(),
548
835
  started: false,
549
836
  terminal: false,
550
837
  waiting: false,
@@ -564,12 +851,14 @@ function validateAgentProviderSession(input) {
564
851
  outputContext(parsedInput.turnId)
565
852
  );
566
853
  observeTurnOutput({
854
+ capabilities,
567
855
  providerKey,
568
856
  output,
569
857
  state: currentTurn.state,
570
858
  pendingRequests: currentTurn.pendingRequests,
571
859
  openedRequestIds,
572
- contextUsageState
860
+ contextUsageState,
861
+ interactionState
573
862
  });
574
863
  yield output;
575
864
  }
@@ -663,12 +952,14 @@ function validateAgentProviderSession(input) {
663
952
  outputContext(pending.turnId)
664
953
  );
665
954
  observeTurnOutput({
955
+ capabilities,
666
956
  providerKey,
667
957
  output,
668
958
  state: currentTurn.state,
669
959
  pendingRequests: currentTurn.pendingRequests,
670
960
  openedRequestIds,
671
- contextUsageState
961
+ contextUsageState,
962
+ interactionState
672
963
  });
673
964
  yield output;
674
965
  }
@@ -743,12 +1034,14 @@ function validateAgentProviderSession(input) {
743
1034
  }
744
1035
  try {
745
1036
  observeTurnOperationOutputs({
1037
+ capabilities,
746
1038
  providerKey,
747
1039
  outputs: result.outputs,
748
1040
  state: targetedTurn.state,
749
1041
  pendingRequests: targetedTurn.pendingRequests,
750
1042
  openedRequestIds,
751
- contextUsageState
1043
+ contextUsageState,
1044
+ interactionState
752
1045
  });
753
1046
  if (terminalized && !targetedTurn.state.terminal) {
754
1047
  completeTurnSequence({
@@ -821,22 +1114,467 @@ function validateAgentProviderSession(input) {
821
1114
  const declaredConfiguration = input.candidate.configuration;
822
1115
  const configuration = declaredConfiguration.kind === "managed" ? Object.freeze({ kind: "managed" }) : Object.freeze({
823
1116
  kind: "selectable",
824
- applyConfiguration: async (configurationInput) => {
1117
+ listConfiguration: async (listInput = {}) => {
825
1118
  requireUsable();
826
- throwIfAgentOperationAborted(configurationInput.signal);
827
- const configuration2 = parseAgentSessionConfiguration(
828
- configurationInput.configuration
1119
+ throwIfAgentOperationAborted(listInput.signal);
1120
+ return validateAgentConfigurationCatalogForCapabilities(
1121
+ capabilities,
1122
+ await declaredConfiguration.listConfiguration(
1123
+ listInput.signal === void 0 ? {} : { signal: listInput.signal }
1124
+ )
829
1125
  );
830
- assertAgentSessionConfigurationSupported(
1126
+ },
1127
+ applyConfigurationSelection: async (configurationInput) => {
1128
+ requireUsable();
1129
+ throwIfAgentOperationAborted(configurationInput.signal);
1130
+ const catalog = validateAgentConfigurationCatalogForCapabilities(
831
1131
  capabilities,
832
- configuration2
1132
+ await declaredConfiguration.listConfiguration(
1133
+ configurationInput.signal === void 0 ? {} : { signal: configurationInput.signal }
1134
+ )
833
1135
  );
834
- return delegateOperation(
835
- () => declaredConfiguration.applyConfiguration({
836
- configuration: configuration2,
1136
+ let selection;
1137
+ try {
1138
+ selection = parseAgentConfigurationSelectionFor(
1139
+ catalog,
1140
+ configurationInput.selection
1141
+ );
1142
+ } catch {
1143
+ return throwAgentProviderContractError(
1144
+ providerKey,
1145
+ "configuration_value_unsupported",
1146
+ "Configuration selection is stale or outside the offered catalog."
1147
+ );
1148
+ }
1149
+ return delegateProviderMutation({
1150
+ operation: "apply_configuration",
1151
+ observer: configurationInput.onProviderExecutionStarted,
1152
+ invoke: (onProviderExecutionStarted) => declaredConfiguration.applyConfigurationSelection({
1153
+ selection,
1154
+ onProviderExecutionStarted,
837
1155
  ...configurationInput.signal === void 0 ? {} : { signal: configurationInput.signal }
1156
+ }),
1157
+ validate: (candidate) => validateAgentProviderOperationResult(
1158
+ candidate,
1159
+ outputContext()
1160
+ )
1161
+ });
1162
+ }
1163
+ });
1164
+ const declaredOperations = input.candidate.operations;
1165
+ const operations = declaredOperations.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1166
+ kind: "supported",
1167
+ listOperations: async (listInput = {}) => {
1168
+ requireUsable();
1169
+ throwIfAgentOperationAborted(listInput.signal);
1170
+ return validateAgentOperationCatalogForCapabilities(
1171
+ capabilities,
1172
+ await declaredOperations.listOperations(
1173
+ listInput.signal === void 0 ? {} : { signal: listInput.signal }
1174
+ )
1175
+ );
1176
+ },
1177
+ invokeOperation: async (operationInput) => {
1178
+ requireUsable();
1179
+ throwIfAgentOperationAborted(operationInput.signal);
1180
+ let invocation;
1181
+ let observationTurnId;
1182
+ try {
1183
+ invocation = parseAgentOperationInvocation(operationInput.invocation);
1184
+ observationTurnId = parseAgentTurnId(
1185
+ operationInput.observationTurnId
1186
+ );
1187
+ } catch {
1188
+ return throwAgentProviderContractError(
1189
+ providerKey,
1190
+ "input_operation_mismatch",
1191
+ "Operation invocation is invalid."
1192
+ );
1193
+ }
1194
+ const catalog = validateAgentOperationCatalogForCapabilities(
1195
+ capabilities,
1196
+ await declaredOperations.listOperations(
1197
+ operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1198
+ )
1199
+ );
1200
+ const descriptor = catalog.operations.find(
1201
+ (operation) => operation.operationId === invocation.operationId
1202
+ );
1203
+ if (descriptor === void 0) {
1204
+ return throwAgentProviderContractError(
1205
+ providerKey,
1206
+ "input_operation_mismatch",
1207
+ "Operation invocation does not identify an offered operation."
1208
+ );
1209
+ }
1210
+ try {
1211
+ invocation = parseAgentOperationInvocationFor(
1212
+ descriptor,
1213
+ invocation
1214
+ );
1215
+ } catch {
1216
+ return throwAgentProviderContractError(
1217
+ providerKey,
1218
+ "input_operation_mismatch",
1219
+ "Operation invocation is stale or outside the offered descriptor."
1220
+ );
1221
+ }
1222
+ const existing = interactionState.operationInvocations.get(
1223
+ invocation.invocationId
1224
+ );
1225
+ if (existing !== void 0) {
1226
+ if (JSON.stringify(existing.invocation) !== JSON.stringify(invocation)) {
1227
+ return throwAgentProviderContractError(
1228
+ providerKey,
1229
+ "input_operation_mismatch",
1230
+ "Operation invocation ID was reused with conflicting input."
1231
+ );
1232
+ }
1233
+ if (descriptor.idempotency === "required" && existing.result !== void 0) {
1234
+ return existing.result;
1235
+ }
1236
+ return throwAgentProviderContractError(
1237
+ providerKey,
1238
+ "input_operation_mismatch",
1239
+ "Operation invocation ID is already active or is not replayable."
1240
+ );
1241
+ }
1242
+ const trackedInvocation = {
1243
+ invocation
1244
+ };
1245
+ const observationState = {
1246
+ fileChangeMode: capabilities.output.fileChanges,
1247
+ observedItems: /* @__PURE__ */ new Map(),
1248
+ proposedPlans: /* @__PURE__ */ new Map(),
1249
+ generatedResourceIds: /* @__PURE__ */ new Set(),
1250
+ started: true,
1251
+ terminal: false,
1252
+ waiting: false,
1253
+ finalDiffObserved: false
1254
+ };
1255
+ interactionState.operationInvocations.set(
1256
+ invocation.invocationId,
1257
+ trackedInvocation
1258
+ );
1259
+ try {
1260
+ const result = await delegateProviderMutation({
1261
+ operation: "invoke_operation",
1262
+ observer: operationInput.onProviderExecutionStarted,
1263
+ invoke: (onProviderExecutionStarted, onOutput) => declaredOperations.invokeOperation({
1264
+ invocation,
1265
+ observationTurnId,
1266
+ onProviderExecutionStarted,
1267
+ onOutput,
1268
+ ...operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1269
+ }),
1270
+ observeOutput: async (candidate) => {
1271
+ const output = validateAgentProviderOutputForContext(
1272
+ candidate,
1273
+ {
1274
+ ...outputContext(observationTurnId),
1275
+ operationInvocationId: invocation.invocationId
1276
+ }
1277
+ );
1278
+ observeSessionOperationOutput({
1279
+ capabilities,
1280
+ providerKey,
1281
+ output,
1282
+ state: observationState,
1283
+ contextUsageState,
1284
+ interactionState
1285
+ });
1286
+ await operationInput.onOutput?.(output);
1287
+ },
1288
+ validate: (candidate) => {
1289
+ const result2 = validateAgentOperationResultTransition({
1290
+ providerKey,
1291
+ candidate: validateAgentOperationResultForInvocation(
1292
+ providerKey,
1293
+ descriptor,
1294
+ invocation,
1295
+ candidate
1296
+ ),
1297
+ previous: interactionState.operationResults.get(
1298
+ invocation.invocationId
1299
+ )
1300
+ });
1301
+ interactionState.operationResults.set(
1302
+ result2.invocationId,
1303
+ result2
1304
+ );
1305
+ return result2;
1306
+ }
1307
+ });
1308
+ trackedInvocation.result = result;
1309
+ return result;
1310
+ } catch (error) {
1311
+ if (!(error instanceof AgentProviderDelegatedOperationError)) {
1312
+ interactionState.operationInvocations.delete(
1313
+ invocation.invocationId
1314
+ );
1315
+ }
1316
+ throw error;
1317
+ }
1318
+ }
1319
+ });
1320
+ const declaredManagedContent = input.candidate.managedContent;
1321
+ const managedContent = declaredManagedContent.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1322
+ kind: "supported",
1323
+ listManagedContent: async (listInput = {}) => {
1324
+ requireUsable();
1325
+ throwIfAgentOperationAborted(listInput.signal);
1326
+ return validateAgentManagedContentCatalogForCapabilities(
1327
+ capabilities,
1328
+ await declaredManagedContent.listManagedContent(
1329
+ listInput.signal === void 0 ? {} : { signal: listInput.signal }
1330
+ )
1331
+ );
1332
+ }
1333
+ });
1334
+ const declaredIntegrations = input.candidate.integrations;
1335
+ const integrations = declaredIntegrations.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1336
+ kind: "supported",
1337
+ observeIntegrations: async (listInput = {}) => {
1338
+ requireUsable();
1339
+ throwIfAgentOperationAborted(listInput.signal);
1340
+ return validateAgentIntegrationCatalogForCapabilities(
1341
+ capabilities,
1342
+ await declaredIntegrations.observeIntegrations(
1343
+ listInput.signal === void 0 ? {} : { signal: listInput.signal }
1344
+ )
1345
+ );
1346
+ }
1347
+ });
1348
+ const declaredCollaboration = input.candidate.collaboration;
1349
+ const collaboration = declaredCollaboration.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1350
+ kind: "supported",
1351
+ spawnCollaboration: async (collaborationInput) => {
1352
+ requireUsable();
1353
+ throwIfAgentOperationAborted(collaborationInput.signal);
1354
+ let spawn;
1355
+ try {
1356
+ spawn = parseAgentCollaborationSpawnInput(collaborationInput.spawn);
1357
+ } catch {
1358
+ return throwAgentProviderContractError(
1359
+ providerKey,
1360
+ "input_operation_mismatch",
1361
+ "Collaboration spawn input is invalid."
1362
+ );
1363
+ }
1364
+ const capability = capabilities.collaboration;
1365
+ if (capability.kind !== "supported" || !capability.controlActions.includes("spawn") || !capability.roles.includes(spawn.role) || collaborationNodes.has(spawn.collaborationId) || collaborationSpawnReservations.has(spawn.collaborationId)) {
1366
+ return throwAgentProviderContractError(
1367
+ providerKey,
1368
+ "input_capability_mismatch",
1369
+ "Collaboration spawn is outside the provider's declared capability."
1370
+ );
1371
+ }
1372
+ const observedParent = spawn.parentCollaborationId === void 0 ? void 0 : collaborationNodes.get(spawn.parentCollaborationId);
1373
+ const admission = evaluateCollaborationGraphAdmission({
1374
+ capability,
1375
+ candidate: {
1376
+ collaborationId: spawn.collaborationId,
1377
+ rootCollaborationId: observedParent?.rootCollaborationId ?? spawn.collaborationId,
1378
+ ...spawn.parentCollaborationId === void 0 ? {} : { parentCollaborationId: spawn.parentCollaborationId },
1379
+ active: true
1380
+ },
1381
+ nodes: collaborationNodes,
1382
+ reservations: collaborationSpawnReservations
1383
+ });
1384
+ if (admission.kind === "conflict") {
1385
+ return throwAgentProviderContractError(
1386
+ providerKey,
1387
+ "input_operation_mismatch",
1388
+ "Collaboration parent is unavailable in the canonical graph."
1389
+ );
1390
+ }
1391
+ if (admission.kind === "capacity_exceeded") {
1392
+ return throwAgentProviderContractError(
1393
+ providerKey,
1394
+ "input_capability_mismatch",
1395
+ "Collaboration graph limit would be exceeded."
1396
+ );
1397
+ }
1398
+ const parent = admission.parent;
1399
+ collaborationSpawnReservations.set(
1400
+ spawn.collaborationId,
1401
+ Object.freeze({
1402
+ ...spawn.parentCollaborationId === void 0 ? {} : { parentCollaborationId: spawn.parentCollaborationId }
838
1403
  })
839
1404
  );
1405
+ try {
1406
+ const node = await delegateProviderMutation({
1407
+ operation: "spawn_collaboration",
1408
+ observer: collaborationInput.onProviderExecutionStarted,
1409
+ invoke: (onProviderExecutionStarted) => declaredCollaboration.spawnCollaboration({
1410
+ spawn,
1411
+ onProviderExecutionStarted,
1412
+ ...collaborationInput.signal === void 0 ? {} : { signal: collaborationInput.signal }
1413
+ }),
1414
+ validate: (candidate) => {
1415
+ const node2 = validateAgentCollaborationNodeForCapabilities({
1416
+ capabilities,
1417
+ candidate
1418
+ });
1419
+ 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)) {
1420
+ return throwAgentProviderContractError(
1421
+ providerKey,
1422
+ "output_collaboration_mismatch",
1423
+ "Provider collaboration node does not match the spawn input."
1424
+ );
1425
+ }
1426
+ return node2;
1427
+ }
1428
+ });
1429
+ collaborationNodes.set(node.collaborationId, node);
1430
+ collaborationSpawnReservations.delete(spawn.collaborationId);
1431
+ return node;
1432
+ } catch (error) {
1433
+ if (!(error instanceof AgentProviderDelegatedOperationError)) {
1434
+ collaborationSpawnReservations.delete(spawn.collaborationId);
1435
+ }
1436
+ throw error;
1437
+ }
1438
+ },
1439
+ controlCollaboration: async (collaborationInput) => {
1440
+ requireUsable();
1441
+ throwIfAgentOperationAborted(collaborationInput.signal);
1442
+ let control;
1443
+ try {
1444
+ control = parseAgentCollaborationControlInput(
1445
+ collaborationInput.control
1446
+ );
1447
+ } catch {
1448
+ return throwAgentProviderContractError(
1449
+ providerKey,
1450
+ "input_operation_mismatch",
1451
+ "Collaboration control input is invalid."
1452
+ );
1453
+ }
1454
+ const capability = capabilities.collaboration;
1455
+ const previous = collaborationNodes.get(control.collaborationId);
1456
+ if (capability.kind !== "supported" || !capability.controlActions.includes(control.action) || previous === void 0) {
1457
+ return throwAgentProviderContractError(
1458
+ providerKey,
1459
+ "input_capability_mismatch",
1460
+ "Collaboration control is outside the observed graph or declared capability."
1461
+ );
1462
+ }
1463
+ const terminal = ["completed", "failed", "canceled"].includes(
1464
+ previous.status
1465
+ );
1466
+ if (control.action === "close" && previous.closedAt !== void 0) {
1467
+ return previous;
1468
+ }
1469
+ if (control.action === "close" && !terminal || control.action === "stop" && terminal || control.action === "steer" && terminal || control.action !== "inspect" && previous.closedAt !== void 0) {
1470
+ return throwAgentProviderContractError(
1471
+ providerKey,
1472
+ "input_capability_mismatch",
1473
+ "Collaboration control is unavailable in the current lifecycle state."
1474
+ );
1475
+ }
1476
+ const node = await delegateProviderMutation({
1477
+ operation: "control_collaboration",
1478
+ observer: collaborationInput.onProviderExecutionStarted,
1479
+ invoke: (onProviderExecutionStarted) => declaredCollaboration.controlCollaboration({
1480
+ control,
1481
+ onProviderExecutionStarted,
1482
+ ...collaborationInput.signal === void 0 ? {} : { signal: collaborationInput.signal }
1483
+ }),
1484
+ validate: (candidate) => {
1485
+ const validated = validateAgentCollaborationNodeForCapabilities({
1486
+ capabilities,
1487
+ candidate,
1488
+ previous
1489
+ });
1490
+ if (control.action === "stop" && validated.status !== "canceled" || control.action === "close" && (validated.status !== previous.status || validated.closedAt === void 0)) {
1491
+ return throwAgentProviderContractError(
1492
+ providerKey,
1493
+ "output_collaboration_mismatch",
1494
+ "Provider collaboration result does not settle the requested control action."
1495
+ );
1496
+ }
1497
+ return validated;
1498
+ }
1499
+ });
1500
+ collaborationNodes.set(node.collaborationId, node);
1501
+ return node;
1502
+ }
1503
+ });
1504
+ function validateGeneratedResourceInspection(candidate, resourceId) {
1505
+ if (candidate === null || typeof candidate !== "object" || !hasExactOwnKeys(candidate, [
1506
+ "descriptor",
1507
+ ..."candidate" in candidate ? ["candidate"] : []
1508
+ ])) {
1509
+ return throwAgentProviderContractError(
1510
+ providerKey,
1511
+ "output_resource_mismatch",
1512
+ "Provider returned an invalid generated-resource inspection."
1513
+ );
1514
+ }
1515
+ const rawInspection = candidate;
1516
+ const descriptor = validateAgentGeneratedResourceForCapabilities({
1517
+ capabilities,
1518
+ candidate: rawInspection.descriptor,
1519
+ expectedResourceId: resourceId,
1520
+ previous: interactionState.generatedResources.get(resourceId)
1521
+ });
1522
+ const hasCandidate = Object.prototype.hasOwnProperty.call(
1523
+ rawInspection,
1524
+ "candidate"
1525
+ );
1526
+ if (descriptor.status === "available" !== hasCandidate) {
1527
+ return throwAgentProviderContractError(
1528
+ providerKey,
1529
+ "output_resource_mismatch",
1530
+ "Exactly available generated resources must include owned artifact bytes."
1531
+ );
1532
+ }
1533
+ if (!hasCandidate) return Object.freeze({ descriptor });
1534
+ let artifactCandidate;
1535
+ try {
1536
+ artifactCandidate = createAgentArtifactCandidate(
1537
+ rawInspection.candidate
1538
+ );
1539
+ } catch {
1540
+ return throwAgentProviderContractError(
1541
+ providerKey,
1542
+ "output_resource_mismatch",
1543
+ "Provider returned invalid generated-resource artifact bytes."
1544
+ );
1545
+ }
1546
+ const artifact = artifactCandidate.descriptor;
1547
+ const expectedArtifactKind = descriptor.kind === "image" ? "image" : "file";
1548
+ 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) {
1549
+ return throwAgentProviderContractError(
1550
+ providerKey,
1551
+ "output_resource_mismatch",
1552
+ "Generated-resource metadata does not match its immutable artifact candidate."
1553
+ );
1554
+ }
1555
+ return Object.freeze({ descriptor, candidate: artifactCandidate });
1556
+ }
1557
+ const declaredGeneratedResources = input.candidate.generatedResources;
1558
+ const generatedResources = declaredGeneratedResources.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
1559
+ kind: "supported",
1560
+ getGeneratedResource: async (resourceInput) => {
1561
+ requireUsable();
1562
+ throwIfAgentOperationAborted(resourceInput.signal);
1563
+ const resourceId = parseAgentGeneratedResourceId(
1564
+ resourceInput.resourceId
1565
+ );
1566
+ const inspection = validateGeneratedResourceInspection(
1567
+ await declaredGeneratedResources.getGeneratedResource({
1568
+ resourceId,
1569
+ ...resourceInput.signal === void 0 ? {} : { signal: resourceInput.signal }
1570
+ }),
1571
+ resourceId
1572
+ );
1573
+ interactionState.generatedResources.set(
1574
+ inspection.descriptor.resourceId,
1575
+ inspection.descriptor
1576
+ );
1577
+ return inspection;
840
1578
  }
841
1579
  });
842
1580
  const close = (closeInput) => {
@@ -868,6 +1606,11 @@ function validateAgentProviderSession(input) {
868
1606
  interruption,
869
1607
  steering,
870
1608
  configuration,
1609
+ operations,
1610
+ managedContent,
1611
+ integrations,
1612
+ collaboration,
1613
+ generatedResources,
871
1614
  close
872
1615
  });
873
1616
  }