mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 17:18:25 +00:00
fix(agents): cap embedded runner retry loop
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import "./run.overflow-compaction.mocks.shared.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { pickFallbackThinkingLevel } from "../pi-embedded-helpers.js";
|
||||
import { compactEmbeddedPiSessionDirect } from "./compact.js";
|
||||
import { runEmbeddedPiAgent } from "./run.js";
|
||||
import { makeAttemptResult, mockOverflowRetrySuccess } from "./run.overflow-compaction.fixture.js";
|
||||
@@ -16,6 +17,7 @@ const mockedSessionLikelyHasOversizedToolResults = vi.mocked(sessionLikelyHasOve
|
||||
const mockedTruncateOversizedToolResultsInSession = vi.mocked(
|
||||
truncateOversizedToolResultsInSession,
|
||||
);
|
||||
const mockedPickFallbackThinkingLevel = vi.mocked(pickFallbackThinkingLevel);
|
||||
|
||||
describe("runEmbeddedPiAgent overflow compaction trigger routing", () => {
|
||||
beforeEach(() => {
|
||||
@@ -106,4 +108,29 @@ describe("runEmbeddedPiAgent overflow compaction trigger routing", () => {
|
||||
expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(4);
|
||||
expect(result.meta.error?.kind).toBe("context_overflow");
|
||||
});
|
||||
|
||||
it("returns retry_limit when repeated retries never converge", async () => {
|
||||
mockedRunEmbeddedAttempt.mockReset();
|
||||
mockedCompactDirect.mockReset();
|
||||
mockedPickFallbackThinkingLevel.mockReset();
|
||||
mockedRunEmbeddedAttempt.mockResolvedValue(
|
||||
makeAttemptResult({ promptError: new Error("unsupported reasoning mode") }),
|
||||
);
|
||||
mockedPickFallbackThinkingLevel.mockReturnValue("low");
|
||||
|
||||
const result = await runEmbeddedPiAgent({
|
||||
sessionId: "test-session",
|
||||
sessionKey: "test-key",
|
||||
sessionFile: "/tmp/session.json",
|
||||
workspaceDir: "/tmp/workspace",
|
||||
prompt: "hello",
|
||||
timeoutMs: 30000,
|
||||
runId: "run-1",
|
||||
});
|
||||
|
||||
expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(24);
|
||||
expect(mockedCompactDirect).not.toHaveBeenCalled();
|
||||
expect(result.meta.error?.kind).toBe("retry_limit");
|
||||
expect(result.payloads?.[0]?.isError).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -102,6 +102,9 @@ function createCompactionDiagId(): string {
|
||||
return `ovf-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
}
|
||||
|
||||
// Defensive guard for the outer run loop across all retry branches.
|
||||
const MAX_RUN_RETRY_ITERATIONS = 24;
|
||||
|
||||
const hasUsageValues = (
|
||||
usage: ReturnType<typeof normalizeUsage>,
|
||||
): usage is NonNullable<ReturnType<typeof normalizeUsage>> =>
|
||||
@@ -475,13 +478,42 @@ export async function runEmbeddedPiAgent(
|
||||
}
|
||||
|
||||
const MAX_OVERFLOW_COMPACTION_ATTEMPTS = 3;
|
||||
const MAX_RUN_LOOP_ITERATIONS = MAX_RUN_RETRY_ITERATIONS;
|
||||
let overflowCompactionAttempts = 0;
|
||||
let toolResultTruncationAttempted = false;
|
||||
const usageAccumulator = createUsageAccumulator();
|
||||
let lastRunPromptUsage: ReturnType<typeof normalizeUsage> | undefined;
|
||||
let autoCompactionCount = 0;
|
||||
let runLoopIterations = 0;
|
||||
try {
|
||||
while (true) {
|
||||
if (runLoopIterations >= MAX_RUN_LOOP_ITERATIONS) {
|
||||
const message = `Exceeded retry limit after ${runLoopIterations} attempts.`;
|
||||
log.error(
|
||||
`[run-retry-limit] sessionKey=${params.sessionKey ?? params.sessionId} ` +
|
||||
`provider=${provider}/${modelId} attempts=${runLoopIterations}`,
|
||||
);
|
||||
return {
|
||||
payloads: [
|
||||
{
|
||||
text:
|
||||
"Request failed after repeated internal retries. " +
|
||||
"Please try again, or use /new to start a fresh session.",
|
||||
isError: true,
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
durationMs: Date.now() - started,
|
||||
agentMeta: {
|
||||
sessionId: params.sessionId,
|
||||
provider,
|
||||
model: model.id,
|
||||
},
|
||||
error: { kind: "retry_limit", message },
|
||||
},
|
||||
};
|
||||
}
|
||||
runLoopIterations += 1;
|
||||
attemptedThinking.add(thinkLevel);
|
||||
await fs.mkdir(resolvedWorkspace, { recursive: true });
|
||||
|
||||
|
||||
@@ -36,7 +36,12 @@ export type EmbeddedPiRunMeta = {
|
||||
aborted?: boolean;
|
||||
systemPromptReport?: SessionSystemPromptReport;
|
||||
error?: {
|
||||
kind: "context_overflow" | "compaction_failure" | "role_ordering" | "image_size";
|
||||
kind:
|
||||
| "context_overflow"
|
||||
| "compaction_failure"
|
||||
| "role_ordering"
|
||||
| "image_size"
|
||||
| "retry_limit";
|
||||
message: string;
|
||||
};
|
||||
/** Stop reason for the agent run (e.g., "completed", "tool_calls"). */
|
||||
|
||||
Reference in New Issue
Block a user