From e989517c6c057607ed9770386175a4e516b7dc5e Mon Sep 17 00:00:00 2001 From: ciregenz Date: Thu, 30 Jul 2026 20:58:16 -0700 Subject: [PATCH] [eric] lint: de-private the wall budget, trim error_classify under cap, drop stray ws_manager --- backend/apps/agents/browser/browser_agent.py | 4 ++-- backend/apps/agents/core/error_classify.py | 17 +++++------------ backend/tests/test_browser_agent_loop.py | 4 ++-- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/backend/apps/agents/browser/browser_agent.py b/backend/apps/agents/browser/browser_agent.py index 90107a0e..57634785 100644 --- a/backend/apps/agents/browser/browser_agent.py +++ b/backend/apps/agents/browser/browser_agent.py @@ -61,7 +61,7 @@ P_BATCHABLE_ACTION_TOOLS = { # Past this many seconds a run stops exploring and delivers what it has. Sits above every run that # actually succeeded in the 2026-07-30 sweeps (slowest good one: 142.8s) and well under the 300s # that produced an empty answer. It nudges rather than kills, so the answer still comes from Done. -P_WALL_BUDGET_S = 180.0 +WALL_BUDGET_S = 180.0 P_WRAPUP_NUDGE = ( "You've spent several turns looking without finishing. Wrap up NOW: call Done with the " @@ -2052,7 +2052,7 @@ async def run_browser_agent( # task ground past 300s and returned NOTHING, while every run that ever succeeded that # day finished inside 143s. So the clock gets the same nudge the turn cap gets, and the # answer arrives partial-but-honest instead of never. - p_out_of_time = time.time() - metrics_started_at > P_WALL_BUDGET_S + p_out_of_time = time.time() - metrics_started_at > WALL_BUDGET_S if ((turn >= MAX_TURNS - 4 or p_out_of_time) and not wrapup_nudged and not done_called and not send_confirmed): wrapup_nudged = True diff --git a/backend/apps/agents/core/error_classify.py b/backend/apps/agents/core/error_classify.py index d48cbf23..c5c8af7b 100644 --- a/backend/apps/agents/core/error_classify.py +++ b/backend/apps/agents/core/error_classify.py @@ -201,19 +201,12 @@ def parse_retry_after(exc: BaseException, extra_text: str = "") -> int | None: return None -# Transports that fail without saying anything a pattern can read. anthropic.APIConnectionError -# stringifies to the bare "Connection error." (no code, no ECONNRESET, nothing), so the list above -# scores it NON-transient and the retry never fires: one network hiccup then throws away a run that -# was already several steps in, and the user is told "Error: Connection error." Measured live, twice -# in one sweep. A transport failure is transient by construction, so classify it by TYPE, which no -# rewording upstream can break. +# anthropic.APIConnectionError stringifies to the bare "Connection error.", so the patterns above +# score it NON-transient and one network hiccup throws away a whole run (measured live, twice). A +# transport failure is transient by construction, so classify by TYPE, which no rewording breaks. P_TRANSIENT_EXC_TYPES: Tuple[type, ...] = ( - anthropic.APIConnectionError, # APITimeoutError subclasses this - anthropic.InternalServerError, - httpx.TransportError, # connect/read/write/pool timeouts, protocol errors - ConnectionError, - TimeoutError, -) + anthropic.APIConnectionError, anthropic.InternalServerError, # APITimeoutError subclasses the first + httpx.TransportError, ConnectionError, TimeoutError) # connect/read/pool timeouts, protocol errors @typechecked diff --git a/backend/tests/test_browser_agent_loop.py b/backend/tests/test_browser_agent_loop.py index 2dab4119..fed80478 100644 --- a/backend/tests/test_browser_agent_loop.py +++ b/backend/tests/test_browser_agent_loop.py @@ -373,7 +373,7 @@ def test_a_run_out_of_wall_time_delivers_what_it_has(monkeypatch): # clock now gets the same one-shot wrap-up nudge the turn cap gets, so a long errand comes back # partial-but-honest instead of never. BH.BROWSER_HISTORY.clear(); BH.DOMAIN_NOTES.clear() - monkeypatch.setattr(BA, "P_WALL_BUDGET_S", 0.0) # over budget from the first turn + monkeypatch.setattr(BA, "WALL_BUDGET_S", 0.0) # over budget from the first turn primary = FakeLLM([ Resp([p_rp("looking around"), p_tu("BrowserGetText")]), Resp([p_tu("Done", message="Top comment is from u/someone, 387 upvotes.")]), @@ -389,7 +389,7 @@ def test_a_run_out_of_wall_time_delivers_what_it_has(monkeypatch): def test_a_quick_run_is_never_nudged_by_the_wall_budget(monkeypatch): # The budget must not touch normal runs, or it would cut short the very tasks it exists to save. BH.BROWSER_HISTORY.clear(); BH.DOMAIN_NOTES.clear() - assert BA.P_WALL_BUDGET_S >= 150, "budget must sit above the slowest run that actually succeeded" + assert BA.WALL_BUDGET_S >= 150, "budget must sit above the slowest run that actually succeeded" primary = FakeLLM([ Resp([p_rp("reading"), p_tu("BrowserGetText")]), Resp([p_tu("Done", message="It costs $9.99.")]),