mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 11:08:37 +00:00
fix(agents): raise dynamic retry cap budget
This commit is contained in:
@@ -31,7 +31,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
- Security/Agents: cap embedded Pi runner outer retry loop to 24 attempts and return an explicit `retry_limit` error payload when retries never converge, preventing unbounded internal retry cycles (`GHSA-76m6-pj3w-v7mf`).
|
- Security/Agents: cap embedded Pi runner outer retry loop with a higher profile-aware dynamic limit (32-160 attempts) and return an explicit `retry_limit` error payload when retries never converge, preventing unbounded internal retry cycles (`GHSA-76m6-pj3w-v7mf`).
|
||||||
- Telegram: detect duplicate bot-token ownership across Telegram accounts at startup/status time, mark secondary accounts as not configured with an explicit fix message, and block duplicate account startup before polling to avoid endless `getUpdates` conflict loops.
|
- Telegram: detect duplicate bot-token ownership across Telegram accounts at startup/status time, mark secondary accounts as not configured with an explicit fix message, and block duplicate account startup before polling to avoid endless `getUpdates` conflict loops.
|
||||||
- Agents/Tool images: include source filenames in `agents/tool-images` resize logs so compression events can be traced back to specific files.
|
- Agents/Tool images: include source filenames in `agents/tool-images` resize logs so compression events can be traced back to specific files.
|
||||||
- Providers/OAuth: harden Qwen and Chutes refresh handling by validating refresh response expiry values and preserving prior refresh tokens when providers return empty refresh token fields, with regression coverage for empty-token responses.
|
- Providers/OAuth: harden Qwen and Chutes refresh handling by validating refresh response expiry values and preserving prior refresh tokens when providers return empty refresh token fields, with regression coverage for empty-token responses.
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ describe("runEmbeddedPiAgent overflow compaction trigger routing", () => {
|
|||||||
runId: "run-1",
|
runId: "run-1",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(24);
|
expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(32);
|
||||||
expect(mockedCompactDirect).not.toHaveBeenCalled();
|
expect(mockedCompactDirect).not.toHaveBeenCalled();
|
||||||
expect(result.meta.error?.kind).toBe("retry_limit");
|
expect(result.meta.error?.kind).toBe("retry_limit");
|
||||||
expect(result.payloads?.[0]?.isError).toBe(true);
|
expect(result.payloads?.[0]?.isError).toBe(true);
|
||||||
|
|||||||
@@ -103,7 +103,17 @@ function createCompactionDiagId(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Defensive guard for the outer run loop across all retry branches.
|
// Defensive guard for the outer run loop across all retry branches.
|
||||||
const MAX_RUN_RETRY_ITERATIONS = 24;
|
const BASE_RUN_RETRY_ITERATIONS = 24;
|
||||||
|
const RUN_RETRY_ITERATIONS_PER_PROFILE = 8;
|
||||||
|
const MIN_RUN_RETRY_ITERATIONS = 32;
|
||||||
|
const MAX_RUN_RETRY_ITERATIONS = 160;
|
||||||
|
|
||||||
|
function resolveMaxRunRetryIterations(profileCandidateCount: number): number {
|
||||||
|
const scaled =
|
||||||
|
BASE_RUN_RETRY_ITERATIONS +
|
||||||
|
Math.max(1, profileCandidateCount) * RUN_RETRY_ITERATIONS_PER_PROFILE;
|
||||||
|
return Math.min(MAX_RUN_RETRY_ITERATIONS, Math.max(MIN_RUN_RETRY_ITERATIONS, scaled));
|
||||||
|
}
|
||||||
|
|
||||||
const hasUsageValues = (
|
const hasUsageValues = (
|
||||||
usage: ReturnType<typeof normalizeUsage>,
|
usage: ReturnType<typeof normalizeUsage>,
|
||||||
@@ -478,7 +488,7 @@ export async function runEmbeddedPiAgent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MAX_OVERFLOW_COMPACTION_ATTEMPTS = 3;
|
const MAX_OVERFLOW_COMPACTION_ATTEMPTS = 3;
|
||||||
const MAX_RUN_LOOP_ITERATIONS = MAX_RUN_RETRY_ITERATIONS;
|
const MAX_RUN_LOOP_ITERATIONS = resolveMaxRunRetryIterations(profileCandidates.length);
|
||||||
let overflowCompactionAttempts = 0;
|
let overflowCompactionAttempts = 0;
|
||||||
let toolResultTruncationAttempted = false;
|
let toolResultTruncationAttempted = false;
|
||||||
const usageAccumulator = createUsageAccumulator();
|
const usageAccumulator = createUsageAccumulator();
|
||||||
@@ -488,10 +498,13 @@ export async function runEmbeddedPiAgent(
|
|||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (runLoopIterations >= MAX_RUN_LOOP_ITERATIONS) {
|
if (runLoopIterations >= MAX_RUN_LOOP_ITERATIONS) {
|
||||||
const message = `Exceeded retry limit after ${runLoopIterations} attempts.`;
|
const message =
|
||||||
|
`Exceeded retry limit after ${runLoopIterations} attempts ` +
|
||||||
|
`(max=${MAX_RUN_LOOP_ITERATIONS}).`;
|
||||||
log.error(
|
log.error(
|
||||||
`[run-retry-limit] sessionKey=${params.sessionKey ?? params.sessionId} ` +
|
`[run-retry-limit] sessionKey=${params.sessionKey ?? params.sessionId} ` +
|
||||||
`provider=${provider}/${modelId} attempts=${runLoopIterations}`,
|
`provider=${provider}/${modelId} attempts=${runLoopIterations} ` +
|
||||||
|
`maxAttempts=${MAX_RUN_LOOP_ITERATIONS}`,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
payloads: [
|
payloads: [
|
||||||
|
|||||||
Reference in New Issue
Block a user