@agen-ai/agent-runtime 0.4.1 → 0.4.2

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 (37) hide show
  1. package/README.md +154 -71
  2. package/dist/adapterValidation.d.ts +4 -2
  3. package/dist/adapterValidation.js +108 -59
  4. package/dist/contractErrors.d.ts +1 -1
  5. package/dist/contractErrors.js +7 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.js +1 -0
  8. package/dist/nativeContinuations/admission.d.ts +17 -0
  9. package/dist/nativeContinuations/admission.js +250 -0
  10. package/dist/nativeContinuations/index.d.ts +2 -0
  11. package/dist/nativeContinuations/index.js +1 -0
  12. package/dist/nativeContinuations/types.d.ts +52 -0
  13. package/dist/nativeContinuations/types.js +0 -0
  14. package/dist/outputValidation.js +1 -0
  15. package/dist/providerCatalog.d.ts +1 -1
  16. package/dist/providerDriver.d.ts +4 -1
  17. package/dist/providerInstanceRegistry.d.ts +4 -4
  18. package/dist/sessionAdmission.d.ts +12 -0
  19. package/dist/sessionAdmission.js +54 -0
  20. package/dist/sessionInteractions/lifetime.d.ts +32 -3
  21. package/dist/sessionInteractions/lifetime.js +145 -13
  22. package/dist/sessionInteractions/request.d.ts +3 -2
  23. package/dist/sessionInteractions/request.js +98 -25
  24. package/dist/sessionInteractions/types.d.ts +68 -12
  25. package/dist/sessionInteractions/validation.d.ts +13 -9
  26. package/dist/sessionInteractions/validation.js +121 -60
  27. package/dist/sessionValidation.d.ts +78 -2
  28. package/dist/sessionValidation.js +213 -162
  29. package/dist/sessions.d.ts +33 -2
  30. package/dist/testing/conformance.d.ts +3 -1
  31. package/dist/testing/conformance.js +180 -85
  32. package/dist/testing/fakeProvider.js +2 -2
  33. package/dist/turnExecution/execution.d.ts +23 -6
  34. package/dist/turnExecution/execution.js +136 -32
  35. package/dist/turnExecution/requests.d.ts +15 -3
  36. package/dist/turnExecution/requests.js +93 -28
  37. package/package.json +2 -2
@@ -44,8 +44,10 @@ import {
44
44
  validateAgentProviderOutputForContext
45
45
  } from "./outputValidation.js";
46
46
  import { validateAgentTurnSteeringResult } from "./steeringValidation.js";
47
- import { createValidatedAgentTurnExecution } from "./turnExecution/execution.js";
47
+ import { createValidatedAgentTurnExecution, adoptValidatedAgentTurnExecution } from "./turnExecution/execution.js";
48
48
  import { validateAgentProviderTurnInterruptionResult } from "./turnExecution/receipts.js";
