fix(auto): honor solver swarm tool counts

This commit is contained in:
Mikael Hugo 2026-05-15 05:54:02 +02:00
parent dbfaca61cf
commit 50383eb2bf
2 changed files with 55 additions and 2 deletions

View file

@ -171,6 +171,20 @@ function clearDeferredCommitAfterCancelledUnit(
);
}
/**
* Return the unit result that should drive the zero-tool-call guard.
*
* Purpose: preserve autonomous progress when a solver or repair pass produced
* the checkpoint after the first executor turn. The guard protects against
* genuine no-op turns, but it must not inspect a stale pre-solver result after
* currentUnitResult has been replaced with a later successful swarm turn.
*
* Consumer: runUnitPhase zero-tool-call guard after solver assessment.
*/
export function resultForZeroToolCallGuard(unitResult, currentUnitResult) {
return currentUnitResult ?? unitResult;
}
// ─── runUnitPhase ─────────────────────────────────────────────────────────────
/**
* Phase 4: Unit execution dispatch prompt, await agent_end, closeout, artifact verify.
@ -1560,8 +1574,13 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
// Swarm bypass: the ledger entry only reflects the parent session, which
// never receives the subagent's tool calls. Use the real count surfaced by
// runUnitViaSwarm (swarmToolCallCount) to avoid a false-positive retry.
const swarmRealToolCalls = unitResult.swarmToolCallCount ?? 0;
const isSwarmWithWork = unitResult._via === "swarm" && swarmRealToolCalls > 0;
const guardResult = resultForZeroToolCallGuard(
unitResult,
currentUnitResult,
);
const swarmRealToolCalls = guardResult.swarmToolCallCount ?? 0;
const isSwarmWithWork =
guardResult._via === "swarm" && swarmRealToolCalls > 0;
if (isSwarmWithWork) {
debugLog("runUnitPhase", {
phase: "zero-tool-calls-swarm-bypass",

View file

@ -0,0 +1,34 @@
import assert from "node:assert/strict";
import { test } from "vitest";
import { resultForZeroToolCallGuard } from "../auto/phases-unit.js";
test("zeroToolGuard_when_solver_pass_replaces_result_uses_current_result", () => {
const executorResult = {
status: "completed",
_via: "swarm",
swarmToolCallCount: 0,
};
const solverResult = {
status: "completed",
_via: "swarm",
swarmToolCallCount: 1,
};
assert.equal(
resultForZeroToolCallGuard(executorResult, solverResult),
solverResult,
);
});
test("zeroToolGuard_when_no_solver_result_uses_original_result", () => {
const executorResult = {
status: "completed",
_via: "swarm",
swarmToolCallCount: 0,
};
assert.equal(
resultForZeroToolCallGuard(executorResult, null),
executorResult,
);
});