fix(solve-issue): handle one-shot coder completing all phases at once

The moderator now treats completedPhase matching the last planned phase name
as full completion. Also recognizes sentinel values (all-done, all_done,
complete) for robustness.

Fixes #21

小橘 🍊(NEKO Team)
This commit is contained in:
2026-05-07 03:13:44 +00:00
parent 7926751b01
commit 96fc3e220a
3 changed files with 52 additions and 6 deletions
@@ -3,6 +3,30 @@ import { END } from "@uncaged/workflow";
import type { SolveIssueMeta } from "./roles.js";
const COMPLETED_PHASE_SENTINELS = new Set(["all-done", "all_done", "complete"]);
function coderFinishedAllPlannedPhases(
phases: ReadonlyArray<{ name: string }>,
coderCompletedPhases: ReadonlyArray<string>,
): boolean {
if (phases.length === 0) {
return true;
}
const plannedNames = new Set(phases.map((p) => p.name));
const lastName = phases[phases.length - 1].name;
const explicit = new Set(coderCompletedPhases.filter((name) => plannedNames.has(name)));
if (phases.every((p) => explicit.has(p.name))) {
return true;
}
// One-shot runs often report only the final phase; treat that as the full plan done.
if (coderCompletedPhases.some((name) => name === lastName)) {
return true;
}
return coderCompletedPhases.some(
(name) => !plannedNames.has(name) && COMPLETED_PHASE_SENTINELS.has(name),
);
}
function nextAfterCoder(
ctx: ModeratorContext<SolveIssueMeta>,
maxRounds: number,
@@ -12,10 +36,10 @@ function nextAfterCoder(
return "reviewer";
}
const phases = plannerStep.meta.phases;
const completedPhases = new Set(
ctx.steps.filter((s) => s.role === "coder").map((s) => s.meta.completedPhase),
);
const allDone = phases.every((p) => completedPhases.has(p.name));
const coderCompletedPhases = ctx.steps
.filter((s) => s.role === "coder")
.map((s) => s.meta.completedPhase);
const allDone = coderFinishedAllPlannedPhases(phases, coderCompletedPhases);
if (allDone) {
return "reviewer";
}