@agen-ai/agent-runtime 0.3.0 → 0.4.0
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 +182 -24
- package/dist/adapterValidation.d.ts +1 -1
- package/dist/adapterValidation.js +162 -95
- package/dist/contractErrors.d.ts +15 -2
- package/dist/contractErrors.js +39 -1
- 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 +12 -0
- package/dist/hostBindings/opening.js +24 -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 +2 -0
- package/dist/index.js +6 -0
- package/dist/internal/objectShape.d.ts +2 -0
- package/dist/internal/objectShape.js +7 -0
- package/dist/outputValidation.js +1 -0
- package/dist/sessionCleanup.d.ts +9 -0
- package/dist/sessionCleanup.js +17 -0
- package/dist/sessionValidation.d.ts +12 -2
- package/dist/sessionValidation.js +134 -305
- package/dist/sessions.d.ts +28 -4
- package/dist/testing/conformance.d.ts +3 -3
- package/dist/testing/conformance.js +24 -30
- package/dist/testing/fakeProvider.js +56 -45
- 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,12 @@ import {
|
|
|
42
44
|
validateAgentProviderOutputForContext
|
|
43
45
|
} from "./outputValidation.js";
|
|
44
46
|
import { validateAgentTurnSteeringResult } from "./steeringValidation.js";
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (ownKeys.some((key) => typeof key !== "string")) return false;
|
|
48
|
-
const actualKeys = ownKeys.sort();
|
|
49
|
-
const canonicalExpectedKeys = [...expectedKeys].sort();
|
|
50
|
-
return actualKeys.length === canonicalExpectedKeys.length && actualKeys.every((key, index) => key === canonicalExpectedKeys[index]);
|
|
51
|
-
}
|
|
47
|
+
import { createValidatedAgentTurnExecution } from "./turnExecution/execution.js";
|
|
48
|
+
import { validateAgentProviderTurnInterruptionResult } from "./turnExecution/receipts.js";
|
|
52
49
|
function validateSessionPorts(capabilities, session) {
|
|
53
50
|
if (!hasExactOwnKeys(session, [
|
|
54
51
|
"binding",
|
|
55
|
-
"
|
|
56
|
-
"resolveRequest",
|
|
52
|
+
"startTurn",
|
|
57
53
|
"interruption",
|
|
58
54
|
"steering",
|
|
59
55
|
"configuration",
|
|
@@ -63,7 +59,7 @@ function validateSessionPorts(capabilities, session) {
|
|
|
63
59
|
"collaboration",
|
|
64
60
|
"generatedResources",
|
|
65
61
|
"close"
|
|
66
|
-
]) || typeof session.
|
|
62
|
+
]) || 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
63
|
throwAgentProviderContractError(
|
|
68
64
|
capabilities.providerKey,
|
|
69
65
|
"invalid_session",
|
|
@@ -169,7 +165,6 @@ function completeTurnSequence(input) {
|
|
|
169
165
|
);
|
|
170
166
|
}
|
|
171
167
|
input.state.terminal = true;
|
|
172
|
-
input.state.waiting = false;
|
|
173
168
|
}
|
|
174
169
|
const FINAL_DIFF_TRAILING_EVENT_TYPES = [
|
|
175
170
|
"artifact.referenced",
|
|
@@ -305,6 +300,7 @@ function observeTurnEvent(input) {
|
|
|
305
300
|
contextUsageState,
|
|
306
301
|
event,
|
|
307
302
|
openedRequestIds,
|
|
303
|
+
turnRequestIds,
|
|
308
304
|
pendingRequests,
|
|
309
305
|
providerKey,
|
|
310
306
|
state
|
|
@@ -399,14 +395,15 @@ function observeTurnEvent(input) {
|
|
|
399
395
|
state
|
|
400
396
|
});
|
|
401
397
|
openedRequestIds.add(requestId);
|
|
398
|
+
turnRequestIds.add(requestId);
|
|
402
399
|
pendingRequests.set(requestId, {
|
|
403
400
|
request: event.payload.request,
|
|
404
401
|
turnId: event.turnId
|
|
405
402
|
});
|
|
406
403
|
}
|
|
407
404
|
if (event.type === "turn.state_changed") {
|
|
408
|
-
|
|
409
|
-
if (
|
|
405
|
+
const waiting = event.payload.state === "waiting_for_request";
|
|
406
|
+
if (waiting && !turnRequestIds.has(event.payload.requestId)) {
|
|
410
407
|
invalidTurnSequence(
|
|
411
408
|
providerKey,
|
|
412
409
|
"Provider entered a waiting state for a request it did not open."
|
|
@@ -414,6 +411,7 @@ function observeTurnEvent(input) {
|
|
|
414
411
|
}
|
|
415
412
|
}
|
|
416
413
|
if (event.type === "turn.completed") {
|
|
414
|
+
if (event.payload.outcome !== "completed") pendingRequests.clear();
|
|
417
415
|
completeTurnSequence({ providerKey, state, pendingRequests });
|
|
418
416
|
}
|
|
419
417
|
}
|
|
@@ -506,6 +504,7 @@ function observeTurnOutput(input) {
|
|
|
506
504
|
state: input.state,
|
|
507
505
|
pendingRequests: input.pendingRequests,
|
|
508
506
|
openedRequestIds: input.openedRequestIds,
|
|
507
|
+
turnRequestIds: input.turnRequestIds,
|
|
509
508
|
contextUsageState: input.contextUsageState
|
|
510
509
|
});
|
|
511
510
|
}
|
|
@@ -544,23 +543,11 @@ function observeSessionOperationOutput(input) {
|
|
|
544
543
|
state: input.state,
|
|
545
544
|
pendingRequests: /* @__PURE__ */ new Map(),
|
|
546
545
|
openedRequestIds: /* @__PURE__ */ new Set(),
|
|
546
|
+
turnRequestIds: /* @__PURE__ */ new Set(),
|
|
547
547
|
contextUsageState: input.contextUsageState,
|
|
548
548
|
interactionState: input.interactionState
|
|
549
549
|
});
|
|
550
550
|
}
|
|
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
551
|
function trackActiveTurnOperation(turn) {
|
|
565
552
|
if (!turn) return null;
|
|
566
553
|
let settle;
|
|
@@ -573,45 +560,6 @@ function trackActiveTurnOperation(turn) {
|
|
|
573
560
|
settle();
|
|
574
561
|
};
|
|
575
562
|
}
|
|
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
563
|
function assertAgentTurnInputCapability(input) {
|
|
616
564
|
const imageParts = input.parts.filter((part) => part.type === "image");
|
|
617
565
|
if (imageParts.length > 0) {
|
|
@@ -726,8 +674,6 @@ function validateAgentProviderSession(input) {
|
|
|
726
674
|
port: input.candidate.environment,
|
|
727
675
|
signal: sessionLifetime.signal
|
|
728
676
|
});
|
|
729
|
-
const pendingRequests = /* @__PURE__ */ new Map();
|
|
730
|
-
const waitingTurnStates = /* @__PURE__ */ new Map();
|
|
731
677
|
const openedRequestIds = /* @__PURE__ */ new Set();
|
|
732
678
|
const contextUsageState = {
|
|
733
679
|
latestByScope: /* @__PURE__ */ new Map(),
|
|
@@ -746,6 +692,7 @@ function validateAgentProviderSession(input) {
|
|
|
746
692
|
let activeTurn = null;
|
|
747
693
|
let closePromise = null;
|
|
748
694
|
let closed = false;
|
|
695
|
+
let providerClosed = false;
|
|
749
696
|
let unusable = false;
|
|
750
697
|
const requireOpen = () => {
|
|
751
698
|
if (closed)
|
|
@@ -771,17 +718,6 @@ function validateAgentProviderSession(input) {
|
|
|
771
718
|
sessionId,
|
|
772
719
|
...turnId === void 0 ? {} : { turnId }
|
|
773
720
|
});
|
|
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
721
|
const delegateProviderMutation = async (input2) => {
|
|
786
722
|
let executionStarted = false;
|
|
787
723
|
const onProviderExecutionStarted = () => {
|
|
@@ -825,7 +761,7 @@ function validateAgentProviderSession(input) {
|
|
|
825
761
|
);
|
|
826
762
|
}
|
|
827
763
|
};
|
|
828
|
-
const
|
|
764
|
+
const startTurn = (turnInput) => {
|
|
829
765
|
requireUsable();
|
|
830
766
|
throwIfAgentOperationAborted(turnInput.signal);
|
|
831
767
|
const parsedInput = parseAgentTurnRunInput({
|
|
@@ -835,11 +771,7 @@ function validateAgentProviderSession(input) {
|
|
|
835
771
|
...turnInput.summary === void 0 ? {} : { summary: turnInput.summary },
|
|
836
772
|
...turnInput.deadlineAt === void 0 ? {} : { deadlineAt: turnInput.deadlineAt }
|
|
837
773
|
});
|
|
838
|
-
assertAgentTurnInputCapability({
|
|
839
|
-
capability: capabilities.input,
|
|
840
|
-
parts: parsedInput.parts,
|
|
841
|
-
providerKey
|
|
842
|
-
});
|
|
774
|
+
assertAgentTurnInputCapability({ capability: capabilities.input, parts: parsedInput.parts, providerKey });
|
|
843
775
|
if (!capabilities.turns.interactionModes.includes(parsedInput.interactionMode)) {
|
|
844
776
|
throwAgentProviderContractError(
|
|
845
777
|
providerKey,
|
|
@@ -847,179 +779,63 @@ function validateAgentProviderSession(input) {
|
|
|
847
779
|
`Provider ${providerKey} does not support ${parsedInput.interactionMode} turn interaction mode.`
|
|
848
780
|
);
|
|
849
781
|
}
|
|
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
782
|
if (activeTurn !== null) {
|
|
858
|
-
throwAgentProviderContractError(
|
|
859
|
-
providerKey,
|
|
860
|
-
"concurrent_turn",
|
|
861
|
-
"Provider session already has an active turn."
|
|
862
|
-
);
|
|
783
|
+
throwAgentProviderContractError(providerKey, "concurrent_turn", "Provider session already has an active turn.");
|
|
863
784
|
}
|
|
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()
|
|
785
|
+
const pendingRequests = /* @__PURE__ */ new Map();
|
|
786
|
+
const turnRequestIds = /* @__PURE__ */ new Set();
|
|
787
|
+
const state = {
|
|
788
|
+
fileChangeMode: capabilities.output.fileChanges,
|
|
789
|
+
observedItems: /* @__PURE__ */ new Map(),
|
|
790
|
+
proposedPlans: /* @__PURE__ */ new Map(),
|
|
791
|
+
generatedResourceIds: /* @__PURE__ */ new Set(),
|
|
792
|
+
started: false,
|
|
793
|
+
terminal: false,
|
|
794
|
+
finalDiffObserved: false
|
|
879
795
|
};
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
796
|
+
const inFlightOperations = /* @__PURE__ */ new Set();
|
|
797
|
+
const owner = createValidatedAgentTurnExecution({
|
|
798
|
+
providerKey,
|
|
799
|
+
turnInput: {
|
|
884
800
|
...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
|
-
);
|
|
801
|
+
...turnInput.signal === void 0 ? {} : { signal: turnInput.signal },
|
|
802
|
+
...turnInput.onProviderExecutionStarted === void 0 ? {} : { onProviderExecutionStarted: turnInput.onProviderExecutionStarted }
|
|
803
|
+
},
|
|
804
|
+
pendingRequests,
|
|
805
|
+
inFlightOperations,
|
|
806
|
+
start: (inputTurn) => input.candidate.startTurn(inputTurn),
|
|
807
|
+
requireUsable,
|
|
808
|
+
isTerminal: () => state.terminal,
|
|
809
|
+
observe(candidate) {
|
|
810
|
+
const output = validateAgentProviderOutputForContext(candidate, outputContext(parsedInput.turnId));
|
|
992
811
|
observeTurnOutput({
|
|
993
812
|
capabilities,
|
|
994
813
|
providerKey,
|
|
995
814
|
output,
|
|
996
|
-
state
|
|
997
|
-
pendingRequests
|
|
815
|
+
state,
|
|
816
|
+
pendingRequests,
|
|
998
817
|
openedRequestIds,
|
|
818
|
+
turnRequestIds,
|
|
999
819
|
contextUsageState,
|
|
1000
820
|
interactionState
|
|
1001
821
|
});
|
|
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
|
-
}
|
|
822
|
+
return output;
|
|
823
|
+
},
|
|
824
|
+
assertCompleted() {
|
|
825
|
+
if (!state.started || !state.terminal || pendingRequests.size > 0) {
|
|
826
|
+
invalidTurnSequence(providerKey, "Provider turn output must remain open until actual terminal completion.");
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
release() {
|
|
830
|
+
if (activeTurn?.owner === owner) activeTurn = null;
|
|
831
|
+
},
|
|
832
|
+
retire() {
|
|
833
|
+
unusable = true;
|
|
834
|
+
},
|
|
835
|
+
abandon: () => close({ reason: "other" })
|
|
836
|
+
});
|
|
837
|
+
activeTurn = { turnId: parsedInput.turnId, pendingRequests, state, inFlightOperations, owner };
|
|
838
|
+
return owner.execution;
|
|
1023
839
|
};
|
|
1024
840
|
const declaredInterruption = input.candidate.interruption;
|
|
1025
841
|
const interruption = declaredInterruption.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
@@ -1033,68 +849,36 @@ function validateAgentProviderSession(input) {
|
|
|
1033
849
|
...interruptionInput.requestedAt === void 0 ? {} : { requestedAt: interruptionInput.requestedAt }
|
|
1034
850
|
});
|
|
1035
851
|
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) {
|
|
852
|
+
const targetedTurn = targetedActiveTurn;
|
|
853
|
+
if (targetedTurn === null || targetedTurn.state.terminal || !targetedTurn.owner.hasEntered()) {
|
|
1043
854
|
throwAgentProviderContractError(
|
|
1044
855
|
providerKey,
|
|
1045
856
|
"active_turn_mismatch",
|
|
1046
|
-
"Provider interruption does not identify an active
|
|
857
|
+
"Provider interruption does not identify an active turn."
|
|
1047
858
|
);
|
|
1048
859
|
}
|
|
1049
860
|
const settleActiveInterruption = trackActiveTurnOperation(
|
|
1050
861
|
targetedActiveTurn
|
|
1051
862
|
);
|
|
1052
863
|
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
|
-
}
|
|
864
|
+
const suspendedRequests = targetedTurn.owner.suspendRequests();
|
|
865
|
+
let result;
|
|
1073
866
|
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
|
-
}
|
|
867
|
+
result = validateAgentProviderTurnInterruptionResult(
|
|
868
|
+
await declaredInterruption.interruptTurn({
|
|
869
|
+
...parsed,
|
|
870
|
+
...interruptionInput.signal === void 0 ? {} : { signal: interruptionInput.signal }
|
|
871
|
+
}),
|
|
872
|
+
outputContext(parsed.turnId)
|
|
873
|
+
);
|
|
1091
874
|
} catch (error) {
|
|
875
|
+
suspendedRequests.withdraw();
|
|
1092
876
|
unusable = true;
|
|
1093
877
|
throw error;
|
|
1094
878
|
}
|
|
1095
|
-
if (result.status === "
|
|
1096
|
-
|
|
1097
|
-
}
|
|
879
|
+
if (result.status === "failed") {
|
|
880
|
+
suspendedRequests.restore();
|
|
881
|
+
} else suspendedRequests.withdraw();
|
|
1098
882
|
return result;
|
|
1099
883
|
} finally {
|
|
1100
884
|
settleActiveInterruption?.();
|
|
@@ -1108,7 +892,7 @@ function validateAgentProviderSession(input) {
|
|
|
1108
892
|
requireUsable();
|
|
1109
893
|
throwIfAgentOperationAborted(steeringInput.signal);
|
|
1110
894
|
const turnId = parseAgentTurnId(steeringInput.turnId);
|
|
1111
|
-
if (activeTurn?.turnId !== turnId || activeTurn.state.terminal || activeTurn.
|
|
895
|
+
if (activeTurn?.turnId !== turnId || !activeTurn.owner.hasEntered() || activeTurn.state.terminal || activeTurn.pendingRequests.size > 0) {
|
|
1112
896
|
throwAgentProviderContractError(
|
|
1113
897
|
providerKey,
|
|
1114
898
|
"active_turn_mismatch",
|
|
@@ -1128,7 +912,7 @@ function validateAgentProviderSession(input) {
|
|
|
1128
912
|
const settleSteering = trackActiveTurnOperation(targetedActiveTurn);
|
|
1129
913
|
try {
|
|
1130
914
|
try {
|
|
1131
|
-
|
|
915
|
+
const result = validateAgentTurnSteeringResult(
|
|
1132
916
|
await declaredSteering.steerTurn({
|
|
1133
917
|
turnId,
|
|
1134
918
|
...content,
|
|
@@ -1136,6 +920,8 @@ function validateAgentProviderSession(input) {
|
|
|
1136
920
|
}),
|
|
1137
921
|
providerKey
|
|
1138
922
|
);
|
|
923
|
+
if (result.status === "delivery_uncertain") unusable = true;
|
|
924
|
+
return result;
|
|
1139
925
|
} catch (error) {
|
|
1140
926
|
unusable = true;
|
|
1141
927
|
throw new AgentProviderDelegatedOperationError(
|
|
@@ -1287,7 +1073,6 @@ function validateAgentProviderSession(input) {
|
|
|
1287
1073
|
generatedResourceIds: /* @__PURE__ */ new Set(),
|
|
1288
1074
|
started: true,
|
|
1289
1075
|
terminal: false,
|
|
1290
|
-
waiting: false,
|
|
1291
1076
|
finalDiffObserved: false
|
|
1292
1077
|
};
|
|
1293
1078
|
interactionState.operationInvocations.set(
|
|
@@ -1617,7 +1402,17 @@ function validateAgentProviderSession(input) {
|
|
|
1617
1402
|
}
|
|
1618
1403
|
unusable = true;
|
|
1619
1404
|
sessionLifetime.abort(new DOMException("The provider session was closed.", "AbortError"));
|
|
1620
|
-
|
|
1405
|
+
input.hostBindingLease?.stop();
|
|
1406
|
+
const closingTurn = activeTurn;
|
|
1407
|
+
closingTurn?.owner.stop(new DOMException("The provider session was closed.", "AbortError"));
|
|
1408
|
+
closePromise = Promise.resolve().then(async () => {
|
|
1409
|
+
if (!providerClosed) {
|
|
1410
|
+
await input.candidate.close(closeInput);
|
|
1411
|
+
providerClosed = true;
|
|
1412
|
+
}
|
|
1413
|
+
await closingTurn?.owner.join();
|
|
1414
|
+
await input.hostBindingLease?.release();
|
|
1415
|
+
}).then(() => {
|
|
1621
1416
|
closed = true;
|
|
1622
1417
|
}).finally(() => {
|
|
1623
1418
|
closePromise = null;
|
|
@@ -1626,8 +1421,7 @@ function validateAgentProviderSession(input) {
|
|
|
1626
1421
|
};
|
|
1627
1422
|
return Object.freeze({
|
|
1628
1423
|
binding,
|
|
1629
|
-
|
|
1630
|
-
resolveRequest,
|
|
1424
|
+
startTurn,
|
|
1631
1425
|
interruption,
|
|
1632
1426
|
steering,
|
|
1633
1427
|
configuration,
|
|
@@ -1639,11 +1433,37 @@ function validateAgentProviderSession(input) {
|
|
|
1639
1433
|
close
|
|
1640
1434
|
});
|
|
1641
1435
|
}
|
|
1642
|
-
async function closeRejectedAgentProviderSession(session, error) {
|
|
1643
|
-
if (!session
|
|
1436
|
+
async function closeRejectedAgentProviderSession(session, error, hostBinding, opening) {
|
|
1437
|
+
if (!session) throw error;
|
|
1438
|
+
hostBinding?.lease.stop();
|
|
1439
|
+
let providerClosed = false;
|
|
1440
|
+
const cleanup = async () => {
|
|
1441
|
+
if (!providerClosed) {
|
|
1442
|
+
if (typeof session.close !== "function") {
|
|
1443
|
+
throw new TypeError("Rejected provider session has no callable close port.");
|
|
1444
|
+
}
|
|
1445
|
+
await session.close({ reason: "contract_rejected" });
|
|
1446
|
+
providerClosed = true;
|
|
1447
|
+
}
|
|
1448
|
+
await hostBinding?.lease.release();
|
|
1449
|
+
};
|
|
1644
1450
|
try {
|
|
1645
|
-
await
|
|
1451
|
+
await cleanup();
|
|
1646
1452
|
} catch (cleanupError) {
|
|
1453
|
+
if (hostBinding) {
|
|
1454
|
+
const retained = createAgentHostBindingCleanupError({
|
|
1455
|
+
providerKey: hostBinding.providerKey,
|
|
1456
|
+
lease: hostBinding.lease,
|
|
1457
|
+
errors: [error, cleanupError],
|
|
1458
|
+
retryCleanup: cleanup
|
|
1459
|
+
});
|
|
1460
|
+
throw opening ? associateAgentSessionCleanupError(retained, opening.input) : retained;
|
|
1461
|
+
}
|
|
1462
|
+
if (opening) throw associateAgentSessionCleanupError(new AgentProviderSessionCleanupError({
|
|
1463
|
+
providerKey: opening.providerKey,
|
|
1464
|
+
errors: [error, cleanupError],
|
|
1465
|
+
retryCleanup: cleanup
|
|
1466
|
+
}), opening.input);
|
|
1647
1467
|
throw new AggregateError(
|
|
1648
1468
|
[error, cleanupError],
|
|
1649
1469
|
"Provider returned an invalid session and cleanup failed."
|
|
@@ -1713,12 +1533,21 @@ async function openIdentityCreatingAgentProviderSession(input) {
|
|
|
1713
1533
|
capabilities: input.capabilities,
|
|
1714
1534
|
sessionId: input.sessionId,
|
|
1715
1535
|
candidate,
|
|
1536
|
+
...input.hostBindingLease === void 0 ? {} : { hostBindingLease: input.hostBindingLease },
|
|
1716
1537
|
...input.sourceBinding === void 0 ? {} : { sourceBinding: input.sourceBinding }
|
|
1717
1538
|
});
|
|
1718
1539
|
tracker.requireMatch(session.binding);
|
|
1719
1540
|
return session;
|
|
1720
1541
|
} catch (error) {
|
|
1721
|
-
return closeRejectedAgentProviderSession(
|
|
1542
|
+
return closeRejectedAgentProviderSession(
|
|
1543
|
+
candidate,
|
|
1544
|
+
error,
|
|
1545
|
+
input.hostBindingLease === void 0 ? void 0 : {
|
|
1546
|
+
providerKey: input.capabilities.providerKey,
|
|
1547
|
+
lease: input.hostBindingLease
|
|
1548
|
+
},
|
|
1549
|
+
input.openingInput === void 0 ? void 0 : { providerKey: input.capabilities.providerKey, input: input.openingInput }
|
|
1550
|
+
);
|
|
1722
1551
|
}
|
|
1723
1552
|
}
|
|
1724
1553
|
export {
|