mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:50:43 +00:00
fix(agents): preserve distinct empty exec failures
This commit is contained in:
@@ -560,6 +560,36 @@ describe("tool-loop-detection", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps changing empty-output exec failures below the global no-progress breaker", () => {
|
||||
const state = createState();
|
||||
const params = { command: "openclaw flaky-helper" };
|
||||
|
||||
for (let index = 0; index < GLOBAL_CIRCUIT_BREAKER_THRESHOLD; index += 1) {
|
||||
recordSuccessfulCall(
|
||||
state,
|
||||
"exec",
|
||||
params,
|
||||
{
|
||||
content: [{ type: "text", text: `Runtime failed before spawn: attempt ${index}` }],
|
||||
details: {
|
||||
status: "failed",
|
||||
exitCode: null,
|
||||
durationMs: 100 + index,
|
||||
aggregated: "",
|
||||
},
|
||||
},
|
||||
index,
|
||||
);
|
||||
}
|
||||
|
||||
const loopResult = detectToolCallLoop(state, "exec", params, enabledLoopDetectionConfig);
|
||||
expect(loopResult.stuck).toBe(true);
|
||||
if (loopResult.stuck) {
|
||||
expect(loopResult.level).toBe("warning");
|
||||
expect(loopResult.detector).toBe("generic_repeat");
|
||||
}
|
||||
});
|
||||
|
||||
it("does not block repeated unknown-tool failures before the unknown-tool threshold", () => {
|
||||
const state = createState();
|
||||
const toolName = "exec";
|
||||
|
||||
@@ -206,6 +206,14 @@ function stringField(value: unknown): string | null {
|
||||
return typeof value === "string" ? value : null;
|
||||
}
|
||||
|
||||
function nonEmptyStringField(value: unknown): string | null {
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
return trimmed ? trimmed : null;
|
||||
}
|
||||
|
||||
function hashExecToolOutcome(details: Record<string, unknown>, text: string): string | undefined {
|
||||
const status = stringField(details.status);
|
||||
if (!status) {
|
||||
@@ -224,7 +232,7 @@ function hashExecToolOutcome(details: Record<string, unknown>, text: string): st
|
||||
status,
|
||||
exitCode: typeof details.exitCode === "number" ? details.exitCode : null,
|
||||
timedOut: details.timedOut === true,
|
||||
output: stringField(details.aggregated) ?? text,
|
||||
output: nonEmptyStringField(details.aggregated) ?? text,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user