@zq-silk/yui 0.15.12 → 0.16.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/ARCHITECTURE.md +3 -2
- package/ARCHITECTURE.zh-CN.md +3 -2
- package/dist/artifacts/artifactCommitLock.js +16 -55
- package/dist/artifacts/taskArtifactRepository.js +3 -3
- package/dist/cli/agentConfigurationPicker.js +1 -1
- package/dist/cli/commandCatalog.js +57 -41
- package/dist/cli/completion.js +18 -18
- package/dist/cli/completionWizard.js +1 -1
- package/dist/cli/dynamicCompletion.js +1 -1
- package/dist/cli/interactionPolicy.js +7 -3
- package/dist/cli/invocationAuthority.js +64 -0
- package/dist/cli/managedDiagnostics.js +1 -1
- package/dist/cli/parseRepeatable.js +35 -0
- package/dist/cli/updatePorts.js +26 -5
- package/dist/cli.js +1280 -1243
- package/dist/commands/agentCommands.js +4 -4
- package/dist/commands/capabilityCommands.js +1 -1
- package/dist/commands/configCommands.js +6 -57
- package/dist/commands/configOverview.js +2 -2
- package/dist/commands/durableJobCommands.js +12 -6
- package/dist/commands/globalRoleCommands.js +53 -29
- package/dist/commands/grantCommands.js +0 -3
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/operatorCommands.js +3 -3
- package/dist/commands/projectCommands.js +1 -10
- package/dist/commands/resourcesCommands.js +10 -40
- package/dist/commands/roleConfiguration.js +2 -6
- package/dist/commands/taskActivationCommands.js +4 -8
- package/dist/commands/taskAgentCapabilities.js +9 -0
- package/dist/commands/taskCommandSupport.js +155 -0
- package/dist/commands/taskCommandTypes.js +1 -0
- package/dist/commands/taskCommands.js +271 -710
- package/dist/commands/taskCompletionGate.js +1 -1
- package/dist/commands/taskExecutionCommands.js +1 -1
- package/dist/commands/taskFactCommands.js +325 -0
- package/dist/commands/taskInputCommands.js +12 -42
- package/dist/commands/taskIntegrationCommands.js +17 -57
- package/dist/commands/taskNextActionCommand.js +7 -6
- package/dist/commands/taskPublicationAdoptCommand.js +3 -3
- package/dist/commands/taskPublicationCommands.js +1 -1
- package/dist/commands/taskPublicationVerifyCommand.js +1 -1
- package/dist/commands/taskRemoteDeliveryCommand.js +2 -94
- package/dist/commands/taskUpstreamCommands.js +19 -8
- package/dist/commands/workflowCommands.js +6 -1
- package/dist/completion/completionInstaller.js +26 -26
- package/dist/completion/completionState.js +26 -26
- package/dist/completion/fileCompletionManager.js +6 -11
- package/dist/config/configCatalog.js +0 -2
- package/dist/config/timeZone.js +14 -0
- package/dist/config/yuiConfig.js +0 -29
- package/dist/context/runContextPack.js +2 -3
- package/dist/context/taskCatalog.js +3 -5
- package/dist/context/taskContext.js +139 -151
- package/dist/context/wakeRunReferences.js +11 -0
- package/dist/controller/agentCapabilities.js +58 -0
- package/dist/controller/agentRuntimeObserver.js +6 -11
- package/dist/controller/clientRuntime.js +22 -14
- package/dist/controller/controller.js +9 -22
- package/dist/controller/fileSchedulerStoreAdapter.js +117 -212
- package/dist/controller/jobClient.js +4 -4
- package/dist/controller/jobControl.js +60 -25
- package/dist/controller/jobSupervisor.js +4 -4
- package/dist/controller/providerRetryDelivery.js +7 -7
- package/dist/controller/runtime.js +51 -44
- package/dist/controller/runtimeEventProcessor.js +0 -5
- package/dist/controller/sessionOwnerReconciliation.js +5 -0
- package/dist/controller/taskAgentError.js +35 -0
- package/dist/coordination/workMailboxQueue.js +2 -24
- package/dist/core/controllerClient.js +2 -2
- package/dist/core/fileLockOwner.js +74 -0
- package/dist/decision/decision.js +17 -0
- package/dist/doctor/doctor.js +18 -9
- package/dist/event/taskEvent.js +12 -0
- package/dist/execution/workItemExecutionProjection.js +2 -2
- package/dist/executor/agentCapabilityConfig.js +43 -0
- package/dist/executor/agentConfigurationCatalog.js +49 -11
- package/dist/executor/agentExecutor.js +5 -8
- package/dist/executor/fileRoleLaunchPlanner.js +11 -53
- package/dist/executor/taskAgentCapabilities.js +64 -0
- package/dist/integration/deliveryObligation.js +1 -69
- package/dist/integration/gitIntegrationService.js +60 -84
- package/dist/integration/integrationAttempt.js +3 -14
- package/dist/integration/integrationSourceApplication.js +4 -12
- package/dist/integration/manifestTags.js +2 -2
- package/dist/job/durableJob.js +4 -25
- package/dist/job/jobAssignmentScope.js +22 -0
- package/dist/job/jobOperation.js +16 -0
- package/dist/job/jobRunner.js +2 -1
- package/dist/job/stepDirectory.js +15 -0
- package/dist/kernel/builtinCapabilities.js +15 -11
- package/dist/kernel/kernelPorts.js +1 -17
- package/dist/lifecycle/exactRunTerminalization.js +1 -9
- package/dist/message/inputControlResolution.js +3 -4
- package/dist/message/message.js +17 -20
- package/dist/message/messageContinuation.js +1 -1
- package/dist/milestone/milestone.js +11 -0
- package/dist/observability/orchestrationMetrics.js +24 -1
- package/dist/observability/runtimeIdentity.js +1 -17
- package/dist/output/agentConfigurationPresentation.js +2 -0
- package/dist/output/timePresentation.js +1 -14
- package/dist/plugins/pluginService.js +12 -4
- package/dist/release/releaseWorkflowPorts.js +45 -96
- package/dist/release/runtimeRelease.js +9 -15
- package/dist/repository/projectMaintenanceLock.js +23 -64
- package/dist/repository/taskBaseFreshness.js +1 -1
- package/dist/repository/taskWorkspaceCoordinator.js +13 -22
- package/dist/repository/taskWorkspacePreparer.js +29 -25
- package/dist/repository/workspaceCleanupInspection.js +5 -5
- package/dist/resources/autoResourceGc.js +4 -77
- package/dist/resources/liveReferences.js +7 -54
- package/dist/resources/resourceDiscovery.js +5 -118
- package/dist/resources/resourceGc.js +233 -181
- package/dist/resources/resourceRegistrar.js +5 -4
- package/dist/resources/resourceRegistry.js +3 -37
- package/dist/resources/resourceRegistryStore.js +13 -36
- package/dist/resources/sqliteResourceRegistry.js +43 -26
- package/dist/review/deltaRecheck.js +1 -1
- package/dist/review/reviewAcceptance.js +1 -1
- package/dist/review/reviewDecision.js +1 -1
- package/dist/review/reviewRound.js +8 -7
- package/dist/review/taskFinalReviewContractResolution.js +1 -1
- package/dist/runtime/acpProtocol.js +4 -51
- package/dist/runtime/acpSession.js +10 -75
- package/dist/runtime/acpSessionConfiguration.js +1 -8
- package/dist/runtime/agentEndpoint.js +3 -2
- package/dist/runtime/agentFailureContext.js +43 -0
- package/dist/runtime/agentHost.js +15 -15
- package/dist/runtime/codexInteractiveHost.js +2 -2
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/managedCaller.js +21 -1
- package/dist/runtime/providerErrors.js +38 -0
- package/dist/runtime/runtimeObservation.js +0 -5
- package/dist/runtime/runtimeSessionCandidate.js +2 -3
- package/dist/runtime/sessionOwnerIdentity.js +1 -1
- package/dist/runtime/structuredProviderHost.js +4 -41
- package/dist/runtime/tmuxAdapters.js +6 -8
- package/dist/scheduler/activeRoleRunDelivery.js +7 -7
- package/dist/scheduler/leaderWakeupProcessor.js +19 -6
- package/dist/scheduler/operatorEvent.js +12 -20
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +5 -8
- package/dist/scheduler/roleRunLiveness.js +4 -4
- package/dist/scheduler/roleRunStall.js +16 -23
- package/dist/scheduler/taskExecutionProjection.js +25 -33
- package/dist/scheduler/taskObservabilityProjection.js +0 -1
- package/dist/scheduler/taskWake.js +5 -10
- package/dist/scheduler/wakeReason.js +2 -0
- package/dist/scheduler/wakeupQueue.js +2 -4
- package/dist/setup/setupCommand.js +1 -1
- package/dist/storage/contextRecords.js +106 -0
- package/dist/storage/currentTaskStore.js +1 -1
- package/dist/storage/homeLayout.js +13 -17
- package/dist/storage/migrations/agentFailureContext.js +22 -0
- package/dist/storage/migrations/currentInputContract.js +86 -0
- package/dist/storage/migrations/currentRuntimeContract.js +228 -0
- package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
- package/dist/storage/migrations/integrationContinuation.js +5 -4
- package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
- package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
- package/dist/storage/migrations/verificationPlanV1.js +162 -0
- package/dist/storage/migrations/verificationPolicy.js +74 -0
- package/dist/storage/migrations/workItemHistory.js +46 -0
- package/dist/storage/persistenceWorker.js +12 -4
- package/dist/storage/recordValidation.js +87 -0
- package/dist/storage/sqliteSchema.js +142 -1
- package/dist/storage/sqliteStore.js +156 -162
- package/dist/storage/storageSchema.js +2 -14
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +15 -7
- package/dist/storage/taskStore.js +3 -7
- package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
- package/dist/task/completionReadiness.js +5 -24
- package/dist/task/draftPlan.js +0 -53
- package/dist/task/nextAction.js +7 -13
- package/dist/task/remoteDeliveryService.js +89 -0
- package/dist/task/taskActivation.js +2 -25
- package/dist/task/taskActivationService.js +0 -2
- package/dist/task/taskRecordReference.js +0 -1
- package/dist/task/taskSubmission.js +3 -14
- package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
- package/dist/telemetry/sqliteTelemetryStore.js +49 -49
- package/dist/telemetry/telemetryWiring.js +4 -3
- package/dist/tmux/tmuxManager.js +29 -20
- package/dist/verification/gateArtifact.js +15 -24
- package/dist/verification/gateArtifactStore.js +14 -7
- package/dist/verification/verificationGateService.js +29 -88
- package/dist/verification/verificationPlan.js +27 -72
- package/dist/web/assets/client/app.js +1 -1
- package/dist/web/assets/client/taskSurface.js +4 -4
- package/dist/web/webServer.js +4 -6
- package/dist/web/webSnapshot.js +3 -83
- package/dist/web/webTaskSurface.js +17 -46
- package/dist/workItem/workItem.js +1 -12
- package/docs/architecture/capabilities-and-resources.md +14 -2
- package/docs/architecture/capabilities-and-resources.zh-CN.md +11 -1
- package/docs/managed-turn-and-session-runtime.md +83 -10
- package/docs/managed-turn-and-session-runtime.zh-CN.md +65 -11
- package/docs/plugin-sdk.md +4 -2
- package/docs/provider-runtime.md +3 -1
- package/docs/provider-runtime.zh-CN.md +4 -2
- package/docs/release-workflow.md +190 -7
- package/docs/release-workflow.zh-CN.md +139 -5
- package/docs/roles-and-configuration.md +29 -0
- package/docs/roles-and-configuration.zh-CN.md +21 -0
- package/docs/sqlite-control-plane-design.md +16 -3
- package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
- package/docs/task-dag-semantics.md +3 -3
- package/docs/task-dag-semantics.zh-CN.md +2 -2
- package/docs/task-delivery.md +91 -5
- package/docs/task-delivery.zh-CN.md +72 -4
- package/docs/task-discovery.md +10 -11
- package/docs/task-discovery.zh-CN.md +8 -9
- package/docs/testing/verification-levels.md +145 -9
- package/docs/testing/verification-levels.zh-CN.md +103 -8
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +5 -0
- package/skills/yui-leader/references/integration.md +9 -5
- package/skills/yui-leader/references/planning.md +9 -3
- package/skills/yui-operator/SKILL.md +15 -10
- package/skills/yui-runtime/SKILL.md +6 -6
- package/skills/yui-runtime/references/recovery.md +47 -0
- package/dist/agent/agentRegistry.js +0 -10
- package/dist/agentRun/runIdentity.js +0 -22
- package/dist/commands/deliveryGuardPreflight.js +0 -30
- package/dist/commands/taskIntegrationQueueCommands.js +0 -226
- package/dist/commands/taskOverviewCommand.js +0 -377
- package/dist/completion/completionWizard.js +0 -125
- package/dist/context/dispatchContext.js +0 -110
- package/dist/context/wakeNotification.js +0 -144
- package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
- package/dist/integration/integrationQueueEntry.js +0 -191
- package/dist/integration/integrationQueueService.js +0 -810
- package/dist/release/fakeReleasePorts.js +0 -55
- package/dist/runtime/sessionOwnerRegistry.js +0 -137
- package/dist/task/deliveryGuard.js +0 -226
- /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
|
@@ -2,18 +2,18 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { findLiveControllerProcessForHome, inspectLiveControllerProcess } from "../core/controllerProcessIdentity.js";
|
|
4
4
|
import { readHomeFilesystemId } from "../core/homeFilesystemIdentity.js";
|
|
5
|
+
import { AGENT_OPERATIONAL_ENVIRONMENT_NAMES, nativeAgentEnvironmentNames, operationalAgentEnvironment, selectEnvironment, YUI_MANAGED_RUNTIME_ENVIRONMENT_NAMES } from "../agent/launchEnvironment.js";
|
|
5
6
|
import { callController, ControllerClientError, readControllerDiscovery, stopOrphanedFileTaskController } from "../core/controllerClient.js";
|
|
6
7
|
import { FILE_TASK_CONTROLLER_PROTOCOL_VERSION } from "../core/protocol.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import { isForeignHandoverLockHeld } from "../release/runtimeRelease.js";
|
|
9
|
+
import { WorkspaceCleanupBlockedError } from "../repository/taskWorkspacePreparer.js";
|
|
9
10
|
import { hasRuntimeLifecycleWork } from "../runtime/lifecycleReservation.js";
|
|
10
11
|
import { assertControllerStatusIdentity } from "../runtime/runtimeCoherence.js";
|
|
11
|
-
import {
|
|
12
|
+
import { CONTROLLER_SHUTDOWN_TIMEOUT_MS, LIFECYCLE_REQUEST_TIMEOUT_MS } from "../runtime/runtimeDeadlines.js";
|
|
13
|
+
import { openCurrentTaskStore } from "../storage/currentTaskStore.js";
|
|
12
14
|
import { yuiVersionIdentity } from "../version.js";
|
|
15
|
+
import { EPHEMERAL_DOMAIN_ENVIRONMENT_NAMES } from "./domainIdentity.js";
|
|
13
16
|
import { SessionOwnerReconciliation } from "./sessionOwnerReconciliation.js";
|
|
14
|
-
import { WorkspaceCleanupBlockedError } from "../repository/taskWorkspacePreparer.js";
|
|
15
|
-
import { CONTROLLER_SHUTDOWN_TIMEOUT_MS, LIFECYCLE_REQUEST_TIMEOUT_MS } from "../runtime/runtimeDeadlines.js";
|
|
16
|
-
import { isForeignHandoverLockHeld } from "../release/runtimeRelease.js";
|
|
17
17
|
const STARTUP_TIMEOUT_MS = 5_000;
|
|
18
18
|
const POLL_INTERVAL_MS = 50;
|
|
19
19
|
const ENVIRONMENT_REFRESH_TIMEOUT_MS = 500;
|
|
@@ -166,7 +166,7 @@ function assertCompatibleControllerStatus(status, expectedVersion) {
|
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
|
-
function spawnDetachedFileTaskController(
|
|
169
|
+
function spawnDetachedFileTaskController(_home, environment) {
|
|
170
170
|
const child = spawn(process.execPath, [fileURLToPath(new URL("./controllerMain.js", import.meta.url))], {
|
|
171
171
|
env: environment,
|
|
172
172
|
detached: true,
|
|
@@ -439,9 +439,6 @@ export class FileTaskWorkflowRuntime {
|
|
|
439
439
|
this.workspacePreparer = workspacePreparer;
|
|
440
440
|
this.clientOptions = clientOptions;
|
|
441
441
|
}
|
|
442
|
-
notifyStateChanged(taskId) {
|
|
443
|
-
void this.notifyMailboxChanged({ kind: "task", taskId });
|
|
444
|
-
}
|
|
445
442
|
notifyMailboxChanged(target) {
|
|
446
443
|
const pending = callFileTaskController(this.home, "scheduler.signal", { key: controllerMailboxKey(target) }, this.clientOptions).then(() => { });
|
|
447
444
|
void pending.catch(this.clientOptions.onError ?? (() => { }));
|
|
@@ -577,6 +574,17 @@ export class FileTaskWorkflowRuntime {
|
|
|
577
574
|
+ blockers.map((entry) => (`${entry.owner.roleName}/${entry.nativeSessionId ?? "unknown-session"}`
|
|
578
575
|
+ ` (pid ${entry.physical?.alive === true ? entry.physical.pid : "?"})`)).join("; "));
|
|
579
576
|
}
|
|
577
|
+
/** Archive cleanup is stronger than a read-only proof that no process is live. */
|
|
578
|
+
async releaseTaskTerminals(taskId) {
|
|
579
|
+
await this.assertTaskPhysicalResourcesReleased(taskId);
|
|
580
|
+
// A Home's server is shared with other Tasks and the Operator. Remove only
|
|
581
|
+
// this Task's session group; exited panes still own scrollback memory.
|
|
582
|
+
await this.tmux.stopTaskAsync(taskId);
|
|
583
|
+
const remaining = this.tmux.inspectTaskRolePanes(taskId);
|
|
584
|
+
if (remaining.length > 0) {
|
|
585
|
+
throw new WorkspaceCleanupBlockedError("physical-resource-live", `task:${taskId}`, true, `Task terminals remain after cleanup: ${remaining.map(pane => pane.roleName).join(", ")}.`);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
580
588
|
async stopGlobalRoleSession(roleName) {
|
|
581
589
|
if (this.store.getGlobalRole(roleName) === null) {
|
|
582
590
|
throw new Error(`Global Role not found: ${roleName}.`);
|
|
@@ -678,11 +686,11 @@ function runtimeOwnerLabel(owner) {
|
|
|
678
686
|
}
|
|
679
687
|
const MANAGED_RUNTIME_ENVIRONMENT = new Set(YUI_MANAGED_RUNTIME_ENVIRONMENT_NAMES);
|
|
680
688
|
function foregroundGlobalRoleEnvironment(store, roleName, source) {
|
|
681
|
-
const role = store.getGlobalRole
|
|
682
|
-
if (role === null
|
|
689
|
+
const role = store.getGlobalRole(roleName);
|
|
690
|
+
if (role === null)
|
|
683
691
|
return undefined;
|
|
684
|
-
const agent = store.getConfiguredAgent
|
|
685
|
-
if (agent === null
|
|
692
|
+
const agent = store.getConfiguredAgent(role.activeAgentId);
|
|
693
|
+
if (agent === null)
|
|
686
694
|
return undefined;
|
|
687
695
|
const declaredSources = new Set(agent.environment.map((binding) => binding.sourceName));
|
|
688
696
|
for (const name of MANAGED_RUNTIME_ENVIRONMENT)
|
|
@@ -16,7 +16,6 @@ import { nearestDeadlineBatch } from "../coordination/deadlineScheduler.js";
|
|
|
16
16
|
import { mailboxHasWork, nextPendingBatch } from "../coordination/workMailbox.js";
|
|
17
17
|
import { hasRuntimeCleanupObligation } from "../runtime/lifecycleReservation.js";
|
|
18
18
|
import { formatTaskRecordReference } from "../task/taskRecordReference.js";
|
|
19
|
-
import { activationRequestIsControllerAdoptable } from "../task/taskActivation.js";
|
|
20
19
|
import { parseDurableJobAcknowledgeParams, parseDurableJobCancelParams, parseDurableJobRefParams, parseDurableJobStartParams } from "./jobControl.js";
|
|
21
20
|
const DEFAULT_RECONCILIATION_INTERVAL_MS = reconciliationIntervalMilliseconds();
|
|
22
21
|
const DEFAULT_SIGNAL_WINDOW_MS = 100;
|
|
@@ -217,8 +216,7 @@ async function processSelectedRoleRuntimeCleanups(store, delivery, lifecycleHost
|
|
|
217
216
|
if (!await lifecycleHost.stopOwner(owner)) {
|
|
218
217
|
throw new Error(`Role runtime cleanup could not confirm the host stopped: ${runtimeOwnerLabel(owner)}.`);
|
|
219
218
|
}
|
|
220
|
-
if (store.completeRuntimeCleanup
|
|
221
|
-
|| !store.completeRuntimeCleanup(target, now)) {
|
|
219
|
+
if (!store.completeRuntimeCleanup(target, now)) {
|
|
222
220
|
throw new Error(`Role runtime cleanup mailbox changed: ${runtimeOwnerLabel(owner)}.`);
|
|
223
221
|
}
|
|
224
222
|
forgetPreparedRuntimeOwner(delivery, owner);
|
|
@@ -252,7 +250,7 @@ function selectedTaskIdsForBoundedPass(store, selection) {
|
|
|
252
250
|
return new Set(selectedActiveSchedulerTasks(store, selection).map((task) => task.id));
|
|
253
251
|
}
|
|
254
252
|
function selectedReadyWorkMailboxes(store) {
|
|
255
|
-
return store.listReadyWorkMailboxes
|
|
253
|
+
return store.listReadyWorkMailboxes();
|
|
256
254
|
}
|
|
257
255
|
function selectedRuntimeLifecycleTargets(store, scope, blockedTaskIds = new Set()) {
|
|
258
256
|
if (scope.kind === "full") {
|
|
@@ -456,9 +454,9 @@ export function compileReconcileSelection(scope) {
|
|
|
456
454
|
};
|
|
457
455
|
}
|
|
458
456
|
/**
|
|
459
|
-
*
|
|
457
|
+
* Continues admitted activation requests once their execution boundaries allow it.
|
|
460
458
|
*
|
|
461
|
-
*
|
|
459
|
+
* A planning deferral is released only by its Turn ending. This phase therefore
|
|
462
460
|
* re-reads the request instead of trusting the signal that woke it: a request
|
|
463
461
|
* cancelled, or a Task retired or stopped, while the Turn was still running is
|
|
464
462
|
* left alone rather than replayed as historical intent. Adoption itself belongs
|
|
@@ -475,10 +473,7 @@ async function adoptReleasedTaskActivations(store, workspace, selection, onError
|
|
|
475
473
|
if (workspace === undefined)
|
|
476
474
|
return;
|
|
477
475
|
const candidates = selection.full
|
|
478
|
-
?
|
|
479
|
-
?? store.listTasks().flatMap((task) => (task.status === "draft" && task.activationRequest?.disposition === "pending"
|
|
480
|
-
? [task.id]
|
|
481
|
-
: [])))
|
|
476
|
+
? store.listPendingActivationRequestTaskIds()
|
|
482
477
|
: selection.taskIds;
|
|
483
478
|
for (const taskId of candidates) {
|
|
484
479
|
if (selection.blockedTaskIds?.has(taskId))
|
|
@@ -489,20 +484,14 @@ async function adoptReleasedTaskActivations(store, workspace, selection, onError
|
|
|
489
484
|
const request = task.activationRequest;
|
|
490
485
|
if (request?.disposition !== "pending")
|
|
491
486
|
continue;
|
|
492
|
-
//
|
|
493
|
-
//
|
|
494
|
-
// develop submission accepted while unplanned). This admits legal
|
|
495
|
-
// Operator/user immediate requests the old actor filter dropped, while
|
|
496
|
-
// still refusing origin-less historical requests, which stay behind the
|
|
497
|
-
// explicit `yui task activate` boundary.
|
|
498
|
-
if (!activationRequestIsControllerAdoptable(request))
|
|
499
|
-
continue;
|
|
487
|
+
// The request was authorized at admission. Recheck its current execution
|
|
488
|
+
// and Session boundaries without a second provenance-based workflow gate.
|
|
500
489
|
// Later Draft discussion is a Session notification, not another AgentRun.
|
|
501
490
|
// Its durable activation intent is sufficient once the exact native input
|
|
502
491
|
// is settled. Never create a synthetic Run merely to release that intent.
|
|
503
492
|
if (store.getActiveRun(taskId, "leader") !== null)
|
|
504
493
|
continue;
|
|
505
|
-
const provider = store.getTaskRoleSessionSet
|
|
494
|
+
const provider = store.getTaskRoleSessionSet(taskId, "leader")?.providerBinding;
|
|
506
495
|
if (provider?.run != null
|
|
507
496
|
&& ["submitting", "accepted", "delivery-unknown"].includes(provider.run.status))
|
|
508
497
|
continue;
|
|
@@ -663,7 +652,6 @@ function mergeControllerSchedulerResults(results) {
|
|
|
663
652
|
export class FileTaskController {
|
|
664
653
|
store;
|
|
665
654
|
delivery;
|
|
666
|
-
#startedAt;
|
|
667
655
|
#intervalMs;
|
|
668
656
|
#now;
|
|
669
657
|
#onError;
|
|
@@ -724,7 +712,6 @@ export class FileTaskController {
|
|
|
724
712
|
this.delivery = delivery;
|
|
725
713
|
this.#intervalMs = positiveInteger(options.intervalMs, DEFAULT_RECONCILIATION_INTERVAL_MS, "Controller reconciliation interval");
|
|
726
714
|
this.#now = options.now ?? (() => new Date());
|
|
727
|
-
this.#startedAt = this.#now();
|
|
728
715
|
this.#onError = options.onError ?? (() => { });
|
|
729
716
|
const workspacePreparer = options.workspacePreparer;
|
|
730
717
|
this.#workspacePreparer = workspacePreparer === undefined ? undefined : {
|
|
@@ -1649,7 +1636,7 @@ export async function startFileTaskController(home, store, delivery, dispatcher,
|
|
|
1649
1636
|
}
|
|
1650
1637
|
if (method === "job.get") {
|
|
1651
1638
|
const ref = parseDurableJobRefParams(params);
|
|
1652
|
-
const job = control.getJob(ref.taskId, ref.jobId);
|
|
1639
|
+
const job = control.getJob(ref.taskId, ref.jobId, ref.caller);
|
|
1653
1640
|
if (job === null) {
|
|
1654
1641
|
throw controllerApplicationError("NOT_FOUND", `DurableJob not found: ${ref.taskId}/${ref.jobId}.`);
|
|
1655
1642
|
}
|
|
@@ -1,47 +1,46 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { prepareMessageContinuations, interruptThenTerminalState } from "../message/messageContinuation.js";
|
|
3
|
-
import { freezeRunContextSnapshot } from "../context/runContextPack.js";
|
|
4
|
-
import { contextSnapshotRef } from "../context/contextSnapshot.js";
|
|
5
2
|
import { isDeepStrictEqual } from "node:util";
|
|
3
|
+
import { contextSnapshotRef } from "../context/contextSnapshot.js";
|
|
4
|
+
import { freezeRunContextSnapshot } from "../context/runContextPack.js";
|
|
5
|
+
import { settleGlobalRetryInput } from "../message/globalProviderRetry.js";
|
|
6
|
+
import { interruptThenTerminalState, prepareMessageContinuations } from "../message/messageContinuation.js";
|
|
6
7
|
import { assertExecutionEnvironmentCurrent } from "../runtime/executionEnvironment.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import { deferProviderRetry, providerRetryPending, recordProviderFailure } from "../runtime/providerRetry.js";
|
|
9
|
+
import { AgentHostObservationDeferred, recordAgentHostConnection, resolveAgentHostObservation } from "./agentHostObservation.js";
|
|
9
10
|
import { admitOwnedProviderInput, ownedProviderInput } from "./providerRetryAdmission.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
11
|
+
import { RuntimeHookRunFenceError } from "./runtimeHookRunFence.js";
|
|
12
|
+
import { appendRunInput, createRun, runPurposeAdmitsTaskState, withRunContextSnapshot } from "../agentRun/agentRun.js";
|
|
13
|
+
import { createRunInput } from "../context/runInputContract.js";
|
|
14
|
+
import { bindExecution, claimPending, completeProcessing, consumePendingBatch, mailboxHasWork, releaseProcessing } from "../coordination/workMailbox.js";
|
|
15
|
+
import { enqueueWork, settleRoleRunDispatch as settleRoleRunDispatchMailbox } from "../coordination/workMailboxQueue.js";
|
|
16
|
+
import { transportAgentResult } from "../domain/agentResultTransport.js";
|
|
14
17
|
import { createTaskEvent } from "../event/taskEvent.js";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { createTaskWake, fallbackWakeCursor, latestTaskWake, markTaskWakeConsumed } from "../scheduler/taskWake.js";
|
|
18
|
+
import { activeLiveRoleAgentSession, bindGlobalRoleProviderRuntime, bindTaskRoleProviderRuntime, createRoleSessionSet, detachRoleAgentSessionHost, recordRoleAgentSession, recordTaskRoleNativeTurnBoundary, rememberRoleAgentCompletedTurn, replaceTaskRoleAgentSession, selectNewTaskRoleSession, taskRoleControlTarget, updateGlobalRoleProviderRuntime, updateRoleAgentSessionStatus, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
|
|
19
|
+
import { effectiveLaunchWithTaskMainWorkspace, resolveEffectiveLaunch, roleSessionMayContinue, validateEffectiveLaunchSnapshot } from "../executor/effectiveLaunch.js";
|
|
18
20
|
import { answerInputRequest } from "../input/inputRequest.js";
|
|
21
|
+
import { createCanonicalLifecycleEvent, foldCanonicalLifecycleEvent } from "../lifecycle/canonicalLifecycleEvent.js";
|
|
22
|
+
import { cancelQuiescentRoleRuns, terminalizeExactTaskRun } from "../lifecycle/exactRunTerminalization.js";
|
|
23
|
+
import { markGlobalRoleMessageDelivered, markGlobalRoleMessageNotDelivered, recordTaskMessageControlOutcome } from "../message/message.js";
|
|
24
|
+
import { snapshotExecutionLaneWorkspaceSync } from "../repository/executionLaneGitSnapshot.js";
|
|
19
25
|
import { activeRoleAgentBinding } from "../role/role.js";
|
|
20
|
-
import { effectiveLaunchWithTaskMainWorkspace, roleSessionMayContinue, resolveEffectiveLaunch, validateEffectiveLaunchSnapshot } from "../executor/effectiveLaunch.js";
|
|
21
26
|
import { SYSTEM_OPERATOR_ROLE } from "../role/systemRoles.js";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
27
|
+
import { standardAgentError } from "../runtime/agentError.js";
|
|
28
|
+
import { recordTaskAgentError } from "./taskAgentError.js";
|
|
29
|
+
import { builtinAgentDriverRegistry } from "../runtime/builtinAgentDrivers.js";
|
|
30
|
+
import { RUNTIME_CLEANUP_REQUIRED_REASON, RUNTIME_HOST_DETACH_REQUIRED_REASON, RUNTIME_LIFECYCLE_OWNER, hasRuntimeCleanupObligation, hasRuntimeLifecycleWork, isRuntimeCleanupReason, runtimeCleanupDisposition, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
26
31
|
import { classifyRuntimeProcessExit, validateRuntimeProcessExitObservation } from "../runtime/processExitObservation.js";
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
32
|
+
import { providerContinuationKey } from "../runtime/providerContinuation.js";
|
|
33
|
+
import { acceptProviderTurn, beginProviderTurn, cancelQuiescentProviderInput, clearProviderGoal, createProviderRuntimeBinding, currentProviderConversation, managedProviderTurnId, settleProviderTurn, settleProviderTurnSubmission, supersedeProviderConversation, transferProviderAuthority, updateProviderConversationRecoverability, updateProviderGoal } from "../runtime/providerRuntimeIdentity.js";
|
|
34
|
+
import { projectProviderContinuations } from "../runtime/runtimeContinuationProjection.js";
|
|
35
|
+
import { RUNTIME_OBSERVATION_TASK_EVENT, createRuntimeObservation, isRuntimeTokenEvidence, runtimeObservationFenceMatches, runtimeObservationFromTaskEvent, runtimeObservationRunFenceMatches, runtimeObservationTaskEventPayload } from "../runtime/runtimeObservation.js";
|
|
29
36
|
import { recordLeaderFailure } from "../scheduler/leaderFailure.js";
|
|
30
|
-
import { recordLeaderAttentionRequired, routeRoleEvent } from "../scheduler/operatorEvent.js";
|
|
31
|
-
import {
|
|
37
|
+
import { enqueueSupervisorEvent, recordLeaderAttentionRequired, routeRoleEvent } from "../scheduler/operatorEvent.js";
|
|
38
|
+
import { RUN_DIAGNOSTIC_FINISHED_EVENT, RUN_PROGRESS_EVENT, RUN_RECOVERED_EVENT, RUN_STALLED_EVENT, foldRunProgressFacts, isRoleRunStalled, latestRunDurableProgressAt, latestRunEventTime, latestStallEvidenceKey } from "../scheduler/roleRunStall.js";
|
|
39
|
+
import { createTaskWake, latestTaskWake, markTaskWakeConsumed } from "../scheduler/taskWake.js";
|
|
32
40
|
import { wakeReason } from "../scheduler/wakeReason.js";
|
|
33
|
-
import {
|
|
41
|
+
import { queueLeaderWakeup } from "../scheduler/wakeupQueue.js";
|
|
34
42
|
import { pendingWakeupProjection } from "../storage/taskStore.js";
|
|
35
|
-
import { projectProviderContinuations } from "../runtime/runtimeContinuationProjection.js";
|
|
36
|
-
import { providerContinuationKey } from "../runtime/providerContinuation.js";
|
|
37
43
|
import { formatRunReceiptId } from "../task/taskRecordReference.js";
|
|
38
|
-
import { bindExecution, claimPending, completeProcessing, consumePendingBatch, mailboxHasWork, releaseProcessing } from "../coordination/workMailbox.js";
|
|
39
|
-
import { enqueueWork, settleRoleRunDispatch as settleRoleRunDispatchMailbox } from "../coordination/workMailboxQueue.js";
|
|
40
|
-
import { RUNTIME_CLEANUP_REQUIRED_REASON, RUNTIME_HOST_DETACH_REQUIRED_REASON, RUNTIME_LIFECYCLE_OWNER, hasRuntimeCleanupObligation, hasRuntimeLifecycleWork, isRuntimeCleanupReason, runtimeCleanupDisposition, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
41
|
-
import { builtinAgentDriverRegistry } from "../runtime/builtinAgentDrivers.js";
|
|
42
|
-
import { standardAgentError } from "../runtime/agentError.js";
|
|
43
|
-
import { RUNTIME_OBSERVATION_TASK_EVENT, createRuntimeObservation, isRuntimeTokenEvidence, runtimeObservationFenceMatches, runtimeObservationFromTaskEvent, runtimeObservationRunFenceMatches, runtimeObservationTaskEventPayload } from "../runtime/runtimeObservation.js";
|
|
44
|
-
import { snapshotExecutionLaneWorkspaceSync } from "../repository/executionLaneGitSnapshot.js";
|
|
45
44
|
export class AgentHostProviderTurnFenceError extends Error {
|
|
46
45
|
constructor(message) {
|
|
47
46
|
super(message);
|
|
@@ -740,31 +739,24 @@ export class FileSchedulerStoreAdapter {
|
|
|
740
739
|
const run = input.fence.runId === undefined
|
|
741
740
|
? null
|
|
742
741
|
: store.getRun(taskId, input.fence.runId);
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
inputDisposition: error.inputDisposition,
|
|
760
|
-
sessionDisposition: error.sessionDisposition,
|
|
761
|
-
...(error.retryAfterMs === undefined
|
|
762
|
-
? {}
|
|
763
|
-
: { retryAfterMs: String(error.retryAfterMs) }),
|
|
764
|
-
...(failure.lastOutput === undefined ? {} : { lastOutput: failure.lastOutput })
|
|
742
|
+
const errorSessions = store.getTaskRoleSessionSet(taskId, input.fence.roleName);
|
|
743
|
+
const errorSession = [...Object.values(errorSessions?.sessions ?? {}), ...(errorSessions?.history ?? [])]
|
|
744
|
+
.find(session => session.nativeSessionId === input.fence.nativeSessionId
|
|
745
|
+
&& session.agentId === input.fence.agentId);
|
|
746
|
+
const effective = run?.effective ?? errorSession?.effective;
|
|
747
|
+
const { event: errorEvent, created } = recordTaskAgentError(store, {
|
|
748
|
+
taskId, roleName: input.fence.roleName, sourceEventId: input.eventId,
|
|
749
|
+
agentId: input.fence.agentId, adapterId: effective?.adapterId ?? "unknown",
|
|
750
|
+
driverId: input.fence.driverId, error, effective,
|
|
751
|
+
evidence: {
|
|
752
|
+
observationEventId,
|
|
753
|
+
runId: input.fence.runId,
|
|
754
|
+
nativeSessionId: input.fence.nativeSessionId,
|
|
755
|
+
nativeTurnId: input.fence.nativeTurnId,
|
|
756
|
+
lastOutput: failure.lastOutput
|
|
757
|
+
},
|
|
765
758
|
}, now);
|
|
766
|
-
store.
|
|
767
|
-
if (!providerRetryPending(store.getTaskRoleSessionSet(taskId, input.fence.roleName)?.providerBinding))
|
|
759
|
+
if (created && !providerRetryPending(store.getTaskRoleSessionSet(taskId, input.fence.roleName)?.providerBinding))
|
|
768
760
|
routeRoleEvent(store, errorEvent, input.fence.roleName, wakeReason("agent-error", errorEvent.id), now);
|
|
769
761
|
}
|
|
770
762
|
if ((input.kind === "operation.completed" || input.kind === "operation.failed")
|
|
@@ -855,29 +847,6 @@ export class FileSchedulerStoreAdapter {
|
|
|
855
847
|
getTaskBrief(taskId) { return this.store.getTaskBrief(taskId); }
|
|
856
848
|
listDecisions(taskId) { return this.store.listDecisions(taskId); }
|
|
857
849
|
listMilestones(taskId) { return this.store.listMilestones(taskId); }
|
|
858
|
-
getTaskWakeEnvelope(taskId) {
|
|
859
|
-
return this.store.transaction((reader) => {
|
|
860
|
-
const pending = reader.getPendingWakeup(taskId);
|
|
861
|
-
if (pending === null)
|
|
862
|
-
return null;
|
|
863
|
-
const task = reader.getTask(taskId);
|
|
864
|
-
if (task === null)
|
|
865
|
-
return null;
|
|
866
|
-
const latest = latestTaskWake(reader.listTaskWakes(taskId));
|
|
867
|
-
const fromCursor = latest?.toCursor ?? fallbackWakeCursor({
|
|
868
|
-
taskCreatedAt: task.createdAt,
|
|
869
|
-
leaderRunCreatedAt: operationalTaskRecords(reader.listRuns(taskId), reader.listEvents(taskId), "run")
|
|
870
|
-
.filter((run) => run.roleName === "leader")
|
|
871
|
-
.at(-1)?.createdAt
|
|
872
|
-
});
|
|
873
|
-
return buildTaskWakeEnvelope(reader, {
|
|
874
|
-
taskId,
|
|
875
|
-
wakeId: reader.peekNextTaskWakeId(taskId),
|
|
876
|
-
reasons: pending.reasons,
|
|
877
|
-
fromCursor
|
|
878
|
-
});
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
850
|
listRoles(taskId) {
|
|
882
851
|
return this.store.listRoles(taskId).map((role) => mapRole(this.store, role));
|
|
883
852
|
}
|
|
@@ -1305,41 +1274,22 @@ export class FileSchedulerStoreAdapter {
|
|
|
1305
1274
|
raw: input.raw,
|
|
1306
1275
|
inputDisposition: input.status === "delivery-unknown" ? "unknown" : "not-accepted"
|
|
1307
1276
|
});
|
|
1308
|
-
const errorEvent =
|
|
1309
|
-
sourceEventId: input.attemptId,
|
|
1310
|
-
runId: input.runId ?? "",
|
|
1311
|
-
roleName: input.roleName,
|
|
1277
|
+
const { event: errorEvent, created } = recordTaskAgentError(store, {
|
|
1278
|
+
taskId: input.taskId, roleName: input.roleName, sourceEventId: input.attemptId,
|
|
1312
1279
|
agentId: run?.effective.agentId ?? sessions.activeAgentId,
|
|
1313
|
-
adapterId:
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
// one the Provider genuinely reported.
|
|
1319
|
-
...optionalEventFields({
|
|
1280
|
+
adapterId: adapterId ?? "unknown", driverId: driver?.id ?? "unknown",
|
|
1281
|
+
error, effective: run?.effective ?? session?.effective,
|
|
1282
|
+
evidence: {
|
|
1283
|
+
attemptId: input.attemptId,
|
|
1284
|
+
runId: input.runId,
|
|
1320
1285
|
nativeSessionId: session?.nativeSessionId
|
|
1321
|
-
}
|
|
1322
|
-
source: error.source,
|
|
1323
|
-
phase: error.phase,
|
|
1324
|
-
category: error.category,
|
|
1325
|
-
code: error.code,
|
|
1326
|
-
message: error.message,
|
|
1327
|
-
raw: error.raw,
|
|
1328
|
-
inputDisposition: error.inputDisposition,
|
|
1329
|
-
sessionDisposition: error.sessionDisposition
|
|
1286
|
+
}
|
|
1330
1287
|
}, input.now);
|
|
1331
|
-
|
|
1332
|
-
if (input.status === "deferred" || providerRetryPending(updated))
|
|
1288
|
+
if (!created || input.status === "deferred" || providerRetryPending(updated))
|
|
1333
1289
|
return;
|
|
1334
|
-
|
|
1335
|
-
? { kind: "operator" }
|
|
1336
|
-
: { kind: "role", taskId: input.taskId, roleName: "leader" };
|
|
1337
|
-
enqueueWork(store, route, input.roleName === "leader"
|
|
1290
|
+
enqueueSupervisorEvent(store, errorEvent, input.roleName === "leader" ? "operator" : "leader", input.roleName === "leader"
|
|
1338
1291
|
? "leader-turn-submission-error"
|
|
1339
|
-
: wakeReason("agent-error", errorEvent.id), input.now
|
|
1340
|
-
source: driver?.id ?? "agent-host",
|
|
1341
|
-
dedupeKey: `agent-error:${input.taskId}:${input.attemptId}`
|
|
1342
|
-
});
|
|
1292
|
+
: wakeReason("agent-error", errorEvent.id), input.now);
|
|
1343
1293
|
});
|
|
1344
1294
|
}
|
|
1345
1295
|
retrySubmissionResolution(binding, input, adapterId) {
|
|
@@ -1403,15 +1353,19 @@ export class FileSchedulerStoreAdapter {
|
|
|
1403
1353
|
}
|
|
1404
1354
|
recordAgentError(input, now) {
|
|
1405
1355
|
return this.store.transaction((store) => {
|
|
1406
|
-
|
|
1356
|
+
if (input.runId === undefined && input.attemptId === undefined) {
|
|
1357
|
+
throw new Error("An Agent error needs an exact Run or notification attempt.");
|
|
1358
|
+
}
|
|
1359
|
+
const run = input.runId === undefined ? null : store.getRun(input.taskId, input.runId);
|
|
1407
1360
|
const sessionSet = store.getTaskRoleSessionSet(input.taskId, input.roleName);
|
|
1408
|
-
const
|
|
1361
|
+
const effective = input.effective ?? run?.effective;
|
|
1362
|
+
const sessionAgentId = effective?.agentId ?? sessionSet?.activeAgentId;
|
|
1409
1363
|
const session = sessionAgentId === undefined
|
|
1410
1364
|
? undefined
|
|
1411
1365
|
: sessionSet?.sessions[sessionAgentId];
|
|
1412
|
-
const driver =
|
|
1366
|
+
const driver = effective === undefined
|
|
1413
1367
|
? null
|
|
1414
|
-
: this.drivers.findByAdapterId(
|
|
1368
|
+
: this.drivers.findByAdapterId(effective.adapterId);
|
|
1415
1369
|
const error = standardAgentError({
|
|
1416
1370
|
source: input.source,
|
|
1417
1371
|
phase: input.phase,
|
|
@@ -1428,57 +1382,22 @@ export class FileSchedulerStoreAdapter {
|
|
|
1428
1382
|
? {}
|
|
1429
1383
|
: { sessionDisposition: input.sessionDisposition })
|
|
1430
1384
|
});
|
|
1431
|
-
const
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
&& event.payload.hostState === input.hostState
|
|
1441
|
-
&& (input.attemptId === undefined
|
|
1442
|
-
? event.payload.raw === error.raw
|
|
1443
|
-
: event.payload.message === error.message
|
|
1444
|
-
&& event.payload.errorName === input.errorName
|
|
1445
|
-
&& event.payload.causeName === input.causeName)));
|
|
1446
|
-
// Re-reading one failed attempt may add a different caller stack, not a
|
|
1447
|
-
// new execution fact. Preserve its first full cause without multiplying
|
|
1448
|
-
// notifications; changed disposition/identity/diagnostic remains visible.
|
|
1449
|
-
if (duplicate !== undefined)
|
|
1450
|
-
return duplicate.id;
|
|
1451
|
-
const event = createTaskEvent(store.nextEventId(input.taskId), input.taskId, "runtime.agent-error", {
|
|
1452
|
-
sourceEventId: `${input.runId}:${input.phase}${input.attemptId === undefined ? "" : `:${input.attemptId}`}`,
|
|
1453
|
-
runId: input.runId,
|
|
1454
|
-
roleName: input.roleName,
|
|
1455
|
-
agentId: run?.effective.agentId ?? session?.agentId ?? "unknown",
|
|
1456
|
-
adapterId: run?.effective.adapterId ?? session?.adapterId ?? "unknown",
|
|
1457
|
-
driverId: driver?.id ?? "unknown",
|
|
1458
|
-
source: error.source,
|
|
1459
|
-
phase: error.phase,
|
|
1460
|
-
category: error.category,
|
|
1461
|
-
code: error.code,
|
|
1462
|
-
message: error.message,
|
|
1463
|
-
raw: error.raw,
|
|
1464
|
-
inputDisposition: error.inputDisposition,
|
|
1465
|
-
sessionDisposition: error.sessionDisposition,
|
|
1466
|
-
// Structured facts from the failing operation. Absent keys stay
|
|
1467
|
-
// absent rather than becoming an empty string, so a reader can tell
|
|
1468
|
-
// "the Host did not report this" from "the Host reported nothing".
|
|
1469
|
-
// The Session identities follow the same rule: this failure can
|
|
1470
|
-
// happen before any Session record exists, and there is no native
|
|
1471
|
-
// AgentRun to name at all.
|
|
1472
|
-
...optionalEventFields({
|
|
1473
|
-
nativeSessionId: session?.nativeSessionId,
|
|
1474
|
-
errorName: input.errorName,
|
|
1475
|
-
causeName: input.causeName,
|
|
1476
|
-
hostState: input.hostState,
|
|
1477
|
-
attemptId: input.attemptId,
|
|
1385
|
+
const { event, created } = recordTaskAgentError(store, {
|
|
1386
|
+
taskId: input.taskId, roleName: input.roleName,
|
|
1387
|
+
sourceEventId: `${input.runId ?? input.attemptId}:${input.phase}${input.runId === undefined || input.attemptId === undefined ? "" : `:${input.attemptId}`}`,
|
|
1388
|
+
agentId: effective?.agentId ?? session?.agentId ?? "unknown",
|
|
1389
|
+
adapterId: effective?.adapterId ?? session?.adapterId ?? "unknown",
|
|
1390
|
+
driverId: driver?.id ?? "unknown", error, effective,
|
|
1391
|
+
evidence: {
|
|
1392
|
+
runId: input.runId, attemptId: input.attemptId, nativeSessionId: session?.nativeSessionId,
|
|
1393
|
+
errorName: input.errorName, causeName: input.causeName, hostState: input.hostState,
|
|
1478
1394
|
registrationDisposition: input.registrationDisposition
|
|
1479
|
-
}
|
|
1395
|
+
}
|
|
1480
1396
|
}, now);
|
|
1481
|
-
|
|
1397
|
+
if (!created)
|
|
1398
|
+
return event.id;
|
|
1399
|
+
if (store.getTask(input.taskId)?.status === "archived")
|
|
1400
|
+
return event.id;
|
|
1482
1401
|
if (input.phase === "turn-submit" && error.inputDisposition === "unknown"
|
|
1483
1402
|
&& input.attemptId !== undefined && sessionSet?.providerBinding?.run?.attemptId === input.attemptId
|
|
1484
1403
|
&& sessionSet.providerBinding.run.status === "submitting") {
|
|
@@ -1492,18 +1411,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
1492
1411
|
return event.id;
|
|
1493
1412
|
const leaderCannotReceive = input.roleName === "leader"
|
|
1494
1413
|
&& ["host-start", "session-start", "session-restore", "turn-submit"].includes(input.phase);
|
|
1495
|
-
|
|
1496
|
-
enqueueWork(store, { kind: "role", taskId: input.taskId, roleName: "leader" }, wakeReason("agent-error", event.id), now, [{ type: "event", taskId: input.taskId, id: event.id }], {
|
|
1497
|
-
source: driver?.id ?? input.source,
|
|
1498
|
-
dedupeKey: `agent-error:${input.taskId}:${input.runId}:${input.phase}:${event.id}`
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
if (leaderCannotReceive) {
|
|
1502
|
-
enqueueWork(store, { kind: "operator" }, "leader-agent-error", now, [{ type: "event", taskId: input.taskId, id: event.id }], {
|
|
1503
|
-
source: driver?.id ?? input.source,
|
|
1504
|
-
dedupeKey: `leader-agent-error:${input.taskId}:${input.runId}:${event.id}`
|
|
1505
|
-
});
|
|
1506
|
-
}
|
|
1414
|
+
enqueueSupervisorEvent(store, event, leaderCannotReceive ? "operator" : "leader", leaderCannotReceive ? "leader-agent-error" : wakeReason("agent-error", event.id), now);
|
|
1507
1415
|
return event.id;
|
|
1508
1416
|
});
|
|
1509
1417
|
}
|
|
@@ -1797,6 +1705,13 @@ export class FileSchedulerStoreAdapter {
|
|
|
1797
1705
|
const task = store.getTask(taskId);
|
|
1798
1706
|
if (task == null || !["active", "draft"].includes(task.status) || task.executionGate.state !== "enabled")
|
|
1799
1707
|
return null;
|
|
1708
|
+
// Admission refuses input while this Session is being cleaned up.
|
|
1709
|
+
// Leave the original batch pending for its successor instead of
|
|
1710
|
+
// claiming a notification that cannot legally reach the Provider.
|
|
1711
|
+
if (hasRuntimeCleanupObligation(store.getWorkMailbox(runtimeLifecycleTarget({
|
|
1712
|
+
scope: "task", taskId, roleName: "leader"
|
|
1713
|
+
}))))
|
|
1714
|
+
return null;
|
|
1800
1715
|
const target = { kind: "role", taskId, roleName: "leader" };
|
|
1801
1716
|
let mailbox = store.getWorkMailbox(target);
|
|
1802
1717
|
if (mailbox === null)
|
|
@@ -1822,8 +1737,10 @@ export class FileSchedulerStoreAdapter {
|
|
|
1822
1737
|
return null;
|
|
1823
1738
|
}
|
|
1824
1739
|
if (native?.status === "rejected" || previous?.payload.outcome === "rejected") {
|
|
1825
|
-
|
|
1826
|
-
|
|
1740
|
+
if (previous?.payload.outcome !== "rejected") {
|
|
1741
|
+
this.settleLeaderNotification(taskId, attemptId, "rejected", now);
|
|
1742
|
+
}
|
|
1743
|
+
return { wakeId, attemptId, disposition: "rejected" };
|
|
1827
1744
|
}
|
|
1828
1745
|
if (native?.status === "submitting")
|
|
1829
1746
|
return { wakeId, attemptId, disposition: "pending" };
|
|
@@ -1898,7 +1815,7 @@ export class FileSchedulerStoreAdapter {
|
|
|
1898
1815
|
return { wakeId, attemptId, disposition: "submit" };
|
|
1899
1816
|
});
|
|
1900
1817
|
}
|
|
1901
|
-
settleLeaderNotification(taskId, attemptId, outcome, now, detail) {
|
|
1818
|
+
settleLeaderNotification(taskId, attemptId, outcome, now, detail, failure) {
|
|
1902
1819
|
this.store.transaction((store) => {
|
|
1903
1820
|
const target = { kind: "role", taskId, roleName: "leader" };
|
|
1904
1821
|
const mailbox = store.getWorkMailbox(target);
|
|
@@ -1908,19 +1825,35 @@ export class FileSchedulerStoreAdapter {
|
|
|
1908
1825
|
return;
|
|
1909
1826
|
if (!store.listEvents(taskId).some((event) => event.type === "notification.delivery"
|
|
1910
1827
|
&& event.payload.attemptId === attemptId && event.payload.outcome === outcome)) {
|
|
1911
|
-
|
|
1828
|
+
// Native ingress may already have persisted the same rejection. Reuse
|
|
1829
|
+
// that original failure rather than reporting it twice from the caller.
|
|
1830
|
+
const existing = store.listEventsByType(taskId, ["runtime.agent-error"])
|
|
1831
|
+
.find(event => event.payload.roleName === "leader"
|
|
1832
|
+
&& (event.payload.attemptId === attemptId || event.payload.sourceEventId === attemptId));
|
|
1833
|
+
const errorEventId = existing?.id ?? (failure !== undefined
|
|
1834
|
+
&& (outcome === "rejected" || outcome === "unknown")
|
|
1835
|
+
? this.recordAgentError({
|
|
1836
|
+
taskId, roleName: "leader", attemptId, effective: failure.effective,
|
|
1837
|
+
source: "host", phase: failure.phase,
|
|
1838
|
+
message: detail ?? `Notification ${outcome}.`, raw: failure.raw,
|
|
1839
|
+
inputDisposition: outcome === "unknown" ? "unknown" : "not-accepted",
|
|
1840
|
+
...(failure.phase === "session-start" ? { registrationDisposition: "not-committed" } : {})
|
|
1841
|
+
}, now) : undefined);
|
|
1842
|
+
store.saveEvent(taskId, createTaskEvent(store.nextEventId(taskId), taskId, "notification.delivery", { attemptId, outcome, ...(detail === undefined ? {} : { detail }),
|
|
1843
|
+
...(errorEventId === undefined ? {} : { errorEventId }) }, now));
|
|
1912
1844
|
}
|
|
1913
1845
|
if (store.getTask(taskId)?.status === "archived")
|
|
1914
1846
|
return;
|
|
1915
|
-
|
|
1847
|
+
// Rejection proves nondelivery, not consumption of the original input.
|
|
1848
|
+
// Keep the exact claim as the existing recovery/completion boundary.
|
|
1849
|
+
// An explicit retry or Session replacement can release it later.
|
|
1850
|
+
if (outcome !== "accepted")
|
|
1916
1851
|
return;
|
|
1917
1852
|
store.saveWorkMailbox(completeProcessing(mailbox, attemptId));
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
store.saveTaskWake(taskId, markTaskWakeConsumed(wake, now));
|
|
1923
|
-
}
|
|
1853
|
+
const wakeId = processing.owner.slice("leader-notification:".length);
|
|
1854
|
+
const wake = store.listTaskWakes(taskId).find((entry) => entry.id === wakeId);
|
|
1855
|
+
if (wake !== undefined)
|
|
1856
|
+
store.saveTaskWake(taskId, markTaskWakeConsumed(wake, now));
|
|
1924
1857
|
});
|
|
1925
1858
|
}
|
|
1926
1859
|
saveRoleRunPrepared(input) {
|
|
@@ -2132,12 +2065,6 @@ export class FileSchedulerStoreAdapter {
|
|
|
2132
2065
|
let sessions = store.getTaskRoleSessionSet(input.taskId, input.roleName)
|
|
2133
2066
|
?? createRoleSessionSet({ scope: "task", taskId: input.taskId, roleName: input.roleName }, input.agentId, now);
|
|
2134
2067
|
const canonicalRunId = input.nativeTurnId ?? resolved.nativeTurnId;
|
|
2135
|
-
const existing = sessions.sessions[input.agentId];
|
|
2136
|
-
const owner = {
|
|
2137
|
-
scope: "task",
|
|
2138
|
-
taskId: input.taskId,
|
|
2139
|
-
roleName: input.roleName
|
|
2140
|
-
};
|
|
2141
2068
|
assertConsistentTerminal(store, input, observedRun);
|
|
2142
2069
|
// A historical operation failure stays failed. The immutable terminal
|
|
2143
2070
|
// observation retains the late report for explicit Leader adoption.
|
|
@@ -3210,28 +3137,6 @@ function requireRole(store, taskId, roleName) {
|
|
|
3210
3137
|
throw new Error(`Role not found: ${taskId}/${roleName}.`);
|
|
3211
3138
|
return role;
|
|
3212
3139
|
}
|
|
3213
|
-
function runLaunchEventPayload(run) {
|
|
3214
|
-
return {
|
|
3215
|
-
runId: run.id,
|
|
3216
|
-
role: run.roleName,
|
|
3217
|
-
purpose: run.purpose,
|
|
3218
|
-
mode: run.mode,
|
|
3219
|
-
agent: `${run.effective.agentId}/${run.effective.adapterId}`,
|
|
3220
|
-
component: run.effective.component,
|
|
3221
|
-
effectiveRevision: String(run.effective.sourceDesiredRevision),
|
|
3222
|
-
profileAccess: run.effective.profileAccess,
|
|
3223
|
-
effectivePermission: run.effective.permission.strategy,
|
|
3224
|
-
writeProjectIds: run.effective.writeProjectIds.join(",") || "none"
|
|
3225
|
-
};
|
|
3226
|
-
}
|
|
3227
|
-
/**
|
|
3228
|
-
* Keeps only the fields the caller actually knew. Event payloads are a
|
|
3229
|
-
* string map, so an unknown fact has to be an absent key: writing `""` would
|
|
3230
|
-
* claim the Host reported an empty value.
|
|
3231
|
-
*/
|
|
3232
|
-
function optionalEventFields(fields) {
|
|
3233
|
-
return Object.fromEntries(Object.entries(fields).filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0));
|
|
3234
|
-
}
|
|
3235
3140
|
function runtimeObservationTelemetryEntry(input) {
|
|
3236
3141
|
return {
|
|
3237
3142
|
taskId: input.fence.taskId,
|