@zq-silk/yui 0.6.8 → 0.6.10
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 +10 -3
- package/dist/cli/commandCatalog.js +1 -1
- package/dist/commands/taskCommands.js +63 -28
- package/dist/commands/taskContextCommand.js +27 -1
- package/dist/commands/taskRoleRuntimeStatus.js +17 -6
- package/dist/controller/agentRuntimeObserver.js +6 -3
- package/dist/controller/controller.js +29 -47
- package/dist/controller/fileSchedulerStoreAdapter.js +572 -258
- package/dist/controller/runtime.js +8 -1
- package/dist/controller/runtimeEventInbox.js +16 -5
- package/dist/controller/runtimeHookRunFence.js +51 -5
- package/dist/controller/runtimeObservationHook.js +8 -2
- package/dist/coordination/workMailbox.js +408 -28
- package/dist/coordination/workMailboxQueue.js +12 -10
- package/dist/executor/agentExecutor.js +101 -94
- package/dist/executor/executorRegistry.js +47 -2
- package/dist/executor/fileRoleLaunchPlanner.js +4 -2
- package/dist/lifecycle/exactRunTerminalization.js +1 -7
- package/dist/repository/taskWorkspaceCoordinator.js +9 -4
- package/dist/runtime/agentDriver.js +83 -4
- package/dist/runtime/agentDriverObservation.js +25 -10
- package/dist/runtime/builtinAgentDrivers.js +168 -18
- package/dist/runtime/codexAppServerRuntime.js +355 -0
- package/dist/runtime/continuationManager.js +117 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/lifecycleReservation.js +4 -3
- package/dist/runtime/promptEnvelope.js +14 -3
- package/dist/runtime/providerContinuation.js +225 -0
- package/dist/runtime/providerContinuationReconciliationService.js +172 -0
- package/dist/runtime/providerRuntimeIdentity.js +232 -0
- package/dist/runtime/providerRuntimeReconciler.js +166 -0
- package/dist/runtime/runtimeContinuationProjection.js +34 -0
- package/dist/runtime/runtimeObservation.js +217 -6
- package/dist/runtime/runtimeProjection.js +172 -11
- package/dist/scheduler/activeRoleRunDelivery.js +314 -1
- package/dist/scheduler/leaderWakeupProcessor.js +2 -1
- package/dist/scheduler/operatorInputNotificationProcessor.js +3 -2
- package/dist/scheduler/roleRunLiveness.js +8 -7
- package/dist/scheduler/roleRunStall.js +4 -2
- package/dist/scheduler/taskExecutionProjection.js +2 -2
- package/dist/storage/migration/productionRegistry.js +474 -1
- package/dist/storage/sqliteSchema.js +102 -21
- package/dist/storage/sqliteStore.js +52 -110
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +0 -1
- package/dist/storage/taskStore.js +40 -53
- package/dist/storage/upgrade/sqliteStateMigration.js +0 -21
- package/dist/task/nextAction.js +1 -1
- package/dist/web/assets/client/app.js +1 -1
- package/dist/web/assets/client/components.js +233 -4
- package/dist/web/assets/client/i18n.js +166 -2
- package/dist/web/assets/client/view.js +30 -13
- package/dist/web/assets/styles/cards.js +62 -0
- package/dist/web/assets/styles/widgets.js +1 -0
- package/dist/web/webSnapshot.js +11 -2
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +33 -24
- package/skills/yui-operator/SKILL.md +7 -5
|
@@ -13,6 +13,7 @@ import { isProjectMaintenanceFenced } from "../repository/projectMaintenanceLock
|
|
|
13
13
|
import { KeyedWorkQueue } from "../coordination/keyedWorkQueue.js";
|
|
14
14
|
import { MailboxScheduler } from "../coordination/mailboxScheduler.js";
|
|
15
15
|
import { nearestDeadlineBatch } from "../coordination/deadlineScheduler.js";
|
|
16
|
+
import { mailboxHasWork, nextPendingBatch } from "../coordination/workMailbox.js";
|
|
16
17
|
import { hasRuntimeCleanupObligation, isRuntimeLaunchReservation, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
17
18
|
import { formatTaskRecordReference } from "../task/taskRecordReference.js";
|
|
18
19
|
import { parseDurableJobAcknowledgeParams, parseDurableJobCancelParams, parseDurableJobRefParams, parseDurableJobStartParams } from "./jobControl.js";
|
|
@@ -43,7 +44,7 @@ const ZERO_DRAIN_METRICS = Object.freeze({
|
|
|
43
44
|
* Runs one lean scheduler pass. Due native Turn completions are folded before
|
|
44
45
|
* liveness, so a valid Hook boundary fences destructive process reconciliation.
|
|
45
46
|
*/
|
|
46
|
-
export async function runControllerSchedulerPass(store, delivery, now, workspacePreparer, scope = { kind: "full" }, includeOperator = true, runtimeCleanupOutcomes = [], lifecycleHost, stallWindowMs = DEFAULT_STALL_WINDOW_MS, maintenanceFence, onMaintenanceFenceDefer, blockedTaskIds = new Set()) {
|
|
47
|
+
export async function runControllerSchedulerPass(store, delivery, now, workspacePreparer, scope = { kind: "full" }, includeOperator = true, runtimeCleanupOutcomes = [], lifecycleHost, stallWindowMs = DEFAULT_STALL_WINDOW_MS, maintenanceFence, onMaintenanceFenceDefer, blockedTaskIds = new Set(), inputDeliveryRecoveryCutoff) {
|
|
47
48
|
const compiledSelection = compileReconcileSelection(scope);
|
|
48
49
|
const selection = includeOperator
|
|
49
50
|
? { ...compiledSelection, blockedTaskIds }
|
|
@@ -75,12 +76,11 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
75
76
|
// Sessions before delivery, so the existing delivery path re-pushes the
|
|
76
77
|
// exact same input in this same pass.
|
|
77
78
|
resolveDueProviderRetries(store, roleSelection, now);
|
|
78
|
-
const activeRunDeliveries = await processActiveRoleRunDeliveries(store, delivery, now, roleSelection);
|
|
79
|
+
const activeRunDeliveries = await processActiveRoleRunDeliveries(store, delivery, now, roleSelection, inputDeliveryRecoveryCutoff);
|
|
79
80
|
await controlEventLoopTurn();
|
|
80
81
|
const unsettledRunRefs = new Set(activeRunDeliveries.flatMap((result) => (result.reason === "delivery-uncertain" || result.terminalFailure !== undefined
|
|
81
82
|
? [formatTaskRecordReference(result.taskId, result.runId, "agentRun")]
|
|
82
83
|
: [])));
|
|
83
|
-
resolveDueRuntimeTurnCompletions(store, delivery, selection, now);
|
|
84
84
|
// Every successful Task has completed the targeted phases owned by its
|
|
85
85
|
// mailbox at this boundary. Settle that exact claim before advisory
|
|
86
86
|
// cross-Task reconciliation so an unrelated failure cannot retain and
|
|
@@ -412,29 +412,6 @@ function runtimeOwnerIdentity(owner) {
|
|
|
412
412
|
? `task\0${owner.taskId}\0${owner.roleName}`
|
|
413
413
|
: `global\0${owner.roleName}`;
|
|
414
414
|
}
|
|
415
|
-
function resolveDueRuntimeTurnCompletions(store, delivery, selection, now) {
|
|
416
|
-
if (typeof store.resolveDueRuntimeTurnCompletions !== "function")
|
|
417
|
-
return;
|
|
418
|
-
const selectedTaskIds = selectedTaskIdsForBoundedPass(store, selection);
|
|
419
|
-
if (selectedTaskIds?.size === 0)
|
|
420
|
-
return;
|
|
421
|
-
const candidateTaskIds = selectedTaskIds === undefined
|
|
422
|
-
? undefined
|
|
423
|
-
: [...selectedTaskIds].sort((left, right) => (left.localeCompare(right, undefined, { numeric: true })));
|
|
424
|
-
const candidates = store.listPendingRuntimeTurnCompletions(candidateTaskIds);
|
|
425
|
-
const finalized = new Set(store.resolveDueRuntimeTurnCompletions(now, selectedTaskIds));
|
|
426
|
-
if (finalized.size === 0)
|
|
427
|
-
return;
|
|
428
|
-
for (const completion of candidates) {
|
|
429
|
-
if (!finalized.has(formatTaskRecordReference(completion.taskId, completion.runId, "agentRun")))
|
|
430
|
-
continue;
|
|
431
|
-
delivery.forgetPrepared?.({
|
|
432
|
-
taskId: completion.taskId,
|
|
433
|
-
roleName: completion.roleName,
|
|
434
|
-
runId: completion.runId
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
415
|
/**
|
|
439
416
|
* Issue 04: reopens due in-place Provider retries on their original Native
|
|
440
417
|
* Sessions before the active-run delivery pass, so the existing delivery
|
|
@@ -540,7 +517,7 @@ function runtimeCleanupMailboxKey(target) {
|
|
|
540
517
|
function runtimeLifecycleBatchIdentity(target, mailbox) {
|
|
541
518
|
if (mailbox.processing !== null)
|
|
542
519
|
return mailbox.processing.batchId;
|
|
543
|
-
const pending = mailbox
|
|
520
|
+
const pending = nextPendingBatch(mailbox);
|
|
544
521
|
return pending === null
|
|
545
522
|
? runtimeTargetIdentity(target)
|
|
546
523
|
: `${runtimeTargetIdentity(target)}:${pending.fromSequence}-${pending.toSequence}`;
|
|
@@ -607,10 +584,11 @@ function claimSelectedTaskMailboxes(store, selection, now) {
|
|
|
607
584
|
const claims = [];
|
|
608
585
|
for (const target of targets) {
|
|
609
586
|
const mailbox = store.getWorkMailbox(target);
|
|
610
|
-
if (mailbox === null || (mailbox
|
|
587
|
+
if (mailbox === null || !mailboxHasWork(mailbox))
|
|
611
588
|
continue;
|
|
589
|
+
const pending = nextPendingBatch(mailbox);
|
|
612
590
|
const batchId = mailbox.processing?.batchId
|
|
613
|
-
?? `task:${encodeURIComponent(target.taskId)}:${
|
|
591
|
+
?? `task:${encodeURIComponent(target.taskId)}:${pending.fromSequence}-${pending.toSequence}`;
|
|
614
592
|
const claim = store.claimWorkMailbox({
|
|
615
593
|
target,
|
|
616
594
|
batchId,
|
|
@@ -809,6 +787,7 @@ function mergeControllerSchedulerResults(results) {
|
|
|
809
787
|
export class FileTaskController {
|
|
810
788
|
store;
|
|
811
789
|
delivery;
|
|
790
|
+
#startedAt;
|
|
812
791
|
#intervalMs;
|
|
813
792
|
#now;
|
|
814
793
|
#onError;
|
|
@@ -841,6 +820,7 @@ export class FileTaskController {
|
|
|
841
820
|
#maintenanceFence;
|
|
842
821
|
#onMaintenanceFenceDefer;
|
|
843
822
|
#jobSupervisor;
|
|
823
|
+
#continuationReconciler;
|
|
844
824
|
#current;
|
|
845
825
|
#operatorCurrent;
|
|
846
826
|
#runtimeObserverCurrent;
|
|
@@ -860,6 +840,7 @@ export class FileTaskController {
|
|
|
860
840
|
this.delivery = delivery;
|
|
861
841
|
this.#intervalMs = positiveInteger(options.intervalMs, DEFAULT_RECONCILIATION_INTERVAL_MS, "Controller reconciliation interval");
|
|
862
842
|
this.#now = options.now ?? (() => new Date());
|
|
843
|
+
this.#startedAt = this.#now();
|
|
863
844
|
this.#onError = options.onError ?? (() => { });
|
|
864
845
|
this.#workspacePreparer = options.workspacePreparer;
|
|
865
846
|
this.#deliveryRetryMs = positiveInteger(options.deliveryRetryMs, DEFAULT_DELIVERY_RETRY_MS, "Controller delivery retry delay");
|
|
@@ -878,6 +859,7 @@ export class FileTaskController {
|
|
|
878
859
|
this.#maintenanceFence = options.maintenanceFence;
|
|
879
860
|
this.#onMaintenanceFenceDefer = options.onMaintenanceFenceDefer;
|
|
880
861
|
this.#jobSupervisor = options.jobSupervisor;
|
|
862
|
+
this.#continuationReconciler = options.continuationReconciler;
|
|
881
863
|
this.#signalScheduler = new MailboxScheduler(async (keys) => { await this.#requestPass({ kind: "dirty", keys }); }, {
|
|
882
864
|
windowMs: options.signalWindowMs ?? DEFAULT_SIGNAL_WINDOW_MS,
|
|
883
865
|
onError: this.#onError,
|
|
@@ -1045,7 +1027,7 @@ export class FileTaskController {
|
|
|
1045
1027
|
return;
|
|
1046
1028
|
const mailbox = this.store.getWorkMailbox({ kind: "operator" });
|
|
1047
1029
|
const shouldArm = mailbox !== null
|
|
1048
|
-
&& (mailbox
|
|
1030
|
+
&& mailboxHasWork(mailbox);
|
|
1049
1031
|
if (shouldArm)
|
|
1050
1032
|
this.#clearDeliveryRetry("operator");
|
|
1051
1033
|
this.#operatorStartupRetryArmed = shouldArm;
|
|
@@ -1116,12 +1098,18 @@ export class FileTaskController {
|
|
|
1116
1098
|
for (const taskId of runtimeTaskFailureIds(firstRuntimeDrain)) {
|
|
1117
1099
|
runtimeFailedTaskIds.add(taskId);
|
|
1118
1100
|
}
|
|
1101
|
+
// Detached reconciliation is deliberately confined to the low-rate
|
|
1102
|
+
// full pass. It queries only identities already present in Task
|
|
1103
|
+
// facts and cannot start a model Turn or scan unknown children.
|
|
1104
|
+
if (scope.kind === "full" && this.#continuationReconciler !== undefined) {
|
|
1105
|
+
await this.#continuationReconciler.reconcile(this.#now());
|
|
1106
|
+
}
|
|
1119
1107
|
// DurableJob reconciliation runs before the scheduler pass so a
|
|
1120
1108
|
// terminal job's Leader wakeup is enqueued in the same pass that
|
|
1121
1109
|
// processes Leader wakeups.
|
|
1122
1110
|
this.#jobSupervisor?.reconcile(this.#now());
|
|
1123
1111
|
if (scope.kind === "full") {
|
|
1124
|
-
result = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, scope, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, runtimeFailedTaskIds);
|
|
1112
|
+
result = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, scope, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, runtimeFailedTaskIds, this.#startedAt);
|
|
1125
1113
|
}
|
|
1126
1114
|
else {
|
|
1127
1115
|
const dirtyPass = await this.#runDirtySchedulerPass(scope, runtimeCleanupOutcomes, runtimeFailedTaskIds);
|
|
@@ -1219,7 +1207,7 @@ export class FileTaskController {
|
|
|
1219
1207
|
const taskScopes = partition.taskScopes.filter((taskScope) => (!blockedTaskIds.has(taskScope.taskId)));
|
|
1220
1208
|
const orderedResults = [];
|
|
1221
1209
|
if (partition.globalKeys.length > 0) {
|
|
1222
|
-
orderedResults.push(await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: partition.globalKeys }, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds));
|
|
1210
|
+
orderedResults.push(await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: partition.globalKeys }, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#startedAt));
|
|
1223
1211
|
}
|
|
1224
1212
|
if (taskScopes.length === 0
|
|
1225
1213
|
|| this.#stopped
|
|
@@ -1252,7 +1240,7 @@ export class FileTaskController {
|
|
|
1252
1240
|
if (this.#stopped || this.#pendingFull)
|
|
1253
1241
|
continue;
|
|
1254
1242
|
try {
|
|
1255
|
-
taskResults[selected.index] = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: selected.taskScope.keys }, false, taskCleanupOutcomes[selected.index], this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds);
|
|
1243
|
+
taskResults[selected.index] = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, { kind: "dirty", keys: selected.taskScope.keys }, false, taskCleanupOutcomes[selected.index], this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer, blockedTaskIds, this.#startedAt);
|
|
1256
1244
|
this.#clearTaskPassRetry(selected.taskScope.taskId);
|
|
1257
1245
|
}
|
|
1258
1246
|
catch (error) {
|
|
@@ -1300,7 +1288,7 @@ export class FileTaskController {
|
|
|
1300
1288
|
if (this.#operatorStartupRetryArmed && result.inputNotifications.length === 0) {
|
|
1301
1289
|
const mailbox = this.store.getWorkMailbox({ kind: "operator" });
|
|
1302
1290
|
if (mailbox === null
|
|
1303
|
-
|| (mailbox
|
|
1291
|
+
|| !mailboxHasWork(mailbox)) {
|
|
1304
1292
|
this.#operatorStartupRetryArmed = false;
|
|
1305
1293
|
}
|
|
1306
1294
|
}
|
|
@@ -1443,12 +1431,6 @@ export class FileTaskController {
|
|
|
1443
1431
|
at: Date.parse(request.policy.timeoutAt)
|
|
1444
1432
|
}]
|
|
1445
1433
|
: []),
|
|
1446
|
-
...(typeof this.store.listPendingRuntimeTurnCompletions === "function"
|
|
1447
|
-
? this.store.listPendingRuntimeTurnCompletions()
|
|
1448
|
-
: []).map((completion) => ({
|
|
1449
|
-
key: `role:${encodeURIComponent(completion.taskId)}/${encodeURIComponent(completion.roleName)}`,
|
|
1450
|
-
at: Date.parse(completion.dueAt)
|
|
1451
|
-
})),
|
|
1452
1434
|
// Issue 04 durable in-place retry timer: arm the Controller wake at the
|
|
1453
1435
|
// earliest `nextAttemptAt` so a due retry re-pushes on its original
|
|
1454
1436
|
// Session. The projection is durable, so a restart resumes the lineage.
|
|
@@ -1491,8 +1473,7 @@ export class FileTaskController {
|
|
|
1491
1473
|
else if (delivery.reason === "writer-attached")
|
|
1492
1474
|
writerBlocked.add(key);
|
|
1493
1475
|
else if (delivery.reason === "not-ready"
|
|
1494
|
-
|| delivery.reason === "runtime-unavailable"
|
|
1495
|
-
|| delivery.reason === "delivery-uncertain") {
|
|
1476
|
+
|| delivery.reason === "runtime-unavailable") {
|
|
1496
1477
|
retry.set(key, {
|
|
1497
1478
|
identity: delivery.runId,
|
|
1498
1479
|
...(delivery.terminalFailure === undefined
|
|
@@ -1508,8 +1489,7 @@ export class FileTaskController {
|
|
|
1508
1489
|
if (wakeup.reason === "writer-attached") {
|
|
1509
1490
|
writerBlocked.add(key);
|
|
1510
1491
|
}
|
|
1511
|
-
else if (wakeup.reason === "not-ready"
|
|
1512
|
-
|| wakeup.reason === "delivery-uncertain") {
|
|
1492
|
+
else if (wakeup.reason === "not-ready") {
|
|
1513
1493
|
retry.set(key, { identity: wakeup.runId ?? key });
|
|
1514
1494
|
}
|
|
1515
1495
|
else if (wakeup.status === "dispatched")
|
|
@@ -1569,7 +1549,8 @@ export class FileTaskController {
|
|
|
1569
1549
|
const mailbox = this.store.getWorkMailbox(target);
|
|
1570
1550
|
// A newly queued pending batch must not reset the retry identity/bound
|
|
1571
1551
|
// while this Controller still owns an older processing batch.
|
|
1572
|
-
const batch = mailbox?.processing?.batch
|
|
1552
|
+
const batch = mailbox?.processing?.batch
|
|
1553
|
+
?? (mailbox === null || mailbox === undefined ? null : nextPendingBatch(mailbox));
|
|
1573
1554
|
if (batch === undefined || batch === null) {
|
|
1574
1555
|
this.#clearDeliveryRetry(key);
|
|
1575
1556
|
continue;
|
|
@@ -1657,7 +1638,7 @@ export class FileTaskController {
|
|
|
1657
1638
|
return;
|
|
1658
1639
|
const mailbox = this.store.getWorkMailbox({ kind: "operator" });
|
|
1659
1640
|
if (mailbox === null
|
|
1660
|
-
|| (mailbox
|
|
1641
|
+
|| !mailboxHasWork(mailbox)) {
|
|
1661
1642
|
this.#operatorStartupRetryArmed = false;
|
|
1662
1643
|
this.#clearDeliveryRetry("operator");
|
|
1663
1644
|
}
|
|
@@ -1886,7 +1867,8 @@ function boundedPositiveInteger(value, fallback, maximum, label) {
|
|
|
1886
1867
|
return resolved;
|
|
1887
1868
|
}
|
|
1888
1869
|
function operatorMailboxBatchIdentity(mailbox) {
|
|
1889
|
-
const batch = mailbox?.
|
|
1870
|
+
const batch = mailbox?.processing?.batch
|
|
1871
|
+
?? (mailbox === null || mailbox === undefined ? null : nextPendingBatch(mailbox));
|
|
1890
1872
|
if (batch === null || batch === undefined)
|
|
1891
1873
|
return null;
|
|
1892
1874
|
return [
|