mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix: stop LLM retry loop when browser control service is unavailable (#17673)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 90f47fe132
Co-authored-by: tag-assistant <260167501+tag-assistant@users.noreply.github.com>
Co-authored-by: sebslight <19554889+sebslight@users.noreply.github.com>
Reviewed-by: @sebslight
This commit is contained in:
@@ -38,6 +38,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Web Fetch/Security: cap downloaded response body size before HTML parsing to prevent memory exhaustion from oversized or deeply nested pages. Thanks @xuemian168.
|
||||
- Skills/Security: restrict `download` installer `targetDir` to the per-skill tools directory to prevent arbitrary file writes. Thanks @Adam55A-code.
|
||||
- Agents: return an explicit timeout error reply when an embedded run times out before producing any payloads, preventing silent dropped turns during slow cache-refresh transitions. (#16659) Thanks @liaosvcaf and @vignesh07.
|
||||
- Browser/Agents: when browser control service is unavailable, return explicit non-retry guidance (instead of "try again") so models do not loop on repeated browser tool calls until timeout. (#17673) Thanks @austenstone.
|
||||
- Agents/OpenAI: force `store=true` for direct OpenAI Responses/Codex runs to preserve multi-turn server-side conversation state, while leaving proxy/non-OpenAI endpoints unchanged. (#16803) Thanks @mark9232 and @vignesh07.
|
||||
- Agents/Security: sanitize workspace paths before embedding into LLM prompts (strip Unicode control/format chars) to prevent instruction injection via malicious directory names. Thanks @aether-ai-agent.
|
||||
- Agents/Context: apply configured model `contextWindow` overrides after provider discovery so `lookupContextTokens()` honors operator config values (including discovery-failure paths). (#17404) Thanks @michaelbship and @vignesh07.
|
||||
|
||||
@@ -90,9 +90,16 @@ function withLoopbackBrowserAuth(
|
||||
}
|
||||
|
||||
function enhanceBrowserFetchError(url: string, err: unknown, timeoutMs: number): Error {
|
||||
const hint = isAbsoluteHttp(url)
|
||||
? "If this is a sandboxed session, ensure the sandbox browser is running and try again."
|
||||
: `Start (or restart) the OpenClaw gateway (OpenClaw.app menubar, or \`${formatCliCommand("openclaw gateway")}\`) and try again.`;
|
||||
const isLocal = !isAbsoluteHttp(url);
|
||||
// Human-facing hint for logs/diagnostics.
|
||||
const operatorHint = isLocal
|
||||
? `Restart the OpenClaw gateway (OpenClaw.app menubar, or \`${formatCliCommand("openclaw gateway")}\`).`
|
||||
: "If this is a sandboxed session, ensure the sandbox browser is running.";
|
||||
// Model-facing suffix: explicitly tell the LLM NOT to retry.
|
||||
// Without this, models see "try again" and enter an infinite tool-call loop.
|
||||
const modelHint =
|
||||
"Do NOT retry the browser tool — it will keep failing. " +
|
||||
"Use an alternative approach or inform the user that the browser is currently unavailable.";
|
||||
const msg = String(err);
|
||||
const msgLower = msg.toLowerCase();
|
||||
const looksLikeTimeout =
|
||||
@@ -103,10 +110,12 @@ function enhanceBrowserFetchError(url: string, err: unknown, timeoutMs: number):
|
||||
msgLower.includes("aborterror");
|
||||
if (looksLikeTimeout) {
|
||||
return new Error(
|
||||
`Can't reach the OpenClaw browser control service (timed out after ${timeoutMs}ms). ${hint}`,
|
||||
`Can't reach the OpenClaw browser control service (timed out after ${timeoutMs}ms). ${operatorHint} ${modelHint}`,
|
||||
);
|
||||
}
|
||||
return new Error(`Can't reach the OpenClaw browser control service. ${hint} (${msg})`);
|
||||
return new Error(
|
||||
`Can't reach the OpenClaw browser control service. ${operatorHint} ${modelHint} (${msg})`,
|
||||
);
|
||||
}
|
||||
|
||||
async function fetchHttpJson<T>(
|
||||
|
||||
Reference in New Issue
Block a user