mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-10-01 05:54:56 +02:00
[eric] browser: dead-dashboard dispatches fail in 1s instead of burning turns, recovery skips systemic causes
This commit is contained in:
@@ -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."""
|
||||
|
||||
@@ -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"])
|
||||
|
||||
Reference in New Issue
Block a user