@useorgx/openclaw-plugin 0.7.20 → 0.7.24
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/dashboard/dist/assets/B6VftyY6.js +1 -0
- package/dashboard/dist/assets/B6VftyY6.js.br +0 -0
- package/dashboard/dist/assets/B6VftyY6.js.gz +0 -0
- package/dashboard/dist/assets/{Dm0CfDGr.js → BANQdlC4.js} +1 -1
- package/dashboard/dist/assets/BANQdlC4.js.br +0 -0
- package/dashboard/dist/assets/BANQdlC4.js.gz +0 -0
- package/dashboard/dist/assets/{_zpQCpjm.js → BPL4CL3c.js} +1 -1
- package/dashboard/dist/assets/BPL4CL3c.js.br +0 -0
- package/dashboard/dist/assets/BPL4CL3c.js.gz +0 -0
- package/dashboard/dist/assets/{DXVs61e1.js → BZCkOZ20.js} +1 -1
- package/dashboard/dist/assets/BZCkOZ20.js.br +0 -0
- package/dashboard/dist/assets/BZCkOZ20.js.gz +0 -0
- package/dashboard/dist/assets/{BYb6DARX.js → B_LdOJUa.js} +1 -1
- package/dashboard/dist/assets/B_LdOJUa.js.br +0 -0
- package/dashboard/dist/assets/B_LdOJUa.js.gz +0 -0
- package/dashboard/dist/assets/Bfp-wdwb.css +1 -0
- package/dashboard/dist/assets/Bfp-wdwb.css.br +0 -0
- package/dashboard/dist/assets/Bfp-wdwb.css.gz +0 -0
- package/dashboard/dist/assets/{DibzNd0I.js → BvFcH_Iy.js} +1 -1
- package/dashboard/dist/assets/BvFcH_Iy.js.br +0 -0
- package/dashboard/dist/assets/BvFcH_Iy.js.gz +0 -0
- package/dashboard/dist/assets/By0MIBj_.js +1 -0
- package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
- package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
- package/dashboard/dist/assets/C0i7ABUU.js +212 -0
- package/dashboard/dist/assets/C0i7ABUU.js.br +0 -0
- package/dashboard/dist/assets/C0i7ABUU.js.gz +0 -0
- package/dashboard/dist/assets/CFB0MM7j.js +1 -0
- package/dashboard/dist/assets/CFB0MM7j.js.br +0 -0
- package/dashboard/dist/assets/CFB0MM7j.js.gz +0 -0
- package/dashboard/dist/assets/CQSRb1yu.js +1 -0
- package/dashboard/dist/assets/CQSRb1yu.js.br +0 -0
- package/dashboard/dist/assets/CQSRb1yu.js.gz +0 -0
- package/dashboard/dist/assets/{wa4jJQK9.js → CUoQoSm-.js} +1 -1
- package/dashboard/dist/assets/CUoQoSm-.js.br +0 -0
- package/dashboard/dist/assets/CUoQoSm-.js.gz +0 -0
- package/dashboard/dist/assets/Ckd1R1iE.js +1 -0
- package/dashboard/dist/assets/Ckd1R1iE.js.br +0 -0
- package/dashboard/dist/assets/Ckd1R1iE.js.gz +0 -0
- package/dashboard/dist/assets/{BGY6oI8h.js → CqRNb2EL.js} +1 -1
- package/dashboard/dist/assets/CqRNb2EL.js.br +0 -0
- package/dashboard/dist/assets/CqRNb2EL.js.gz +0 -0
- package/dashboard/dist/assets/{DAr4MfFk.js → DClUc9rw.js} +1 -1
- package/dashboard/dist/assets/DClUc9rw.js.br +0 -0
- package/dashboard/dist/assets/DClUc9rw.js.gz +0 -0
- package/dashboard/dist/assets/DF2PMTwT.js +1 -0
- package/dashboard/dist/assets/DF2PMTwT.js.br +0 -0
- package/dashboard/dist/assets/DF2PMTwT.js.gz +0 -0
- package/dashboard/dist/assets/{B014hrCe.js → DJYl7gyA.js} +2 -2
- package/dashboard/dist/assets/DJYl7gyA.js.br +0 -0
- package/dashboard/dist/assets/DJYl7gyA.js.gz +0 -0
- package/dashboard/dist/assets/{BoDhb8_y.js → DZtNMX0t.js} +2 -2
- package/dashboard/dist/assets/DZtNMX0t.js.br +0 -0
- package/dashboard/dist/assets/DZtNMX0t.js.gz +0 -0
- package/dashboard/dist/assets/DlEa8PI0.js +1 -0
- package/dashboard/dist/assets/DlEa8PI0.js.br +0 -0
- package/dashboard/dist/assets/DlEa8PI0.js.gz +0 -0
- package/dashboard/dist/assets/M4QxcXjh.js +1 -0
- package/dashboard/dist/assets/M4QxcXjh.js.br +0 -0
- package/dashboard/dist/assets/M4QxcXjh.js.gz +0 -0
- package/dashboard/dist/assets/{CV0sWMbv.js → MrW1ixGx.js} +1 -1
- package/dashboard/dist/assets/MrW1ixGx.js.br +0 -0
- package/dashboard/dist/assets/MrW1ixGx.js.gz +0 -0
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/activity-store.js +68 -8
- package/dist/agent-run-store.js +162 -24
- package/dist/cli/orgx.d.ts +3 -0
- package/dist/config/resolution.d.ts +7 -0
- package/dist/config/resolution.js +13 -5
- package/dist/contracts/onboarding-state.d.ts +2 -0
- package/dist/contracts/onboarding-state.js +23 -0
- package/dist/contracts/shared-types.d.ts +45 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
- package/dist/http/helpers/auto-continue-engine.js +468 -85
- package/dist/http/helpers/autopilot-runtime.js +5 -1
- package/dist/http/helpers/autopilot-slice-utils.js +25 -1
- package/dist/http/helpers/decision-mapper.d.ts +1 -0
- package/dist/http/helpers/decision-mapper.js +19 -2
- package/dist/http/helpers/dispatch-lifecycle.js +3 -0
- package/dist/http/helpers/mission-control.d.ts +1 -0
- package/dist/http/helpers/mission-control.js +5 -2
- package/dist/http/helpers/slice-run-projections.d.ts +27 -0
- package/dist/http/helpers/slice-run-projections.js +198 -10
- package/dist/http/helpers/triage-mapper.js +499 -6
- package/dist/http/helpers/value-utils.d.ts +1 -0
- package/dist/http/helpers/value-utils.js +17 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +179 -46
- package/dist/http/router.js +64 -9
- package/dist/http/routes/live-legacy.d.ts +19 -2
- package/dist/http/routes/live-legacy.js +110 -27
- package/dist/http/routes/live-snapshot.d.ts +16 -2
- package/dist/http/routes/live-snapshot.js +169 -25
- package/dist/http/routes/live-triage.js +6 -1
- package/dist/http/routes/mission-control-actions.d.ts +9 -0
- package/dist/http/routes/mission-control-actions.js +185 -7
- package/dist/http/routes/mission-control-read.d.ts +13 -0
- package/dist/http/routes/mission-control-read.js +100 -219
- package/dist/http/routes/onboarding.d.ts +1 -0
- package/dist/http/routes/onboarding.js +17 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +199 -123
- package/dist/outbox.d.ts +0 -2
- package/dist/outbox.js +259 -148
- package/dist/reporting/rollups.js +18 -11
- package/dist/runtime-instance-store.js +212 -58
- package/dist/stores/materialized-snapshot-store.d.ts +18 -0
- package/dist/stores/materialized-snapshot-store.js +91 -0
- package/dist/stores/sqlite-state.d.ts +6 -0
- package/dist/stores/sqlite-state.js +330 -0
- package/package.json +5 -1
- package/dashboard/dist/assets/B014hrCe.js.br +0 -0
- package/dashboard/dist/assets/B014hrCe.js.gz +0 -0
- package/dashboard/dist/assets/BCudUvwg.js +0 -1
- package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
- package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
- package/dashboard/dist/assets/BGY6oI8h.js.br +0 -0
- package/dashboard/dist/assets/BGY6oI8h.js.gz +0 -0
- package/dashboard/dist/assets/BJI1Iy5v.css +0 -1
- package/dashboard/dist/assets/BJI1Iy5v.css.br +0 -0
- package/dashboard/dist/assets/BJI1Iy5v.css.gz +0 -0
- package/dashboard/dist/assets/BUvcp_7V.js +0 -1
- package/dashboard/dist/assets/BUvcp_7V.js.br +0 -0
- package/dashboard/dist/assets/BUvcp_7V.js.gz +0 -0
- package/dashboard/dist/assets/BV2Tf8S2.js +0 -212
- package/dashboard/dist/assets/BV2Tf8S2.js.br +0 -0
- package/dashboard/dist/assets/BV2Tf8S2.js.gz +0 -0
- package/dashboard/dist/assets/BYb6DARX.js.br +0 -0
- package/dashboard/dist/assets/BYb6DARX.js.gz +0 -0
- package/dashboard/dist/assets/BoDhb8_y.js.br +0 -0
- package/dashboard/dist/assets/BoDhb8_y.js.gz +0 -0
- package/dashboard/dist/assets/Bqk_l0k6.js +0 -1
- package/dashboard/dist/assets/Bqk_l0k6.js.br +0 -0
- package/dashboard/dist/assets/Bqk_l0k6.js.gz +0 -0
- package/dashboard/dist/assets/C-MOJWHs.js +0 -1
- package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
- package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
- package/dashboard/dist/assets/CV0sWMbv.js.br +0 -0
- package/dashboard/dist/assets/CV0sWMbv.js.gz +0 -0
- package/dashboard/dist/assets/CaAkScfa.js +0 -1
- package/dashboard/dist/assets/CaAkScfa.js.br +0 -0
- package/dashboard/dist/assets/CaAkScfa.js.gz +0 -0
- package/dashboard/dist/assets/Ck5KlsPN.js +0 -1
- package/dashboard/dist/assets/Ck5KlsPN.js.br +0 -0
- package/dashboard/dist/assets/Ck5KlsPN.js.gz +0 -0
- package/dashboard/dist/assets/D2G51wQm.js +0 -1
- package/dashboard/dist/assets/D2G51wQm.js.br +0 -0
- package/dashboard/dist/assets/D2G51wQm.js.gz +0 -0
- package/dashboard/dist/assets/DAr4MfFk.js.br +0 -0
- package/dashboard/dist/assets/DAr4MfFk.js.gz +0 -0
- package/dashboard/dist/assets/DXVs61e1.js.br +0 -0
- package/dashboard/dist/assets/DXVs61e1.js.gz +0 -0
- package/dashboard/dist/assets/DibzNd0I.js.br +0 -0
- package/dashboard/dist/assets/DibzNd0I.js.gz +0 -0
- package/dashboard/dist/assets/Dm0CfDGr.js.br +0 -0
- package/dashboard/dist/assets/Dm0CfDGr.js.gz +0 -0
- package/dashboard/dist/assets/_zpQCpjm.js.br +0 -0
- package/dashboard/dist/assets/_zpQCpjm.js.gz +0 -0
- package/dashboard/dist/assets/uNGpYMSH.js +0 -1
- package/dashboard/dist/assets/uNGpYMSH.js.br +0 -0
- package/dashboard/dist/assets/uNGpYMSH.js.gz +0 -0
- package/dashboard/dist/assets/wa4jJQK9.js.br +0 -0
- package/dashboard/dist/assets/wa4jJQK9.js.gz +0 -0
|
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { readdir, stat, unlink } from "node:fs/promises";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
|
-
import { normalizeActivityActionPhase, normalizeActivityActionType, } from "../../contracts/shared-types.js";
|
|
6
|
+
import { normalizeActivityActionPhase, normalizeActivityActionType, normalizeDecisionActionType, } from "../../contracts/shared-types.js";
|
|
7
7
|
import { upsertAgentContext, upsertRunContext } from "../../agent-context-store.js";
|
|
8
8
|
import { appendTeamCompletion } from "../../team-context-store.js";
|
|
9
9
|
import { readOpenClawGatewayPort, readOpenClawSettingsSnapshot, } from "../../openclaw-settings.js";
|
|
@@ -11,7 +11,7 @@ import { resolveRuntimeHookToken, } from "../../runtime-instance-store.js";
|
|
|
11
11
|
import { detectMcpHandshakeFailure, shouldKillWorker } from "../../worker-supervisor.js";
|
|
12
12
|
import { humanizeSliceFailure, humanizeSliceFailureSummary } from "./humanize-slice-failure.js";
|
|
13
13
|
import { getOrgxPluginConfigDir } from "../../paths.js";
|
|
14
|
-
import { buildMissionControlGraph, DEFAULT_TOKEN_BUDGET_ASSUMPTIONS, dedupeStrings, detectBehaviorConfigDrift, deriveBehaviorAutomationLevel, deriveBehaviorConfigContext, deriveExecutionPolicy, evaluateScopeCompletion, isDispatchableWorkstreamStatus, isDoneStatus, isTodoStatus, readBudgetEnvNumber, selectSliceTasksByScope, SLICE_SCOPE_TIMEOUT_MULTIPLIER, spawnGuardIsRateLimited, summarizeSpawnGuardBlockReason, } from "./mission-control.js";
|
|
14
|
+
import { buildMissionControlGraph, DEFAULT_TOKEN_BUDGET_ASSUMPTIONS, dedupeStrings, detectBehaviorConfigDrift, deriveBehaviorAutomationLevel, deriveBehaviorConfigContext, deriveInitiativeLifecycleStatus, deriveExecutionPolicy, evaluateScopeCompletion, isDispatchableWorkstreamStatus, isDoneStatus, isTodoStatus, readBudgetEnvNumber, selectSliceTasksByScope, SLICE_SCOPE_TIMEOUT_MULTIPLIER, spawnGuardIsRateLimited, summarizeSpawnGuardBlockReason, } from "./mission-control.js";
|
|
15
15
|
import { createAutopilotRuntime } from "./autopilot-runtime.js";
|
|
16
16
|
import { buildScopeDirective, buildSliceOutputInstructions, buildWorkstreamSlicePrompt, createCodexBinResolver, ensureAutopilotSliceSchemaPath, extractSessionIdFromLog, extractSessionIdFromOutput, fileUpdatedAtEpochMs, parseSliceResult, readFileTailSafe, readSliceOutputFile, } from "./autopilot-slice-utils.js";
|
|
17
17
|
import { pickString } from "./value-utils.js";
|
|
@@ -28,7 +28,18 @@ function resolveAutopilotDefaultCwd(filename) {
|
|
|
28
28
|
}
|
|
29
29
|
return homedir();
|
|
30
30
|
}
|
|
31
|
+
function captureAutopilotWorkerEnv() {
|
|
32
|
+
return {
|
|
33
|
+
ORGX_AUTOPILOT_CWD: (process.env.ORGX_AUTOPILOT_CWD ?? "").trim() || undefined,
|
|
34
|
+
ORGX_AUTOPILOT_EXECUTOR: (process.env.ORGX_AUTOPILOT_EXECUTOR ?? "").trim() || undefined,
|
|
35
|
+
ORGX_AUTOPILOT_WORKER_KIND: (process.env.ORGX_AUTOPILOT_WORKER_KIND ?? "").trim() || undefined,
|
|
36
|
+
ORGX_AUTOPILOT_MOCK_SCENARIO: (process.env.ORGX_AUTOPILOT_MOCK_SCENARIO ?? "").trim() || undefined,
|
|
37
|
+
ORGX_AUTOPILOT_MOCK_SLEEP_MS: (process.env.ORGX_AUTOPILOT_MOCK_SLEEP_MS ?? "").trim() || undefined,
|
|
38
|
+
ORGX_AUTOPILOT_SESSION_RESUME: (process.env.ORGX_AUTOPILOT_SESSION_RESUME ?? "").trim() || undefined,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
31
41
|
export function createAutoContinueEngine(deps) {
|
|
42
|
+
const defaultWorkerEnvOverrides = captureAutopilotWorkerEnv();
|
|
32
43
|
const { client, safeErrorMessage, pidAlive, stopProcess, resolveOrgxAgentForDomain, checkSpawnGuardSafe, syncParentRollupsForTask, emitActivitySafe, requestDecisionSafe, registerArtifactSafe, applyAgentStatusUpdatesSafe, upsertRuntimeInstanceFromHook, broadcastRuntimeSse, clearSnapshotResponseCache, resolveByokEnvOverrides, } = deps;
|
|
33
44
|
const randomUUID = deps.randomUUID ?? randomUuidFn;
|
|
34
45
|
const fetchKickoffContextSafeFn = deps.fetchKickoffContextSafe ?? null;
|
|
@@ -319,10 +330,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
319
330
|
event: "question_timeout_started",
|
|
320
331
|
action_type: normalizeActivityActionType("question_timeout_started"),
|
|
321
332
|
action_phase: normalizeActivityActionPhase("review"),
|
|
322
|
-
|
|
323
|
-
workstream_id: pending.workstreamId,
|
|
324
|
-
source_run_id: pending.sourceRunId,
|
|
325
|
-
source_client: pending.sourceClient,
|
|
333
|
+
...(pending.eventMetadata ?? {}),
|
|
326
334
|
decision_ids: pending.decisionIds,
|
|
327
335
|
decision_count: pending.decisionIds.length,
|
|
328
336
|
decision_action: pending.action,
|
|
@@ -367,6 +375,166 @@ export function createAutoContinueEngine(deps) {
|
|
|
367
375
|
}, delaySeconds * 1_000);
|
|
368
376
|
pending.timer.unref?.();
|
|
369
377
|
};
|
|
378
|
+
const pickMetadataString = (record, keys) => {
|
|
379
|
+
if (!record)
|
|
380
|
+
return null;
|
|
381
|
+
for (const key of keys) {
|
|
382
|
+
const value = record[key];
|
|
383
|
+
if (typeof value !== "string")
|
|
384
|
+
continue;
|
|
385
|
+
const trimmed = value.trim();
|
|
386
|
+
if (trimmed.length > 0)
|
|
387
|
+
return trimmed;
|
|
388
|
+
}
|
|
389
|
+
return null;
|
|
390
|
+
};
|
|
391
|
+
const pickMetadataStringArray = (record, keys) => {
|
|
392
|
+
if (!record)
|
|
393
|
+
return [];
|
|
394
|
+
for (const key of keys) {
|
|
395
|
+
const raw = record[key];
|
|
396
|
+
if (!Array.isArray(raw))
|
|
397
|
+
continue;
|
|
398
|
+
const values = raw
|
|
399
|
+
.filter((entry) => typeof entry === "string")
|
|
400
|
+
.map((entry) => entry.trim())
|
|
401
|
+
.filter(Boolean);
|
|
402
|
+
if (values.length > 0)
|
|
403
|
+
return values;
|
|
404
|
+
}
|
|
405
|
+
return [];
|
|
406
|
+
};
|
|
407
|
+
const normalizeQueuedDecisionOptions = (value, recommendedAction) => {
|
|
408
|
+
if (!Array.isArray(value))
|
|
409
|
+
return [];
|
|
410
|
+
const normalized = [];
|
|
411
|
+
const seen = new Set();
|
|
412
|
+
const recommendedLower = recommendedAction?.trim().toLowerCase() ?? null;
|
|
413
|
+
for (const rawOption of value) {
|
|
414
|
+
if (typeof rawOption === "string") {
|
|
415
|
+
const label = rawOption.trim();
|
|
416
|
+
if (!label)
|
|
417
|
+
continue;
|
|
418
|
+
const key = label.toLowerCase();
|
|
419
|
+
if (seen.has(key))
|
|
420
|
+
continue;
|
|
421
|
+
seen.add(key);
|
|
422
|
+
normalized.push({
|
|
423
|
+
label,
|
|
424
|
+
recommended: recommendedLower !== null && label.toLowerCase() === recommendedLower,
|
|
425
|
+
});
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (!rawOption || typeof rawOption !== "object" || Array.isArray(rawOption))
|
|
429
|
+
continue;
|
|
430
|
+
const optionRecord = rawOption;
|
|
431
|
+
const label = pickMetadataString(optionRecord, ["label", "title", "name"]) ??
|
|
432
|
+
pickMetadataString(optionRecord, ["action", "action_type", "actionType"]);
|
|
433
|
+
if (!label)
|
|
434
|
+
continue;
|
|
435
|
+
const id = pickMetadataString(optionRecord, ["id", "option_id", "optionId"]);
|
|
436
|
+
const description = pickMetadataString(optionRecord, ["description", "summary"]);
|
|
437
|
+
const consequences = pickMetadataString(optionRecord, ["consequences", "impact"]);
|
|
438
|
+
const actionType = pickMetadataString(optionRecord, ["action_type", "actionType", "action"]);
|
|
439
|
+
const impliedStatus = pickMetadataString(optionRecord, ["implied_status", "impliedStatus", "status"]);
|
|
440
|
+
const requiresNote = optionRecord.requires_note === true ||
|
|
441
|
+
optionRecord.requiresNote === true ||
|
|
442
|
+
optionRecord.note_required === true;
|
|
443
|
+
const recommended = optionRecord.recommended === true ||
|
|
444
|
+
optionRecord.is_recommended === true ||
|
|
445
|
+
optionRecord.isRecommended === true ||
|
|
446
|
+
(recommendedLower !== null && label.toLowerCase() === recommendedLower);
|
|
447
|
+
const key = `${(id ?? "").toLowerCase()}|${label.toLowerCase()}`;
|
|
448
|
+
if (seen.has(key))
|
|
449
|
+
continue;
|
|
450
|
+
seen.add(key);
|
|
451
|
+
normalized.push({
|
|
452
|
+
...(id ? { id } : {}),
|
|
453
|
+
label,
|
|
454
|
+
...(description ? { description } : {}),
|
|
455
|
+
...(consequences ? { consequences } : {}),
|
|
456
|
+
...(actionType ? { action_type: actionType } : {}),
|
|
457
|
+
...(impliedStatus ? { implied_status: impliedStatus } : {}),
|
|
458
|
+
...(requiresNote ? { requires_note: true } : {}),
|
|
459
|
+
...(recommended ? { recommended: true } : {}),
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
return normalized.slice(0, 8);
|
|
463
|
+
};
|
|
464
|
+
const normalizeQueuedDecisionEvidence = (value) => {
|
|
465
|
+
if (!Array.isArray(value))
|
|
466
|
+
return [];
|
|
467
|
+
const normalized = [];
|
|
468
|
+
const seen = new Set();
|
|
469
|
+
for (const rawEvidence of value) {
|
|
470
|
+
if (!rawEvidence || typeof rawEvidence !== "object" || Array.isArray(rawEvidence))
|
|
471
|
+
continue;
|
|
472
|
+
const record = rawEvidence;
|
|
473
|
+
const title = pickMetadataString(record, ["title", "label", "name"]) ??
|
|
474
|
+
pickMetadataString(record, ["source_pointer", "sourcePointer", "source_url", "sourceUrl"]) ??
|
|
475
|
+
"Evidence";
|
|
476
|
+
const summary = pickMetadataString(record, ["summary", "description"]);
|
|
477
|
+
const sourceUrl = pickMetadataString(record, ["source_url", "sourceUrl", "url"]);
|
|
478
|
+
const sourcePointer = pickMetadataString(record, ["source_pointer", "sourcePointer", "path"]);
|
|
479
|
+
const evidenceType = pickMetadataString(record, ["evidence_type", "evidenceType", "type"]);
|
|
480
|
+
const confidenceRaw = record.confidence ?? record.confidence_score;
|
|
481
|
+
const confidence = typeof confidenceRaw === "number" && Number.isFinite(confidenceRaw)
|
|
482
|
+
? Math.max(0, Math.min(1, confidenceRaw))
|
|
483
|
+
: null;
|
|
484
|
+
const key = `${title.toLowerCase()}|${sourceUrl ?? ""}|${sourcePointer ?? ""}`;
|
|
485
|
+
if (seen.has(key))
|
|
486
|
+
continue;
|
|
487
|
+
seen.add(key);
|
|
488
|
+
normalized.push({
|
|
489
|
+
title,
|
|
490
|
+
...(summary ? { summary } : {}),
|
|
491
|
+
...(sourceUrl ? { source_url: sourceUrl } : {}),
|
|
492
|
+
...(sourcePointer ? { source_pointer: sourcePointer } : {}),
|
|
493
|
+
...(evidenceType ? { evidence_type: evidenceType } : {}),
|
|
494
|
+
...(confidence !== null ? { confidence } : {}),
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
return normalized.slice(0, 8);
|
|
498
|
+
};
|
|
499
|
+
const buildQuestionEventMetadata = (input) => {
|
|
500
|
+
const metadata = {
|
|
501
|
+
initiative_id: input.initiativeId,
|
|
502
|
+
workstream_id: input.workstreamId,
|
|
503
|
+
source_run_id: input.sourceRunId,
|
|
504
|
+
source_client: input.sourceClient,
|
|
505
|
+
decision_ids: input.decisionIds,
|
|
506
|
+
decision_count: input.decisionIds.length,
|
|
507
|
+
blocking: input.blocking,
|
|
508
|
+
decision_title: input.title,
|
|
509
|
+
decision_prompt: input.title,
|
|
510
|
+
question: input.title,
|
|
511
|
+
required_action: input.recommendedAction,
|
|
512
|
+
recommended_action: input.recommendedAction,
|
|
513
|
+
current_run_state: input.currentRunState,
|
|
514
|
+
impact_if_delayed: input.impactIfDelayed,
|
|
515
|
+
reason: input.reason,
|
|
516
|
+
decision_type: input.decisionType,
|
|
517
|
+
};
|
|
518
|
+
if (input.summary)
|
|
519
|
+
metadata.decision_summary = input.summary;
|
|
520
|
+
if (input.options.length > 0) {
|
|
521
|
+
metadata.decision_options = input.options;
|
|
522
|
+
metadata.decision_option_labels = input.options.map((option) => option.label);
|
|
523
|
+
}
|
|
524
|
+
if (input.evidenceRefs.length > 0)
|
|
525
|
+
metadata.evidence_refs = input.evidenceRefs;
|
|
526
|
+
if (input.scopeHierarchy.length > 0)
|
|
527
|
+
metadata.scope_hierarchy = input.scopeHierarchy;
|
|
528
|
+
if (input.initiativeTitle)
|
|
529
|
+
metadata.initiative_title = input.initiativeTitle;
|
|
530
|
+
if (input.workstreamTitle)
|
|
531
|
+
metadata.workstream_title = input.workstreamTitle;
|
|
532
|
+
if (input.taskTitle)
|
|
533
|
+
metadata.task_title = input.taskTitle;
|
|
534
|
+
if (input.nextActions.length > 0)
|
|
535
|
+
metadata.next_actions = input.nextActions;
|
|
536
|
+
return metadata;
|
|
537
|
+
};
|
|
370
538
|
const scheduleQuestionAutoAnswer = async (input) => {
|
|
371
539
|
const decisionIds = dedupeStrings(input.decisionIds
|
|
372
540
|
.map((entry) => (entry ?? "").trim())
|
|
@@ -374,6 +542,28 @@ export function createAutoContinueEngine(deps) {
|
|
|
374
542
|
if (decisionIds.length === 0)
|
|
375
543
|
return;
|
|
376
544
|
const policy = resolveQuestionPolicy(input.initiativeId, input.workstreamId);
|
|
545
|
+
const questionMetadata = buildQuestionEventMetadata({
|
|
546
|
+
initiativeId: input.initiativeId,
|
|
547
|
+
workstreamId: input.workstreamId,
|
|
548
|
+
sourceRunId: input.sourceRunId,
|
|
549
|
+
sourceClient: input.sourceClient,
|
|
550
|
+
decisionIds,
|
|
551
|
+
blocking: input.blocking,
|
|
552
|
+
title: input.title,
|
|
553
|
+
summary: input.summary,
|
|
554
|
+
decisionType: input.decisionType,
|
|
555
|
+
options: input.options,
|
|
556
|
+
recommendedAction: input.recommendedAction,
|
|
557
|
+
evidenceRefs: input.evidenceRefs,
|
|
558
|
+
scopeHierarchy: input.scopeHierarchy,
|
|
559
|
+
initiativeTitle: input.initiativeTitle,
|
|
560
|
+
workstreamTitle: input.workstreamTitle,
|
|
561
|
+
taskTitle: input.taskTitle,
|
|
562
|
+
nextActions: input.nextActions,
|
|
563
|
+
currentRunState: input.currentRunState,
|
|
564
|
+
impactIfDelayed: input.impactIfDelayed,
|
|
565
|
+
reason: input.reason,
|
|
566
|
+
});
|
|
377
567
|
await emitActivitySafe({
|
|
378
568
|
initiativeId: input.initiativeId,
|
|
379
569
|
runId: input.sourceRunId,
|
|
@@ -391,13 +581,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
391
581
|
event: "question_asked",
|
|
392
582
|
action_type: normalizeActivityActionType("question_asked"),
|
|
393
583
|
action_phase: normalizeActivityActionPhase("review"),
|
|
394
|
-
|
|
395
|
-
workstream_id: input.workstreamId,
|
|
396
|
-
source_run_id: input.sourceRunId,
|
|
397
|
-
source_client: input.sourceClient,
|
|
398
|
-
decision_ids: decisionIds,
|
|
399
|
-
decision_count: decisionIds.length,
|
|
400
|
-
blocking: input.blocking,
|
|
584
|
+
...questionMetadata,
|
|
401
585
|
question_policy_mode: policy.mode,
|
|
402
586
|
question_policy_version: policy.policyVersion,
|
|
403
587
|
timeout_seconds_applied: policy.timeoutSeconds,
|
|
@@ -423,12 +607,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
423
607
|
event: "review_item_created",
|
|
424
608
|
action_type: normalizeActivityActionType("review_item_created"),
|
|
425
609
|
action_phase: normalizeActivityActionPhase("blocked"),
|
|
426
|
-
|
|
427
|
-
workstream_id: input.workstreamId,
|
|
428
|
-
source_run_id: input.sourceRunId,
|
|
429
|
-
source_client: input.sourceClient,
|
|
430
|
-
decision_ids: decisionIds,
|
|
431
|
-
decision_count: decisionIds.length,
|
|
610
|
+
...questionMetadata,
|
|
432
611
|
blocking: true,
|
|
433
612
|
reason: "blocking_question_requires_human",
|
|
434
613
|
question_policy_mode: policy.mode,
|
|
@@ -452,11 +631,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
452
631
|
event: "review_item_created",
|
|
453
632
|
action_type: normalizeActivityActionType("review_item_created"),
|
|
454
633
|
action_phase: normalizeActivityActionPhase("review"),
|
|
455
|
-
|
|
456
|
-
workstream_id: input.workstreamId,
|
|
457
|
-
source_run_id: input.sourceRunId,
|
|
458
|
-
source_client: input.sourceClient,
|
|
459
|
-
decision_ids: decisionIds,
|
|
634
|
+
...questionMetadata,
|
|
460
635
|
reason: "policy_disabled",
|
|
461
636
|
question_policy_mode: policy.mode,
|
|
462
637
|
question_policy_version: policy.policyVersion,
|
|
@@ -476,6 +651,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
476
651
|
existing.policyVersion = policy.policyVersion;
|
|
477
652
|
existing.timeoutSeconds = policy.timeoutSeconds;
|
|
478
653
|
existing.dueAt = new Date(dueAtEpoch).toISOString();
|
|
654
|
+
existing.eventMetadata = questionMetadata;
|
|
479
655
|
armQuestionAutoAnswerTimer(key, existing, policy.timeoutSeconds);
|
|
480
656
|
await emitActivitySafe({
|
|
481
657
|
initiativeId: input.initiativeId,
|
|
@@ -490,10 +666,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
490
666
|
event: "question_timeout_started",
|
|
491
667
|
action_type: normalizeActivityActionType("question_timeout_started"),
|
|
492
668
|
action_phase: normalizeActivityActionPhase("review"),
|
|
493
|
-
|
|
494
|
-
workstream_id: input.workstreamId,
|
|
495
|
-
source_run_id: input.sourceRunId,
|
|
496
|
-
source_client: input.sourceClient,
|
|
669
|
+
...questionMetadata,
|
|
497
670
|
decision_ids: existing.decisionIds,
|
|
498
671
|
decision_count: existing.decisionIds.length,
|
|
499
672
|
decision_action: existing.action,
|
|
@@ -519,6 +692,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
519
692
|
dueAt: new Date(dueAtEpoch).toISOString(),
|
|
520
693
|
timer: null,
|
|
521
694
|
decisionIds,
|
|
695
|
+
eventMetadata: questionMetadata,
|
|
522
696
|
};
|
|
523
697
|
armQuestionAutoAnswerTimer(key, pending, policy.timeoutSeconds);
|
|
524
698
|
pendingQuestionAutoAnswerByScope.set(key, pending);
|
|
@@ -535,12 +709,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
535
709
|
event: "question_timeout_started",
|
|
536
710
|
action_type: normalizeActivityActionType("question_timeout_started"),
|
|
537
711
|
action_phase: normalizeActivityActionPhase("review"),
|
|
538
|
-
|
|
539
|
-
workstream_id: input.workstreamId,
|
|
540
|
-
source_run_id: input.sourceRunId,
|
|
541
|
-
source_client: input.sourceClient,
|
|
542
|
-
decision_ids: decisionIds,
|
|
543
|
-
decision_count: decisionIds.length,
|
|
712
|
+
...questionMetadata,
|
|
544
713
|
decision_action: policy.action,
|
|
545
714
|
timeout_seconds_applied: policy.timeoutSeconds,
|
|
546
715
|
question_policy_mode: policy.mode,
|
|
@@ -692,6 +861,34 @@ export function createAutoContinueEngine(deps) {
|
|
|
692
861
|
inferredStreamId ??
|
|
693
862
|
linkedSlice?.workstreamId ??
|
|
694
863
|
null);
|
|
864
|
+
const initiativeTitle = pickMetadataString(metadataBase, ["initiative_title", "initiativeTitle"]) ??
|
|
865
|
+
pickMetadataString(sourceRefBase, ["initiative_title", "initiativeTitle"]) ??
|
|
866
|
+
null;
|
|
867
|
+
const workstreamTitle = pickMetadataString(metadataBase, ["workstream_title", "workstreamTitle"]) ??
|
|
868
|
+
pickMetadataString(sourceRefBase, ["workstream_title", "workstreamTitle"]) ??
|
|
869
|
+
linkedSlice?.workstreamTitle ??
|
|
870
|
+
null;
|
|
871
|
+
const taskTitle = pickMetadataString(metadataBase, ["task_title", "taskTitle", "dispatch_task_title"]) ??
|
|
872
|
+
null;
|
|
873
|
+
const recommendedAction = typeof normalizedInput.recommendedAction === "string" && normalizedInput.recommendedAction.trim().length > 0
|
|
874
|
+
? normalizedInput.recommendedAction.trim()
|
|
875
|
+
: pickMetadataString(metadataBase, ["recommended_action", "recommendedAction"]);
|
|
876
|
+
const decisionOptions = normalizeQueuedDecisionOptions(normalizedInput.options ?? [], recommendedAction);
|
|
877
|
+
const decisionEvidenceRefs = normalizeQueuedDecisionEvidence(normalizedInput.evidenceRefs ?? []);
|
|
878
|
+
const scopeHierarchy = [
|
|
879
|
+
...pickMetadataStringArray(metadataBase, ["scope_hierarchy", "scopeHierarchy"]),
|
|
880
|
+
...pickMetadataStringArray(sourceRefBase, ["scope_hierarchy", "scopeHierarchy"]),
|
|
881
|
+
...[initiativeTitle, workstreamTitle, taskTitle].filter((entry) => typeof entry === "string" && entry.trim().length > 0),
|
|
882
|
+
].filter((entry, index, source) => source.indexOf(entry) === index);
|
|
883
|
+
const nextActions = [
|
|
884
|
+
...pickMetadataStringArray(metadataBase, ["next_actions", "nextActions"]),
|
|
885
|
+
...(recommendedAction ? [recommendedAction] : []),
|
|
886
|
+
].filter((entry, index, source) => source.indexOf(entry) === index);
|
|
887
|
+
const currentRunState = pickMetadataString(metadataBase, ["current_run_state", "currentRunState", "runtime_state", "runtimeState", "parsed_status", "parsedStatus"]) ??
|
|
888
|
+
linkedSlice?.status ??
|
|
889
|
+
null;
|
|
890
|
+
const impactIfDelayed = pickMetadataString(metadataBase, ["impact_if_delayed", "impactIfDelayed"]) ??
|
|
891
|
+
null;
|
|
695
892
|
const result = await requestDecisionSafe(normalizedInput);
|
|
696
893
|
if (typeof result === "boolean") {
|
|
697
894
|
return { queued: result, decisionIds: [] };
|
|
@@ -719,6 +916,23 @@ export function createAutoContinueEngine(deps) {
|
|
|
719
916
|
sourceClient,
|
|
720
917
|
decisionIds,
|
|
721
918
|
blocking: Boolean(normalizedInput.blocking),
|
|
919
|
+
title: normalizedInput.title,
|
|
920
|
+
summary: typeof normalizedInput.summary === "string" && normalizedInput.summary.trim().length > 0
|
|
921
|
+
? normalizedInput.summary.trim()
|
|
922
|
+
: null,
|
|
923
|
+
decisionType: typeof normalizedInput.decisionType === "string" && normalizedInput.decisionType.trim().length > 0
|
|
924
|
+
? normalizedInput.decisionType.trim()
|
|
925
|
+
: null,
|
|
926
|
+
options: decisionOptions,
|
|
927
|
+
recommendedAction,
|
|
928
|
+
evidenceRefs: decisionEvidenceRefs,
|
|
929
|
+
scopeHierarchy,
|
|
930
|
+
initiativeTitle,
|
|
931
|
+
workstreamTitle,
|
|
932
|
+
taskTitle,
|
|
933
|
+
nextActions,
|
|
934
|
+
currentRunState,
|
|
935
|
+
impactIfDelayed,
|
|
722
936
|
reason: typeof normalizedInput.conflictSource === "string"
|
|
723
937
|
? normalizedInput.conflictSource
|
|
724
938
|
: null,
|
|
@@ -731,6 +945,35 @@ export function createAutoContinueEngine(deps) {
|
|
|
731
945
|
}
|
|
732
946
|
return { queued: false, decisionIds: [] };
|
|
733
947
|
};
|
|
948
|
+
const defaultInterventionDecisionOptions = () => [
|
|
949
|
+
{
|
|
950
|
+
id: "retry_slice",
|
|
951
|
+
label: "Retry this workstream slice",
|
|
952
|
+
description: "Retry once with the latest context and logs.",
|
|
953
|
+
consequences: "Autopilot retries this workstream slice immediately.",
|
|
954
|
+
implied_status: "approved",
|
|
955
|
+
action_type: "retry",
|
|
956
|
+
requires_note: false,
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
id: "pause_and_investigate",
|
|
960
|
+
label: "Pause autopilot and investigate",
|
|
961
|
+
description: "Pause orchestration and capture operator notes for handoff.",
|
|
962
|
+
consequences: "Autopilot pauses and waits for new operator guidance.",
|
|
963
|
+
implied_status: "declined",
|
|
964
|
+
action_type: "pause",
|
|
965
|
+
requires_note: true,
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
id: "skip_for_now",
|
|
969
|
+
label: "Skip this workstream for now",
|
|
970
|
+
description: "Defer this lane and keep other workstreams moving.",
|
|
971
|
+
consequences: "This lane is deferred while the rest of the queue continues.",
|
|
972
|
+
implied_status: "declined",
|
|
973
|
+
action_type: "defer",
|
|
974
|
+
requires_note: true,
|
|
975
|
+
},
|
|
976
|
+
];
|
|
734
977
|
const __filename = deps.filename;
|
|
735
978
|
const autoContinueRuns = new Map();
|
|
736
979
|
/**
|
|
@@ -780,6 +1023,9 @@ export function createAutoContinueEngine(deps) {
|
|
|
780
1023
|
const now = new Date().toISOString();
|
|
781
1024
|
const run = {
|
|
782
1025
|
initiativeId,
|
|
1026
|
+
workspaceId: typeof meta.workspace_id === "string" && meta.workspace_id.trim().length > 0
|
|
1027
|
+
? meta.workspace_id.trim()
|
|
1028
|
+
: null,
|
|
783
1029
|
agentId: "",
|
|
784
1030
|
agentName: null,
|
|
785
1031
|
includeVerification: Boolean(meta.auto_continue_include_verification),
|
|
@@ -817,6 +1063,10 @@ export function createAutoContinueEngine(deps) {
|
|
|
817
1063
|
activeTaskTokenEstimate: typeof meta.auto_continue_active_task_token_estimate === "number"
|
|
818
1064
|
? meta.auto_continue_active_task_token_estimate
|
|
819
1065
|
: null,
|
|
1066
|
+
workerEnvOverrides: null,
|
|
1067
|
+
lastInitiativeStatus: typeof meta.status === "string" && meta.status.trim().length > 0
|
|
1068
|
+
? meta.status.trim()
|
|
1069
|
+
: null,
|
|
820
1070
|
};
|
|
821
1071
|
ensureRunInternals(run);
|
|
822
1072
|
syncLegacyRunPointers(run);
|
|
@@ -1024,6 +1274,38 @@ export function createAutoContinueEngine(deps) {
|
|
|
1024
1274
|
autoContinueSliceChildren.delete(id);
|
|
1025
1275
|
autoContinueSliceLastHeartbeatMs.delete(id);
|
|
1026
1276
|
};
|
|
1277
|
+
const stopActiveSliceProcesses = async (sliceRunIds) => {
|
|
1278
|
+
for (const rawRunId of sliceRunIds) {
|
|
1279
|
+
const sliceRunId = rawRunId.trim();
|
|
1280
|
+
if (!sliceRunId)
|
|
1281
|
+
continue;
|
|
1282
|
+
const child = autoContinueSliceChildren.get(sliceRunId) ?? null;
|
|
1283
|
+
try {
|
|
1284
|
+
if (child && child.exitCode === null && !child.killed) {
|
|
1285
|
+
child.kill("SIGTERM");
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
catch {
|
|
1289
|
+
// best effort
|
|
1290
|
+
}
|
|
1291
|
+
const slice = autoContinueSliceRuns.get(sliceRunId) ?? null;
|
|
1292
|
+
const pid = slice?.pid ?? child?.pid ?? null;
|
|
1293
|
+
if (pid && pidAlive(pid)) {
|
|
1294
|
+
try {
|
|
1295
|
+
await stopProcess(pid);
|
|
1296
|
+
}
|
|
1297
|
+
catch {
|
|
1298
|
+
// best effort
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
if (slice) {
|
|
1302
|
+
slice.pid = null;
|
|
1303
|
+
slice.updatedAt = new Date().toISOString();
|
|
1304
|
+
autoContinueSliceRuns.set(sliceRunId, slice);
|
|
1305
|
+
}
|
|
1306
|
+
clearAutoContinueSliceTransientState(sliceRunId);
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1027
1309
|
const AUTO_CONTINUE_SLICE_TIMEOUT_MS = readBudgetEnvNumber("ORGX_AUTOPILOT_SLICE_TIMEOUT_MS", 55 * 60_000,
|
|
1028
1310
|
// Keep test runs fast; real-world defaults are still ~1h unless overridden.
|
|
1029
1311
|
{ min: 250, max: 6 * 60 * 60_000 });
|
|
@@ -1211,6 +1493,57 @@ export function createAutoContinueEngine(deps) {
|
|
|
1211
1493
|
run.maxParallelSlices = normalizeMaxParallelSlices(run.maxParallelSlices, AUTO_CONTINUE_MAX_PARALLEL_DEFAULT);
|
|
1212
1494
|
run.parallelMode = normalizeParallelMode(run.parallelMode);
|
|
1213
1495
|
run.tokenBudget = normalizeTokenBudget(run.tokenBudget, defaultAutoContinueTokenBudget());
|
|
1496
|
+
if (!run.workerEnvOverrides || typeof run.workerEnvOverrides !== "object") {
|
|
1497
|
+
run.workerEnvOverrides = null;
|
|
1498
|
+
}
|
|
1499
|
+
run.workspaceId =
|
|
1500
|
+
typeof run.workspaceId === "string" && run.workspaceId.trim().length > 0
|
|
1501
|
+
? run.workspaceId.trim()
|
|
1502
|
+
: null;
|
|
1503
|
+
run.lastInitiativeStatus =
|
|
1504
|
+
typeof run.lastInitiativeStatus === "string" && run.lastInitiativeStatus.trim().length > 0
|
|
1505
|
+
? run.lastInitiativeStatus.trim()
|
|
1506
|
+
: null;
|
|
1507
|
+
};
|
|
1508
|
+
const laneStateToChildStatus = (laneState) => {
|
|
1509
|
+
if (laneState === LaneState.RUNNING)
|
|
1510
|
+
return "in_progress";
|
|
1511
|
+
if (laneState === LaneState.BLOCKED)
|
|
1512
|
+
return "blocked";
|
|
1513
|
+
if (laneState === LaneState.WAITING_DEPENDENCY || laneState === LaneState.RATE_LIMITED) {
|
|
1514
|
+
return "paused";
|
|
1515
|
+
}
|
|
1516
|
+
if (laneState === LaneState.COMPLETED)
|
|
1517
|
+
return "completed";
|
|
1518
|
+
return "todo";
|
|
1519
|
+
};
|
|
1520
|
+
const deriveInitiativeStatusFromRun = (run) => {
|
|
1521
|
+
ensureRunInternals(run);
|
|
1522
|
+
const childStatuses = Object.values(run.laneByWorkstreamId ?? {}).map((lane) => laneStateToChildStatus(lane.state));
|
|
1523
|
+
if (run.status === RunStatus.RUNNING || run.status === RunStatus.STOPPING) {
|
|
1524
|
+
return deriveInitiativeLifecycleStatus("active", childStatuses.length > 0 ? childStatuses : ["in_progress"]);
|
|
1525
|
+
}
|
|
1526
|
+
if (run.stopReason === "blocked" || run.stopReason === "error") {
|
|
1527
|
+
return "blocked";
|
|
1528
|
+
}
|
|
1529
|
+
if (run.stopReason === "completed") {
|
|
1530
|
+
const scopedRun = run.stopAfterSlice ||
|
|
1531
|
+
(Array.isArray(run.allowedWorkstreamIds) && run.allowedWorkstreamIds.length > 0);
|
|
1532
|
+
return scopedRun ? "paused" : "completed";
|
|
1533
|
+
}
|
|
1534
|
+
if (run.stopReason === "budget_exhausted" || run.stopReason === "stopped") {
|
|
1535
|
+
return "paused";
|
|
1536
|
+
}
|
|
1537
|
+
return childStatuses.length > 0
|
|
1538
|
+
? deriveInitiativeLifecycleStatus("paused", childStatuses)
|
|
1539
|
+
: "paused";
|
|
1540
|
+
};
|
|
1541
|
+
const syncInitiativeLifecycleStatus = async (run) => {
|
|
1542
|
+
const nextStatus = deriveInitiativeStatusFromRun(run);
|
|
1543
|
+
if (run.lastInitiativeStatus === nextStatus)
|
|
1544
|
+
return;
|
|
1545
|
+
await client.updateEntity("initiative", run.initiativeId, { status: nextStatus });
|
|
1546
|
+
run.lastInitiativeStatus = nextStatus;
|
|
1214
1547
|
};
|
|
1215
1548
|
const recordLocalStatusOverrides = (input) => {
|
|
1216
1549
|
const initiativeId = input.initiativeId.trim();
|
|
@@ -1485,6 +1818,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1485
1818
|
updated_at: lane.updatedAt,
|
|
1486
1819
|
}));
|
|
1487
1820
|
const patch = {
|
|
1821
|
+
...(input.run.workspaceId ? { workspace_id: input.run.workspaceId } : {}),
|
|
1488
1822
|
auto_continue_enabled: input.run.status === RunStatus.RUNNING || input.run.status === RunStatus.STOPPING,
|
|
1489
1823
|
auto_continue_status: input.run.status,
|
|
1490
1824
|
auto_continue_stop_reason: input.run.stopReason,
|
|
@@ -1510,6 +1844,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1510
1844
|
...(input.run.lastError ? { auto_continue_last_error: input.run.lastError } : {}),
|
|
1511
1845
|
};
|
|
1512
1846
|
await updateInitiativeMetadata(input.initiativeId, patch);
|
|
1847
|
+
await syncInitiativeLifecycleStatus(input.run);
|
|
1513
1848
|
}
|
|
1514
1849
|
async function stopAutoContinueRun(input) {
|
|
1515
1850
|
const decisionRequired = input.reason === "blocked" && input.decisionRequired === true;
|
|
@@ -1524,6 +1859,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1524
1859
|
const now = new Date().toISOString();
|
|
1525
1860
|
ensureRunInternals(input.run);
|
|
1526
1861
|
const activeRunIds = listActiveSliceRunIds(input.run);
|
|
1862
|
+
await stopActiveSliceProcesses(activeRunIds);
|
|
1527
1863
|
input.run.status = RunStatus.STOPPED;
|
|
1528
1864
|
input.run.stopReason = input.reason;
|
|
1529
1865
|
input.run.stoppedAt = now;
|
|
@@ -1553,18 +1889,6 @@ export function createAutoContinueEngine(deps) {
|
|
|
1553
1889
|
for (const runId of activeRunIds) {
|
|
1554
1890
|
clearAutoContinueSliceTransientState(runId);
|
|
1555
1891
|
}
|
|
1556
|
-
// Only pause the initiative on non-terminal stops (error, blocked, user-requested).
|
|
1557
|
-
// Completed / budget-exhausted runs should not override the initiative status.
|
|
1558
|
-
if (input.reason !== "completed" && input.reason !== "budget_exhausted") {
|
|
1559
|
-
try {
|
|
1560
|
-
await client.updateEntity("initiative", input.run.initiativeId, {
|
|
1561
|
-
status: "paused",
|
|
1562
|
-
});
|
|
1563
|
-
}
|
|
1564
|
-
catch {
|
|
1565
|
-
// best effort
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
1892
|
try {
|
|
1569
1893
|
await updateInitiativeAutoContinueState({
|
|
1570
1894
|
initiativeId: input.run.initiativeId,
|
|
@@ -1685,7 +2009,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1685
2009
|
old_state: LaneState.RUNNING,
|
|
1686
2010
|
new_state: input.reason === "completed" || input.reason === "stopped" ? "idle" : input.reason === "blocked" ? "blocked" : input.reason === "error" ? "error" : "idle",
|
|
1687
2011
|
reason: input.reason,
|
|
1688
|
-
workspace_id: input.run.
|
|
2012
|
+
workspace_id: input.run.workspaceId ?? null,
|
|
1689
2013
|
},
|
|
1690
2014
|
});
|
|
1691
2015
|
}
|
|
@@ -1843,11 +2167,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1843
2167
|
title: `Agent couldn't connect to tools: ${slice.workstreamTitle ?? slice.workstreamId}`,
|
|
1844
2168
|
summary: humanizeSliceFailureSummary(`MCP handshake failed${mcpHandshake.server ? ` for ${mcpHandshake.server}` : ""}.`),
|
|
1845
2169
|
urgency: "high",
|
|
1846
|
-
options:
|
|
1847
|
-
"Retry this workstream slice",
|
|
1848
|
-
"Pause autopilot and investigate",
|
|
1849
|
-
"Skip this workstream for now",
|
|
1850
|
-
],
|
|
2170
|
+
options: defaultInterventionDecisionOptions(),
|
|
1851
2171
|
blocking: true,
|
|
1852
2172
|
decisionType: "autopilot_failure",
|
|
1853
2173
|
workstreamId: slice.workstreamId,
|
|
@@ -1965,11 +2285,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1965
2285
|
title: stallDecisionTitle,
|
|
1966
2286
|
summary: humanizeSliceFailureSummary(slice.lastError ?? `Autopilot slice ${humanLabel}`),
|
|
1967
2287
|
urgency: "high",
|
|
1968
|
-
options:
|
|
1969
|
-
"Retry this workstream slice",
|
|
1970
|
-
"Pause autopilot and investigate",
|
|
1971
|
-
"Skip this workstream for now",
|
|
1972
|
-
],
|
|
2288
|
+
options: defaultInterventionDecisionOptions(),
|
|
1973
2289
|
blocking: true,
|
|
1974
2290
|
decisionType: "autopilot_failure",
|
|
1975
2291
|
workstreamId: slice.workstreamId,
|
|
@@ -2067,6 +2383,68 @@ export function createAutoContinueEngine(deps) {
|
|
|
2067
2383
|
}
|
|
2068
2384
|
}
|
|
2069
2385
|
const defaultDecisionBlocking = parsedStatus === "completed" ? false : true;
|
|
2386
|
+
const normalizeDecisionOptions = (value) => {
|
|
2387
|
+
if (!Array.isArray(value))
|
|
2388
|
+
return [];
|
|
2389
|
+
const normalized = [];
|
|
2390
|
+
for (const rawOption of value) {
|
|
2391
|
+
if (typeof rawOption === "string") {
|
|
2392
|
+
const label = rawOption.trim();
|
|
2393
|
+
if (label.length > 0)
|
|
2394
|
+
normalized.push(label);
|
|
2395
|
+
continue;
|
|
2396
|
+
}
|
|
2397
|
+
if (!rawOption || typeof rawOption !== "object" || Array.isArray(rawOption)) {
|
|
2398
|
+
continue;
|
|
2399
|
+
}
|
|
2400
|
+
const optionRecord = rawOption;
|
|
2401
|
+
const label = (typeof optionRecord.label === "string" && optionRecord.label.trim()) ||
|
|
2402
|
+
(typeof optionRecord.title === "string" && optionRecord.title.trim()) ||
|
|
2403
|
+
(typeof optionRecord.name === "string" && optionRecord.name.trim()) ||
|
|
2404
|
+
null;
|
|
2405
|
+
if (!label)
|
|
2406
|
+
continue;
|
|
2407
|
+
const normalizedRecord = { label };
|
|
2408
|
+
const id = (typeof optionRecord.id === "string" && optionRecord.id.trim()) ||
|
|
2409
|
+
(typeof optionRecord.option_id === "string" && optionRecord.option_id.trim()) ||
|
|
2410
|
+
null;
|
|
2411
|
+
if (id)
|
|
2412
|
+
normalizedRecord.id = id;
|
|
2413
|
+
const description = (typeof optionRecord.description === "string" && optionRecord.description.trim()) ||
|
|
2414
|
+
null;
|
|
2415
|
+
if (description)
|
|
2416
|
+
normalizedRecord.description = description;
|
|
2417
|
+
const consequences = (typeof optionRecord.consequences === "string" && optionRecord.consequences.trim()) ||
|
|
2418
|
+
(typeof optionRecord.impact === "string" && optionRecord.impact.trim()) ||
|
|
2419
|
+
null;
|
|
2420
|
+
if (consequences)
|
|
2421
|
+
normalizedRecord.consequences = consequences;
|
|
2422
|
+
const impliedStatusRaw = typeof optionRecord.implied_status === "string"
|
|
2423
|
+
? optionRecord.implied_status
|
|
2424
|
+
: typeof optionRecord.status === "string"
|
|
2425
|
+
? optionRecord.status
|
|
2426
|
+
: null;
|
|
2427
|
+
if (impliedStatusRaw) {
|
|
2428
|
+
const implied = impliedStatusRaw.trim().toLowerCase();
|
|
2429
|
+
if (implied === "approved" ||
|
|
2430
|
+
implied === "declined" ||
|
|
2431
|
+
implied === "cancelled" ||
|
|
2432
|
+
implied === "rejected") {
|
|
2433
|
+
normalizedRecord.implied_status = implied;
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
const actionType = normalizeDecisionActionType(optionRecord.action_type ?? optionRecord.type ?? optionRecord.verb ?? optionRecord.action);
|
|
2437
|
+
if (actionType)
|
|
2438
|
+
normalizedRecord.action_type = actionType;
|
|
2439
|
+
if (optionRecord.requires_note === true ||
|
|
2440
|
+
optionRecord.requiresNote === true ||
|
|
2441
|
+
optionRecord.note_required === true) {
|
|
2442
|
+
normalizedRecord.requires_note = true;
|
|
2443
|
+
}
|
|
2444
|
+
normalized.push(normalizedRecord);
|
|
2445
|
+
}
|
|
2446
|
+
return normalized.slice(0, 8);
|
|
2447
|
+
};
|
|
2070
2448
|
const allDecisions = Array.isArray(parsed?.decisions_needed)
|
|
2071
2449
|
? (parsed?.decisions_needed ?? [])
|
|
2072
2450
|
.filter((item) => Boolean(item && typeof item.question === "string" && item.question.trim()))
|
|
@@ -2210,9 +2588,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
2210
2588
|
title: normalizedQuestion,
|
|
2211
2589
|
summary: decision.summary ?? parsed?.summary ?? null,
|
|
2212
2590
|
urgency: decision.urgency ?? "high",
|
|
2213
|
-
options:
|
|
2214
|
-
? decision.options.filter((opt) => typeof opt === "string" && opt.trim())
|
|
2215
|
-
: [],
|
|
2591
|
+
options: normalizeDecisionOptions(decision.options),
|
|
2216
2592
|
blocking: isBlocking,
|
|
2217
2593
|
decisionType: isBlocking
|
|
2218
2594
|
? "autopilot_blocking_decision"
|
|
@@ -2606,11 +2982,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
2606
2982
|
title: fallbackDecisionTitle,
|
|
2607
2983
|
summary: fallbackDecisionSummary,
|
|
2608
2984
|
urgency: "high",
|
|
2609
|
-
options:
|
|
2610
|
-
"Retry this workstream slice",
|
|
2611
|
-
"Pause autopilot and investigate",
|
|
2612
|
-
"Skip this workstream for now",
|
|
2613
|
-
],
|
|
2985
|
+
options: defaultInterventionDecisionOptions(),
|
|
2614
2986
|
blocking: true,
|
|
2615
2987
|
decisionType: looksLikeNoOutcome
|
|
2616
2988
|
? "autopilot_completed_without_outcome"
|
|
@@ -2692,11 +3064,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
2692
3064
|
title: attentionTitle,
|
|
2693
3065
|
summary: attentionSummary,
|
|
2694
3066
|
urgency: "high",
|
|
2695
|
-
options:
|
|
2696
|
-
"Retry this workstream slice",
|
|
2697
|
-
"Pause autopilot and investigate",
|
|
2698
|
-
"Skip this workstream for now",
|
|
2699
|
-
],
|
|
3067
|
+
options: defaultInterventionDecisionOptions(),
|
|
2700
3068
|
blocking: true,
|
|
2701
3069
|
decisionType: completionHadNoOutcome
|
|
2702
3070
|
? "autopilot_completed_without_outcome"
|
|
@@ -3704,16 +4072,27 @@ export function createAutoContinueEngine(deps) {
|
|
|
3704
4072
|
const logsDir = join(getOrgxPluginConfigDir(), AUTO_CONTINUE_SLICE_LOG_DIRNAME);
|
|
3705
4073
|
const logPath = join(logsDir, `${sliceRunId}.log`);
|
|
3706
4074
|
const outputPath = join(logsDir, `${sliceRunId}.output.json`);
|
|
3707
|
-
const
|
|
4075
|
+
const workerEnvOverrides = run.workerEnvOverrides ?? defaultWorkerEnvOverrides;
|
|
4076
|
+
const configuredWorkerCwd = (workerEnvOverrides?.ORGX_AUTOPILOT_CWD ??
|
|
4077
|
+
process.env.ORGX_AUTOPILOT_CWD ??
|
|
4078
|
+
"").trim();
|
|
3708
4079
|
let workerCwd = configuredWorkerCwd || resolveAutopilotDefaultCwd(__filename);
|
|
3709
4080
|
// LaunchAgents sometimes start with cwd="/". Fall back to plugin root (or home if unresolved).
|
|
3710
4081
|
if (!workerCwd || workerCwd === "/") {
|
|
3711
4082
|
workerCwd = resolveAutopilotDefaultCwd(__filename);
|
|
3712
4083
|
}
|
|
3713
4084
|
const sliceAgent = resolveOrgxAgentForDomain(executionPolicy.domain);
|
|
3714
|
-
const workerKind = (
|
|
4085
|
+
const workerKind = (workerEnvOverrides?.ORGX_AUTOPILOT_WORKER_KIND ??
|
|
4086
|
+
process.env.ORGX_AUTOPILOT_WORKER_KIND ??
|
|
4087
|
+
"")
|
|
4088
|
+
.trim()
|
|
4089
|
+
.toLowerCase();
|
|
3715
4090
|
const inferredExecutor = workerKind === "claude-code" || workerKind === "claude_code" ? "claude-code" : "codex";
|
|
3716
|
-
const executorRaw = (
|
|
4091
|
+
const executorRaw = (workerEnvOverrides?.ORGX_AUTOPILOT_EXECUTOR ??
|
|
4092
|
+
process.env.ORGX_AUTOPILOT_EXECUTOR ??
|
|
4093
|
+
"")
|
|
4094
|
+
.trim()
|
|
4095
|
+
.toLowerCase() || inferredExecutor;
|
|
3717
4096
|
const executorSourceClient = executorRaw === "claude-code" || executorRaw === "claude_code" ? "claude-code" : "codex";
|
|
3718
4097
|
let runtimeHookUrl = null;
|
|
3719
4098
|
let runtimeHookToken = null;
|
|
@@ -3738,6 +4117,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
3738
4117
|
outputSchemaPath: schemaPath,
|
|
3739
4118
|
resumeSessionId: resumedFromSessionId,
|
|
3740
4119
|
env: {
|
|
4120
|
+
...(workerEnvOverrides ?? {}),
|
|
3741
4121
|
ORGX_SOURCE_CLIENT: executorSourceClient,
|
|
3742
4122
|
ORGX_RUN_ID: sliceRunId,
|
|
3743
4123
|
ORGX_CORRELATION_ID: sliceRunId,
|
|
@@ -3915,12 +4295,6 @@ export function createAutoContinueEngine(deps) {
|
|
|
3915
4295
|
// Clear stale errors when a new slice dispatches successfully.
|
|
3916
4296
|
run.lastError = null;
|
|
3917
4297
|
run.updatedAt = now;
|
|
3918
|
-
try {
|
|
3919
|
-
await client.updateEntity("initiative", run.initiativeId, { status: "active" });
|
|
3920
|
-
}
|
|
3921
|
-
catch {
|
|
3922
|
-
// best effort
|
|
3923
|
-
}
|
|
3924
4298
|
try {
|
|
3925
4299
|
await updateInitiativeAutoContinueState({
|
|
3926
4300
|
initiativeId: run.initiativeId,
|
|
@@ -4013,6 +4387,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4013
4387
|
const sourceEvent = (input.event ?? "").trim() || null;
|
|
4014
4388
|
const requestedByAgentId = (input.requestedByAgentId ?? "").trim() || null;
|
|
4015
4389
|
const requestedByAgentName = (input.requestedByAgentName ?? "").trim() || null;
|
|
4390
|
+
const autoFixWorkerEnv = captureAutopilotWorkerEnv();
|
|
4016
4391
|
const providedGraceMs = typeof input.graceMs === "number" && Number.isFinite(input.graceMs)
|
|
4017
4392
|
? Math.floor(input.graceMs)
|
|
4018
4393
|
: null;
|
|
@@ -4188,6 +4563,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4188
4563
|
null;
|
|
4189
4564
|
const dispatchRun = await startAutoContinueRun({
|
|
4190
4565
|
initiativeId,
|
|
4566
|
+
workspaceId: latestRun?.workspaceId ?? null,
|
|
4191
4567
|
agentId: dispatchAgentId,
|
|
4192
4568
|
agentName: dispatchAgentName,
|
|
4193
4569
|
// Auto-fix retries should follow current defaults unless an operator explicitly
|
|
@@ -4199,6 +4575,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4199
4575
|
parallelMode: latestRun?.parallelMode ?? "iwmt",
|
|
4200
4576
|
stopAfterSlice: true,
|
|
4201
4577
|
ignoreSpawnGuardRateLimit: latestRun?.ignoreSpawnGuardRateLimit ?? false,
|
|
4578
|
+
workerEnvOverrides: autoFixWorkerEnv,
|
|
4202
4579
|
});
|
|
4203
4580
|
await tickAutoContinueRun(dispatchRun);
|
|
4204
4581
|
await emitActivitySafe({
|
|
@@ -4293,11 +4670,15 @@ export function createAutoContinueEngine(deps) {
|
|
|
4293
4670
|
}
|
|
4294
4671
|
async function startAutoContinueRun(input) {
|
|
4295
4672
|
const now = new Date().toISOString();
|
|
4673
|
+
const nextWorkerEnvOverrides = input.workerEnvOverrides && typeof input.workerEnvOverrides === "object"
|
|
4674
|
+
? { ...input.workerEnvOverrides }
|
|
4675
|
+
: { ...defaultWorkerEnvOverrides };
|
|
4296
4676
|
const existing = autoContinueRuns.get(input.initiativeId) ?? null;
|
|
4297
4677
|
const existingIsLive = existing?.status === RunStatus.RUNNING || existing?.status === RunStatus.STOPPING;
|
|
4298
4678
|
const run = existing ??
|
|
4299
4679
|
{
|
|
4300
4680
|
initiativeId: input.initiativeId,
|
|
4681
|
+
workspaceId: null,
|
|
4301
4682
|
agentId: input.agentId,
|
|
4302
4683
|
agentName: input.agentName ?? null,
|
|
4303
4684
|
includeVerification: false,
|
|
@@ -4325,8 +4706,14 @@ export function createAutoContinueEngine(deps) {
|
|
|
4325
4706
|
activeTaskId: null,
|
|
4326
4707
|
activeRunId: null,
|
|
4327
4708
|
activeTaskTokenEstimate: null,
|
|
4709
|
+
workerEnvOverrides: null,
|
|
4710
|
+
lastInitiativeStatus: null,
|
|
4328
4711
|
};
|
|
4329
4712
|
ensureRunInternals(run);
|
|
4713
|
+
run.workspaceId =
|
|
4714
|
+
typeof input.workspaceId === "string" && input.workspaceId.trim().length > 0
|
|
4715
|
+
? input.workspaceId.trim()
|
|
4716
|
+
: run.workspaceId;
|
|
4330
4717
|
run.agentId = input.agentId;
|
|
4331
4718
|
run.agentName =
|
|
4332
4719
|
typeof input.agentName === "string" && input.agentName.trim().length > 0
|
|
@@ -4339,6 +4726,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4339
4726
|
run.stopAfterSlice = Boolean(input.stopAfterSlice);
|
|
4340
4727
|
run.ignoreSpawnGuardRateLimit = Boolean(input.ignoreSpawnGuardRateLimit);
|
|
4341
4728
|
run.scope = input.scope ?? "task";
|
|
4729
|
+
run.workerEnvOverrides = nextWorkerEnvOverrides;
|
|
4342
4730
|
const hasExplicitTokenBudgetInput = input.tokenBudget !== null &&
|
|
4343
4731
|
input.tokenBudget !== undefined &&
|
|
4344
4732
|
!(typeof input.tokenBudget === "string" && input.tokenBudget.trim().length === 0);
|
|
@@ -4375,11 +4763,6 @@ export function createAutoContinueEngine(deps) {
|
|
|
4375
4763
|
}
|
|
4376
4764
|
syncLegacyRunPointers(run);
|
|
4377
4765
|
autoContinueRuns.set(input.initiativeId, run);
|
|
4378
|
-
void client
|
|
4379
|
-
.updateEntity("initiative", input.initiativeId, { status: "active" })
|
|
4380
|
-
.catch(() => {
|
|
4381
|
-
// best effort
|
|
4382
|
-
});
|
|
4383
4766
|
void updateInitiativeAutoContinueState({
|
|
4384
4767
|
initiativeId: input.initiativeId,
|
|
4385
4768
|
run,
|
|
@@ -4438,7 +4821,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4438
4821
|
old_state: LaneState.IDLE,
|
|
4439
4822
|
new_state: LaneState.RUNNING,
|
|
4440
4823
|
reason: "started",
|
|
4441
|
-
workspace_id: run.
|
|
4824
|
+
workspace_id: run.workspaceId ?? null,
|
|
4442
4825
|
},
|
|
4443
4826
|
});
|
|
4444
4827
|
}
|