@agen-ai/agent-runtime 0.4.2 → 0.4.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.
Files changed (58) hide show
  1. package/README.md +316 -10
  2. package/dist/adapterValidation.js +38 -4
  3. package/dist/contractErrors.d.ts +2 -2
  4. package/dist/contractErrors.js +8 -1
  5. package/dist/executionInput/index.d.ts +3 -0
  6. package/dist/executionInput/index.js +4 -0
  7. package/dist/executionInput/lifetime.d.ts +47 -0
  8. package/dist/executionInput/lifetime.js +241 -0
  9. package/dist/executionInput/types.d.ts +61 -0
  10. package/dist/executionInput/types.js +0 -0
  11. package/dist/executionInput/validation.d.ts +25 -0
  12. package/dist/executionInput/validation.js +178 -0
  13. package/dist/generation/cleanup.d.ts +15 -0
  14. package/dist/generation/cleanup.js +108 -0
  15. package/dist/generation/deadline.d.ts +16 -0
  16. package/dist/generation/deadline.js +81 -0
  17. package/dist/generation/decoding.d.ts +4 -0
  18. package/dist/generation/decoding.js +59 -0
  19. package/dist/generation/errors.d.ts +29 -0
  20. package/dist/generation/errors.js +39 -0
  21. package/dist/generation/generateObject.d.ts +3 -0
  22. package/dist/generation/generateObject.js +148 -0
  23. package/dist/generation/index.d.ts +5 -0
  24. package/dist/generation/index.js +8 -0
  25. package/dist/generation/preflight.d.ts +25 -0
  26. package/dist/generation/preflight.js +48 -0
  27. package/dist/generation/requests.d.ts +17 -0
  28. package/dist/generation/requests.js +117 -0
  29. package/dist/generation/types.d.ts +22 -0
  30. package/dist/generation/types.js +0 -0
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.js +7 -1
  33. package/dist/nativeContinuations/admission.js +1 -0
  34. package/dist/outputValidation.d.ts +2 -0
  35. package/dist/outputValidation.js +29 -1
  36. package/dist/sessionAdmission.d.ts +2 -0
  37. package/dist/sessionAdmission.js +13 -0
  38. package/dist/sessionInteractions/lifetime.d.ts +1 -0
  39. package/dist/sessionInteractions/lifetime.js +4 -0
  40. package/dist/sessionInteractions/request.d.ts +1 -0
  41. package/dist/sessionInteractions/request.js +3 -0
  42. package/dist/sessionValidation.d.ts +15 -3
  43. package/dist/sessionValidation.js +215 -127
  44. package/dist/sessions.d.ts +7 -1
  45. package/dist/structuredOutput/admission.d.ts +16 -0
  46. package/dist/structuredOutput/admission.js +89 -0
  47. package/dist/structuredOutput/candidate.d.ts +22 -0
  48. package/dist/structuredOutput/candidate.js +64 -0
  49. package/dist/structuredOutput/validation.d.ts +8 -0
  50. package/dist/structuredOutput/validation.js +26 -0
  51. package/dist/testing/conformance.d.ts +20 -1
  52. package/dist/testing/conformance.js +103 -3
  53. package/dist/testing/fakeProvider.js +5 -4
  54. package/dist/turnExecution/execution.d.ts +9 -1
  55. package/dist/turnExecution/execution.js +88 -7
  56. package/dist/turnExecution/terminalBuffer.d.ts +9 -0
  57. package/dist/turnExecution/terminalBuffer.js +38 -0
  58. package/package.json +6 -2
