From 5cf6e2a4b1d14f113dcb1dfb284ff718bb14ea93 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Fri, 12 Jun 2026 17:31:46 -0700 Subject: [PATCH] [eric] browser: honor the user's selected browser card instead of spawning a new one (selection now reaches sub-agent dispatch + is claimed for the task) --- backend/apps/agents/agent_manager.py | 9 ++++++++- backend/apps/agents/browser/browser_agent.py | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/backend/apps/agents/agent_manager.py b/backend/apps/agents/agent_manager.py index 6abe7937..25e90e3c 100644 --- a/backend/apps/agents/agent_manager.py +++ b/backend/apps/agents/agent_manager.py @@ -1153,7 +1153,14 @@ class AgentManager: os.path.dirname(__file__), "browser_agent_mcp_server.py" ) backend_port = os.environ.get("OPENSWARM_PORT", "8324") - pre_selected_bids = self._get_pre_selected_browser_ids(session.dashboard_id) + # The browser the user picked in select-mode must be driven, not duplicated. + # Put their selection FIRST so the dispatch claims it for the task; keep the + # rest of the dashboard's cards in the list so their host/no-renavigate + # semantics still hold. Without the user's selection here the sub-agent fell + # back to host-based auto-create and opened its own browser. + _user_sel = [b for b in (selected_browser_ids or []) if b] + _all_bids = self._get_pre_selected_browser_ids(session.dashboard_id) + pre_selected_bids = _user_sel + [b for b in _all_bids if b not in _user_sel] from backend.auth import get_auth_token as _get_auth_token _auth_tok = _get_auth_token() mcp_servers["openswarm-browser-agent"] = { diff --git a/backend/apps/agents/browser/browser_agent.py b/backend/apps/agents/browser/browser_agent.py index fafb1a9a..1cfa4907 100644 --- a/backend/apps/agents/browser/browser_agent.py +++ b/backend/apps/agents/browser/browser_agent.py @@ -2273,6 +2273,16 @@ async def run_browser_agents( pre_selected = set(pre_selected_browser_ids or []) + # The user explicitly picked a browser via select-mode, so that card must be driven + # instead of spawning a fresh one. The model often omits browser_id when calling the + # tool, which used to fall through to host-based auto-create (the "it always opens its + # own browser" bug); here we hand each unclaimed selected card to the next task that + # named none, BEFORE the parallel dispatch so it can't race the card-pick lock. + _unclaimed = [b for b in (pre_selected_browser_ids or []) if b] + for _t in tasks: + if not _t.get("browser_id") and _unclaimed: + _t["browser_id"] = _unclaimed.pop(0) + async def _run_one(task_def: dict) -> dict: browser_id = task_def.get("browser_id", "") task_text = task_def.get("task", "")