@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.
- package/README.md +154 -71
- package/dist/adapterValidation.d.ts +4 -2
- package/dist/adapterValidation.js +108 -59
- package/dist/contractErrors.d.ts +1 -1
- package/dist/contractErrors.js +7 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/nativeContinuations/admission.d.ts +17 -0
- package/dist/nativeContinuations/admission.js +250 -0
- package/dist/nativeContinuations/index.d.ts +2 -0
- package/dist/nativeContinuations/index.js +1 -0
- package/dist/nativeContinuations/types.d.ts +52 -0
- package/dist/nativeContinuations/types.js +0 -0
- package/dist/outputValidation.js +1 -0
- package/dist/providerCatalog.d.ts +1 -1
- package/dist/providerDriver.d.ts +4 -1
- package/dist/providerInstanceRegistry.d.ts +4 -4
- package/dist/sessionAdmission.d.ts +12 -0
- package/dist/sessionAdmission.js +54 -0
- package/dist/sessionInteractions/lifetime.d.ts +32 -3
- package/dist/sessionInteractions/lifetime.js +145 -13
- package/dist/sessionInteractions/request.d.ts +3 -2
- package/dist/sessionInteractions/request.js +98 -25
- package/dist/sessionInteractions/types.d.ts +68 -12
- package/dist/sessionInteractions/validation.d.ts +13 -9
- package/dist/sessionInteractions/validation.js +121 -60
- package/dist/sessionValidation.d.ts +78 -2
- package/dist/sessionValidation.js +213 -162
- package/dist/sessions.d.ts +33 -2
- package/dist/testing/conformance.d.ts +3 -1
- package/dist/testing/conformance.js +180 -85
- package/dist/testing/fakeProvider.js +2 -2
- package/dist/turnExecution/execution.d.ts +23 -6
- package/dist/turnExecution/execution.js +136 -32
- package/dist/turnExecution/requests.d.ts +15 -3
- package/dist/turnExecution/requests.js +93 -28
- 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.
|
|
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
|
-
|
|
231
|
-
|
|
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.
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 && !
|
|
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")
|
|
420
|
-
completeTurnSequence({ providerKey, state,
|
|
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
|
-
|
|
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
|
|
550
|
-
|
|
551
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
790
|
-
|
|
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
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
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
|
-
|
|
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")
|
|
970
|
+
if (result.status === "delivery_uncertain") validationOwner.fence();
|
|
931
971
|
return result;
|
|
932
972
|
} catch (error) {
|
|
933
|
-
|
|
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
|
-
|
|
1402
|
-
|
|
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
|
-
|
|
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
|
};
|
package/dist/sessions.d.ts
CHANGED
|
@@ -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?:
|
|
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
|
|
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
|
}
|