@flowdesk/opencode-plugin 0.1.13 → 0.1.14

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.
Files changed (78) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-task-output.d.ts +17 -0
  3. package/dist/agent-task-output.d.ts.map +1 -0
  4. package/dist/agent-task-output.js +119 -0
  5. package/dist/agent-task-output.js.map +1 -0
  6. package/dist/agent-task-runner.d.ts +23 -0
  7. package/dist/agent-task-runner.d.ts.map +1 -1
  8. package/dist/agent-task-runner.js +410 -81
  9. package/dist/agent-task-runner.js.map +1 -1
  10. package/dist/auto-continue-preview-tool.d.ts +36 -0
  11. package/dist/auto-continue-preview-tool.d.ts.map +1 -0
  12. package/dist/auto-continue-preview-tool.js +119 -0
  13. package/dist/auto-continue-preview-tool.js.map +1 -0
  14. package/dist/completion-ui-cache.d.ts +6 -0
  15. package/dist/completion-ui-cache.d.ts.map +1 -0
  16. package/dist/completion-ui-cache.js +260 -0
  17. package/dist/completion-ui-cache.js.map +1 -0
  18. package/dist/event-hook-observer.d.ts +14 -0
  19. package/dist/event-hook-observer.d.ts.map +1 -0
  20. package/dist/event-hook-observer.js +193 -0
  21. package/dist/event-hook-observer.js.map +1 -0
  22. package/dist/managed-dispatch-adapter.d.ts.map +1 -1
  23. package/dist/managed-dispatch-adapter.js +7 -3
  24. package/dist/managed-dispatch-adapter.js.map +1 -1
  25. package/dist/model-selection-engine.d.ts +47 -0
  26. package/dist/model-selection-engine.d.ts.map +1 -0
  27. package/dist/model-selection-engine.js +175 -0
  28. package/dist/model-selection-engine.js.map +1 -0
  29. package/dist/provider-usage-live-tool.d.ts +10 -0
  30. package/dist/provider-usage-live-tool.d.ts.map +1 -1
  31. package/dist/provider-usage-live-tool.js +145 -18
  32. package/dist/provider-usage-live-tool.js.map +1 -1
  33. package/dist/server.d.ts +35 -1
  34. package/dist/server.d.ts.map +1 -1
  35. package/dist/server.js +447 -19
  36. package/dist/server.js.map +1 -1
  37. package/dist/stall-recovery.d.ts +33 -0
  38. package/dist/stall-recovery.d.ts.map +1 -1
  39. package/dist/stall-recovery.js +459 -2
  40. package/dist/stall-recovery.js.map +1 -1
  41. package/dist/status-live-tool.d.ts +54 -0
  42. package/dist/status-live-tool.d.ts.map +1 -1
  43. package/dist/status-live-tool.js +448 -44
  44. package/dist/status-live-tool.js.map +1 -1
  45. package/dist/tui-subtask-activity.d.ts +69 -0
  46. package/dist/tui-subtask-activity.d.ts.map +1 -0
  47. package/dist/tui-subtask-activity.js +266 -0
  48. package/dist/tui-subtask-activity.js.map +1 -0
  49. package/dist/tui-usage-snapshot.d.ts +14 -0
  50. package/dist/tui-usage-snapshot.d.ts.map +1 -1
  51. package/dist/tui-usage-snapshot.js +189 -8
  52. package/dist/tui-usage-snapshot.js.map +1 -1
  53. package/dist/tui.d.ts.map +1 -1
  54. package/dist/tui.js +72 -41
  55. package/dist/tui.js.map +1 -1
  56. package/dist/workflow-assign-tool.d.ts +23 -0
  57. package/dist/workflow-assign-tool.d.ts.map +1 -0
  58. package/dist/workflow-assign-tool.js +117 -0
  59. package/dist/workflow-assign-tool.js.map +1 -0
  60. package/dist/workflow-author-tool.d.ts +29 -0
  61. package/dist/workflow-author-tool.d.ts.map +1 -0
  62. package/dist/workflow-author-tool.js +227 -0
  63. package/dist/workflow-author-tool.js.map +1 -0
  64. package/dist/workflow-dispatch-tool.d.ts.map +1 -1
  65. package/dist/workflow-dispatch-tool.js +32 -2
  66. package/dist/workflow-dispatch-tool.js.map +1 -1
  67. package/dist/workflow-orchestrator.d.ts +31 -0
  68. package/dist/workflow-orchestrator.d.ts.map +1 -0
  69. package/dist/workflow-orchestrator.js +160 -0
  70. package/dist/workflow-orchestrator.js.map +1 -0
  71. package/dist/workflow-scheduler.d.ts.map +1 -1
  72. package/dist/workflow-scheduler.js +3 -1
  73. package/dist/workflow-scheduler.js.map +1 -1
  74. package/dist/workflow-synthesis-tool.d.ts +31 -0
  75. package/dist/workflow-synthesis-tool.d.ts.map +1 -0
  76. package/dist/workflow-synthesis-tool.js +194 -0
  77. package/dist/workflow-synthesis-tool.js.map +1 -0
  78. package/package.json +2 -2
