@zq-silk/yui 0.15.7 → 0.15.8
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 +192 -399
- package/README.md +127 -1149
- package/dist/agent/adapterCatalog.js +15 -2
- package/dist/agent/agent.js +23 -3
- package/dist/agent/argumentPolicy.js +7 -1
- package/dist/agent/connectionPlan.js +62 -0
- package/dist/agent/executionComponents.js +158 -0
- package/dist/agent/launchEnvironment.js +31 -3
- package/dist/agent/managedRuntimeEnvironment.js +3 -5
- package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
- package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
- package/dist/brief/taskBrief.js +12 -0
- package/dist/cli/agentConfigurationPicker.js +13 -0
- package/dist/cli/commandCatalog.js +157 -70
- package/dist/cli/interactionCandidates.js +5 -5
- package/dist/cli/interactionPolicy.js +38 -8
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/managedDiagnostics.js +28 -0
- package/dist/cli/operatorWizard.js +1 -7
- package/dist/cli/roleOptionOrder.js +27 -0
- package/dist/cli/roleWizard.js +50 -14
- package/dist/cli/updateOrchestrator.js +1 -1
- package/dist/cli/updatePorts.js +3 -4
- package/dist/cli.js +178 -95
- package/dist/commands/agentCommands.js +72 -14
- package/dist/commands/capabilityCommands.js +9 -6
- package/dist/commands/configCommands.js +20 -20
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/executionAuditCommands.js +24 -24
- package/dist/commands/globalRoleCommands.js +1 -1
- package/dist/commands/grantCommands.js +4 -4
- package/dist/commands/operatorCommands.js +1 -7
- package/dist/commands/projectCommands.js +4 -4
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/roleConfiguration.js +25 -5
- package/dist/commands/roleRuntimeGuard.js +4 -5
- package/dist/commands/sessionCommands.js +3 -7
- package/dist/commands/taskActivationCommands.js +259 -0
- package/dist/commands/taskActor.js +28 -49
- package/dist/commands/taskCommands.js +1188 -710
- package/dist/commands/taskContextCommand.js +39 -583
- package/dist/commands/taskExecutionCommands.js +32 -32
- package/dist/commands/taskInputCommands.js +40 -104
- package/dist/commands/taskIntegrationCommands.js +3 -2
- package/dist/commands/taskIntegrationQueueCommands.js +1 -1
- package/dist/commands/taskNextActionCommand.js +8 -8
- package/dist/commands/taskOverviewCommand.js +33 -45
- package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
- package/dist/commands/taskRoleRuntimeStatus.js +133 -102
- package/dist/commands/telemetryCommands.js +36 -38
- package/dist/config/configCatalog.js +4 -4
- package/dist/config/yuiConfig.js +8 -8
- package/dist/context/contextSnapshot.js +10 -10
- package/dist/context/dispatchContext.js +11 -11
- package/dist/context/roleSessionContext.js +6 -3
- package/dist/context/{turnContextPack.js → runContextPack.js} +146 -81
- package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
- package/dist/context/sessionBootstrapManifest.js +21 -2
- package/dist/context/sourceRunContext.js +30 -0
- package/dist/context/taskContext.js +458 -0
- package/dist/context/wakeNotification.js +27 -27
- package/dist/controller/agentRuntimeObserver.js +21 -24
- package/dist/controller/capabilityBridge.js +17 -6
- package/dist/controller/clientRuntime.js +65 -92
- package/dist/controller/controller.js +114 -188
- package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
- package/dist/controller/jobControl.js +54 -85
- package/dist/controller/resourceInventory.js +8 -27
- package/dist/controller/resourceInventoryLinux.js +12 -13
- package/dist/controller/runtime.js +529 -479
- package/dist/controller/runtimeEventInbox.js +55 -25
- package/dist/controller/runtimeEventProcessor.js +22 -31
- package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
- package/dist/controller/runtimeLaunchCoordinator.js +80 -426
- package/dist/controller/runtimeObservationHook.js +14 -18
- package/dist/controller/sessionNotify.js +16 -24
- package/dist/controller/sessionOwnerReconciliation.js +168 -50
- package/dist/controller/structuredProviderObservation.js +138 -99
- package/dist/coordination/workMailbox.js +3 -3
- package/dist/coordination/workMailboxQueue.js +36 -33
- package/dist/core/boundedRpc.js +8 -1
- package/dist/core/controllerClient.js +20 -1
- package/dist/core/controllerServer.js +4 -4
- package/dist/doctor/doctor.js +13 -2
- package/dist/domain/agentResultTransport.js +9 -9
- package/dist/execution/codexThreadNaming.js +2 -8
- package/dist/execution/executionHealth.js +51 -63
- package/dist/execution/reviewMainRun.js +137 -0
- package/dist/execution/workItemExecution.js +28 -29
- package/dist/execution/workItemExecutionProjection.js +99 -107
- package/dist/execution/workItemMainRun.js +141 -0
- package/dist/executor/agentAdapter.js +227 -20
- package/dist/executor/agentConfigurationCatalog.js +126 -4
- package/dist/executor/agentConfigurationProbe.js +162 -4
- package/dist/executor/agentExecutor.js +79 -78
- package/dist/executor/effectiveLaunch.js +105 -18
- package/dist/executor/executorRegistry.js +29 -44
- package/dist/executor/fileRoleLaunchPlanner.js +229 -154
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +6 -3
- package/dist/input/inputRequest.js +12 -10
- package/dist/integration/gitIntegrationService.js +4 -11
- package/dist/integration/integrationQueueService.js +4 -4
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/kernel/builtinCapabilities.js +247 -12
- package/dist/kernel/capabilityRegistry.js +64 -18
- package/dist/kernel/instanceHost.js +12 -1
- package/dist/kernel/kernelPorts.js +2 -2
- package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
- package/dist/lifecycle/exactRunTerminalization.js +449 -0
- package/dist/message/message.js +62 -6
- package/dist/message/messageContinuation.js +204 -0
- package/dist/observability/executionAudit.js +70 -72
- package/dist/observability/faultClassification.js +2 -2
- package/dist/observability/orchestrationMetrics.js +8 -8
- package/dist/operator/operatorSessionHistory.js +1 -7
- package/dist/output/agentConfigurationPresentation.js +8 -3
- package/dist/output/agentRunConfigurationPresentation.js +128 -0
- package/dist/output/rolePresentation.js +54 -3
- package/dist/plugins/pluginChild.js +104 -0
- package/dist/plugins/pluginIntent.js +26 -0
- package/dist/plugins/pluginInterpreter.js +43 -0
- package/dist/plugins/pluginPackage.js +101 -0
- package/dist/plugins/pluginProcess.js +112 -0
- package/dist/plugins/pluginService.js +380 -0
- package/dist/profile/agentProfile.js +1 -1
- package/dist/repository/gitWorkspace.js +26 -4
- package/dist/repository/project.js +19 -4
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +20 -27
- package/dist/repository/taskWorkspacePreparer.js +344 -83
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +3 -3
- package/dist/resources/projectResource.js +123 -0
- package/dist/resources/projectResourceService.js +421 -0
- package/dist/resources/resourceDiscovery.js +6 -6
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/resourceRegistrar.js +1 -1
- package/dist/resources/resourceTypes.js +1 -1
- package/dist/review/deltaRecheck.js +3 -3
- package/dist/review/reviewAcceptance.js +16 -16
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewRound.js +21 -20
- package/dist/review/reviewerAvailability.js +2 -2
- package/dist/role/role.js +51 -7
- package/dist/role/taskRoleUpdate.js +30 -0
- package/dist/runtime/acpProtocol.js +425 -0
- package/dist/runtime/acpSession.js +731 -0
- package/dist/runtime/acpSessionConfiguration.js +260 -0
- package/dist/runtime/agentDriver.js +30 -11
- package/dist/runtime/agentEndpoint.js +278 -0
- package/dist/runtime/agentEndpointIdentity.js +86 -0
- package/dist/runtime/agentEndpointOwnership.js +239 -0
- package/dist/runtime/agentError.js +2 -10
- package/dist/runtime/agentHost.js +565 -314
- package/dist/runtime/agentRunConfiguration.js +258 -0
- package/dist/runtime/builtinAgentDrivers.js +134 -18
- package/dist/runtime/builtinAgentErrorMappers.js +55 -3
- package/dist/runtime/builtinTranscriptUsage.js +1 -1
- package/dist/runtime/claude-process-owner +0 -0
- package/dist/runtime/codexAppServerRuntime.js +38 -30
- package/dist/runtime/codexInteractiveHost.js +41 -6
- package/dist/runtime/continuationManager.js +2 -6
- package/dist/runtime/executionEnvironment.js +30 -0
- package/dist/runtime/firstProgressAdvisory.js +11 -11
- package/dist/runtime/index.js +4 -3
- package/dist/runtime/jsonLineChannel.js +109 -0
- package/dist/runtime/launchBroker.js +91 -16
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +10 -18
- package/dist/runtime/managedCaller.js +61 -17
- package/dist/runtime/nativeSessionControl.js +102 -0
- package/dist/runtime/ports.js +6 -21
- package/dist/runtime/processExitObservation.js +8 -7
- package/dist/runtime/promptEnvelope.js +17 -6
- package/dist/runtime/providerContinuation.js +3 -9
- package/dist/runtime/providerContinuationReconciliationService.js +4 -13
- package/dist/runtime/providerControl.js +2 -7
- package/dist/runtime/providerRuntimeIdentity.js +110 -222
- package/dist/runtime/providerRuntimeReconciler.js +5 -9
- package/dist/runtime/runtimeBinding.js +0 -1
- package/dist/runtime/runtimeContinuationProjection.js +4 -7
- package/dist/runtime/runtimeDeadlines.js +9 -0
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +29 -65
- package/dist/runtime/runtimeProjection.js +43 -51
- package/dist/runtime/runtimeSessionCandidate.js +1 -3
- package/dist/runtime/sessionLaunchRequest.js +3 -7
- package/dist/runtime/sessionOwnerIdentity.js +7 -54
- package/dist/runtime/sessionOwnerRegistry.js +22 -17
- package/dist/runtime/sessionReconciliation.js +4 -8
- package/dist/runtime/sessionTerminationGuard.js +70 -259
- package/dist/runtime/sessionTokenMetrics.js +5 -16
- package/dist/runtime/structuredProviderHost.js +237 -117
- package/dist/runtime/taskRuntimeIsolation.js +39 -122
- package/dist/runtime/tmuxAdapters.js +39 -86
- package/dist/scheduler/activeRoleRunDelivery.js +354 -0
- package/dist/scheduler/leaderWakeupProcessor.js +75 -266
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +80 -9
- package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
- package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
- package/dist/scheduler/taskExecutionProjection.js +120 -124
- package/dist/scheduler/taskObservabilityProjection.js +29 -29
- package/dist/scheduler/taskWake.js +11 -4
- package/dist/scheduler/wakeReason.js +9 -1
- package/dist/setup/setupCommand.js +1 -0
- package/dist/storage/migrations/agentRunContract.js +159 -0
- package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
- package/dist/storage/sqliteSchema.js +431 -5
- package/dist/storage/sqliteStore.js +375 -220
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +10 -5
- package/dist/storage/taskStore.js +13 -11
- package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
- package/dist/surface/surfaceContributions.js +102 -0
- package/dist/task/completionReadiness.js +32 -6
- package/dist/task/deliveryGuard.js +16 -16
- package/dist/task/draftPlan.js +72 -12
- package/dist/task/nextAction.js +144 -128
- package/dist/task/remoteDelivery.js +6 -6
- package/dist/task/task.js +184 -18
- package/dist/task/taskActivation.js +301 -0
- package/dist/task/taskActivationService.js +392 -0
- package/dist/task/taskRecordReference.js +5 -4
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/telemetry/sqliteTelemetryStore.js +55 -68
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +2 -2
- package/dist/web/assets/assetManifest.js +2 -0
- package/dist/web/assets/client/app.js +120 -20
- package/dist/web/assets/client/components.js +87 -54
- package/dist/web/assets/client/i18n.js +83 -41
- package/dist/web/assets/client/markdown.js +1 -1
- package/dist/web/assets/client/taskSurface.js +353 -0
- package/dist/web/assets/client/view.js +49 -44
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +22 -4
- package/dist/web/controllerWeb.js +60 -0
- package/dist/web/webMutation.js +28 -0
- package/dist/web/webServer.js +118 -8
- package/dist/web/webSnapshot.js +81 -74
- package/dist/web/webTaskSurface.js +64 -0
- package/dist/workItem/dependencyGate.js +1 -1
- package/dist/workItem/workItem.js +80 -48
- package/dist/workspace/workItemChangeSetManager.js +16 -9
- package/docs/agent-result-consumption.md +94 -0
- package/docs/agent-runtime-drivers.md +91 -0
- package/docs/architecture/README.md +38 -0
- package/docs/architecture/capabilities-and-resources.md +79 -0
- package/docs/managed-turn-and-session-runtime.md +222 -0
- package/docs/observability/README.md +81 -0
- package/docs/plugin-sdk.md +290 -0
- package/docs/provider-runtime.md +163 -0
- package/docs/release-workflow.md +303 -0
- package/docs/roles-and-configuration.md +113 -0
- package/docs/sqlite-control-plane-design.md +76 -0
- package/docs/task-dag-semantics.md +57 -0
- package/docs/task-delivery.md +103 -0
- package/docs/task-local-identity.md +6 -6
- package/docs/testing/verification-levels.md +86 -0
- package/i18n/README.zh-CN.md +98 -739
- package/package.json +2 -2
- package/skills/yui-leader/SKILL.md +130 -103
- package/skills/yui-leader/references/integration.md +39 -0
- package/skills/yui-leader/references/replicated-execution.md +42 -0
- package/skills/yui-leader/references/task-plugins.md +33 -0
- package/skills/yui-operator/SKILL.md +30 -59
- package/skills/yui-reviewer/SKILL.md +35 -36
- package/skills/yui-runtime/SKILL.md +88 -24
- package/skills/yui-runtime/references/publication.md +22 -0
- package/skills/yui-runtime/references/recovery.md +64 -0
- package/skills/yui-worker/SKILL.md +37 -39
- package/dist/cli/roleOptionCatalog.js +0 -68
- package/dist/context/sourceTurnContext.js +0 -30
- package/dist/execution/reviewMainTurn.js +0 -161
- package/dist/execution/workItemMainTurn.js +0 -164
- package/dist/lifecycle/exactTurnTerminalization.js +0 -407
- package/dist/runtime/preallocatedNativeSession.js +0 -13
- package/dist/runtime/runtimeStopReceipt.js +0 -42
- package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { reconciliationIntervalMilliseconds } from "../config/yuiConfig.js";
|
|
2
|
-
import { LEADER_WAKE_AGGREGATION_MS,
|
|
2
|
+
import { LEADER_WAKE_AGGREGATION_MS, processLeaderWakeups } from "../scheduler/leaderWakeupProcessor.js";
|
|
3
3
|
import { pendingWakeupsMatch } from "../scheduler/pendingWakeup.js";
|
|
4
|
-
import {
|
|
4
|
+
import { processActiveRoleRunDeliveries } from "../scheduler/activeRoleRunDelivery.js";
|
|
5
5
|
import { selectedActiveSchedulerTasks } from "../scheduler/ports.js";
|
|
6
|
-
import {
|
|
7
|
-
import { DEFAULT_STALL_WINDOW_MS, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS,
|
|
6
|
+
import { reconcileExitedRoleRuns } from "../scheduler/roleRunLiveness.js";
|
|
7
|
+
import { DEFAULT_STALL_WINDOW_MS, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, reconcileStalledRoleRuns } from "../scheduler/roleRunStall.js";
|
|
8
8
|
import { processOperatorInputNotifications } from "../scheduler/operatorInputNotificationProcessor.js";
|
|
9
9
|
import { startControllerServer } from "../core/controllerServer.js";
|
|
10
10
|
import { monotonicMilliseconds } from "../core/controllerTelemetry.js";
|
|
@@ -14,7 +14,7 @@ import { KeyedWorkQueue } from "../coordination/keyedWorkQueue.js";
|
|
|
14
14
|
import { MailboxScheduler } from "../coordination/mailboxScheduler.js";
|
|
15
15
|
import { nearestDeadlineBatch } from "../coordination/deadlineScheduler.js";
|
|
16
16
|
import { mailboxHasWork, nextPendingBatch } from "../coordination/workMailbox.js";
|
|
17
|
-
import { hasRuntimeCleanupObligation
|
|
17
|
+
import { hasRuntimeCleanupObligation } from "../runtime/lifecycleReservation.js";
|
|
18
18
|
import { formatTaskRecordReference } from "../task/taskRecordReference.js";
|
|
19
19
|
import { parseDurableJobAcknowledgeParams, parseDurableJobCancelParams, parseDurableJobRefParams, parseDurableJobStartParams } from "./jobControl.js";
|
|
20
20
|
const DEFAULT_RECONCILIATION_INTERVAL_MS = reconciliationIntervalMilliseconds();
|
|
@@ -26,7 +26,6 @@ const DEFAULT_DELIVERY_TIMEOUT_MS = 120_000;
|
|
|
26
26
|
const DEFAULT_TASK_ORCHESTRATION_RETRY_LIMIT = 2;
|
|
27
27
|
const DEFAULT_TASK_CONCURRENCY = 4;
|
|
28
28
|
const MAX_TASK_CONCURRENCY = 32;
|
|
29
|
-
const RUNTIME_RESERVATION_RECOVERY_AGE_MS = 120_000;
|
|
30
29
|
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
31
30
|
const CONTROLLER_LATENCY_BUCKETS_MS = [10, 50, 100, 250, 500, 1_000, 3_000];
|
|
32
31
|
class RuntimeEventApplyError extends AggregateError {
|
|
@@ -45,7 +44,7 @@ const ZERO_DRAIN_METRICS = Object.freeze({
|
|
|
45
44
|
* Runs one lean scheduler pass. Due native Turn completions are folded before
|
|
46
45
|
* liveness, so a valid Hook boundary fences destructive process reconciliation.
|
|
47
46
|
*/
|
|
48
|
-
export async function runControllerSchedulerPass(store, delivery, now, workspacePreparer, scope = { kind: "full" }, includeOperator = true, runtimeCleanupOutcomes = [], lifecycleHost, stallWindowMs = DEFAULT_STALL_WINDOW_MS, maintenanceFence, onMaintenanceFenceDefer, blockedTaskIds = new Set(), diagnosticAfterMs = DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, leaderWakeFence) {
|
|
47
|
+
export async function runControllerSchedulerPass(store, delivery, now, workspacePreparer, scope = { kind: "full" }, includeOperator = true, runtimeCleanupOutcomes = [], lifecycleHost, stallWindowMs = DEFAULT_STALL_WINDOW_MS, maintenanceFence, onMaintenanceFenceDefer, blockedTaskIds = new Set(), diagnosticAfterMs = DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, leaderWakeFence, onError) {
|
|
49
48
|
const compiledSelection = compileReconcileSelection(scope);
|
|
50
49
|
const selection = includeOperator
|
|
51
50
|
? { ...compiledSelection, blockedTaskIds }
|
|
@@ -54,12 +53,7 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
54
53
|
// control sockets when several scheduler phases repeat it in one native
|
|
55
54
|
// event-loop turn. Give already-written requests a poll boundary before the
|
|
56
55
|
// next durable phase; later phases retain their existing CAS fences.
|
|
57
|
-
await
|
|
58
|
-
// A dormant Session may still name a Host that disappeared after its last
|
|
59
|
-
// Provider Turn. Detach that disposable Host before claiming the next Turn,
|
|
60
|
-
// so retained Agent intent restores the same Session instead of first
|
|
61
|
-
// connecting to a known-dead control socket.
|
|
62
|
-
await reconcileDormantRuntimeOwners(store, delivery, lifecycleHost, scope, now, blockedTaskIds);
|
|
56
|
+
await controlEventLoopRun();
|
|
63
57
|
const failedCleanupRoles = await processSelectedRoleRuntimeCleanups(store, delivery, lifecycleHost, scope, now, runtimeCleanupOutcomes, blockedTaskIds);
|
|
64
58
|
const roleSelection = selectionWithoutFailedCleanupRoles(store, selection, failedCleanupRoles);
|
|
65
59
|
const availableWakeupSelection = () => (leaderWakeFence?.() === true
|
|
@@ -74,13 +68,18 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
74
68
|
const initialWakeupResults = await processLeaderWakeups(store, delivery, now, exactTaskSelection(new Set(initialWakeups.keys())));
|
|
75
69
|
// Preserve ready-Leader-first ordering, then bound the repeated state
|
|
76
70
|
// projections that follow it in this pass.
|
|
77
|
-
await
|
|
71
|
+
await controlEventLoopRun();
|
|
72
|
+
// A Task whose deferred activation was just released must become active
|
|
73
|
+
// before the workspace phase, so its first workspace preparation happens in
|
|
74
|
+
// this same pass rather than waiting for the next one.
|
|
75
|
+
await adoptReleasedTaskActivations(store, workspacePreparer, selection, onError);
|
|
76
|
+
await controlEventLoopRun();
|
|
78
77
|
const workspacePreparation = await prepareActiveWorkspaces(store, workspacePreparer, selection, maintenanceFence, onMaintenanceFenceDefer);
|
|
79
|
-
await
|
|
80
|
-
const
|
|
81
|
-
await
|
|
82
|
-
const
|
|
83
|
-
? [formatTaskRecordReference(result.taskId, result.
|
|
78
|
+
await controlEventLoopRun();
|
|
79
|
+
const activeRunDeliveries = await processActiveRoleRunDeliveries(store, delivery, now, roleSelection);
|
|
80
|
+
await controlEventLoopRun();
|
|
81
|
+
const unsettledRunRefs = new Set(activeRunDeliveries.flatMap((result) => (result.reason === "delivery-uncertain"
|
|
82
|
+
? [formatTaskRecordReference(result.taskId, result.runId, "run")]
|
|
84
83
|
: [])));
|
|
85
84
|
// Every successful Task has completed the targeted phases owned by its
|
|
86
85
|
// mailbox at this boundary. Settle that exact claim before advisory
|
|
@@ -92,28 +91,27 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
92
91
|
}
|
|
93
92
|
}
|
|
94
93
|
const newlyIdleBusyTaskIds = new Set(initialWakeupResults.flatMap((result) => (result.reason === "busy"
|
|
95
|
-
&& store.
|
|
94
|
+
&& store.getActiveRun(result.taskId, "leader") === null
|
|
96
95
|
? [result.taskId]
|
|
97
96
|
: [])));
|
|
98
|
-
// Phase-one Leader
|
|
99
|
-
// Keep every newly claimed
|
|
100
|
-
// a later pass can observe its stable provider/runtime
|
|
97
|
+
// Phase-one Leader AgentRuns did not exist at the pass's liveness boundary.
|
|
98
|
+
// Keep every newly claimed AgentRun outside destructive absence decisions until
|
|
99
|
+
// a later pass can observe its stable provider/runtime.
|
|
101
100
|
for (const result of initialWakeupResults) {
|
|
102
|
-
if (result.
|
|
103
|
-
&& store.
|
|
104
|
-
|
|
101
|
+
if (result.runId !== undefined
|
|
102
|
+
&& store.getActiveRun(result.taskId, "leader")?.id === result.runId) {
|
|
103
|
+
unsettledRunRefs.add(formatTaskRecordReference(result.taskId, result.runId, "run"));
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
106
|
// Let socket callbacks queued during the bounded scheduler phases run
|
|
108
107
|
// before starting a potentially large liveness inventory.
|
|
109
|
-
await
|
|
108
|
+
await controlEventLoopRun();
|
|
110
109
|
const liveStatuses = new Map();
|
|
111
110
|
const resourceEvidence = new Map();
|
|
112
|
-
const
|
|
113
|
-
await
|
|
114
|
-
await
|
|
115
|
-
await
|
|
116
|
-
await reconcileDormantRuntimeOwners(store, delivery, lifecycleHost, scope, now, selection.blockedTaskIds);
|
|
111
|
+
const failedRunRefs = await reconcileExitedRoleRuns(store, delivery, now, roleSelection, unsettledRunRefs, liveStatuses, resourceEvidence, scope.kind === "dirty");
|
|
112
|
+
await controlEventLoopRun();
|
|
113
|
+
await reconcileStalledRoleRuns(store, delivery, now, roleSelection, stallWindowMs, liveStatuses, resourceEvidence, diagnosticAfterMs);
|
|
114
|
+
await controlEventLoopRun();
|
|
117
115
|
const selectedInputTaskIds = selectedTaskIdsForBoundedPass(store, selection);
|
|
118
116
|
const autoResolvedInputs = selectedInputTaskIds === undefined
|
|
119
117
|
? store.resolveExpiredInputRecommendations(now)
|
|
@@ -148,8 +146,8 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
148
146
|
? await processOperatorInputNotifications(store, delivery, selection, now)
|
|
149
147
|
: [];
|
|
150
148
|
return {
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
activeRunDeliveries,
|
|
150
|
+
failedRunRefs,
|
|
153
151
|
wakeups: mergeWakeupPhaseResults(initialWakeupResults, laterWakeups),
|
|
154
152
|
inputNotifications,
|
|
155
153
|
autoResolvedInputs
|
|
@@ -218,34 +216,6 @@ async function processSelectedRoleRuntimeCleanups(store, delivery, lifecycleHost
|
|
|
218
216
|
if (!await lifecycleHost.stopOwner(owner)) {
|
|
219
217
|
throw new Error(`Role runtime cleanup could not confirm the host stopped: ${runtimeOwnerLabel(owner)}.`);
|
|
220
218
|
}
|
|
221
|
-
if (target.kind === "role-runtime") {
|
|
222
|
-
const session = store.getRoleSession(target.taskId, target.roleName);
|
|
223
|
-
const reservedRuntimeGenerationId = isRuntimeLaunchReservation(mailbox.processing)
|
|
224
|
-
? mailbox.processing.batchId
|
|
225
|
-
: undefined;
|
|
226
|
-
// A failed fresh-Conversation launch can leave two exact resource
|
|
227
|
-
// generations: the detached Session's last committed launch and the
|
|
228
|
-
// replacement reservation. They are not competing authorities. The
|
|
229
|
-
// owner-wide stop has already proven physical zero, so clean both
|
|
230
|
-
// exact launch roots idempotently before settling the mailbox.
|
|
231
|
-
const runtimeGenerationIds = new Set([
|
|
232
|
-
reservedRuntimeGenerationId,
|
|
233
|
-
session?.runtimeGenerationId
|
|
234
|
-
].filter((runtimeGenerationId) => runtimeGenerationId !== undefined));
|
|
235
|
-
if (lifecycleHost.cleanupTaskLaunch !== undefined) {
|
|
236
|
-
const task = store.getTask(target.taskId);
|
|
237
|
-
const reason = task?.status === "completed"
|
|
238
|
-
? "completion"
|
|
239
|
-
: "interruption";
|
|
240
|
-
for (const runtimeGenerationId of runtimeGenerationIds) {
|
|
241
|
-
lifecycleHost.cleanupTaskLaunch({
|
|
242
|
-
taskId: target.taskId,
|
|
243
|
-
runtimeGenerationId,
|
|
244
|
-
reason
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
219
|
if (store.completeRuntimeCleanup === undefined
|
|
250
220
|
|| !store.completeRuntimeCleanup(target, now)) {
|
|
251
221
|
throw new Error(`Role runtime cleanup mailbox changed: ${runtimeOwnerLabel(owner)}.`);
|
|
@@ -259,95 +229,9 @@ async function processSelectedRoleRuntimeCleanups(store, delivery, lifecycleHost
|
|
|
259
229
|
}
|
|
260
230
|
continue;
|
|
261
231
|
}
|
|
262
|
-
const reservation = mailbox.processing;
|
|
263
|
-
if (reservation === null
|
|
264
|
-
|| !isRuntimeLaunchReservation(reservation)
|
|
265
|
-
|| now.getTime() - Date.parse(reservation.startedAt)
|
|
266
|
-
< RUNTIME_RESERVATION_RECOVERY_AGE_MS) {
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
if (lifecycleHost === undefined) {
|
|
271
|
-
throw new Error("Role runtime reservation inspection is unavailable.");
|
|
272
|
-
}
|
|
273
|
-
const inspection = await lifecycleHost.inspectOwner(owner);
|
|
274
|
-
if (inspection.state === "running" || inspection.state === "starting") {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (inspection.state === "unavailable") {
|
|
278
|
-
throw new Error(`Role runtime reservation could not inspect the host: ${runtimeOwnerLabel(owner)}.`);
|
|
279
|
-
}
|
|
280
|
-
const completed = store.completeStoppedRuntimeReservation === undefined
|
|
281
|
-
? store.completeWorkMailbox(target, reservation.batchId)
|
|
282
|
-
: store.completeStoppedRuntimeReservation(target, reservation.batchId, now);
|
|
283
|
-
if (!completed) {
|
|
284
|
-
throw new Error(`Role runtime reservation mailbox changed: ${runtimeOwnerLabel(owner)}.`);
|
|
285
|
-
}
|
|
286
|
-
forgetPreparedRuntimeOwner(delivery, owner);
|
|
287
|
-
outcomes.push({ target, batchId, status: "completed" });
|
|
288
|
-
}
|
|
289
|
-
catch (error) {
|
|
290
|
-
markFailedRuntimeTarget(failedRoles, target);
|
|
291
|
-
outcomes.push({ target, batchId, status: "failed", error });
|
|
292
|
-
}
|
|
293
232
|
}
|
|
294
233
|
return failedRoles;
|
|
295
234
|
}
|
|
296
|
-
async function reconcileDormantRuntimeOwners(store, delivery, lifecycleHost, scope, now, blockedTaskIds = new Set()) {
|
|
297
|
-
if (lifecycleHost === undefined
|
|
298
|
-
|| store.listDormantRuntimeOwners === undefined) {
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
const selectedOwners = scope.kind === "full"
|
|
302
|
-
? undefined
|
|
303
|
-
: new Set(selectedRuntimeLifecycleTargets(store, scope, blockedTaskIds)
|
|
304
|
-
.map((target) => runtimeOwnerIdentity(runtimeOwner(target))));
|
|
305
|
-
const candidates = store.listDormantRuntimeOwners().filter((candidate) => ((candidate.owner.scope !== "task"
|
|
306
|
-
|| !blockedTaskIds.has(candidate.owner.taskId))
|
|
307
|
-
&& (selectedOwners === undefined
|
|
308
|
-
|| selectedOwners.has(runtimeOwnerIdentity(candidate.owner)))));
|
|
309
|
-
if (candidates.length === 0)
|
|
310
|
-
return;
|
|
311
|
-
const owners = candidates.map((candidate) => candidate.owner);
|
|
312
|
-
let inspections;
|
|
313
|
-
try {
|
|
314
|
-
inspections = lifecycleHost.inspectOwners === undefined
|
|
315
|
-
? await Promise.all(owners.map(async (owner) => ({
|
|
316
|
-
owner,
|
|
317
|
-
inspection: await lifecycleHost.inspectOwner(owner)
|
|
318
|
-
})))
|
|
319
|
-
: await lifecycleHost.inspectOwners(owners);
|
|
320
|
-
}
|
|
321
|
-
catch {
|
|
322
|
-
// Host inventory is an advisory safety scan. Unknown state must never
|
|
323
|
-
// mutate persisted session facts; the next full pass will retry.
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
const requested = new Set(owners.map(runtimeOwnerIdentity));
|
|
327
|
-
const byOwner = new Map();
|
|
328
|
-
for (const result of inspections) {
|
|
329
|
-
const identity = runtimeOwnerIdentity(result.owner);
|
|
330
|
-
if (!requested.has(identity)
|
|
331
|
-
|| byOwner.has(identity)) {
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
byOwner.set(identity, result.inspection);
|
|
335
|
-
}
|
|
336
|
-
if (byOwner.size !== requested.size)
|
|
337
|
-
return;
|
|
338
|
-
for (const candidate of candidates) {
|
|
339
|
-
if (byOwner.get(runtimeOwnerIdentity(candidate.owner))?.state
|
|
340
|
-
=== "stopped") {
|
|
341
|
-
if (candidate.runtimeGenerationId !== undefined) {
|
|
342
|
-
// The exact launch-owned resources must settle through the durable
|
|
343
|
-
// cleanup lane before its Host fact is detached. The resumable Session
|
|
344
|
-
// remains active; the candidate is the CAS fence against a concurrent
|
|
345
|
-
// Hook or replacement launch.
|
|
346
|
-
store.enqueueRuntimeHostDetach?.(candidate.owner, now, candidate);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
235
|
function forgetPreparedRuntimeOwner(delivery, owner) {
|
|
352
236
|
if (owner.scope !== "task")
|
|
353
237
|
return;
|
|
@@ -356,11 +240,6 @@ function forgetPreparedRuntimeOwner(delivery, owner) {
|
|
|
356
240
|
roleName: owner.roleName
|
|
357
241
|
});
|
|
358
242
|
}
|
|
359
|
-
function runtimeOwnerIdentity(owner) {
|
|
360
|
-
return owner.scope === "task"
|
|
361
|
-
? `task\0${owner.taskId}\0${owner.roleName}`
|
|
362
|
-
: `global\0${owner.roleName}`;
|
|
363
|
-
}
|
|
364
243
|
function selectedTaskIdsForBoundedPass(store, selection) {
|
|
365
244
|
if (!selection.full) {
|
|
366
245
|
if ((selection.blockedTaskIds?.size ?? 0) === 0)
|
|
@@ -575,6 +454,62 @@ export function compileReconcileSelection(scope) {
|
|
|
575
454
|
blockedTaskIds: new Set()
|
|
576
455
|
};
|
|
577
456
|
}
|
|
457
|
+
/**
|
|
458
|
+
* Adopts activation requests whose deferral has been released.
|
|
459
|
+
*
|
|
460
|
+
* The deferral is only ever released by the planning Turn ending, so this phase
|
|
461
|
+
* re-reads the request instead of trusting the signal that woke it: a request
|
|
462
|
+
* cancelled, or a Task retired or stopped, while the Turn was still running is
|
|
463
|
+
* left alone rather than replayed as historical intent. Adoption itself belongs
|
|
464
|
+
* to the preparer's single activation boundary, so status and environment facts
|
|
465
|
+
* still commit together, and a failure here leaves a continuable Draft.
|
|
466
|
+
*
|
|
467
|
+
* Full reconciliation resolves the candidates from the durable pending-request
|
|
468
|
+
* projection rather than from dirty keys. A Controller that restarts after the
|
|
469
|
+
* releasing signal was enqueued has no dirty key for it, and the startup pass
|
|
470
|
+
* claims and completes that Task's mailbox — so without the projection a
|
|
471
|
+
* released request would wait for unrelated traffic on the Task.
|
|
472
|
+
*/
|
|
473
|
+
async function adoptReleasedTaskActivations(store, workspace, selection, onError) {
|
|
474
|
+
if (workspace === undefined)
|
|
475
|
+
return;
|
|
476
|
+
const candidates = selection.full
|
|
477
|
+
? (store.listPendingActivationRequestTaskIds?.()
|
|
478
|
+
?? store.listTasks().flatMap((task) => (task.status === "draft" && task.activationRequest?.disposition === "pending"
|
|
479
|
+
? [task.id]
|
|
480
|
+
: [])))
|
|
481
|
+
: selection.taskIds;
|
|
482
|
+
for (const taskId of candidates) {
|
|
483
|
+
if (selection.blockedTaskIds?.has(taskId))
|
|
484
|
+
continue;
|
|
485
|
+
const task = store.getTask(taskId);
|
|
486
|
+
if (task?.status !== "draft" || task.executionGate.state !== "enabled")
|
|
487
|
+
continue;
|
|
488
|
+
const request = task.activationRequest;
|
|
489
|
+
if (request?.disposition !== "pending")
|
|
490
|
+
continue;
|
|
491
|
+
if (request.startMode !== "after-planning-turn"
|
|
492
|
+
&& request.operation.actorId !== `task:${taskId}/role:leader`)
|
|
493
|
+
continue;
|
|
494
|
+
// Later Draft discussion is a Session notification, not another AgentRun.
|
|
495
|
+
// Its durable activation intent is sufficient once the exact native input
|
|
496
|
+
// is settled. Never create a synthetic Run merely to release that intent.
|
|
497
|
+
if (store.getActiveRun(taskId, "leader") !== null)
|
|
498
|
+
continue;
|
|
499
|
+
const provider = store.getTaskRoleSessionSet?.(taskId, "leader")?.providerBinding;
|
|
500
|
+
if (provider?.run != null
|
|
501
|
+
&& ["submitting", "accepted", "delivery-unknown"].includes(provider.run.status))
|
|
502
|
+
continue;
|
|
503
|
+
try {
|
|
504
|
+
await workspace.activateTaskWorkspace(taskId);
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
// Activation failure is durable Task state, not a Controller fault: the
|
|
508
|
+
// request records it and the Draft stays continuable.
|
|
509
|
+
onError?.(error);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
578
513
|
async function prepareActiveWorkspaces(store, workspace, selection, maintenanceFence, onMaintenanceFenceDefer) {
|
|
579
514
|
if (workspace === undefined)
|
|
580
515
|
return { failed: new Set(), ready: new Set() };
|
|
@@ -689,8 +624,8 @@ function partitionDirtyScope(keys) {
|
|
|
689
624
|
}
|
|
690
625
|
function emptyControllerSchedulerResult() {
|
|
691
626
|
return {
|
|
692
|
-
|
|
693
|
-
|
|
627
|
+
activeRunDeliveries: [],
|
|
628
|
+
failedRunRefs: [],
|
|
694
629
|
wakeups: [],
|
|
695
630
|
inputNotifications: [],
|
|
696
631
|
autoResolvedInputs: []
|
|
@@ -707,8 +642,8 @@ function runtimeTaskFailureIds(result) {
|
|
|
707
642
|
}
|
|
708
643
|
function mergeControllerSchedulerResults(results) {
|
|
709
644
|
return {
|
|
710
|
-
|
|
711
|
-
|
|
645
|
+
activeRunDeliveries: results.flatMap((result) => result.activeRunDeliveries),
|
|
646
|
+
failedRunRefs: results.flatMap((result) => result.failedRunRefs),
|
|
712
647
|
wakeups: results.flatMap((result) => result.wakeups),
|
|
713
648
|
inputNotifications: results.flatMap((result) => result.inputNotifications),
|
|
714
649
|
autoResolvedInputs: results.flatMap((result) => result.autoResolvedInputs)
|
|
@@ -791,8 +726,8 @@ export class FileTaskController {
|
|
|
791
726
|
: this.#deliveryRetryLimit;
|
|
792
727
|
this.#taskOrchestrationRetryLimit = positiveInteger(options.taskOrchestrationRetryLimit, DEFAULT_TASK_ORCHESTRATION_RETRY_LIMIT, "Controller Task orchestration retry limit");
|
|
793
728
|
this.#taskConcurrency = boundedPositiveInteger(options.taskConcurrency, DEFAULT_TASK_CONCURRENCY, MAX_TASK_CONCURRENCY, "Controller Task concurrency");
|
|
794
|
-
this.#stallWindowMs = positiveInteger(options.stallWindowMs, DEFAULT_STALL_WINDOW_MS, "Controller
|
|
795
|
-
this.#diagnosticAfterMs = positiveInteger(options.diagnosticAfterMs, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, "Controller
|
|
729
|
+
this.#stallWindowMs = positiveInteger(options.stallWindowMs, DEFAULT_STALL_WINDOW_MS, "Controller AgentRun stall window");
|
|
730
|
+
this.#diagnosticAfterMs = positiveInteger(options.diagnosticAfterMs, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS, "Controller AgentRun diagnostic threshold");
|
|
796
731
|
this.#runtimeEventProcessor = options.runtimeEventProcessor;
|
|
797
732
|
this.#runtimeObserver = options.runtimeObserver;
|
|
798
733
|
this.#runtimeObserverIntervalMs = positiveInteger(options.runtimeObserverIntervalMs, DEFAULT_RUNTIME_OBSERVER_INTERVAL_MS, "Controller runtime observer interval");
|
|
@@ -1050,7 +985,7 @@ export class FileTaskController {
|
|
|
1050
985
|
}
|
|
1051
986
|
// Detached reconciliation is deliberately confined to the low-rate
|
|
1052
987
|
// full pass. It queries only identities already present in Task
|
|
1053
|
-
// facts and cannot start a model
|
|
988
|
+
// facts and cannot start a model AgentRun or scan unknown children.
|
|
1054
989
|
if (scope.kind === "full" && this.#continuationReconciler !== undefined) {
|
|
1055
990
|
await this.#continuationReconciler.reconcile(this.#now());
|
|
1056
991
|
}
|
|
@@ -1059,7 +994,7 @@ export class FileTaskController {
|
|
|
1059
994
|
// processes Leader wakeups.
|
|
1060
995
|
this.#jobSupervisor?.reconcile(this.#now());
|
|
1061
996
|
if (scope.kind === "full") {
|
|
1062
|
-
result = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, scope, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, runtimeFailedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence);
|
|
997
|
+
result = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, scope, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, runtimeFailedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence, this.#onError);
|
|
1063
998
|
}
|
|
1064
999
|
else {
|
|
1065
1000
|
const dirtyPass = await this.#runDirtySchedulerPass(scope, runtimeCleanupOutcomes, runtimeFailedTaskIds);
|
|
@@ -1144,7 +1079,7 @@ export class FileTaskController {
|
|
|
1144
1079
|
if (this.#pendingFull || this.#pendingKeys.size > 0 || pendingRuntimeDrain) {
|
|
1145
1080
|
// A continuous Hook signal stream must yield to socket callbacks
|
|
1146
1081
|
// between bounded scheduler passes.
|
|
1147
|
-
await
|
|
1082
|
+
await eventLoopRun();
|
|
1148
1083
|
}
|
|
1149
1084
|
}
|
|
1150
1085
|
return result;
|
|
@@ -1159,7 +1094,7 @@ export class FileTaskController {
|
|
|
1159
1094
|
const taskScopes = partition.taskScopes.filter((taskScope) => (!blockedTaskIds.has(taskScope.taskId)));
|
|
1160
1095
|
const orderedResults = [];
|
|
1161
1096
|
if (partition.globalKeys.length > 0) {
|
|
1162
|
-
orderedResults.push(await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: partition.globalKeys }, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence));
|
|
1097
|
+
orderedResults.push(await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: partition.globalKeys }, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence, this.#onError));
|
|
1163
1098
|
}
|
|
1164
1099
|
if (taskScopes.length === 0
|
|
1165
1100
|
|| this.#stopped
|
|
@@ -1192,7 +1127,7 @@ export class FileTaskController {
|
|
|
1192
1127
|
if (this.#stopped || this.#pendingFull)
|
|
1193
1128
|
continue;
|
|
1194
1129
|
try {
|
|
1195
|
-
taskResults[selected.index] = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: selected.taskScope.keys }, false, taskCleanupOutcomes[selected.index], this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence);
|
|
1130
|
+
taskResults[selected.index] = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: selected.taskScope.keys }, false, taskCleanupOutcomes[selected.index], this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#diagnosticAfterMs, this.#leaderWakeFence, this.#onError);
|
|
1196
1131
|
this.#clearTaskPassRetry(selected.taskScope.taskId);
|
|
1197
1132
|
}
|
|
1198
1133
|
catch (error) {
|
|
@@ -1424,13 +1359,7 @@ export class FileTaskController {
|
|
|
1424
1359
|
at: aggregationAt
|
|
1425
1360
|
}];
|
|
1426
1361
|
}
|
|
1427
|
-
|
|
1428
|
-
return forceAt > now && this.store.getActiveTurn(wakeup.taskId, "leader") !== null
|
|
1429
|
-
? [{
|
|
1430
|
-
key: `role:${encodeURIComponent(wakeup.taskId)}/leader`,
|
|
1431
|
-
at: forceAt
|
|
1432
|
-
}]
|
|
1433
|
-
: [];
|
|
1362
|
+
return [];
|
|
1434
1363
|
});
|
|
1435
1364
|
const nearest = nearestDeadlineBatch(deadlines);
|
|
1436
1365
|
if (nearest === null)
|
|
@@ -1449,7 +1378,7 @@ export class FileTaskController {
|
|
|
1449
1378
|
const settled = new Set();
|
|
1450
1379
|
const writerBlocked = new Set();
|
|
1451
1380
|
const resignal = new Set();
|
|
1452
|
-
for (const delivery of result.
|
|
1381
|
+
for (const delivery of result.activeRunDeliveries) {
|
|
1453
1382
|
const key = `role:${encodeURIComponent(delivery.taskId)}/${encodeURIComponent(delivery.roleName)}`;
|
|
1454
1383
|
if (delivery.terminalized === true) {
|
|
1455
1384
|
settled.add(key);
|
|
@@ -1459,7 +1388,7 @@ export class FileTaskController {
|
|
|
1459
1388
|
writerBlocked.add(key);
|
|
1460
1389
|
else if (delivery.reason === "not-ready"
|
|
1461
1390
|
|| delivery.reason === "runtime-unavailable") {
|
|
1462
|
-
retry.set(key, { identity: delivery.
|
|
1391
|
+
retry.set(key, { identity: delivery.runId });
|
|
1463
1392
|
}
|
|
1464
1393
|
else if (delivery.status === "delivered" || delivery.status === "already-delivered")
|
|
1465
1394
|
settled.add(key);
|
|
@@ -1467,8 +1396,8 @@ export class FileTaskController {
|
|
|
1467
1396
|
for (const wakeup of result.wakeups) {
|
|
1468
1397
|
const key = `role:${encodeURIComponent(wakeup.taskId)}/leader`;
|
|
1469
1398
|
if (wakeup.reason === "not-ready"
|
|
1470
|
-
|| (wakeup.reason === "busy" && wakeup.
|
|
1471
|
-
retry.set(key, { identity: wakeup.
|
|
1399
|
+
|| (wakeup.reason === "busy" && wakeup.runId !== undefined)) {
|
|
1400
|
+
retry.set(key, { identity: wakeup.runId ?? key });
|
|
1472
1401
|
}
|
|
1473
1402
|
else if (wakeup.status === "dispatched")
|
|
1474
1403
|
settled.add(key);
|
|
@@ -1575,9 +1504,9 @@ export class FileTaskController {
|
|
|
1575
1504
|
timer.unref();
|
|
1576
1505
|
this.#deliveryRetryTimers.set(key, timer);
|
|
1577
1506
|
}
|
|
1578
|
-
#terminalizePreparedAfterRetryExhaustion(key,
|
|
1507
|
+
#terminalizePreparedAfterRetryExhaustion(key, runId, failure) {
|
|
1579
1508
|
if (!key.startsWith("role:")
|
|
1580
|
-
||
|
|
1509
|
+
|| runId.startsWith("runtime-cleanup:")
|
|
1581
1510
|
|| failure === undefined) {
|
|
1582
1511
|
return;
|
|
1583
1512
|
}
|
|
@@ -1586,10 +1515,10 @@ export class FileTaskController {
|
|
|
1586
1515
|
return;
|
|
1587
1516
|
if (target.taskId !== failure.taskId
|
|
1588
1517
|
|| target.roleName !== failure.roleName
|
|
1589
|
-
||
|
|
1590
|
-
throw new Error(`Role delivery retry identity changed: ${key}/${
|
|
1518
|
+
|| runId !== failure.runId) {
|
|
1519
|
+
throw new Error(`Role delivery retry identity changed: ${key}/${runId}.`);
|
|
1591
1520
|
}
|
|
1592
|
-
const result = this.store.
|
|
1521
|
+
const result = this.store.saveRoleRunDeliveryFailure({
|
|
1593
1522
|
...failure,
|
|
1594
1523
|
now: this.#now()
|
|
1595
1524
|
});
|
|
@@ -1599,10 +1528,7 @@ export class FileTaskController {
|
|
|
1599
1528
|
this.delivery.forgetPrepared?.({
|
|
1600
1529
|
taskId: failure.taskId,
|
|
1601
1530
|
roleName: failure.roleName,
|
|
1602
|
-
|
|
1603
|
-
...(failure.runtimeGenerationId === undefined
|
|
1604
|
-
? {}
|
|
1605
|
-
: { runtimeGenerationId: failure.runtimeGenerationId })
|
|
1531
|
+
runId: failure.runId,
|
|
1606
1532
|
});
|
|
1607
1533
|
if (!this.#stopped)
|
|
1608
1534
|
this.signal(key);
|
|
@@ -1808,15 +1734,15 @@ class ControllerDispatcherServiceTimeMetrics {
|
|
|
1808
1734
|
};
|
|
1809
1735
|
}
|
|
1810
1736
|
}
|
|
1811
|
-
function
|
|
1737
|
+
function eventLoopRun() {
|
|
1812
1738
|
return new Promise((resolve) => setImmediate(resolve));
|
|
1813
1739
|
}
|
|
1814
|
-
async function
|
|
1740
|
+
async function controlEventLoopRun() {
|
|
1815
1741
|
// A setImmediate scheduled from the check phase may resume before the next
|
|
1816
1742
|
// poll phase. Two turns guarantee already-written socket data gets one poll
|
|
1817
1743
|
// opportunity before another synchronous scheduler projection starts.
|
|
1818
|
-
await
|
|
1819
|
-
await
|
|
1744
|
+
await eventLoopRun();
|
|
1745
|
+
await eventLoopRun();
|
|
1820
1746
|
}
|
|
1821
1747
|
function signalMailboxKey(value) {
|
|
1822
1748
|
if (typeof value !== "object"
|