diff --git a/backend/apps/agents/browser/browser_agent.py b/backend/apps/agents/browser/browser_agent.py index 42fb86cd..b4a7d6e9 100644 --- a/backend/apps/agents/browser/browser_agent.py +++ b/backend/apps/agents/browser/browser_agent.py @@ -151,22 +151,6 @@ def p_app_output_id(browser_id: str) -> str | None: return browser_id[4:] if browser_id.startswith("app:") else None -def p_app_workspace_dir(browser_id: str) -> str | None: - """Resolve the on-disk workspace folder for an `app:` target.""" - oid = p_app_output_id(browser_id) - if not oid: - return None - try: - from backend.apps.outputs.workspace_io import load_output - from backend.config.paths import OUTPUTS_WORKSPACE_DIR - out = load_output(oid) - if not out or not getattr(out, "workspace_id", None): - return None - return os.path.join(OUTPUTS_WORKSPACE_DIR, out.workspace_id) - except Exception: - return None - - def render_app_controls(describe_value: object) -> tuple[str, str] | None: """From a decoded describe() value build (rules_md, controls_md). Returns None when the value is not a ready, usable describe.""" @@ -194,29 +178,6 @@ def render_app_controls(describe_value: object) -> tuple[str, str] | None: return rules_md, controls_md -def p_persist_app_controls(browser_id: str, describe_value: object) -> None: - """Cache rules.md + controls.md into the app workspace so the agent reads them - up front and only re-describes when controls change. Best-effort; written - under .openswarm/ so they stay out of the app's own file tree.""" - rendered = render_app_controls(describe_value) - if not rendered: - return - folder = p_app_workspace_dir(browser_id) - if not folder or not os.path.isdir(folder): - return - rules_md, controls_md = rendered - try: - cache_dir = os.path.join(folder, ".openswarm") - os.makedirs(cache_dir, exist_ok=True) - with open(os.path.join(cache_dir, "controls.md"), "w", encoding="utf-8") as f: - f.write(controls_md) - if rules_md: - with open(os.path.join(cache_dir, "rules.md"), "w", encoding="utf-8") as f: - f.write(rules_md) - except Exception: - logger.debug("[app-agent] failed to persist controls cache", exc_info=True) - - # Single-tool names -> the sub-action type they map to, so one summarizer covers # both BrowserPressKey({key}) and a batch's {"type":"press_key","params":{key}}. P_SINGLE_ACTION_TYPE = { @@ -286,10 +247,6 @@ async def execute_browser_tool( tool_name: str, tool_input: dict, browser_id: str, tab_id: str = "", ) -> dict: """Execute a browser tool via ws_manager directly (no MCP/HTTP round-trip).""" - # [app-agent] step trace: only for app targets / bridge tools so normal - # browser-agent runs stay quiet. Greppable prefix; remove when done. - p_trace = browser_id.startswith("app:") or tool_name in APP_BRIDGE_TOOLS - # One greppable line naming the actual buttons/keys/selectors this call drives, # so a run reads as "key:ArrowRight x5" rather than an opaque tool name. Fires # for action tools only (reads stay quiet) and ungated so web runs get it too. @@ -306,12 +263,7 @@ async def execute_browser_tool( async def p_eval_once() -> dict: rid = uuid4().hex - if p_trace: - logger.info(f"[app-agent] DISPATCH {tool_name} -> {browser_id} (req {rid[:8]}) js={expr[:120]}") - r = await ws_manager.send_browser_command(rid, action, browser_id, params, tab_id=tab_id) - if p_trace: - logger.info(f"[app-agent] RESULT {tool_name} <- {browser_id}: {json.dumps(r)[:300]}") - return r + return await ws_manager.send_browser_command(rid, action, browser_id, params, tab_id=tab_id) result = await p_eval_once() # Reads poll for the bridge to come up (app still mounting on turn 1). @@ -334,8 +286,6 @@ async def execute_browser_tool( p_bridge_known_absent.discard(browser_id) else: p_bridge_known_absent.add(browser_id) - if tool_name == "AppDescribe": - p_persist_app_controls(browser_id, parse_bridge_result(result)) return result action = ACTION_MAP.get(tool_name) @@ -344,13 +294,9 @@ async def execute_browser_tool( params = {k: v for k, v in tool_input.items()} request_id = uuid4().hex - if p_trace: - logger.info(f"[app-agent] DISPATCH {tool_name}/{action} -> {browser_id} (req {request_id[:8]})") result = await ws_manager.send_browser_command( request_id, action, browser_id, params, tab_id=tab_id, ) - if p_trace: - logger.info(f"[app-agent] RESULT {tool_name} <- {browser_id}: {json.dumps(result)[:300]}") return result @@ -604,9 +550,6 @@ async def run_browser_agent( p_browser_perms = load_builtin_permissions() - if app_mode: - logger.info(f"[app-agent] START loop: browser_id={browser_id} task={task[:140]!r}") - session_id = uuid4().hex cancel_event = asyncio.Event() session = AgentSession( diff --git a/backend/main.py b/backend/main.py index 5505aba4..7905f39d 100644 --- a/backend/main.py +++ b/backend/main.py @@ -485,14 +485,6 @@ async def browser_agent_run(request: Request): if not tasks: return JSONResponse({"error": "tasks array is required"}, status_code=400) - # [app-agent] step trace: log app-mode dispatches arriving at the route. - for p_t in tasks: - if p_t.get("app_mode") or str(p_t.get("browser_id", "")).startswith("app:"): - logger.info( - f"[app-agent] ROUTE /run: browser_id={p_t.get('browser_id')!r} " - f"app_mode={p_t.get('app_mode')} task={str(p_t.get('task',''))[:120]!r}" - ) - results = await run_browser_agents( tasks=tasks, model=model, diff --git a/backend/tests/test_app_agent.py b/backend/tests/test_app_agent.py index 943b48bd..9a555a29 100644 --- a/backend/tests/test_app_agent.py +++ b/backend/tests/test_app_agent.py @@ -203,7 +203,6 @@ def test_app_describe_polls_until_bridge_ready(monkeypatch): monkeypatch.setattr(BA.ws_manager, "send_browser_command", p_send, raising=False) monkeypatch.setattr(BA.asyncio, "sleep", p_no_sleep, raising=True) - monkeypatch.setattr(BA, "p_persist_app_controls", lambda *a, **k: None, raising=True) out = asyncio.run(BA.execute_browser_tool("AppDescribe", {}, "app:abc")) assert calls["n"] == 3 # polled twice, succeeded on the third @@ -225,19 +224,3 @@ def test_app_invoke_does_not_poll(monkeypatch): asyncio.run(BA.execute_browser_tool("AppInvoke", {"name": "flap"}, "app:abc")) assert calls["n"] == 1 # single shot, no readiness wait - - -def test_app_describe_persists_controls_cache(monkeypatch, tmp_path): - ready = {"rules": "Keep the bird airborne.", "controls": [{"name": "flap", "keys": "Space"}], "__rev": 1} - - async def p_send(request_id, action, browser_id, params, tab_id=""): - return {"text": json.dumps(ready)} - - monkeypatch.setattr(BA.ws_manager, "send_browser_command", p_send, raising=False) - monkeypatch.setattr(BA, "p_app_workspace_dir", lambda bid: str(tmp_path), raising=True) - - asyncio.run(BA.execute_browser_tool("AppDescribe", {}, "app:abc")) - controls = (tmp_path / ".openswarm" / "controls.md").read_text() - rules = (tmp_path / ".openswarm" / "rules.md").read_text() - assert "- `flap`" in controls and "[Space]" in controls - assert "Keep the bird airborne." in rules diff --git a/frontend/src/shared/browserCommandHandler.ts b/frontend/src/shared/browserCommandHandler.ts index e2cdbe4c..506c02e8 100644 --- a/frontend/src/shared/browserCommandHandler.ts +++ b/frontend/src/shared/browserCommandHandler.ts @@ -1,4 +1,4 @@ -import { getWebview, registeredKeys, type BrowserWebview } from './browserRegistry'; +import { getWebview, type BrowserWebview } from './browserRegistry'; import { store } from './state/store'; import { resumeBrowserCard } from './state/dashboardLayoutSlice'; import { dashboardWs } from './ws/WebSocketManager'; @@ -1339,13 +1339,8 @@ async function handleReplayRoute(wv: BrowserWebview, params: Record async function handleEvaluate(wv: BrowserWebview, params: Record): Promise> { const expression = params.expression as string; if (!expression) return { error: 'expression parameter is required' }; - // [app-agent] step trace: surface what the app's bridge actually returned. - const _bridgeCall = expression.includes('OPENSWARM_APP'); try { const result = await wv.executeJavaScript(expression); - if (_bridgeCall) { - console.log(`[app-agent] BRIDGE eval -> ${typeof result === 'string' ? result : JSON.stringify(result)}`); - } const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2); // evaluate is the agent's main read path; sample routes here too (XHRs have fired by now) so the backend can surface the fast network tier once. const routes_available = await countSafeRoutes(wv); @@ -1405,27 +1400,14 @@ async function runBrowserCommand( request_id: string, action: string, browser_id: string, tab_id: string | undefined, params: Record, ) { - // [app-agent] step trace: only for app targets so browser-agent runs stay quiet. - const _appTrace = String(browser_id || '').startsWith('app:'); - if (_appTrace) { - console.log(`[app-agent] CMD recv: action=${action} browser_id=${browser_id} tab_id=${tab_id ?? ''} registered=[${registeredKeys().join(', ')}]`); - } const wv = await awaitWebview(browser_id, tab_id || undefined); if (!wv) { - if (_appTrace) { - console.warn(`[app-agent] LOOKUP MISS: no webview for '${browser_id}' (registered keys: [${registeredKeys().join(', ')}]) -> the app card isn't mounted on the active dashboard`); - } dashboardWs.send('browser:result', { request_id, error: `Browser card '${browser_id}'${tab_id ? ` tab '${tab_id}'` : ''} not found or not an Electron webview`, }); return; } - if (_appTrace) { - let _url = ''; - try { _url = wv.getURL(); } catch (_e) {} - console.log(`[app-agent] LOOKUP HIT: webview for '${browser_id}' found, url=${_url} loading=${(() => { try { return wv.isLoading(); } catch { return '?'; } })()}`); - } const detail = params.url || params.selector || params.expression || undefined; setActivity(browser_id, { action: action as BrowserAction, detail }); diff --git a/frontend/src/shared/browserRegistry.ts b/frontend/src/shared/browserRegistry.ts index e91c484e..21e5967d 100644 --- a/frontend/src/shared/browserRegistry.ts +++ b/frontend/src/shared/browserRegistry.ts @@ -54,11 +54,6 @@ export function setActiveTab(browserId: string, tabId: string): void { activeTabMap.set(browserId, tabId); } -// [app-agent] diagnostic: list currently-registered keys ("browserId:tabId"). -export function registeredKeys(): string[] { - return Array.from(registry.keys()); -} - export function getWebview(browserId: string, tabId?: string): BrowserWebview | undefined { const resolvedTabId = tabId || activeTabMap.get(browserId); if (!resolvedTabId) return undefined;