@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.
- package/README.md +1 -1
- package/dist/agent-task-output.d.ts +17 -0
- package/dist/agent-task-output.d.ts.map +1 -0
- package/dist/agent-task-output.js +119 -0
- package/dist/agent-task-output.js.map +1 -0
- package/dist/agent-task-runner.d.ts +23 -0
- package/dist/agent-task-runner.d.ts.map +1 -1
- package/dist/agent-task-runner.js +410 -81
- package/dist/agent-task-runner.js.map +1 -1
- package/dist/auto-continue-preview-tool.d.ts +36 -0
- package/dist/auto-continue-preview-tool.d.ts.map +1 -0
- package/dist/auto-continue-preview-tool.js +119 -0
- package/dist/auto-continue-preview-tool.js.map +1 -0
- package/dist/completion-ui-cache.d.ts +6 -0
- package/dist/completion-ui-cache.d.ts.map +1 -0
- package/dist/completion-ui-cache.js +260 -0
- package/dist/completion-ui-cache.js.map +1 -0
- package/dist/event-hook-observer.d.ts +14 -0
- package/dist/event-hook-observer.d.ts.map +1 -0
- package/dist/event-hook-observer.js +193 -0
- package/dist/event-hook-observer.js.map +1 -0
- package/dist/managed-dispatch-adapter.d.ts.map +1 -1
- package/dist/managed-dispatch-adapter.js +7 -3
- package/dist/managed-dispatch-adapter.js.map +1 -1
- package/dist/model-selection-engine.d.ts +47 -0
- package/dist/model-selection-engine.d.ts.map +1 -0
- package/dist/model-selection-engine.js +175 -0
- package/dist/model-selection-engine.js.map +1 -0
- package/dist/provider-usage-live-tool.d.ts +10 -0
- package/dist/provider-usage-live-tool.d.ts.map +1 -1
- package/dist/provider-usage-live-tool.js +145 -18
- package/dist/provider-usage-live-tool.js.map +1 -1
- package/dist/server.d.ts +35 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +447 -19
- package/dist/server.js.map +1 -1
- package/dist/stall-recovery.d.ts +33 -0
- package/dist/stall-recovery.d.ts.map +1 -1
- package/dist/stall-recovery.js +459 -2
- package/dist/stall-recovery.js.map +1 -1
- package/dist/status-live-tool.d.ts +54 -0
- package/dist/status-live-tool.d.ts.map +1 -1
- package/dist/status-live-tool.js +448 -44
- package/dist/status-live-tool.js.map +1 -1
- package/dist/tui-subtask-activity.d.ts +69 -0
- package/dist/tui-subtask-activity.d.ts.map +1 -0
- package/dist/tui-subtask-activity.js +266 -0
- package/dist/tui-subtask-activity.js.map +1 -0
- package/dist/tui-usage-snapshot.d.ts +14 -0
- package/dist/tui-usage-snapshot.d.ts.map +1 -1
- package/dist/tui-usage-snapshot.js +189 -8
- package/dist/tui-usage-snapshot.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +72 -41
- package/dist/tui.js.map +1 -1
- package/dist/workflow-assign-tool.d.ts +23 -0
- package/dist/workflow-assign-tool.d.ts.map +1 -0
- package/dist/workflow-assign-tool.js +117 -0
- package/dist/workflow-assign-tool.js.map +1 -0
- package/dist/workflow-author-tool.d.ts +29 -0
- package/dist/workflow-author-tool.d.ts.map +1 -0
- package/dist/workflow-author-tool.js +227 -0
- package/dist/workflow-author-tool.js.map +1 -0
- package/dist/workflow-dispatch-tool.d.ts.map +1 -1
- package/dist/workflow-dispatch-tool.js +32 -2
- package/dist/workflow-dispatch-tool.js.map +1 -1
- package/dist/workflow-orchestrator.d.ts +31 -0
- package/dist/workflow-orchestrator.d.ts.map +1 -0
- package/dist/workflow-orchestrator.js +160 -0
- package/dist/workflow-orchestrator.js.map +1 -0
- package/dist/workflow-scheduler.d.ts.map +1 -1
- package/dist/workflow-scheduler.js +3 -1
- package/dist/workflow-scheduler.js.map +1 -1
- package/dist/workflow-synthesis-tool.d.ts +31 -0
- package/dist/workflow-synthesis-tool.d.ts.map +1 -0
- package/dist/workflow-synthesis-tool.js +194 -0
- package/dist/workflow-synthesis-tool.js.map +1 -0
- package/package.json +2 -2
package/dist/stall-recovery.d.ts
CHANGED
|
@@ -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":"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,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
|