feat(web): add source-first Python autopilot and optimize provider waits
This commit is contained in:
@@ -81,6 +81,8 @@ const pushVerification = (task) => {
|
||||
return { path: file, localHead: match?.[1] ?? null, remoteHead: match?.[2] ?? null, equal: Boolean(match && match[1] === match[2]) };
|
||||
};
|
||||
const collect = () => {
|
||||
const autopilot = readJson(`${controlRoot}/autopilot/state.json`);
|
||||
const autopilotLock = lockInfo(`${controlRoot}/autopilot/owner.lock`);
|
||||
const queue = currentPointer();
|
||||
const scheduler = readJson(schedulerCheckpointPath);
|
||||
const guardian = readJson(guardianCheckpointPath);
|
||||
@@ -88,21 +90,23 @@ const collect = () => {
|
||||
const schedulerLock = lockInfo(schedulerLockPath);
|
||||
const guardianLock = lockInfo(guardianLockPath);
|
||||
const supervisorLock = lockInfo(supervisorLockPath);
|
||||
const pythonOwnsScheduler = autopilotLock.alive && schedulerLock.pid === autopilotLock.pid;
|
||||
const handoff = latestHandoff();
|
||||
const active = schedulerLock.alive || (guardianLock.alive && supervisorLock.alive);
|
||||
const active = autopilotLock.alive || schedulerLock.alive || (guardianLock.alive && supervisorLock.alive);
|
||||
let terminalQueue = false;
|
||||
try {
|
||||
const manifest = queue.task ? readJson(`tests/golden/${queue.task}/manifest.json`) : null;
|
||||
const index = readJson("tests/golden/WBV2/task-index.json");
|
||||
terminalQueue = !active && index?.activeTask === null && manifest?.status === "done" && manifest?.nextTask === null;
|
||||
terminalQueue = !active && index?.activeTask === null && manifest?.status === "done" && manifest?.nextTask === null && manifest?.acceptanceComplete === true && manifest?.verificationDeferred !== true;
|
||||
} catch { /* A malformed pointer remains visible as a normal checkpoint failure. */ }
|
||||
const checkpointBlocked = scheduler?.state === "blocked" || guardian?.state === "blocked" || supervisor?.state === "blocked";
|
||||
// A terminal task can leave a historical blocked checkpoint behind (for
|
||||
// example, after a push retry). The watchdog owns the next planner attempt;
|
||||
// do not report that stale checkpoint as a live execution block.
|
||||
const blocked = checkpointBlocked && !terminalQueue;
|
||||
const autopilotBlocked = ["blocked", "provider_blocked", "needs_reconcile", "planning_required", "budget_exhausted", "ready_to_publish"].includes(autopilot?.state);
|
||||
const blocked = autopilotBlocked || (!autopilotLock.alive && checkpointBlocked && !terminalQueue);
|
||||
const state = blocked ? "BLOCKED" : active ? "RUNNING" : "IDLE";
|
||||
const phase = blocked ? "blocked" : scheduler?.state === "running" ? "scheduler-task" : supervisor?.state === "running" ? "task-or-gate" : scheduler?.state ?? supervisor?.state ?? "unknown";
|
||||
const phase = autopilotLock.alive || autopilotBlocked ? `python-${autopilot?.state ?? "starting"}` : blocked ? "blocked" : scheduler?.state === "running" ? "scheduler-task" : supervisor?.state === "running" ? "task-or-gate" : scheduler?.state ?? supervisor?.state ?? "unknown";
|
||||
const observed = new Date().toISOString();
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
@@ -110,10 +114,11 @@ const collect = () => {
|
||||
state,
|
||||
phase,
|
||||
message: state === "RUNNING"
|
||||
? `RUNNING: ${queue.task ?? "unknown task"} is owned by the guardian/supervisor process; wait for its handoff.`
|
||||
? `RUNNING: ${queue.task ?? "unknown task"} is owned by ${autopilotLock.alive ? "Python autopilot" : "guardian/supervisor"}; wait for its handoff.`
|
||||
: state === "BLOCKED" ? "BLOCKED: inspect the scheduler/guardian/supervisor checkpoint reason before any write or retry." : "IDLE: no live scheduler, guardian or supervisor lock was found.",
|
||||
queue,
|
||||
scheduler: { pid: scheduler?.pid ?? schedulerLock.pid, alive: schedulerLock.alive, state: scheduler?.state ?? null, updatedAt: scheduler?.updatedAt ?? null, iteration: scheduler?.iteration ?? null, before: scheduler?.before ?? null, after: scheduler?.after ?? null, latestBatch: scheduler?.latestBatch ?? null },
|
||||
autopilot: { pid: autopilot?.pid ?? autopilotLock.pid, alive: autopilotLock.alive, state: autopilot?.state ?? null, phase: autopilot?.currentProcess?.phase ?? null, activeJob: autopilot?.activeJob ?? null, reason: autopilot?.reason ?? null, tokensUsed: autopilot?.tokensUsed ?? 0, providerFailures: autopilot?.providerFailures ?? 0, nextRetryAt: autopilot?.nextRetryAt ?? null },
|
||||
scheduler: { pid: schedulerLock.alive ? schedulerLock.pid : scheduler?.pid ?? schedulerLock.pid, alive: schedulerLock.alive, state: pythonOwnsScheduler ? "python-owned" : scheduler?.state ?? null, updatedAt: pythonOwnsScheduler ? autopilot?.updatedAt : scheduler?.updatedAt ?? null, iteration: pythonOwnsScheduler ? null : scheduler?.iteration ?? null, before: pythonOwnsScheduler ? null : scheduler?.before ?? null, after: pythonOwnsScheduler ? null : scheduler?.after ?? null, latestBatch: pythonOwnsScheduler ? null : scheduler?.latestBatch ?? null },
|
||||
guardian: { pid: guardian?.pid ?? guardianLock.pid, alive: guardianLock.alive, state: guardian?.state ?? null, updatedAt: guardian?.updatedAt ?? null, heartbeatAt: guardian?.heartbeatAt ?? null, restartCount: guardian?.restartCount ?? null },
|
||||
supervisor: { pid: supervisor?.pid ?? supervisorLock.pid, alive: supervisorLock.alive, state: supervisor?.state ?? null, updatedAt: supervisor?.updatedAt ?? null, iteration: supervisor?.iteration ?? null, before: supervisor?.before ?? null, after: supervisor?.after ?? null },
|
||||
latestHandoff: handoff,
|
||||
@@ -127,6 +132,7 @@ const format = (status) => [
|
||||
`阶段: ${status.phase}`,
|
||||
`当前任务: ${status.queue.task ?? "unknown"}`,
|
||||
`parent manifest: ${status.queue.parentManifest ?? "unknown"}`,
|
||||
`Python autopilot: pid=${status.autopilot.pid ?? "none"} alive=${status.autopilot.alive} state=${status.autopilot.state ?? "unknown"} job=${status.autopilot.activeJob ?? "none"} reason=${status.autopilot.reason ?? "none"}`,
|
||||
`scheduler: pid=${status.scheduler.pid ?? "none"} alive=${status.scheduler.alive} state=${status.scheduler.state ?? "unknown"} iteration=${status.scheduler.iteration ?? "none"} batch=${status.scheduler.latestBatch?.batchId ?? "none"} completed=${status.scheduler.latestBatch?.completed ?? false}`,
|
||||
`guardian: pid=${status.guardian.pid ?? "none"} alive=${status.guardian.alive} state=${status.guardian.state ?? "unknown"} heartbeat=${status.guardian.heartbeatAt ?? "none"}`,
|
||||
`supervisor: pid=${status.supervisor.pid ?? "none"} alive=${status.supervisor.alive} state=${status.supervisor.state ?? "unknown"} iteration=${status.supervisor.iteration ?? "none"}`,
|
||||
|
||||
Reference in New Issue
Block a user