fix: align timeout cooldown behavior docs/tests (#22622) (thanks @vageeshkumar)

This commit is contained in:
Peter Steinberger
2026-02-22 15:33:40 +01:00
parent 71d0b86352
commit 3e2849c578
3 changed files with 23 additions and 5 deletions

View File

@@ -67,6 +67,7 @@ Docs: https://docs.openclaw.ai
- Agents/Replies: emit a default completion acknowledgement (`✅ Done.`) when runs execute tools successfully but return no final assistant text, preventing silent no-reply turns after tool-only completions. (#22834) Thanks @Oldshue.
- Agents/Subagents: honor `tools.subagents.tools.alsoAllow` and explicit subagent `allow` entries when resolving built-in subagent deny defaults, so explicitly granted tools (for example `sessions_send`) are no longer blocked unless re-denied in `tools.subagents.tools.deny`. (#23359) Thanks @goren-beehero.
- Agents/Diagnostics: include resolved lifecycle error text in `embedded run agent end` warnings so UI/TUI “Connection error” runs expose actionable provider failure reasons in gateway logs. (#23054) Thanks @Raize.
- Agents/Auth profiles: skip auth-profile cooldown writes for timeout failures in embedded runner rotation so model/network timeouts do not poison same-provider fallback model selection while still allowing in-turn account rotation. (#22622) Thanks @vageeshkumar.
- Plugins/Hooks: run legacy `before_agent_start` once per agent turn and reuse that result across model-resolve and prompt-build compatibility paths, preventing duplicate hook side effects (for example duplicate external API calls). (#23289) Thanks @ksato8710.
- Models/Config: default missing Anthropic provider/model `api` fields to `anthropic-messages` during config validation so custom relay model entries are preserved instead of being dropped by runtime model registry validation. (#23332) Thanks @bigbigmonkey123.
- Gateway/Pairing: treat operator.admin pairing tokens as satisfying operator.write requests so legacy devices stop looping through scope-upgrade prompts introduced in 2026.2.19. (#23125, #23006) Thanks @vignesh07.

View File

@@ -331,6 +331,25 @@ describe("runEmbeddedPiAgent auth profile rotation", () => {
}
});
it("rotates on timeout without cooling down the timed-out profile", async () => {
await withAgentWorkspace(async ({ agentDir, workspaceDir }) => {
await writeAuthStore(agentDir);
mockFailedThenSuccessfulAttempt("request ended without sending any chunks");
await runAutoPinnedOpenAiTurn({
agentDir,
workspaceDir,
sessionKey: "agent:test:timeout-no-cooldown",
runId: "run:timeout-no-cooldown",
});
expect(runEmbeddedAttemptMock).toHaveBeenCalledTimes(2);
const usageStats = await readUsageStats(agentDir);
expect(typeof usageStats["openai:p2"]?.lastUsed).toBe("number");
expect(usageStats["openai:p1"]?.cooldownUntil).toBeUndefined();
});
});
it("does not rotate for compaction timeouts", async () => {
await withAgentWorkspace(async ({ agentDir, workspaceDir }) => {
await writeAuthStore(agentDir);

View File

@@ -949,8 +949,8 @@ export async function runEmbeddedPiAgent(
);
}
// Treat timeout as potential rate limit (Antigravity hangs on rate limit)
// But exclude post-prompt compaction timeouts (model succeeded; no profile issue)
// Rotate on timeout to try another account/model path in this turn,
// but exclude post-prompt compaction timeouts (model succeeded; no profile issue).
const shouldRotate =
(!aborted && failoverFailure) || (timedOut && !timedOutDuringCompaction);
@@ -973,9 +973,7 @@ export async function runEmbeddedPiAgent(
});
}
if (timedOut && !isProbeSession) {
log.warn(
`Profile ${lastProfileId} timed out (possible rate limit). Trying next account...`,
);
log.warn(`Profile ${lastProfileId} timed out. Trying next account...`);
}
if (cloudCodeAssistFormatError) {
log.warn(