@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
|
@@ -14,11 +14,11 @@ const messages = {
|
|
|
14
14
|
"overview.lede": "Tracking {total} tasks — {active} active, {inputs} awaiting input, {completed} completed.",
|
|
15
15
|
"overview.distribution": "Status distribution",
|
|
16
16
|
"overview.attention": "Needs attention",
|
|
17
|
-
"overview.attentionEmpty": "No open inputs or stalled
|
|
17
|
+
"overview.attentionEmpty": "No open inputs or stalled Turns.",
|
|
18
18
|
"overview.activeNow": "Active now",
|
|
19
19
|
"overview.activeEmpty": "No tasks are currently active.",
|
|
20
20
|
"sync.label": "LAST SYNC",
|
|
21
|
-
"actions.
|
|
21
|
+
"actions.openSession": "Open Session",
|
|
22
22
|
"actions.operator": "Operator session",
|
|
23
23
|
"actions.refresh": "Refresh",
|
|
24
24
|
"actions.showLess": "Show less",
|
|
@@ -81,7 +81,7 @@ const messages = {
|
|
|
81
81
|
"detail.effective": "Effective launch",
|
|
82
82
|
"detail.effectiveAgent": "Effective Agent",
|
|
83
83
|
"detail.evidence": "Diagnostic evidence",
|
|
84
|
-
"detail.execution": "
|
|
84
|
+
"detail.execution": "Turns",
|
|
85
85
|
"detail.expectedOutput": "Expected output",
|
|
86
86
|
"detail.focus": "Current focus",
|
|
87
87
|
"detail.runtimeHealth": "Runtime health",
|
|
@@ -129,7 +129,7 @@ const messages = {
|
|
|
129
129
|
"disposition.removed": "Removed",
|
|
130
130
|
"empty.brief": "No task brief has been recorded.",
|
|
131
131
|
"empty.none": "No items",
|
|
132
|
-
"empty.
|
|
132
|
+
"empty.turns": "No Turns yet.",
|
|
133
133
|
"empty.tasks": "No tasks match this view.",
|
|
134
134
|
"errors.answer": "Unable to answer this input.",
|
|
135
135
|
"errors.dashboard": "Unable to read the dashboard.",
|
|
@@ -192,9 +192,8 @@ const messages = {
|
|
|
192
192
|
"role.failed": "Failed",
|
|
193
193
|
"role.idle": "Idle",
|
|
194
194
|
"role.running": "Running",
|
|
195
|
-
"
|
|
196
|
-
"
|
|
197
|
-
"run.yielded": "Yielded",
|
|
195
|
+
"turn.active": "Active",
|
|
196
|
+
"turn.failed": "Failed",
|
|
198
197
|
"search.label": "Search tasks",
|
|
199
198
|
"search.placeholder": "Filter by title, ID, tag, or project…",
|
|
200
199
|
"stats.inputs": "inputs",
|
|
@@ -206,7 +205,7 @@ const messages = {
|
|
|
206
205
|
"status.draft": "Draft",
|
|
207
206
|
"status.retired": "Retired",
|
|
208
207
|
"sync.label": "Last sync",
|
|
209
|
-
"tabs.exec": "
|
|
208
|
+
"tabs.exec": "Turns",
|
|
210
209
|
"tabs.focus": "Focus",
|
|
211
210
|
"tabs.history": "History",
|
|
212
211
|
"tabs.label": "Task sections",
|
|
@@ -238,7 +237,6 @@ const messages = {
|
|
|
238
237
|
"work.superseded": "Superseded",
|
|
239
238
|
"stats.running": "running",
|
|
240
239
|
"stats.inputs": "inputs",
|
|
241
|
-
"stats.stalledRuns": "stalled Runs",
|
|
242
240
|
"exec.status.needs-leader-action": "Needs leader action",
|
|
243
241
|
"exec.status.waiting-on-agents": "Waiting on agents",
|
|
244
242
|
"exec.status.waiting-user": "Waiting on you",
|
|
@@ -286,7 +284,6 @@ const messages = {
|
|
|
286
284
|
"exec.lanesFailed": "failed",
|
|
287
285
|
"lane.pending": "Pending",
|
|
288
286
|
"lane.running": "Running",
|
|
289
|
-
"lane.yielded": "Yielded",
|
|
290
287
|
"lane.completed": "Completed",
|
|
291
288
|
"lane.failed": "Failed",
|
|
292
289
|
"lane.skipped": "Skipped",
|
|
@@ -317,22 +314,15 @@ const messages = {
|
|
|
317
314
|
"detail.lineage": "Execution",
|
|
318
315
|
"detail.requester": "Requested by",
|
|
319
316
|
"candidate.source.direct": "Direct",
|
|
320
|
-
"candidate.source.
|
|
317
|
+
"candidate.source.turn": "Turn",
|
|
321
318
|
"finding.severity.low": "Low",
|
|
322
319
|
"finding.severity.medium": "Medium",
|
|
323
320
|
"finding.severity.high": "High",
|
|
324
321
|
"finding.severity.critical": "Critical",
|
|
325
322
|
"finding.status.open": "Open",
|
|
326
323
|
"finding.status.resolved": "Resolved",
|
|
327
|
-
"
|
|
328
|
-
"
|
|
329
|
-
"run.disposition": "Disposition",
|
|
330
|
-
"run.disposition.progress": "Progressing",
|
|
331
|
-
"run.disposition.waiting": "Waiting",
|
|
332
|
-
"run.disposition.blocked": "Blocked",
|
|
333
|
-
"run.disposition.completed": "Completed",
|
|
334
|
-
"run.waitReason": "Waiting on",
|
|
335
|
-
"run.yieldReceipt": "Yield receipt",
|
|
324
|
+
"turn.purpose.execution": "Execution",
|
|
325
|
+
"turn.purpose.review": "Review",
|
|
336
326
|
"review.scope.work-item": "Work item",
|
|
337
327
|
"review.scope.task": "Task"
|
|
338
328
|
},
|
|
@@ -354,7 +344,7 @@ const messages = {
|
|
|
354
344
|
"overview.activeNow": "进行中",
|
|
355
345
|
"overview.activeEmpty": "当前没有进行中的任务。",
|
|
356
346
|
"sync.label": "最近同步",
|
|
357
|
-
"actions.
|
|
347
|
+
"actions.openSession": "打开会话",
|
|
358
348
|
"actions.operator": "Operator 会话",
|
|
359
349
|
"actions.refresh": "刷新",
|
|
360
350
|
"actions.showLess": "收起",
|
|
@@ -465,7 +455,7 @@ const messages = {
|
|
|
465
455
|
"disposition.removed": "已移除",
|
|
466
456
|
"empty.brief": "尚未记录任务简报。",
|
|
467
457
|
"empty.none": "暂无条目",
|
|
468
|
-
"empty.
|
|
458
|
+
"empty.turns": "暂无 Turn 记录。",
|
|
469
459
|
"empty.tasks": "当前视图没有匹配的任务。",
|
|
470
460
|
"errors.answer": "无法回答该输入请求。",
|
|
471
461
|
"errors.dashboard": "无法读取控制面板。",
|
|
@@ -528,9 +518,8 @@ const messages = {
|
|
|
528
518
|
"role.failed": "失败",
|
|
529
519
|
"role.idle": "空闲",
|
|
530
520
|
"role.running": "运行中",
|
|
531
|
-
"
|
|
532
|
-
"
|
|
533
|
-
"run.yielded": "已交付",
|
|
521
|
+
"turn.active": "执行中",
|
|
522
|
+
"turn.failed": "失败",
|
|
534
523
|
"search.label": "搜索任务",
|
|
535
524
|
"search.placeholder": "按标题、ID、标签或项目筛选…",
|
|
536
525
|
"stats.inputs": "项输入",
|
|
@@ -574,7 +563,6 @@ const messages = {
|
|
|
574
563
|
"work.superseded": "已替代",
|
|
575
564
|
"stats.running": "运行中",
|
|
576
565
|
"stats.inputs": "项输入",
|
|
577
|
-
"stats.stalledRuns": "停滞运行",
|
|
578
566
|
"exec.status.needs-leader-action": "待负责人处理",
|
|
579
567
|
"exec.status.waiting-on-agents": "等待智能体",
|
|
580
568
|
"exec.status.waiting-user": "等待你回答",
|
|
@@ -622,7 +610,6 @@ const messages = {
|
|
|
622
610
|
"exec.lanesFailed": "失败",
|
|
623
611
|
"lane.pending": "待处理",
|
|
624
612
|
"lane.running": "运行中",
|
|
625
|
-
"lane.yielded": "已交付",
|
|
626
613
|
"lane.completed": "已完成",
|
|
627
614
|
"lane.failed": "失败",
|
|
628
615
|
"lane.skipped": "已跳过",
|
|
@@ -653,22 +640,15 @@ const messages = {
|
|
|
653
640
|
"detail.lineage": "执行谱系",
|
|
654
641
|
"detail.requester": "请求方",
|
|
655
642
|
"candidate.source.direct": "直接",
|
|
656
|
-
"candidate.source.
|
|
643
|
+
"candidate.source.turn": "Turn",
|
|
657
644
|
"finding.severity.low": "低",
|
|
658
645
|
"finding.severity.medium": "中",
|
|
659
646
|
"finding.severity.high": "高",
|
|
660
647
|
"finding.severity.critical": "严重",
|
|
661
648
|
"finding.status.open": "未解决",
|
|
662
649
|
"finding.status.resolved": "已解决",
|
|
663
|
-
"
|
|
664
|
-
"
|
|
665
|
-
"run.disposition": "处置",
|
|
666
|
-
"run.disposition.progress": "推进中",
|
|
667
|
-
"run.disposition.waiting": "等待中",
|
|
668
|
-
"run.disposition.blocked": "已阻塞",
|
|
669
|
-
"run.disposition.completed": "已完成",
|
|
670
|
-
"run.waitReason": "等待",
|
|
671
|
-
"run.yieldReceipt": "交付回执",
|
|
650
|
+
"turn.purpose.execution": "执行",
|
|
651
|
+
"turn.purpose.review": "评审",
|
|
672
652
|
"review.scope.work-item": "工作项",
|
|
673
653
|
"review.scope.task": "任务"
|
|
674
654
|
}
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
reviewCard,
|
|
24
24
|
richText,
|
|
25
25
|
roleCard,
|
|
26
|
-
|
|
26
|
+
turnCard,
|
|
27
27
|
sectionHead,
|
|
28
28
|
taskCard,
|
|
29
29
|
translatedStatus,
|
|
@@ -182,7 +182,7 @@ export function renderOverview(detail, state, t, locale, onSelect) {
|
|
|
182
182
|
wrap.append(inbox);
|
|
183
183
|
|
|
184
184
|
// Tasks whose Task-first projection says they need attention: blocked,
|
|
185
|
-
// recovering, or in an attention state. This replaces the raw stalled-
|
|
185
|
+
// recovering, or in an attention state. This replaces the raw stalled-Turn
|
|
186
186
|
// count with the derived execution status.
|
|
187
187
|
const attentionTasks = (state.tasks || []).filter(function (task) {
|
|
188
188
|
const status = task.executionStatus;
|
|
@@ -232,23 +232,23 @@ export function renderError(container, message) {
|
|
|
232
232
|
container.append(node("div", "error", message));
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
const
|
|
235
|
+
const TURN_PAGE_SIZE = 12;
|
|
236
236
|
const LIST_PAGE_SIZE = 10;
|
|
237
|
-
const
|
|
237
|
+
const TURN_FILTERS = ["all", "active", "completed", "failed"];
|
|
238
238
|
|
|
239
|
-
function
|
|
240
|
-
const row = node("div", "filter-row
|
|
239
|
+
function turnFilterRow(sortedTurns, t, onChange) {
|
|
240
|
+
const row = node("div", "filter-row turn-filter");
|
|
241
241
|
const buttons = [];
|
|
242
|
-
|
|
242
|
+
TURN_FILTERS.forEach(function (status) {
|
|
243
243
|
const count = status === "all"
|
|
244
|
-
?
|
|
245
|
-
:
|
|
244
|
+
? sortedTurns.length
|
|
245
|
+
: sortedTurns.filter(function (turn) { return turn.status === status; }).length;
|
|
246
246
|
if (status !== "all" && count === 0) return;
|
|
247
247
|
const btn = node("button", "filter-chip");
|
|
248
248
|
btn.type = "button";
|
|
249
249
|
btn.dataset.status = status;
|
|
250
250
|
if (status !== "all") btn.append(node("span", "filter-dot " + status));
|
|
251
|
-
btn.append(document.createTextNode(status === "all" ? t("status.all") : t("
|
|
251
|
+
btn.append(document.createTextNode(status === "all" ? t("status.all") : t("turn." + status)));
|
|
252
252
|
btn.append(node("span", "filter-count", String(count)));
|
|
253
253
|
btn.addEventListener("click", function () { onChange(status); });
|
|
254
254
|
buttons.push({ status: status, element: btn });
|
|
@@ -333,23 +333,23 @@ export function renderTaskDetail(detail, data, t, locale, actions) {
|
|
|
333
333
|
attentionBody));
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
-
const
|
|
337
|
-
? data.runtimeHealth.
|
|
336
|
+
const stalledTurns = data.runtimeHealth && data.runtimeHealth.needsAttentionTurns
|
|
337
|
+
? data.runtimeHealth.needsAttentionTurns
|
|
338
338
|
: [];
|
|
339
|
-
if (
|
|
339
|
+
if (stalledTurns.length) {
|
|
340
340
|
const runtimeHealthBody = node("div", "section-body");
|
|
341
|
-
|
|
341
|
+
stalledTurns.forEach(function (turn) {
|
|
342
342
|
const card = node("article", "record-card");
|
|
343
343
|
card.append(
|
|
344
|
-
node("strong", "",
|
|
345
|
-
node("p", "record-copy", (
|
|
346
|
-
node("small", "", t("detail.lastProgress") + " · " + formatDateTime(
|
|
344
|
+
node("strong", "", turn.roleName + " · " + turn.turnId),
|
|
345
|
+
node("p", "record-copy", (turn.kind || "workflow-not-progressing") + " · " + (turn.classification || "truly-stalled")),
|
|
346
|
+
node("small", "", t("detail.lastProgress") + " · " + formatDateTime(turn.progressAt, locale))
|
|
347
347
|
);
|
|
348
348
|
runtimeHealthBody.append(card);
|
|
349
349
|
});
|
|
350
350
|
scaffold.append(anchorSection(
|
|
351
351
|
"detail-health",
|
|
352
|
-
sectionHead(t("detail.runtimeHealth"), { count:
|
|
352
|
+
sectionHead(t("detail.runtimeHealth"), { count: stalledTurns.length }),
|
|
353
353
|
runtimeHealthBody
|
|
354
354
|
));
|
|
355
355
|
}
|
|
@@ -394,38 +394,38 @@ export function renderTaskDetail(detail, data, t, locale, actions) {
|
|
|
394
394
|
sectionHead(t("detail.workItems"), { count: data.workItems.length }),
|
|
395
395
|
workBody));
|
|
396
396
|
|
|
397
|
-
// 5.
|
|
397
|
+
// 5. Turns (anchor #detail-exec) — execution grid with status filter + paging
|
|
398
398
|
const execWrap = node("div", "section-body");
|
|
399
|
-
const execBody = node("div", "
|
|
400
|
-
const
|
|
401
|
-
if (!
|
|
402
|
-
execBody.append(emptyRow(t, "empty.
|
|
399
|
+
const execBody = node("div", "turn-grid");
|
|
400
|
+
const sortedTurns = data.turns.slice().sort(byNewest);
|
|
401
|
+
if (!sortedTurns.length) {
|
|
402
|
+
execBody.append(emptyRow(t, "empty.turns"));
|
|
403
403
|
execWrap.append(execBody);
|
|
404
404
|
} else {
|
|
405
|
-
let
|
|
406
|
-
const filter =
|
|
407
|
-
|
|
405
|
+
let activeTurnFilter = "all";
|
|
406
|
+
const filter = turnFilterRow(sortedTurns, t, function (status) {
|
|
407
|
+
activeTurnFilter = status;
|
|
408
408
|
filter.sync(status);
|
|
409
|
-
|
|
409
|
+
renderTurnGrid();
|
|
410
410
|
});
|
|
411
|
-
function
|
|
411
|
+
function renderTurnGrid() {
|
|
412
412
|
clear(execBody);
|
|
413
|
-
const visible =
|
|
414
|
-
?
|
|
415
|
-
:
|
|
416
|
-
pagedList(execBody, visible,
|
|
417
|
-
return
|
|
413
|
+
const visible = activeTurnFilter === "all"
|
|
414
|
+
? sortedTurns
|
|
415
|
+
: sortedTurns.filter(function (turn) { return turn.status === activeTurnFilter; });
|
|
416
|
+
pagedList(execBody, visible, TURN_PAGE_SIZE, function (turn) {
|
|
417
|
+
return turnCard(turn, t, locale);
|
|
418
418
|
}, t);
|
|
419
419
|
}
|
|
420
|
-
filter.sync(
|
|
420
|
+
filter.sync(activeTurnFilter);
|
|
421
421
|
execWrap.append(filter.row, execBody);
|
|
422
|
-
|
|
422
|
+
renderTurnGrid();
|
|
423
423
|
}
|
|
424
424
|
scaffold.append(anchorSection("detail-exec",
|
|
425
|
-
sectionHead(t("detail.execution"), { count: data.
|
|
425
|
+
sectionHead(t("detail.execution"), { count: data.turns.length }),
|
|
426
426
|
execWrap));
|
|
427
427
|
|
|
428
|
-
// 5b. Reviews (anchor #detail-reviews) — review rounds for
|
|
428
|
+
// 5b. Reviews (anchor #detail-reviews) — review rounds for completed candidates
|
|
429
429
|
const reviewBody = node("div", "row-list");
|
|
430
430
|
const sortedRounds = (data.reviewRounds || []).slice().sort(byNewest);
|
|
431
431
|
if (!sortedRounds.length) {
|
package/dist/web/assets/shell.js
CHANGED
|
@@ -83,7 +83,7 @@ export const DASHBOARD_HTML = `<!doctype html>
|
|
|
83
83
|
<button class="tab" type="button" data-target="detail-top" data-i18n="tabs.summary">Summary</button>
|
|
84
84
|
<button class="tab" type="button" data-target="detail-focus" data-i18n="tabs.focus">Focus</button>
|
|
85
85
|
<button class="tab" type="button" data-target="detail-work" data-i18n="tabs.work">Work items</button>
|
|
86
|
-
<button class="tab" type="button" data-target="detail-exec" data-i18n="tabs.exec">
|
|
86
|
+
<button class="tab" type="button" data-target="detail-exec" data-i18n="tabs.exec">Turns</button>
|
|
87
87
|
<button class="tab" type="button" data-target="detail-reviews" data-i18n="tabs.reviews">Reviews</button>
|
|
88
88
|
<button class="tab" type="button" data-target="detail-roles" data-i18n="tabs.roles">Roles</button>
|
|
89
89
|
<button class="tab" type="button" data-target="detail-history" data-i18n="tabs.history">History</button>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* CARDS — content-bearing surfaces.
|
|
3
3
|
* Overview blocks, detail head / conclusion band, sections, record cards,
|
|
4
|
-
* input cards,
|
|
4
|
+
* input cards, Turn cards, criteria lists. Widgets (pills, chips, metrics)
|
|
5
5
|
* live in widgets.ts; markdown typography lives in markdown.ts.
|
|
6
6
|
*/
|
|
7
7
|
export const CARD_STYLES = `
|
|
@@ -109,13 +109,13 @@ details.work-item-card>summary.record-head~*{margin-top:0}
|
|
|
109
109
|
.input-answer:hover{border-color:var(--accent-line);color:var(--accent);background:var(--accent-soft)}
|
|
110
110
|
.input-form{display:flex;gap:8px;flex:1}
|
|
111
111
|
.input-form input{min-width:0;flex:1;padding:8px 12px;color:var(--text);background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius);font-family:var(--font-body);font-size:12.5px}
|
|
112
|
-
/* Execution
|
|
113
|
-
.
|
|
114
|
-
.
|
|
112
|
+
/* Execution Turns */
|
|
113
|
+
.turn-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(320px,100%),1fr));gap:9px}
|
|
114
|
+
.turn-filter{margin-bottom:3px}
|
|
115
115
|
.execute-card{background:var(--bg-2);border:1px solid var(--border);border-left:2px solid var(--border);border-radius:var(--radius);padding:9px 12px;display:grid;gap:6px;box-shadow:var(--shadow-card);transition:border-color var(--motion-fast)}
|
|
116
116
|
.execute-card:hover{border-left-color:var(--border-strong)}
|
|
117
117
|
.execute-card[data-status=active]{border-left-color:var(--accent)}
|
|
118
|
-
.execute-card[data-status=completed]
|
|
118
|
+
.execute-card[data-status=completed]{border-left-color:var(--success)}
|
|
119
119
|
.execute-card[data-status=failed]{border-left-color:var(--danger)}
|
|
120
120
|
.execute-id{display:flex;align-items:center;gap:8px;flex-wrap:wrap;color:var(--muted);font-family:var(--font-mono);font-size:10.5px;letter-spacing:.02em}
|
|
121
121
|
.execute-id .status-dot{margin-top:0}
|
|
@@ -52,7 +52,6 @@ kbd{background:var(--bg-3);border:1px solid var(--border);border-bottom-width:2p
|
|
|
52
52
|
.filter-dot.active{background:var(--active);box-shadow:0 0 6px var(--active)}
|
|
53
53
|
.filter-dot.draft{background:var(--warning);box-shadow:0 0 6px var(--warning)}
|
|
54
54
|
.filter-dot.completed{background:var(--success);box-shadow:0 0 6px var(--success)}
|
|
55
|
-
.filter-dot.yielded{background:var(--success);box-shadow:0 0 6px var(--success)}
|
|
56
55
|
.filter-dot.failed{background:var(--danger);box-shadow:0 0 6px var(--danger)}
|
|
57
56
|
.filter-dot.retired{background:var(--faint)}
|
|
58
57
|
.filter-dot.archived{background:var(--muted)}
|
|
@@ -95,7 +94,7 @@ kbd{background:var(--bg-3);border:1px solid var(--border);border-bottom-width:2p
|
|
|
95
94
|
/* Pills + dots + chips */
|
|
96
95
|
.pill{display:inline-flex;align-items:center;font-family:var(--font-mono);font-size:9px;text-transform:uppercase;letter-spacing:.07em;padding:3px 10px;border-radius:var(--radius-pill);white-space:nowrap;color:var(--accent);background:var(--accent-soft);border:1px solid var(--accent-line)}
|
|
97
96
|
.pill[data-status=failed],.pill[data-status=urgent],.pill[data-status=required]{color:var(--danger);background:var(--danger-soft);border-color:transparent}
|
|
98
|
-
.pill[data-status=active],.pill[data-status=running]
|
|
97
|
+
.pill[data-status=active],.pill[data-status=running],
|
|
99
98
|
.pill[data-status=user],.pill[data-status=operator]{color:var(--active);background:var(--active-soft);border-color:transparent}
|
|
100
99
|
.pill[data-status=completed],.pill[data-status=integrated],.pill[data-status=role-result]{color:var(--success);background:var(--success-soft);border-color:transparent}
|
|
101
100
|
.pill[data-status=pending],.pill[data-status=draft],.pill[data-status=recommended],
|
package/dist/web/webSnapshot.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isRoleTurnStalled, latestTurnDurableProgressAt } from "../scheduler/roleTurnStall.js";
|
|
2
2
|
import { buildTaskExecutionProjection } from "../scheduler/taskExecutionProjection.js";
|
|
3
3
|
import { summarizeExecutionGroup } from "../execution/executionGroup.js";
|
|
4
4
|
import { currentWorkItemExecutionGroup } from "../workItem/workItem.js";
|
|
5
5
|
import { classifyRuntimeHealth, projectRuntimeTaskEvents } from "../runtime/runtimeProjection.js";
|
|
6
6
|
import { builtinDriverIdForAdapter } from "../runtime/builtinAgentDrivers.js";
|
|
7
|
-
import {
|
|
7
|
+
import { formatTurnReceiptId } from "../task/taskRecordReference.js";
|
|
8
8
|
import { resolveRuntimeHealth } from "../config/yuiConfig.js";
|
|
9
9
|
import { projectSessionTokenMetrics, resolveSessionTokenIdentity } from "../runtime/sessionTokenMetrics.js";
|
|
10
10
|
export function buildWebDashboardSnapshot(store, now = new Date()) {
|
|
@@ -30,8 +30,8 @@ export function buildWebDashboardSnapshot(store, now = new Date()) {
|
|
|
30
30
|
attention.push({ taskId: task.id, taskTitle: task.title, request });
|
|
31
31
|
}
|
|
32
32
|
const events = reader.listEvents?.(task.id) ?? [];
|
|
33
|
-
const needsAttentionCount = reader.
|
|
34
|
-
.filter((
|
|
33
|
+
const needsAttentionCount = reader.listTurns(task.id)
|
|
34
|
+
.filter((turn) => turn.status === "active" && isRoleTurnStalled(events, turn.id))
|
|
35
35
|
.length;
|
|
36
36
|
const execution = buildTaskExecutionProjection(reader, task.id, task, now);
|
|
37
37
|
const names = task.projectBindings.flatMap(({ projectId }) => {
|
|
@@ -68,40 +68,40 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
|
|
|
68
68
|
const name = projectNamesById.get(projectId);
|
|
69
69
|
return name === undefined ? [] : [name];
|
|
70
70
|
});
|
|
71
|
-
const
|
|
71
|
+
const turns = reader.listTurns(taskId);
|
|
72
72
|
const events = reader.listEvents?.(taskId) ?? [];
|
|
73
|
-
const
|
|
74
|
-
.filter((
|
|
75
|
-
.map((
|
|
76
|
-
|
|
77
|
-
roleName:
|
|
78
|
-
progressAt: latestStallProgress(events,
|
|
79
|
-
kind: latestStallField(events,
|
|
80
|
-
classification: latestStallField(events,
|
|
73
|
+
const needsAttentionTurns = turns
|
|
74
|
+
.filter((turn) => turn.status === "active" && isRoleTurnStalled(events, turn.id))
|
|
75
|
+
.map((turn) => ({
|
|
76
|
+
turnId: turn.id,
|
|
77
|
+
roleName: turn.roleName,
|
|
78
|
+
progressAt: latestStallProgress(events, turn.id),
|
|
79
|
+
kind: latestStallField(events, turn.id, "kind") ?? "workflow-not-progressing",
|
|
80
|
+
classification: latestStallField(events, turn.id, "classification") ?? "truly-stalled"
|
|
81
81
|
}));
|
|
82
|
-
const
|
|
83
|
-
.filter((
|
|
84
|
-
.map((
|
|
85
|
-
const
|
|
86
|
-
.filter((
|
|
87
|
-
.map((
|
|
82
|
+
const activeTurns = new Map(turns
|
|
83
|
+
.filter((turn) => turn.status === "active")
|
|
84
|
+
.map((turn) => [turn.roleName, turn]));
|
|
85
|
+
const activeTurnHealth = turns
|
|
86
|
+
.filter((turn) => turn.status === "active")
|
|
87
|
+
.map((turn) => projectWebTurnRuntimeHealth(reader, taskId, turn, events, now, resolveRuntimeHealth(reader.getConfig().runtimeHealth)));
|
|
88
88
|
const roles = reader.listRoles(taskId).map((role) => {
|
|
89
|
-
const
|
|
89
|
+
const activeTurn = activeTurns.get(role.name);
|
|
90
90
|
const sessions = reader.getTaskRoleSessionSet(taskId, role.name);
|
|
91
91
|
const activeSession = sessions?.sessions[sessions.activeAgentId];
|
|
92
|
-
const effectiveLaunch =
|
|
92
|
+
const effectiveLaunch = activeTurn?.effective ?? activeSession?.effective ?? null;
|
|
93
93
|
return {
|
|
94
94
|
...role,
|
|
95
|
-
// Presentation only: workflow activity is derived from
|
|
96
|
-
// native Session contributes lifecycle detail when no
|
|
97
|
-
status:
|
|
95
|
+
// Presentation only: workflow activity is derived from Turn; the
|
|
96
|
+
// native Session contributes lifecycle detail when no Turn is active.
|
|
97
|
+
status: activeTurn === undefined ? activeSession?.status ?? "idle" : "running",
|
|
98
98
|
sessionTokens: projectSessionTokenMetrics(events, resolveSessionTokenIdentity(activeSession === undefined
|
|
99
99
|
? null
|
|
100
100
|
: { taskId, roleName: role.name, ...activeSession })),
|
|
101
101
|
effectiveLaunch,
|
|
102
|
-
effectiveLaunchSource:
|
|
102
|
+
effectiveLaunchSource: activeTurn === undefined
|
|
103
103
|
? activeSession === undefined ? null : "session"
|
|
104
|
-
: "
|
|
104
|
+
: "turn",
|
|
105
105
|
launchDrift: effectiveLaunch !== null
|
|
106
106
|
&& effectiveLaunch.sourceDesiredRevision !== role.launchRevision
|
|
107
107
|
};
|
|
@@ -127,8 +127,8 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
|
|
|
127
127
|
...(group === undefined ? {} : { currentExecution: summarizeExecutionGroup(group) })
|
|
128
128
|
};
|
|
129
129
|
}),
|
|
130
|
-
|
|
131
|
-
runtimeHealth: {
|
|
130
|
+
turns,
|
|
131
|
+
runtimeHealth: { needsAttentionTurns, activeTurns: activeTurnHealth },
|
|
132
132
|
reviewRounds: reader.listReviewRounds(taskId),
|
|
133
133
|
openInputs: inputs.filter((request) => request.status === "open"),
|
|
134
134
|
messages: reader.listMessages(taskId),
|
|
@@ -137,61 +137,66 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
|
|
|
137
137
|
};
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
|
-
function latestStallProgress(events,
|
|
141
|
-
return latestStallField(events,
|
|
140
|
+
function latestStallProgress(events, turnId) {
|
|
141
|
+
return latestStallField(events, turnId, "progressAt");
|
|
142
142
|
}
|
|
143
143
|
/**
|
|
144
|
-
* Layered runtime health for one active
|
|
144
|
+
* Layered runtime health for one active Turn, computed from the same stored
|
|
145
145
|
* observations and durable semantic fold as the CLI status projection. The
|
|
146
146
|
* Web snapshot has no live tmux pane, so host state stays "unknown"; the
|
|
147
147
|
* classifier still surfaces session/turn/operation/observer layers and the
|
|
148
|
-
* scheduler's durable `
|
|
148
|
+
* scheduler's durable `turn.stalled` episode is surfaced as
|
|
149
149
|
* `stalled-candidate`.
|
|
150
150
|
*/
|
|
151
|
-
function
|
|
152
|
-
const stalled =
|
|
153
|
-
const sessions = reader.getTaskRoleSessionSet(taskId,
|
|
154
|
-
const session = sessions?.sessions[
|
|
155
|
-
const stallReason = "the live active
|
|
156
|
-
if (
|
|
151
|
+
function projectWebTurnRuntimeHealth(reader, taskId, turn, events, now, policy) {
|
|
152
|
+
const stalled = isRoleTurnStalled(events, turn.id);
|
|
153
|
+
const sessions = reader.getTaskRoleSessionSet(taskId, turn.roleName);
|
|
154
|
+
const session = sessions?.sessions[turn.effective.agentId];
|
|
155
|
+
const stallReason = "the live active Turn has no durable progress in the configured stall window";
|
|
156
|
+
if (session?.launchId === undefined) {
|
|
157
157
|
return {
|
|
158
|
-
|
|
159
|
-
roleName:
|
|
158
|
+
turnId: turn.id,
|
|
159
|
+
roleName: turn.roleName,
|
|
160
160
|
layer: stalled ? "stalled-candidate" : "awaiting-provider-acceptance",
|
|
161
|
-
reason: stalled ? stallReason : "the
|
|
161
|
+
reason: stalled ? stallReason : "the active Turn is awaiting a Provider Session",
|
|
162
162
|
stalled,
|
|
163
|
-
lastSemanticProgressAt:
|
|
163
|
+
lastSemanticProgressAt: turn.createdAt
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
166
|
let driverId;
|
|
167
167
|
try {
|
|
168
|
-
driverId = builtinDriverIdForAdapter(
|
|
168
|
+
driverId = builtinDriverIdForAdapter(turn.effective.adapterId);
|
|
169
169
|
}
|
|
170
170
|
catch {
|
|
171
171
|
return {
|
|
172
|
-
|
|
173
|
-
roleName:
|
|
172
|
+
turnId: turn.id,
|
|
173
|
+
roleName: turn.roleName,
|
|
174
174
|
layer: stalled ? "stalled-candidate" : "runtime-unobservable",
|
|
175
175
|
reason: stalled ? stallReason : "the Agent Driver is not a built-in driver",
|
|
176
176
|
stalled,
|
|
177
|
-
lastSemanticProgressAt:
|
|
177
|
+
lastSemanticProgressAt: turn.createdAt
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
|
+
const providerTurn = sessions?.providerBinding?.turn;
|
|
180
181
|
const fence = {
|
|
181
182
|
taskId,
|
|
182
|
-
roleName:
|
|
183
|
-
|
|
184
|
-
agentId:
|
|
183
|
+
roleName: turn.roleName,
|
|
184
|
+
turnId: turn.id,
|
|
185
|
+
agentId: turn.effective.agentId,
|
|
185
186
|
driverId,
|
|
186
187
|
launchId: session.launchId,
|
|
187
188
|
sessionGenerationId: session.launchId,
|
|
188
189
|
nativeSessionId: session.nativeSessionId,
|
|
189
|
-
nativeTurnId:
|
|
190
|
-
|
|
190
|
+
nativeTurnId: providerTurn?.turnId === turn.id
|
|
191
|
+
? providerTurn.nativeTurnId ?? turn.id
|
|
192
|
+
: turn.id,
|
|
193
|
+
receiptId: providerTurn?.turnId === turn.id
|
|
194
|
+
? providerTurn.attemptId
|
|
195
|
+
: formatTurnReceiptId(taskId, turn.id)
|
|
191
196
|
};
|
|
192
|
-
const projection = projectRuntimeTaskEvents(fence,
|
|
197
|
+
const projection = projectRuntimeTaskEvents(fence, turn.createdAt, events);
|
|
193
198
|
const view = {
|
|
194
|
-
|
|
199
|
+
getTurn: (taskId, turnId) => reader.listTurns(taskId).find((candidate) => candidate.id === turnId) ?? null,
|
|
195
200
|
listEvents: () => events,
|
|
196
201
|
getWorkItem: (workItemTaskId, workItemId) => reader.listWorkItems(workItemTaskId).find((item) => item.id === workItemId) ?? null,
|
|
197
202
|
listReviewRounds: (taskId) => reader.listReviewRounds(taskId),
|
|
@@ -199,8 +204,8 @@ function projectWebRunRuntimeHealth(reader, taskId, run, events, now, policy) {
|
|
|
199
204
|
listIntegrationAttempts: (taskId) => reader.listIntegrationAttempts(taskId),
|
|
200
205
|
listInputRequests: (taskId) => reader.listInputRequests(taskId)
|
|
201
206
|
};
|
|
202
|
-
const semanticProgress =
|
|
203
|
-
?? { progressAt:
|
|
207
|
+
const semanticProgress = latestTurnDurableProgressAt(view, taskId, turn.roleName, turn.id)
|
|
208
|
+
?? { progressAt: turn.createdAt };
|
|
204
209
|
const classification = classifyRuntimeHealth({
|
|
205
210
|
projection,
|
|
206
211
|
semanticProgressAt: semanticProgress.progressAt,
|
|
@@ -208,8 +213,8 @@ function projectWebRunRuntimeHealth(reader, taskId, run, events, now, policy) {
|
|
|
208
213
|
policy
|
|
209
214
|
});
|
|
210
215
|
return {
|
|
211
|
-
|
|
212
|
-
roleName:
|
|
216
|
+
turnId: turn.id,
|
|
217
|
+
roleName: turn.roleName,
|
|
213
218
|
layer: stalled ? "stalled-candidate" : classification.layer,
|
|
214
219
|
reason: stalled ? stallReason : classification.reason,
|
|
215
220
|
stalled,
|
|
@@ -219,10 +224,10 @@ function projectWebRunRuntimeHealth(reader, taskId, run, events, now, policy) {
|
|
|
219
224
|
lastSemanticProgressAt: classification.lastSemanticProgressAt
|
|
220
225
|
};
|
|
221
226
|
}
|
|
222
|
-
function latestStallField(events,
|
|
227
|
+
function latestStallField(events, turnId, field) {
|
|
223
228
|
const stalled = events
|
|
224
|
-
.filter((event) => event.type === "
|
|
225
|
-
&& event.payload.
|
|
229
|
+
.filter((event) => event.type === "turn.stalled"
|
|
230
|
+
&& event.payload.turnId === turnId
|
|
226
231
|
&& event.payload.status !== "diagnostic-only")
|
|
227
232
|
.sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt))[0];
|
|
228
233
|
return stalled?.payload[field];
|