@useorgx/openclaw-plugin 0.7.18 → 0.7.23
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/9gFmK3Kr.js +1 -0
- package/dashboard/dist/assets/9gFmK3Kr.js.br +0 -0
- package/dashboard/dist/assets/9gFmK3Kr.js.gz +0 -0
- package/dashboard/dist/assets/{DS79hzMu.js → BrMXbzQ-.js} +2 -2
- package/dashboard/dist/assets/BrMXbzQ-.js.br +0 -0
- package/dashboard/dist/assets/BrMXbzQ-.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/C1u2SGin.css +1 -0
- package/dashboard/dist/assets/C1u2SGin.css.br +0 -0
- package/dashboard/dist/assets/C1u2SGin.css.gz +0 -0
- package/dashboard/dist/assets/{467jKHFJ.js → CGJiHCIx.js} +1 -1
- package/dashboard/dist/assets/CGJiHCIx.js.br +0 -0
- package/dashboard/dist/assets/CGJiHCIx.js.gz +0 -0
- package/dashboard/dist/assets/CSd4rSuU.js +212 -0
- package/dashboard/dist/assets/CSd4rSuU.js.br +0 -0
- package/dashboard/dist/assets/CSd4rSuU.js.gz +0 -0
- package/dashboard/dist/assets/{5Ihga-4X.js → CZXS5i_5.js} +1 -1
- package/dashboard/dist/assets/CZXS5i_5.js.br +0 -0
- package/dashboard/dist/assets/CZXS5i_5.js.gz +0 -0
- package/dashboard/dist/assets/{a6qcPiWt.js → CbVWL74-.js} +1 -1
- package/dashboard/dist/assets/CbVWL74-.js.br +0 -0
- package/dashboard/dist/assets/CbVWL74-.js.gz +0 -0
- package/dashboard/dist/assets/{qDJ6rqcs.js → D-FuHfT8.js} +1 -1
- package/dashboard/dist/assets/D-FuHfT8.js.br +0 -0
- package/dashboard/dist/assets/D-FuHfT8.js.gz +0 -0
- package/dashboard/dist/assets/{BcJmNILk.js → D0PN5_vY.js} +1 -1
- package/dashboard/dist/assets/D0PN5_vY.js.br +0 -0
- package/dashboard/dist/assets/D0PN5_vY.js.gz +0 -0
- package/dashboard/dist/assets/DDCPrZRt.js +1 -0
- package/dashboard/dist/assets/DDCPrZRt.js.br +0 -0
- package/dashboard/dist/assets/DDCPrZRt.js.gz +0 -0
- package/dashboard/dist/assets/{B71dt9yu.js → DNQ-iFO2.js} +1 -1
- package/dashboard/dist/assets/DNQ-iFO2.js.br +0 -0
- package/dashboard/dist/assets/DNQ-iFO2.js.gz +0 -0
- package/dashboard/dist/assets/{PVi0vr9a.js → DhPuHPK7.js} +1 -1
- package/dashboard/dist/assets/DhPuHPK7.js.br +0 -0
- package/dashboard/dist/assets/DhPuHPK7.js.gz +0 -0
- package/dashboard/dist/assets/Dhz7qPtn.js +1 -0
- package/dashboard/dist/assets/Dhz7qPtn.js.br +0 -0
- package/dashboard/dist/assets/Dhz7qPtn.js.gz +0 -0
- package/dashboard/dist/assets/LOFrVoPD.js +1 -0
- package/dashboard/dist/assets/LOFrVoPD.js.br +0 -0
- package/dashboard/dist/assets/LOFrVoPD.js.gz +0 -0
- package/dashboard/dist/assets/OlLPtzdz.js +1 -0
- package/dashboard/dist/assets/OlLPtzdz.js.br +0 -0
- package/dashboard/dist/assets/OlLPtzdz.js.gz +0 -0
- package/dashboard/dist/assets/{sdoPH_Z1.js → RN4M9u9W.js} +2 -2
- package/dashboard/dist/assets/RN4M9u9W.js.br +0 -0
- package/dashboard/dist/assets/RN4M9u9W.js.gz +0 -0
- package/dashboard/dist/assets/VCHu272d.js +1 -0
- package/dashboard/dist/assets/VCHu272d.js.br +0 -0
- package/dashboard/dist/assets/VCHu272d.js.gz +0 -0
- package/dashboard/dist/assets/m2smti3F.js +1 -0
- package/dashboard/dist/assets/m2smti3F.js.br +0 -0
- package/dashboard/dist/assets/m2smti3F.js.gz +0 -0
- package/dashboard/dist/assets/{C3_j_W9V.js → nra1yvJX.js} +1 -1
- package/dashboard/dist/assets/nra1yvJX.js.br +0 -0
- package/dashboard/dist/assets/nra1yvJX.js.gz +0 -0
- package/dashboard/dist/assets/qLX6NZ-J.js +1 -0
- package/dashboard/dist/assets/qLX6NZ-J.js.br +0 -0
- package/dashboard/dist/assets/qLX6NZ-J.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/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 +17 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +62 -0
- package/dist/http/helpers/auto-continue-engine.js +329 -53
- 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 +220 -6
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +94 -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/mission-control-actions.js +28 -0
- package/dist/http/routes/mission-control-read.d.ts +18 -0
- package/dist/http/routes/mission-control-read.js +130 -218
- 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 +268 -150
- 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 +179 -0
- package/package.json +6 -1
- package/dashboard/dist/assets/467jKHFJ.js.br +0 -0
- package/dashboard/dist/assets/467jKHFJ.js.gz +0 -0
- package/dashboard/dist/assets/5Ihga-4X.js.br +0 -0
- package/dashboard/dist/assets/5Ihga-4X.js.gz +0 -0
- package/dashboard/dist/assets/B71dt9yu.js.br +0 -0
- package/dashboard/dist/assets/B71dt9yu.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/BEnI6kNR.js +0 -1
- package/dashboard/dist/assets/BEnI6kNR.js.br +0 -0
- package/dashboard/dist/assets/BEnI6kNR.js.gz +0 -0
- package/dashboard/dist/assets/BcJmNILk.js.br +0 -0
- package/dashboard/dist/assets/BcJmNILk.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/C-XuWXGi.js +0 -1
- package/dashboard/dist/assets/C-XuWXGi.js.br +0 -0
- package/dashboard/dist/assets/C-XuWXGi.js.gz +0 -0
- package/dashboard/dist/assets/C3_j_W9V.js.br +0 -0
- package/dashboard/dist/assets/C3_j_W9V.js.gz +0 -0
- package/dashboard/dist/assets/C9-UYhBb.js +0 -1
- package/dashboard/dist/assets/C9-UYhBb.js.br +0 -0
- package/dashboard/dist/assets/C9-UYhBb.js.gz +0 -0
- package/dashboard/dist/assets/C9yV06GS.js +0 -1
- package/dashboard/dist/assets/C9yV06GS.js.br +0 -0
- package/dashboard/dist/assets/C9yV06GS.js.gz +0 -0
- package/dashboard/dist/assets/CReugbyT.js +0 -1
- package/dashboard/dist/assets/CReugbyT.js.br +0 -0
- package/dashboard/dist/assets/CReugbyT.js.gz +0 -0
- package/dashboard/dist/assets/CSDhTbKy.js +0 -1
- package/dashboard/dist/assets/CSDhTbKy.js.br +0 -0
- package/dashboard/dist/assets/CSDhTbKy.js.gz +0 -0
- package/dashboard/dist/assets/CfMS9yIf.js +0 -1
- package/dashboard/dist/assets/CfMS9yIf.js.br +0 -0
- package/dashboard/dist/assets/CfMS9yIf.js.gz +0 -0
- package/dashboard/dist/assets/D2Kqcmv9.js +0 -212
- package/dashboard/dist/assets/D2Kqcmv9.js.br +0 -0
- package/dashboard/dist/assets/D2Kqcmv9.js.gz +0 -0
- package/dashboard/dist/assets/DS79hzMu.js.br +0 -0
- package/dashboard/dist/assets/DS79hzMu.js.gz +0 -0
- package/dashboard/dist/assets/PVi0vr9a.js.br +0 -0
- package/dashboard/dist/assets/PVi0vr9a.js.gz +0 -0
- package/dashboard/dist/assets/RZkbqlJk.css +0 -1
- package/dashboard/dist/assets/RZkbqlJk.css.br +0 -0
- package/dashboard/dist/assets/RZkbqlJk.css.gz +0 -0
- package/dashboard/dist/assets/a6qcPiWt.js.br +0 -0
- package/dashboard/dist/assets/a6qcPiWt.js.gz +0 -0
- package/dashboard/dist/assets/qDJ6rqcs.js.br +0 -0
- package/dashboard/dist/assets/qDJ6rqcs.js.gz +0 -0
- package/dashboard/dist/assets/sdoPH_Z1.js.br +0 -0
- package/dashboard/dist/assets/sdoPH_Z1.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;
|
|
@@ -731,8 +742,139 @@ export function createAutoContinueEngine(deps) {
|
|
|
731
742
|
}
|
|
732
743
|
return { queued: false, decisionIds: [] };
|
|
733
744
|
};
|
|
745
|
+
const defaultInterventionDecisionOptions = () => [
|
|
746
|
+
{
|
|
747
|
+
id: "retry_slice",
|
|
748
|
+
label: "Retry this workstream slice",
|
|
749
|
+
description: "Retry once with the latest context and logs.",
|
|
750
|
+
consequences: "Autopilot retries this workstream slice immediately.",
|
|
751
|
+
implied_status: "approved",
|
|
752
|
+
action_type: "retry",
|
|
753
|
+
requires_note: false,
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
id: "pause_and_investigate",
|
|
757
|
+
label: "Pause autopilot and investigate",
|
|
758
|
+
description: "Pause orchestration and capture operator notes for handoff.",
|
|
759
|
+
consequences: "Autopilot pauses and waits for new operator guidance.",
|
|
760
|
+
implied_status: "declined",
|
|
761
|
+
action_type: "pause",
|
|
762
|
+
requires_note: true,
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
id: "skip_for_now",
|
|
766
|
+
label: "Skip this workstream for now",
|
|
767
|
+
description: "Defer this lane and keep other workstreams moving.",
|
|
768
|
+
consequences: "This lane is deferred while the rest of the queue continues.",
|
|
769
|
+
implied_status: "declined",
|
|
770
|
+
action_type: "defer",
|
|
771
|
+
requires_note: true,
|
|
772
|
+
},
|
|
773
|
+
];
|
|
734
774
|
const __filename = deps.filename;
|
|
735
775
|
const autoContinueRuns = new Map();
|
|
776
|
+
/**
|
|
777
|
+
* Rehydrate an AutoContinueRun from persisted initiative metadata.
|
|
778
|
+
* Called when the in-memory Map is empty (e.g. after server restart) to
|
|
779
|
+
* restore the last-known autopilot state so the dashboard toggle stays
|
|
780
|
+
* accurate.
|
|
781
|
+
*/
|
|
782
|
+
async function restoreAutoContinueRun(initiativeId) {
|
|
783
|
+
// Already in memory — nothing to restore.
|
|
784
|
+
if (autoContinueRuns.has(initiativeId)) {
|
|
785
|
+
return autoContinueRuns.get(initiativeId) ?? null;
|
|
786
|
+
}
|
|
787
|
+
try {
|
|
788
|
+
const entity = await fetchInitiativeEntity(initiativeId);
|
|
789
|
+
if (!entity)
|
|
790
|
+
return null;
|
|
791
|
+
const meta = entity && typeof entity === "object"
|
|
792
|
+
? entity.metadata ?? {}
|
|
793
|
+
: {};
|
|
794
|
+
const enabled = meta.auto_continue_enabled;
|
|
795
|
+
const status = meta.auto_continue_status;
|
|
796
|
+
if (!enabled || !status)
|
|
797
|
+
return null;
|
|
798
|
+
// Reconstruct lane objects from persisted array.
|
|
799
|
+
const rawLanes = Array.isArray(meta.auto_continue_lane_states)
|
|
800
|
+
? meta.auto_continue_lane_states
|
|
801
|
+
: [];
|
|
802
|
+
const laneByWorkstreamId = {};
|
|
803
|
+
for (const raw of rawLanes) {
|
|
804
|
+
const wsId = String(raw.workstream_id ?? "").trim();
|
|
805
|
+
if (!wsId)
|
|
806
|
+
continue;
|
|
807
|
+
laneByWorkstreamId[wsId] = {
|
|
808
|
+
workstreamId: wsId,
|
|
809
|
+
state: raw.state ?? LaneState.IDLE,
|
|
810
|
+
activeRunId: raw.active_run_id ?? null,
|
|
811
|
+
activeTaskIds: Array.isArray(raw.active_task_ids) ? raw.active_task_ids : [],
|
|
812
|
+
blockedReason: raw.blocked_reason ?? null,
|
|
813
|
+
waitingOnWorkstreamIds: Array.isArray(raw.waiting_on_workstream_ids)
|
|
814
|
+
? raw.waiting_on_workstream_ids
|
|
815
|
+
: [],
|
|
816
|
+
retryAt: raw.retry_at ?? null,
|
|
817
|
+
updatedAt: raw.updated_at ?? new Date().toISOString(),
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
const now = new Date().toISOString();
|
|
821
|
+
const run = {
|
|
822
|
+
initiativeId,
|
|
823
|
+
workspaceId: typeof meta.workspace_id === "string" && meta.workspace_id.trim().length > 0
|
|
824
|
+
? meta.workspace_id.trim()
|
|
825
|
+
: null,
|
|
826
|
+
agentId: "",
|
|
827
|
+
agentName: null,
|
|
828
|
+
includeVerification: Boolean(meta.auto_continue_include_verification),
|
|
829
|
+
allowedWorkstreamIds: Array.isArray(meta.auto_continue_workstream_filter)
|
|
830
|
+
? meta.auto_continue_workstream_filter
|
|
831
|
+
: null,
|
|
832
|
+
stopAfterSlice: false,
|
|
833
|
+
ignoreSpawnGuardRateLimit: Boolean(meta.auto_continue_ignore_spawn_guard_rate_limit),
|
|
834
|
+
maxParallelSlices: normalizeMaxParallelSlices(meta.auto_continue_max_parallel, AUTO_CONTINUE_MAX_PARALLEL_DEFAULT),
|
|
835
|
+
parallelMode: normalizeParallelMode(meta.auto_continue_parallel_mode),
|
|
836
|
+
scope: "task",
|
|
837
|
+
tokenBudget: normalizeTokenBudget(meta.auto_continue_token_budget, defaultAutoContinueTokenBudget()),
|
|
838
|
+
tokensUsed: typeof meta.auto_continue_tokens_used === "number" ? meta.auto_continue_tokens_used : 0,
|
|
839
|
+
status: status,
|
|
840
|
+
stopReason: meta.auto_continue_stop_reason ?? null,
|
|
841
|
+
stopRequested: false,
|
|
842
|
+
startedAt: meta.auto_continue_started_at ?? now,
|
|
843
|
+
stoppedAt: meta.auto_continue_stopped_at ?? null,
|
|
844
|
+
updatedAt: meta.auto_continue_updated_at ?? now,
|
|
845
|
+
lastError: meta.auto_continue_last_error ?? null,
|
|
846
|
+
lastTaskId: meta.auto_continue_last_task_id ?? null,
|
|
847
|
+
lastRunId: meta.auto_continue_last_run_id ?? null,
|
|
848
|
+
activeSliceRunIds: Array.isArray(meta.auto_continue_active_run_ids)
|
|
849
|
+
? meta.auto_continue_active_run_ids
|
|
850
|
+
: [],
|
|
851
|
+
activeTaskIds: Array.isArray(meta.auto_continue_active_task_ids)
|
|
852
|
+
? meta.auto_continue_active_task_ids
|
|
853
|
+
: [],
|
|
854
|
+
laneByWorkstreamId,
|
|
855
|
+
blockedWorkstreamIds: Array.isArray(meta.auto_continue_blocked_workstream_ids)
|
|
856
|
+
? meta.auto_continue_blocked_workstream_ids
|
|
857
|
+
: [],
|
|
858
|
+
activeTaskId: meta.auto_continue_active_task_id ?? null,
|
|
859
|
+
activeRunId: meta.auto_continue_active_run_id ?? null,
|
|
860
|
+
activeTaskTokenEstimate: typeof meta.auto_continue_active_task_token_estimate === "number"
|
|
861
|
+
? meta.auto_continue_active_task_token_estimate
|
|
862
|
+
: null,
|
|
863
|
+
workerEnvOverrides: null,
|
|
864
|
+
lastInitiativeStatus: typeof meta.status === "string" && meta.status.trim().length > 0
|
|
865
|
+
? meta.status.trim()
|
|
866
|
+
: null,
|
|
867
|
+
};
|
|
868
|
+
ensureRunInternals(run);
|
|
869
|
+
syncLegacyRunPointers(run);
|
|
870
|
+
// Insert into in-memory map so subsequent lookups are fast.
|
|
871
|
+
autoContinueRuns.set(initiativeId, run);
|
|
872
|
+
return run;
|
|
873
|
+
}
|
|
874
|
+
catch {
|
|
875
|
+
return null;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
736
878
|
const localInitiativeStatusOverrides = new Map();
|
|
737
879
|
const localTaskStatusOverrides = new Map();
|
|
738
880
|
const localMilestoneStatusOverrides = new Map();
|
|
@@ -929,6 +1071,38 @@ export function createAutoContinueEngine(deps) {
|
|
|
929
1071
|
autoContinueSliceChildren.delete(id);
|
|
930
1072
|
autoContinueSliceLastHeartbeatMs.delete(id);
|
|
931
1073
|
};
|
|
1074
|
+
const stopActiveSliceProcesses = async (sliceRunIds) => {
|
|
1075
|
+
for (const rawRunId of sliceRunIds) {
|
|
1076
|
+
const sliceRunId = rawRunId.trim();
|
|
1077
|
+
if (!sliceRunId)
|
|
1078
|
+
continue;
|
|
1079
|
+
const child = autoContinueSliceChildren.get(sliceRunId) ?? null;
|
|
1080
|
+
try {
|
|
1081
|
+
if (child && child.exitCode === null && !child.killed) {
|
|
1082
|
+
child.kill("SIGTERM");
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
catch {
|
|
1086
|
+
// best effort
|
|
1087
|
+
}
|
|
1088
|
+
const slice = autoContinueSliceRuns.get(sliceRunId) ?? null;
|
|
1089
|
+
const pid = slice?.pid ?? child?.pid ?? null;
|
|
1090
|
+
if (pid && pidAlive(pid)) {
|
|
1091
|
+
try {
|
|
1092
|
+
await stopProcess(pid);
|
|
1093
|
+
}
|
|
1094
|
+
catch {
|
|
1095
|
+
// best effort
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
if (slice) {
|
|
1099
|
+
slice.pid = null;
|
|
1100
|
+
slice.updatedAt = new Date().toISOString();
|
|
1101
|
+
autoContinueSliceRuns.set(sliceRunId, slice);
|
|
1102
|
+
}
|
|
1103
|
+
clearAutoContinueSliceTransientState(sliceRunId);
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
932
1106
|
const AUTO_CONTINUE_SLICE_TIMEOUT_MS = readBudgetEnvNumber("ORGX_AUTOPILOT_SLICE_TIMEOUT_MS", 55 * 60_000,
|
|
933
1107
|
// Keep test runs fast; real-world defaults are still ~1h unless overridden.
|
|
934
1108
|
{ min: 250, max: 6 * 60 * 60_000 });
|
|
@@ -1116,6 +1290,57 @@ export function createAutoContinueEngine(deps) {
|
|
|
1116
1290
|
run.maxParallelSlices = normalizeMaxParallelSlices(run.maxParallelSlices, AUTO_CONTINUE_MAX_PARALLEL_DEFAULT);
|
|
1117
1291
|
run.parallelMode = normalizeParallelMode(run.parallelMode);
|
|
1118
1292
|
run.tokenBudget = normalizeTokenBudget(run.tokenBudget, defaultAutoContinueTokenBudget());
|
|
1293
|
+
if (!run.workerEnvOverrides || typeof run.workerEnvOverrides !== "object") {
|
|
1294
|
+
run.workerEnvOverrides = null;
|
|
1295
|
+
}
|
|
1296
|
+
run.workspaceId =
|
|
1297
|
+
typeof run.workspaceId === "string" && run.workspaceId.trim().length > 0
|
|
1298
|
+
? run.workspaceId.trim()
|
|
1299
|
+
: null;
|
|
1300
|
+
run.lastInitiativeStatus =
|
|
1301
|
+
typeof run.lastInitiativeStatus === "string" && run.lastInitiativeStatus.trim().length > 0
|
|
1302
|
+
? run.lastInitiativeStatus.trim()
|
|
1303
|
+
: null;
|
|
1304
|
+
};
|
|
1305
|
+
const laneStateToChildStatus = (laneState) => {
|
|
1306
|
+
if (laneState === LaneState.RUNNING)
|
|
1307
|
+
return "in_progress";
|
|
1308
|
+
if (laneState === LaneState.BLOCKED)
|
|
1309
|
+
return "blocked";
|
|
1310
|
+
if (laneState === LaneState.WAITING_DEPENDENCY || laneState === LaneState.RATE_LIMITED) {
|
|
1311
|
+
return "paused";
|
|
1312
|
+
}
|
|
1313
|
+
if (laneState === LaneState.COMPLETED)
|
|
1314
|
+
return "completed";
|
|
1315
|
+
return "todo";
|
|
1316
|
+
};
|
|
1317
|
+
const deriveInitiativeStatusFromRun = (run) => {
|
|
1318
|
+
ensureRunInternals(run);
|
|
1319
|
+
const childStatuses = Object.values(run.laneByWorkstreamId ?? {}).map((lane) => laneStateToChildStatus(lane.state));
|
|
1320
|
+
if (run.status === RunStatus.RUNNING || run.status === RunStatus.STOPPING) {
|
|
1321
|
+
return deriveInitiativeLifecycleStatus("active", childStatuses.length > 0 ? childStatuses : ["in_progress"]);
|
|
1322
|
+
}
|
|
1323
|
+
if (run.stopReason === "blocked" || run.stopReason === "error") {
|
|
1324
|
+
return "blocked";
|
|
1325
|
+
}
|
|
1326
|
+
if (run.stopReason === "completed") {
|
|
1327
|
+
const scopedRun = run.stopAfterSlice ||
|
|
1328
|
+
(Array.isArray(run.allowedWorkstreamIds) && run.allowedWorkstreamIds.length > 0);
|
|
1329
|
+
return scopedRun ? "paused" : "completed";
|
|
1330
|
+
}
|
|
1331
|
+
if (run.stopReason === "budget_exhausted" || run.stopReason === "stopped") {
|
|
1332
|
+
return "paused";
|
|
1333
|
+
}
|
|
1334
|
+
return childStatuses.length > 0
|
|
1335
|
+
? deriveInitiativeLifecycleStatus("paused", childStatuses)
|
|
1336
|
+
: "paused";
|
|
1337
|
+
};
|
|
1338
|
+
const syncInitiativeLifecycleStatus = async (run) => {
|
|
1339
|
+
const nextStatus = deriveInitiativeStatusFromRun(run);
|
|
1340
|
+
if (run.lastInitiativeStatus === nextStatus)
|
|
1341
|
+
return;
|
|
1342
|
+
await client.updateEntity("initiative", run.initiativeId, { status: nextStatus });
|
|
1343
|
+
run.lastInitiativeStatus = nextStatus;
|
|
1119
1344
|
};
|
|
1120
1345
|
const recordLocalStatusOverrides = (input) => {
|
|
1121
1346
|
const initiativeId = input.initiativeId.trim();
|
|
@@ -1390,6 +1615,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1390
1615
|
updated_at: lane.updatedAt,
|
|
1391
1616
|
}));
|
|
1392
1617
|
const patch = {
|
|
1618
|
+
...(input.run.workspaceId ? { workspace_id: input.run.workspaceId } : {}),
|
|
1393
1619
|
auto_continue_enabled: input.run.status === RunStatus.RUNNING || input.run.status === RunStatus.STOPPING,
|
|
1394
1620
|
auto_continue_status: input.run.status,
|
|
1395
1621
|
auto_continue_stop_reason: input.run.stopReason,
|
|
@@ -1415,6 +1641,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1415
1641
|
...(input.run.lastError ? { auto_continue_last_error: input.run.lastError } : {}),
|
|
1416
1642
|
};
|
|
1417
1643
|
await updateInitiativeMetadata(input.initiativeId, patch);
|
|
1644
|
+
await syncInitiativeLifecycleStatus(input.run);
|
|
1418
1645
|
}
|
|
1419
1646
|
async function stopAutoContinueRun(input) {
|
|
1420
1647
|
const decisionRequired = input.reason === "blocked" && input.decisionRequired === true;
|
|
@@ -1429,6 +1656,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1429
1656
|
const now = new Date().toISOString();
|
|
1430
1657
|
ensureRunInternals(input.run);
|
|
1431
1658
|
const activeRunIds = listActiveSliceRunIds(input.run);
|
|
1659
|
+
await stopActiveSliceProcesses(activeRunIds);
|
|
1432
1660
|
input.run.status = RunStatus.STOPPED;
|
|
1433
1661
|
input.run.stopReason = input.reason;
|
|
1434
1662
|
input.run.stoppedAt = now;
|
|
@@ -1458,18 +1686,6 @@ export function createAutoContinueEngine(deps) {
|
|
|
1458
1686
|
for (const runId of activeRunIds) {
|
|
1459
1687
|
clearAutoContinueSliceTransientState(runId);
|
|
1460
1688
|
}
|
|
1461
|
-
// Only pause the initiative on non-terminal stops (error, blocked, user-requested).
|
|
1462
|
-
// Completed / budget-exhausted runs should not override the initiative status.
|
|
1463
|
-
if (input.reason !== "completed" && input.reason !== "budget_exhausted") {
|
|
1464
|
-
try {
|
|
1465
|
-
await client.updateEntity("initiative", input.run.initiativeId, {
|
|
1466
|
-
status: "paused",
|
|
1467
|
-
});
|
|
1468
|
-
}
|
|
1469
|
-
catch {
|
|
1470
|
-
// best effort
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
1689
|
try {
|
|
1474
1690
|
await updateInitiativeAutoContinueState({
|
|
1475
1691
|
initiativeId: input.run.initiativeId,
|
|
@@ -1590,7 +1806,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1590
1806
|
old_state: LaneState.RUNNING,
|
|
1591
1807
|
new_state: input.reason === "completed" || input.reason === "stopped" ? "idle" : input.reason === "blocked" ? "blocked" : input.reason === "error" ? "error" : "idle",
|
|
1592
1808
|
reason: input.reason,
|
|
1593
|
-
workspace_id: input.run.
|
|
1809
|
+
workspace_id: input.run.workspaceId ?? null,
|
|
1594
1810
|
},
|
|
1595
1811
|
});
|
|
1596
1812
|
}
|
|
@@ -1748,11 +1964,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1748
1964
|
title: `Agent couldn't connect to tools: ${slice.workstreamTitle ?? slice.workstreamId}`,
|
|
1749
1965
|
summary: humanizeSliceFailureSummary(`MCP handshake failed${mcpHandshake.server ? ` for ${mcpHandshake.server}` : ""}.`),
|
|
1750
1966
|
urgency: "high",
|
|
1751
|
-
options:
|
|
1752
|
-
"Retry this workstream slice",
|
|
1753
|
-
"Pause autopilot and investigate",
|
|
1754
|
-
"Skip this workstream for now",
|
|
1755
|
-
],
|
|
1967
|
+
options: defaultInterventionDecisionOptions(),
|
|
1756
1968
|
blocking: true,
|
|
1757
1969
|
decisionType: "autopilot_failure",
|
|
1758
1970
|
workstreamId: slice.workstreamId,
|
|
@@ -1870,11 +2082,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
1870
2082
|
title: stallDecisionTitle,
|
|
1871
2083
|
summary: humanizeSliceFailureSummary(slice.lastError ?? `Autopilot slice ${humanLabel}`),
|
|
1872
2084
|
urgency: "high",
|
|
1873
|
-
options:
|
|
1874
|
-
"Retry this workstream slice",
|
|
1875
|
-
"Pause autopilot and investigate",
|
|
1876
|
-
"Skip this workstream for now",
|
|
1877
|
-
],
|
|
2085
|
+
options: defaultInterventionDecisionOptions(),
|
|
1878
2086
|
blocking: true,
|
|
1879
2087
|
decisionType: "autopilot_failure",
|
|
1880
2088
|
workstreamId: slice.workstreamId,
|
|
@@ -1972,6 +2180,68 @@ export function createAutoContinueEngine(deps) {
|
|
|
1972
2180
|
}
|
|
1973
2181
|
}
|
|
1974
2182
|
const defaultDecisionBlocking = parsedStatus === "completed" ? false : true;
|
|
2183
|
+
const normalizeDecisionOptions = (value) => {
|
|
2184
|
+
if (!Array.isArray(value))
|
|
2185
|
+
return [];
|
|
2186
|
+
const normalized = [];
|
|
2187
|
+
for (const rawOption of value) {
|
|
2188
|
+
if (typeof rawOption === "string") {
|
|
2189
|
+
const label = rawOption.trim();
|
|
2190
|
+
if (label.length > 0)
|
|
2191
|
+
normalized.push(label);
|
|
2192
|
+
continue;
|
|
2193
|
+
}
|
|
2194
|
+
if (!rawOption || typeof rawOption !== "object" || Array.isArray(rawOption)) {
|
|
2195
|
+
continue;
|
|
2196
|
+
}
|
|
2197
|
+
const optionRecord = rawOption;
|
|
2198
|
+
const label = (typeof optionRecord.label === "string" && optionRecord.label.trim()) ||
|
|
2199
|
+
(typeof optionRecord.title === "string" && optionRecord.title.trim()) ||
|
|
2200
|
+
(typeof optionRecord.name === "string" && optionRecord.name.trim()) ||
|
|
2201
|
+
null;
|
|
2202
|
+
if (!label)
|
|
2203
|
+
continue;
|
|
2204
|
+
const normalizedRecord = { label };
|
|
2205
|
+
const id = (typeof optionRecord.id === "string" && optionRecord.id.trim()) ||
|
|
2206
|
+
(typeof optionRecord.option_id === "string" && optionRecord.option_id.trim()) ||
|
|
2207
|
+
null;
|
|
2208
|
+
if (id)
|
|
2209
|
+
normalizedRecord.id = id;
|
|
2210
|
+
const description = (typeof optionRecord.description === "string" && optionRecord.description.trim()) ||
|
|
2211
|
+
null;
|
|
2212
|
+
if (description)
|
|
2213
|
+
normalizedRecord.description = description;
|
|
2214
|
+
const consequences = (typeof optionRecord.consequences === "string" && optionRecord.consequences.trim()) ||
|
|
2215
|
+
(typeof optionRecord.impact === "string" && optionRecord.impact.trim()) ||
|
|
2216
|
+
null;
|
|
2217
|
+
if (consequences)
|
|
2218
|
+
normalizedRecord.consequences = consequences;
|
|
2219
|
+
const impliedStatusRaw = typeof optionRecord.implied_status === "string"
|
|
2220
|
+
? optionRecord.implied_status
|
|
2221
|
+
: typeof optionRecord.status === "string"
|
|
2222
|
+
? optionRecord.status
|
|
2223
|
+
: null;
|
|
2224
|
+
if (impliedStatusRaw) {
|
|
2225
|
+
const implied = impliedStatusRaw.trim().toLowerCase();
|
|
2226
|
+
if (implied === "approved" ||
|
|
2227
|
+
implied === "declined" ||
|
|
2228
|
+
implied === "cancelled" ||
|
|
2229
|
+
implied === "rejected") {
|
|
2230
|
+
normalizedRecord.implied_status = implied;
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
const actionType = normalizeDecisionActionType(optionRecord.action_type ?? optionRecord.type ?? optionRecord.verb ?? optionRecord.action);
|
|
2234
|
+
if (actionType)
|
|
2235
|
+
normalizedRecord.action_type = actionType;
|
|
2236
|
+
if (optionRecord.requires_note === true ||
|
|
2237
|
+
optionRecord.requiresNote === true ||
|
|
2238
|
+
optionRecord.note_required === true) {
|
|
2239
|
+
normalizedRecord.requires_note = true;
|
|
2240
|
+
}
|
|
2241
|
+
normalized.push(normalizedRecord);
|
|
2242
|
+
}
|
|
2243
|
+
return normalized.slice(0, 8);
|
|
2244
|
+
};
|
|
1975
2245
|
const allDecisions = Array.isArray(parsed?.decisions_needed)
|
|
1976
2246
|
? (parsed?.decisions_needed ?? [])
|
|
1977
2247
|
.filter((item) => Boolean(item && typeof item.question === "string" && item.question.trim()))
|
|
@@ -2115,9 +2385,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
2115
2385
|
title: normalizedQuestion,
|
|
2116
2386
|
summary: decision.summary ?? parsed?.summary ?? null,
|
|
2117
2387
|
urgency: decision.urgency ?? "high",
|
|
2118
|
-
options:
|
|
2119
|
-
? decision.options.filter((opt) => typeof opt === "string" && opt.trim())
|
|
2120
|
-
: [],
|
|
2388
|
+
options: normalizeDecisionOptions(decision.options),
|
|
2121
2389
|
blocking: isBlocking,
|
|
2122
2390
|
decisionType: isBlocking
|
|
2123
2391
|
? "autopilot_blocking_decision"
|
|
@@ -2511,11 +2779,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
2511
2779
|
title: fallbackDecisionTitle,
|
|
2512
2780
|
summary: fallbackDecisionSummary,
|
|
2513
2781
|
urgency: "high",
|
|
2514
|
-
options:
|
|
2515
|
-
"Retry this workstream slice",
|
|
2516
|
-
"Pause autopilot and investigate",
|
|
2517
|
-
"Skip this workstream for now",
|
|
2518
|
-
],
|
|
2782
|
+
options: defaultInterventionDecisionOptions(),
|
|
2519
2783
|
blocking: true,
|
|
2520
2784
|
decisionType: looksLikeNoOutcome
|
|
2521
2785
|
? "autopilot_completed_without_outcome"
|
|
@@ -2597,11 +2861,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
2597
2861
|
title: attentionTitle,
|
|
2598
2862
|
summary: attentionSummary,
|
|
2599
2863
|
urgency: "high",
|
|
2600
|
-
options:
|
|
2601
|
-
"Retry this workstream slice",
|
|
2602
|
-
"Pause autopilot and investigate",
|
|
2603
|
-
"Skip this workstream for now",
|
|
2604
|
-
],
|
|
2864
|
+
options: defaultInterventionDecisionOptions(),
|
|
2605
2865
|
blocking: true,
|
|
2606
2866
|
decisionType: completionHadNoOutcome
|
|
2607
2867
|
? "autopilot_completed_without_outcome"
|
|
@@ -3609,16 +3869,27 @@ export function createAutoContinueEngine(deps) {
|
|
|
3609
3869
|
const logsDir = join(getOrgxPluginConfigDir(), AUTO_CONTINUE_SLICE_LOG_DIRNAME);
|
|
3610
3870
|
const logPath = join(logsDir, `${sliceRunId}.log`);
|
|
3611
3871
|
const outputPath = join(logsDir, `${sliceRunId}.output.json`);
|
|
3612
|
-
const
|
|
3872
|
+
const workerEnvOverrides = run.workerEnvOverrides ?? defaultWorkerEnvOverrides;
|
|
3873
|
+
const configuredWorkerCwd = (workerEnvOverrides?.ORGX_AUTOPILOT_CWD ??
|
|
3874
|
+
process.env.ORGX_AUTOPILOT_CWD ??
|
|
3875
|
+
"").trim();
|
|
3613
3876
|
let workerCwd = configuredWorkerCwd || resolveAutopilotDefaultCwd(__filename);
|
|
3614
3877
|
// LaunchAgents sometimes start with cwd="/". Fall back to plugin root (or home if unresolved).
|
|
3615
3878
|
if (!workerCwd || workerCwd === "/") {
|
|
3616
3879
|
workerCwd = resolveAutopilotDefaultCwd(__filename);
|
|
3617
3880
|
}
|
|
3618
3881
|
const sliceAgent = resolveOrgxAgentForDomain(executionPolicy.domain);
|
|
3619
|
-
const workerKind = (
|
|
3882
|
+
const workerKind = (workerEnvOverrides?.ORGX_AUTOPILOT_WORKER_KIND ??
|
|
3883
|
+
process.env.ORGX_AUTOPILOT_WORKER_KIND ??
|
|
3884
|
+
"")
|
|
3885
|
+
.trim()
|
|
3886
|
+
.toLowerCase();
|
|
3620
3887
|
const inferredExecutor = workerKind === "claude-code" || workerKind === "claude_code" ? "claude-code" : "codex";
|
|
3621
|
-
const executorRaw = (
|
|
3888
|
+
const executorRaw = (workerEnvOverrides?.ORGX_AUTOPILOT_EXECUTOR ??
|
|
3889
|
+
process.env.ORGX_AUTOPILOT_EXECUTOR ??
|
|
3890
|
+
"")
|
|
3891
|
+
.trim()
|
|
3892
|
+
.toLowerCase() || inferredExecutor;
|
|
3622
3893
|
const executorSourceClient = executorRaw === "claude-code" || executorRaw === "claude_code" ? "claude-code" : "codex";
|
|
3623
3894
|
let runtimeHookUrl = null;
|
|
3624
3895
|
let runtimeHookToken = null;
|
|
@@ -3643,6 +3914,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
3643
3914
|
outputSchemaPath: schemaPath,
|
|
3644
3915
|
resumeSessionId: resumedFromSessionId,
|
|
3645
3916
|
env: {
|
|
3917
|
+
...(workerEnvOverrides ?? {}),
|
|
3646
3918
|
ORGX_SOURCE_CLIENT: executorSourceClient,
|
|
3647
3919
|
ORGX_RUN_ID: sliceRunId,
|
|
3648
3920
|
ORGX_CORRELATION_ID: sliceRunId,
|
|
@@ -3820,12 +4092,6 @@ export function createAutoContinueEngine(deps) {
|
|
|
3820
4092
|
// Clear stale errors when a new slice dispatches successfully.
|
|
3821
4093
|
run.lastError = null;
|
|
3822
4094
|
run.updatedAt = now;
|
|
3823
|
-
try {
|
|
3824
|
-
await client.updateEntity("initiative", run.initiativeId, { status: "active" });
|
|
3825
|
-
}
|
|
3826
|
-
catch {
|
|
3827
|
-
// best effort
|
|
3828
|
-
}
|
|
3829
4095
|
try {
|
|
3830
4096
|
await updateInitiativeAutoContinueState({
|
|
3831
4097
|
initiativeId: run.initiativeId,
|
|
@@ -3918,6 +4184,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
3918
4184
|
const sourceEvent = (input.event ?? "").trim() || null;
|
|
3919
4185
|
const requestedByAgentId = (input.requestedByAgentId ?? "").trim() || null;
|
|
3920
4186
|
const requestedByAgentName = (input.requestedByAgentName ?? "").trim() || null;
|
|
4187
|
+
const autoFixWorkerEnv = captureAutopilotWorkerEnv();
|
|
3921
4188
|
const providedGraceMs = typeof input.graceMs === "number" && Number.isFinite(input.graceMs)
|
|
3922
4189
|
? Math.floor(input.graceMs)
|
|
3923
4190
|
: null;
|
|
@@ -4093,6 +4360,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4093
4360
|
null;
|
|
4094
4361
|
const dispatchRun = await startAutoContinueRun({
|
|
4095
4362
|
initiativeId,
|
|
4363
|
+
workspaceId: latestRun?.workspaceId ?? null,
|
|
4096
4364
|
agentId: dispatchAgentId,
|
|
4097
4365
|
agentName: dispatchAgentName,
|
|
4098
4366
|
// Auto-fix retries should follow current defaults unless an operator explicitly
|
|
@@ -4104,6 +4372,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4104
4372
|
parallelMode: latestRun?.parallelMode ?? "iwmt",
|
|
4105
4373
|
stopAfterSlice: true,
|
|
4106
4374
|
ignoreSpawnGuardRateLimit: latestRun?.ignoreSpawnGuardRateLimit ?? false,
|
|
4375
|
+
workerEnvOverrides: autoFixWorkerEnv,
|
|
4107
4376
|
});
|
|
4108
4377
|
await tickAutoContinueRun(dispatchRun);
|
|
4109
4378
|
await emitActivitySafe({
|
|
@@ -4198,11 +4467,15 @@ export function createAutoContinueEngine(deps) {
|
|
|
4198
4467
|
}
|
|
4199
4468
|
async function startAutoContinueRun(input) {
|
|
4200
4469
|
const now = new Date().toISOString();
|
|
4470
|
+
const nextWorkerEnvOverrides = input.workerEnvOverrides && typeof input.workerEnvOverrides === "object"
|
|
4471
|
+
? { ...input.workerEnvOverrides }
|
|
4472
|
+
: { ...defaultWorkerEnvOverrides };
|
|
4201
4473
|
const existing = autoContinueRuns.get(input.initiativeId) ?? null;
|
|
4202
4474
|
const existingIsLive = existing?.status === RunStatus.RUNNING || existing?.status === RunStatus.STOPPING;
|
|
4203
4475
|
const run = existing ??
|
|
4204
4476
|
{
|
|
4205
4477
|
initiativeId: input.initiativeId,
|
|
4478
|
+
workspaceId: null,
|
|
4206
4479
|
agentId: input.agentId,
|
|
4207
4480
|
agentName: input.agentName ?? null,
|
|
4208
4481
|
includeVerification: false,
|
|
@@ -4230,8 +4503,14 @@ export function createAutoContinueEngine(deps) {
|
|
|
4230
4503
|
activeTaskId: null,
|
|
4231
4504
|
activeRunId: null,
|
|
4232
4505
|
activeTaskTokenEstimate: null,
|
|
4506
|
+
workerEnvOverrides: null,
|
|
4507
|
+
lastInitiativeStatus: null,
|
|
4233
4508
|
};
|
|
4234
4509
|
ensureRunInternals(run);
|
|
4510
|
+
run.workspaceId =
|
|
4511
|
+
typeof input.workspaceId === "string" && input.workspaceId.trim().length > 0
|
|
4512
|
+
? input.workspaceId.trim()
|
|
4513
|
+
: run.workspaceId;
|
|
4235
4514
|
run.agentId = input.agentId;
|
|
4236
4515
|
run.agentName =
|
|
4237
4516
|
typeof input.agentName === "string" && input.agentName.trim().length > 0
|
|
@@ -4244,6 +4523,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4244
4523
|
run.stopAfterSlice = Boolean(input.stopAfterSlice);
|
|
4245
4524
|
run.ignoreSpawnGuardRateLimit = Boolean(input.ignoreSpawnGuardRateLimit);
|
|
4246
4525
|
run.scope = input.scope ?? "task";
|
|
4526
|
+
run.workerEnvOverrides = nextWorkerEnvOverrides;
|
|
4247
4527
|
const hasExplicitTokenBudgetInput = input.tokenBudget !== null &&
|
|
4248
4528
|
input.tokenBudget !== undefined &&
|
|
4249
4529
|
!(typeof input.tokenBudget === "string" && input.tokenBudget.trim().length === 0);
|
|
@@ -4280,11 +4560,6 @@ export function createAutoContinueEngine(deps) {
|
|
|
4280
4560
|
}
|
|
4281
4561
|
syncLegacyRunPointers(run);
|
|
4282
4562
|
autoContinueRuns.set(input.initiativeId, run);
|
|
4283
|
-
void client
|
|
4284
|
-
.updateEntity("initiative", input.initiativeId, { status: "active" })
|
|
4285
|
-
.catch(() => {
|
|
4286
|
-
// best effort
|
|
4287
|
-
});
|
|
4288
4563
|
void updateInitiativeAutoContinueState({
|
|
4289
4564
|
initiativeId: input.initiativeId,
|
|
4290
4565
|
run,
|
|
@@ -4343,7 +4618,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4343
4618
|
old_state: LaneState.IDLE,
|
|
4344
4619
|
new_state: LaneState.RUNNING,
|
|
4345
4620
|
reason: "started",
|
|
4346
|
-
workspace_id: run.
|
|
4621
|
+
workspace_id: run.workspaceId ?? null,
|
|
4347
4622
|
},
|
|
4348
4623
|
});
|
|
4349
4624
|
}
|
|
@@ -4470,6 +4745,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
4470
4745
|
getAutoContinueLaneForWorkstream,
|
|
4471
4746
|
scheduleAutoFixForWorkstream,
|
|
4472
4747
|
startAutoContinueRun,
|
|
4748
|
+
restoreAutoContinueRun,
|
|
4473
4749
|
skipCurrentWorkstream,
|
|
4474
4750
|
getCanonicalAutopilotState,
|
|
4475
4751
|
// Session store (for resume support)
|
|
@@ -199,7 +199,11 @@ export function createAutopilotRuntime(deps) {
|
|
|
199
199
|
function spawnCodexSliceWorker(input) {
|
|
200
200
|
ensurePrivateDirForFile(input.logPath);
|
|
201
201
|
ensurePrivateDirForFile(input.outputPath);
|
|
202
|
-
const workerKind = (
|
|
202
|
+
const workerKind = (input.env.ORGX_AUTOPILOT_WORKER_KIND ??
|
|
203
|
+
process.env.ORGX_AUTOPILOT_WORKER_KIND ??
|
|
204
|
+
"")
|
|
205
|
+
.trim()
|
|
206
|
+
.toLowerCase();
|
|
203
207
|
if (workerKind === "mock") {
|
|
204
208
|
const scriptPath = resolve(dirname(deps.filename), "..", "..", "scripts", "mock-autopilot-slice-worker.mjs");
|
|
205
209
|
const logStream = createSafeAppendStream(input.logPath);
|
|
@@ -33,7 +33,27 @@ function autopilotSliceSchema() {
|
|
|
33
33
|
const decisionProperties = {
|
|
34
34
|
question: { type: "string", minLength: 1 },
|
|
35
35
|
summary: { type: ["string", "null"] },
|
|
36
|
-
options: {
|
|
36
|
+
options: {
|
|
37
|
+
type: ["array", "null"],
|
|
38
|
+
items: {
|
|
39
|
+
type: ["string", "object"],
|
|
40
|
+
minLength: 1,
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
required: ["label"],
|
|
43
|
+
properties: {
|
|
44
|
+
id: { type: ["string", "null"] },
|
|
45
|
+
label: { type: "string", minLength: 1 },
|
|
46
|
+
description: { type: ["string", "null"] },
|
|
47
|
+
consequences: { type: ["string", "null"] },
|
|
48
|
+
implied_status: {
|
|
49
|
+
type: ["string", "null"],
|
|
50
|
+
enum: ["approved", "declined", "cancelled", "rejected", null],
|
|
51
|
+
},
|
|
52
|
+
action_type: { type: ["string", "null"] },
|
|
53
|
+
requires_note: { type: ["boolean", "null"] },
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
37
57
|
urgency: {
|
|
38
58
|
type: ["string", "null"],
|
|
39
59
|
enum: ["low", "medium", "high", "urgent", null],
|
|
@@ -859,6 +879,8 @@ export function buildSliceOutputInstructions(input) {
|
|
|
859
879
|
"- Artifacts must be verifiable: include URLs or local paths, plus verification steps.",
|
|
860
880
|
"- Include `confidence_score` for each artifact (`0` to `1`; use `null` when unknown).",
|
|
861
881
|
"- If you need a human decision, include it in decisions_needed.",
|
|
882
|
+
"- Prefer structured decision options objects with: id, label, description, consequences, implied_status, action_type, requires_note.",
|
|
883
|
+
"- String options are still accepted, but structured options are required for precise decision routing.",
|
|
862
884
|
"- For every decisions_needed entry, ALWAYS set blocking explicitly (true or false).",
|
|
863
885
|
"- If status is blocked, needs_decision, or error: include at least one decisions_needed entry with blocking=true.",
|
|
864
886
|
"- Status/decision consistency is strict:",
|
|
@@ -959,6 +981,8 @@ export function buildWorkstreamSlicePrompt(input) {
|
|
|
959
981
|
"- Artifacts must be verifiable: include URLs or local paths, plus verification steps.",
|
|
960
982
|
"- Include `confidence_score` for each artifact (`0` to `1`; use `null` when unknown).",
|
|
961
983
|
"- If you need a human decision, include it in decisions_needed.",
|
|
984
|
+
"- Prefer structured decision options objects with: id, label, description, consequences, implied_status, action_type, requires_note.",
|
|
985
|
+
"- String options are still accepted, but structured options are required for precise decision routing.",
|
|
962
986
|
"- For every decisions_needed entry, ALWAYS set blocking explicitly (true or false).",
|
|
963
987
|
"- If status is blocked, needs_decision, or error: include at least one decisions_needed entry with blocking=true.",
|
|
964
988
|
"- Status/decision consistency is strict:",
|