@zq-silk/yui 0.13.4 → 0.13.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/cli/commandCatalog.js +22 -21
- package/dist/cli/interactionPolicy.js +0 -14
- package/dist/cli.js +42 -0
- package/dist/commands/executionAuditCommands.js +1 -1
- package/dist/commands/taskCommands.js +60 -326
- package/dist/commands/taskContextCommand.js +3 -14
- package/dist/commands/taskExecutionCommands.js +254 -0
- package/dist/commands/taskNextActionCommand.js +1 -3
- package/dist/commands/taskOverviewCommand.js +9 -2
- package/dist/commands/taskRoleRuntimeStatus.js +2 -25
- package/dist/controller/agentRuntimeObserver.js +4 -2
- package/dist/controller/clientRuntime.js +45 -2
- package/dist/controller/controller.js +6 -3
- package/dist/controller/fileSchedulerStoreAdapter.js +59 -188
- package/dist/controller/jobControl.js +3 -2
- package/dist/controller/runtime.js +6 -33
- package/dist/controller/runtimeEventProcessor.js +8 -4
- package/dist/controller/runtimeHookRunFence.js +4 -10
- package/dist/execution/executionHealth.js +8 -16
- package/dist/executor/agentExecutor.js +13 -14
- package/dist/executor/fileRoleLaunchPlanner.js +9 -16
- package/dist/lifecycle/exactRunTerminalization.js +24 -322
- package/dist/repository/taskWorkspaceCoordinator.js +0 -9
- package/dist/runtime/agentHost.js +20 -80
- package/dist/runtime/exactControlPlane.js +15 -9
- package/dist/runtime/providerContinuationReconciliationService.js +1 -1
- package/dist/runtime/providerRecoveryDecision.js +1 -1
- package/dist/runtime/providerRuntimeIdentity.js +25 -15
- package/dist/scheduler/activeRoleRunDelivery.js +1 -19
- package/dist/scheduler/leaderWakeupProcessor.js +12 -63
- package/dist/scheduler/ports.js +3 -2
- package/dist/scheduler/roleRunLiveness.js +4 -1
- package/dist/scheduler/roleRunStall.js +0 -2
- package/dist/scheduler/taskExecutionProjection.js +18 -1
- package/dist/scheduler/wakeupQueue.js +2 -1
- package/dist/storage/migration/productionRegistry.js +65 -0
- package/dist/storage/sqliteStore.js +10 -2
- package/dist/storage/taskStore.js +11 -3
- package/dist/task/completionReadiness.js +0 -67
- package/dist/task/nextAction.js +16 -32
- package/dist/task/task.js +38 -3
- package/dist/web/assets/client/i18n.js +0 -4
- package/dist/web/assets/client/view.js +0 -18
- package/dist/web/webSnapshot.js +7 -13
- package/package.json +1 -1
- package/dist/run/recoveryProjection.js +0 -252
- package/dist/runtime/conversationSwitch.js +0 -277
|
@@ -10,19 +10,17 @@ import { isRoleRunStalled, RUN_PROGRESS_EVENT, RUN_RECOVERED_EVENT } from "../sc
|
|
|
10
10
|
import { routeRoleEvent } from "../scheduler/operatorEvent.js";
|
|
11
11
|
import { readCommandText } from "./textInput.js";
|
|
12
12
|
import { assertTaskCompletionPublishedTreeProof } from "./taskCompletionGate.js";
|
|
13
|
-
import { createRoleSessionSet, retireTaskRoleSessionsForWorkspace, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
|
|
13
|
+
import { createRoleSessionSet, roleAgentSessionResumeMode, retireTaskRoleSessionsForWorkspace, terminalizeTaskRoleRunSession, updateTaskRoleProviderRuntime, updateRoleAgentSessionStatus } from "../executor/agentExecutor.js";
|
|
14
14
|
import { currentProviderActivation, transferProviderAuthority } from "../runtime/providerRuntimeIdentity.js";
|
|
15
|
-
import { CONVERSATION_SWITCH_REQUESTED_EVENT, CONVERSATION_SWITCH_RESOLVED_EVENT, projectConversationSwitch, providerConversationGeneration, roleSessionDispatchModeWithConversationSwitch } from "../runtime/conversationSwitch.js";
|
|
16
15
|
import { resolveEffectiveLaunch } from "../executor/effectiveLaunch.js";
|
|
17
16
|
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
18
17
|
import { formatTimestamp } from "../output/timePresentation.js";
|
|
19
18
|
import { renderRoleDetails } from "../output/rolePresentation.js";
|
|
20
19
|
import { createTaskMessage, taskMessageAuthorLabel } from "../message/message.js";
|
|
21
20
|
import { cancelInputRequest } from "../input/inputRequest.js";
|
|
22
|
-
import {
|
|
21
|
+
import { retireExactActiveAgentRun, terminalizeExactTaskRun, validateExactRunReviewRound } from "../lifecycle/exactRunTerminalization.js";
|
|
23
22
|
import { activeRoleAgentBinding, copyGlobalRoleToTaskRole, createRole, createRoleAgentBinding, switchActiveRoleAgent, unbindRoleAgent, updateRole, updateRoleStatus } from "../role/role.js";
|
|
24
|
-
import { agentRunDeliveryReceiptId, createAgentRun, withAgentRunContextSnapshot } from "../run/agentRun.js";
|
|
25
|
-
import { projectRunRecovery, readRunRecoveryFacts } from "../run/recoveryProjection.js";
|
|
23
|
+
import { agentRunDeliveryReceiptId, createAgentRun, failAgentRun, withAgentRunContextSnapshot, yieldAgentRun } from "../run/agentRun.js";
|
|
26
24
|
import { matchYieldReceipt } from "../run/yieldReceipt.js";
|
|
27
25
|
import { createRejectedYieldAttempt, rejectedYieldAttemptEventPayload, rejectedYieldAttemptFromTaskEvent, RUN_YIELD_REJECTED_EVENT } from "../run/rejectedYieldAttempt.js";
|
|
28
26
|
import { createReviewRound, createTaskReviewRound, createTaskDeltaReviewRound, attachReviewExecutionGroup, deltaRecheckBlocksAcceptance, finishReviewRound, parseReviewYieldReport, recordReviewWorkspaceDisposition, retryRunningReviewExecutionLane, retryTaskReviewRound, startReviewRound, updateReviewExecutionGroup, validateTaskReviewCandidate } from "../review/reviewRound.js";
|
|
@@ -38,7 +36,7 @@ import { runPublicationCommand } from "./taskPublicationCommands.js";
|
|
|
38
36
|
import { enqueueWork, settleExactWorkExecution } from "../coordination/workMailboxQueue.js";
|
|
39
37
|
import { mailboxHasWork as workMailboxHasWork, nextPendingBatch } from "../coordination/workMailbox.js";
|
|
40
38
|
import { RUNTIME_CLEANUP_REQUIRED_REASON, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
41
|
-
import {
|
|
39
|
+
import { projectProviderContinuations } from "../runtime/runtimeContinuationProjection.js";
|
|
42
40
|
import { runtimeObservationFromTaskEvent } from "../runtime/runtimeObservation.js";
|
|
43
41
|
import { addTaskProjectBinding, archiveTask, completeTask, createTask, retireTask, reopenTask, updateTaskMetadata } from "../task/task.js";
|
|
44
42
|
import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
|
|
@@ -196,19 +194,6 @@ export function preflightTaskCompletion(taskId, store, options = {}, request = {
|
|
|
196
194
|
if (blockers.length > 0) {
|
|
197
195
|
throw usageError(formatCompletionBlockers(task.id, blockers));
|
|
198
196
|
}
|
|
199
|
-
const roles = store.listRoles(task.id);
|
|
200
|
-
const activeRuns = roles
|
|
201
|
-
.map((role) => ({ role, run: store.getActiveAgentRun(task.id, role.name) }))
|
|
202
|
-
.filter((entry) => entry.run !== null);
|
|
203
|
-
const leaderEntry = activeRuns.find(({ role }) => role.name === LEADER_ROLE);
|
|
204
|
-
if (leaderEntry !== undefined) {
|
|
205
|
-
if (leaderEntry.run.workItemId !== undefined) {
|
|
206
|
-
throw usageError(`Task ${task.id} has running work: ${leaderEntry.run.workItemId}.`);
|
|
207
|
-
}
|
|
208
|
-
if (leaderEntry.run.pushedAt === undefined) {
|
|
209
|
-
throw usageError(`Task ${task.id} Leader delivery is still pending.`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
197
|
return {
|
|
213
198
|
task,
|
|
214
199
|
actor,
|
|
@@ -728,33 +713,6 @@ function completeTaskCommand(args, store, options) {
|
|
|
728
713
|
? undefined
|
|
729
714
|
: assertTaskCompletionPublishedTreeProof(tx, task, request.acceptedPublishedTreePublicationId, options.completionPublishedTreeProof, actualTaskCandidate);
|
|
730
715
|
const roles = tx.listRoles(task.id);
|
|
731
|
-
const activeRuns = roles
|
|
732
|
-
.map((role) => ({ role, run: tx.getActiveAgentRun(task.id, role.name) }))
|
|
733
|
-
.filter((entry) => entry.run !== null);
|
|
734
|
-
// The preflight (above, same transaction) already projected the full
|
|
735
|
-
// readiness via projectCompletionReadiness. The leader-Run check is
|
|
736
|
-
// actor-dependent and stays here; every other blocker is re-validated by
|
|
737
|
-
// the post-Review readiness fence below.
|
|
738
|
-
const leaderEntry = activeRuns.find(({ role }) => role.name === LEADER_ROLE);
|
|
739
|
-
if (leaderEntry !== undefined) {
|
|
740
|
-
if (leaderEntry.run.workItemId !== undefined) {
|
|
741
|
-
throw usageError(`Task ${task.id} has running work: ${leaderEntry.run.workItemId}.`);
|
|
742
|
-
}
|
|
743
|
-
if (leaderEntry.run.pushedAt === undefined) {
|
|
744
|
-
throw usageError(`Task ${task.id} Leader delivery is still pending.`);
|
|
745
|
-
}
|
|
746
|
-
const terminal = terminalizeExactTaskRun(tx, {
|
|
747
|
-
taskId: task.id,
|
|
748
|
-
roleName: LEADER_ROLE,
|
|
749
|
-
agentId: leaderEntry.run.effective.agentId,
|
|
750
|
-
runId: leaderEntry.run.id,
|
|
751
|
-
receiptId: agentRunDeliveryReceiptId(leaderEntry.run),
|
|
752
|
-
outcome: { status: "yielded", summary }
|
|
753
|
-
}, now);
|
|
754
|
-
if (terminal.disposition !== "applied") {
|
|
755
|
-
throw usageError(`Task Leader Run changed during completion: ${leaderEntry.run.id}/${terminal.reason}.`);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
716
|
// A final (Task-scoped) review is the Task delivery policy: it reviews the
|
|
759
717
|
// complete frozen Task heads, not a single WorkItem Candidate. If the
|
|
760
718
|
// review config requests a final review, create the Task ReviewRound here
|
|
@@ -769,6 +727,10 @@ function completeTaskCommand(args, store, options) {
|
|
|
769
727
|
finalReview,
|
|
770
728
|
};
|
|
771
729
|
}
|
|
730
|
+
// Completion is a semantic boundary. Current Runs and Sessions are
|
|
731
|
+
// disposable execution attempts; settle them before deriving readiness so
|
|
732
|
+
// only durable Task results decide whether the Task can complete.
|
|
733
|
+
const runtimeCleanupTargets = settleTaskExecutionForCompletion(tx, task.id, roles, summary, now);
|
|
772
734
|
// Issue 06: re-validate the full completion readiness inside the
|
|
773
735
|
// transaction (the CAS fence) after final-review preparation. This is the
|
|
774
736
|
// same pure projection `task next-action` displays, now with the finding
|
|
@@ -818,13 +780,12 @@ function completeTaskCommand(args, store, options) {
|
|
|
818
780
|
// The durable records remain intact; only the derived mailbox work is
|
|
819
781
|
// discarded at this lifecycle boundary.
|
|
820
782
|
tx.removeWorkMailbox(taskMailbox(task.id));
|
|
821
|
-
// Role mailboxes are also derived wake state. A Worker result or
|
|
783
|
+
// Role mailboxes are also derived wake state. A Worker result or runtime
|
|
822
784
|
// signal queued while the final Run was being settled must not survive a
|
|
823
785
|
// completed Task and become actionable after a later explicit reopen.
|
|
824
786
|
for (const role of roles) {
|
|
825
787
|
tx.removeWorkMailbox(roleMailbox(task.id, role.name));
|
|
826
788
|
}
|
|
827
|
-
const runtimeCleanupTargets = queueCompletedTaskRuntimeCleanups(tx, task.id, roles, now);
|
|
828
789
|
return {
|
|
829
790
|
task: completed,
|
|
830
791
|
changed: true,
|
|
@@ -930,11 +891,6 @@ function archiveTaskCommand(args, store, options) {
|
|
|
930
891
|
if (activeArchiveJob !== undefined) {
|
|
931
892
|
throw usageError(`Task ${task.id} has an active DurableJob: ${activeArchiveJob.id}/${activeArchiveJob.status}.`);
|
|
932
893
|
}
|
|
933
|
-
const continuationBlockers = blockingProviderContinuations(tx.listEvents(task.id));
|
|
934
|
-
if (continuationBlockers.length > 0) {
|
|
935
|
-
throw usageError(`Task ${task.id} still owns unsettled Provider continuation(s); `
|
|
936
|
-
+ "reconcile or cancel them before archiving.");
|
|
937
|
-
}
|
|
938
894
|
if (task.cwd !== undefined || tx.listManagedWorkspaces(task.id).length > 0) {
|
|
939
895
|
throw usageError(`Task ${task.id} still has managed worktrees; clean them before archiving.`);
|
|
940
896
|
}
|
|
@@ -1325,8 +1281,6 @@ function taskRoleCommand(args, store, options) {
|
|
|
1325
1281
|
return output(bindTaskRole(rest, store, options));
|
|
1326
1282
|
if (command === "unbind")
|
|
1327
1283
|
return output(unbindTaskRole(rest, store, options));
|
|
1328
|
-
if (command === "session")
|
|
1329
|
-
return taskRoleSessionCommand(rest, store, options);
|
|
1330
1284
|
if (command === "view")
|
|
1331
1285
|
return viewTaskRole(rest, store);
|
|
1332
1286
|
if (command === "takeover")
|
|
@@ -1337,79 +1291,6 @@ function taskRoleCommand(args, store, options) {
|
|
|
1337
1291
|
? "Task role command is required."
|
|
1338
1292
|
: `Unknown command: task role ${command}`);
|
|
1339
1293
|
}
|
|
1340
|
-
function taskRoleSessionCommand(args, store, options) {
|
|
1341
|
-
const [command, ...rest] = args;
|
|
1342
|
-
if (command === "switch")
|
|
1343
|
-
return switchTaskRoleSession(rest, store, options);
|
|
1344
|
-
throw usageError(command === undefined
|
|
1345
|
-
? "Task role session command is required."
|
|
1346
|
-
: `Unknown command: task role session ${command}`);
|
|
1347
|
-
}
|
|
1348
|
-
function switchTaskRoleSession(args, store, options) {
|
|
1349
|
-
const usage = "Task role session switch usage: yui task role session switch <task> <role> --reason <text>.";
|
|
1350
|
-
const parsed = parseTail(args, new Set(["--reason"]), usage);
|
|
1351
|
-
exactPositionals(parsed.positionals, 2, usage);
|
|
1352
|
-
const reason = truncateEventNote(requiredOption(parsed.options, "--reason"));
|
|
1353
|
-
const now = clock(options);
|
|
1354
|
-
const result = store.transaction((tx) => {
|
|
1355
|
-
const task = requireTask(tx, parsed.positionals[0]);
|
|
1356
|
-
if (task.status !== "active") {
|
|
1357
|
-
throw usageError(inactiveTaskMessage(task, "switching a Provider Conversation"), usage);
|
|
1358
|
-
}
|
|
1359
|
-
const role = requireRole(tx, task.id, parsed.positionals[1]);
|
|
1360
|
-
const requestedBy = taskActor(tx, options, task.id);
|
|
1361
|
-
const leaderRunId = requestedBy === "leader"
|
|
1362
|
-
? taskLeaderActionRunId(tx, task.id, options.environment, options.yuiHome)
|
|
1363
|
-
: undefined;
|
|
1364
|
-
if (requestedBy === "leader" && leaderRunId === undefined) {
|
|
1365
|
-
throw usageError("Leader Conversation switching requires the exact current-Turn assertion.", usage);
|
|
1366
|
-
}
|
|
1367
|
-
const sessions = tx.getTaskRoleSessionSet(task.id, role.name);
|
|
1368
|
-
const generation = providerConversationGeneration(sessions);
|
|
1369
|
-
if (sessions === null || generation === null) {
|
|
1370
|
-
throw usageError(`Task Role has no current Provider Conversation: ${task.id}/${role.name}.`, usage);
|
|
1371
|
-
}
|
|
1372
|
-
const events = tx.listEvents(task.id);
|
|
1373
|
-
const previous = projectConversationSwitch(events, role.name, sessions);
|
|
1374
|
-
if (previous?.status === "pending"
|
|
1375
|
-
&& previous.generation === generation
|
|
1376
|
-
&& previous.requestedBy === requestedBy
|
|
1377
|
-
&& previous.reason === reason) {
|
|
1378
|
-
return { taskId: task.id, roleName: role.name, request: previous, replayed: true };
|
|
1379
|
-
}
|
|
1380
|
-
if (previous !== null && previous.resolvedAt === undefined) {
|
|
1381
|
-
tx.saveEvent(task.id, createTaskEvent(tx.nextEventId(task.id), task.id, CONVERSATION_SWITCH_RESOLVED_EVENT, {
|
|
1382
|
-
requestId: previous.requestId,
|
|
1383
|
-
roleName: role.name,
|
|
1384
|
-
generation: previous.generation,
|
|
1385
|
-
status: "obsolete"
|
|
1386
|
-
}, now));
|
|
1387
|
-
}
|
|
1388
|
-
const requestId = tx.nextEventId(task.id);
|
|
1389
|
-
const event = createTaskEvent(requestId, task.id, CONVERSATION_SWITCH_REQUESTED_EVENT, {
|
|
1390
|
-
requestId,
|
|
1391
|
-
roleName: role.name,
|
|
1392
|
-
generation,
|
|
1393
|
-
requestedBy,
|
|
1394
|
-
reason,
|
|
1395
|
-
...(leaderRunId === undefined ? {} : { leaderRunId })
|
|
1396
|
-
}, now);
|
|
1397
|
-
tx.saveEvent(task.id, event);
|
|
1398
|
-
return {
|
|
1399
|
-
taskId: task.id,
|
|
1400
|
-
roleName: role.name,
|
|
1401
|
-
request: projectConversationSwitch([...events, event], role.name, sessions),
|
|
1402
|
-
replayed: false
|
|
1403
|
-
};
|
|
1404
|
-
});
|
|
1405
|
-
options.runtime?.notifyStateChanged(result.taskId);
|
|
1406
|
-
options.runtime?.notifyMailboxChanged?.({
|
|
1407
|
-
kind: "role",
|
|
1408
|
-
taskId: result.taskId,
|
|
1409
|
-
roleName: result.roleName
|
|
1410
|
-
});
|
|
1411
|
-
return output(`${result.replayed ? "Reused" : "Recorded"} pending Provider Conversation switch ${result.request.requestId} for ${result.taskId}/${result.roleName}. The current Conversation remains authoritative until safe replacement binding.\n`, result);
|
|
1412
|
-
}
|
|
1413
1294
|
function addTaskRole(args, store, options) {
|
|
1414
1295
|
const usage = "Task role add usage: yui task role add <task> <name> [Role and Agent settings].";
|
|
1415
1296
|
const [taskId, roleName, ...tail] = args;
|
|
@@ -2099,6 +1980,7 @@ function dispatchWork(args, store, options) {
|
|
|
2099
1980
|
if (task.status !== "active") {
|
|
2100
1981
|
throw usageError(inactiveTaskMessage(task, "dispatch"));
|
|
2101
1982
|
}
|
|
1983
|
+
assertTaskExecutionEnabled(task, "dispatching work");
|
|
2102
1984
|
taskActor(tx, options, task.id);
|
|
2103
1985
|
const currentGroup = currentWorkItemExecutionGroup(item);
|
|
2104
1986
|
const existingGroup = currentGroup?.resolution === undefined
|
|
@@ -2342,7 +2224,7 @@ function dispatchWork(args, store, options) {
|
|
|
2342
2224
|
workItemWriteProjectIds: item.writeProjectIds
|
|
2343
2225
|
});
|
|
2344
2226
|
const sessions = tx.getTaskRoleSessionSet(task.id, plan.role.name);
|
|
2345
|
-
const dispatchMode =
|
|
2227
|
+
const dispatchMode = roleAgentSessionResumeMode(sessions, effective.agentId, effective);
|
|
2346
2228
|
const laneWorkspace = laneManagedWorkspace === undefined
|
|
2347
2229
|
? undefined
|
|
2348
2230
|
: {
|
|
@@ -4041,8 +3923,6 @@ function taskRunCommand(args, store, options) {
|
|
|
4041
3923
|
return retryRun(rest, store, options);
|
|
4042
3924
|
if (command === "settle")
|
|
4043
3925
|
return settleStaleFinalReviewRun(rest, store, options);
|
|
4044
|
-
if (command === "recover")
|
|
4045
|
-
return output(recoverRun(rest, store, options));
|
|
4046
3926
|
if (command === "yield")
|
|
4047
3927
|
return yieldRun(rest, store, options);
|
|
4048
3928
|
if (command === "yield-status")
|
|
@@ -4413,15 +4293,7 @@ function retryRun(args, store, options) {
|
|
|
4413
4293
|
const task = requireTask(tx, previous.taskId);
|
|
4414
4294
|
if (task.status !== "active")
|
|
4415
4295
|
throw usageError(`Task is not active: ${task.id}.`);
|
|
4416
|
-
|
|
4417
|
-
taskId: previous.taskId,
|
|
4418
|
-
roleName: previous.roleName,
|
|
4419
|
-
runId: previous.id,
|
|
4420
|
-
agentId: previous.effective.agentId
|
|
4421
|
-
})) {
|
|
4422
|
-
throw usageError(`Run ${previous.id} still owns an unsettled Provider continuation; `
|
|
4423
|
-
+ "reconcile it before retrying the Lane.");
|
|
4424
|
-
}
|
|
4296
|
+
assertTaskExecutionEnabled(task, "retrying a Run");
|
|
4425
4297
|
const role = requireRole(tx, task.id, previous.roleName);
|
|
4426
4298
|
if (tx.getActiveAgentRun(task.id, role.name) !== null) {
|
|
4427
4299
|
throw usageError(`${task.id}/${role.name} already has an active run.`);
|
|
@@ -4616,7 +4488,7 @@ function retryRun(args, store, options) {
|
|
|
4616
4488
|
contextSnapshotRef: contextSnapshotRef(retrySnapshot),
|
|
4617
4489
|
deltaRefIds: contextSnapshotDeltaRefIds(tx, retrySnapshot)
|
|
4618
4490
|
});
|
|
4619
|
-
const created = createAgentRun(runId, task.id, role.name,
|
|
4491
|
+
const created = createAgentRun(runId, task.id, role.name, roleAgentSessionResumeMode(sessions, effective.agentId, effective), assignment, now, {
|
|
4620
4492
|
...(previous.workItemId === undefined ? {} : { workItemId: previous.workItemId }),
|
|
4621
4493
|
...(runningGroup === undefined ? {} : {
|
|
4622
4494
|
executionGroupId: runningGroup.id,
|
|
@@ -4960,15 +4832,6 @@ function retryFailedReviewRun(previous, store, options, now) {
|
|
|
4960
4832
|
const task = requireTask(tx, run.taskId);
|
|
4961
4833
|
if (task.status !== "active")
|
|
4962
4834
|
throw usageError(`Task is not active: ${task.id}.`);
|
|
4963
|
-
if (runOwnsBlockingProviderContinuation(tx.listEvents(task.id), {
|
|
4964
|
-
taskId: run.taskId,
|
|
4965
|
-
roleName: run.roleName,
|
|
4966
|
-
runId: run.id,
|
|
4967
|
-
agentId: run.effective.agentId
|
|
4968
|
-
})) {
|
|
4969
|
-
throw usageError(`Review Run ${run.id} still owns an unsettled Provider continuation; `
|
|
4970
|
-
+ "reconcile it before retrying the Lane.");
|
|
4971
|
-
}
|
|
4972
4835
|
const requestedBy = taskActor(tx, options, task.id);
|
|
4973
4836
|
const round = tx.getReviewRound(task.id, run.reviewRoundId);
|
|
4974
4837
|
if (round === null) {
|
|
@@ -5161,127 +5024,7 @@ function retryFailedReviewRun(previous, store, options, now) {
|
|
|
5161
5024
|
? `Review retry requested as ${result.round.id}\n`
|
|
5162
5025
|
: `Review retry already requested as ${result.round.id} (${result.round.status})\n`, { reviewRound: result.round });
|
|
5163
5026
|
}
|
|
5164
|
-
/**
|
|
5165
|
-
* Records one explicit Leader recovery decision against an exact live Run.
|
|
5166
|
-
* Diagnose and retry remain same-Run requests: this command never changes a
|
|
5167
|
-
* native Conversation generation.
|
|
5168
|
-
*/
|
|
5169
|
-
function recoverRun(args, store, options) {
|
|
5170
|
-
const usage = "Task run recover usage: yui task run recover <task>/<run> --action <diagnose|retry|terminate> (--expected-progress-at <timestamp>|--from-next-action <fingerprint>) --provider-acceptance <accepted|rejected|ambiguous> --reason <text> [--agent-id <id>] [--adapter-id <id>] [--native-session-id <id>] [--launch-id <id>].";
|
|
5171
|
-
const parsed = parseTail(args, new Set([
|
|
5172
|
-
"--action",
|
|
5173
|
-
"--expected-progress-at",
|
|
5174
|
-
"--progress-at",
|
|
5175
|
-
"--from-next-action",
|
|
5176
|
-
"--provider-acceptance",
|
|
5177
|
-
"--reason",
|
|
5178
|
-
"--role",
|
|
5179
|
-
"--agent-id",
|
|
5180
|
-
"--adapter-id",
|
|
5181
|
-
"--native-session-id",
|
|
5182
|
-
"--launch-id"
|
|
5183
|
-
]), usage);
|
|
5184
|
-
exactPositionals(parsed.positionals, 1, usage);
|
|
5185
|
-
const now = clock(options);
|
|
5186
|
-
const fingerprint = parsed.options.get("--from-next-action");
|
|
5187
|
-
const explicitFence = parsed.options.get("--expected-progress-at")
|
|
5188
|
-
?? parsed.options.get("--progress-at");
|
|
5189
|
-
if (fingerprint !== undefined && explicitFence !== undefined) {
|
|
5190
|
-
throw usageError("--from-next-action and --expected-progress-at/--progress-at are mutually exclusive.", usage);
|
|
5191
|
-
}
|
|
5192
|
-
const input = store.transaction((tx) => {
|
|
5193
|
-
const active = requireRun(tx, parsed.positionals[0], options);
|
|
5194
|
-
const task = requireTask(tx, active.taskId);
|
|
5195
|
-
if (task.status !== "active")
|
|
5196
|
-
throw usageError(inactiveTaskMessage(task, "recovering a run"));
|
|
5197
|
-
taskActor(tx, options, task.id);
|
|
5198
|
-
const roleName = parsed.options.get("--role") ?? active.roleName;
|
|
5199
|
-
if (roleName !== active.roleName) {
|
|
5200
|
-
throw usageError(`Recovery Role does not match Run ${active.id}: ${roleName}.`);
|
|
5201
|
-
}
|
|
5202
|
-
const role = requireRole(tx, task.id, roleName);
|
|
5203
|
-
const sessions = tx.getTaskRoleSessionSet(task.id, role.name);
|
|
5204
|
-
const session = sessions?.sessions[sessions.activeAgentId];
|
|
5205
|
-
// Issue 08: a fingerprint copied from `task run show` resolves the
|
|
5206
|
-
// canonical fence server-side. The projection is recomputed here, so a
|
|
5207
|
-
// fingerprint from stale observations matches nothing and fails closed.
|
|
5208
|
-
let plan = null;
|
|
5209
|
-
if (fingerprint !== undefined) {
|
|
5210
|
-
const facts = readRunRecoveryFacts(tx, task.id, active.id);
|
|
5211
|
-
if (facts === null)
|
|
5212
|
-
throw usageError(`Agent Run not found: ${task.id}/${active.id}.`, usage);
|
|
5213
|
-
const projection = projectRunRecovery(facts);
|
|
5214
|
-
plan = projection.actions.find((entry) => entry.fingerprint === fingerprint) ?? null;
|
|
5215
|
-
if (plan === null) {
|
|
5216
|
-
throw usageError(runRecoveryStaleDiagnosis(task.id, active.id, projection.canonicalProgressAt ?? null, "recovery action fingerprint is stale or unknown"), usage);
|
|
5217
|
-
}
|
|
5218
|
-
}
|
|
5219
|
-
const action = parseRecoveryAction(parsed.options.get("--action") ?? plan?.action, usage);
|
|
5220
|
-
if (plan !== null && plan.action !== action) {
|
|
5221
|
-
throw usageError(`--action ${action} does not match recovery fingerprint action ${plan.action}.`, usage);
|
|
5222
|
-
}
|
|
5223
|
-
const expectedProgressAt = explicitFence ?? plan?.expectedProgressAt;
|
|
5224
|
-
if (expectedProgressAt === undefined) {
|
|
5225
|
-
throw usageError("--expected-progress-at is required.", usage);
|
|
5226
|
-
}
|
|
5227
|
-
const providerAcceptance = parseProviderAcceptance(parsed.options.get("--provider-acceptance"), usage);
|
|
5228
|
-
const agentId = parsed.options.get("--agent-id")
|
|
5229
|
-
?? plan?.agentId
|
|
5230
|
-
?? active.effective.agentId;
|
|
5231
|
-
const adapterId = parsed.options.get("--adapter-id")
|
|
5232
|
-
?? plan?.adapterId
|
|
5233
|
-
?? active.effective.adapterId;
|
|
5234
|
-
const nativeSessionId = parsed.options.get("--native-session-id")
|
|
5235
|
-
?? plan?.nativeSessionId
|
|
5236
|
-
?? session?.nativeSessionId;
|
|
5237
|
-
const launchId = parsed.options.get("--launch-id")
|
|
5238
|
-
?? plan?.launchId
|
|
5239
|
-
?? session?.launchId;
|
|
5240
|
-
return {
|
|
5241
|
-
taskId: task.id,
|
|
5242
|
-
roleName: role.name,
|
|
5243
|
-
runId: active.id,
|
|
5244
|
-
agentId,
|
|
5245
|
-
adapterId,
|
|
5246
|
-
...(nativeSessionId === undefined ? {} : { nativeSessionId }),
|
|
5247
|
-
...(launchId === undefined ? {} : { launchId }),
|
|
5248
|
-
expectedProgressAt,
|
|
5249
|
-
providerAcceptance,
|
|
5250
|
-
action,
|
|
5251
|
-
reason: requiredOption(parsed.options, "--reason"),
|
|
5252
|
-
now
|
|
5253
|
-
};
|
|
5254
|
-
});
|
|
5255
|
-
const result = recoverExactAgentRun(store, input);
|
|
5256
|
-
if (result.disposition !== "applied") {
|
|
5257
|
-
throw usageError(runRecoveryStaleDiagnosis(input.taskId, input.runId, result.progressAt ?? null, `exact Run recovery ${result.disposition}: ${result.reason ?? "state changed"}`), usage);
|
|
5258
|
-
}
|
|
5259
|
-
// The durable recovery request is committed before asking the Controller to
|
|
5260
|
-
// wake the owning Leader; a failed transaction must not leak a signal.
|
|
5261
|
-
if (result.run !== null && result.run.roleName !== LEADER_ROLE) {
|
|
5262
|
-
notifyMailbox(options.runtime, leaderMailbox(result.run.taskId), result.run.taskId);
|
|
5263
|
-
}
|
|
5264
|
-
const followup = result.requiresExplicitFollowup === true
|
|
5265
|
-
? " Leader follow-up is required; no provider input or Session action was performed."
|
|
5266
|
-
: "";
|
|
5267
|
-
return `Recorded exact ${result.action} recovery for ${result.run?.id ?? "unknown Run"}.${followup}\n`;
|
|
5268
|
-
}
|
|
5269
|
-
/**
|
|
5270
|
-
* Issue 08: every recovery rejection carries the current canonical fence and
|
|
5271
|
-
* points at the single read-only command that projects it. The caller's
|
|
5272
|
-
* side-effecting action is never retried automatically.
|
|
5273
|
-
*/
|
|
5274
|
-
function runRecoveryStaleDiagnosis(taskId, runId, canonicalProgressAt, detail) {
|
|
5275
|
-
const fence = canonicalProgressAt === null
|
|
5276
|
-
? "no durable progress timestamp is available for this Run"
|
|
5277
|
-
: `the canonical durable fence is now ${canonicalProgressAt}`;
|
|
5278
|
-
return `${detail}; ${fence}. Re-read the recovery plan: yui task run show ${taskId}/${runId}.`;
|
|
5279
|
-
}
|
|
5280
|
-
/**
|
|
5281
|
-
* Issue 08: read-only Run detail with the canonical recovery fence, Provider
|
|
5282
|
-
* evidence, and every exact recovery action. Never mutates state and never
|
|
5283
|
-
* selects an action or Provider acceptance for the Leader.
|
|
5284
|
-
*/
|
|
5027
|
+
/** Run details are retained audit evidence; continuation uses durable Task state. */
|
|
5285
5028
|
function showRun(args, store, options) {
|
|
5286
5029
|
const usage = "Task run show usage: yui task run show <task>/<run> [--json].";
|
|
5287
5030
|
const asJson = args.includes("--json");
|
|
@@ -5289,9 +5032,6 @@ function showRun(args, store, options) {
|
|
|
5289
5032
|
exactPositionals(positionals, 1, usage);
|
|
5290
5033
|
const data = store.transaction((tx) => {
|
|
5291
5034
|
const run = requireRun(tx, positionals[0], options);
|
|
5292
|
-
const facts = readRunRecoveryFacts(tx, run.taskId, run.id);
|
|
5293
|
-
if (facts === null)
|
|
5294
|
-
throw usageError(`Agent Run not found: ${run.taskId}/${run.id}.`, usage);
|
|
5295
5035
|
const retirement = tx.listEvents(run.taskId)
|
|
5296
5036
|
.map(taskRecordRetirement)
|
|
5297
5037
|
.find((entry) => entry?.recordKind === "agent-run" && entry.recordId === run.id) ?? null;
|
|
@@ -5300,7 +5040,6 @@ function showRun(args, store, options) {
|
|
|
5300
5040
|
.filter((attempt) => (attempt !== null && attempt.runId === run.id));
|
|
5301
5041
|
return {
|
|
5302
5042
|
run,
|
|
5303
|
-
recovery: projectRunRecovery(facts),
|
|
5304
5043
|
retirement,
|
|
5305
5044
|
rejectedYieldAttemptCount: allRejectedYieldAttempts.length,
|
|
5306
5045
|
rejectedYieldAttempts: allRejectedYieldAttempts.slice(-16)
|
|
@@ -5311,11 +5050,11 @@ function showRun(args, store, options) {
|
|
|
5311
5050
|
}
|
|
5312
5051
|
return {
|
|
5313
5052
|
kind: "output",
|
|
5314
|
-
output: renderRunShow(data.run, data.
|
|
5053
|
+
output: renderRunShow(data.run, data.retirement, data.rejectedYieldAttemptCount, data.rejectedYieldAttempts),
|
|
5315
5054
|
data
|
|
5316
5055
|
};
|
|
5317
5056
|
}
|
|
5318
|
-
function renderRunShow(run,
|
|
5057
|
+
function renderRunShow(run, retirement, rejectedYieldAttemptCount, rejectedYieldAttempts) {
|
|
5319
5058
|
const lines = [
|
|
5320
5059
|
`Run: ${run.id}`,
|
|
5321
5060
|
`Task: ${run.taskId}`,
|
|
@@ -5329,6 +5068,7 @@ function renderRunShow(run, recovery, retirement, rejectedYieldAttemptCount, rej
|
|
|
5329
5068
|
]),
|
|
5330
5069
|
`Effective: ${run.effective.agentId}/${run.effective.adapterId} r${run.effective.sourceDesiredRevision}`,
|
|
5331
5070
|
`Created: ${run.createdAt}`,
|
|
5071
|
+
...(run.endedAt === undefined ? [] : [`Ended: ${run.endedAt}`]),
|
|
5332
5072
|
...(run.pushedAt === undefined ? [] : [`Pushed: ${run.pushedAt}`]),
|
|
5333
5073
|
...(run.deliveredAt === undefined
|
|
5334
5074
|
? []
|
|
@@ -5349,33 +5089,6 @@ function renderRunShow(run, recovery, retirement, rejectedYieldAttemptCount, rej
|
|
|
5349
5089
|
])
|
|
5350
5090
|
])
|
|
5351
5091
|
];
|
|
5352
|
-
if (recovery.canonicalProgressAt !== null) {
|
|
5353
|
-
lines.push(`Canonical recovery fence (Yui durable CAS): ${recovery.canonicalProgressAt}`, ...(recovery.canonicalProgressEvidence === undefined
|
|
5354
|
-
? []
|
|
5355
|
-
: [`Fence evidence: ${recovery.canonicalProgressEvidence}`]));
|
|
5356
|
-
}
|
|
5357
|
-
if (recovery.provider.observedAt !== null) {
|
|
5358
|
-
lines.push(`Provider observation (evidence only, not a fence): `
|
|
5359
|
-
+ `${recovery.provider.observationKind} at ${recovery.provider.observedAt}`);
|
|
5360
|
-
}
|
|
5361
|
-
if (recovery.session !== null) {
|
|
5362
|
-
const session = recovery.session;
|
|
5363
|
-
lines.push(`Session: ${session.status}`
|
|
5364
|
-
+ `${session.nativeSessionId === undefined ? "" : ` ${session.nativeSessionId}`}`
|
|
5365
|
-
+ `${session.launchId === undefined ? "" : ` launch ${session.launchId}`}`);
|
|
5366
|
-
}
|
|
5367
|
-
if (recovery.recoverable) {
|
|
5368
|
-
lines.push(`Provider acceptance options: ${recovery.providerAcceptance.options.join(", ")}`, "Recovery actions (copy one; the fence is already canonical):");
|
|
5369
|
-
for (const plan of recovery.actions) {
|
|
5370
|
-
lines.push(` [${plan.action}] ${plan.reason}`, ` ${plan.command}`);
|
|
5371
|
-
}
|
|
5372
|
-
if (recovery.judgmentRequired !== undefined) {
|
|
5373
|
-
lines.push(`Judgment: ${recovery.judgmentRequired}`);
|
|
5374
|
-
}
|
|
5375
|
-
}
|
|
5376
|
-
else {
|
|
5377
|
-
lines.push(`Not recoverable: ${recovery.reason ?? "unknown"}`);
|
|
5378
|
-
}
|
|
5379
5092
|
return `${lines.join("\n")}\n`;
|
|
5380
5093
|
}
|
|
5381
5094
|
function truncateRunShowText(value) {
|
|
@@ -6027,6 +5740,9 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
|
|
|
6027
5740
|
}
|
|
6028
5741
|
}
|
|
6029
5742
|
const task = requireTask(tx, taskId);
|
|
5743
|
+
if (task.status !== "active")
|
|
5744
|
+
throw usageError(`Task is not active: ${task.id}.`);
|
|
5745
|
+
assertTaskExecutionEnabled(task, "dispatching a Review");
|
|
6030
5746
|
if ((round.scope ?? "work-item") === "task") {
|
|
6031
5747
|
let taskFinalContract;
|
|
6032
5748
|
try {
|
|
@@ -6308,7 +6024,7 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
|
|
|
6308
6024
|
effective,
|
|
6309
6025
|
workspace: laneWorkspace
|
|
6310
6026
|
}, now);
|
|
6311
|
-
createdRuns.push(createAgentRun(runId, taskId, laneReviewer.name,
|
|
6027
|
+
createdRuns.push(createAgentRun(runId, taskId, laneReviewer.name, roleAgentSessionResumeMode(sessions, effective.agentId, effective), assignment, now, {
|
|
6312
6028
|
...(item === undefined ? {} : { workItemId: item.id }),
|
|
6313
6029
|
purpose: "review",
|
|
6314
6030
|
reviewRoundId: round.id,
|
|
@@ -6650,12 +6366,14 @@ function assertTaskOpen(task) {
|
|
|
6650
6366
|
if (task.status === "retired")
|
|
6651
6367
|
throw usageError(`Task is retired: ${task.id}.`);
|
|
6652
6368
|
}
|
|
6369
|
+
function assertTaskExecutionEnabled(task, action) {
|
|
6370
|
+
if (task.executionGate.state === "enabled")
|
|
6371
|
+
return;
|
|
6372
|
+
throw usageError(`Task execution is stopped: ${task.id}. Run "yui task execution start ${task.id}" before ${action}.`);
|
|
6373
|
+
}
|
|
6653
6374
|
function taskActor(store, options, taskId) {
|
|
6654
6375
|
return resolveTaskLocalActor(store, options.environment, taskId, options.yuiHome);
|
|
6655
6376
|
}
|
|
6656
|
-
function taskRoleDispatchMode(store, taskId, roleName, sessions, agentId, effective) {
|
|
6657
|
-
return roleSessionDispatchModeWithConversationSwitch(sessions, store.listEvents(taskId), store.getWorkMailbox({ kind: "role", taskId, roleName }), roleName, agentId, effective);
|
|
6658
|
-
}
|
|
6659
6377
|
function inactiveTaskMessage(task, action) {
|
|
6660
6378
|
if (task.status === "draft") {
|
|
6661
6379
|
return `Task ${task.id} is a Draft; activate it before ${action}.`;
|
|
@@ -6683,18 +6401,6 @@ function parseWorkStatus(value) {
|
|
|
6683
6401
|
return "failed";
|
|
6684
6402
|
throw usageError(`Invalid work item status: ${value}.`);
|
|
6685
6403
|
}
|
|
6686
|
-
function parseRecoveryAction(value, usage) {
|
|
6687
|
-
if (value === "diagnose"
|
|
6688
|
-
|| value === "retry"
|
|
6689
|
-
|| value === "terminate")
|
|
6690
|
-
return value;
|
|
6691
|
-
throw usageError("--action must be diagnose, retry, or terminate.", usage);
|
|
6692
|
-
}
|
|
6693
|
-
function parseProviderAcceptance(value, usage) {
|
|
6694
|
-
if (value === "accepted" || value === "rejected" || value === "ambiguous")
|
|
6695
|
-
return value;
|
|
6696
|
-
throw usageError("--provider-acceptance must be accepted, rejected, or ambiguous.", usage);
|
|
6697
|
-
}
|
|
6698
6404
|
function presentWorkStatus(status) {
|
|
6699
6405
|
if (status === "pending")
|
|
6700
6406
|
return "todo";
|
|
@@ -7437,14 +7143,42 @@ function messageOf(error) {
|
|
|
7437
7143
|
function taskMailbox(taskId) {
|
|
7438
7144
|
return { kind: "task", taskId };
|
|
7439
7145
|
}
|
|
7440
|
-
function
|
|
7146
|
+
function settleTaskExecutionForCompletion(store, taskId, roles, summary, now) {
|
|
7147
|
+
const activeRuns = store.listAgentRuns(taskId).filter((run) => run.status === "active");
|
|
7148
|
+
for (const run of activeRuns) {
|
|
7149
|
+
store.saveAgentRun(run.roleName === LEADER_ROLE && run.pushedAt !== undefined
|
|
7150
|
+
? yieldAgentRun(run, summary, now)
|
|
7151
|
+
: failAgentRun(run, `Task completed: ${summary}`, now));
|
|
7152
|
+
if (run.executionGroupId !== undefined && run.executionLaneId !== undefined) {
|
|
7153
|
+
store.clearActiveExecutionLaneRun(taskId, run.executionGroupId, run.executionLaneId);
|
|
7154
|
+
}
|
|
7155
|
+
}
|
|
7156
|
+
// Historical pointer projections are execution state, not Task progress.
|
|
7157
|
+
for (const run of store.listAgentRuns(taskId)) {
|
|
7158
|
+
if (run.executionGroupId !== undefined && run.executionLaneId !== undefined) {
|
|
7159
|
+
store.clearActiveExecutionLaneRun(taskId, run.executionGroupId, run.executionLaneId);
|
|
7160
|
+
}
|
|
7161
|
+
}
|
|
7441
7162
|
const targets = [];
|
|
7442
7163
|
for (const role of roles) {
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
const
|
|
7446
|
-
const
|
|
7447
|
-
if (
|
|
7164
|
+
store.clearActiveAgentRun(taskId, role.name);
|
|
7165
|
+
let sessions = store.getTaskRoleSessionSet(taskId, role.name);
|
|
7166
|
+
const activeSession = sessions?.sessions[sessions.activeAgentId];
|
|
7167
|
+
const cleanupRequired = ownedRuntimeSessionRequiresCleanup(activeSession);
|
|
7168
|
+
if (sessions !== null) {
|
|
7169
|
+
if (sessions.inFlight !== null) {
|
|
7170
|
+
sessions = terminalizeTaskRoleRunSession(sessions, sessions.inFlight, now);
|
|
7171
|
+
}
|
|
7172
|
+
const current = sessions.sessions[sessions.activeAgentId];
|
|
7173
|
+
if (current !== undefined && current.status !== "stopped" && current.status !== "broken") {
|
|
7174
|
+
sessions = updateRoleAgentSessionStatus(sessions, sessions.activeAgentId, "stopped", now);
|
|
7175
|
+
}
|
|
7176
|
+
store.saveTaskRoleSessionSet(sessions);
|
|
7177
|
+
}
|
|
7178
|
+
if (role.status !== "idle") {
|
|
7179
|
+
store.saveRole(taskId, updateRoleStatus(role, "idle", now));
|
|
7180
|
+
}
|
|
7181
|
+
if (!cleanupRequired)
|
|
7448
7182
|
continue;
|
|
7449
7183
|
const target = runtimeLifecycleTarget({
|
|
7450
7184
|
scope: "task",
|
|
@@ -4,11 +4,9 @@ import { formatTimestamp } from "../output/timePresentation.js";
|
|
|
4
4
|
import { isRoleRunStalled, latestStallProgressAt } from "../scheduler/roleRunStall.js";
|
|
5
5
|
import { buildTaskExecutionProjection } from "../scheduler/taskExecutionProjection.js";
|
|
6
6
|
import { projectNextAction } from "../task/nextAction.js";
|
|
7
|
-
import { inspectTaskRoleSessionRecovery } from "./taskRoleRuntimeStatus.js";
|
|
8
7
|
import { summarizeExecutionGroup } from "../execution/executionGroup.js";
|
|
9
8
|
import { currentWorkItemExecutionGroup } from "../workItem/workItem.js";
|
|
10
9
|
import { operationalTaskRecords } from "../task/taskRecordRetirement.js";
|
|
11
|
-
import { projectExecutionLaneRunRecoveries } from "../run/recoveryProjection.js";
|
|
12
10
|
import { projectReviewDecision } from "../review/reviewDecision.js";
|
|
13
11
|
const RECENT_RECORD_LIMIT = 5;
|
|
14
12
|
const RELATED_RECORD_LIMIT = 5;
|
|
@@ -76,7 +74,6 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
76
74
|
managedWorkspaces: reader.listManagedWorkspaces(task.id),
|
|
77
75
|
roleSessionSets,
|
|
78
76
|
coordinationMailboxes,
|
|
79
|
-
roleSessionRecoveries: roles.map((role) => (inspectTaskRoleSessionRecovery(task.id, role.name, reader))),
|
|
80
77
|
workItems,
|
|
81
78
|
agentRuns,
|
|
82
79
|
reviewRounds,
|
|
@@ -90,12 +87,11 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
90
87
|
nextAction: projectNextAction({
|
|
91
88
|
...nextActionFacts,
|
|
92
89
|
currentTaskReviewCandidate,
|
|
93
|
-
executionGroups: execution.executionGroups
|
|
94
|
-
runRecoveries: projectExecutionLaneRunRecoveries(reader, task.id, execution.executionGroups)
|
|
90
|
+
executionGroups: execution.executionGroups
|
|
95
91
|
})
|
|
96
92
|
};
|
|
97
93
|
});
|
|
98
|
-
const { task, execution, reviewConfig, reviewDecision, brief, activeDecisions, milestones, roles, managedWorkspaces, roleSessionSets, coordinationMailboxes,
|
|
94
|
+
const { task, execution, reviewConfig, reviewDecision, brief, activeDecisions, milestones, roles, managedWorkspaces, roleSessionSets, coordinationMailboxes, workItems, agentRuns, reviewRounds, changeSets, integrations, publications, messages, openInputRequests, resolvedInputRequests, events, nextAction } = data;
|
|
99
95
|
const timeZone = store.getConfig().timeZone;
|
|
100
96
|
const displayedActiveDecisions = activeDecisions.slice(-RECENT_RECORD_LIMIT);
|
|
101
97
|
const displayedWorkItems = currentAndRecentWorkItems(workItems);
|
|
@@ -251,7 +247,6 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
251
247
|
const activeSession = sessions?.sessions[sessions.activeAgentId];
|
|
252
248
|
const effective = activeRun?.effective ?? activeSession?.effective;
|
|
253
249
|
const effectiveSource = activeRun === undefined ? "Session" : "Run";
|
|
254
|
-
const recovery = roleSessionRecoveries.find((entry) => entry.roleName === role.name);
|
|
255
250
|
const creation = [...events].reverse().find((event) => (event.type === "role.added" && event.payload.role === role.name));
|
|
256
251
|
return [
|
|
257
252
|
` ${role.name} [${role.status}]: ${role.activeAgentId}/${binding.adapterId}`,
|
|
@@ -266,13 +261,7 @@ export function runTaskContextCommand(args, store, currentTaskReviewCandidate =
|
|
|
266
261
|
: "pending next launch"}`,
|
|
267
262
|
...(creation?.payload.runtimeSource === undefined
|
|
268
263
|
? []
|
|
269
|
-
: [` Runtime source at creation: ${creation.payload.runtimeSource}`])
|
|
270
|
-
...(recovery === undefined ? [] : [
|
|
271
|
-
` Runtime cleanup: ${recovery.runtimeCleanupPending ? "pending" : "none"}`,
|
|
272
|
-
` Fresh launch: ${recovery.freshLaunchAllowed
|
|
273
|
-
? "allowed"
|
|
274
|
-
: `blocked (${recovery.freshLaunchBlockers.join(", ")})`}`
|
|
275
|
-
])
|
|
264
|
+
: [` Runtime source at creation: ${creation.payload.runtimeSource}`])
|
|
276
265
|
];
|
|
277
266
|
})),
|
|
278
267
|
"",
|