@@ -188,6 +188,10 @@ export declare function evaluateGuardedAutoRetryHookV1(input: {
188
188
  timeoutMs?: number;
189
189
  abortSignal?: AbortSignal;
190
190
  now?: Date;
191
+ /** Override nudge quiet period — for testing only */
192
+ _nudgeQuietPeriodMs?: number;
193
+ /** Override messages poll timeout — for testing only */
194
+ _messagesTimeoutMs?: number;
191
195
  }): Promise<FlowDeskAutoRetryResultV1>;
192
196
  export interface FlowDeskWatchdogConfigV1 {
193
197
  enabled?: boolean;
@@ -210,5 +214,34 @@ export declare function runFlowDeskWatchdogCycleV1(input: {
210
214
  client: FlowDeskManagedDispatchBetaOpenCodeClientV1 | undefined;
211
215
  parentSessionId: string;
212
216
  now?: Date;
217
+ /** Override nudge quiet period — for testing only */
218
+ _nudgeQuietPeriodMs?: number;
219
+ /** Override messages poll timeout — for testing only */
220
+ _messagesTimeoutMs?: number;
213
221
  }): Promise<FlowDeskWatchdogCycleResultV1>;
222
+ export interface FlowDeskChildSessionMonitorResultV1 {
223
+ lanesPolled: number;
224
+ lanesCompleted: number;
225
+ lanesNudged: number;
226
+ lanesAborted: number;
227
+ }
228
+ /**
229
+ * Monitor all async-mode agent task lanes in the given workflow.
230
+ * Called from the watchdog cycle once per interval:
231
+ * - Poll session.messages for each running child session
232
+ * - On result: write task_result evidence + terminal lifecycle
233
+ * - At 20s silence: nudge with noReply: true
234
+ * - At 40s: second nudge
235
+ * - At 60s+: session.abort + task_failed + terminal lifecycle
236
+ */
237
+ export declare function monitorChildSessionsV1(input: {
238
+ rootDir: string;
239
+ workflowId: string;
240
+ client: FlowDeskManagedDispatchBetaOpenCodeClientV1;
241
+ now?: Date;
242
+ nudgeQuietPeriodMs?: number;
243
+ maxNudges?: number;
244
+ abortThresholdMs?: number;
245
+ _forceTaskResultWriteFailureForTest?: boolean;
246
+ }): Promise<FlowDeskChildSessionMonitorResultV1>;
214
247
  //# sourceMappingURL=stall-recovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stall-recovery.d.ts","sourceRoot":"","sources":["../src/stall-recovery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stall-recovery.d.ts","sourceRoot":"","sources":["../src/stall-recovery.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  import { applyFlowDeskSessionEvidenceWriteIntentsV1, prepareFlowDeskSessionEvidenceWriteIntentV1, reloadFlowDeskSessionEvidenceV1, projectFlowDeskLaneStallV1, } from "@flowdesk/core";
2
- import { createHmac, createHash, timingSafeEqual } from "node:crypto";
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";
5
5
  import { launchFlowDeskInjectedSdkRuntimeLaneFromPlanV1, } from "./managed-dispatch-adapter.js";
6
6
  import { FLOWDESK_TIMEOUT_DEFAULTS, FlowDeskTimeoutError, withTimeout, } from "./shared/with-timeout.js";
7
- import { executeFlowDeskAgentTaskV1 } from "./agent-task-runner.js";
7
+ import { executeFlowDeskAgentTaskV1, AGENT_TASK_CHILD_SESSION_SCHEMA_VERSION, sanitizeFlowDeskTaskResultTextV1 } from "./agent-task-runner.js";
8
+ import { observeFlowDeskAgentTaskOutputV1 } from "./agent-task-output.js";
9
+ import { refreshFlowDeskCompletionUiCachesV1 } from "./completion-ui-cache.js";
8
10
  export async function checkSdkSessionApiHealthV1(client, sessionId, timeouts = {}) {
9
11
  if (typeof client.session.messages !== "function") {
10
12
  return { status: "unknown", reason: "sdk_messages_not_available" };
@@ -900,6 +902,8 @@ export async function evaluateGuardedAutoRetryHookV1(input) {
900
902
  rootDir: input.rootDir,
901
903
  client: input.client,
902
904
  timeoutMs: timeoutMs,
905
+ _nudgeQuietPeriodMs: input._nudgeQuietPeriodMs,
906
+ _messagesTimeoutMs: input._messagesTimeoutMs,
903
907
  });
904
908
  if (taskResult.status === "task_failed") {
905
909
  const failedId = `retry-failed-agent-task-${safeToken(newLaneId)}-${retryToken}`;
@@ -1169,6 +1173,18 @@ export async function runFlowDeskWatchdogCycleV1(input) {
1169
1173
  const workflowIds = listWatchdogWorkflowIds(input.rootDir);
1170
1174
  const now = input.now ?? new Date();
1171
1175
  for (const workflowId of workflowIds) {
1176
+ // Monitor async-mode child sessions (nudge + abort + result collection)
1177
+ if (input.client !== undefined) {
1178
+ try {
1179
+ await monitorChildSessionsV1({
1180
+ rootDir: input.rootDir,
1181
+ workflowId,
1182
+ client: input.client,
1183
+ now,
1184
+ });
1185
+ }
1186
+ catch { /* best-effort, must not crash watchdog */ }
1187
+ }
1172
1188
  backfillTerminalAgentTaskFailedLanesV1({
1173
1189
  rootDir: input.rootDir,
1174
1190
  workflowId,
@@ -1218,6 +1234,8 @@ export async function runFlowDeskWatchdogCycleV1(input) {
1218
1234
  client: input.client,
1219
1235
  parentSessionId: input.parentSessionId,
1220
1236
  now,
1237
+ _nudgeQuietPeriodMs: input._nudgeQuietPeriodMs,
1238
+ _messagesTimeoutMs: input._messagesTimeoutMs,
1221
1239
  });
1222
1240
  if (retryResult.status === "retry_launched") {
1223
1241
  lanesRetried++;
@@ -1254,4 +1272,443 @@ export async function runFlowDeskWatchdogCycleV1(input) {
1254
1272
  lanesFailed,
1255
1273
  };
1256
1274
  }
1275
+ // ─────────────────────────────────────────────────────────────────────────────
1276
+ // Child session monitor (async-mode lanes)
1277
+ // ─────────────────────────────────────────────────────────────────────────────
1278
+ const AGENT_TASK_NUDGE_TEXT_WATCHDOG = "Please provide your final answer now. If you have completed your analysis, output your complete response.";
1279
+ /** Poll result from one session.messages call */
1280
+ function monitorRecord(value) {
1281
+ return typeof value === "object" && value !== null && !Array.isArray(value)
1282
+ ? value
1283
+ : undefined;
1284
+ }
1285
+ function monitorResponseData(value) {
1286
+ const record = monitorRecord(value);
1287
+ return record !== undefined && "data" in record ? record.data : value;
1288
+ }
1289
+ function monitorSdkErrorResponse(value) {
1290
+ const record = monitorRecord(value);
1291
+ const data = monitorRecord(monitorResponseData(value));
1292
+ return record?.error !== undefined || data?.error !== undefined;
1293
+ }
1294
+ async function pollChildSessionOutput(client, childSessionId, messagesTimeoutMs = 3_000) {
1295
+ const messages = client.session.messages;
1296
+ if (typeof messages !== "function")
1297
+ return null;
1298
+ try {
1299
+ const readMessages = async () => {
1300
+ const current = await messages.call(client.session, {
1301
+ sessionID: childSessionId,
1302
+ });
1303
+ if (!monitorSdkErrorResponse(current))
1304
+ return current;
1305
+ return messages.call(client.session, {
1306
+ path: { id: childSessionId },
1307
+ });
1308
+ };
1309
+ const raw = await Promise.race([
1310
+ readMessages(),
1311
+ new Promise(resolve => setTimeout(() => resolve(null), messagesTimeoutMs)),
1312
+ ]);
1313
+ if (raw === null)
1314
+ return null;
1315
+ const observed = observeFlowDeskAgentTaskOutputV1(raw);
1316
+ if (observed.terminalObserved && observed.latestText !== undefined && observed.latestText.trim().length > 0)
1317
+ return { text: observed.latestText, completionStatus: "final", outputKind: observed.outputKind, usableForSynthesis: observed.usableForSynthesis };
1318
+ return null;
1319
+ }
1320
+ catch {
1321
+ return null;
1322
+ }
1323
+ }
1324
+ async function pollChildSessionCandidate(client, childSessionId, messagesTimeoutMs = 3_000) {
1325
+ const messages = client.session.messages;
1326
+ if (typeof messages !== "function")
1327
+ return null;
1328
+ try {
1329
+ const readMessages = async () => {
1330
+ const current = await messages.call(client.session, { sessionID: childSessionId });
1331
+ if (!monitorSdkErrorResponse(current))
1332
+ return current;
1333
+ return messages.call(client.session, { path: { id: childSessionId } });
1334
+ };
1335
+ const raw = await Promise.race([
1336
+ readMessages(),
1337
+ new Promise(resolve => setTimeout(() => resolve(null), messagesTimeoutMs)),
1338
+ ]);
1339
+ if (raw === null)
1340
+ return null;
1341
+ const observed = observeFlowDeskAgentTaskOutputV1(raw);
1342
+ 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 };
1344
+ return null;
1345
+ }
1346
+ catch {
1347
+ return null;
1348
+ }
1349
+ }
1350
+ /** Send a noReply nudge to a child session — best effort with hard timeout */
1351
+ async function sendWatchdogNudge(client, childSessionId, timeoutMs = 5_000) {
1352
+ const promptFn = client.session.promptAsync ?? client.session.prompt;
1353
+ if (promptFn === undefined)
1354
+ return "skipped";
1355
+ try {
1356
+ await Promise.race([
1357
+ promptFn.call(client.session, {
1358
+ sessionID: childSessionId,
1359
+ noReply: true,
1360
+ parts: [{ type: "text", text: AGENT_TASK_NUDGE_TEXT_WATCHDOG }],
1361
+ }),
1362
+ new Promise((_, reject) => setTimeout(() => reject(new Error("nudge timeout")), timeoutMs)),
1363
+ ]);
1364
+ return "sent";
1365
+ }
1366
+ catch {
1367
+ return "timeout";
1368
+ }
1369
+ }
1370
+ /** Abort a child session via the injected SDK client */
1371
+ async function abortChildSession(client, childSessionId) {
1372
+ const abort = client.session.abort;
1373
+ if (typeof abort !== "function")
1374
+ return;
1375
+ try {
1376
+ await abort.call(client.session, {
1377
+ path: { id: childSessionId },
1378
+ });
1379
+ }
1380
+ catch { /* best-effort */ }
1381
+ }
1382
+ function writeChildSessionEvidence(rootDir, workflowId, evidenceId, record) {
1383
+ const prepared = prepareFlowDeskSessionEvidenceWriteIntentV1({ workflowId, evidenceId, record });
1384
+ if (!prepared.ok || prepared.writeIntent === undefined)
1385
+ return false;
1386
+ const applied = applyFlowDeskSessionEvidenceWriteIntentsV1(rootDir, [prepared.writeIntent]);
1387
+ return applied.ok && applied.writtenPaths.length > 0;
1388
+ }
1389
+ function laneAlreadyHasTerminalTaskEvidence(input) {
1390
+ const reloaded = reloadFlowDeskSessionEvidenceV1({
1391
+ rootDir: input.rootDir,
1392
+ workflowId: input.workflowId,
1393
+ });
1394
+ if (!reloaded.ok)
1395
+ return false;
1396
+ return reloaded.entries.some((entry) => {
1397
+ if (entry.evidenceClass !== "task_result" && entry.evidenceClass !== "task_failed")
1398
+ return false;
1399
+ const record = entry.record;
1400
+ return record.lane_id === input.laneId;
1401
+ });
1402
+ }
1403
+ function childProgressLabel(value) {
1404
+ const compact = value.replace(/\s+/g, " ").trim();
1405
+ return compact.length > 120 ? `${compact.slice(0, 119)}…` : compact;
1406
+ }
1407
+ function writeAgentTaskProgressEvidence(input) {
1408
+ const record = {
1409
+ schema_version: "flowdesk.agent_task_progress.v1",
1410
+ workflow_id: input.workflowId,
1411
+ lane_id: input.laneId,
1412
+ task_id: input.taskId,
1413
+ agent_ref: input.agentRef,
1414
+ provider_qualified_model_id: input.providerQualifiedModelId,
1415
+ progress_seq: input.progressSeq,
1416
+ observed_at: input.observedAt,
1417
+ phase: input.phase,
1418
+ progress_label: childProgressLabel(input.progressLabel),
1419
+ progress_ref: `progress-${input.laneId}-${input.progressSeq}`,
1420
+ redaction_version: "v1",
1421
+ dispatch_authority_enabled: false,
1422
+ };
1423
+ writeChildSessionEvidence(input.rootDir, input.workflowId, `agent-task-progress-${input.laneId}-${input.progressSeq}`, record);
1424
+ }
1425
+ /**
1426
+ * Monitor all async-mode agent task lanes in the given workflow.
1427
+ * Called from the watchdog cycle once per interval:
1428
+ * - Poll session.messages for each running child session
1429
+ * - On result: write task_result evidence + terminal lifecycle
1430
+ * - At 20s silence: nudge with noReply: true
1431
+ * - At 40s: second nudge
1432
+ * - At 60s+: session.abort + task_failed + terminal lifecycle
1433
+ */
1434
+ export async function monitorChildSessionsV1(input) {
1435
+ const nowMs = (input.now ?? new Date()).getTime();
1436
+ const nudgeQuietPeriodMs = input.nudgeQuietPeriodMs ?? 20_000;
1437
+ const maxNudges = input.maxNudges ?? 2;
1438
+ const abortThresholdMs = input.abortThresholdMs ?? 60_000;
1439
+ const result = { lanesPolled: 0, lanesCompleted: 0, lanesNudged: 0, lanesAborted: 0 };
1440
+ const reloaded = reloadFlowDeskSessionEvidenceV1({ rootDir: input.rootDir, workflowId: input.workflowId });
1441
+ if (!reloaded.ok)
1442
+ return result;
1443
+ // Find all child session records for running lanes
1444
+ const childRecords = reloaded.entries
1445
+ .filter(e => e.evidenceClass === "agent_task_child_session")
1446
+ .map(e => e.record)
1447
+ .filter(r => r.schema_version === AGENT_TASK_CHILD_SESSION_SCHEMA_VERSION);
1448
+ // Find lanes that are NOT yet terminal (by lifecycle state or by task_result/task_failed evidence)
1449
+ const terminalLaneIds = new Set();
1450
+ const terminalTaskResultLaneIds = new Set();
1451
+ const awaitingPermissionLaneIds = new Set();
1452
+ const latestProgressByLane = new Map();
1453
+ for (const entry of reloaded.entries) {
1454
+ const rec = entry.record;
1455
+ const laneIdVal = typeof rec.lane_id === "string" ? rec.lane_id : undefined;
1456
+ if (!laneIdVal)
1457
+ continue;
1458
+ if (entry.evidenceClass === "agent_task_progress") {
1459
+ const observedAtMs = typeof rec.observed_at === "string" ? Date.parse(rec.observed_at) : NaN;
1460
+ const phase = typeof rec.phase === "string" ? rec.phase : undefined;
1461
+ const current = latestProgressByLane.get(laneIdVal);
1462
+ if (phase !== undefined && Number.isFinite(observedAtMs) && (current === undefined || current.observedAtMs <= observedAtMs)) {
1463
+ latestProgressByLane.set(laneIdVal, { observedAtMs, phase });
1464
+ }
1465
+ }
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
+ }
1477
+ for (const [laneId, progress] of latestProgressByLane) {
1478
+ if (progress.phase === "awaiting_permission")
1479
+ awaitingPermissionLaneIds.add(laneId);
1480
+ }
1481
+ // Defensive fallback for older/event-written progress records: if any explicit
1482
+ // awaiting_permission marker is present and no later permission response has
1483
+ // been observed, suspend watchdog nudge/abort for the lane.
1484
+ for (const entry of reloaded.entries) {
1485
+ if (entry.evidenceClass !== "agent_task_progress")
1486
+ continue;
1487
+ const rec = entry.record;
1488
+ if (rec.phase === "awaiting_permission" && typeof rec.lane_id === "string")
1489
+ awaitingPermissionLaneIds.add(rec.lane_id);
1490
+ if (rec.phase === "waiting" && typeof rec.progress_label === "string" && rec.progress_label.includes("permission response") && typeof rec.lane_id === "string")
1491
+ awaitingPermissionLaneIds.delete(rec.lane_id);
1492
+ }
1493
+ for (const record of childRecords) {
1494
+ const laneId = typeof record.lane_id === "string" ? record.lane_id : "";
1495
+ const childSessionId = typeof record.child_session_id === "string" ? record.child_session_id : "";
1496
+ if (!laneId || !childSessionId)
1497
+ continue;
1498
+ if (terminalLaneIds.has(laneId)) {
1499
+ if (terminalTaskResultLaneIds.has(laneId)) {
1500
+ refreshFlowDeskCompletionUiCachesV1({
1501
+ rootDir: input.rootDir,
1502
+ workflowId: input.workflowId,
1503
+ observedAt: new Date(nowMs).toISOString(),
1504
+ });
1505
+ }
1506
+ continue; // already done
1507
+ }
1508
+ if (awaitingPermissionLaneIds.has(laneId))
1509
+ continue; // user permission is outstanding; do not nudge or abort
1510
+ result.lanesPolled++;
1511
+ const createdAtMs = typeof record.created_at === "string" ? Date.parse(record.created_at) : nowMs;
1512
+ const nudgeCount = typeof record.nudge_count === "number" ? record.nudge_count : 0;
1513
+ const lastNudgeAtMs = typeof record.last_nudge_at === "string" ? Date.parse(record.last_nudge_at) : createdAtMs;
1514
+ const silenceMs = nowMs - lastNudgeAtMs;
1515
+ const totalAgeMs = nowMs - createdAtMs;
1516
+ // 1. Try to collect terminal result text. Candidate text without terminal is kept for abort-time partial capture.
1517
+ const resultObservation = await pollChildSessionOutput(input.client, childSessionId);
1518
+ if (resultObservation !== null && resultObservation.text.trim().length > 0) {
1519
+ const taskId = typeof record.task_id === "string" ? record.task_id : laneId;
1520
+ const agentRef = typeof record.agent_ref === "string" ? record.agent_ref : "agent-unknown";
1521
+ const modelId = typeof record.provider_qualified_model_id === "string" ? record.provider_qualified_model_id : "unknown/unknown";
1522
+ if (laneAlreadyHasTerminalTaskEvidence({ rootDir: input.rootDir, workflowId: input.workflowId, laneId })) {
1523
+ continue;
1524
+ }
1525
+ const token = randomBytes(4).toString("hex");
1526
+ const completedAt = new Date(nowMs).toISOString();
1527
+ const sanitizedResult = sanitizeFlowDeskTaskResultTextV1(resultObservation.text);
1528
+ const finalText = sanitizedResult.text;
1529
+ const taskResultEvidenceId = `task-result-${taskId}-watchdog-${token}`;
1530
+ const taskResultWritten = input._forceTaskResultWriteFailureForTest === true
1531
+ ? false
1532
+ : writeChildSessionEvidence(input.rootDir, input.workflowId, taskResultEvidenceId, {
1533
+ schema_version: "flowdesk.task_result.v1",
1534
+ workflow_id: input.workflowId,
1535
+ lane_id: laneId,
1536
+ task_id: taskId,
1537
+ agent_ref: agentRef,
1538
+ provider_qualified_model_id: modelId,
1539
+ task_prompt_sha256: createHash("sha256").update("watchdog-collected").digest("hex"),
1540
+ result_text: finalText,
1541
+ result_text_truncated: sanitizedResult.truncated,
1542
+ result_text_sha256: createHash("sha256").update(resultObservation.text).digest("hex"),
1543
+ completion_status: resultObservation.completionStatus,
1544
+ output_kind: resultObservation.outputKind,
1545
+ usable_for_synthesis: resultObservation.usableForSynthesis,
1546
+ missing_contract: false,
1547
+ created_at: completedAt,
1548
+ dispatch_authority_enabled: false,
1549
+ });
1550
+ if (!taskResultWritten) {
1551
+ writeChildSessionEvidence(input.rootDir, input.workflowId, `task-failed-${taskId}-watchdog-result-write-${token}`, {
1552
+ schema_version: "flowdesk.task_failed.v1",
1553
+ workflow_id: input.workflowId,
1554
+ lane_id: laneId,
1555
+ task_id: taskId,
1556
+ agent_ref: agentRef,
1557
+ provider_qualified_model_id: modelId,
1558
+ failure_category: "unknown",
1559
+ redacted_reason: "watchdog could not persist task_result evidence",
1560
+ created_at: completedAt,
1561
+ dispatch_authority_enabled: false,
1562
+ });
1563
+ writeAgentTaskProgressEvidence({
1564
+ rootDir: input.rootDir,
1565
+ workflowId: input.workflowId,
1566
+ laneId,
1567
+ taskId,
1568
+ agentRef,
1569
+ providerQualifiedModelId: modelId,
1570
+ phase: "failed",
1571
+ progressSeq: 20 + nudgeCount,
1572
+ progressLabel: "async agent task result persistence failed",
1573
+ observedAt: completedAt,
1574
+ });
1575
+ continue;
1576
+ }
1577
+ writeAgentTaskProgressEvidence({
1578
+ rootDir: input.rootDir,
1579
+ workflowId: input.workflowId,
1580
+ laneId,
1581
+ taskId,
1582
+ agentRef,
1583
+ providerQualifiedModelId: modelId,
1584
+ phase: "finalizing",
1585
+ progressSeq: 10 + nudgeCount,
1586
+ progressLabel: "async agent task result captured by watchdog",
1587
+ observedAt: completedAt,
1588
+ });
1589
+ refreshFlowDeskCompletionUiCachesV1({
1590
+ rootDir: input.rootDir,
1591
+ workflowId: input.workflowId,
1592
+ observedAt: completedAt,
1593
+ });
1594
+ result.lanesCompleted++;
1595
+ continue;
1596
+ }
1597
+ // 2. Abort threshold exceeded
1598
+ if (totalAgeMs >= abortThresholdMs && nudgeCount >= maxNudges) {
1599
+ await abortChildSession(input.client, childSessionId);
1600
+ const taskId = typeof record.task_id === "string" ? record.task_id : laneId;
1601
+ const agentRef = typeof record.agent_ref === "string" ? record.agent_ref : "agent-unknown";
1602
+ const modelId = typeof record.provider_qualified_model_id === "string" ? record.provider_qualified_model_id : "unknown/unknown";
1603
+ if (laneAlreadyHasTerminalTaskEvidence({ rootDir: input.rootDir, workflowId: input.workflowId, laneId })) {
1604
+ continue;
1605
+ }
1606
+ const token = randomBytes(4).toString("hex");
1607
+ const abortedAt = new Date(nowMs).toISOString();
1608
+ const partialObservation = await pollChildSessionCandidate(input.client, childSessionId);
1609
+ if (partialObservation !== null && partialObservation.text.trim().length > 0) {
1610
+ const sanitizedResult = sanitizeFlowDeskTaskResultTextV1(partialObservation.text);
1611
+ const taskResultWritten = writeChildSessionEvidence(input.rootDir, input.workflowId, `task-result-${taskId}-watchdog-partial-${token}`, {
1612
+ schema_version: "flowdesk.task_result.v1",
1613
+ workflow_id: input.workflowId,
1614
+ lane_id: laneId,
1615
+ task_id: taskId,
1616
+ agent_ref: agentRef,
1617
+ provider_qualified_model_id: modelId,
1618
+ task_prompt_sha256: createHash("sha256").update("watchdog-collected").digest("hex"),
1619
+ result_text: sanitizedResult.text,
1620
+ result_text_truncated: sanitizedResult.truncated,
1621
+ result_text_sha256: createHash("sha256").update(partialObservation.text).digest("hex"),
1622
+ completion_status: "partial",
1623
+ output_kind: partialObservation.outputKind,
1624
+ usable_for_synthesis: partialObservation.usableForSynthesis,
1625
+ missing_contract: true,
1626
+ created_at: abortedAt,
1627
+ dispatch_authority_enabled: false,
1628
+ });
1629
+ if (taskResultWritten) {
1630
+ writeAgentTaskProgressEvidence({
1631
+ rootDir: input.rootDir,
1632
+ workflowId: input.workflowId,
1633
+ laneId,
1634
+ taskId,
1635
+ agentRef,
1636
+ providerQualifiedModelId: modelId,
1637
+ phase: "finalizing",
1638
+ progressSeq: 20 + nudgeCount,
1639
+ progressLabel: "async agent task partial result captured before abort",
1640
+ observedAt: abortedAt,
1641
+ });
1642
+ refreshFlowDeskCompletionUiCachesV1({
1643
+ rootDir: input.rootDir,
1644
+ workflowId: input.workflowId,
1645
+ observedAt: abortedAt,
1646
+ });
1647
+ result.lanesCompleted++;
1648
+ continue;
1649
+ }
1650
+ }
1651
+ const failureCategory = totalAgeMs > abortThresholdMs * 2
1652
+ ? "network_interrupted"
1653
+ : "sdk_prompt_timeout";
1654
+ writeChildSessionEvidence(input.rootDir, input.workflowId, `task-failed-${taskId}-watchdog-abort-${token}`, {
1655
+ schema_version: "flowdesk.task_failed.v1",
1656
+ workflow_id: input.workflowId,
1657
+ lane_id: laneId,
1658
+ task_id: taskId,
1659
+ agent_ref: agentRef,
1660
+ provider_qualified_model_id: modelId,
1661
+ failure_category: failureCategory,
1662
+ redacted_reason: `watchdog aborted child session after ${Math.round(totalAgeMs / 1000)}s with no response`,
1663
+ created_at: abortedAt,
1664
+ dispatch_authority_enabled: false,
1665
+ });
1666
+ writeAgentTaskProgressEvidence({
1667
+ rootDir: input.rootDir,
1668
+ workflowId: input.workflowId,
1669
+ laneId,
1670
+ taskId,
1671
+ agentRef,
1672
+ providerQualifiedModelId: modelId,
1673
+ phase: "failed",
1674
+ progressSeq: 20 + nudgeCount,
1675
+ progressLabel: "async agent task aborted after no response",
1676
+ observedAt: abortedAt,
1677
+ });
1678
+ result.lanesAborted++;
1679
+ continue;
1680
+ }
1681
+ // 3. Nudge if silence threshold exceeded
1682
+ if (silenceMs >= nudgeQuietPeriodMs && nudgeCount < maxNudges) {
1683
+ await sendWatchdogNudge(input.client, childSessionId);
1684
+ result.lanesNudged++;
1685
+ const taskId = typeof record.task_id === "string" ? record.task_id : laneId;
1686
+ const agentRef = typeof record.agent_ref === "string" ? record.agent_ref : "agent-unknown";
1687
+ const modelId = typeof record.provider_qualified_model_id === "string" ? record.provider_qualified_model_id : "unknown/unknown";
1688
+ const nudgedAt = new Date(nowMs).toISOString();
1689
+ writeAgentTaskProgressEvidence({
1690
+ rootDir: input.rootDir,
1691
+ workflowId: input.workflowId,
1692
+ laneId,
1693
+ taskId,
1694
+ agentRef,
1695
+ providerQualifiedModelId: modelId,
1696
+ phase: "nudged",
1697
+ progressSeq: 2 + nudgeCount,
1698
+ progressLabel: "async agent task nudged after quiet period",
1699
+ observedAt: nudgedAt,
1700
+ });
1701
+ // Update nudge_count in evidence (overwrite record)
1702
+ const evidenceId = reloaded.entries
1703
+ .find(e => e.evidenceClass === "agent_task_child_session" && e.record.lane_id === laneId)
1704
+ ?.evidenceId ?? `agent-task-child-session-${laneId}-watchdog`;
1705
+ writeChildSessionEvidence(input.rootDir, input.workflowId, evidenceId, {
1706
+ ...record,
1707
+ nudge_count: nudgeCount + 1,
1708
+ last_nudge_at: new Date(nowMs).toISOString(),
1709
+ });
1710
+ }
1711
+ }
1712
+ return result;
1713
+ }
1257
1714
  //# sourceMappingURL=stall-recovery.js.map