@agen-ai/agent-runtime 0.3.1 → 0.4.1
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 +288 -29
- package/dist/adapterValidation.d.ts +1 -1
- package/dist/adapterValidation.js +199 -92
- package/dist/artifacts.js +0 -1
- package/dist/contractErrors.d.ts +16 -3
- package/dist/contractErrors.js +42 -6
- package/dist/hostBindings/index.d.ts +4 -0
- package/dist/hostBindings/index.js +9 -0
- package/dist/hostBindings/lifetime.d.ts +25 -0
- package/dist/hostBindings/lifetime.js +147 -0
- package/dist/hostBindings/opening.d.ts +14 -0
- package/dist/hostBindings/opening.js +82 -0
- package/dist/hostBindings/schema.d.ts +9 -0
- package/dist/hostBindings/schema.js +169 -0
- package/dist/hostBindings/types.d.ts +71 -0
- package/dist/hostBindings/types.js +0 -0
- package/dist/hostBindings/validation.d.ts +14 -0
- package/dist/hostBindings/validation.js +107 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/internal/objectShape.d.ts +2 -0
- package/dist/internal/objectShape.js +7 -0
- package/dist/outputValidation.js +3 -2
- package/dist/providerDriver.js +0 -1
- package/dist/providerInstanceRegistry.js +2 -1
- package/dist/sessionCleanup.d.ts +9 -0
- package/dist/sessionCleanup.js +17 -0
- package/dist/sessionInteractions/index.d.ts +2 -0
- package/dist/sessionInteractions/index.js +1 -0
- package/dist/sessionInteractions/lifetime.d.ts +52 -0
- package/dist/sessionInteractions/lifetime.js +251 -0
- package/dist/sessionInteractions/request.d.ts +42 -0
- package/dist/sessionInteractions/request.js +308 -0
- package/dist/sessionInteractions/types.d.ts +54 -0
- package/dist/sessionInteractions/types.js +10 -0
- package/dist/sessionInteractions/validation.d.ts +21 -0
- package/dist/sessionInteractions/validation.js +119 -0
- package/dist/sessionValidation.d.ts +15 -2
- package/dist/sessionValidation.js +155 -318
- package/dist/sessions.d.ts +31 -4
- package/dist/testing/conformance.d.ts +3 -3
- package/dist/testing/conformance.js +24 -31
- package/dist/testing/fakeProvider.js +59 -49
- package/dist/turnExecution/execution.d.ts +26 -0
- package/dist/turnExecution/execution.js +214 -0
- package/dist/turnExecution/receipts.d.ts +6 -0
- package/dist/turnExecution/receipts.js +39 -0
- package/dist/turnExecution/requests.d.ts +19 -0
- package/dist/turnExecution/requests.js +56 -0
- package/package.json +2 -2
|
@@ -9,8 +9,6 @@ import {
|
|
|
9
9
|
parseAgentGeneratedResourceId,
|
|
10
10
|
parseAgentOperationInvocation,
|
|
11
11
|
parseAgentOperationInvocationFor,
|
|
12
|
-
parseAgentRequestResolution,
|
|
13
|
-
parseAgentRequestResolutionFor,
|
|
14
12
|
parseAgentSessionBinding,
|
|
15
13
|
parseAgentTurnId,
|
|
16
14
|
parseAgentTurnInputContent,
|
|
@@ -32,8 +30,12 @@ import {
|
|
|
32
30
|
} from "./interactionValidation.js";
|
|
33
31
|
import {
|
|
34
32
|
AgentProviderDelegatedOperationError,
|
|
33
|
+
AgentProviderSessionCleanupError,
|
|
35
34
|
throwAgentProviderContractError
|
|
36
35
|
} from "./contractErrors.js";
|
|
36
|
+
import { createAgentHostBindingCleanupError } from "./hostBindings/lifetime.js";
|
|
37
|
+
import { associateAgentSessionCleanupError } from "./sessionCleanup.js";
|
|
38
|
+
import { hasExactOwnKeys } from "./internal/objectShape.js";
|
|
37
39
|
import {
|
|
38
40
|
throwIfAgentOperationAborted
|
|
39
41
|
} from "./foundation.js";
|
|
@@ -42,18 +44,17 @@ import {
|
|
|
42
44
|
validateAgentProviderOutputForContext
|
|
43
45
|
} from "./outputValidation.js";
|
|
44
46
|
import { validateAgentTurnSteeringResult } from "./steeringValidation.js";
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
import { createValidatedAgentTurnExecution } from "./turnExecution/execution.js";
|
|
48
|
+
import { validateAgentProviderTurnInterruptionResult } from "./turnExecution/receipts.js";
|
|
49
|
+
function validateCloseReason(reason) {
|
|
50
|
+
if (reason !== void 0 && !["idle", "shutdown", "replaced", "contract_rejected", "error", "other"].includes(reason)) {
|
|
51
|
+
throw new TypeError("Provider session close reason is unsupported.");
|
|
52
|
+
}
|
|
51
53
|
}
|
|
52
54
|
function validateSessionPorts(capabilities, session) {
|
|
53
55
|
if (!hasExactOwnKeys(session, [
|
|
54
56
|
"binding",
|
|
55
|
-
"
|
|
56
|
-
"resolveRequest",
|
|
57
|
+
"startTurn",
|
|
57
58
|
"interruption",
|
|
58
59
|
"steering",
|
|
59
60
|
"configuration",
|
|
@@ -63,7 +64,7 @@ function validateSessionPorts(capabilities, session) {
|
|
|
63
64
|
"collaboration",
|
|
64
65
|
"generatedResources",
|
|
65
66
|
"close"
|
|
66
|
-
]) || typeof session.
|
|
67
|
+
]) || typeof session.startTurn !== "function" || typeof session.close !== "function" || session.interruption === null || typeof session.interruption !== "object" || !["supported", "unsupported"].includes(session.interruption.kind) || session.steering === null || typeof session.steering !== "object" || !["supported", "unsupported"].includes(session.steering.kind) || session.configuration === null || typeof session.configuration !== "object" || !["managed", "selectable"].includes(session.configuration.kind) || session.operations === null || typeof session.operations !== "object" || !["supported", "unsupported"].includes(session.operations.kind) || session.managedContent === null || typeof session.managedContent !== "object" || !["supported", "unsupported"].includes(session.managedContent.kind) || session.environment === null || typeof session.environment !== "object" || !["read", "read_and_watch", "unsupported"].includes(session.environment.kind) || session.collaboration === null || typeof session.collaboration !== "object" || !["supported", "unsupported"].includes(session.collaboration.kind) || session.generatedResources === null || typeof session.generatedResources !== "object" || !["supported", "unsupported"].includes(session.generatedResources.kind)) {
|
|
67
68
|
throwAgentProviderContractError(
|
|
68
69
|
capabilities.providerKey,
|
|
69
70
|
"invalid_session",
|
|
@@ -169,7 +170,6 @@ function completeTurnSequence(input) {
|
|
|
169
170
|
);
|
|
170
171
|
}
|
|
171
172
|
input.state.terminal = true;
|
|
172
|
-
input.state.waiting = false;
|
|
173
173
|
}
|
|
174
174
|
const FINAL_DIFF_TRAILING_EVENT_TYPES = [
|
|
175
175
|
"artifact.referenced",
|
|
@@ -305,6 +305,7 @@ function observeTurnEvent(input) {
|
|
|
305
305
|
contextUsageState,
|
|
306
306
|
event,
|
|
307
307
|
openedRequestIds,
|
|
308
|
+
turnRequestIds,
|
|
308
309
|
pendingRequests,
|
|
309
310
|
providerKey,
|
|
310
311
|
state
|
|
@@ -399,14 +400,15 @@ function observeTurnEvent(input) {
|
|
|
399
400
|
state
|
|
400
401
|
});
|
|
401
402
|
openedRequestIds.add(requestId);
|
|
403
|
+
turnRequestIds.add(requestId);
|
|
402
404
|
pendingRequests.set(requestId, {
|
|
403
405
|
request: event.payload.request,
|
|
404
406
|
turnId: event.turnId
|
|
405
407
|
});
|
|
406
408
|
}
|
|
407
409
|
if (event.type === "turn.state_changed") {
|
|
408
|
-
|
|
409
|
-
if (
|
|
410
|
+
const waiting = event.payload.state === "waiting_for_request";
|
|
411
|
+
if (waiting && !turnRequestIds.has(event.payload.requestId)) {
|
|
410
412
|
invalidTurnSequence(
|
|
411
413
|
providerKey,
|
|
412
414
|
"Provider entered a waiting state for a request it did not open."
|
|
@@ -414,6 +416,7 @@ function observeTurnEvent(input) {
|
|
|
414
416
|
}
|
|
415
417
|
}
|
|
416
418
|
if (event.type === "turn.completed") {
|
|
419
|
+
if (event.payload.outcome !== "completed") pendingRequests.clear();
|
|
417
420
|
completeTurnSequence({ providerKey, state, pendingRequests });
|
|
418
421
|
}
|
|
419
422
|
}
|
|
@@ -506,6 +509,7 @@ function observeTurnOutput(input) {
|
|
|
506
509
|
state: input.state,
|
|
507
510
|
pendingRequests: input.pendingRequests,
|
|
508
511
|
openedRequestIds: input.openedRequestIds,
|
|
512
|
+
turnRequestIds: input.turnRequestIds,
|
|
509
513
|
contextUsageState: input.contextUsageState
|
|
510
514
|
});
|
|
511
515
|
}
|
|
@@ -544,23 +548,11 @@ function observeSessionOperationOutput(input) {
|
|
|
544
548
|
state: input.state,
|
|
545
549
|
pendingRequests: /* @__PURE__ */ new Map(),
|
|
546
550
|
openedRequestIds: /* @__PURE__ */ new Set(),
|
|
551
|
+
turnRequestIds: /* @__PURE__ */ new Set(),
|
|
547
552
|
contextUsageState: input.contextUsageState,
|
|
548
553
|
interactionState: input.interactionState
|
|
549
554
|
});
|
|
550
555
|
}
|
|
551
|
-
function assertStableTurnBoundary(input) {
|
|
552
|
-
const terminal = input.state.terminal && !input.state.waiting;
|
|
553
|
-
const waiting = !input.state.terminal && input.state.waiting && input.pendingRequests.size === 1;
|
|
554
|
-
if (terminal && input.pendingRequests.size === 0 || waiting) return;
|
|
555
|
-
invalidTurnSequence(
|
|
556
|
-
input.providerKey,
|
|
557
|
-
"Provider turn must finish with completion or exactly one pending request."
|
|
558
|
-
);
|
|
559
|
-
}
|
|
560
|
-
function replacePendingRequests(target, source) {
|
|
561
|
-
target.clear();
|
|
562
|
-
for (const [requestId, pending] of source) target.set(requestId, pending);
|
|
563
|
-
}
|
|
564
556
|
function trackActiveTurnOperation(turn) {
|
|
565
557
|
if (!turn) return null;
|
|
566
558
|
let settle;
|
|
@@ -573,45 +565,6 @@ function trackActiveTurnOperation(turn) {
|
|
|
573
565
|
settle();
|
|
574
566
|
};
|
|
575
567
|
}
|
|
576
|
-
function interruptionTerminalizesTurn(input) {
|
|
577
|
-
if (["completed", "canceled"].includes(input.result.status)) {
|
|
578
|
-
return true;
|
|
579
|
-
}
|
|
580
|
-
return (input.result.outputs ?? []).some(
|
|
581
|
-
(output) => output.kind === "event" && output.event.turnId === input.turnId && output.event.type === "turn.completed"
|
|
582
|
-
);
|
|
583
|
-
}
|
|
584
|
-
function observeTurnOperationOutputs(input) {
|
|
585
|
-
for (const output of input.outputs ?? []) {
|
|
586
|
-
observeTurnOutput({
|
|
587
|
-
providerKey: input.providerKey,
|
|
588
|
-
output,
|
|
589
|
-
state: input.state,
|
|
590
|
-
pendingRequests: input.pendingRequests,
|
|
591
|
-
openedRequestIds: input.openedRequestIds,
|
|
592
|
-
contextUsageState: input.contextUsageState,
|
|
593
|
-
capabilities: input.capabilities,
|
|
594
|
-
interactionState: input.interactionState
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
function reconstructWaitingTurn(input) {
|
|
599
|
-
const targetedPendingRequests = new Map(
|
|
600
|
-
[...input.pendingRequests].filter(
|
|
601
|
-
([, pending]) => pending.turnId === input.turnId
|
|
602
|
-
)
|
|
603
|
-
);
|
|
604
|
-
if (targetedPendingRequests.size === 0 || input.state === void 0 || input.state.terminal || !input.state.waiting) return null;
|
|
605
|
-
return {
|
|
606
|
-
state: input.state,
|
|
607
|
-
pendingRequests: targetedPendingRequests
|
|
608
|
-
};
|
|
609
|
-
}
|
|
610
|
-
function clearPendingRequestsForTurn(pendingRequests, turnId) {
|
|
611
|
-
for (const [requestId, pending] of pendingRequests) {
|
|
612
|
-
if (pending.turnId === turnId) pendingRequests.delete(requestId);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
568
|
function assertAgentTurnInputCapability(input) {
|
|
616
569
|
const imageParts = input.parts.filter((part) => part.type === "image");
|
|
617
570
|
if (imageParts.length > 0) {
|
|
@@ -726,8 +679,6 @@ function validateAgentProviderSession(input) {
|
|
|
726
679
|
port: input.candidate.environment,
|
|
727
680
|
signal: sessionLifetime.signal
|
|
728
681
|
});
|
|
729
|
-
const pendingRequests = /* @__PURE__ */ new Map();
|
|
730
|
-
const waitingTurnStates = /* @__PURE__ */ new Map();
|
|
731
682
|
const openedRequestIds = /* @__PURE__ */ new Set();
|
|
732
683
|
const contextUsageState = {
|
|
733
684
|
latestByScope: /* @__PURE__ */ new Map(),
|
|
@@ -746,6 +697,7 @@ function validateAgentProviderSession(input) {
|
|
|
746
697
|
let activeTurn = null;
|
|
747
698
|
let closePromise = null;
|
|
748
699
|
let closed = false;
|
|
700
|
+
let providerClosed = false;
|
|
749
701
|
let unusable = false;
|
|
750
702
|
const requireOpen = () => {
|
|
751
703
|
if (closed)
|
|
@@ -756,6 +708,7 @@ function validateAgentProviderSession(input) {
|
|
|
756
708
|
);
|
|
757
709
|
};
|
|
758
710
|
const requireUsable = () => {
|
|
711
|
+
input.sessionInteractionOwner?.requireUsable();
|
|
759
712
|
requireOpen();
|
|
760
713
|
if (unusable) {
|
|
761
714
|
throwAgentProviderContractError(
|
|
@@ -771,17 +724,6 @@ function validateAgentProviderSession(input) {
|
|
|
771
724
|
sessionId,
|
|
772
725
|
...turnId === void 0 ? {} : { turnId }
|
|
773
726
|
});
|
|
774
|
-
const delegateOperation = async (operation, turnId) => {
|
|
775
|
-
try {
|
|
776
|
-
return validateAgentProviderOperationResult(
|
|
777
|
-
await operation(),
|
|
778
|
-
outputContext(turnId)
|
|
779
|
-
);
|
|
780
|
-
} catch (error) {
|
|
781
|
-
unusable = true;
|
|
782
|
-
throw error;
|
|
783
|
-
}
|
|
784
|
-
};
|
|
785
727
|
const delegateProviderMutation = async (input2) => {
|
|
786
728
|
let executionStarted = false;
|
|
787
729
|
const onProviderExecutionStarted = () => {
|
|
@@ -806,6 +748,7 @@ function validateAgentProviderSession(input) {
|
|
|
806
748
|
await input2.observeOutput?.(candidate);
|
|
807
749
|
};
|
|
808
750
|
try {
|
|
751
|
+
requireUsable();
|
|
809
752
|
const candidate = await input2.invoke(onProviderExecutionStarted, onOutput);
|
|
810
753
|
if (!executionStarted) {
|
|
811
754
|
throwAgentProviderContractError(
|
|
@@ -825,7 +768,7 @@ function validateAgentProviderSession(input) {
|
|
|
825
768
|
);
|
|
826
769
|
}
|
|
827
770
|
};
|
|
828
|
-
const
|
|
771
|
+
const startTurn = (turnInput) => {
|
|
829
772
|
requireUsable();
|
|
830
773
|
throwIfAgentOperationAborted(turnInput.signal);
|
|
831
774
|
const parsedInput = parseAgentTurnRunInput({
|
|
@@ -835,11 +778,7 @@ function validateAgentProviderSession(input) {
|
|
|
835
778
|
...turnInput.summary === void 0 ? {} : { summary: turnInput.summary },
|
|
836
779
|
...turnInput.deadlineAt === void 0 ? {} : { deadlineAt: turnInput.deadlineAt }
|
|
837
780
|
});
|
|
838
|
-
assertAgentTurnInputCapability({
|
|
839
|
-
capability: capabilities.input,
|
|
840
|
-
parts: parsedInput.parts,
|
|
841
|
-
providerKey
|
|
842
|
-
});
|
|
781
|
+
assertAgentTurnInputCapability({ capability: capabilities.input, parts: parsedInput.parts, providerKey });
|
|
843
782
|
if (!capabilities.turns.interactionModes.includes(parsedInput.interactionMode)) {
|
|
844
783
|
throwAgentProviderContractError(
|
|
845
784
|
providerKey,
|
|
@@ -847,179 +786,63 @@ function validateAgentProviderSession(input) {
|
|
|
847
786
|
`Provider ${providerKey} does not support ${parsedInput.interactionMode} turn interaction mode.`
|
|
848
787
|
);
|
|
849
788
|
}
|
|
850
|
-
if (pendingRequests.size > 0) {
|
|
851
|
-
throwAgentProviderContractError(
|
|
852
|
-
providerKey,
|
|
853
|
-
"request_pending",
|
|
854
|
-
"Provider session cannot start another turn while a request is pending."
|
|
855
|
-
);
|
|
856
|
-
}
|
|
857
789
|
if (activeTurn !== null) {
|
|
858
|
-
throwAgentProviderContractError(
|
|
859
|
-
providerKey,
|
|
860
|
-
"concurrent_turn",
|
|
861
|
-
"Provider session already has an active turn."
|
|
862
|
-
);
|
|
790
|
+
throwAgentProviderContractError(providerKey, "concurrent_turn", "Provider session already has an active turn.");
|
|
863
791
|
}
|
|
864
|
-
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
terminal: false,
|
|
875
|
-
waiting: false,
|
|
876
|
-
finalDiffObserved: false
|
|
877
|
-
},
|
|
878
|
-
inFlightOperations: /* @__PURE__ */ new Set()
|
|
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
|
|
879
802
|
};
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
803
|
+
const inFlightOperations = /* @__PURE__ */ new Set();
|
|
804
|
+
const owner = createValidatedAgentTurnExecution({
|
|
805
|
+
providerKey,
|
|
806
|
+
turnInput: {
|
|
884
807
|
...parsedInput,
|
|
885
|
-
...turnInput.signal === void 0 ? {} : { signal: turnInput.signal }
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
state: currentTurn.state,
|
|
896
|
-
pendingRequests: currentTurn.pendingRequests,
|
|
897
|
-
openedRequestIds,
|
|
898
|
-
contextUsageState,
|
|
899
|
-
interactionState
|
|
900
|
-
});
|
|
901
|
-
yield output;
|
|
902
|
-
}
|
|
903
|
-
while (currentTurn.inFlightOperations.size > 0) {
|
|
904
|
-
await Promise.all(currentTurn.inFlightOperations);
|
|
905
|
-
}
|
|
906
|
-
if (!currentTurn.state.started) {
|
|
907
|
-
invalidTurnSequence(
|
|
908
|
-
providerKey,
|
|
909
|
-
"Provider turn must emit turn.started before reaching a stable boundary."
|
|
910
|
-
);
|
|
911
|
-
}
|
|
912
|
-
assertStableTurnBoundary({
|
|
913
|
-
providerKey,
|
|
914
|
-
state: currentTurn.state,
|
|
915
|
-
pendingRequests: currentTurn.pendingRequests
|
|
916
|
-
});
|
|
917
|
-
if (currentTurn.state.waiting) {
|
|
918
|
-
replacePendingRequests(pendingRequests, currentTurn.pendingRequests);
|
|
919
|
-
waitingTurnStates.set(currentTurn.turnId, currentTurn.state);
|
|
920
|
-
} else {
|
|
921
|
-
waitingTurnStates.delete(currentTurn.turnId);
|
|
922
|
-
}
|
|
923
|
-
reachedStableBoundary = true;
|
|
924
|
-
} finally {
|
|
925
|
-
if (!reachedStableBoundary) unusable = true;
|
|
926
|
-
if (activeTurn === currentTurn) activeTurn = null;
|
|
927
|
-
}
|
|
928
|
-
};
|
|
929
|
-
const resolveRequest = async function* (requestInput) {
|
|
930
|
-
requireUsable();
|
|
931
|
-
throwIfAgentOperationAborted(requestInput.signal);
|
|
932
|
-
const resolution = parseAgentRequestResolution(requestInput.resolution);
|
|
933
|
-
const pending = pendingRequests.get(resolution.requestId);
|
|
934
|
-
if (!pending) {
|
|
935
|
-
throwAgentProviderContractError(
|
|
936
|
-
providerKey,
|
|
937
|
-
"request_resolution_mismatch",
|
|
938
|
-
"Provider request resolution does not identify a pending request."
|
|
939
|
-
);
|
|
940
|
-
}
|
|
941
|
-
try {
|
|
942
|
-
parseAgentRequestResolutionFor(pending.request, resolution);
|
|
943
|
-
} catch {
|
|
944
|
-
throwAgentProviderContractError(
|
|
945
|
-
providerKey,
|
|
946
|
-
"request_resolution_mismatch",
|
|
947
|
-
"Provider request resolution does not match the opened request."
|
|
948
|
-
);
|
|
949
|
-
}
|
|
950
|
-
if (pending.request.expiresAt !== void 0 && Date.parse(pending.request.expiresAt) <= Date.now() && resolution.disposition !== "canceled") {
|
|
951
|
-
throwAgentProviderContractError(
|
|
952
|
-
providerKey,
|
|
953
|
-
"request_resolution_mismatch",
|
|
954
|
-
"Provider request resolution identifies an expired request."
|
|
955
|
-
);
|
|
956
|
-
}
|
|
957
|
-
const nextPendingRequests = new Map(pendingRequests);
|
|
958
|
-
nextPendingRequests.delete(resolution.requestId);
|
|
959
|
-
if (activeTurn !== null) {
|
|
960
|
-
throwAgentProviderContractError(
|
|
961
|
-
providerKey,
|
|
962
|
-
"concurrent_turn",
|
|
963
|
-
"Provider session already has an active turn."
|
|
964
|
-
);
|
|
965
|
-
}
|
|
966
|
-
const waitingTurnState = waitingTurnStates.get(pending.turnId);
|
|
967
|
-
if (waitingTurnState === void 0 || waitingTurnState.terminal || !waitingTurnState.waiting) {
|
|
968
|
-
throwAgentProviderContractError(
|
|
969
|
-
providerKey,
|
|
970
|
-
"request_resolution_mismatch",
|
|
971
|
-
"Provider request resolution does not identify a waiting turn."
|
|
972
|
-
);
|
|
973
|
-
}
|
|
974
|
-
waitingTurnState.waiting = false;
|
|
975
|
-
const currentTurn = {
|
|
976
|
-
turnId: pending.turnId,
|
|
977
|
-
pendingRequests: nextPendingRequests,
|
|
978
|
-
state: waitingTurnState,
|
|
979
|
-
inFlightOperations: /* @__PURE__ */ new Set()
|
|
980
|
-
};
|
|
981
|
-
let reachedStableBoundary = false;
|
|
982
|
-
activeTurn = currentTurn;
|
|
983
|
-
try {
|
|
984
|
-
for await (const candidate of input.candidate.resolveRequest({
|
|
985
|
-
resolution,
|
|
986
|
-
...requestInput.signal === void 0 ? {} : { signal: requestInput.signal }
|
|
987
|
-
})) {
|
|
988
|
-
const output = validateAgentProviderOutputForContext(
|
|
989
|
-
candidate,
|
|
990
|
-
outputContext(pending.turnId)
|
|
991
|
-
);
|
|
808
|
+
...turnInput.signal === void 0 ? {} : { signal: turnInput.signal },
|
|
809
|
+
...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));
|
|
992
818
|
observeTurnOutput({
|
|
993
819
|
capabilities,
|
|
994
820
|
providerKey,
|
|
995
821
|
output,
|
|
996
|
-
state
|
|
997
|
-
pendingRequests
|
|
822
|
+
state,
|
|
823
|
+
pendingRequests,
|
|
998
824
|
openedRequestIds,
|
|
825
|
+
turnRequestIds,
|
|
999
826
|
contextUsageState,
|
|
1000
827
|
interactionState
|
|
1001
828
|
});
|
|
1002
|
-
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
} finally {
|
|
1020
|
-
if (!reachedStableBoundary) unusable = true;
|
|
1021
|
-
if (activeTurn === currentTurn) activeTurn = null;
|
|
1022
|
-
}
|
|
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;
|
|
1023
846
|
};
|
|
1024
847
|
const declaredInterruption = input.candidate.interruption;
|
|
1025
848
|
const interruption = declaredInterruption.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
@@ -1033,68 +856,36 @@ function validateAgentProviderSession(input) {
|
|
|
1033
856
|
...interruptionInput.requestedAt === void 0 ? {} : { requestedAt: interruptionInput.requestedAt }
|
|
1034
857
|
});
|
|
1035
858
|
const targetedActiveTurn = activeTurn?.turnId === parsed.turnId ? activeTurn : null;
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1038
|
-
turnId: parsed.turnId,
|
|
1039
|
-
state: waitingTurnStates.get(parsed.turnId)
|
|
1040
|
-
}) : null;
|
|
1041
|
-
const targetedTurn = targetedActiveTurn ?? targetedWaitingTurn;
|
|
1042
|
-
if (targetedTurn === null) {
|
|
859
|
+
const targetedTurn = targetedActiveTurn;
|
|
860
|
+
if (targetedTurn === null || targetedTurn.state.terminal || !targetedTurn.owner.hasEntered()) {
|
|
1043
861
|
throwAgentProviderContractError(
|
|
1044
862
|
providerKey,
|
|
1045
863
|
"active_turn_mismatch",
|
|
1046
|
-
"Provider interruption does not identify an active
|
|
864
|
+
"Provider interruption does not identify an active turn."
|
|
1047
865
|
);
|
|
1048
866
|
}
|
|
1049
867
|
const settleActiveInterruption = trackActiveTurnOperation(
|
|
1050
868
|
targetedActiveTurn
|
|
1051
869
|
);
|
|
1052
870
|
try {
|
|
1053
|
-
const
|
|
1054
|
-
|
|
1055
|
-
...parsed,
|
|
1056
|
-
...interruptionInput.signal === void 0 ? {} : { signal: interruptionInput.signal }
|
|
1057
|
-
}),
|
|
1058
|
-
parsed.turnId
|
|
1059
|
-
);
|
|
1060
|
-
const terminalized = interruptionTerminalizesTurn({
|
|
1061
|
-
turnId: parsed.turnId,
|
|
1062
|
-
result
|
|
1063
|
-
});
|
|
1064
|
-
if (terminalized || result.status === "accepted") {
|
|
1065
|
-
clearPendingRequestsForTurn(pendingRequests, parsed.turnId);
|
|
1066
|
-
clearPendingRequestsForTurn(
|
|
1067
|
-
targetedTurn.pendingRequests,
|
|
1068
|
-
parsed.turnId
|
|
1069
|
-
);
|
|
1070
|
-
targetedTurn.state.waiting = false;
|
|
1071
|
-
waitingTurnStates.delete(parsed.turnId);
|
|
1072
|
-
}
|
|
871
|
+
const suspendedRequests = targetedTurn.owner.suspendRequests();
|
|
872
|
+
let result;
|
|
1073
873
|
try {
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
contextUsageState,
|
|
1082
|
-
interactionState
|
|
1083
|
-
});
|
|
1084
|
-
if (terminalized && !targetedTurn.state.terminal) {
|
|
1085
|
-
completeTurnSequence({
|
|
1086
|
-
providerKey,
|
|
1087
|
-
state: targetedTurn.state,
|
|
1088
|
-
pendingRequests: targetedTurn.pendingRequests
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
874
|
+
result = validateAgentProviderTurnInterruptionResult(
|
|
875
|
+
await declaredInterruption.interruptTurn({
|
|
876
|
+
...parsed,
|
|
877
|
+
...interruptionInput.signal === void 0 ? {} : { signal: interruptionInput.signal }
|
|
878
|
+
}),
|
|
879
|
+
outputContext(parsed.turnId)
|
|
880
|
+
);
|
|
1091
881
|
} catch (error) {
|
|
882
|
+
suspendedRequests.withdraw();
|
|
1092
883
|
unusable = true;
|
|
1093
884
|
throw error;
|
|
1094
885
|
}
|
|
1095
|
-
if (result.status === "
|
|
1096
|
-
|
|
1097
|
-
}
|
|
886
|
+
if (result.status === "failed") {
|
|
887
|
+
suspendedRequests.restore();
|
|
888
|
+
} else suspendedRequests.withdraw();
|
|
1098
889
|
return result;
|
|
1099
890
|
} finally {
|
|
1100
891
|
settleActiveInterruption?.();
|
|
@@ -1108,7 +899,7 @@ function validateAgentProviderSession(input) {
|
|
|
1108
899
|
requireUsable();
|
|
1109
900
|
throwIfAgentOperationAborted(steeringInput.signal);
|
|
1110
901
|
const turnId = parseAgentTurnId(steeringInput.turnId);
|
|
1111
|
-
if (activeTurn?.turnId !== turnId || activeTurn.state.terminal || activeTurn.
|
|
902
|
+
if (activeTurn?.turnId !== turnId || !activeTurn.owner.hasEntered() || activeTurn.state.terminal || activeTurn.pendingRequests.size > 0) {
|
|
1112
903
|
throwAgentProviderContractError(
|
|
1113
904
|
providerKey,
|
|
1114
905
|
"active_turn_mismatch",
|
|
@@ -1128,7 +919,7 @@ function validateAgentProviderSession(input) {
|
|
|
1128
919
|
const settleSteering = trackActiveTurnOperation(targetedActiveTurn);
|
|
1129
920
|
try {
|
|
1130
921
|
try {
|
|
1131
|
-
|
|
922
|
+
const result = validateAgentTurnSteeringResult(
|
|
1132
923
|
await declaredSteering.steerTurn({
|
|
1133
924
|
turnId,
|
|
1134
925
|
...content,
|
|
@@ -1136,6 +927,8 @@ function validateAgentProviderSession(input) {
|
|
|
1136
927
|
}),
|
|
1137
928
|
providerKey
|
|
1138
929
|
);
|
|
930
|
+
if (result.status === "delivery_uncertain") unusable = true;
|
|
931
|
+
return result;
|
|
1139
932
|
} catch (error) {
|
|
1140
933
|
unusable = true;
|
|
1141
934
|
throw new AgentProviderDelegatedOperationError(
|
|
@@ -1287,7 +1080,6 @@ function validateAgentProviderSession(input) {
|
|
|
1287
1080
|
generatedResourceIds: /* @__PURE__ */ new Set(),
|
|
1288
1081
|
started: true,
|
|
1289
1082
|
terminal: false,
|
|
1290
|
-
waiting: false,
|
|
1291
1083
|
finalDiffObserved: false
|
|
1292
1084
|
};
|
|
1293
1085
|
interactionState.operationInvocations.set(
|
|
@@ -1601,33 +1393,37 @@ function validateAgentProviderSession(input) {
|
|
|
1601
1393
|
return inspection;
|
|
1602
1394
|
}
|
|
1603
1395
|
});
|
|
1604
|
-
const
|
|
1605
|
-
if (closed) return Promise.resolve();
|
|
1606
|
-
if (closePromise) return closePromise;
|
|
1396
|
+
const closeOwned = (closeInput, explicit) => {
|
|
1397
|
+
if (closed && !input.sessionInteractionOwner) return Promise.resolve();
|
|
1398
|
+
if (!input.sessionInteractionOwner && closePromise) return closePromise;
|
|
1607
1399
|
throwIfAgentOperationAborted(closeInput.signal);
|
|
1608
|
-
|
|
1609
|
-
"idle",
|
|
1610
|
-
"shutdown",
|
|
1611
|
-
"replaced",
|
|
1612
|
-
"contract_rejected",
|
|
1613
|
-
"error",
|
|
1614
|
-
"other"
|
|
1615
|
-
].includes(closeInput.reason)) {
|
|
1616
|
-
throw new TypeError("Provider session close reason is unsupported.");
|
|
1617
|
-
}
|
|
1400
|
+
validateCloseReason(closeInput.reason);
|
|
1618
1401
|
unusable = true;
|
|
1619
1402
|
sessionLifetime.abort(new DOMException("The provider session was closed.", "AbortError"));
|
|
1620
|
-
|
|
1403
|
+
input.hostBindingLease?.stop();
|
|
1404
|
+
const closingTurn = activeTurn;
|
|
1405
|
+
closingTurn?.owner.stop(new DOMException("The provider session was closed.", "AbortError"));
|
|
1406
|
+
const cleanup = async () => {
|
|
1407
|
+
if (!providerClosed) {
|
|
1408
|
+
await input.candidate.close(closeInput);
|
|
1409
|
+
providerClosed = true;
|
|
1410
|
+
}
|
|
1411
|
+
await input.sessionInteractionOwner?.join();
|
|
1412
|
+
await closingTurn?.owner.join();
|
|
1413
|
+
await input.hostBindingLease?.release();
|
|
1621
1414
|
closed = true;
|
|
1622
|
-
}
|
|
1415
|
+
};
|
|
1416
|
+
if (input.sessionInteractionOwner) return input.sessionInteractionOwner.close(cleanup, explicit);
|
|
1417
|
+
closePromise = Promise.resolve().then(cleanup).finally(() => {
|
|
1623
1418
|
closePromise = null;
|
|
1624
1419
|
});
|
|
1625
1420
|
return closePromise;
|
|
1626
1421
|
};
|
|
1422
|
+
const close = (closeInput) => closeOwned(closeInput, true);
|
|
1423
|
+
input.sessionInteractionOwner?.installClose(() => closeOwned({ reason: "error" }, false));
|
|
1627
1424
|
return Object.freeze({
|
|
1628
1425
|
binding,
|
|
1629
|
-
|
|
1630
|
-
resolveRequest,
|
|
1426
|
+
startTurn,
|
|
1631
1427
|
interruption,
|
|
1632
1428
|
steering,
|
|
1633
1429
|
configuration,
|
|
@@ -1639,11 +1435,40 @@ function validateAgentProviderSession(input) {
|
|
|
1639
1435
|
close
|
|
1640
1436
|
});
|
|
1641
1437
|
}
|
|
1642
|
-
async function closeRejectedAgentProviderSession(session, error) {
|
|
1643
|
-
if (!session
|
|
1438
|
+
async function closeRejectedAgentProviderSession(session, error, hostBinding, opening, interactions) {
|
|
1439
|
+
if (!session) throw error;
|
|
1440
|
+
hostBinding?.lease.stop();
|
|
1441
|
+
interactions?.stop();
|
|
1442
|
+
let providerClosed = false;
|
|
1443
|
+
const cleanup = async () => {
|
|
1444
|
+
if (!providerClosed) {
|
|
1445
|
+
if (typeof session.close !== "function") {
|
|
1446
|
+
throw new TypeError("Rejected provider session has no callable close port.");
|
|
1447
|
+
}
|
|
1448
|
+
await session.close({ reason: "contract_rejected" });
|
|
1449
|
+
providerClosed = true;
|
|
1450
|
+
}
|
|
1451
|
+
await interactions?.join();
|
|
1452
|
+
await hostBinding?.lease.release();
|
|
1453
|
+
};
|
|
1644
1454
|
try {
|
|
1645
|
-
await
|
|
1455
|
+
if (interactions) await interactions.close(cleanup, false);
|
|
1456
|
+
else await cleanup();
|
|
1646
1457
|
} catch (cleanupError) {
|
|
1458
|
+
if (hostBinding) {
|
|
1459
|
+
const retained = createAgentHostBindingCleanupError({
|
|
1460
|
+
providerKey: hostBinding.providerKey,
|
|
1461
|
+
lease: hostBinding.lease,
|
|
1462
|
+
errors: [error, cleanupError],
|
|
1463
|
+
retryCleanup: () => interactions ? interactions.close(cleanup, false) : cleanup()
|
|
1464
|
+
});
|
|
1465
|
+
throw opening ? associateAgentSessionCleanupError(retained, opening.input) : retained;
|
|
1466
|
+
}
|
|
1467
|
+
if (opening) throw associateAgentSessionCleanupError(new AgentProviderSessionCleanupError({
|
|
1468
|
+
providerKey: opening.providerKey,
|
|
1469
|
+
errors: [error, cleanupError],
|
|
1470
|
+
retryCleanup: () => interactions ? interactions.close(cleanup, false) : cleanup()
|
|
1471
|
+
}), opening.input);
|
|
1647
1472
|
throw new AggregateError(
|
|
1648
1473
|
[error, cleanupError],
|
|
1649
1474
|
"Provider returned an invalid session and cleanup failed."
|
|
@@ -1713,12 +1538,24 @@ async function openIdentityCreatingAgentProviderSession(input) {
|
|
|
1713
1538
|
capabilities: input.capabilities,
|
|
1714
1539
|
sessionId: input.sessionId,
|
|
1715
1540
|
candidate,
|
|
1541
|
+
...input.sessionInteractionOwner === void 0 ? {} : { sessionInteractionOwner: input.sessionInteractionOwner },
|
|
1542
|
+
...input.hostBindingLease === void 0 ? {} : { hostBindingLease: input.hostBindingLease },
|
|
1716
1543
|
...input.sourceBinding === void 0 ? {} : { sourceBinding: input.sourceBinding }
|
|
1717
1544
|
});
|
|
1718
1545
|
tracker.requireMatch(session.binding);
|
|
1546
|
+
input.sessionInteractionOwner?.adopt();
|
|
1719
1547
|
return session;
|
|
1720
1548
|
} catch (error) {
|
|
1721
|
-
return closeRejectedAgentProviderSession(
|
|
1549
|
+
return closeRejectedAgentProviderSession(
|
|
1550
|
+
candidate,
|
|
1551
|
+
error,
|
|
1552
|
+
input.hostBindingLease === void 0 ? void 0 : {
|
|
1553
|
+
providerKey: input.capabilities.providerKey,
|
|
1554
|
+
lease: input.hostBindingLease
|
|
1555
|
+
},
|
|
1556
|
+
input.openingInput === void 0 ? void 0 : { providerKey: input.capabilities.providerKey, input: input.openingInput },
|
|
1557
|
+
input.sessionInteractionOwner
|
|
1558
|
+
);
|
|
1722
1559
|
}
|
|
1723
1560
|
}
|
|
1724
1561
|
export {
|