@@ -1,6 +1,7 @@
1
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
+ import type { AgentStructuredOutputBinding } from "./structuredOutput/admission.js";
4
5
  export interface AgentProviderOutputValidationContext {
5
6
  readonly capabilities: AgentCapabilities;
6
7
  readonly providerKey: AgentProviderKey;
@@ -10,6 +11,7 @@ export interface AgentProviderOutputValidationContext {
10
11
  readonly operationInvocationId?: AgentOperationInvocationId;
11
12
  readonly collaborationId?: AgentCollaborationId;
12
13
  readonly generatedResourceId?: AgentGeneratedResourceId;
14
+ readonly structuredOutputBinding?: AgentStructuredOutputBinding;
13
15
  }
14
16
  export declare function validateAgentProviderOutputForContext(candidate: AgentProviderOutput, context: AgentProviderOutputValidationContext): AgentProviderOutput;
15
17
  export declare function validateAgentProviderOperationResult(candidate: AgentProviderOperationResult, context: AgentProviderOutputValidationContext): AgentProviderOperationResult;
@@ -1,10 +1,14 @@
1
1
  import {
2
- parseAgentError
2
+ AGENT_PROTOCOL_EVENT_BYTES_LIMIT,
3
+ agentProtocolSerializedJsonBytes,
4
+ parseAgentError,
5
+ parseAgentEvent
3
6
  } from "@agen-ai/agent-protocol";
4
7
  import { throwAgentProviderContractError } from "./contractErrors.js";
5
8
  import {
6
9
  validateAgentProviderOutput
7
10
  } from "./outputs.js";
11
+ import { validateAgentStructuredOutputResult } from "./structuredOutput/validation.js";
8
12
  function unsupportedCapabilitySemantic(value) {
9
13
  throw new TypeError(
10
14
  `Unsupported Agent Protocol capability semantic: ${String(value)}.`
@@ -206,6 +210,30 @@ function validateAgentProviderOutputForContext(candidate, context) {
206
210
  );
207
211
  }
208
212
  assertOutputCapability(context, output);
213
+ if (output.kind === "event" && output.event.type === "turn.completed") {
214
+ let structuredOutput = validateAgentStructuredOutputResult({
215
+ providerKey: context.providerKey,
216
+ ...context.structuredOutputBinding === void 0 ? {} : { binding: context.structuredOutputBinding },
217
+ result: output.event.payload.structuredOutput
218
+ });
219
+ if (output.event.payload.outcome !== "completed") return output;
220
+ let event = {
221
+ ...output.event,
222
+ payload: { ...output.event.payload, structuredOutput }
223
+ };
224
+ if (structuredOutput.kind === "unavailable" && structuredOutput.reason === "schema_mismatch" && structuredOutput.issues !== void 0 && agentProtocolSerializedJsonBytes(event) > AGENT_PROTOCOL_EVENT_BYTES_LIMIT) {
225
+ structuredOutput = Object.freeze({ kind: "unavailable", reason: "schema_mismatch" });
226
+ event = { ...event, payload: { ...event.payload, structuredOutput } };
227
+ }
228
+ parseAgentEvent(event);
229
+ return Object.freeze({
230
+ ...output,
231
+ event: Object.freeze({
232
+ ...event,
233
+ payload: Object.freeze(event.payload)
234
+ })
235
+ });
236
+ }
209
237
  return output;
210
238
  }
211
239
  function validateAgentProviderOperationResult(candidate, context) {
@@ -1,5 +1,7 @@
1
1
  import type { AgentProviderKey, AgentRequestId } from "@agen-ai/agent-protocol";
2
2
  export declare function createAgentSessionAdmission<Execution = unknown>(providerKey: AgentProviderKey): {
3
+ trackOperation(): () => void;
4
+ joinOperations(): Promise<void>;
3
5
  reserveExecution(): object;
4
6
  installExecution(token: object, execution: Execution): void;
5
7
  releaseExecution(token: object): void;
@@ -6,7 +6,20 @@ function createAgentSessionAdmission(providerKey) {
6
6
  let requestIdBytes = 0;
7
7
  let slot;
8
8
  let stopped = false;
9
+ const operations = /* @__PURE__ */ new Set();
9
10
  return {
11
+ trackOperation() {
12
+ if (stopped) throwAgentProviderContractError(providerKey, "session_unusable", "Session admission is stopped.");
13
+ const completion = Promise.withResolvers();
14
+ operations.add(completion.promise);
15
+ return () => {
16
+ operations.delete(completion.promise);
17
+ completion.resolve();
18
+ };
19
+ },
20
+ async joinOperations() {
21
+ await Promise.all(operations);
22
+ },
10
23
  reserveExecution() {
11
24
  if (stopped) throwAgentProviderContractError(providerKey, "session_unusable", "Session admission is stopped.");
12
25
  if (slot) throwAgentProviderContractError(providerKey, "concurrent_turn", "Provider session already owns an execution.");
@@ -49,6 +49,7 @@ export declare class SessionInteractionOwner {
49
49
  constructor(providerKey: AgentProviderKey, sessionId: AgentSessionId, context: AgentSessionInteractionContext, validationOwner: AgentSessionValidationOwner, operation: AgentSessionInteractionOpeningOperation, support: AgentSessionInteractionSupport, nativeSupport: AgentNativeContinuationSupport, continuations?: AgentNativeContinuationContext, signal?: AbortSignal);
50
50
  track<Result>(promise: Promise<Result>): Promise<Result>;
51
51
  get accepting(): boolean;
52
+ get hasLiveRequests(): boolean;
52
53
  requireUsable(): void;
53
54
  private offer;
54
55
  requireContinuation(kind: "form" | "plan_review"): void;
@@ -102,6 +102,10 @@ class SessionInteractionOwner {
102
102
  get accepting() {
103
103
  return this.state === "opening" || this.state === "open";
104
104
  }
105
+ get hasLiveRequests() {
106
+ for (const request of this.requests.values()) if (request.blocksExecutionInput) return true;
107
+ return false;
108
+ }
105
109
  requireUsable() {
106
110
  if (this.fatal) throw this.fatal.cause;
107
111
  this.validationOwner.requireUsable();
@@ -25,6 +25,7 @@ export declare class SessionInteractionRequest {
25
25
  constructor(owner: SessionInteractionOwner, candidate: Candidate, retire: () => void);
26
26
  observe(): void;
27
27
  setCallback(callback: Promise<void>): void;
28
+ get blocksExecutionInput(): boolean;
28
29
  private scheduleExpiry;
29
30
  private expire;
30
31
  private protocolFailure;
@@ -76,6 +76,9 @@ class SessionInteractionRequest {
76
76
  }
77
77
  );
78
78
  }
79
+ get blocksExecutionInput() {
80
+ return this.state.kind !== "terminal" || this.responseWork > 0 || !this.rawTerminalSettled;
81
+ }
79
82
  scheduleExpiry() {
80
83
  if (this.candidate.deadlineAt === void 0 || this.state.kind === "terminal") return;
81
84
  const remainingMs = this.candidate.deadlineAt - Date.now();
@@ -1,4 +1,4 @@
1
- import { type AgentCapabilities, type AgentCollaborationNode, type AgentContextCumulativeUsage, type AgentContextMeasurementScope, type AgentContextUsage, type AgentGeneratedResourceDescriptor, type AgentItemKind, type AgentItemStatus, type AgentOperationInvocation, type AgentOperationResult, type AgentProviderKey, type AgentSessionBinding, type AgentSessionId, type AgentTurnId } from "@agen-ai/agent-protocol";
1
+ import { type AgentCapabilities, type AgentCollaborationNode, type AgentContextCumulativeUsage, type AgentContextMeasurementScope, type AgentContextUsage, type AgentGeneratedResourceDescriptor, type AgentItemKind, type AgentItemStatus, type AgentOperationInputCapability, type AgentOperationInvocation, type AgentOperationResult, type AgentProviderKey, type AgentSessionBinding, type AgentSessionId, type AgentTurnId } from "@agen-ai/agent-protocol";
2
2
  import { type AgentHostBindingLease } from "./hostBindings/lifetime.js";
3
3
  import { type MaybePromise } from "./foundation.js";
4
4
  import { type AgentProviderOutputValidationContext } from "./outputValidation.js";
@@ -6,6 +6,8 @@ import type { AgentProviderStartTurnInput, AgentProviderSession, AgentSessionBin
6
6
  import { type ValidatedAgentTurnExecution, type AdoptedAgentTurnExecution } from "./turnExecution/execution.js";
7
7
  import { type PendingAgentRequest } from "./turnExecution/requests.js";
8
8
  import type { SessionInteractionOwner } from "./sessionInteractions/lifetime.js";
9
+ import type { AgentExecutionInputSupport } from "./executionInput/types.js";
10
+ import { type AgentStructuredOutputBinding } from "./structuredOutput/admission.js";
9
11
  interface ObservedAgentItem {
10
12
  readonly itemKind: AgentItemKind;
11
13
  readonly status: AgentItemStatus;
@@ -47,8 +49,15 @@ interface ActiveAgentTurn {
47
49
  readonly inFlightOperations: Set<Promise<void>>;
48
50
  readonly owner: ValidatedAgentTurnExecution;
49
51
  }
50
- export declare function createAgentSessionValidationOwner(capabilities: AgentCapabilities, sessionId: AgentSessionId): {
52
+ export declare function assertAgentTurnInputCapability(input: {
53
+ readonly capability: AgentOperationInputCapability;
54
+ readonly parts: AgentProviderStartTurnInput["parts"];
55
+ readonly providerKey: AgentProviderKey;
56
+ }): void;
57
+ export declare function createAgentSessionValidationOwner(capabilities: AgentCapabilities, sessionId: AgentSessionId, structuredOutputBinding?: AgentStructuredOutputBinding, executionInputSupport?: AgentExecutionInputSupport): {
51
58
  sessionAdmission: {
59
+ trackOperation(): () => void;
60
+ joinOperations(): Promise<void>;
52
61
  reserveExecution(): object;
53
62
  installExecution(token: object, execution: ActiveAgentTurn): void;
54
63
  releaseExecution(token: object): void;
@@ -69,11 +78,14 @@ export declare function createAgentSessionValidationOwner(capabilities: AgentCap
69
78
  stop(): void;
70
79
  completeClose(): void;
71
80
  installClose(close: () => Promise<void>): void;
81
+ installInputContextGuard(guard: () => void): void;
72
82
  reserveExecution: () => object;
73
83
  ownsExecution: (token: object) => boolean;
74
84
  releaseExecution: (token: object) => void;
85
+ admitTurnOutput(output: unknown, hasOutput: boolean): AgentStructuredOutputBinding | undefined;
86
+ requireNativeContinuationSupport: () => void;
75
87
  installNativeExecution(token: object, turnId: AgentTurnId, createCandidate: (signal: AbortSignal) => AgentProviderTurnExecution): AdoptedAgentTurnExecution;
76
- installCallerExecution(token: object, turnInput: AgentProviderStartTurnInput, start: (input: AgentProviderStartTurnInput) => AgentProviderTurnExecution): ValidatedAgentTurnExecution;
88
+ installCallerExecution(token: object, turnInput: AgentProviderStartTurnInput, start: (input: AgentProviderStartTurnInput) => AgentProviderTurnExecution, binding?: AgentStructuredOutputBinding): ValidatedAgentTurnExecution;
77
89
  };
78
90
  export type AgentSessionValidationOwner = ReturnType<typeof createAgentSessionValidationOwner>;
79
91
  export declare function validateAgentProviderSession(input: {
@@ -48,6 +48,10 @@ import { createValidatedAgentTurnExecution, adoptValidatedAgentTurnExecution } f
48
48
  import { validateAgentProviderTurnInterruptionResult } from "./turnExecution/receipts.js";
49
49
  import { createAgentTurnRequestAdmission } from "./turnExecution/requests.js";
50
50
  import { createAgentSessionAdmission } from "./sessionAdmission.js";
51
+ import { createExecutionInputCensus } from "./executionInput/lifetime.js";
52
+ import {
53
+ admitAgentStructuredOutputTurn
54
+ } from "./structuredOutput/admission.js";
51
55
  function validateCloseReason(reason) {
52
56
  if (reason !== void 0 && !["idle", "shutdown", "replaced", "contract_rejected", "error", "other"].includes(reason)) {
53
57
  throw new TypeError("Provider session close reason is unsupported.");
@@ -499,6 +503,7 @@ const SESSION_OPERATION_OBSERVATION_EVENT_TYPES = /* @__PURE__ */ new Set([
499
503
  "resource.updated",
500
504
  "runtime.warning",
501
505
  "runtime.error",
506
+ "runtime.retrying",
502
507
  "provider.diagnostic"
503
508
  ]);
504
509
  function observeSessionOperationOutput(input) {
@@ -619,7 +624,7 @@ function assertAgentTurnInputCapability(input) {
619
624
  });
620
625
  if (textIssue) rejectReference(`${textIssue.target} must use ${textIssue.format} text`);
621
626
  }
622
- function createAgentSessionValidationOwner(capabilities, sessionId) {
627
+ function createAgentSessionValidationOwner(capabilities, sessionId, structuredOutputBinding, executionInputSupport) {
623
628
  const providerKey = capabilities.providerKey;
624
629
  const sessionLifetime = new AbortController();
625
630
  const sessionAdmission = createAgentSessionAdmission(providerKey);
@@ -638,6 +643,15 @@ function createAgentSessionValidationOwner(capabilities, sessionId) {
638
643
  let closed = false;
639
644
  let unusable = false;
640
645
  let closing;
646
+ let requireInputContext = () => {
647
+ };
648
+ const executionInputCensus = createExecutionInputCensus(providerKey, () => {
649
+ unusable = true;
650
+ queueMicrotask(() => {
651
+ void closing?.().catch(() => {
652
+ });
653
+ });
654
+ });
641
655
  const requireOpen = () => {
642
656
  if (closed)
643
657
  throwAgentProviderContractError(
@@ -676,6 +690,11 @@ function createAgentSessionValidationOwner(capabilities, sessionId) {
676
690
  const inFlightOperations = /* @__PURE__ */ new Set();
677
691
  const common = {
678
692
  providerKey,
693
+ ...executionInputSupport === void 0 ? {} : { executionInputSupport },
694
+ executionInputCensus,
695
+ ownsExecution: () => sessionAdmission.ownsExecution(token),
696
+ requireInputContext: () => requireInputContext(),
697
+ structuredOutputBound: source.kind === "caller" && source.binding !== void 0,
679
698
  pendingRequests,
680
699
  sessionAdmission,
681
700
  inFlightOperations,
@@ -683,7 +702,10 @@ function createAgentSessionValidationOwner(capabilities, sessionId) {
683
702
  isTerminal: () => state.terminal,
684
703
  canRestoreRequest: (pending) => hasLiveApprovalSubject(pending.request, state),
685
704
  observe(candidate, requests) {
686
- const output = validateAgentProviderOutputForContext(candidate, outputContext(turnId));
705
+ const output = validateAgentProviderOutputForContext(candidate, {
706
+ ...outputContext(turnId),
707
+ ...source.kind !== "caller" || source.binding === void 0 ? {} : { structuredOutputBinding: source.binding }
708
+ });
687
709
  observeTurnOutput({
688
710
  capabilities,
689
711
  providerKey,
@@ -718,6 +740,15 @@ function createAgentSessionValidationOwner(capabilities, sessionId) {
718
740
  }
719
741
  return owner;
720
742
  }
743
+ const requireNativeContinuationSupport = () => {
744
+ if (structuredOutputBinding !== void 0) {
745
+ throwAgentProviderContractError(
746
+ providerKey,
747
+ "structured_output_unsupported",
748
+ "Schema-bound sessions cannot dispatch native continuations without structured-output admission."
749
+ );
750
+ }
751
+ };
721
752
  return {
722
753
  sessionAdmission,
723
754
  sessionLifetime,
@@ -748,14 +779,38 @@ function createAgentSessionValidationOwner(capabilities, sessionId) {
748
779
  installClose(close) {
749
780
  closing = close;
750
781
  },
782
+ installInputContextGuard(guard) {
783
+ requireInputContext = guard;
784
+ },
751
785
  reserveExecution: sessionAdmission.reserveExecution,
752
786
  ownsExecution: sessionAdmission.ownsExecution,
753
787
  releaseExecution: sessionAdmission.releaseExecution,
788
+ admitTurnOutput(output, hasOutput) {
789
+ if (structuredOutputBinding !== void 0 && hasOutput) {
790
+ throwAgentProviderContractError(
791
+ providerKey,
792
+ "structured_output_scope_mismatch",
793
+ "A schema-bound session cannot override or remove its opening structured-output request."
794
+ );
795
+ }
796
+ return admitAgentStructuredOutputTurn({
797
+ capabilities,
798
+ ...structuredOutputBinding === void 0 ? {} : { binding: structuredOutputBinding },
799
+ output
800
+ });
801
+ },
802
+ requireNativeContinuationSupport,
754
803
  installNativeExecution(token, turnId, createCandidate) {
804
+ requireNativeContinuationSupport();
755
805
  return installExecution(token, turnId, { kind: "native", createCandidate });
756
806
  },
757
- installCallerExecution(token, turnInput, start) {
758
- return installExecution(token, turnInput.turnId, { kind: "caller", input: turnInput, start });
807
+ installCallerExecution(token, turnInput, start, binding) {
808
+ return installExecution(token, turnInput.turnId, {
809
+ kind: "caller",
810
+ input: turnInput,
811
+ start,
812
+ ...binding === void 0 ? {} : { binding }
813
+ });
759
814
  }
760
815
  };
761
816
  }
@@ -795,6 +850,14 @@ function validateAgentProviderSession(input) {
795
850
  }
796
851
  validateSessionPorts(capabilities, input.candidate);
797
852
  const validationOwner = input.validationOwner ?? createAgentSessionValidationOwner(capabilities, sessionId);
853
+ validationOwner.installInputContextGuard(() => {
854
+ input.sessionInteractionOwner?.requireUsable();
855
+ if (input.sessionInteractionOwner?.hasLiveRequests) throwAgentProviderContractError(
856
+ providerKey,
857
+ "request_pending",
858
+ "Execution input cannot enter while a session interaction remains unsettled."
859
+ );
860
+ });
798
861
  const { sessionLifetime, contextUsageState, interactionState, outputContext } = validationOwner;
799
862
  const collaborationNodes = interactionState.collaborationNodes;
800
863
  const collaborationSpawnReservations = interactionState.collaborationSpawnReservations;
@@ -861,6 +924,7 @@ function validateAgentProviderSession(input) {
861
924
  turnId: turnInput.turnId,
862
925
  interactionMode: turnInput.interactionMode,
863
926
  parts: turnInput.parts,
927
+ ...turnInput.output === void 0 ? {} : { output: turnInput.output },
864
928
  ...turnInput.summary === void 0 ? {} : { summary: turnInput.summary },
865
929
  ...turnInput.deadlineAt === void 0 ? {} : { deadlineAt: turnInput.deadlineAt }
866
930
  });
@@ -872,13 +936,15 @@ function validateAgentProviderSession(input) {
872
936
  `Provider ${providerKey} does not support ${parsedInput.interactionMode} turn interaction mode.`
873
937
  );
874
938
  }
939
+ const binding2 = validationOwner.admitTurnOutput(parsedInput.output, Reflect.has(turnInput, "output"));
875
940
  const token = validationOwner.reserveExecution();
876
941
  try {
877
942
  return validationOwner.installCallerExecution(token, {
878
943
  ...parsedInput,
944
+ ...parsedInput.output === void 0 || binding2 === void 0 ? {} : { output: binding2.request },
879
945
  ...turnInput.signal === void 0 ? {} : { signal: turnInput.signal },
880
946
  ...turnInput.onProviderExecutionStarted === void 0 ? {} : { onProviderExecutionStarted: turnInput.onProviderExecutionStarted }
881
- }, (inputTurn) => input.candidate.startTurn(inputTurn)).execution;
947
+ }, (inputTurn) => input.candidate.startTurn(inputTurn), binding2).execution;
882
948
  } catch (error) {
883
949
  validationOwner.releaseExecution(token);
884
950
  throw error;
@@ -907,6 +973,7 @@ function validateAgentProviderSession(input) {
907
973
  const settleActiveInterruption = trackActiveTurnOperation(
908
974
  targetedActiveTurn
909
975
  );
976
+ targetedTurn.owner.closeInputAdmission();
910
977
  try {
911
978
  const suspendedRequests = targetedTurn.owner.suspendRequests();
912
979
  let result;
@@ -938,6 +1005,13 @@ function validateAgentProviderSession(input) {
938
1005
  steerTurn: async (steeringInput) => {
939
1006
  requireUsable();
940
1007
  throwIfAgentOperationAborted(steeringInput.signal);
1008
+ if (Reflect.has(steeringInput, "output")) {
1009
+ throwAgentProviderContractError(
1010
+ providerKey,
1011
+ "structured_output_scope_mismatch",
1012
+ "Steering cannot change a turn's structured-output request."
1013
+ );
1014
+ }
941
1015
  const turnId = parseAgentTurnId(steeringInput.turnId);
942
1016
  if (validationOwner.activeTurn?.turnId !== turnId || !validationOwner.activeTurn.owner.hasEntered() || validationOwner.activeTurn.state.terminal || validationOwner.activeTurn.pendingRequests.size > 0) {
943
1017
  throwAgentProviderContractError(
@@ -1048,142 +1122,154 @@ function validateAgentProviderSession(input) {
1048
1122
  invokeOperation: async (operationInput) => {
1049
1123
  requireUsable();
1050
1124
  throwIfAgentOperationAborted(operationInput.signal);
1051
- let invocation;
1052
- let observationTurnId;
1125
+ const settle = validationOwner.sessionAdmission.trackOperation();
1126
+ const signal = operationInput.signal === void 0 ? sessionLifetime.signal : AbortSignal.any([operationInput.signal, sessionLifetime.signal]);
1127
+ operationInput = { ...operationInput, signal };
1053
1128
  try {
1054
- invocation = parseAgentOperationInvocation(operationInput.invocation);
1055
- observationTurnId = parseAgentTurnId(
1056
- operationInput.observationTurnId
1057
- );
1058
- } catch {
1059
- return throwAgentProviderContractError(
1060
- providerKey,
1061
- "input_operation_mismatch",
1062
- "Operation invocation is invalid."
1063
- );
1064
- }
1065
- const catalog = validateAgentOperationCatalogForCapabilities(
1066
- capabilities,
1067
- await declaredOperations.listOperations(
1068
- operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1069
- )
1070
- );
1071
- const descriptor = catalog.operations.find(
1072
- (operation) => operation.operationId === invocation.operationId
1073
- );
1074
- if (descriptor === void 0) {
1075
- return throwAgentProviderContractError(
1076
- providerKey,
1077
- "input_operation_mismatch",
1078
- "Operation invocation does not identify an offered operation."
1129
+ let invocation;
1130
+ let observationTurnId;
1131
+ try {
1132
+ invocation = parseAgentOperationInvocation(operationInput.invocation);
1133
+ observationTurnId = parseAgentTurnId(
1134
+ operationInput.observationTurnId
1135
+ );
1136
+ } catch {
1137
+ return throwAgentProviderContractError(
1138
+ providerKey,
1139
+ "input_operation_mismatch",
1140
+ "Operation invocation is invalid."
1141
+ );
1142
+ }
1143
+ const catalog = validateAgentOperationCatalogForCapabilities(
1144
+ capabilities,
1145
+ await declaredOperations.listOperations(
1146
+ operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1147
+ )
1079
1148
  );
1080
- }
1081
- try {
1082
- invocation = parseAgentOperationInvocationFor(
1083
- descriptor,
1084
- invocation
1149
+ const descriptor = catalog.operations.find(
1150
+ (operation) => operation.operationId === invocation.operationId
1085
1151
  );
1086
- } catch {
1087
- return throwAgentProviderContractError(
1088
- providerKey,
1089
- "input_operation_mismatch",
1090
- "Operation invocation is stale or outside the offered descriptor."
1091
- );
1092
- }
1093
- const existing = interactionState.operationInvocations.get(
1094
- invocation.invocationId
1095
- );
1096
- if (existing !== void 0) {
1097
- if (JSON.stringify(existing.invocation) !== JSON.stringify(invocation)) {
1152
+ if (descriptor === void 0) {
1098
1153
  return throwAgentProviderContractError(
1099
1154
  providerKey,
1100
1155
  "input_operation_mismatch",
1101
- "Operation invocation ID was reused with conflicting input."
1156
+ "Operation invocation does not identify an offered operation."
1102
1157
  );
1103
1158
  }
1104
- if (descriptor.idempotency === "required" && existing.result !== void 0) {
1105
- return existing.result;
1159
+ try {
1160
+ invocation = parseAgentOperationInvocationFor(
1161
+ descriptor,
1162
+ invocation
1163
+ );
1164
+ } catch {
1165
+ return throwAgentProviderContractError(
1166
+ providerKey,
1167
+ "input_operation_mismatch",
1168
+ "Operation invocation is stale or outside the offered descriptor."
1169
+ );
1106
1170
  }
1107
- return throwAgentProviderContractError(
1108
- providerKey,
1109
- "input_operation_mismatch",
1110
- "Operation invocation ID is already active or is not replayable."
1171
+ const existing = interactionState.operationInvocations.get(
1172
+ invocation.invocationId
1111
1173
  );
1112
- }
1113
- const trackedInvocation = {
1114
- invocation
1115
- };
1116
- const observationState = {
1117
- fileChangeMode: capabilities.output.fileChanges,
1118
- observedItems: /* @__PURE__ */ new Map(),
1119
- proposedPlans: /* @__PURE__ */ new Map(),
1120
- generatedResourceIds: /* @__PURE__ */ new Set(),
1121
- started: true,
1122
- terminal: false,
1123
- finalDiffObserved: false
1124
- };
1125
- interactionState.operationInvocations.set(
1126
- invocation.invocationId,
1127
- trackedInvocation
1128
- );
1129
- try {
1130
- const result = await delegateProviderMutation({
1131
- operation: "invoke_operation",
1132
- observer: operationInput.onProviderExecutionStarted,
1133
- invoke: (onProviderExecutionStarted, onOutput) => declaredOperations.invokeOperation({
1134
- invocation,
1135
- observationTurnId,
1136
- onProviderExecutionStarted,
1137
- onOutput,
1138
- ...operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1139
- }),
1140
- observeOutput: async (candidate) => {
1141
- const output = validateAgentProviderOutputForContext(
1142
- candidate,
1143
- {
1144
- ...outputContext(observationTurnId),
1145
- operationInvocationId: invocation.invocationId
1146
- }
1147
- );
1148
- observeSessionOperationOutput({
1149
- capabilities,
1150
- providerKey,
1151
- output,
1152
- state: observationState,
1153
- contextUsageState,
1154
- interactionState
1155
- });
1156
- await operationInput.onOutput?.(output);
1157
- },
1158
- validate: (candidate) => {
1159
- const result2 = validateAgentOperationResultTransition({
1174
+ if (existing !== void 0) {
1175
+ if (JSON.stringify(existing.invocation) !== JSON.stringify(invocation)) {
1176
+ return throwAgentProviderContractError(
1160
1177
  providerKey,
1161
- candidate: validateAgentOperationResultForInvocation(
1162
- providerKey,
1163
- descriptor,
1164
- invocation,
1165
- candidate
1166
- ),
1167
- previous: interactionState.operationResults.get(
1168
- invocation.invocationId
1169
- )
1170
- });
1171
- interactionState.operationResults.set(
1172
- result2.invocationId,
1173
- result2
1178
+ "input_operation_mismatch",
1179
+ "Operation invocation ID was reused with conflicting input."
1174
1180
  );
1175
- return result2;
1176
1181
  }
1177
- });
1178
- trackedInvocation.result = result;
1179
- return result;
1180
- } catch (error) {
1181
- if (!(error instanceof AgentProviderDelegatedOperationError)) {
1182
- interactionState.operationInvocations.delete(
1183
- invocation.invocationId
1182
+ if (descriptor.idempotency === "required" && existing.result !== void 0) {
1183
+ return existing.result;
1184
+ }
1185
+ return throwAgentProviderContractError(
1186
+ providerKey,
1187
+ "input_operation_mismatch",
1188
+ "Operation invocation ID is already active or is not replayable."
1184
1189
  );
1185
1190
  }
1186
- throw error;
1191
+ requireUsable();
1192
+ signal.throwIfAborted();
1193
+ const reservation = descriptor.timing === "idle_session" && descriptor.executionMode === "immediate" ? validationOwner.reserveExecution() : void 0;
1194
+ const trackedInvocation = {
1195
+ invocation
1196
+ };
1197
+ const observationState = {
1198
+ fileChangeMode: capabilities.output.fileChanges,
1199
+ observedItems: /* @__PURE__ */ new Map(),
1200
+ proposedPlans: /* @__PURE__ */ new Map(),
1201
+ generatedResourceIds: /* @__PURE__ */ new Set(),
1202
+ started: true,
1203
+ terminal: false,
1204
+ finalDiffObserved: false
1205
+ };
1206
+ interactionState.operationInvocations.set(
1207
+ invocation.invocationId,
1208
+ trackedInvocation
1209
+ );
1210
+ try {
1211
+ const result = await delegateProviderMutation({
1212
+ operation: "invoke_operation",
1213
+ observer: operationInput.onProviderExecutionStarted,
1214
+ invoke: (onProviderExecutionStarted, onOutput) => declaredOperations.invokeOperation({
1215
+ invocation,
1216
+ observationTurnId,
1217
+ onProviderExecutionStarted,
1218
+ onOutput,
1219
+ ...operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1220
+ }),
1221
+ observeOutput: async (candidate) => {
1222
+ const output = validateAgentProviderOutputForContext(
1223
+ candidate,
1224
+ {
1225
+ ...outputContext(observationTurnId),
1226
+ operationInvocationId: invocation.invocationId
1227
+ }
1228
+ );
1229
+ observeSessionOperationOutput({
1230
+ capabilities,
1231
+ providerKey,
1232
+ output,
1233
+ state: observationState,
1234
+ contextUsageState,
1235
+ interactionState
1236
+ });
1237
+ await operationInput.onOutput?.(output);
1238
+ },
1239
+ validate: (candidate) => {
1240
+ const result2 = validateAgentOperationResultTransition({
1241
+ providerKey,
1242
+ candidate: validateAgentOperationResultForInvocation(
1243
+ providerKey,
1244
+ descriptor,
1245
+ invocation,
1246
+ candidate
1247
+ ),
1248
+ previous: interactionState.operationResults.get(
1249
+ invocation.invocationId
1250
+ )
1251
+ });
1252
+ interactionState.operationResults.set(
1253
+ result2.invocationId,
1254
+ result2
1255
+ );
1256
+ return result2;
1257
+ }
1258
+ });
1259
+ trackedInvocation.result = result;
1260
+ return result;
1261
+ } catch (error) {
1262
+ if (!(error instanceof AgentProviderDelegatedOperationError)) {
1263
+ interactionState.operationInvocations.delete(
1264
+ invocation.invocationId
1265
+ );
1266
+ }
1267
+ throw error;
1268
+ } finally {
1269
+ if (reservation !== void 0) validationOwner.releaseExecution(reservation);
1270
+ }
1271
+ } finally {
1272
+ settle();
1187
1273
  }
1188
1274
  }
1189
1275
  });
@@ -1442,7 +1528,7 @@ function validateAgentProviderSession(input) {
1442
1528
  validationOwner.stop();
1443
1529
  input.hostBindingLease?.stop();
1444
1530
  const closingTurn = validationOwner.activeTurn;
1445
- closingTurn?.owner.stop(new DOMException("The provider session was closed.", "AbortError"));
1531
+ closingTurn?.owner.stop(new DOMException("The provider session was closed.", "AbortError"), "closed");
1446
1532
  const cleanup = async () => {
1447
1533
  if (!providerClosed) {
1448
1534
  await input.candidate.close(closeInput);
@@ -1450,6 +1536,7 @@ function validateAgentProviderSession(input) {
1450
1536
  }
1451
1537
  await input.sessionInteractionOwner?.join();
1452
1538
  await closingTurn?.owner.join();
1539
+ await validationOwner.sessionAdmission.joinOperations();
1453
1540
  await input.hostBindingLease?.release();
1454
1541
  validationOwner.completeClose();
1455
1542
  };
@@ -1609,6 +1696,7 @@ async function openIdentityCreatingAgentProviderSession(input) {
1609
1696
  }
1610
1697
  }
1611
1698
  export {
1699
+ assertAgentTurnInputCapability,
1612
1700
  closeRejectedAgentProviderSession,
1613
1701
  createAgentSessionValidationOwner,
1614
1702
  openIdentityCreatingAgentProviderSession,