@flowdesk/opencode-plugin 0.1.14 → 0.1.16
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 +6 -6
- package/dist/agent-task-output.d.ts +12 -0
- package/dist/agent-task-output.d.ts.map +1 -1
- package/dist/agent-task-output.js +110 -4
- package/dist/agent-task-output.js.map +1 -1
- package/dist/agent-task-runner.d.ts +12 -1
- package/dist/agent-task-runner.d.ts.map +1 -1
- package/dist/agent-task-runner.js +237 -16
- package/dist/agent-task-runner.js.map +1 -1
- package/dist/completion-ui-cache.d.ts.map +1 -1
- package/dist/completion-ui-cache.js +159 -29
- package/dist/completion-ui-cache.js.map +1 -1
- package/dist/event-hook-observer.d.ts.map +1 -1
- package/dist/event-hook-observer.js +66 -2
- package/dist/event-hook-observer.js.map +1 -1
- package/dist/index.d.ts +2 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -17
- package/dist/index.js.map +1 -1
- package/dist/managed-dispatch-adapter.d.ts +62 -0
- package/dist/managed-dispatch-adapter.d.ts.map +1 -1
- package/dist/managed-dispatch-adapter.js +465 -1
- package/dist/managed-dispatch-adapter.js.map +1 -1
- package/dist/metadata.d.ts +19 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +18 -0
- package/dist/metadata.js.map +1 -0
- package/dist/model-selection-engine.d.ts +15 -2
- package/dist/model-selection-engine.d.ts.map +1 -1
- package/dist/model-selection-engine.js +109 -42
- package/dist/model-selection-engine.js.map +1 -1
- package/dist/provider-usage-live-tool.d.ts.map +1 -1
- package/dist/provider-usage-live-tool.js +135 -33
- package/dist/provider-usage-live-tool.js.map +1 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +53 -4
- package/dist/server.js.map +1 -1
- package/dist/stall-recovery.d.ts +4 -3
- package/dist/stall-recovery.d.ts.map +1 -1
- package/dist/stall-recovery.js +245 -25
- package/dist/stall-recovery.js.map +1 -1
- package/dist/status-live-tool.d.ts.map +1 -1
- package/dist/status-live-tool.js +1 -0
- package/dist/status-live-tool.js.map +1 -1
- package/dist/tui-subtask-activity.d.ts +4 -0
- package/dist/tui-subtask-activity.d.ts.map +1 -1
- package/dist/tui-subtask-activity.js +29 -24
- package/dist/tui-subtask-activity.js.map +1 -1
- package/dist/tui-usage-snapshot.d.ts.map +1 -1
- package/dist/tui-usage-snapshot.js +92 -6
- package/dist/tui-usage-snapshot.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +43 -16
- package/dist/tui.js.map +1 -1
- package/dist/workflow-assign-tool.d.ts.map +1 -1
- package/dist/workflow-assign-tool.js +21 -3
- package/dist/workflow-assign-tool.js.map +1 -1
- package/dist/workflow-dispatch-tool.d.ts +12 -0
- package/dist/workflow-dispatch-tool.d.ts.map +1 -1
- package/dist/workflow-dispatch-tool.js +24 -26
- package/dist/workflow-dispatch-tool.js.map +1 -1
- package/package.json +2 -2
package/dist/stall-recovery.d.ts
CHANGED
|
@@ -161,6 +161,7 @@ export declare function backfillTerminalAgentTaskFailedLanesV1(input: {
|
|
|
161
161
|
rootDir: string;
|
|
162
162
|
workflowId: string;
|
|
163
163
|
now?: Date;
|
|
164
|
+
refreshCompletionUiCaches?: boolean;
|
|
164
165
|
}): FlowDeskAgentTaskTerminalBackfillResultV1;
|
|
165
166
|
/**
|
|
166
167
|
* On startup/reload: any `pending_retry_plan` in `launched` state with no matching
|
|
@@ -230,9 +231,9 @@ export interface FlowDeskChildSessionMonitorResultV1 {
|
|
|
230
231
|
* Called from the watchdog cycle once per interval:
|
|
231
232
|
* - Poll session.messages for each running child session
|
|
232
233
|
* - On result: write task_result evidence + terminal lifecycle
|
|
233
|
-
* - At
|
|
234
|
-
* - At
|
|
235
|
-
* - At
|
|
234
|
+
* - At 10s silence: nudge with noReply: true
|
|
235
|
+
* - At 20s: second nudge
|
|
236
|
+
* - At 30s+: session.abort + task_failed + terminal lifecycle
|
|
236
237
|
*/
|
|
237
238
|
export declare function monitorChildSessionsV1(input: {
|
|
238
239
|
rootDir: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stall-recovery.d.ts","sourceRoot":"","sources":["../src/stall-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"stall-recovery.d.ts","sourceRoot":"","sources":["../src/stall-recovery.ts"],"names":[],"mappings":"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"}
|
package/dist/stall-recovery.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyFlowDeskSessionEvidenceWriteIntentsV1, prepareFlowDeskSessionEvidenceWriteIntentV1, reloadFlowDeskSessionEvidenceV1, projectFlowDeskLaneStallV1, } from "@flowdesk/core";
|
|
1
|
+
import { applyFlowDeskSessionEvidenceWriteIntentsV1, prepareFlowDeskSessionEvidenceWriteIntentV1, reloadFlowDeskSessionEvidenceV1, projectFlowDeskLaneStallV1, validateTopTierReviewVerdictV1, } from "@flowdesk/core";
|
|
2
2
|
import { createHmac, createHash, timingSafeEqual, randomBytes } from "node:crypto";
|
|
3
3
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -254,6 +254,11 @@ export function validateAndAbortFlowDeskLaneEvidenceV1(input) {
|
|
|
254
254
|
entry.record.state === "aborted");
|
|
255
255
|
if (!persisted)
|
|
256
256
|
return { status: "write_failed", reason: "abort_evidence_not_persisted" };
|
|
257
|
+
refreshFlowDeskCompletionUiCachesV1({
|
|
258
|
+
rootDir: input.rootDir,
|
|
259
|
+
workflowId: input.workflow_id,
|
|
260
|
+
observedAt: observedAt,
|
|
261
|
+
});
|
|
257
262
|
return {
|
|
258
263
|
status: "aborted",
|
|
259
264
|
lane_id: input.lane_id,
|
|
@@ -582,6 +587,14 @@ export function backfillTerminalAgentTaskFailedLanesV1(input) {
|
|
|
582
587
|
terminalEvidenceIds.push(evidenceId);
|
|
583
588
|
}
|
|
584
589
|
}
|
|
590
|
+
if ((input.refreshCompletionUiCaches ?? true) &&
|
|
591
|
+
(terminalEvidenceIds.length > 0 || latestFailure.size > 0)) {
|
|
592
|
+
refreshFlowDeskCompletionUiCachesV1({
|
|
593
|
+
rootDir: input.rootDir,
|
|
594
|
+
workflowId: input.workflowId,
|
|
595
|
+
observedAt,
|
|
596
|
+
});
|
|
597
|
+
}
|
|
585
598
|
return {
|
|
586
599
|
status: "backfill_completed",
|
|
587
600
|
workflowId: input.workflowId,
|
|
@@ -1314,7 +1327,7 @@ async function pollChildSessionOutput(client, childSessionId, messagesTimeoutMs
|
|
|
1314
1327
|
return null;
|
|
1315
1328
|
const observed = observeFlowDeskAgentTaskOutputV1(raw);
|
|
1316
1329
|
if (observed.terminalObserved && observed.latestText !== undefined && observed.latestText.trim().length > 0)
|
|
1317
|
-
return { text: observed.latestText, completionStatus: "final", outputKind: observed.outputKind, usableForSynthesis: observed.usableForSynthesis };
|
|
1330
|
+
return { text: observed.latestText, completionStatus: "final", outputKind: observed.outputKind, usableForSynthesis: observed.usableForSynthesis, looksLikeRefusalOrError: observed.looksLikeRefusalOrError };
|
|
1318
1331
|
return null;
|
|
1319
1332
|
}
|
|
1320
1333
|
catch {
|
|
@@ -1340,7 +1353,7 @@ async function pollChildSessionCandidate(client, childSessionId, messagesTimeout
|
|
|
1340
1353
|
return null;
|
|
1341
1354
|
const observed = observeFlowDeskAgentTaskOutputV1(raw);
|
|
1342
1355
|
if (observed.latestText !== undefined && observed.latestText.trim().length > 0)
|
|
1343
|
-
return { text: observed.latestText, completionStatus: observed.terminalObserved ? "final" : "partial", outputKind: observed.outputKind, usableForSynthesis: observed.usableForSynthesis };
|
|
1356
|
+
return { text: observed.latestText, completionStatus: observed.terminalObserved ? "final" : "partial", outputKind: observed.outputKind, usableForSynthesis: observed.usableForSynthesis, looksLikeRefusalOrError: observed.looksLikeRefusalOrError };
|
|
1344
1357
|
return null;
|
|
1345
1358
|
}
|
|
1346
1359
|
catch {
|
|
@@ -1386,6 +1399,91 @@ function writeChildSessionEvidence(rootDir, workflowId, evidenceId, record) {
|
|
|
1386
1399
|
const applied = applyFlowDeskSessionEvidenceWriteIntentsV1(rootDir, [prepared.writeIntent]);
|
|
1387
1400
|
return applied.ok && applied.writtenPaths.length > 0;
|
|
1388
1401
|
}
|
|
1402
|
+
function extractJsonBlocksFromText(raw) {
|
|
1403
|
+
const trimmed = raw.trim();
|
|
1404
|
+
const results = [];
|
|
1405
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}"))
|
|
1406
|
+
return [trimmed];
|
|
1407
|
+
const fencePattern = /```(?:json)?\s*\n?(\{[\s\S]*?\})\s*\n?```/g;
|
|
1408
|
+
for (const match of trimmed.matchAll(fencePattern)) {
|
|
1409
|
+
if (match[1])
|
|
1410
|
+
results.push(match[1].trim());
|
|
1411
|
+
}
|
|
1412
|
+
if (results.length > 0)
|
|
1413
|
+
return results;
|
|
1414
|
+
let depth = 0;
|
|
1415
|
+
let start = -1;
|
|
1416
|
+
let lastBlock;
|
|
1417
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
1418
|
+
const ch = trimmed[i];
|
|
1419
|
+
if (ch === "{") {
|
|
1420
|
+
if (depth === 0)
|
|
1421
|
+
start = i;
|
|
1422
|
+
depth++;
|
|
1423
|
+
}
|
|
1424
|
+
else if (ch === "}") {
|
|
1425
|
+
depth--;
|
|
1426
|
+
if (depth === 0 && start !== -1) {
|
|
1427
|
+
lastBlock = trimmed.slice(start, i + 1).trim();
|
|
1428
|
+
start = -1;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
return lastBlock === undefined ? [] : [lastBlock];
|
|
1433
|
+
}
|
|
1434
|
+
function observedTopTierReviewerVerdictFromText(input) {
|
|
1435
|
+
for (const block of extractJsonBlocksFromText(input.text)) {
|
|
1436
|
+
try {
|
|
1437
|
+
const candidate = JSON.parse(block);
|
|
1438
|
+
const validation = validateTopTierReviewVerdictV1(candidate);
|
|
1439
|
+
if (!validation.ok)
|
|
1440
|
+
continue;
|
|
1441
|
+
const verdict = candidate;
|
|
1442
|
+
if (verdict.workflow_id === input.workflowId)
|
|
1443
|
+
return verdict;
|
|
1444
|
+
}
|
|
1445
|
+
catch {
|
|
1446
|
+
// Keep scanning candidates.
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return undefined;
|
|
1450
|
+
}
|
|
1451
|
+
function persistObservedReviewerVerdict(input) {
|
|
1452
|
+
const evidenceId = input.verdict.verdict_id;
|
|
1453
|
+
if (!writeChildSessionEvidence(input.rootDir, input.workflowId, evidenceId, input.verdict))
|
|
1454
|
+
return false;
|
|
1455
|
+
const reloaded = reloadFlowDeskSessionEvidenceV1({ rootDir: input.rootDir, workflowId: input.workflowId });
|
|
1456
|
+
return reloaded.ok && reloaded.blocked.length === 0 && reloaded.entries.some((entry) => entry.evidenceClass === "reviewer_verdict" &&
|
|
1457
|
+
entry.evidenceId === evidenceId &&
|
|
1458
|
+
entry.record.verdict_id === input.verdict.verdict_id);
|
|
1459
|
+
}
|
|
1460
|
+
function writeAgentTaskCompleteLifecycleForVerdict(input) {
|
|
1461
|
+
return writeChildSessionEvidence(input.rootDir, input.workflowId, `lifecycle-agent-task-complete-${input.laneId}-${input.verdictId}`, {
|
|
1462
|
+
schema_version: "flowdesk.lane_lifecycle_record.v1",
|
|
1463
|
+
lane_id: input.laneId,
|
|
1464
|
+
workflow_id: input.workflowId,
|
|
1465
|
+
attempt_id: input.attemptId,
|
|
1466
|
+
parent_session_ref: input.parentSessionRef,
|
|
1467
|
+
child_session_ref: input.childSessionId.startsWith("ses-") ? input.childSessionId : `ses-${input.childSessionId}`,
|
|
1468
|
+
message_ref: `msg-${input.laneId}`,
|
|
1469
|
+
agent_ref: input.agentRef,
|
|
1470
|
+
provider_qualified_model_id: input.providerQualifiedModelId,
|
|
1471
|
+
state: "complete",
|
|
1472
|
+
verdict_ref: input.verdictId,
|
|
1473
|
+
output_ref: `output-${input.taskResultEvidenceId}`,
|
|
1474
|
+
runtime_echo_ref: `runtime-echo-${input.laneId}`,
|
|
1475
|
+
telemetry_ref: `telemetry-${input.laneId}`,
|
|
1476
|
+
timeout_ms: 0,
|
|
1477
|
+
orphan_max_age_ms: 0,
|
|
1478
|
+
retry_count: 0,
|
|
1479
|
+
created_at: input.observedAt,
|
|
1480
|
+
updated_at: input.observedAt,
|
|
1481
|
+
dispatch_authority_enabled: false,
|
|
1482
|
+
providerCall: false,
|
|
1483
|
+
actualLaneLaunch: false,
|
|
1484
|
+
runtimeExecution: false,
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1389
1487
|
function laneAlreadyHasTerminalTaskEvidence(input) {
|
|
1390
1488
|
const reloaded = reloadFlowDeskSessionEvidenceV1({
|
|
1391
1489
|
rootDir: input.rootDir,
|
|
@@ -1400,6 +1498,64 @@ function laneAlreadyHasTerminalTaskEvidence(input) {
|
|
|
1400
1498
|
return record.lane_id === input.laneId;
|
|
1401
1499
|
});
|
|
1402
1500
|
}
|
|
1501
|
+
function terminalEvidenceObservedAtMs(record) {
|
|
1502
|
+
const value = typeof record.updated_at === "string"
|
|
1503
|
+
? record.updated_at
|
|
1504
|
+
: typeof record.created_at === "string"
|
|
1505
|
+
? record.created_at
|
|
1506
|
+
: typeof record.observed_at === "string"
|
|
1507
|
+
? record.observed_at
|
|
1508
|
+
: undefined;
|
|
1509
|
+
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
1510
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
1511
|
+
}
|
|
1512
|
+
function chooseLaterTerminalEndState(existing, candidate) {
|
|
1513
|
+
if (existing === undefined)
|
|
1514
|
+
return candidate;
|
|
1515
|
+
if (candidate.observedAtMs > existing.observedAtMs)
|
|
1516
|
+
return candidate;
|
|
1517
|
+
if (candidate.observedAtMs < existing.observedAtMs)
|
|
1518
|
+
return existing;
|
|
1519
|
+
// Prefer task_result for equal timestamps; otherwise keep the existing entry so
|
|
1520
|
+
// duplicate event-session-error / failed-child evidence is idempotent.
|
|
1521
|
+
return candidate.hasTaskResult && !existing.hasTaskResult ? candidate : existing;
|
|
1522
|
+
}
|
|
1523
|
+
function collectTerminalLaneEndStatesV1(entries) {
|
|
1524
|
+
const terminalByLane = new Map();
|
|
1525
|
+
for (const entry of entries) {
|
|
1526
|
+
const rec = entry.record;
|
|
1527
|
+
const laneId = typeof rec.lane_id === "string" ? rec.lane_id : undefined;
|
|
1528
|
+
if (laneId === undefined)
|
|
1529
|
+
continue;
|
|
1530
|
+
let state;
|
|
1531
|
+
let hasTaskResult = false;
|
|
1532
|
+
if (entry.evidenceClass === "lane_lifecycle") {
|
|
1533
|
+
state = typeof rec.state === "string" && TERMINAL_LANE_STATES.has(rec.state) ? rec.state : undefined;
|
|
1534
|
+
}
|
|
1535
|
+
else if (entry.evidenceClass === "task_result") {
|
|
1536
|
+
state = "complete";
|
|
1537
|
+
hasTaskResult = true;
|
|
1538
|
+
}
|
|
1539
|
+
else if (entry.evidenceClass === "task_failed") {
|
|
1540
|
+
state = rec.failure_category === "no_response" ? "no_output" : "invocation_failed";
|
|
1541
|
+
}
|
|
1542
|
+
if (state === undefined)
|
|
1543
|
+
continue;
|
|
1544
|
+
terminalByLane.set(laneId, chooseLaterTerminalEndState(terminalByLane.get(laneId), {
|
|
1545
|
+
laneId,
|
|
1546
|
+
state,
|
|
1547
|
+
observedAtMs: terminalEvidenceObservedAtMs(rec),
|
|
1548
|
+
hasTaskResult,
|
|
1549
|
+
}));
|
|
1550
|
+
}
|
|
1551
|
+
return terminalByLane;
|
|
1552
|
+
}
|
|
1553
|
+
function latestTerminalObservedAtIso(endStates, fallbackMs) {
|
|
1554
|
+
let latest = 0;
|
|
1555
|
+
for (const state of endStates)
|
|
1556
|
+
latest = Math.max(latest, state.observedAtMs);
|
|
1557
|
+
return new Date(latest > 0 ? latest : fallbackMs).toISOString();
|
|
1558
|
+
}
|
|
1403
1559
|
function childProgressLabel(value) {
|
|
1404
1560
|
const compact = value.replace(/\s+/g, " ").trim();
|
|
1405
1561
|
return compact.length > 120 ? `${compact.slice(0, 119)}…` : compact;
|
|
@@ -1427,15 +1583,15 @@ function writeAgentTaskProgressEvidence(input) {
|
|
|
1427
1583
|
* Called from the watchdog cycle once per interval:
|
|
1428
1584
|
* - Poll session.messages for each running child session
|
|
1429
1585
|
* - On result: write task_result evidence + terminal lifecycle
|
|
1430
|
-
* - At
|
|
1431
|
-
* - At
|
|
1432
|
-
* - At
|
|
1586
|
+
* - At 10s silence: nudge with noReply: true
|
|
1587
|
+
* - At 20s: second nudge
|
|
1588
|
+
* - At 30s+: session.abort + task_failed + terminal lifecycle
|
|
1433
1589
|
*/
|
|
1434
1590
|
export async function monitorChildSessionsV1(input) {
|
|
1435
1591
|
const nowMs = (input.now ?? new Date()).getTime();
|
|
1436
|
-
const nudgeQuietPeriodMs = input.nudgeQuietPeriodMs ??
|
|
1592
|
+
const nudgeQuietPeriodMs = input.nudgeQuietPeriodMs ?? 10_000;
|
|
1437
1593
|
const maxNudges = input.maxNudges ?? 2;
|
|
1438
|
-
const abortThresholdMs = input.abortThresholdMs ??
|
|
1594
|
+
const abortThresholdMs = input.abortThresholdMs ?? 30_000;
|
|
1439
1595
|
const result = { lanesPolled: 0, lanesCompleted: 0, lanesNudged: 0, lanesAborted: 0 };
|
|
1440
1596
|
const reloaded = reloadFlowDeskSessionEvidenceV1({ rootDir: input.rootDir, workflowId: input.workflowId });
|
|
1441
1597
|
if (!reloaded.ok)
|
|
@@ -1445,9 +1601,12 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1445
1601
|
.filter(e => e.evidenceClass === "agent_task_child_session")
|
|
1446
1602
|
.map(e => e.record)
|
|
1447
1603
|
.filter(r => r.schema_version === AGENT_TASK_CHILD_SESSION_SCHEMA_VERSION);
|
|
1448
|
-
// Find lanes that are NOT yet terminal
|
|
1449
|
-
|
|
1450
|
-
|
|
1604
|
+
// Find lanes that are NOT yet terminal. Terminal evidence can come from
|
|
1605
|
+
// task_result, task_failed (including event-session-error records), or a
|
|
1606
|
+
// lifecycle terminal state. The map keeps the extracted end-state timestamp so
|
|
1607
|
+
// cache refreshes are monotonic/idempotent even when no task_result exists.
|
|
1608
|
+
const terminalEndStates = collectTerminalLaneEndStatesV1(reloaded.entries);
|
|
1609
|
+
const terminalLaneIds = new Set(terminalEndStates.keys());
|
|
1451
1610
|
const awaitingPermissionLaneIds = new Set();
|
|
1452
1611
|
const latestProgressByLane = new Map();
|
|
1453
1612
|
for (const entry of reloaded.entries) {
|
|
@@ -1463,17 +1622,8 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1463
1622
|
latestProgressByLane.set(laneIdVal, { observedAtMs, phase });
|
|
1464
1623
|
}
|
|
1465
1624
|
}
|
|
1466
|
-
if (entry.evidenceClass === "lane_lifecycle") {
|
|
1467
|
-
const s = rec.state;
|
|
1468
|
-
if (s === "complete" || s === "invocation_failed" || s === "no_output" || s === "incomplete")
|
|
1469
|
-
terminalLaneIds.add(laneIdVal);
|
|
1470
|
-
}
|
|
1471
|
-
else if (entry.evidenceClass === "task_result" || entry.evidenceClass === "task_failed") {
|
|
1472
|
-
terminalLaneIds.add(laneIdVal);
|
|
1473
|
-
if (entry.evidenceClass === "task_result")
|
|
1474
|
-
terminalTaskResultLaneIds.add(laneIdVal);
|
|
1475
|
-
}
|
|
1476
1625
|
}
|
|
1626
|
+
const terminalRefreshObservedAt = latestTerminalObservedAtIso(terminalEndStates.values(), nowMs);
|
|
1477
1627
|
for (const [laneId, progress] of latestProgressByLane) {
|
|
1478
1628
|
if (progress.phase === "awaiting_permission")
|
|
1479
1629
|
awaitingPermissionLaneIds.add(laneId);
|
|
@@ -1490,18 +1640,26 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1490
1640
|
if (rec.phase === "waiting" && typeof rec.progress_label === "string" && rec.progress_label.includes("permission response") && typeof rec.lane_id === "string")
|
|
1491
1641
|
awaitingPermissionLaneIds.delete(rec.lane_id);
|
|
1492
1642
|
}
|
|
1643
|
+
let uiCacheRefreshed = false;
|
|
1493
1644
|
for (const record of childRecords) {
|
|
1494
1645
|
const laneId = typeof record.lane_id === "string" ? record.lane_id : "";
|
|
1495
1646
|
const childSessionId = typeof record.child_session_id === "string" ? record.child_session_id : "";
|
|
1496
1647
|
if (!laneId || !childSessionId)
|
|
1497
1648
|
continue;
|
|
1498
1649
|
if (terminalLaneIds.has(laneId)) {
|
|
1499
|
-
|
|
1650
|
+
// Refresh the completion UI cache for terminal lanes so stale "running"
|
|
1651
|
+
// rows are promoted to terminal. This must run for any terminal lane,
|
|
1652
|
+
// including lanes that only have lane_lifecycle/task_failed evidence and
|
|
1653
|
+
// no task_result (e.g. reviewer execution bridge writing only
|
|
1654
|
+
// lane_lifecycle=invocation_failed). Without this, the sidebar row stays
|
|
1655
|
+
// stuck at progressing_normal/running until a task_result appears.
|
|
1656
|
+
if (!uiCacheRefreshed) {
|
|
1500
1657
|
refreshFlowDeskCompletionUiCachesV1({
|
|
1501
1658
|
rootDir: input.rootDir,
|
|
1502
1659
|
workflowId: input.workflowId,
|
|
1503
|
-
observedAt:
|
|
1660
|
+
observedAt: terminalRefreshObservedAt,
|
|
1504
1661
|
});
|
|
1662
|
+
uiCacheRefreshed = true;
|
|
1505
1663
|
}
|
|
1506
1664
|
continue; // already done
|
|
1507
1665
|
}
|
|
@@ -1544,6 +1702,8 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1544
1702
|
output_kind: resultObservation.outputKind,
|
|
1545
1703
|
usable_for_synthesis: resultObservation.usableForSynthesis,
|
|
1546
1704
|
missing_contract: false,
|
|
1705
|
+
finalization_reason: "terminal_marker",
|
|
1706
|
+
looks_like_refusal_or_error: resultObservation.looksLikeRefusalOrError,
|
|
1547
1707
|
created_at: completedAt,
|
|
1548
1708
|
dispatch_authority_enabled: false,
|
|
1549
1709
|
});
|
|
@@ -1572,8 +1732,43 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1572
1732
|
progressLabel: "async agent task result persistence failed",
|
|
1573
1733
|
observedAt: completedAt,
|
|
1574
1734
|
});
|
|
1735
|
+
refreshFlowDeskCompletionUiCachesV1({
|
|
1736
|
+
rootDir: input.rootDir,
|
|
1737
|
+
workflowId: input.workflowId,
|
|
1738
|
+
observedAt: completedAt,
|
|
1739
|
+
});
|
|
1575
1740
|
continue;
|
|
1576
1741
|
}
|
|
1742
|
+
const observedReviewerVerdict = observedTopTierReviewerVerdictFromText({
|
|
1743
|
+
text: resultObservation.text,
|
|
1744
|
+
workflowId: input.workflowId,
|
|
1745
|
+
});
|
|
1746
|
+
const reviewerVerdictPersisted = observedReviewerVerdict === undefined
|
|
1747
|
+
? false
|
|
1748
|
+
: persistObservedReviewerVerdict({
|
|
1749
|
+
rootDir: input.rootDir,
|
|
1750
|
+
workflowId: input.workflowId,
|
|
1751
|
+
verdict: observedReviewerVerdict,
|
|
1752
|
+
});
|
|
1753
|
+
const runningLifecycle = reloaded.entries.find((entry) => {
|
|
1754
|
+
const lifecycle = entry.record;
|
|
1755
|
+
return entry.evidenceClass === "lane_lifecycle" && lifecycle.lane_id === laneId && typeof lifecycle.attempt_id === "string";
|
|
1756
|
+
})?.record;
|
|
1757
|
+
if (reviewerVerdictPersisted && observedReviewerVerdict !== undefined) {
|
|
1758
|
+
writeAgentTaskCompleteLifecycleForVerdict({
|
|
1759
|
+
rootDir: input.rootDir,
|
|
1760
|
+
workflowId: input.workflowId,
|
|
1761
|
+
laneId,
|
|
1762
|
+
attemptId: typeof runningLifecycle?.attempt_id === "string" ? runningLifecycle.attempt_id : `attempt-${laneId}`,
|
|
1763
|
+
parentSessionRef: typeof record.parent_session_ref === "string" ? record.parent_session_ref : "ses-agent-task-parent",
|
|
1764
|
+
childSessionId,
|
|
1765
|
+
taskResultEvidenceId,
|
|
1766
|
+
agentRef,
|
|
1767
|
+
providerQualifiedModelId: modelId,
|
|
1768
|
+
verdictId: observedReviewerVerdict.verdict_id,
|
|
1769
|
+
observedAt: completedAt,
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1577
1772
|
writeAgentTaskProgressEvidence({
|
|
1578
1773
|
rootDir: input.rootDir,
|
|
1579
1774
|
workflowId: input.workflowId,
|
|
@@ -1583,7 +1778,9 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1583
1778
|
providerQualifiedModelId: modelId,
|
|
1584
1779
|
phase: "finalizing",
|
|
1585
1780
|
progressSeq: 10 + nudgeCount,
|
|
1586
|
-
progressLabel:
|
|
1781
|
+
progressLabel: reviewerVerdictPersisted
|
|
1782
|
+
? "async agent task result captured with reviewer verdict evidence"
|
|
1783
|
+
: "async agent task result captured by watchdog",
|
|
1587
1784
|
observedAt: completedAt,
|
|
1588
1785
|
});
|
|
1589
1786
|
refreshFlowDeskCompletionUiCachesV1({
|
|
@@ -1622,7 +1819,11 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1622
1819
|
completion_status: "partial",
|
|
1623
1820
|
output_kind: partialObservation.outputKind,
|
|
1624
1821
|
usable_for_synthesis: partialObservation.usableForSynthesis,
|
|
1625
|
-
|
|
1822
|
+
// Captured partial text is still a usable result, not a contract
|
|
1823
|
+
// failure. The coordinator judges substance from the advisory fields.
|
|
1824
|
+
missing_contract: false,
|
|
1825
|
+
finalization_reason: "timeout_partial",
|
|
1826
|
+
looks_like_refusal_or_error: partialObservation.looksLikeRefusalOrError,
|
|
1626
1827
|
created_at: abortedAt,
|
|
1627
1828
|
dispatch_authority_enabled: false,
|
|
1628
1829
|
});
|
|
@@ -1675,6 +1876,11 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1675
1876
|
progressLabel: "async agent task aborted after no response",
|
|
1676
1877
|
observedAt: abortedAt,
|
|
1677
1878
|
});
|
|
1879
|
+
refreshFlowDeskCompletionUiCachesV1({
|
|
1880
|
+
rootDir: input.rootDir,
|
|
1881
|
+
workflowId: input.workflowId,
|
|
1882
|
+
observedAt: abortedAt,
|
|
1883
|
+
});
|
|
1678
1884
|
result.lanesAborted++;
|
|
1679
1885
|
continue;
|
|
1680
1886
|
}
|
|
@@ -1709,6 +1915,20 @@ export async function monitorChildSessionsV1(input) {
|
|
|
1709
1915
|
});
|
|
1710
1916
|
}
|
|
1711
1917
|
}
|
|
1918
|
+
// Invariant: terminal/failure lanes observed during this cycle MUST cause a
|
|
1919
|
+
// completion UI cache refresh, even when the failed lane has no paired
|
|
1920
|
+
// `agent_task_child_session` record (e.g. reviewer execution bridge wrote
|
|
1921
|
+
// only `lane_lifecycle=invocation_failed`, or `task_failed`/`no_output`
|
|
1922
|
+
// arrived via the event hook without a task_result). Without this defensive
|
|
1923
|
+
// refresh, the `subtask-activity-sidebar` and `auto-next-ready` caches stay
|
|
1924
|
+
// stuck at `progressing_normal/running` until the next backfill pass.
|
|
1925
|
+
if (!uiCacheRefreshed && terminalLaneIds.size > 0) {
|
|
1926
|
+
refreshFlowDeskCompletionUiCachesV1({
|
|
1927
|
+
rootDir: input.rootDir,
|
|
1928
|
+
workflowId: input.workflowId,
|
|
1929
|
+
observedAt: terminalRefreshObservedAt,
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1712
1932
|
return result;
|
|
1713
1933
|
}
|
|
1714
1934
|
//# sourceMappingURL=stall-recovery.js.map
|