49
+ import { createAgentTurnRequestAdmission } from "./turnExecution/requests.js";
50
+ import { createAgentSessionAdmission } from "./sessionAdmission.js";
49
51
  function validateCloseReason(reason) {
50
52
  if (reason !== void 0 && !["idle", "shutdown", "replaced", "contract_rejected", "error", "other"].includes(reason)) {
51
53
  throw new TypeError("Provider session close reason is unsupported.");
@@ -163,7 +165,7 @@ function invalidTurnSequence(providerKey, message) {
163
165
  );
164
166
  }
165
167
  function completeTurnSequence(input) {
166
- if (input.pendingRequests.size > 0) {
168
+ if (input.requests.hasUnclaimedRequest()) {
167
169
  invalidTurnSequence(
168
170
  input.providerKey,
169
171
  "Provider completed a turn while an interaction request remained pending."
@@ -176,6 +178,7 @@ const FINAL_DIFF_TRAILING_EVENT_TYPES = [
176
178
  "collaboration.updated",
177
179
  "operation.updated",
178
180
  "provider.diagnostic",
181
+ "request.unavailable",
179
182
  "resource.updated",
180
183
  "runtime.error",
181
184
  "runtime.warning",
@@ -226,29 +229,19 @@ function observeItemLifecycle(input) {
226
229
  terminal: event.type === "item.completed" || TERMINAL_ITEM_STATUSES.has(event.payload.status)
227
230
  });
228
231
  }
232
+ function hasLiveApprovalSubject(request, state) {
233
+ if (request.requestKind !== "approval") return true;
234
+ if (request.subject.kind === "plan") return state.proposedPlans.get(request.subject.artifactId) === request.requestId;
235
+ const item = state.observedItems.get(request.subject.itemId);
236
+ return item !== void 0 && !item.terminal && (item.status === "pending" || item.status === "in_progress" || item.status === "unknown" && item.inProgressObserved);
237
+ }
229
238
  function assertApprovalSubjectCorrelation(input) {
230
- const { request } = input;
231
- if (request.requestKind !== "approval") return;
232
- if (request.subject.kind === "plan") {
233
- if (input.state.proposedPlans.get(request.subject.artifactId) !== request.requestId) {
234
- invalidTurnSequence(
235
- input.providerKey,
236
- "Provider approval request does not identify a proposed plan from this turn."
237
- );
238
- }
239
- return;
240
- }
241
- const item = input.state.observedItems.get(request.subject.itemId);
242
- const itemIsLive = item !== void 0 && !item.terminal && (item.status === "pending" || item.status === "in_progress" || item.status === "unknown" && item.inProgressObserved);
243
- if (!itemIsLive) {
244
- invalidTurnSequence(
245
- input.providerKey,
246
- "Provider approval request does not identify a live item from this turn."
247
- );
239
+ if (!hasLiveApprovalSubject(input.request, input.state)) {
240
+ invalidTurnSequence(input.providerKey, input.request.requestKind === "approval" && input.request.subject.kind === "plan" ? "Provider approval request does not identify a proposed plan from this turn." : "Provider approval request does not identify a live item from this turn.");
248
241
  }
249
242
  }
250
243
  function assertPendingApprovalSubjectCorrelations(input) {
251
- for (const pending of input.pendingRequests.values()) {
244
+ for (const pending of input.requests.unclaimedRequests()) {
252
245
  assertApprovalSubjectCorrelation({
253
246
  providerKey: input.providerKey,
254
247
  request: pending.request,
@@ -304,9 +297,7 @@ function observeTurnEvent(input) {
304
297
  const {
305
298
  contextUsageState,
306
299
  event,
307
- openedRequestIds,
308
- turnRequestIds,
309
- pendingRequests,
300
+ requests,
310
301
  providerKey,
311
302
  state
312
303
  } = input;
@@ -332,7 +323,7 @@ function observeTurnEvent(input) {
332
323
  }
333
324
  if (state.fileChangeMode === "final_diff") {
334
325
  if (event.type === "turn.diff.updated") {
335
- if (pendingRequests.size > 0) {
326
+ if (requests.hasUnclaimedRequest()) {
336
327
  invalidTurnSequence(
337
328
  providerKey,
338
329
  "Provider emitted a terminal diff while an interaction request remained pending."
@@ -356,7 +347,7 @@ function observeTurnEvent(input) {
356
347
  observeItemLifecycle({ providerKey, event, state });
357
348
  assertPendingApprovalSubjectCorrelations({
358
349
  providerKey,
359
- pendingRequests,
350
+ requests,
360
351
  state
361
352
  });
362
353
  if (event.payload.itemKind === "context_compaction" && event.type === "item.completed" && event.payload.status === "completed") {
@@ -369,7 +360,7 @@ function observeTurnEvent(input) {
369
360
  state.proposedPlans.set(event.payload.artifactId, event.payload.requestId);
370
361
  assertPendingApprovalSubjectCorrelations({
371
362
  providerKey,
372
- pendingRequests,
363
+ requests,
373
364
  state
374
365
  });
375
366
  }
@@ -381,34 +372,20 @@ function observeTurnEvent(input) {
381
372
  });
382
373
  }
383
374
  if (event.type === "request.opened") {
384
- if (pendingRequests.size > 0) {
385
- invalidTurnSequence(
386
- providerKey,
387
- "Provider opened more than one pending request for a session."
388
- );
389
- }
390
- const requestId = event.payload.request.requestId;
391
- if (openedRequestIds.has(requestId)) {
392
- invalidTurnSequence(
393
- providerKey,
394
- "Provider reused a request ID within a session."
395
- );
396
- }
397
375
  assertApprovalSubjectCorrelation({
398
376
  providerKey,
399
377
  request: event.payload.request,
400
378
  state
401
379
  });
402
- openedRequestIds.add(requestId);
403
- turnRequestIds.add(requestId);
404
- pendingRequests.set(requestId, {
380
+ requests.open({
405
381
  request: event.payload.request,
406
382
  turnId: event.turnId
407
383
  });
408
384
  }
385
+ if (event.type === "request.unavailable") requests.unavailable(event.payload.requestId);
409
386
  if (event.type === "turn.state_changed") {
410
387
  const waiting = event.payload.state === "waiting_for_request";
411
- if (waiting && !turnRequestIds.has(event.payload.requestId)) {
388
+ if (waiting && !requests.hasOpened(event.payload.requestId)) {
412
389
  invalidTurnSequence(
413
390
  providerKey,
414
391
  "Provider entered a waiting state for a request it did not open."
@@ -416,8 +393,8 @@ function observeTurnEvent(input) {
416
393
  }
417
394
  }
418
395
  if (event.type === "turn.completed") {
419
- if (event.payload.outcome !== "completed") pendingRequests.clear();
420
- completeTurnSequence({ providerKey, state, pendingRequests });
396
+ if (event.payload.outcome !== "completed") requests.withdraw();
397
+ completeTurnSequence({ providerKey, state, requests });
421
398
  }
422
399
  }
423
400
  function observeTurnOutput(input) {
@@ -508,8 +485,7 @@ function observeTurnOutput(input) {
508
485
  event: input.output.event,
509
486
  state: input.state,
510
487
  pendingRequests: input.pendingRequests,
511
- openedRequestIds: input.openedRequestIds,
512
- turnRequestIds: input.turnRequestIds,
488
+ requests: input.requests,
513
489
  contextUsageState: input.contextUsageState
514
490
  });
515
491
  }
@@ -541,14 +517,20 @@ function observeSessionOperationOutput(input) {
541
517
  );
542
518
  }
543
519
  }
520
+ const pendingRequests = /* @__PURE__ */ new Map();
544
521
  observeTurnOutput({
545
522
  capabilities: input.capabilities,
546
523
  providerKey: input.providerKey,
547
524
  output: input.output,
548
525
  state: input.state,
549
- pendingRequests: /* @__PURE__ */ new Map(),
550
- openedRequestIds: /* @__PURE__ */ new Set(),
551
- turnRequestIds: /* @__PURE__ */ new Set(),
526
+ pendingRequests,
527
+ requests: createAgentTurnRequestAdmission({
528
+ providerKey: input.providerKey,
529
+ sessionAdmission: createAgentSessionAdmission(input.providerKey),
530
+ pendingRequests,
531
+ canRestore: () => false,
532
+ canRestoreRequest: () => false
533
+ }),
552
534
  contextUsageState: input.contextUsageState,
553
535
  interactionState: input.interactionState
554
536
  });
@@ -637,6 +619,146 @@ function assertAgentTurnInputCapability(input) {
637
619
  });
638
620
  if (textIssue) rejectReference(`${textIssue.target} must use ${textIssue.format} text`);
639
621
  }
622
+ function createAgentSessionValidationOwner(capabilities, sessionId) {
623
+ const providerKey = capabilities.providerKey;
624
+ const sessionLifetime = new AbortController();
625
+ const sessionAdmission = createAgentSessionAdmission(providerKey);
626
+ const contextUsageState = {
627
+ latestByScope: /* @__PURE__ */ new Map(),
628
+ cumulativeByScope: /* @__PURE__ */ new Map(),
629
+ compactionReadyScopes: /* @__PURE__ */ new Set()
630
+ };
631
+ const interactionState = {
632
+ operationResults: /* @__PURE__ */ new Map(),
633
+ operationInvocations: /* @__PURE__ */ new Map(),
634
+ collaborationNodes: /* @__PURE__ */ new Map(),
635
+ collaborationSpawnReservations: /* @__PURE__ */ new Map(),
636
+ generatedResources: /* @__PURE__ */ new Map()
637
+ };
638
+ let closed = false;
639
+ let unusable = false;
640
+ let closing;
641
+ const requireOpen = () => {
642
+ if (closed)
643
+ throwAgentProviderContractError(
644
+ providerKey,
645
+ "session_closed",
646
+ "Provider session is closed."
647
+ );
648
+ };
649
+ const requireUsable = () => {
650
+ requireOpen();
651
+ if (unusable) {
652
+ throwAgentProviderContractError(
653
+ providerKey,
654
+ "session_unusable",
655
+ "Provider session cannot be reused after an incomplete operation."
656
+ );
657
+ }
658
+ };
659
+ const outputContext = (turnId) => ({
660
+ capabilities,
661
+ providerKey,
662
+ sessionId,
663
+ ...turnId === void 0 ? {} : { turnId }
664
+ });
665
+ function installExecution(token, turnId, source) {
666
+ const pendingRequests = /* @__PURE__ */ new Map();
667
+ const state = {
668
+ fileChangeMode: capabilities.output.fileChanges,
669
+ observedItems: /* @__PURE__ */ new Map(),
670
+ proposedPlans: /* @__PURE__ */ new Map(),
671
+ generatedResourceIds: /* @__PURE__ */ new Set(),
672
+ started: false,
673
+ terminal: false,
674
+ finalDiffObserved: false
675
+ };
676
+ const inFlightOperations = /* @__PURE__ */ new Set();
677
+ const common = {
678
+ providerKey,
679
+ pendingRequests,
680
+ sessionAdmission,
681
+ inFlightOperations,
682
+ requireUsable,
683
+ isTerminal: () => state.terminal,
684
+ canRestoreRequest: (pending) => hasLiveApprovalSubject(pending.request, state),
685
+ observe(candidate, requests) {
686
+ const output = validateAgentProviderOutputForContext(candidate, outputContext(turnId));
687
+ observeTurnOutput({
688
+ capabilities,
689
+ providerKey,
690
+ output,
691
+ state,
692
+ pendingRequests,
693
+ requests,
694
+ contextUsageState,
695
+ interactionState
696
+ });
697
+ return output;
698
+ },
699
+ assertCompleted() {
700
+ if (!state.started || !state.terminal || pendingRequests.size > 0) {
701
+ invalidTurnSequence(providerKey, "Provider turn output must remain open until actual terminal completion.");
702
+ }
703
+ },
704
+ release() {
705
+ if (source.kind === "caller") sessionAdmission.releaseExecution(token);
706
+ },
707
+ retire() {
708
+ unusable = true;
709
+ },
710
+ abandon: () => closing ? closing() : Promise.reject(new Error("Session cleanup is waiting for its opening owner."))
711
+ };
712
+ const owner = source.kind === "caller" ? createValidatedAgentTurnExecution({ ...common, turnInput: source.input, start: source.start }) : adoptValidatedAgentTurnExecution({ ...common, turnId, createCandidate: source.createCandidate });
713
+ try {
714
+ sessionAdmission.installExecution(token, { turnId, pendingRequests, state, inFlightOperations, owner });
715
+ } catch (cause) {
716
+ owner.stop(cause instanceof Error ? cause : new Error("Execution installation failed.", { cause }));
717
+ throw cause;
718
+ }
719
+ return owner;
720
+ }
721
+ return {
722
+ sessionAdmission,
723
+ sessionLifetime,
724
+ contextUsageState,
725
+ interactionState,
726
+ outputContext,
727
+ requireUsable,
728
+ get activeTurn() {
729
+ return sessionAdmission.execution;
730
+ },
731
+ get closed() {
732
+ return closed;
733
+ },
734
+ get unusable() {
735
+ return unusable;
736
+ },
737
+ fence() {
738
+ unusable = true;
739
+ },
740
+ stop() {
741
+ unusable = true;
742
+ sessionAdmission.stop();
743
+ sessionLifetime.abort(new DOMException("The provider session was closed.", "AbortError"));
744
+ },
745
+ completeClose() {
746
+ closed = true;
747
+ },
748
+ installClose(close) {
749
+ closing = close;
750
+ },
751
+ reserveExecution: sessionAdmission.reserveExecution,
752
+ ownsExecution: sessionAdmission.ownsExecution,
753
+ releaseExecution: sessionAdmission.releaseExecution,
754
+ installNativeExecution(token, turnId, createCandidate) {
755
+ return installExecution(token, turnId, { kind: "native", createCandidate });
756
+ },
757
+ installCallerExecution(token, turnInput, start) {
758
+ return installExecution(token, turnInput.turnId, { kind: "caller", input: turnInput, start });
759
+ }
760
+ };
761
+ }
640
762
  function validateAgentProviderSession(input) {
641
763
  const { capabilities, sessionId } = input;
642
764
  const providerKey = capabilities.providerKey;
@@ -672,58 +794,22 @@ function validateAgentProviderSession(input) {
672
794
  );
673
795
  }
674
796
  validateSessionPorts(capabilities, input.candidate);
675
- const sessionLifetime = new AbortController();
797
+ const validationOwner = input.validationOwner ?? createAgentSessionValidationOwner(capabilities, sessionId);
798
+ const { sessionLifetime, contextUsageState, interactionState, outputContext } = validationOwner;
799
+ const collaborationNodes = interactionState.collaborationNodes;
800
+ const collaborationSpawnReservations = interactionState.collaborationSpawnReservations;
801
+ const requireUsable = () => {
802
+ input.sessionInteractionOwner?.requireUsable();
803
+ validationOwner.requireUsable();
804
+ };
676
805
  const environment = validateAgentEnvironmentObservationPort({
677
806
  providerKey,
678
807
  capability: capabilities.environment.session,
679
808
  port: input.candidate.environment,
680
809
  signal: sessionLifetime.signal
681
810
  });
682
- const openedRequestIds = /* @__PURE__ */ new Set();
683
- const contextUsageState = {
684
- latestByScope: /* @__PURE__ */ new Map(),
685
- cumulativeByScope: /* @__PURE__ */ new Map(),
686
- compactionReadyScopes: /* @__PURE__ */ new Set()
687
- };
688
- const interactionState = {
689
- operationResults: /* @__PURE__ */ new Map(),
690
- operationInvocations: /* @__PURE__ */ new Map(),
691
- collaborationNodes: /* @__PURE__ */ new Map(),
692
- collaborationSpawnReservations: /* @__PURE__ */ new Map(),
693
- generatedResources: /* @__PURE__ */ new Map()
694
- };
695
- const collaborationNodes = interactionState.collaborationNodes;
696
- const collaborationSpawnReservations = interactionState.collaborationSpawnReservations;
697
- let activeTurn = null;
698
811
  let closePromise = null;
699
- let closed = false;
700
812
  let providerClosed = false;
701
- let unusable = false;
702
- const requireOpen = () => {
703
- if (closed)
704
- throwAgentProviderContractError(
705
- providerKey,
706
- "session_closed",
707
- "Provider session is closed."
708
- );
709
- };
710
- const requireUsable = () => {
711
- input.sessionInteractionOwner?.requireUsable();
712
- requireOpen();
713
- if (unusable) {
714
- throwAgentProviderContractError(
715
- providerKey,
716
- "session_unusable",
717
- "Provider session cannot be reused after an incomplete operation."
718
- );
719
- }
720
- };
721
- const outputContext = (turnId) => ({
722
- capabilities,
723
- providerKey,
724
- sessionId,
725
- ...turnId === void 0 ? {} : { turnId }
726
- });
727
813
  const delegateProviderMutation = async (input2) => {
728
814
  let executionStarted = false;
729
815
  const onProviderExecutionStarted = () => {
@@ -760,7 +846,7 @@ function validateAgentProviderSession(input) {
760
846
  return input2.validate(candidate);
761
847
  } catch (error) {
762
848
  if (!executionStarted) throw error;
763
- unusable = true;
849
+ validationOwner.fence();
764
850
  throw new AgentProviderDelegatedOperationError(
765
851
  providerKey,
766
852
  input2.operation,
@@ -786,63 +872,17 @@ function validateAgentProviderSession(input) {
786
872
  `Provider ${providerKey} does not support ${parsedInput.interactionMode} turn interaction mode.`
787
873
  );
788
874
  }
789
- if (activeTurn !== null) {
790
- throwAgentProviderContractError(providerKey, "concurrent_turn", "Provider session already has an active turn.");
791
- }
792
- const pendingRequests = /* @__PURE__ */ new Map();
793
- const turnRequestIds = /* @__PURE__ */ new Set();
794
- const state = {
795
- fileChangeMode: capabilities.output.fileChanges,
796
- observedItems: /* @__PURE__ */ new Map(),
797
- proposedPlans: /* @__PURE__ */ new Map(),
798
- generatedResourceIds: /* @__PURE__ */ new Set(),
799
- started: false,
800
- terminal: false,
801
- finalDiffObserved: false
802
- };
803
- const inFlightOperations = /* @__PURE__ */ new Set();
804
- const owner = createValidatedAgentTurnExecution({
805
- providerKey,
806
- turnInput: {
875
+ const token = validationOwner.reserveExecution();
876
+ try {
877
+ return validationOwner.installCallerExecution(token, {
807
878
  ...parsedInput,
808
879
  ...turnInput.signal === void 0 ? {} : { signal: turnInput.signal },
809
880
  ...turnInput.onProviderExecutionStarted === void 0 ? {} : { onProviderExecutionStarted: turnInput.onProviderExecutionStarted }
810
- },
811
- pendingRequests,
812
- inFlightOperations,
813
- start: (inputTurn) => input.candidate.startTurn(inputTurn),
814
- requireUsable,
815
- isTerminal: () => state.terminal,
816
- observe(candidate) {
817
- const output = validateAgentProviderOutputForContext(candidate, outputContext(parsedInput.turnId));
818
- observeTurnOutput({
819
- capabilities,
820
- providerKey,
821
- output,
822
- state,
823
- pendingRequests,
824
- openedRequestIds,
825
- turnRequestIds,
826
- contextUsageState,
827
- interactionState
828
- });
829
- return output;
830
- },
831
- assertCompleted() {
832
- if (!state.started || !state.terminal || pendingRequests.size > 0) {
833
- invalidTurnSequence(providerKey, "Provider turn output must remain open until actual terminal completion.");
834
- }
835
- },
836
- release() {
837
- if (activeTurn?.owner === owner) activeTurn = null;
838
- },
839
- retire() {
840
- unusable = true;
841
- },
842
- abandon: () => close({ reason: "other" })
843
- });
844
- activeTurn = { turnId: parsedInput.turnId, pendingRequests, state, inFlightOperations, owner };
845
- return owner.execution;
881
+ }, (inputTurn) => input.candidate.startTurn(inputTurn)).execution;
882
+ } catch (error) {
883
+ validationOwner.releaseExecution(token);
884
+ throw error;
885
+ }
846
886
  };
847
887
  const declaredInterruption = input.candidate.interruption;
848
888
  const interruption = declaredInterruption.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
@@ -855,7 +895,7 @@ function validateAgentProviderSession(input) {
855
895
  reason: interruptionInput.reason,
856
896
  ...interruptionInput.requestedAt === void 0 ? {} : { requestedAt: interruptionInput.requestedAt }
857
897
  });
858
- const targetedActiveTurn = activeTurn?.turnId === parsed.turnId ? activeTurn : null;
898
+ const targetedActiveTurn = validationOwner.activeTurn?.turnId === parsed.turnId ? validationOwner.activeTurn : null;
859
899
  const targetedTurn = targetedActiveTurn;
860
900
  if (targetedTurn === null || targetedTurn.state.terminal || !targetedTurn.owner.hasEntered()) {
861
901
  throwAgentProviderContractError(
@@ -880,7 +920,7 @@ function validateAgentProviderSession(input) {
880
920
  );
881
921
  } catch (error) {
882
922
  suspendedRequests.withdraw();
883
- unusable = true;
923
+ validationOwner.fence();
884
924
  throw error;
885
925
  }
886
926
  if (result.status === "failed") {
@@ -899,7 +939,7 @@ function validateAgentProviderSession(input) {
899
939
  requireUsable();
900
940
  throwIfAgentOperationAborted(steeringInput.signal);
901
941
  const turnId = parseAgentTurnId(steeringInput.turnId);
902
- if (activeTurn?.turnId !== turnId || !activeTurn.owner.hasEntered() || activeTurn.state.terminal || activeTurn.pendingRequests.size > 0) {
942
+ if (validationOwner.activeTurn?.turnId !== turnId || !validationOwner.activeTurn.owner.hasEntered() || validationOwner.activeTurn.state.terminal || validationOwner.activeTurn.pendingRequests.size > 0) {
903
943
  throwAgentProviderContractError(
904
944
  providerKey,
905
945
  "active_turn_mismatch",
@@ -915,7 +955,7 @@ function validateAgentProviderSession(input) {
915
955
  parts: content.parts,
916
956
  providerKey
917
957
  });
918
- const targetedActiveTurn = activeTurn;
958
+ const targetedActiveTurn = validationOwner.activeTurn;
919
959
  const settleSteering = trackActiveTurnOperation(targetedActiveTurn);
920
960
  try {
921
961
  try {
@@ -927,10 +967,10 @@ function validateAgentProviderSession(input) {
927
967
  }),
928
968
  providerKey
929
969
  );
930
- if (result.status === "delivery_uncertain") unusable = true;
970
+ if (result.status === "delivery_uncertain") validationOwner.fence();
931
971
  return result;
932
972
  } catch (error) {
933
- unusable = true;
973
+ validationOwner.fence();
934
974
  throw new AgentProviderDelegatedOperationError(
935
975
  providerKey,
936
976
  "steer_turn",
@@ -1394,14 +1434,14 @@ function validateAgentProviderSession(input) {
1394
1434
  }
1395
1435
  });
1396
1436
  const closeOwned = (closeInput, explicit) => {
1397
- if (closed && !input.sessionInteractionOwner) return Promise.resolve();
1437
+ if (validationOwner.closed && !input.sessionInteractionOwner) return Promise.resolve();
1398
1438
  if (!input.sessionInteractionOwner && closePromise) return closePromise;
1399
1439
  throwIfAgentOperationAborted(closeInput.signal);
1400
1440
  validateCloseReason(closeInput.reason);
1401
- unusable = true;
1402
- sessionLifetime.abort(new DOMException("The provider session was closed.", "AbortError"));
1441
+ validationOwner.fence();
1442
+ validationOwner.stop();
1403
1443
  input.hostBindingLease?.stop();
1404
- const closingTurn = activeTurn;
1444
+ const closingTurn = validationOwner.activeTurn;
1405
1445
  closingTurn?.owner.stop(new DOMException("The provider session was closed.", "AbortError"));
1406
1446
  const cleanup = async () => {
1407
1447
  if (!providerClosed) {
@@ -1411,7 +1451,7 @@ function validateAgentProviderSession(input) {
1411
1451
  await input.sessionInteractionOwner?.join();
1412
1452
  await closingTurn?.owner.join();
1413
1453
  await input.hostBindingLease?.release();
1414
- closed = true;
1454
+ validationOwner.completeClose();
1415
1455
  };
1416
1456
  if (input.sessionInteractionOwner) return input.sessionInteractionOwner.close(cleanup, explicit);
1417
1457
  closePromise = Promise.resolve().then(cleanup).finally(() => {
@@ -1420,6 +1460,7 @@ function validateAgentProviderSession(input) {
1420
1460
  return closePromise;
1421
1461
  };
1422
1462
  const close = (closeInput) => closeOwned(closeInput, true);
1463
+ validationOwner.installClose(() => closeOwned({ reason: "error" }, false));
1423
1464
  input.sessionInteractionOwner?.installClose(() => closeOwned({ reason: "error" }, false));
1424
1465
  return Object.freeze({
1425
1466
  binding,
@@ -1504,8 +1545,14 @@ function bindingTracker(input) {
1504
1545
  "Provider branch reused its source binding."
1505
1546
  );
1506
1547
  }
1507
- input.observer(binding);
1508
1548
  observed = binding;
1549
+ try {
1550
+ input.interactions?.bind();
1551
+ input.observer(binding);
1552
+ } catch (cause) {
1553
+ input.interactions?.fail(cause);
1554
+ throw cause;
1555
+ }
1509
1556
  },
1510
1557
  requireMatch(binding) {
1511
1558
  if (!observed) {
@@ -1529,15 +1576,18 @@ async function openIdentityCreatingAgentProviderSession(input) {
1529
1576
  const tracker = bindingTracker({
1530
1577
  providerKey: input.capabilities.providerKey,
1531
1578
  observer: input.observer,
1579
+ ...input.sessionInteractionOwner === void 0 ? {} : { interactions: input.sessionInteractionOwner },
1532
1580
  ...input.sourceBinding === void 0 ? {} : { sourceBinding: input.sourceBinding }
1533
1581
  });
1534
1582
  let candidate = null;
1535
1583
  try {
1536
1584
  candidate = await input.open(tracker.observe);
1585
+ tracker.requireMatch(parseAgentSessionBinding(candidate.binding));
1537
1586
  const session = validateAgentProviderSession({
1538
1587
  capabilities: input.capabilities,
1539
1588
  sessionId: input.sessionId,
1540
1589
  candidate,
1590
+ ...input.validationOwner === void 0 ? {} : { validationOwner: input.validationOwner },
1541
1591
  ...input.sessionInteractionOwner === void 0 ? {} : { sessionInteractionOwner: input.sessionInteractionOwner },
1542
1592
  ...input.hostBindingLease === void 0 ? {} : { hostBindingLease: input.hostBindingLease },
1543
1593
  ...input.sourceBinding === void 0 ? {} : { sourceBinding: input.sourceBinding }
@@ -1560,6 +1610,7 @@ async function openIdentityCreatingAgentProviderSession(input) {
1560
1610
  }
1561
1611
  export {
1562
1612
  closeRejectedAgentProviderSession,
1613
+ createAgentSessionValidationOwner,
1563
1614
  openIdentityCreatingAgentProviderSession,
1564
1615
  validateAgentProviderSession
1565
1616
  };
@@ -1,9 +1,10 @@
1
1
  import type { AgentAuthenticationFlow, AgentCollaborationControlInput, AgentCollaborationNode, AgentCollaborationSpawnInput, AgentConfigurationCatalog, AgentConfigurationSelectionInput, AgentError, AgentGeneratedResourceDescriptor, AgentGeneratedResourceId, AgentManagedContentCatalog, AgentOperationCatalog, AgentOperationInvocation, AgentOperationResult, AgentRequestResolution, AgentSessionBinding, AgentSessionBranchSource, AgentSessionConfiguration, AgentSessionId, AgentTurnId, AgentTurnInputContent, AgentTurnInteractionMode, AgentTurnInputPart, AgentTurnInterruptionReason } from "@agen-ai/agent-protocol";
2
+ import type { AgentNativeContinuationContext, AgentNativeContinuationSupport } from "./nativeContinuations/types.js";
2
3
  import type { MaybePromise } from "./foundation.js";
3
4
  import type { AgentSessionHostBinding, AgentSessionHostBindingSupport } from "./hostBindings/types.js";
4
5
  import type { AgentProviderOutput } from "./outputs.js";
5
6
  import type { AgentArtifactCandidate } from "./artifacts.js";
6
- import type { AgentSessionInteractionContext, AgentSessionInteractionSupport } from "./sessionInteractions/types.js";
7
+ import type { AgentProviderSessionInteractionContext, AgentSessionInteractionContext, AgentSessionInteractionSupport } from "./sessionInteractions/types.js";
7
8
  import type { AgentEnvironmentObservationPort } from "./environment/types.js";
8
9
  export interface AgentProviderSessionContext {
9
10
  readonly sessionId: AgentSessionId;
@@ -11,7 +12,7 @@ export interface AgentProviderSessionContext {
11
12
  readonly configuration: AgentSessionConfiguration;
12
13
  readonly signal?: AbortSignal;
13
14
  readonly hostBinding?: AgentSessionHostBinding;
14
- readonly interactions?: AgentSessionInteractionContext;
15
+ readonly interactions?: AgentProviderSessionInteractionContext;
15
16
  }
16
17
  export type AgentSessionBindingCreatedObserver = (binding: AgentSessionBinding) => void;
17
18
  export interface AgentProviderCreateSessionInput extends AgentProviderSessionContext {
@@ -216,9 +217,39 @@ export type AgentProviderAuthentication = Readonly<{
216
217
  export interface AgentProviderAdapter {
217
218
  readonly sessionInteractions?: AgentSessionInteractionSupport;
218
219
  readonly hostBinding?: AgentSessionHostBindingSupport;
220
+ readonly nativeContinuations?: AgentNativeContinuationSupport;
219
221
  readonly createSession: (input: AgentProviderCreateSessionInput) => MaybePromise<AgentProviderSession>;
220
222
  readonly resumption: AgentSessionResumption;
221
223
  readonly branching: AgentSessionBranching;
222
224
  readonly authentication: AgentProviderAuthentication;
223
225
  }
226
+ export type AgentSessionOpenContext = Omit<AgentProviderSessionContext, "interactions"> & Readonly<{
227
+ interactions?: AgentSessionInteractionContext;
228
+ nativeContinuations?: AgentNativeContinuationContext;
229
+ }>;
230
+ export type AgentCreateSessionInput = AgentSessionOpenContext & Readonly<{
231
+ onBindingCreated: AgentSessionBindingCreatedObserver;
232
+ }>;
233
+ export type AgentResumeSessionInput = AgentSessionOpenContext & Readonly<{
234
+ binding: AgentSessionBinding;
235
+ }>;
236
+ export type AgentBranchSessionInput = AgentSessionOpenContext & Readonly<{
237
+ source: AgentSessionBranchSource;
238
+ onBindingCreated: AgentSessionBindingCreatedObserver;
239
+ }>;
240
+ export type AgentValidatedProviderAdapter = Omit<AgentProviderAdapter, "createSession" | "resumption" | "branching"> & Readonly<{
241
+ createSession: (input: AgentCreateSessionInput) => MaybePromise<AgentProviderSession>;
242
+ resumption: Readonly<{
243
+ kind: "unsupported";
244
+ }> | Readonly<{
245
+ kind: "supported";
246
+ resumeSession: (input: AgentResumeSessionInput) => MaybePromise<AgentProviderSession>;
247
+ }>;
248
+ branching: Readonly<{
249
+ kind: "unsupported";
250
+ }> | Readonly<{
251
+ kind: "through_turn";
252
+ branchSession: (input: AgentBranchSessionInput) => MaybePromise<AgentProviderSession>;
253
+ }>;
254
+ }>;
224
255
  //# sourceMappingURL=sessions.d.ts.map
@@ -18,7 +18,9 @@ export interface AgentProviderConformanceScenario {
18
18
  readonly interruptionSessionId: AgentSessionId;
19
19
  readonly turn: AgentProviderStartTurnInput;
20
20
  readonly interruptionTurn: AgentProviderStartTurnInput;
21
- readonly resolutionFor: (request: AgentRequest) => AgentRequestResolution;
21
+ readonly resolutionFor: (request: AgentRequest, context: Readonly<{
22
+ signal: AbortSignal;
23
+ }>) => AgentRequestResolution | undefined | Promise<AgentRequestResolution | undefined>;
22
24
  readonly branchSource?: (binding: AgentSessionBinding, turnId: AgentTurnId) => AgentSessionBranchSource;
23
25
  readonly steeringInput?: AgentTurnInputContent;
24
26
  }