From dfff42d3ddb2d23976e6047c70338f62aa1d004d Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Thu, 27 Aug 2026 04:39:19 -0700 Subject: [PATCH] refactor(browser_exec): schema diet 803->663 tok/call, A/B-gated; eval harness runs on Windows + Nous auth (#96300) --- evals/browser_use/orchestrate.py | 8 ++++++- evals/browser_use/single_run.py | 30 +++++++++++++++++++---- tools/browser_use_cli.py | 41 +++++++++++++------------------- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/evals/browser_use/orchestrate.py b/evals/browser_use/orchestrate.py index 010a1966a6..678708430e 100644 --- a/evals/browser_use/orchestrate.py +++ b/evals/browser_use/orchestrate.py @@ -52,7 +52,13 @@ if os.path.exists(args.results): def reset_browser_state(): """Kill lingering drivers and clear cookies between cells.""" - subprocess.run(["pkill", "-f", "agent-browser"], capture_output=True) + if sys.platform == "win32": + subprocess.run( + ["taskkill", "/F", "/IM", "agent-browser.exe", "/T"], + capture_output=True, + ) + else: + subprocess.run(["pkill", "-f", "agent-browser"], capture_output=True) code = "cdp('Network.clearBrowserCookies')\nprint('cleared')\n" try: subprocess.run( diff --git a/evals/browser_use/single_run.py b/evals/browser_use/single_run.py index 411ca4a194..6015656fb1 100644 --- a/evals/browser_use/single_run.py +++ b/evals/browser_use/single_run.py @@ -77,7 +77,9 @@ logging.disable(logging.CRITICAL) import run_agent # noqa: E402 -assert run_agent.__file__.startswith(WT), f"wrong tree: {run_agent.__file__}" +_loaded = os.path.normcase(os.path.normpath(run_agent.__file__)) +_want = os.path.normcase(os.path.normpath(WT)) +assert _loaded.startswith(_want), f"wrong tree: {run_agent.__file__}" if ARM == "prns": # Strip the helpers digest from the schema: header-only description. @@ -89,10 +91,30 @@ if ARM == "prns": from run_agent import AIAgent # noqa: E402 +# Provider resolution: default openrouter (original battery), but allow the +# Nous-subscription path on boxes without an OpenRouter key. Credentials are +# resolved through the product's own auth state, never printed. +_or_key = os.environ.get("OPENROUTER_API_KEY", "").strip() +if _or_key: + _agent_auth = dict( + base_url="https://openrouter.ai/api/v1", + api_key=_or_key, + provider="openrouter", + ) +else: + # Resolved by the orchestrator BEFORE HERMES_HOME is redirected to the + # throwaway home (auth state lives in the real profile). Never printed. + _tok = os.environ.get("BUBENCH_NOUS_TOKEN", "").strip() + if not _tok: + raise SystemExit("no OPENROUTER_API_KEY and no Nous auth available") + _agent_auth = dict( + base_url=os.environ.get("BUBENCH_NOUS_BASE_URL", "https://inference-api.nousresearch.com/v1"), + api_key=_tok, + provider="nous", + ) + agent = AIAgent( - base_url="https://openrouter.ai/api/v1", - api_key=os.environ["OPENROUTER_API_KEY"], - provider="openrouter", + **_agent_auth, model=MODEL, max_iterations=30, quiet_mode=True, diff --git a/tools/browser_use_cli.py b/tools/browser_use_cli.py index 23dbd24bed..8e9d719121 100644 --- a/tools/browser_use_cli.py +++ b/tools/browser_use_cli.py @@ -822,32 +822,25 @@ def browser_exec( # The tool description is the CLI's skill, fetched from browser-use skill _HEADER_BASE = ( - "Drive a real web browser via the Browser Use CLI. The `code` argument " - "is piped verbatim to the `browser-use` CLI on stdin and executed as " - "full Python (standard library available) with the CLI's pre-imported " - "browser helpers; stdout comes back in the result. Start `code` with a " - "one-line comment describing the step for the user in plain, " - "non-technical language, max 60 chars (e.g. `# Searching Amazon for " - "paper towels`) — the UI displays it as the step label.\n\n" - "STATE: the browser session and the workspace persist across calls; " - "Python variables do NOT (each call is a fresh interpreter). The " - "workspace is a stable directory — path in $BH_AGENT_WORKSPACE and " - "returned as `workspace` in every result. For multi-item tasks " - "('collect all N products / every entry / the full table'), append each " - "batch to a JSON/CSV file in the workspace as you go, then read it back " - "to assemble the final answer; define reusable functions in " - "agent_helpers.py there — the harness auto-imports it into every call. " - "Do aggregation in code, not in your head: dedupe, count, sort, and " - "format with Python inside the exec. Before giving a final answer on a " - "multi-item task, verify the collected count against what was asked " - "and go back for anything missing.\n\n" + "Drive a real web browser via the Browser Use CLI: `code` runs as full " + "Python (stdlib available) with pre-imported browser helpers; stdout " + "comes back in the result. Start `code` with a one-line comment " + "describing the step for the user in plain language, max 60 chars " + "(e.g. `# Searching Amazon for paper towels`) — the UI shows it as the " + "step label.\n\n" + "STATE: the browser session and workspace persist across calls; Python " + "variables do NOT (fresh interpreter each call). The workspace dir is " + "$BH_AGENT_WORKSPACE (also `workspace` in every result); functions " + "defined in agent_helpers.py there are auto-imported into every call. " + "For multi-item tasks ('all N products / every entry'), append each " + "batch to a JSON/CSV file in the workspace, then read it back and " + "aggregate in code — dedupe/count/sort with Python, not in your head — " + "and verify the collected count against what was asked before " + "answering.\n\n" "Batch each sub-procedure (navigate, wait, extract, act) into one call " "— do not spend a call per action — but for long extractions prefer " "several medium calls that append to workspace files over one giant " - "call, so progress survives timeouts. For an isolated concurrent " - "browser session (parallel tasks that must not share tabs), pass " - "session= (never BU_NAME env syntax) and reuse the same name on " - "every related call." + "call, so progress survives timeouts." ) _HEADER_VISION = ( @@ -967,7 +960,7 @@ BROWSER_EXEC_SCHEMA = { }, "session": { "type": "string", - "description": "Named isolated browser session (sets BU_NAME): each name gets its own harness daemon — and on cloud backends its own browser — so concurrent tasks don't clobber each other. Omit for the shared default session. Reuse the same name across calls to keep working in that session (and the name passed to start_remote_daemon(), if used).", + "description": "Named isolated browser session — its own daemon and (on cloud backends) own browser, so concurrent tasks don't share tabs. Reuse the same name on every related call; omit for the shared default session.", }, "timeout_s": { "type": "integer",