fix(auto): count only unproductive runaway iterations
This commit is contained in:
parent
5faa789f52
commit
d1ca3d035c
1 changed files with 18 additions and 6 deletions
|
|
@ -11,11 +11,14 @@ import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|||
import { join } from "node:path";
|
||||
import { atomicWriteSync, delay } from "../atomic-write.js";
|
||||
import { ModelPolicyDispatchBlockedError } from "../auto-model-selection.js";
|
||||
import { getTotalToolCallCount } from "../auto-tool-tracking.js";
|
||||
import { runAutomaticAutonomousSolverEval } from "../autonomous-solver-eval.js";
|
||||
import { debugLog } from "../debug-logger.js";
|
||||
import { resolveEngine } from "../engine-resolver.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
import { NOTICE_KIND } from "../notification-store.js";
|
||||
import { sfRoot } from "../paths.js";
|
||||
import { recordSelfFeedback } from "../self-feedback.js";
|
||||
import { getDatabase } from "../sf-db.js";
|
||||
import {
|
||||
ExecutionGraphScheduler,
|
||||
|
|
@ -40,8 +43,6 @@ import {
|
|||
} from "./phases.js";
|
||||
import { _clearCurrentResolve } from "./resolve.js";
|
||||
import { MAX_LOOP_ITERATIONS } from "./types.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
import { recordSelfFeedback } from "../self-feedback.js";
|
||||
|
||||
// ── Stuck detection persistence (#3704) ──────────────────────────────────
|
||||
// Persist stuck detection state to disk so it survives session restarts.
|
||||
|
|
@ -325,7 +326,7 @@ async function drainSleeptimeQueue(basePath) {
|
|||
? typeof result.response === "string"
|
||||
? result.response
|
||||
: JSON.stringify(result.response)
|
||||
: result.error ?? "";
|
||||
: (result.error ?? "");
|
||||
db.prepare(
|
||||
`UPDATE sleeptime_consolidation_queue
|
||||
SET status = 'done', processed_at = :ts, result = :result
|
||||
|
|
@ -593,7 +594,17 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|||
const recentErrorMessages = [];
|
||||
const watchdog = new HaltWatchdog(s.basePath);
|
||||
watchdog.heartbeat(); // initial heartbeat before entering the loop
|
||||
let lastObservedToolCallCount = getTotalToolCallCount();
|
||||
let unproductiveIterations = 0;
|
||||
while (s.active) {
|
||||
const toolCallCount = getTotalToolCallCount();
|
||||
if (toolCallCount !== lastObservedToolCallCount) {
|
||||
lastObservedToolCallCount = toolCallCount;
|
||||
unproductiveIterations = 0;
|
||||
watchdog.heartbeat();
|
||||
} else {
|
||||
unproductiveIterations++;
|
||||
}
|
||||
iteration++;
|
||||
debugLog("autoLoop", { phase: "loop-top", iteration });
|
||||
// ── Halt watchdog: detect idle/stuck iterations ──
|
||||
|
|
@ -644,22 +655,23 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|||
basePath: s.basePath,
|
||||
startedAt: turnStartedAt,
|
||||
});
|
||||
if (iteration > MAX_LOOP_ITERATIONS) {
|
||||
if (unproductiveIterations > MAX_LOOP_ITERATIONS) {
|
||||
debugLog("autoLoop", {
|
||||
phase: "exit",
|
||||
reason: "max-iterations",
|
||||
iteration,
|
||||
unproductiveIterations,
|
||||
});
|
||||
if (s.isYolo()) {
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`YOLO: loop at ${iteration} iterations — continuing past safety limit`,
|
||||
`YOLO: loop at ${unproductiveIterations} unproductive iterations — continuing past safety limit`,
|
||||
);
|
||||
} else {
|
||||
await deps.stopAuto(
|
||||
ctx,
|
||||
pi,
|
||||
`Safety: loop exceeded ${MAX_LOOP_ITERATIONS} iterations — possible runaway`,
|
||||
`Safety: loop exceeded ${MAX_LOOP_ITERATIONS} unproductive iterations — possible runaway`,
|
||||
);
|
||||
finishTurn("stopped", "manual-attention", "max-iterations");
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue