@zq-silk/yui 0.7.1 → 0.8.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/ARCHITECTURE.md +27 -28
- package/README.md +79 -71
- package/dist/cli/commandCatalog.js +283 -136
- package/dist/cli/completion.js +3 -3
- package/dist/cli/helpRenderer.js +3 -0
- package/dist/cli/interactionPolicy.js +48 -33
- package/dist/cli/interactiveSelection.js +1 -1
- package/dist/cli/invocationRouter.js +3 -2
- package/dist/cli/roleWizard.js +8 -8
- package/dist/cli.js +189 -93
- package/dist/commands/agentCommands.js +5 -5
- package/dist/commands/configCommands.js +351 -104
- package/dist/commands/configOverview.js +60 -0
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/globalRoleCommands.js +9 -9
- package/dist/commands/profileCommands.js +8 -8
- package/dist/commands/resourcesCommands.js +6 -5
- package/dist/commands/taskCommands.js +111 -59
- package/dist/commands/taskRoleRuntimeStatus.js +3 -1
- package/dist/commands/telemetryCommands.js +11 -6
- package/dist/config/configCatalog.js +42 -0
- package/dist/config/yuiConfig.js +80 -35
- package/dist/context/sessionBootstrapManifest.js +1 -1
- package/dist/controller/clientRuntime.js +0 -2
- package/dist/controller/controller.js +21 -9
- package/dist/controller/fileSchedulerStoreAdapter.js +409 -79
- package/dist/controller/resourceInventory.js +9 -5
- package/dist/controller/runtime.js +112 -25
- package/dist/controller/runtimeLaunchCoordinator.js +18 -78
- package/dist/controller/structuredProviderObservation.js +273 -0
- package/dist/doctor/doctor.js +2 -2
- package/dist/executor/agentAdapter.js +40 -0
- package/dist/executor/agentExecutor.js +31 -7
- package/dist/executor/executorRegistry.js +11 -49
- package/dist/executor/fileRoleLaunchPlanner.js +115 -37
- package/dist/lifecycle/canonicalLifecycleEvent.js +5 -2
- package/dist/resources/autoResourceGc.js +3 -1
- package/dist/review/reviewConfig.js +0 -2
- package/dist/run/agentRun.js +2 -2
- package/dist/run/providerRetry.js +29 -16
- package/dist/run/providerRetryConfig.js +5 -3
- package/dist/runtime/agentHost.js +767 -158
- package/dist/runtime/builtinAgentDrivers.js +1 -5
- package/dist/runtime/codexAppServerRuntime.js +67 -60
- package/dist/runtime/exactControlPlane.js +7 -2
- package/dist/runtime/index.js +6 -2
- package/dist/runtime/launchBroker.js +30 -8
- package/dist/runtime/launchDiagnostics.js +1 -1
- package/dist/runtime/providerAuthorityFence.js +24 -0
- package/dist/runtime/providerControl.js +63 -0
- package/dist/runtime/providerRecoveryDecision.js +55 -0
- package/dist/runtime/providerRuntimeIdentity.js +269 -19
- package/dist/runtime/runtimeBinding.js +20 -11
- package/dist/runtime/structuredProviderHost.js +476 -0
- package/dist/runtime/tmuxAdapters.js +143 -42
- package/dist/scheduler/activeRoleRunDelivery.js +206 -120
- package/dist/scheduler/leaderWakeupProcessor.js +141 -16
- package/dist/scheduler/roleRunStall.js +12 -9
- package/dist/setup/setupCommand.js +153 -492
- package/dist/storage/compatibleTaskStore.js +9 -5
- package/dist/storage/migration/productionRegistry.js +169 -0
- package/dist/storage/taskStore.js +22 -3
- package/dist/telemetry/sqliteTelemetryStore.js +9 -1
- package/dist/telemetry/telemetryConfig.js +1 -18
- package/dist/telemetry/telemetryStore.js +2 -2
- package/dist/telemetry/telemetryWiring.js +6 -5
- package/dist/tmux/tmuxManager.js +1 -1
- package/dist/web/webSnapshot.js +5 -3
- package/i18n/README.zh-CN.md +48 -40
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +12 -5
- package/skills/yui-operator/SKILL.md +44 -6
- package/skills/yui-runtime/SKILL.md +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { isDeepStrictEqual } from "node:util";
|
|
3
|
-
import { activeLiveRoleAgentSession, bindTaskRoleProviderRuntime, bindTaskRoleRun, clearTaskRoleRun, createRoleSessionSet, markTaskRoleRunDelivered, markTaskRoleRunPushed, recordRoleAgentSession, recordTaskRoleTurnBoundary, rememberRoleAgentCompletedTurn, updateRoleAgentSessionStatus, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
|
|
4
|
-
import { createProviderRuntimeBinding, endProviderActivation, startProviderActivation, updateProviderConversationRecoverability } from "../runtime/providerRuntimeIdentity.js";
|
|
3
|
+
import { activeLiveRoleAgentSession, bindTaskRoleProviderRuntime, bindTaskRoleRun, clearTaskRoleRun, createRoleSessionSet, markTaskRoleRunDelivered, markTaskRoleRunPushed, prepareTaskRoleRunRedispatch, recordRoleAgentSession, recordTaskRoleTurnBoundary, rememberRoleAgentCompletedTurn, updateRoleAgentSessionStatus, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
|
|
4
|
+
import { acceptProviderTurn, beginProviderTurn, createProviderRuntimeBinding, endProviderActivation, currentProviderActivation, currentProviderConversation, markProviderTurnDeliveryUnknown, rejectProviderTurn, settleProviderTurn, startProviderActivation, supersedeProviderConversation, updateProviderConversationRecoverability } from "../runtime/providerRuntimeIdentity.js";
|
|
5
|
+
import { decideProviderRecovery } from "../runtime/providerRecoveryDecision.js";
|
|
5
6
|
import { hasRecentTurnId } from "../executor/turnCompletion.js";
|
|
6
7
|
import { createTaskEvent } from "../event/taskEvent.js";
|
|
7
8
|
import { buildTaskWakeEnvelope } from "../context/wakeNotification.js";
|
|
@@ -40,6 +41,12 @@ import { RUNTIME_OBSERVATION_TASK_EVENT, createRuntimeObservation, runtimeObserv
|
|
|
40
41
|
import { projectRuntimeTaskEvents } from "../runtime/runtimeProjection.js";
|
|
41
42
|
import { contextSnapshotRef } from "../context/contextSnapshot.js";
|
|
42
43
|
import { contextSnapshotDeltaRefIds, freezeRunContextSnapshot } from "../context/runContextPack.js";
|
|
44
|
+
export class AgentHostProviderTurnFenceError extends Error {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "AgentHostProviderTurnFenceError";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
43
50
|
/** Maps the authoritative FileTaskStore records to the scheduler's narrow port. */
|
|
44
51
|
export class FileSchedulerStoreAdapter {
|
|
45
52
|
store;
|
|
@@ -145,7 +152,8 @@ export class FileSchedulerStoreAdapter {
|
|
|
145
152
|
nativeSessionId: input.fence.nativeSessionId,
|
|
146
153
|
turnId: input.fence.nativeTurnId,
|
|
147
154
|
runId: input.fence.runId,
|
|
148
|
-
summary: input.payload.summary ?? `Provider Turn failed: ${failureEvidence.code}
|
|
155
|
+
summary: input.payload.summary ?? `Provider Turn failed: ${failureEvidence.code}.`,
|
|
156
|
+
providerStatus: "failed"
|
|
149
157
|
}, now);
|
|
150
158
|
outcome = boundary.disposition === "obsolete" ? "obsolete" : "applied";
|
|
151
159
|
break;
|
|
@@ -505,7 +513,14 @@ export class FileSchedulerStoreAdapter {
|
|
|
505
513
|
});
|
|
506
514
|
if (this.telemetry !== null && input.fence.runId !== undefined) {
|
|
507
515
|
try {
|
|
508
|
-
|
|
516
|
+
const entry = runtimeObservationTelemetryEntry(input);
|
|
517
|
+
this.telemetry.sink.observe(entry);
|
|
518
|
+
const run = this.store.getAgentRun(entry.taskId, input.fence.runId);
|
|
519
|
+
if (run !== null && run.status !== "active") {
|
|
520
|
+
void this.telemetry.retention.flush().then(() => {
|
|
521
|
+
this.telemetry?.retention.pruneGeneration(entry.taskId, entry.roleName, entry.runId, entry.generation);
|
|
522
|
+
}).catch(() => undefined);
|
|
523
|
+
}
|
|
509
524
|
}
|
|
510
525
|
catch {
|
|
511
526
|
// Runtime telemetry is diagnostic; the compact durable state snapshot
|
|
@@ -805,42 +820,129 @@ export class FileSchedulerStoreAdapter {
|
|
|
805
820
|
const sessions = this.store.getTaskRoleSessionSet(taskId, roleName);
|
|
806
821
|
return sessions !== null && sessions.inFlight !== null;
|
|
807
822
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
.
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
const
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
823
|
+
beginAgentHostProviderTurn(input) {
|
|
824
|
+
this.store.transaction((store) => {
|
|
825
|
+
const sessions = store.getTaskRoleSessionSet(input.taskId, input.roleName);
|
|
826
|
+
const session = sessions?.sessions[input.agentId];
|
|
827
|
+
const binding = sessions?.providerBinding;
|
|
828
|
+
if (sessions === null || sessions === undefined
|
|
829
|
+
|| binding === null || binding === undefined
|
|
830
|
+
|| sessions.inFlight?.runId !== input.runId
|
|
831
|
+
|| binding.runId !== input.runId
|
|
832
|
+
|| session?.launchId !== input.launchId
|
|
833
|
+
|| session.nativeSessionId !== input.nativeSessionId
|
|
834
|
+
|| currentProviderConversation(binding).conversationId !== input.nativeSessionId
|
|
835
|
+
|| binding.authority.owner !== input.authorityOwner
|
|
836
|
+
|| binding.authority.epoch !== input.authorityEpoch
|
|
837
|
+
|| binding.authority.holderId !== input.holderId) {
|
|
838
|
+
throw new AgentHostProviderTurnFenceError("Agent Host Provider Turn carries a stale durable writer fence. Release and reacquire Provider authority before retrying input.");
|
|
839
|
+
}
|
|
840
|
+
const exactReplay = binding.turn?.attemptId === input.attemptId
|
|
841
|
+
&& binding.turn.authorityEpoch === input.authorityEpoch
|
|
842
|
+
&& binding.turn.status === "submitting";
|
|
843
|
+
if (!exactReplay && binding.turn !== null
|
|
844
|
+
&& ["submitting", "accepted", "running", "delivery-unknown"]
|
|
845
|
+
.includes(binding.turn.status)) {
|
|
846
|
+
throw new AgentHostProviderTurnFenceError("Provider Conversation already has an unsettled Turn.");
|
|
847
|
+
}
|
|
848
|
+
store.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(sessions, beginProviderTurn(binding, {
|
|
849
|
+
attemptId: input.attemptId,
|
|
850
|
+
authorityEpoch: input.authorityEpoch,
|
|
851
|
+
submittedAt: input.now.toISOString()
|
|
852
|
+
}), input.now));
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
resolveAgentHostProviderTurnSubmission(input) {
|
|
856
|
+
this.store.transaction((store) => {
|
|
857
|
+
const sessions = store.getTaskRoleSessionSet(input.taskId, input.roleName);
|
|
858
|
+
const binding = sessions?.providerBinding;
|
|
859
|
+
if (sessions === null || sessions === undefined
|
|
860
|
+
|| binding === null || binding === undefined
|
|
861
|
+
|| binding.runId !== input.runId
|
|
862
|
+
|| binding.turn?.attemptId !== input.attemptId
|
|
863
|
+
|| binding.turn.status !== "submitting") {
|
|
864
|
+
throw new Error("Agent Host Provider Turn submission is no longer current.");
|
|
865
|
+
}
|
|
866
|
+
const updated = input.status === "delivery-unknown"
|
|
867
|
+
? markProviderTurnDeliveryUnknown(binding, {
|
|
868
|
+
attemptId: input.attemptId,
|
|
869
|
+
observedAt: input.now.toISOString(),
|
|
870
|
+
reason: input.reason
|
|
871
|
+
})
|
|
872
|
+
: rejectProviderTurn(binding, {
|
|
873
|
+
attemptId: input.attemptId,
|
|
874
|
+
rejectedAt: input.now.toISOString(),
|
|
875
|
+
reason: input.reason
|
|
876
|
+
});
|
|
877
|
+
store.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(sessions, updated, input.now));
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
getProviderAuthorityFence(input) {
|
|
881
|
+
const sessions = this.store.getTaskRoleSessionSet(input.taskId, input.roleName);
|
|
882
|
+
const session = sessions?.sessions[input.agentId];
|
|
883
|
+
const binding = sessions?.providerBinding;
|
|
884
|
+
if (binding === null || binding === undefined
|
|
885
|
+
|| binding.runId !== input.runId
|
|
886
|
+
|| session?.launchId !== input.launchId
|
|
887
|
+
|| session.nativeSessionId !== input.nativeSessionId
|
|
888
|
+
|| currentProviderConversation(binding).conversationId !== input.nativeSessionId)
|
|
889
|
+
return null;
|
|
890
|
+
const activation = currentProviderActivation(binding);
|
|
891
|
+
if (activation === null)
|
|
836
892
|
return null;
|
|
837
|
-
const observation = fences.get(active[0][0]);
|
|
838
893
|
return {
|
|
839
|
-
conversationId:
|
|
840
|
-
activationId:
|
|
841
|
-
|
|
894
|
+
conversationId: currentProviderConversation(binding).conversationId,
|
|
895
|
+
activationId: activation.activationId,
|
|
896
|
+
...binding.authority
|
|
842
897
|
};
|
|
843
898
|
}
|
|
899
|
+
beginRoleRunProviderTurn(input) {
|
|
900
|
+
return this.store.transaction((store) => {
|
|
901
|
+
const sessions = store.getTaskRoleSessionSet(input.taskId, input.roleName);
|
|
902
|
+
const session = sessions?.sessions[input.agentId];
|
|
903
|
+
const binding = sessions?.providerBinding;
|
|
904
|
+
if (sessions === null || sessions === undefined
|
|
905
|
+
|| binding === null || binding === undefined
|
|
906
|
+
|| sessions.inFlight?.runId !== input.runId
|
|
907
|
+
|| binding.runId !== input.runId
|
|
908
|
+
|| session?.launchId !== input.launchId
|
|
909
|
+
|| session.nativeSessionId !== input.nativeSessionId
|
|
910
|
+
|| currentProviderConversation(binding).conversationId !== input.nativeSessionId
|
|
911
|
+
|| binding.authority.owner !== "controller")
|
|
912
|
+
return false;
|
|
913
|
+
store.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(sessions, beginProviderTurn(binding, {
|
|
914
|
+
attemptId: input.attemptId,
|
|
915
|
+
authorityEpoch: binding.authority.epoch,
|
|
916
|
+
submittedAt: input.now.toISOString()
|
|
917
|
+
}), input.now));
|
|
918
|
+
return true;
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
resolveRoleRunProviderSubmission(input) {
|
|
922
|
+
return this.store.transaction((store) => {
|
|
923
|
+
const sessions = store.getTaskRoleSessionSet(input.taskId, input.roleName);
|
|
924
|
+
const binding = sessions?.providerBinding;
|
|
925
|
+
if (sessions === null || sessions === undefined
|
|
926
|
+
|| binding === null || binding === undefined
|
|
927
|
+
|| binding.runId !== input.runId
|
|
928
|
+
|| binding.turn?.attemptId !== input.attemptId
|
|
929
|
+
|| binding.turn.status !== "submitting")
|
|
930
|
+
return false;
|
|
931
|
+
const updated = input.status === "delivery-unknown"
|
|
932
|
+
? markProviderTurnDeliveryUnknown(binding, {
|
|
933
|
+
attemptId: input.attemptId,
|
|
934
|
+
observedAt: input.now.toISOString(),
|
|
935
|
+
reason: input.reason
|
|
936
|
+
})
|
|
937
|
+
: rejectProviderTurn(binding, {
|
|
938
|
+
attemptId: input.attemptId,
|
|
939
|
+
rejectedAt: input.now.toISOString(),
|
|
940
|
+
reason: input.reason
|
|
941
|
+
});
|
|
942
|
+
store.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(sessions, updated, input.now));
|
|
943
|
+
return true;
|
|
944
|
+
});
|
|
945
|
+
}
|
|
844
946
|
isRoleGenerationProviderReady(input) {
|
|
845
947
|
// A session.ready observation for this exact generation is the durable
|
|
846
948
|
// pre-input fence. This reads folded Driver truth
|
|
@@ -964,6 +1066,31 @@ export class FileSchedulerStoreAdapter {
|
|
|
964
1066
|
executionRef: input.executionRef,
|
|
965
1067
|
providerFence: input.providerFence
|
|
966
1068
|
});
|
|
1069
|
+
if (input.target.kind === "role"
|
|
1070
|
+
&& input.executionRef.type === "run"
|
|
1071
|
+
&& input.executionRef.taskId === input.target.taskId) {
|
|
1072
|
+
const sessions = store.getTaskRoleSessionSet(input.target.taskId, input.target.roleName);
|
|
1073
|
+
const binding = sessions?.providerBinding;
|
|
1074
|
+
if (sessions === null || sessions === undefined
|
|
1075
|
+
|| binding === null || binding === undefined
|
|
1076
|
+
|| binding.runId !== input.executionRef.id
|
|
1077
|
+
|| binding.authority.owner !== "controller") {
|
|
1078
|
+
throw new Error("Controller does not own the Provider writer authority.");
|
|
1079
|
+
}
|
|
1080
|
+
const conversation = currentProviderConversation(binding);
|
|
1081
|
+
const activation = currentProviderActivation(binding);
|
|
1082
|
+
if (input.providerFence === undefined
|
|
1083
|
+
|| conversation.conversationId !== input.providerFence.conversationId
|
|
1084
|
+
|| activation?.activationId !== input.providerFence.activationId) {
|
|
1085
|
+
throw new Error("Provider input claim carries a stale Conversation/Activation fence.");
|
|
1086
|
+
}
|
|
1087
|
+
const next = beginProviderTurn(binding, {
|
|
1088
|
+
attemptId: input.attemptId,
|
|
1089
|
+
authorityEpoch: binding.authority.epoch,
|
|
1090
|
+
submittedAt: input.now.toISOString()
|
|
1091
|
+
});
|
|
1092
|
+
store.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(sessions, next, input.now));
|
|
1093
|
+
}
|
|
967
1094
|
store.saveWorkMailbox(claimed);
|
|
968
1095
|
return { status: "claimed", delivery: claimed.inputDelivery };
|
|
969
1096
|
});
|
|
@@ -1002,20 +1129,22 @@ export class FileSchedulerStoreAdapter {
|
|
|
1002
1129
|
return true;
|
|
1003
1130
|
});
|
|
1004
1131
|
}
|
|
1005
|
-
releaseInputDelivery(target, attemptId) {
|
|
1132
|
+
releaseInputDelivery(target, attemptId, now) {
|
|
1006
1133
|
return this.store.transaction((store) => {
|
|
1007
1134
|
const mailbox = store.getWorkMailbox(target);
|
|
1008
1135
|
if (mailbox?.inputDelivery?.attemptId !== attemptId)
|
|
1009
1136
|
return false;
|
|
1137
|
+
rejectSubmittingProviderTurn(store, target, mailbox.inputDelivery, now, "Provider write was not attempted.");
|
|
1010
1138
|
store.saveWorkMailbox(releaseMailboxInputDelivery(mailbox, attemptId));
|
|
1011
1139
|
return true;
|
|
1012
1140
|
});
|
|
1013
1141
|
}
|
|
1014
|
-
resolveInputDeliveryNotAccepted(target, attemptId) {
|
|
1142
|
+
resolveInputDeliveryNotAccepted(target, attemptId, now) {
|
|
1015
1143
|
return this.store.transaction((store) => {
|
|
1016
1144
|
const mailbox = store.getWorkMailbox(target);
|
|
1017
1145
|
if (mailbox?.inputDelivery?.attemptId !== attemptId)
|
|
1018
1146
|
return false;
|
|
1147
|
+
rejectSubmittingProviderTurn(store, target, mailbox.inputDelivery, now, "Provider returned an exact negative acknowledgement.");
|
|
1019
1148
|
store.saveWorkMailbox(resolveMailboxInputDeliveryNotAccepted(mailbox, attemptId));
|
|
1020
1149
|
return true;
|
|
1021
1150
|
});
|
|
@@ -1026,6 +1155,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
1026
1155
|
if (mailbox?.inputDelivery?.attemptId !== attemptId)
|
|
1027
1156
|
return false;
|
|
1028
1157
|
const unknown = markMailboxInputDeliveryUnknown(mailbox, attemptId, reason, now);
|
|
1158
|
+
markSubmittingProviderTurnUnknown(store, target, mailbox.inputDelivery, now, reason);
|
|
1029
1159
|
store.saveWorkMailbox(unknown);
|
|
1030
1160
|
const taskId = target.kind === "role" ? target.taskId : undefined;
|
|
1031
1161
|
if (taskId !== undefined) {
|
|
@@ -1865,6 +1995,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
1865
1995
|
: sessions.inFlight === null ? idleStatus : "running",
|
|
1866
1996
|
effective
|
|
1867
1997
|
}, now);
|
|
1998
|
+
sessions = settleStructuredProviderTurn(sessions, input.turnId, input.providerStatus ?? "completed", now);
|
|
1868
1999
|
if (sessions.inFlight === null) {
|
|
1869
2000
|
sessions = rememberRoleAgentCompletedTurn(sessions, input.agentId, input.nativeSessionId, input.turnId, now);
|
|
1870
2001
|
store.saveTaskRoleSessionSet(sessions);
|
|
@@ -2084,7 +2215,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
2084
2215
|
failedNativeTurnId: input.nativeTurnId,
|
|
2085
2216
|
lastErrorSummary: summary,
|
|
2086
2217
|
scheduleNextAttempt: false
|
|
2087
|
-
}, now);
|
|
2218
|
+
}, now, configuredProviderRetryPolicy(store));
|
|
2088
2219
|
if (blocked.outcome === "exhausted")
|
|
2089
2220
|
return null;
|
|
2090
2221
|
store.saveAgentRun(withProviderRetry(run, blocked.retry));
|
|
@@ -2110,7 +2241,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
2110
2241
|
failedNativeTurnId: input.nativeTurnId,
|
|
2111
2242
|
lastErrorSummary: summary,
|
|
2112
2243
|
...(input.retryAfterMs === undefined ? {} : { retryAfterMs: input.retryAfterMs })
|
|
2113
|
-
}, now);
|
|
2244
|
+
}, now, configuredProviderRetryPolicy(store));
|
|
2114
2245
|
if (retryDecision.outcome === "exhausted") {
|
|
2115
2246
|
this.recordProviderRetryClassified(store, input, classification.errorClass, {
|
|
2116
2247
|
wouldRetry: "false",
|
|
@@ -2122,24 +2253,17 @@ export class FileSchedulerStoreAdapter {
|
|
|
2122
2253
|
if (run.providerRetry === undefined)
|
|
2123
2254
|
return null;
|
|
2124
2255
|
const finalized = finalizeProviderRetryDeadline(store, run, retryDecision.reason === "attempts"
|
|
2125
|
-
?
|
|
2256
|
+
? `Provider retry failed after all ${config.delaysMs.length} in-Session continuation attempts.`
|
|
2126
2257
|
: retryDecision.reason === "retry-after-window"
|
|
2127
|
-
?
|
|
2128
|
-
:
|
|
2258
|
+
? `Provider Retry-After exceeded the bounded ${config.maxWindowMs / 1_000}-second episode window.`
|
|
2259
|
+
: `Provider retry did not recover within the bounded ${config.maxWindowMs / 1_000}-second episode window.`, retryDecision.reason === "attempts" ? "attempts-exhausted" : "episode-window-exhausted", now);
|
|
2129
2260
|
return finalized ? { disposition: "applied", runId: input.runId } : null;
|
|
2130
2261
|
}
|
|
2131
2262
|
const retry = retryDecision.retry;
|
|
2132
2263
|
store.saveAgentRun(withProviderRetry(run, retry));
|
|
2133
|
-
//
|
|
2134
|
-
|
|
2135
|
-
//
|
|
2136
|
-
if (sessions !== null && sessions.inFlight !== null) {
|
|
2137
|
-
store.saveTaskRoleSessionSet(clearTaskRoleRun(sessions, {
|
|
2138
|
-
agentId: input.agentId,
|
|
2139
|
-
runId: input.runId,
|
|
2140
|
-
receiptId: agentRunDeliveryReceiptId(run)
|
|
2141
|
-
}, now));
|
|
2142
|
-
}
|
|
2264
|
+
// The in-flight fence and Provider Conversation stay bound while the
|
|
2265
|
+
// retry waits. resolveDueProviderRetries advances only the delivery
|
|
2266
|
+
// receipt immediately before the exact redispatch.
|
|
2143
2267
|
// Settle the delivery claim so the retry push can re-claim the mailbox.
|
|
2144
2268
|
const target = runtimeLifecycleTarget({
|
|
2145
2269
|
scope: "task",
|
|
@@ -2183,7 +2307,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
2183
2307
|
failedNativeTurnId: input.nativeTurnId,
|
|
2184
2308
|
lastErrorSummary: summary,
|
|
2185
2309
|
scheduleNextAttempt: false
|
|
2186
|
-
}, now);
|
|
2310
|
+
}, now, configuredProviderRetryPolicy(store));
|
|
2187
2311
|
if (retryDecision.outcome === "exhausted")
|
|
2188
2312
|
return null;
|
|
2189
2313
|
store.saveAgentRun(withProviderRetry(run, retryDecision.retry));
|
|
@@ -2223,7 +2347,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
2223
2347
|
failedNativeTurnId: input.nativeTurnId,
|
|
2224
2348
|
lastErrorSummary: summary,
|
|
2225
2349
|
scheduleNextAttempt: false
|
|
2226
|
-
}, now);
|
|
2350
|
+
}, now, configuredProviderRetryPolicy(store));
|
|
2227
2351
|
if (decision.outcome === "exhausted")
|
|
2228
2352
|
return null;
|
|
2229
2353
|
store.saveAgentRun(withProviderRetry(run, decision.retry));
|
|
@@ -2262,7 +2386,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
2262
2386
|
failedNativeTurnId: input.nativeTurnId,
|
|
2263
2387
|
lastErrorSummary: summary,
|
|
2264
2388
|
scheduleNextAttempt: false
|
|
2265
|
-
}, now);
|
|
2389
|
+
}, now, configuredProviderRetryPolicy(store));
|
|
2266
2390
|
if (decision.outcome === "exhausted")
|
|
2267
2391
|
return null;
|
|
2268
2392
|
store.saveAgentRun(withProviderRetry(run, decision.retry));
|
|
@@ -2380,7 +2504,61 @@ export class FileSchedulerStoreAdapter {
|
|
|
2380
2504
|
|| !providerRetryIsDue(run.providerRetry, now)) {
|
|
2381
2505
|
return;
|
|
2382
2506
|
}
|
|
2383
|
-
|
|
2507
|
+
let sessions = store.getTaskRoleSessionSet(entry.taskId, entry.roleName);
|
|
2508
|
+
const providerBinding = sessions?.providerBinding;
|
|
2509
|
+
let recoveryMode = "resume";
|
|
2510
|
+
if (providerBinding === null || providerBinding === undefined) {
|
|
2511
|
+
deferUnprovenProviderRecovery(store, run, entry.roleName, "Provider Conversation identity is missing; automatic recovery is fenced.", now);
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
const conversation = currentProviderConversation(providerBinding);
|
|
2515
|
+
const roleMailbox = store.getWorkMailbox({
|
|
2516
|
+
kind: "role",
|
|
2517
|
+
taskId: entry.taskId,
|
|
2518
|
+
roleName: entry.roleName
|
|
2519
|
+
});
|
|
2520
|
+
const activeTurnId = providerBinding.turn !== null
|
|
2521
|
+
&& ["accepted", "running"].includes(providerBinding.turn.status)
|
|
2522
|
+
? providerBinding.turn.turnId
|
|
2523
|
+
: undefined;
|
|
2524
|
+
const recovery = decideProviderRecovery({
|
|
2525
|
+
binding: providerBinding,
|
|
2526
|
+
probe: {
|
|
2527
|
+
state: conversation.recoverability === "recoverable"
|
|
2528
|
+
? "exists"
|
|
2529
|
+
: conversation.recoverability === "unrecoverable" ? "missing" : "unknown",
|
|
2530
|
+
conversationId: conversation.conversationId,
|
|
2531
|
+
...(activeTurnId === undefined ? {} : { activeTurnId })
|
|
2532
|
+
},
|
|
2533
|
+
unsettledInputDelivery: roleMailbox?.inputDelivery != null
|
|
2534
|
+
});
|
|
2535
|
+
if (recovery.action === "attention") {
|
|
2536
|
+
deferUnprovenProviderRecovery(store, run, entry.roleName, recovery.reason, now);
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2539
|
+
if (recovery.action === "observe-active-turn") {
|
|
2540
|
+
const deferred = deferProviderRetry(run.providerRetry, now);
|
|
2541
|
+
if (deferred === null) {
|
|
2542
|
+
finalizeProviderRetryDeadline(store, run, `Provider Turn ${recovery.turnId} remained active through the bounded recovery deadline.`, "provider-progress-timeout", now);
|
|
2543
|
+
}
|
|
2544
|
+
else {
|
|
2545
|
+
store.saveAgentRun(withProviderRetry(run, deferred));
|
|
2546
|
+
}
|
|
2547
|
+
return;
|
|
2548
|
+
}
|
|
2549
|
+
if (recovery.action === "replace") {
|
|
2550
|
+
if (conversation.recoverability !== "unrecoverable") {
|
|
2551
|
+
deferUnprovenProviderRecovery(store, run, entry.roleName, "Provider replacement lacks an exact missing-Conversation observation.", now);
|
|
2552
|
+
return;
|
|
2553
|
+
}
|
|
2554
|
+
recoveryMode = "new";
|
|
2555
|
+
const currentSession = sessions?.sessions[run.effective.agentId];
|
|
2556
|
+
if (sessions !== null && currentSession !== undefined
|
|
2557
|
+
&& currentSession.status !== "broken") {
|
|
2558
|
+
sessions = updateRoleAgentSessionStatus(sessions, run.effective.agentId, "broken", now);
|
|
2559
|
+
store.saveTaskRoleSessionSet(sessions);
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2384
2562
|
const session = sessions?.sessions[run.effective.agentId];
|
|
2385
2563
|
const identityMatches = session !== undefined
|
|
2386
2564
|
&& session.adapterId === run.effective.adapterId
|
|
@@ -2425,7 +2603,15 @@ export class FileSchedulerStoreAdapter {
|
|
|
2425
2603
|
// Reopen the Run on its original Session: reset transport markers,
|
|
2426
2604
|
// switch to resume, and mark the projection in-flight. The delivery
|
|
2427
2605
|
// pass re-pushes the exact same input in this same pass.
|
|
2428
|
-
|
|
2606
|
+
const reopenedRun = reopenRunForProviderRetry(run, `provider-retry-${run.providerRetry.episodeId}-${run.providerRetry.dispatchedRetries + 1}`, now, recoveryMode);
|
|
2607
|
+
store.saveAgentRun(reopenedRun);
|
|
2608
|
+
if (sessions !== null && sessions.inFlight !== null) {
|
|
2609
|
+
store.saveTaskRoleSessionSet(prepareTaskRoleRunRedispatch(sessions, {
|
|
2610
|
+
agentId: run.effective.agentId,
|
|
2611
|
+
runId: run.id,
|
|
2612
|
+
receiptId: agentRunDeliveryReceiptId(reopenedRun)
|
|
2613
|
+
}, now));
|
|
2614
|
+
}
|
|
2429
2615
|
// The retry decision settled the original delivery claim; re-queue the
|
|
2430
2616
|
// Role mailbox so the delivery pass can claim and re-push the Run.
|
|
2431
2617
|
enqueueWork(store, { kind: "role", taskId: entry.taskId, roleName: entry.roleName }, "provider-retry-repush", now, [{ type: "run", taskId: entry.taskId, id: run.id }]);
|
|
@@ -2444,7 +2630,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
2444
2630
|
const sessions = store.getTaskRoleSessionSet(taskId, input.fence.roleName);
|
|
2445
2631
|
const run = store.getAgentRun(taskId, input.fence.runId);
|
|
2446
2632
|
if (sessions === null || sessions.providerBinding === null || run === null
|
|
2447
|
-
||
|
|
2633
|
+
|| sessions.providerBinding.runId !== input.fence.runId
|
|
2448
2634
|
|| input.fence.conversationId === undefined) {
|
|
2449
2635
|
recordCanonicalObservationObsolete(store, input, "provider-binding-missing", now);
|
|
2450
2636
|
return "obsolete";
|
|
@@ -2532,16 +2718,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
2532
2718
|
status: "running",
|
|
2533
2719
|
effective: run.effective
|
|
2534
2720
|
}, now);
|
|
2535
|
-
const withProvider = bound
|
|
2536
|
-
? bound
|
|
2537
|
-
: bindTaskRoleProviderRuntime(bound, createProviderRuntimeBinding({
|
|
2538
|
-
providerNamespace: input.fence.driverId,
|
|
2539
|
-
accountScope: input.fence.agentId,
|
|
2540
|
-
runId: bound.inFlight.runId,
|
|
2541
|
-
conversationId: input.fence.conversationId ?? decision.outcome.nativeSessionId,
|
|
2542
|
-
activationId: input.fence.activationId ?? input.fence.launchId,
|
|
2543
|
-
startedAt: bound.inFlight.preparedAt
|
|
2544
|
-
}), now);
|
|
2721
|
+
const withProvider = bindOrSupersedeProviderRuntime(bound, input, now);
|
|
2545
2722
|
store.saveTaskRoleSessionSet(withProvider);
|
|
2546
2723
|
const driver = this.drivers.require(input.fence.driverId);
|
|
2547
2724
|
if (driver.capabilities.observation.sessionBootstrap === "discovered"
|
|
@@ -2556,17 +2733,9 @@ export class FileSchedulerStoreAdapter {
|
|
|
2556
2733
|
const current = store.getTaskRoleSessionSet(input.fence.taskId, input.fence.roleName);
|
|
2557
2734
|
const currentSession = current?.sessions[input.fence.agentId];
|
|
2558
2735
|
if (current !== null && current !== undefined
|
|
2559
|
-
&& current.providerBinding === null
|
|
2560
2736
|
&& current.inFlight !== null
|
|
2561
2737
|
&& currentSession?.nativeSessionId === input.fence.nativeSessionId) {
|
|
2562
|
-
store.saveTaskRoleSessionSet(
|
|
2563
|
-
providerNamespace: input.fence.driverId,
|
|
2564
|
-
accountScope: input.fence.agentId,
|
|
2565
|
-
runId: current.inFlight.runId,
|
|
2566
|
-
conversationId: input.fence.conversationId ?? input.fence.nativeSessionId,
|
|
2567
|
-
activationId: input.fence.activationId ?? input.fence.launchId,
|
|
2568
|
-
startedAt: current.inFlight.preparedAt
|
|
2569
|
-
}), now));
|
|
2738
|
+
store.saveTaskRoleSessionSet(bindOrSupersedeProviderRuntime(current, input, now));
|
|
2570
2739
|
}
|
|
2571
2740
|
return "applied";
|
|
2572
2741
|
}
|
|
@@ -2591,6 +2760,32 @@ export class FileSchedulerStoreAdapter {
|
|
|
2591
2760
|
&& inputDelivery.executionRef.taskId === input.fence.taskId
|
|
2592
2761
|
&& inputDelivery.executionRef.id === input.fence.runId
|
|
2593
2762
|
&& inputDelivery.attemptId !== formatAgentRunReceiptId(input.fence.taskId, input.fence.runId);
|
|
2763
|
+
const humanAttemptId = input.fence.receiptId;
|
|
2764
|
+
if (humanAttemptId !== undefined && humanAttemptId.startsWith("human:")) {
|
|
2765
|
+
const active = store.getActiveAgentRun(input.fence.taskId, input.fence.roleName);
|
|
2766
|
+
const sessions = store.getTaskRoleSessionSet(input.fence.taskId, input.fence.roleName);
|
|
2767
|
+
const session = sessions?.sessions[input.fence.agentId];
|
|
2768
|
+
const binding = sessions?.providerBinding;
|
|
2769
|
+
if (active === null || active.id !== input.fence.runId
|
|
2770
|
+
|| sessions === null || sessions === undefined
|
|
2771
|
+
|| binding === null || binding === undefined
|
|
2772
|
+
|| binding.authority.owner !== "human"
|
|
2773
|
+
|| !humanAttemptId.startsWith(`human:${binding.authority.holderId}:`)
|
|
2774
|
+
|| binding.turn?.attemptId !== humanAttemptId
|
|
2775
|
+
|| session?.launchId !== input.fence.launchId
|
|
2776
|
+
|| session.nativeSessionId !== input.fence.nativeSessionId) {
|
|
2777
|
+
recordCanonicalObservationObsolete(store, input, "human-turn-fence-mismatch", now);
|
|
2778
|
+
return "obsolete";
|
|
2779
|
+
}
|
|
2780
|
+
store.saveTaskRoleSessionSet(recordStructuredProviderAcceptance(updateRoleAgentSessionStatus(sessions, input.fence.agentId, "running", now), input, now));
|
|
2781
|
+
store.saveEvent(input.fence.taskId, createTaskEvent(store.nextEventId(input.fence.taskId), input.fence.taskId, "run.human-input-delivered", {
|
|
2782
|
+
attemptId: humanAttemptId,
|
|
2783
|
+
runId: active.id,
|
|
2784
|
+
authorityEpoch: String(binding.authority.epoch),
|
|
2785
|
+
nativeTurnId: input.fence.nativeTurnId
|
|
2786
|
+
}, now));
|
|
2787
|
+
return "applied";
|
|
2788
|
+
}
|
|
2594
2789
|
if (continuation) {
|
|
2595
2790
|
const active = store.getActiveAgentRun(input.fence.taskId, input.fence.roleName);
|
|
2596
2791
|
const sessions = store.getTaskRoleSessionSet(input.fence.taskId, input.fence.roleName);
|
|
@@ -2605,7 +2800,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
2605
2800
|
recordCanonicalObservationObsolete(store, input, "continuation-fence-mismatch", now);
|
|
2606
2801
|
return "obsolete";
|
|
2607
2802
|
}
|
|
2608
|
-
store.saveTaskRoleSessionSet(updateRoleAgentSessionStatus(sessions, input.fence.agentId, "running", now));
|
|
2803
|
+
store.saveTaskRoleSessionSet(recordStructuredProviderAcceptance(updateRoleAgentSessionStatus(sessions, input.fence.agentId, "running", now), input, now));
|
|
2609
2804
|
const role = store.getRole(input.fence.taskId, input.fence.roleName);
|
|
2610
2805
|
if (role !== null && role.status !== "running") {
|
|
2611
2806
|
store.saveRole(input.fence.taskId, updateRoleStatus(role, "running", now));
|
|
@@ -2652,6 +2847,10 @@ export class FileSchedulerStoreAdapter {
|
|
|
2652
2847
|
recordCanonicalObservationObsolete(store, input, "role-missing", now);
|
|
2653
2848
|
return "obsolete";
|
|
2654
2849
|
}
|
|
2850
|
+
const sessions = store.getTaskRoleSessionSet(input.fence.taskId, input.fence.roleName);
|
|
2851
|
+
if (sessions !== null) {
|
|
2852
|
+
store.saveTaskRoleSessionSet(recordStructuredProviderAcceptance(sessions, input, now));
|
|
2853
|
+
}
|
|
2655
2854
|
const progressed = clearProviderRetryOnProgress(active);
|
|
2656
2855
|
if (progressed !== active) {
|
|
2657
2856
|
store.saveAgentRun(progressed);
|
|
@@ -3641,6 +3840,133 @@ function compactedRuntimeObservationIds(events, incoming) {
|
|
|
3641
3840
|
};
|
|
3642
3841
|
return existing.filter(remove).map(({ event }) => event.id);
|
|
3643
3842
|
}
|
|
3843
|
+
function recordStructuredProviderAcceptance(sessions, input, now) {
|
|
3844
|
+
const current = sessions.providerBinding;
|
|
3845
|
+
const attemptId = input.fence.receiptId;
|
|
3846
|
+
const turnId = input.fence.nativeTurnId;
|
|
3847
|
+
if (current === null || attemptId === undefined || turnId === undefined)
|
|
3848
|
+
return sessions;
|
|
3849
|
+
if (current.turn?.attemptId === attemptId
|
|
3850
|
+
&& current.turn.turnId === turnId
|
|
3851
|
+
&& ["accepted", "running", "completed", "failed", "cancelled"].includes(current.turn.status))
|
|
3852
|
+
return sessions;
|
|
3853
|
+
const binding = acceptProviderTurn(current, {
|
|
3854
|
+
attemptId,
|
|
3855
|
+
turnId,
|
|
3856
|
+
acceptedAt: input.observedAt ?? input.receivedAt
|
|
3857
|
+
});
|
|
3858
|
+
return updateTaskRoleProviderRuntime(sessions, binding, now);
|
|
3859
|
+
}
|
|
3860
|
+
function bindOrSupersedeProviderRuntime(sessions, input, now) {
|
|
3861
|
+
if (sessions.inFlight === null)
|
|
3862
|
+
return sessions;
|
|
3863
|
+
const conversationId = input.fence.conversationId ?? input.fence.nativeSessionId;
|
|
3864
|
+
const activationId = input.fence.activationId ?? input.fence.launchId;
|
|
3865
|
+
if (sessions.providerBinding === null) {
|
|
3866
|
+
return bindTaskRoleProviderRuntime(sessions, createProviderRuntimeBinding({
|
|
3867
|
+
providerNamespace: input.fence.driverId,
|
|
3868
|
+
accountScope: input.fence.agentId,
|
|
3869
|
+
runId: sessions.inFlight.runId,
|
|
3870
|
+
conversationId,
|
|
3871
|
+
activationId,
|
|
3872
|
+
startedAt: sessions.inFlight.preparedAt
|
|
3873
|
+
}), now);
|
|
3874
|
+
}
|
|
3875
|
+
const current = currentProviderConversation(sessions.providerBinding);
|
|
3876
|
+
if (current.conversationId === conversationId) {
|
|
3877
|
+
const active = currentProviderActivation(sessions.providerBinding);
|
|
3878
|
+
if (active?.activationId === activationId)
|
|
3879
|
+
return sessions;
|
|
3880
|
+
if (active !== null) {
|
|
3881
|
+
throw new Error("Provider Conversation cannot start a second Activation while the current one is active.");
|
|
3882
|
+
}
|
|
3883
|
+
return updateTaskRoleProviderRuntime(sessions, startProviderActivation(sessions.providerBinding, {
|
|
3884
|
+
activationId,
|
|
3885
|
+
startedAt: input.observedAt ?? input.receivedAt
|
|
3886
|
+
}), now);
|
|
3887
|
+
}
|
|
3888
|
+
const turn = sessions.providerBinding.turn;
|
|
3889
|
+
const noUnsettledInputDelivery = turn === null
|
|
3890
|
+
|| ["completed", "failed", "cancelled", "rejected"].includes(turn.status);
|
|
3891
|
+
return updateTaskRoleProviderRuntime(sessions, supersedeProviderConversation(sessions.providerBinding, {
|
|
3892
|
+
conversationId,
|
|
3893
|
+
activationId,
|
|
3894
|
+
switchedAt: input.observedAt ?? input.receivedAt,
|
|
3895
|
+
noUnsettledInputDelivery
|
|
3896
|
+
}), now);
|
|
3897
|
+
}
|
|
3898
|
+
function rejectSubmittingProviderTurn(store, target, delivery, now, reason) {
|
|
3899
|
+
if (target.kind !== "role"
|
|
3900
|
+
|| delivery.executionRef.type !== "run"
|
|
3901
|
+
|| delivery.executionRef.taskId !== target.taskId)
|
|
3902
|
+
return;
|
|
3903
|
+
const sessions = store.getTaskRoleSessionSet(target.taskId, target.roleName);
|
|
3904
|
+
const binding = sessions?.providerBinding;
|
|
3905
|
+
if (sessions === null || sessions === undefined
|
|
3906
|
+
|| binding === null || binding === undefined
|
|
3907
|
+
|| binding.runId !== delivery.executionRef.id
|
|
3908
|
+
|| binding.turn?.attemptId !== delivery.attemptId
|
|
3909
|
+
|| (binding.turn.status !== "submitting"
|
|
3910
|
+
&& binding.turn.status !== "delivery-unknown"))
|
|
3911
|
+
return;
|
|
3912
|
+
store.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(sessions, rejectProviderTurn(binding, {
|
|
3913
|
+
attemptId: delivery.attemptId,
|
|
3914
|
+
rejectedAt: now.toISOString(),
|
|
3915
|
+
reason
|
|
3916
|
+
}), now));
|
|
3917
|
+
}
|
|
3918
|
+
function deferUnprovenProviderRecovery(store, run, roleName, reason, now) {
|
|
3919
|
+
if (run.providerRetry === undefined)
|
|
3920
|
+
return;
|
|
3921
|
+
const deferred = deferProviderRetry(run.providerRetry, now);
|
|
3922
|
+
if (deferred === null) {
|
|
3923
|
+
finalizeProviderRetryDeadline(store, run, reason, "native-resume-unproven", now);
|
|
3924
|
+
return;
|
|
3925
|
+
}
|
|
3926
|
+
store.saveAgentRun(withProviderRetry(run, deferred));
|
|
3927
|
+
store.saveEvent(run.taskId, createTaskEvent(store.nextEventId(run.taskId), run.taskId, "runtime.provider-recovery-attention", {
|
|
3928
|
+
runId: run.id,
|
|
3929
|
+
roleName,
|
|
3930
|
+
reason,
|
|
3931
|
+
nextAttemptAt: deferred.nextAttemptAt ?? ""
|
|
3932
|
+
}, now));
|
|
3933
|
+
enqueueWork(store, { kind: "operator" }, "provider-recovery-attention", now, [
|
|
3934
|
+
{ type: "task", id: run.taskId },
|
|
3935
|
+
{ type: "run", taskId: run.taskId, id: run.id }
|
|
3936
|
+
]);
|
|
3937
|
+
}
|
|
3938
|
+
function markSubmittingProviderTurnUnknown(store, target, delivery, now, reason) {
|
|
3939
|
+
if (target.kind !== "role"
|
|
3940
|
+
|| delivery.executionRef.type !== "run"
|
|
3941
|
+
|| delivery.executionRef.taskId !== target.taskId)
|
|
3942
|
+
return;
|
|
3943
|
+
const sessions = store.getTaskRoleSessionSet(target.taskId, target.roleName);
|
|
3944
|
+
const binding = sessions?.providerBinding;
|
|
3945
|
+
if (sessions === null || sessions === undefined
|
|
3946
|
+
|| binding === null || binding === undefined
|
|
3947
|
+
|| binding.runId !== delivery.executionRef.id
|
|
3948
|
+
|| binding.turn?.attemptId !== delivery.attemptId
|
|
3949
|
+
|| binding.turn.status !== "submitting")
|
|
3950
|
+
return;
|
|
3951
|
+
store.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(sessions, markProviderTurnDeliveryUnknown(binding, {
|
|
3952
|
+
attemptId: delivery.attemptId,
|
|
3953
|
+
observedAt: now.toISOString(),
|
|
3954
|
+
reason
|
|
3955
|
+
}), now));
|
|
3956
|
+
}
|
|
3957
|
+
function settleStructuredProviderTurn(sessions, turnId, status, now) {
|
|
3958
|
+
const binding = sessions.providerBinding;
|
|
3959
|
+
if (binding === null || binding.turn === null || binding.turn.turnId !== turnId) {
|
|
3960
|
+
return sessions;
|
|
3961
|
+
}
|
|
3962
|
+
if (["completed", "failed", "cancelled"].includes(binding.turn.status))
|
|
3963
|
+
return sessions;
|
|
3964
|
+
return updateTaskRoleProviderRuntime(sessions, settleProviderTurn(binding, {
|
|
3965
|
+
turnId,
|
|
3966
|
+
status,
|
|
3967
|
+
settledAt: now.toISOString()
|
|
3968
|
+
}), now);
|
|
3969
|
+
}
|
|
3644
3970
|
function confirmedUsageActivityObservation(events, incoming) {
|
|
3645
3971
|
const usage = incoming.payload.usage;
|
|
3646
3972
|
if (incoming.kind !== "activity.observed" || usage === undefined)
|
|
@@ -3695,3 +4021,7 @@ function compareCanonicalObservationOrder(left, right) {
|
|
|
3695
4021
|
|| (left.ordinal ?? -1) - (right.ordinal ?? -1)
|
|
3696
4022
|
|| left.eventId.localeCompare(right.eventId);
|
|
3697
4023
|
}
|
|
4024
|
+
function configuredProviderRetryPolicy(store) {
|
|
4025
|
+
const config = providerRetryConfig(store.getConfig());
|
|
4026
|
+
return { delaysMs: config.delaysMs, maxWindowMs: config.maxWindowMs };
|
|
4027
|
+
}
|