@zq-silk/yui 0.13.9 → 0.14.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 +69 -428
- package/README.md +108 -298
- package/dist/agent/managedRuntimeEnvironment.js +2 -2
- package/dist/cli/commandCatalog.js +39 -77
- package/dist/cli/interactionCandidates.js +4 -4
- package/dist/cli/interactionPolicy.js +7 -10
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/updateCommand.js +6 -27
- package/dist/cli/updateOrchestrator.js +63 -484
- package/dist/cli/updatePorts.js +15 -333
- package/dist/cli/upgradeCommand.js +8 -65
- package/dist/cli.js +57 -242
- package/dist/commands/configCommands.js +11 -62
- package/dist/commands/executionAuditCommands.js +23 -23
- package/dist/commands/globalRoleCommands.js +2 -7
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/projectCommands.js +5 -5
- package/dist/commands/releaseCommands.js +3 -10
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/sessionCommands.js +2 -2
- package/dist/commands/taskActor.js +31 -39
- package/dist/commands/taskChangeSetCommands.js +5 -12
- package/dist/commands/taskCommands.js +464 -1249
- package/dist/commands/taskContextCommand.js +35 -36
- package/dist/commands/taskExecutionCommands.js +33 -46
- package/dist/commands/taskInputCommands.js +20 -42
- package/dist/commands/taskNextActionCommand.js +9 -9
- package/dist/commands/taskOverviewCommand.js +56 -95
- package/dist/commands/taskRoleRuntimeStatus.js +77 -107
- package/dist/commands/taskUpstreamCommands.js +3 -3
- package/dist/commands/taskWorkspaceCommands.js +7 -79
- package/dist/commands/telemetryCommands.js +32 -124
- package/dist/commands/workflowCommands.js +3 -3
- package/dist/completion/fileCompletionManager.js +1 -1
- package/dist/config/configCatalog.js +4 -6
- package/dist/config/yuiConfig.js +6 -43
- package/dist/context/dispatchContext.js +14 -30
- package/dist/context/roleSessionContext.js +2 -2
- package/dist/context/sessionBootstrapManifest.js +2 -2
- package/dist/context/{runContextPack.js → turnContextPack.js} +58 -73
- package/dist/context/turnInputContract.js +204 -0
- package/dist/context/wakeNotification.js +2 -2
- package/dist/controller/agentRuntimeObserver.js +18 -18
- package/dist/controller/clientRuntime.js +13 -20
- package/dist/controller/controller.js +89 -116
- package/dist/controller/fileSchedulerStoreAdapter.js +511 -742
- package/dist/controller/jobControl.js +17 -17
- package/dist/controller/resourceInventory.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +38 -59
- package/dist/controller/resourceInventoryRpc.js +3 -3
- package/dist/controller/resourceInventoryWorker.js +1 -1
- package/dist/controller/runtime.js +46 -53
- package/dist/controller/runtimeEventInbox.js +23 -31
- package/dist/controller/runtimeEventProcessor.js +15 -15
- package/dist/controller/{runtimeHookRunFence.js → runtimeHookTurnFence.js} +87 -81
- package/dist/controller/runtimeLaunchCoordinator.js +3 -3
- package/dist/controller/runtimeObservationHook.js +11 -8
- package/dist/controller/sessionNotify.js +11 -11
- package/dist/controller/structuredProviderObservation.js +89 -16
- package/dist/coordination/workMailbox.js +309 -579
- package/dist/coordination/workMailboxQueue.js +5 -6
- package/dist/core/controllerClient.js +1 -91
- package/dist/core/controllerServer.js +3 -6
- package/dist/doctor/doctor.js +51 -314
- package/dist/execution/candidateConvergence.js +3 -3
- package/dist/execution/executionGroup.js +32 -33
- package/dist/execution/executionHealth.js +36 -38
- package/dist/execution/resourceBroker.js +12 -12
- package/dist/executor/agentExecutor.js +30 -265
- package/dist/executor/effectiveLaunch.js +9 -19
- package/dist/executor/executorRegistry.js +43 -17
- package/dist/executor/fileRoleLaunchPlanner.js +56 -56
- package/dist/executor/launchPlan.js +3 -3
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +20 -25
- package/dist/input/inputRequest.js +12 -12
- package/dist/integration/changeSet.js +9 -13
- package/dist/integration/changeSetManifest.js +1 -1
- package/dist/integration/gitIntegrationService.js +2 -2
- package/dist/integration/integrationQueueService.js +5 -21
- package/dist/integration/overlapDiagnostics.js +2 -2
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/job/jobRunner.js +1 -1
- package/dist/lifecycle/canonicalLifecycleEvent.js +25 -25
- package/dist/lifecycle/{exactRunTerminalization.js → exactTurnTerminalization.js} +116 -232
- package/dist/message/message.js +6 -6
- package/dist/observability/executionAudit.js +74 -86
- package/dist/observability/faultClassification.js +7 -24
- package/dist/observability/orchestrationMetrics.js +5 -5
- package/dist/observability/runtimeIdentity.js +34 -101
- package/dist/profile/agentProfile.js +1 -1
- package/dist/release/cliHomeReleaseFence.js +3 -3
- package/dist/release/releaseWorkflowEngine.js +6 -10
- package/dist/release/releaseWorkflowPorts.js +2 -2
- package/dist/release/workflowFileLock.js +1 -1
- package/dist/repository/checkoutSwap.js +1 -1
- package/dist/repository/gitWorkspace.js +0 -13
- package/dist/repository/project.js +1 -1
- package/dist/repository/projectMaintenanceLock.js +1 -2
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +21 -25
- package/dist/repository/taskWorkspaceIdentity.js +8 -21
- package/dist/repository/taskWorkspacePreparer.js +63 -620
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +1 -1
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/sqliteResourceRegistry.js +1 -1
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewFindingLedger.js +1 -1
- package/dist/review/reviewOutcomeClassifier.js +35 -50
- package/dist/review/reviewRound.js +14 -25
- package/dist/review/reviewerAvailability.js +4 -4
- package/dist/review/taskFinalReviewContractResolution.js +41 -0
- package/dist/role/role.js +6 -3
- package/dist/runtime/agentDriver.js +4 -0
- package/dist/runtime/agentHost.js +151 -36
- package/dist/runtime/builtinAgentDrivers.js +79 -2
- package/dist/runtime/codexAppServerRuntime.js +122 -0
- package/dist/runtime/continuationManager.js +3 -5
- package/dist/runtime/exactControlPlane.js +17 -42
- package/dist/runtime/firstProgressAdvisory.js +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +4 -4
- package/dist/runtime/processExitObservation.js +1 -1
- package/dist/runtime/processExitOutbox.js +0 -32
- package/dist/runtime/promptEnvelope.js +9 -9
- package/dist/runtime/providerContinuation.js +2 -2
- package/dist/runtime/providerContinuationReconciliationService.js +2 -2
- package/dist/runtime/providerRuntimeIdentity.js +76 -24
- package/dist/runtime/recentTurnIds.js +38 -0
- package/dist/runtime/runtimeContinuationProjection.js +2 -2
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +58 -21
- package/dist/runtime/runtimeProjection.js +19 -27
- package/dist/runtime/sessionLaunchRequest.js +2 -2
- package/dist/runtime/structuredProviderHost.js +177 -12
- package/dist/runtime/tmuxAdapters.js +46 -11
- package/dist/scheduler/activeRoleTurnDelivery.js +245 -0
- package/dist/scheduler/leaderWakeupProcessor.js +147 -445
- package/dist/scheduler/operatorEvent.js +4 -6
- package/dist/scheduler/resourceQueueProjection.js +71 -0
- package/dist/scheduler/{roleRunLiveness.js → roleTurnLiveness.js} +24 -28
- package/dist/scheduler/{roleRunStall.js → roleTurnStall.js} +162 -247
- package/dist/scheduler/taskExecutionProjection.js +99 -99
- package/dist/scheduler/taskObservabilityProjection.js +10 -10
- package/dist/scheduler/taskWake.js +4 -4
- package/dist/scheduler/wakeReason.js +6 -10
- package/dist/scheduler/wakeupQueue.js +0 -9
- package/dist/setup/setupCommand.js +2 -2
- package/dist/storage/currentTaskStore.js +46 -0
- package/dist/storage/persistenceWorker.js +1 -1
- package/dist/storage/sqliteSchema.js +81 -485
- package/dist/storage/sqliteStore.js +206 -365
- package/dist/storage/storageSchema.js +1 -15
- package/dist/storage/storageVersions.js +8 -9
- package/dist/storage/storeRpc.js +10 -34
- package/dist/storage/taskStore.js +63 -3415
- package/dist/storage/upgrade/recordVersions.js +55 -149
- package/dist/storage/upgrade/upgradeOrchestrator.js +89 -1752
- package/dist/task/completionReadiness.js +5 -5
- package/dist/task/deliveryGuard.js +10 -10
- package/dist/task/nextAction.js +74 -77
- package/dist/task/task.js +2 -4
- package/dist/task/taskRecordReference.js +3 -3
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/telemetry/sqliteTelemetryStore.js +53 -53
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +8 -14
- package/dist/turn/turn.js +356 -0
- package/dist/{run/runIdentity.js → turn/turnIdentity.js} +4 -4
- package/dist/verification/gateArtifactStore.js +2 -2
- package/dist/web/assets/client/app.js +1 -1
- package/dist/web/assets/client/components.js +29 -54
- package/dist/web/assets/client/i18n.js +17 -37
- package/dist/web/assets/client/view.js +37 -37
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +5 -5
- package/dist/web/assets/styles/widgets.js +1 -2
- package/dist/web/webSnapshot.js +65 -60
- package/dist/workItem/workItem.js +11 -11
- package/dist/workspace/workItemChangeSetManager.js +1 -1
- package/docs/task-local-identity.md +5 -5
- package/i18n/README.zh-CN.md +41 -54
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +85 -83
- package/skills/yui-operator/SKILL.md +16 -16
- package/skills/yui-reviewer/SKILL.md +10 -10
- package/skills/yui-runtime/SKILL.md +17 -18
- package/skills/yui-worker/SKILL.md +16 -18
- package/dist/context/runContextContract.js +0 -162
- package/dist/executor/turnCompletion.js +0 -126
- package/dist/review/taskFinalReviewContractEvent.js +0 -1
- package/dist/review/taskFinalReviewContractRebind.js +0 -367
- package/dist/run/agentRun.js +0 -356
- package/dist/run/rejectedYieldAttempt.js +0 -221
- package/dist/run/runControlRequest.js +0 -50
- package/dist/run/yieldReceipt.js +0 -65
- package/dist/runtime/turnCompletion.js +0 -3
- package/dist/scheduler/actionability.js +0 -323
- package/dist/scheduler/activeRoleRunDelivery.js +0 -868
- package/dist/scheduler/activeTaskProgress.js +0 -126
- package/dist/storage/compatibleTaskStore.js +0 -248
- package/dist/storage/migration/baseline.js +0 -78
- package/dist/storage/migration/classifier.js +0 -51
- package/dist/storage/migration/compatibleCodec.js +0 -53
- package/dist/storage/migration/engine.js +0 -147
- package/dist/storage/migration/index.js +0 -33
- package/dist/storage/migration/planner.js +0 -154
- package/dist/storage/migration/productionRegistry.js +0 -3931
- package/dist/storage/migration/registry.js +0 -169
- package/dist/storage/migration/report.js +0 -54
- package/dist/storage/migration/types.js +0 -31
- package/dist/storage/upgrade/homeClassification.js +0 -353
- package/dist/storage/upgrade/homeMigrationTarget.js +0 -595
- package/dist/storage/upgrade/migrationReceipt.js +0 -67
- package/dist/storage/upgrade/offlineUpgradeInventory.js +0 -453
- package/dist/storage/upgrade/productionMigrationRegistry.js +0 -6
- package/dist/storage/upgrade/pseudoLayoutRepair.js +0 -241
- package/dist/storage/upgrade/recordVersionScan.js +0 -176
- package/dist/storage/upgrade/sqliteFileSet.js +0 -50
- package/dist/storage/upgrade/sqliteMigrationTarget.js +0 -375
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +0 -305
- package/dist/storage/upgrade/sqliteStateMigration.js +0 -918
- package/dist/storage/upgrade/switchProgress.js +0 -80
- package/dist/storage/upgrade/upgradeReceipt.js +0 -161
- package/dist/storage/upgradeCoordination.js +0 -187
- package/dist/storage/upgradeFence.js +0 -366
- package/dist/telemetry/telemetryCompaction.js +0 -252
|
@@ -1,868 +0,0 @@
|
|
|
1
|
-
import { selectedSchedulerRoles, selectedActiveSchedulerTasks } from "./ports.js";
|
|
2
|
-
import { isSchedulerTaskWorkspaceReady } from "./ports.js";
|
|
3
|
-
import { formatAgentRunReceiptId } from "../task/taskRecordReference.js";
|
|
4
|
-
import { agentRunDeliveryReceiptId } from "../run/agentRun.js";
|
|
5
|
-
import { serializeRunBootstrapEnvelope, serializeRunHostRecoveryEnvelope } from "../context/runContextContract.js";
|
|
6
|
-
import { serializeWorkflowOutcomeRequestEnvelope } from "../run/runControlRequest.js";
|
|
7
|
-
import { effectiveLaunchSnapshotsCompatible, effectiveLaunchSnapshotsCompatibleForTaskSession } from "../executor/effectiveLaunch.js";
|
|
8
|
-
import { RuntimeLaunchError } from "../runtime/ports.js";
|
|
9
|
-
import { RuntimeLaunchFailure } from "../runtime/launchDiagnostics.js";
|
|
10
|
-
import { mailboxHasWork, nextPendingBatch } from "../coordination/workMailbox.js";
|
|
11
|
-
import { runtimeObservationFromTaskEvent } from "../runtime/runtimeObservation.js";
|
|
12
|
-
import { projectProviderContinuations } from "../runtime/runtimeContinuationProjection.js";
|
|
13
|
-
import { RuntimeLifecycleBusyError } from "../runtime/lifecycleReservation.js";
|
|
14
|
-
import { serializeAgentErrorRaw } from "../runtime/agentError.js";
|
|
15
|
-
/**
|
|
16
|
-
* Delivers durable Work AgentRuns before liveness reconciliation. Task command
|
|
17
|
-
* handlers only record intent; this Controller path is the sole automated
|
|
18
|
-
* route into the Agent terminal, through tmux receipt-backed delivery.
|
|
19
|
-
*/
|
|
20
|
-
export async function processActiveRoleRunDeliveries(store, delivery, now, selection, inputDeliveryRecoveryCutoff) {
|
|
21
|
-
const results = [];
|
|
22
|
-
for (const task of selectedActiveSchedulerTasks(store, selection)) {
|
|
23
|
-
for (const role of selectedSchedulerRoles(store, task.id, selection)) {
|
|
24
|
-
const run = store.getActiveAgentRun(task.id, role.name);
|
|
25
|
-
if (run !== null && run.pushedAt !== undefined
|
|
26
|
-
&& run.controlRequest?.state !== "dispatching") {
|
|
27
|
-
const continuation = await processActiveRunContinuation(store, delivery, task, role, run, now, inputDeliveryRecoveryCutoff);
|
|
28
|
-
if (continuation !== null)
|
|
29
|
-
results.push(continuation);
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
// A crash after a Leader wake is durably claimed but before tmux input
|
|
33
|
-
// is recoverable through the same receipt-backed delivery path. The
|
|
34
|
-
// re-push guard keys on pushedAt (transport), not deliveredAt (provider
|
|
35
|
-
// acceptance): a pushed-but-unaccepted Run must never be pushed twice —
|
|
36
|
-
// no duplicate Enter while acceptance is still pending.
|
|
37
|
-
if (run === null
|
|
38
|
-
|| (run.pushedAt !== undefined
|
|
39
|
-
&& run.controlRequest?.state !== "dispatching"))
|
|
40
|
-
continue;
|
|
41
|
-
const taskWorkspace = store.getTaskWorkspace(task.id);
|
|
42
|
-
if (!isSchedulerTaskWorkspaceReady(task, taskWorkspace)) {
|
|
43
|
-
results.push({
|
|
44
|
-
taskId: task.id,
|
|
45
|
-
roleName: role.name,
|
|
46
|
-
runId: run.id,
|
|
47
|
-
status: "skipped",
|
|
48
|
-
reason: "workspace-not-ready"
|
|
49
|
-
});
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
// Recovery can expose an unpushed Run while an older Provider Turn is
|
|
53
|
-
// still settling. Preserve the Run and its mailbox claim without even
|
|
54
|
-
// touching the Host; terminal observation will wake the next pass.
|
|
55
|
-
if (providerTurnIsUnsettled(store, task.id, role.name)) {
|
|
56
|
-
results.push({
|
|
57
|
-
taskId: task.id,
|
|
58
|
-
roleName: role.name,
|
|
59
|
-
runId: run.id,
|
|
60
|
-
status: "skipped",
|
|
61
|
-
reason: "not-ready"
|
|
62
|
-
});
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
const existingSession = store.getRoleSession(task.id, role.name, run.effective.agentId);
|
|
66
|
-
const receiptId = agentRunDeliveryReceiptId(run);
|
|
67
|
-
const target = { kind: "role", taskId: task.id, roleName: role.name };
|
|
68
|
-
const claim = store.claimWorkMailbox({
|
|
69
|
-
target,
|
|
70
|
-
batchId: receiptId,
|
|
71
|
-
owner: "controller",
|
|
72
|
-
now,
|
|
73
|
-
executionRef: { type: "run", taskId: task.id, id: run.id }
|
|
74
|
-
});
|
|
75
|
-
if (claim.status === "empty") {
|
|
76
|
-
results.push({
|
|
77
|
-
taskId: task.id,
|
|
78
|
-
roleName: role.name,
|
|
79
|
-
runId: run.id,
|
|
80
|
-
status: "skipped",
|
|
81
|
-
reason: "mailbox-empty"
|
|
82
|
-
});
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
const processing = claim.processing;
|
|
86
|
-
if (processing.executionRef?.type !== "run"
|
|
87
|
-
|| processing.executionRef.taskId !== task.id
|
|
88
|
-
|| processing.executionRef.id !== run.id) {
|
|
89
|
-
results.push({
|
|
90
|
-
taskId: task.id,
|
|
91
|
-
roleName: role.name,
|
|
92
|
-
runId: run.id,
|
|
93
|
-
status: "skipped",
|
|
94
|
-
reason: "mailbox-busy"
|
|
95
|
-
});
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
let prepared;
|
|
99
|
-
let preStartFencePersisted = false;
|
|
100
|
-
let deliveryAttempted = false;
|
|
101
|
-
const launchMode = run.controlRequest?.state === "dispatching"
|
|
102
|
-
? "resume"
|
|
103
|
-
: run.mode;
|
|
104
|
-
try {
|
|
105
|
-
// Workflow-outcome control is always another Turn on the already-bound
|
|
106
|
-
// Session. A fresh Session is selected only by the Run created after
|
|
107
|
-
// the prior Session was explicitly ended.
|
|
108
|
-
const nativeSessionId = launchMode === "resume"
|
|
109
|
-
? requireResumeSession(role, run.effective, existingSession)
|
|
110
|
-
: undefined;
|
|
111
|
-
prepared = await delivery.prepareRoleSession({
|
|
112
|
-
taskId: task.id,
|
|
113
|
-
roleName: role.name,
|
|
114
|
-
agentId: run.effective.agentId,
|
|
115
|
-
adapterId: run.effective.adapterId,
|
|
116
|
-
effective: run.effective,
|
|
117
|
-
workspace: run.effective.workspace.root,
|
|
118
|
-
...(run.workspace === undefined
|
|
119
|
-
? {}
|
|
120
|
-
: { managedWorkspace: run.workspace }),
|
|
121
|
-
mode: launchMode,
|
|
122
|
-
runId: run.id,
|
|
123
|
-
...(nativeSessionId === undefined ? {} : { nativeSessionId }),
|
|
124
|
-
...(launchMode !== "resume" || existingSession?.launchId === undefined
|
|
125
|
-
? {}
|
|
126
|
-
: { hostActivationId: existingSession.launchId }),
|
|
127
|
-
beforeHostStart: (preflight) => {
|
|
128
|
-
persistPreStartFence(store, task, role, run, existingSession, preflight, now);
|
|
129
|
-
preflightSession(role, run.effective, existingSession, launchMode, preflight);
|
|
130
|
-
preStartFencePersisted = true;
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
// Persist the Session identity before submitting any Turn. Host start
|
|
134
|
-
// and Session restore are complete lifecycle operations; neither owns
|
|
135
|
-
// nor implies the Run's first Provider write.
|
|
136
|
-
if (!preStartFencePersisted) {
|
|
137
|
-
const preparedFenceSession = validateLaunchSubmittedRecoverySession(role, run.effective, existingSession, launchMode, prepared.session);
|
|
138
|
-
store.saveRoleRunPrepared({
|
|
139
|
-
task,
|
|
140
|
-
role,
|
|
141
|
-
run,
|
|
142
|
-
session: preparedFenceSession,
|
|
143
|
-
...(prepared.launchId === undefined ? {} : { launchId: prepared.launchId }),
|
|
144
|
-
now
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
const ready = await delivery.waitUntilReady(prepared);
|
|
148
|
-
const session = validateLaunchSubmittedRecoverySession(role, run.effective, existingSession, launchMode, ready.session);
|
|
149
|
-
store.saveRoleRunPrepared({
|
|
150
|
-
task,
|
|
151
|
-
role,
|
|
152
|
-
run,
|
|
153
|
-
session,
|
|
154
|
-
...(ready.prepared.launchId === undefined
|
|
155
|
-
? {}
|
|
156
|
-
: { launchId: ready.prepared.launchId }),
|
|
157
|
-
now
|
|
158
|
-
});
|
|
159
|
-
deliveryAttempted = true;
|
|
160
|
-
const outcome = await delivery.sendOnce({
|
|
161
|
-
delivery: ready,
|
|
162
|
-
receiptId,
|
|
163
|
-
text: initialRunTurnInput(run)
|
|
164
|
-
});
|
|
165
|
-
if (outcome === "busy" || outcome === "unavailable") {
|
|
166
|
-
delivery.forgetPrepared?.({
|
|
167
|
-
taskId: task.id,
|
|
168
|
-
roleName: role.name,
|
|
169
|
-
runId: run.id,
|
|
170
|
-
...(ready.prepared.launchId === undefined
|
|
171
|
-
? {}
|
|
172
|
-
: { launchId: ready.prepared.launchId })
|
|
173
|
-
});
|
|
174
|
-
results.push({
|
|
175
|
-
taskId: task.id,
|
|
176
|
-
roleName: role.name,
|
|
177
|
-
runId: run.id,
|
|
178
|
-
status: "skipped",
|
|
179
|
-
reason: outcome === "busy" ? "not-ready" : "runtime-unavailable"
|
|
180
|
-
});
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
if (outcome === "rejected") {
|
|
184
|
-
const terminal = store.saveRoleRunDeliveryFailure({
|
|
185
|
-
taskId: task.id,
|
|
186
|
-
roleName: role.name,
|
|
187
|
-
agentId: run.effective.agentId,
|
|
188
|
-
adapterId: run.effective.adapterId,
|
|
189
|
-
runId: run.id,
|
|
190
|
-
mailboxBatchId: processing.batchId,
|
|
191
|
-
...(session?.nativeSessionId === undefined
|
|
192
|
-
? {}
|
|
193
|
-
: { nativeSessionId: session.nativeSessionId }),
|
|
194
|
-
...(ready.prepared.launchId === undefined
|
|
195
|
-
? {}
|
|
196
|
-
: { launchId: ready.prepared.launchId }),
|
|
197
|
-
summary: "Provider rejected the Turn before acceptance; Agent recovery is required.",
|
|
198
|
-
cleanupRequired: false,
|
|
199
|
-
now
|
|
200
|
-
});
|
|
201
|
-
delivery.forgetPrepared?.({
|
|
202
|
-
taskId: task.id,
|
|
203
|
-
roleName: role.name,
|
|
204
|
-
runId: run.id,
|
|
205
|
-
...(ready.prepared.launchId === undefined
|
|
206
|
-
? {}
|
|
207
|
-
: { launchId: ready.prepared.launchId })
|
|
208
|
-
});
|
|
209
|
-
results.push({
|
|
210
|
-
taskId: task.id,
|
|
211
|
-
roleName: role.name,
|
|
212
|
-
runId: run.id,
|
|
213
|
-
status: terminal === "failed" ? "failed" : "skipped",
|
|
214
|
-
reason: "provider-rejected",
|
|
215
|
-
...(terminal === "failed" ? { terminalized: true } : {})
|
|
216
|
-
});
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
if (outcome === "delivery-unknown") {
|
|
220
|
-
store.saveRoleRunDelivery({
|
|
221
|
-
task,
|
|
222
|
-
role,
|
|
223
|
-
run,
|
|
224
|
-
session,
|
|
225
|
-
...(ready.prepared.launchId === undefined
|
|
226
|
-
? {}
|
|
227
|
-
: { launchId: ready.prepared.launchId }),
|
|
228
|
-
now
|
|
229
|
-
});
|
|
230
|
-
delivery.forgetPrepared?.({
|
|
231
|
-
taskId: task.id,
|
|
232
|
-
roleName: role.name,
|
|
233
|
-
runId: run.id,
|
|
234
|
-
...(ready.prepared.launchId === undefined
|
|
235
|
-
? {}
|
|
236
|
-
: { launchId: ready.prepared.launchId })
|
|
237
|
-
});
|
|
238
|
-
results.push({
|
|
239
|
-
taskId: task.id,
|
|
240
|
-
roleName: role.name,
|
|
241
|
-
runId: run.id,
|
|
242
|
-
status: "skipped",
|
|
243
|
-
reason: "delivery-uncertain"
|
|
244
|
-
});
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
store.saveRoleRunDelivery({
|
|
248
|
-
task,
|
|
249
|
-
role,
|
|
250
|
-
run,
|
|
251
|
-
session,
|
|
252
|
-
...(ready.prepared.launchId === undefined
|
|
253
|
-
? {}
|
|
254
|
-
: { launchId: ready.prepared.launchId }),
|
|
255
|
-
now
|
|
256
|
-
});
|
|
257
|
-
delivery.forgetPrepared?.({
|
|
258
|
-
taskId: task.id,
|
|
259
|
-
roleName: role.name,
|
|
260
|
-
runId: run.id,
|
|
261
|
-
...(ready.prepared.launchId === undefined
|
|
262
|
-
? {}
|
|
263
|
-
: { launchId: ready.prepared.launchId })
|
|
264
|
-
});
|
|
265
|
-
results.push({
|
|
266
|
-
taskId: task.id,
|
|
267
|
-
roleName: role.name,
|
|
268
|
-
runId: run.id,
|
|
269
|
-
status: outcome === "sent" ? "delivered" : "already-delivered"
|
|
270
|
-
});
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
catch (error) {
|
|
274
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
275
|
-
// Scheduler single-flight backpressure: the Role runtime lifecycle
|
|
276
|
-
// lane was busy when the launch was reserved. The Run stays
|
|
277
|
-
// active-unpushed and its mailbox claim is retained; the next pass
|
|
278
|
-
// retries after the lane settles. This is contention before any
|
|
279
|
-
// semantic launch, never a Run failure.
|
|
280
|
-
if (error instanceof RuntimeLifecycleBusyError) {
|
|
281
|
-
delivery.forgetPrepared?.({
|
|
282
|
-
taskId: task.id,
|
|
283
|
-
roleName: role.name,
|
|
284
|
-
runId: run.id
|
|
285
|
-
});
|
|
286
|
-
results.push({
|
|
287
|
-
taskId: task.id,
|
|
288
|
-
roleName: role.name,
|
|
289
|
-
runId: run.id,
|
|
290
|
-
status: "skipped",
|
|
291
|
-
reason: "runtime-unavailable",
|
|
292
|
-
error: message
|
|
293
|
-
});
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
store.recordAgentError?.({
|
|
297
|
-
taskId: task.id,
|
|
298
|
-
roleName: role.name,
|
|
299
|
-
runId: run.id,
|
|
300
|
-
source: error instanceof RuntimeLaunchError || error instanceof RuntimeLaunchFailure
|
|
301
|
-
? "host"
|
|
302
|
-
: "yui",
|
|
303
|
-
phase: deliveryAttempted
|
|
304
|
-
? "turn-submit"
|
|
305
|
-
: launchMode === "new" ? "session-start" : "session-restore",
|
|
306
|
-
message,
|
|
307
|
-
raw: serializeAgentErrorRaw(error),
|
|
308
|
-
inputDisposition: deliveryAttempted ? "unknown" : "not-accepted"
|
|
309
|
-
}, now);
|
|
310
|
-
if (!deliveryAttempted) {
|
|
311
|
-
const failedSession = store.getRoleSession(task.id, role.name, run.effective.agentId);
|
|
312
|
-
const terminal = store.saveRoleRunDeliveryFailure({
|
|
313
|
-
taskId: task.id,
|
|
314
|
-
roleName: role.name,
|
|
315
|
-
agentId: run.effective.agentId,
|
|
316
|
-
adapterId: run.effective.adapterId,
|
|
317
|
-
runId: run.id,
|
|
318
|
-
mailboxBatchId: processing.batchId,
|
|
319
|
-
...(failedSession?.nativeSessionId === undefined
|
|
320
|
-
? {}
|
|
321
|
-
: { nativeSessionId: failedSession.nativeSessionId }),
|
|
322
|
-
...(prepared?.launchId === undefined && failedSession?.launchId === undefined
|
|
323
|
-
? {}
|
|
324
|
-
: { launchId: prepared?.launchId ?? failedSession.launchId }),
|
|
325
|
-
summary: `Agent Session preparation failed before Turn acceptance: ${message}`,
|
|
326
|
-
cleanupRequired: false,
|
|
327
|
-
now
|
|
328
|
-
});
|
|
329
|
-
if (terminal === "failed") {
|
|
330
|
-
delivery.forgetPrepared?.({
|
|
331
|
-
taskId: task.id,
|
|
332
|
-
roleName: role.name,
|
|
333
|
-
runId: run.id,
|
|
334
|
-
...(prepared?.launchId === undefined
|
|
335
|
-
? {}
|
|
336
|
-
: { launchId: prepared.launchId })
|
|
337
|
-
});
|
|
338
|
-
results.push({
|
|
339
|
-
taskId: task.id,
|
|
340
|
-
roleName: role.name,
|
|
341
|
-
runId: run.id,
|
|
342
|
-
status: "failed",
|
|
343
|
-
reason: "launch-failed",
|
|
344
|
-
error: message,
|
|
345
|
-
terminalized: true
|
|
346
|
-
});
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
if (error instanceof RuntimeLaunchFailure) {
|
|
351
|
-
if (!deliveryAttempted) {
|
|
352
|
-
delivery.forgetPrepared?.({
|
|
353
|
-
taskId: task.id,
|
|
354
|
-
roleName: role.name,
|
|
355
|
-
runId: run.id,
|
|
356
|
-
...(prepared?.launchId === undefined
|
|
357
|
-
? {}
|
|
358
|
-
: { launchId: prepared.launchId })
|
|
359
|
-
});
|
|
360
|
-
results.push({
|
|
361
|
-
taskId: task.id,
|
|
362
|
-
roleName: role.name,
|
|
363
|
-
runId: run.id,
|
|
364
|
-
status: "skipped",
|
|
365
|
-
reason: "launch-failed",
|
|
366
|
-
error: message
|
|
367
|
-
});
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
if (error instanceof RuntimeLaunchError) {
|
|
372
|
-
const writerAttached = error.reason === "writable-client";
|
|
373
|
-
results.push({
|
|
374
|
-
taskId: task.id,
|
|
375
|
-
roleName: role.name,
|
|
376
|
-
runId: run.id,
|
|
377
|
-
status: "skipped",
|
|
378
|
-
reason: writerAttached ? "writer-attached" : "runtime-unavailable",
|
|
379
|
-
error: message
|
|
380
|
-
});
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
if (!deliveryAttempted) {
|
|
384
|
-
delivery.forgetPrepared?.({
|
|
385
|
-
taskId: task.id,
|
|
386
|
-
roleName: role.name,
|
|
387
|
-
runId: run.id,
|
|
388
|
-
...(prepared?.launchId === undefined
|
|
389
|
-
? {}
|
|
390
|
-
: { launchId: prepared.launchId })
|
|
391
|
-
});
|
|
392
|
-
results.push({
|
|
393
|
-
taskId: task.id,
|
|
394
|
-
roleName: role.name,
|
|
395
|
-
runId: run.id,
|
|
396
|
-
status: "skipped",
|
|
397
|
-
reason: "runtime-unavailable",
|
|
398
|
-
error: message
|
|
399
|
-
});
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
results.push({
|
|
403
|
-
taskId: task.id,
|
|
404
|
-
roleName: role.name,
|
|
405
|
-
runId: run.id,
|
|
406
|
-
status: "failed",
|
|
407
|
-
reason: "delivery-uncertain",
|
|
408
|
-
error: message
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
return results;
|
|
414
|
-
}
|
|
415
|
-
function providerTurnIsUnsettled(store, taskId, roleName) {
|
|
416
|
-
if (store.getRoleSession(taskId, roleName)?.status !== "active")
|
|
417
|
-
return false;
|
|
418
|
-
const turn = store.getTaskRoleSessionSet?.(taskId, roleName)?.providerBinding?.turn;
|
|
419
|
-
return turn !== null
|
|
420
|
-
&& turn !== undefined
|
|
421
|
-
&& ["submitting", "accepted", "running", "delivery-unknown"].includes(turn.status);
|
|
422
|
-
}
|
|
423
|
-
async function processActiveRunContinuation(store, delivery, task, role, run, now, inputDeliveryRecoveryCutoff) {
|
|
424
|
-
const target = { kind: "role", taskId: task.id, roleName: role.name };
|
|
425
|
-
const mailbox = store.getWorkMailbox(target);
|
|
426
|
-
if (mailbox === null || !mailboxHasWork(mailbox))
|
|
427
|
-
return null;
|
|
428
|
-
const blockedBy = latestContinuationPreparationFailure(store, task.id, run);
|
|
429
|
-
if (blockedBy !== null) {
|
|
430
|
-
return {
|
|
431
|
-
taskId: task.id,
|
|
432
|
-
roleName: role.name,
|
|
433
|
-
runId: run.id,
|
|
434
|
-
status: "skipped",
|
|
435
|
-
reason: "runtime-unavailable",
|
|
436
|
-
error: blockedBy.payload.message
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
const session = store.getRoleSession(task.id, role.name, run.effective.agentId);
|
|
440
|
-
if (session === null || session.launchId === undefined || !hasText(session.nativeSessionId)) {
|
|
441
|
-
return {
|
|
442
|
-
taskId: task.id,
|
|
443
|
-
roleName: role.name,
|
|
444
|
-
runId: run.id,
|
|
445
|
-
status: "skipped",
|
|
446
|
-
reason: "not-ready"
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
const writer = store.getProviderAuthorityFence?.({
|
|
450
|
-
taskId: task.id,
|
|
451
|
-
roleName: role.name,
|
|
452
|
-
runId: run.id,
|
|
453
|
-
agentId: run.effective.agentId,
|
|
454
|
-
launchId: session.launchId,
|
|
455
|
-
nativeSessionId: session.nativeSessionId
|
|
456
|
-
}) ?? null;
|
|
457
|
-
if (writer !== null && writer.owner !== "controller") {
|
|
458
|
-
return {
|
|
459
|
-
taskId: task.id,
|
|
460
|
-
roleName: role.name,
|
|
461
|
-
runId: run.id,
|
|
462
|
-
status: "skipped",
|
|
463
|
-
reason: "writer-attached"
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
const originalReceipt = formatAgentRunReceiptId(task.id, run.id);
|
|
467
|
-
if (mailbox.processing !== null && (mailbox.processing.executionRef?.type !== "run"
|
|
468
|
-
|| mailbox.processing.executionRef.taskId !== task.id
|
|
469
|
-
|| mailbox.processing.executionRef.id !== run.id
|
|
470
|
-
|| mailbox.processing.batchId !== originalReceipt)) {
|
|
471
|
-
return {
|
|
472
|
-
taskId: task.id,
|
|
473
|
-
roleName: role.name,
|
|
474
|
-
runId: run.id,
|
|
475
|
-
status: "skipped",
|
|
476
|
-
reason: "mailbox-busy"
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
if (mailbox.inputDelivery !== null) {
|
|
480
|
-
const existing = mailbox.inputDelivery;
|
|
481
|
-
if ((existing.status === "delivery-unknown"
|
|
482
|
-
|| (existing.status === "dispatching"
|
|
483
|
-
&& inputDeliveryRecoveryCutoff !== undefined
|
|
484
|
-
&& Date.parse(existing.startedAt) < inputDeliveryRecoveryCutoff.getTime()))) {
|
|
485
|
-
return reconcileStrandedInputDelivery(store, task, role, run, existing, now);
|
|
486
|
-
}
|
|
487
|
-
return {
|
|
488
|
-
taskId: task.id,
|
|
489
|
-
roleName: role.name,
|
|
490
|
-
runId: run.id,
|
|
491
|
-
status: "skipped",
|
|
492
|
-
reason: "delivery-uncertain"
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
const pending = nextPendingBatch(mailbox);
|
|
496
|
-
const lane = mailbox.pending.userCorrection === pending ? "user-correction" : "normal";
|
|
497
|
-
const requestedBatchId = pending === null
|
|
498
|
-
? originalReceipt
|
|
499
|
-
: `agent-input:${task.id}/${run.id}/${lane}:${pending.fromSequence}-${pending.toSequence}`;
|
|
500
|
-
if (requestedBatchId === originalReceipt) {
|
|
501
|
-
// Initial provider acceptance is still outstanding. It owns this claim;
|
|
502
|
-
// never reinterpret the original Run prompt as a continuation.
|
|
503
|
-
return {
|
|
504
|
-
taskId: task.id,
|
|
505
|
-
roleName: role.name,
|
|
506
|
-
runId: run.id,
|
|
507
|
-
status: "skipped",
|
|
508
|
-
reason: "delivery-uncertain"
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
if (pending === null || session.launchId === undefined)
|
|
512
|
-
return null;
|
|
513
|
-
if (session.status === "ended") {
|
|
514
|
-
return {
|
|
515
|
-
taskId: task.id,
|
|
516
|
-
roleName: role.name,
|
|
517
|
-
runId: run.id,
|
|
518
|
-
status: "skipped",
|
|
519
|
-
reason: "runtime-unavailable"
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
// Managed input has one write path: a new structured Turn at a settled
|
|
523
|
-
// boundary. AgentHost owns Provider serialization; a busy send releases the
|
|
524
|
-
// claim and leaves the durable correction pending for the next pass.
|
|
525
|
-
const mode = "followup";
|
|
526
|
-
if (writer === null) {
|
|
527
|
-
return {
|
|
528
|
-
taskId: task.id,
|
|
529
|
-
roleName: role.name,
|
|
530
|
-
runId: run.id,
|
|
531
|
-
status: "skipped",
|
|
532
|
-
reason: "not-ready"
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
let deliveryAttempted = false;
|
|
536
|
-
let inputDelivery;
|
|
537
|
-
try {
|
|
538
|
-
const prepared = await delivery.prepareRoleSession({
|
|
539
|
-
taskId: task.id,
|
|
540
|
-
roleName: role.name,
|
|
541
|
-
agentId: run.effective.agentId,
|
|
542
|
-
adapterId: run.effective.adapterId,
|
|
543
|
-
effective: run.effective,
|
|
544
|
-
workspace: run.effective.workspace.root,
|
|
545
|
-
...(run.workspace === undefined ? {} : { managedWorkspace: run.workspace }),
|
|
546
|
-
mode: "resume",
|
|
547
|
-
runId: run.id,
|
|
548
|
-
nativeSessionId: session.nativeSessionId,
|
|
549
|
-
hostActivationId: session.launchId
|
|
550
|
-
});
|
|
551
|
-
const ready = await delivery.waitUntilReady(prepared);
|
|
552
|
-
const readyLaunchId = ready.prepared.launchId
|
|
553
|
-
?? ready.session?.launchId
|
|
554
|
-
?? session.launchId;
|
|
555
|
-
const readyNativeSessionId = ready.session?.nativeSessionId
|
|
556
|
-
?? session.nativeSessionId;
|
|
557
|
-
if (readyLaunchId === undefined || !hasText(readyNativeSessionId)) {
|
|
558
|
-
throw new Error("Continuation delivery has no Provider Activation fence.");
|
|
559
|
-
}
|
|
560
|
-
const providerFence = {
|
|
561
|
-
conversationId: writer.conversationId,
|
|
562
|
-
activationId: writer.activationId
|
|
563
|
-
};
|
|
564
|
-
const claim = store.claimInputDelivery({
|
|
565
|
-
target,
|
|
566
|
-
attemptId: requestedBatchId,
|
|
567
|
-
lane,
|
|
568
|
-
mode,
|
|
569
|
-
owner: "controller",
|
|
570
|
-
now,
|
|
571
|
-
executionRef: { type: "run", taskId: task.id, id: run.id },
|
|
572
|
-
providerFence
|
|
573
|
-
});
|
|
574
|
-
if (claim.status === "empty")
|
|
575
|
-
return null;
|
|
576
|
-
if (claim.status === "busy") {
|
|
577
|
-
return {
|
|
578
|
-
taskId: task.id,
|
|
579
|
-
roleName: role.name,
|
|
580
|
-
runId: run.id,
|
|
581
|
-
status: "skipped",
|
|
582
|
-
reason: "not-ready"
|
|
583
|
-
};
|
|
584
|
-
}
|
|
585
|
-
if (claim.delivery.attemptId !== requestedBatchId || claim.status === "delivery") {
|
|
586
|
-
return {
|
|
587
|
-
taskId: task.id,
|
|
588
|
-
roleName: role.name,
|
|
589
|
-
runId: run.id,
|
|
590
|
-
status: "skipped",
|
|
591
|
-
reason: "delivery-uncertain"
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
inputDelivery = claim.delivery;
|
|
595
|
-
deliveryAttempted = true;
|
|
596
|
-
const text = continuationInput(task, role, run, inputDelivery.attemptId, inputDelivery.batch, boundedContinuationSummaries(store, task.id, inputDelivery.batch.refs));
|
|
597
|
-
const outcome = await delivery.sendOnce({
|
|
598
|
-
delivery: ready,
|
|
599
|
-
receiptId: inputDelivery.attemptId,
|
|
600
|
-
text
|
|
601
|
-
});
|
|
602
|
-
if (outcome === "busy" || outcome === "unavailable") {
|
|
603
|
-
store.releaseInputDelivery(target, inputDelivery.attemptId, now);
|
|
604
|
-
return {
|
|
605
|
-
taskId: task.id,
|
|
606
|
-
roleName: role.name,
|
|
607
|
-
runId: run.id,
|
|
608
|
-
status: "skipped",
|
|
609
|
-
reason: outcome === "busy" ? "not-ready" : "runtime-unavailable"
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
if (outcome === "rejected") {
|
|
613
|
-
store.resolveInputDeliveryNotAccepted(target, inputDelivery.attemptId, now);
|
|
614
|
-
return {
|
|
615
|
-
taskId: task.id,
|
|
616
|
-
roleName: role.name,
|
|
617
|
-
runId: run.id,
|
|
618
|
-
status: "skipped",
|
|
619
|
-
reason: "not-ready"
|
|
620
|
-
};
|
|
621
|
-
}
|
|
622
|
-
if (outcome === "delivery-unknown") {
|
|
623
|
-
store.markInputDeliveryUnknown(target, inputDelivery.attemptId, "Provider Turn delivery is ambiguous; automatic retry is fenced.", now);
|
|
624
|
-
return {
|
|
625
|
-
taskId: task.id,
|
|
626
|
-
roleName: role.name,
|
|
627
|
-
runId: run.id,
|
|
628
|
-
status: "skipped",
|
|
629
|
-
reason: "delivery-uncertain"
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
store.markInputDeliveryPushed(target, inputDelivery.attemptId, now);
|
|
633
|
-
// Keep the exact claim until the matching structured provider acceptance
|
|
634
|
-
// observation folds it. An interrupted acknowledgement becomes
|
|
635
|
-
// delivery-unknown and cannot be resubmitted automatically.
|
|
636
|
-
return {
|
|
637
|
-
taskId: task.id,
|
|
638
|
-
roleName: role.name,
|
|
639
|
-
runId: run.id,
|
|
640
|
-
status: outcome === "sent" ? "delivered" : "already-delivered"
|
|
641
|
-
};
|
|
642
|
-
}
|
|
643
|
-
catch (error) {
|
|
644
|
-
store.recordAgentError?.({
|
|
645
|
-
taskId: task.id,
|
|
646
|
-
roleName: role.name,
|
|
647
|
-
runId: run.id,
|
|
648
|
-
source: error instanceof RuntimeLaunchError || error instanceof RuntimeLaunchFailure
|
|
649
|
-
? "host"
|
|
650
|
-
: "yui",
|
|
651
|
-
phase: deliveryAttempted ? "turn-submit" : "session-restore",
|
|
652
|
-
message: error instanceof Error ? error.message : String(error),
|
|
653
|
-
raw: serializeAgentErrorRaw(error),
|
|
654
|
-
inputDisposition: deliveryAttempted ? "unknown" : "not-accepted"
|
|
655
|
-
}, now);
|
|
656
|
-
if (inputDelivery === undefined) {
|
|
657
|
-
// No durable input intent existed and no provider input method was
|
|
658
|
-
// called. Session preparation may be retried safely.
|
|
659
|
-
}
|
|
660
|
-
else if (!deliveryAttempted)
|
|
661
|
-
store.releaseInputDelivery(target, inputDelivery.attemptId, now);
|
|
662
|
-
else
|
|
663
|
-
store.markInputDeliveryUnknown(target, inputDelivery.attemptId, error instanceof Error ? error.message : String(error), now);
|
|
664
|
-
return {
|
|
665
|
-
taskId: task.id,
|
|
666
|
-
roleName: role.name,
|
|
667
|
-
runId: run.id,
|
|
668
|
-
status: "skipped",
|
|
669
|
-
reason: deliveryAttempted ? "delivery-uncertain" : "runtime-unavailable",
|
|
670
|
-
error: error instanceof Error ? error.message : String(error)
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* A persisted, conclusively unaccepted continuation failure is the recovery
|
|
676
|
-
* fence for this exact Run. Periodic scheduler passes must not reinterpret it
|
|
677
|
-
* as permission to start another Host or submit the same pending input. A new
|
|
678
|
-
* Run has a new identity and therefore makes the Agent's explicit retry
|
|
679
|
-
* observable without adding a second writable recovery state.
|
|
680
|
-
*/
|
|
681
|
-
function latestContinuationPreparationFailure(store, taskId, run) {
|
|
682
|
-
if (run.deliveredAt === undefined)
|
|
683
|
-
return null;
|
|
684
|
-
const deliveredAt = Date.parse(run.deliveredAt);
|
|
685
|
-
const events = store.listEvents?.(taskId) ?? [];
|
|
686
|
-
return [...events].reverse().find((event) => (event.type === "runtime.agent-error"
|
|
687
|
-
&& event.payload.runId === run.id
|
|
688
|
-
&& ["session-restore", "turn-submit"].includes(event.payload.phase ?? "")
|
|
689
|
-
&& event.payload.inputDisposition === "not-accepted"
|
|
690
|
-
&& Date.parse(event.createdAt) >= deliveredAt)) ?? null;
|
|
691
|
-
}
|
|
692
|
-
async function reconcileStrandedInputDelivery(store, task, role, run, input, now) {
|
|
693
|
-
const target = { kind: "role", taskId: task.id, roleName: role.name };
|
|
694
|
-
const uncertain = (reason) => {
|
|
695
|
-
store.markInputDeliveryUnknown(target, input.attemptId, reason, now);
|
|
696
|
-
return {
|
|
697
|
-
taskId: task.id,
|
|
698
|
-
roleName: role.name,
|
|
699
|
-
runId: run.id,
|
|
700
|
-
status: "skipped",
|
|
701
|
-
reason: "delivery-uncertain"
|
|
702
|
-
};
|
|
703
|
-
};
|
|
704
|
-
return uncertain("Controller restarted with unsettled Provider delivery; automatic resubmission is fenced.");
|
|
705
|
-
}
|
|
706
|
-
function continuationInput(task, role, run, attemptId, batch, resultSummaries) {
|
|
707
|
-
const references = batch.refs.map((ref) => ("taskId" in ref
|
|
708
|
-
? `${ref.type}:${ref.taskId}/${ref.id}`
|
|
709
|
-
: `${ref.type}:${ref.id}`));
|
|
710
|
-
return [
|
|
711
|
-
`Yui Task Event Batch: ${attemptId}.`,
|
|
712
|
-
"New durable task events are available for the current Yui Run.",
|
|
713
|
-
"Read the referenced shared context through the Yui CLI, incorporate it, and decide whether to continue work or wait for more results.",
|
|
714
|
-
"Do not create a new Yui Run merely because this is a new Provider Turn.",
|
|
715
|
-
`Reasons: ${batch.reasons.join(", ")}.`,
|
|
716
|
-
...(batch.sources.length === 0 ? [] : [`Sources: ${batch.sources.join(", ")}.`]),
|
|
717
|
-
...(references.length === 0 ? [] : [`References: ${references.join(", ")}.`]),
|
|
718
|
-
...(resultSummaries.length === 0
|
|
719
|
-
? []
|
|
720
|
-
: [
|
|
721
|
-
"Native child results (bounded excerpts; read the referenced event for the full content):",
|
|
722
|
-
...resultSummaries
|
|
723
|
-
])
|
|
724
|
-
].join("\n");
|
|
725
|
-
}
|
|
726
|
-
/**
|
|
727
|
-
* Issue 13: the parent prompt only ever sees a bounded excerpt of a native
|
|
728
|
-
* child result plus its durable event reference. The full content stays in
|
|
729
|
-
* the Task event log and is read on demand through `yui task event show`.
|
|
730
|
-
* This prevents an unbounded provider result from being re-injected into the
|
|
731
|
-
* parent Session on every continuation wake.
|
|
732
|
-
*/
|
|
733
|
-
const MAX_RESULT_SUMMARY_CHARS = 512;
|
|
734
|
-
const MAX_RESULT_SUMMARY_LINES = 8;
|
|
735
|
-
function boundedContinuationSummaries(store, taskId, refs) {
|
|
736
|
-
if (store.listEvents === undefined)
|
|
737
|
-
return [];
|
|
738
|
-
const events = store.listEvents(taskId);
|
|
739
|
-
const continuations = projectProviderContinuations(events);
|
|
740
|
-
const byKey = new Map(continuations.map((entry) => [
|
|
741
|
-
`${entry.identity.continuationId}\u0000${entry.identity.generation}`,
|
|
742
|
-
entry
|
|
743
|
-
]));
|
|
744
|
-
const summaries = [];
|
|
745
|
-
for (const ref of refs) {
|
|
746
|
-
if (!("taskId" in ref) || ref.type !== "event")
|
|
747
|
-
continue;
|
|
748
|
-
const event = events.find((entry) => entry.id === ref.id);
|
|
749
|
-
if (event === undefined)
|
|
750
|
-
continue;
|
|
751
|
-
const observation = runtimeObservationFromTaskEvent(event);
|
|
752
|
-
if (observation === null || observation.kind !== "continuation.reported")
|
|
753
|
-
continue;
|
|
754
|
-
const summary = observation.payload?.summary;
|
|
755
|
-
if (summary === undefined || summary.trim().length === 0)
|
|
756
|
-
continue;
|
|
757
|
-
const continuation = byKey.get(`${observation.fence.continuationId}\u0000${observation.fence.continuationGeneration}`);
|
|
758
|
-
const digest = continuation?.reports
|
|
759
|
-
.find((report) => report.reportId === observation.payload?.reportId)
|
|
760
|
-
?.resultDigest;
|
|
761
|
-
summaries.push([
|
|
762
|
-
`- child ${observation.fence.continuationId}`,
|
|
763
|
-
...(continuation?.durability === "durable-result"
|
|
764
|
-
? [" (durable-result; full content: "
|
|
765
|
-
+ `yui task event show ${taskId} ${ref.id}`
|
|
766
|
-
+ (digest === undefined ? "" : `; digest ${digest.slice(0, 12)}`)
|
|
767
|
-
+ ")"]
|
|
768
|
-
: [" (best-effort; rerun if the parent Session was lost)"]),
|
|
769
|
-
` ${boundedExcerpt(summary)}`
|
|
770
|
-
].join("\n"));
|
|
771
|
-
}
|
|
772
|
-
return summaries;
|
|
773
|
-
}
|
|
774
|
-
function boundedExcerpt(text) {
|
|
775
|
-
const lines = text.split("\n").slice(0, MAX_RESULT_SUMMARY_LINES);
|
|
776
|
-
const joined = lines.join("\n");
|
|
777
|
-
if (joined.length <= MAX_RESULT_SUMMARY_CHARS && text.length === joined.length)
|
|
778
|
-
return joined;
|
|
779
|
-
return `${joined.slice(0, MAX_RESULT_SUMMARY_CHARS)}… [truncated]`;
|
|
780
|
-
}
|
|
781
|
-
function requireResumeSession(role, effective, session) {
|
|
782
|
-
if (session === null || !hasText(session.nativeSessionId)) {
|
|
783
|
-
throw new Error(`Role resume has no fixed native session: ${role.taskId}/${role.name}.`);
|
|
784
|
-
}
|
|
785
|
-
if (!effectiveLaunchSnapshotsCompatibleForTaskSession(session.effective, effective)) {
|
|
786
|
-
throw new Error(`Role resume effective snapshot drifted: ${role.taskId}/${role.name}.`);
|
|
787
|
-
}
|
|
788
|
-
return session.nativeSessionId;
|
|
789
|
-
}
|
|
790
|
-
function persistPreStartFence(store, task, role, run, existingSession, preflight, now) {
|
|
791
|
-
if (preflight.owner.scope !== "task"
|
|
792
|
-
|| preflight.owner.taskId !== task.id
|
|
793
|
-
|| preflight.owner.roleName !== role.name
|
|
794
|
-
|| preflight.runId !== run.id
|
|
795
|
-
|| preflight.launchId.trim().length === 0) {
|
|
796
|
-
throw new Error(`Pre-start launch fence changed the active Role Run: ${task.id}/${role.name}.`);
|
|
797
|
-
}
|
|
798
|
-
const session = preflightSession(role, run.effective, existingSession, run.mode, preflight);
|
|
799
|
-
store.saveRoleRunPrepared({
|
|
800
|
-
task,
|
|
801
|
-
role,
|
|
802
|
-
run,
|
|
803
|
-
session,
|
|
804
|
-
launchId: preflight.launchId,
|
|
805
|
-
now
|
|
806
|
-
});
|
|
807
|
-
}
|
|
808
|
-
function preflightSession(role, effective, existing, mode, preflight) {
|
|
809
|
-
const session = preflight.nativeSessionId === undefined
|
|
810
|
-
? null
|
|
811
|
-
: {
|
|
812
|
-
agentId: preflight.agentId,
|
|
813
|
-
adapterId: preflight.adapterId,
|
|
814
|
-
nativeSessionId: preflight.nativeSessionId,
|
|
815
|
-
launchId: preflight.launchId,
|
|
816
|
-
...(preflight.sessionTitle === undefined ? {} : { title: preflight.sessionTitle }),
|
|
817
|
-
status: "active",
|
|
818
|
-
effective: preflight.effective
|
|
819
|
-
};
|
|
820
|
-
return validateRoleSession(role, effective, existing, mode, session);
|
|
821
|
-
}
|
|
822
|
-
function validateLaunchSubmittedRecoverySession(role, effective, existing, mode, session) {
|
|
823
|
-
return session === undefined
|
|
824
|
-
? existing
|
|
825
|
-
: validateRoleSession(role, effective, existing, mode, session);
|
|
826
|
-
}
|
|
827
|
-
function initialRunTurnInput(run) {
|
|
828
|
-
if (run.controlRequest?.state === "dispatching") {
|
|
829
|
-
return serializeWorkflowOutcomeRequestEnvelope({
|
|
830
|
-
taskId: run.taskId,
|
|
831
|
-
runId: run.id,
|
|
832
|
-
roleName: run.roleName,
|
|
833
|
-
request: run.controlRequest
|
|
834
|
-
});
|
|
835
|
-
}
|
|
836
|
-
return run.pushedAt === undefined
|
|
837
|
-
? serializeRunBootstrapEnvelope(run.bootstrapEnvelope)
|
|
838
|
-
: serializeRunHostRecoveryEnvelope(run.bootstrapEnvelope);
|
|
839
|
-
}
|
|
840
|
-
function validateRoleSession(role, effective, existing, mode, session) {
|
|
841
|
-
if (mode === "new" && session === null)
|
|
842
|
-
return null;
|
|
843
|
-
if (session === null || !hasText(session.nativeSessionId)) {
|
|
844
|
-
throw new Error(`Ready Role session has no native session id: ${role.taskId}/${role.name}.`);
|
|
845
|
-
}
|
|
846
|
-
if (session.agentId !== effective.agentId || session.adapterId !== effective.adapterId) {
|
|
847
|
-
throw new Error(`Ready Role session identity changed: ${role.taskId}/${role.name}.`);
|
|
848
|
-
}
|
|
849
|
-
const compatible = mode === "resume"
|
|
850
|
-
? effectiveLaunchSnapshotsCompatibleForTaskSession(session.effective, effective)
|
|
851
|
-
: effectiveLaunchSnapshotsCompatible(session.effective, effective);
|
|
852
|
-
if (!compatible) {
|
|
853
|
-
throw new Error(`Ready Role session effective snapshot changed: ${role.taskId}/${role.name}.`);
|
|
854
|
-
}
|
|
855
|
-
if (mode === "resume" && session.nativeSessionId !== existing?.nativeSessionId) {
|
|
856
|
-
throw new Error(`Role resume changed the fixed native session id: ${role.taskId}/${role.name}.`);
|
|
857
|
-
}
|
|
858
|
-
return {
|
|
859
|
-
...session,
|
|
860
|
-
status: "active",
|
|
861
|
-
...(mode === "resume" && existing !== null
|
|
862
|
-
? { effective: existing.effective }
|
|
863
|
-
: {})
|
|
864
|
-
};
|
|
865
|
-
}
|
|
866
|
-
function hasText(value) {
|
|
867
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
868
|
-
}
|