[eric] browser: dead-dashboard dispatches fail in 1s instead of burning turns, recovery skips systemic causes

This commit is contained in:
ciregenz
2026-06-05 15:56:38 -07:00
parent dde8186762
commit 2c55d17f50
4 changed files with 38 additions and 2 deletions
+7 -2
View File
@@ -3386,8 +3386,13 @@ class AgentManager:
if not text:
text = await _dispatch(browser_fast_path.compose_task(prompt, brief))
if browser_fast_path.dispatch_failed(text):
logger.info(f"[browser-fast-path] first dispatch failed for {session_id}; one recovery dispatch")
text = await _dispatch(browser_fast_path.recovery_task(prompt, text))
# Retry only transient failures; a dead dashboard fails the
# retry identically, so skip it and tell the user instead.
if ws_manager.global_connections:
logger.info(f"[browser-fast-path] first dispatch failed for {session_id}; one recovery dispatch")
text = await _dispatch(browser_fast_path.recovery_task(prompt, text))
else:
text = browser_fast_path.NO_DASHBOARD_REPLY
if not text:
text = "The browser agent couldn't complete this and gave no report."
except asyncio.CancelledError:
@@ -1596,6 +1596,19 @@ async def run_browser_agents(
"""
pass # Browser agent launch captured via session dump
# No dashboard renderer means every browser command is dead on arrival;
# failing here saves the 2-5 LLM turns a sub burns narrating timeouts at a
# corpse before card-gone detection trips.
if not ws_manager.global_connections:
logger.warning("[browser-agent] dispatch refused: no dashboard connected")
return [{
"summary": (
"Error: no dashboard window is connected, so browser tools cannot run. "
"Tell the user to open the OpenSwarm window and try again; do not retry until they do."
),
"action_log": [], "final_screenshot": None,
} for _ in tasks]
pre_selected = set(pre_selected_browser_ids or [])
async def _run_one(task_def: dict) -> dict:
@@ -125,6 +125,12 @@ def dispatch_failed(summary: str) -> bool:
return not ("OUTCOME: DONE" in s.upper() or "learned skill replay" in s)
NO_DASHBOARD_REPLY = (
"I can't drive a browser right now because no OpenSwarm window is connected. "
"Open the app window and send this again."
)
def recovery_task(prompt: str, first_report: str) -> str:
"""One informed retry, replacing the orchestrator's recovery role. Verify-
first wording keeps a maybe-already-sent irreversible step from repeating."""
+12
View File
@@ -92,3 +92,15 @@ def test_text_normalizes_to_message_without_phone_number():
assert _normalize_for_classifier(sms) == sms
count = "count messages containing the exact text r10-os"
assert "message r10-os" in _normalize_for_classifier(count)
def test_dispatch_refused_instantly_when_no_dashboard_connected():
import asyncio
from backend.apps.agents.browser.browser_agent import run_browser_agents
from backend.apps.agents.core.ws_manager import ws_manager
assert not ws_manager.global_connections
results = asyncio.run(run_browser_agents(tasks=[{"task": "go to example.com"}], model="sonnet"))
assert len(results) == 1
assert results[0]["summary"].startswith("Error: no dashboard window is connected")
assert dispatch_failed(results[0]["summary"])