Skip to main content

custom-agent-creator

Create and integrate new modular agents for browseruse-bench (BaseAgent in browseruse_bench/agents/, registry import in __init__.py, entry in configs/agent_registry.yaml, runtime config in root config.yaml agents section). Use when a user asks to add/register a new agent, scaffold a custom agent, or implement a new agent based on external docs.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
lexmount/browseruse-agent-bench
آخر نشاط في المصدر
١٣ يوليو ٢٠٢٦ في ١٦:٣٧
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١٩
التفرعات
٥

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
2 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
custom-agent-creator
description
Create and integrate new modular agents for browseruse-bench (BaseAgent in browseruse_bench/agents/, registry import in __init__.py, entry in configs/agent_registry.yaml, runtime config in root config.yaml agents section). Use when a user asks to add/register a new agent, scaffold a custom agent, or implement a new agent based on external docs.
# Custom Agent Creation and Integration ## Minimum Inputs - Confirm Agent name (registry key used in configs/agent_registry.yaml and root config.yaml) - Confirm Python module name (browseruse_bench/agents/<module>.py) - Confirm supported benchmarks (e.g., Online-Mind2Web / BrowseComp / LexBench-Browser) - Collect external docs URL(s); read and extract usable SDK/API details - Define config keys (model_id, api_key, base_url, timeout, SDK-specific options) - Agent runtime config lives in root config.yaml under agents:<agent_name>; model/provider parameters are read from agent_config and injected into SDK constructors directly ## Required References - browseruse_bench/agents/__init__.py (check existing imports before adding) - configs/agent_registry.yaml (check existing agent registrations) ## Load when needed (do NOT read upfront) - references/custom-agent-integration.md — SDK integration patterns - browseruse_bench/agents/base.py — BaseAgent method signatures - browseruse_bench/agents/registry.py — @register_agent internals - browseruse_bench/runner/agent_runner.py — runner entrypoint conventions - browseruse_bench/cli/run.py — extra dependency mapping - browseruse_bench/utils/venv.py — install_agent_dependencies (supports requirements_file) - browseruse_bench/agents/browser_use.py — simple agent reference example - browseruse_bench/agents/agent_tars.py — subprocess-based agent example - browseruse_bench/agents/skyvern.py — async/CDP agent example - docs/en/agents/custom-agent.mdx — user-facing docs template - docs/zh/agents/custom-agent.mdx — Chinese docs template ## Standard Workflow 1) Create module: - browseruse_bench/agents/<agent_module>.py 2) Implement BaseAgent subclass: - Add from __future__ import annotations - PEP8 import order: stdlib → third-party → local - Use typing annotations (Dict, Any, Path) - Do not use print(); use logger - Do not use sys.path.insert - Read all configurable values from agent_config (no hardcoding) - Pass model/provider parameters from agent_config directly into SDK constructors (avoid relying solely on environment variables) - If the upstream SDK has a hardcoded/whitelist model check, do not expose that limitation directly to browseruse-bench users when it can be avoided: use a provider-native bootstrap/default model only for SDK initialization, and after initialization replace the SDK's runtime inference client/engine with your own wrapper that honors the configured `model_id`, `api_key`, and `base_url` - Resolve paths with REPO_ROOT when touching files 3) Register module import: - Add `from browseruse_bench.agents import <agent_module> # noqa: F401` to browseruse_bench/agents/__init__.py 4) Register agent in configs/agent_registry.yaml: - path: browseruse_bench/agents - entrypoint: browseruse_bench/runner/agent_runner.py - venv: .venv (or .venvs/<agent> if it needs an isolated environment) - supported_benchmarks: [...] 5) Add runtime config to root config.yaml under agents:<agent_name>: - active_model: <default_model_key> - models: { <model_key>: { model_id, api_key, base_url, ... } } - browser: { browser_id, ... } (if the agent uses a browser) - defaults: { timeout, max_steps, ... } 6) Add dependencies — two paths depending on whether the agent's deps conflict with core: **Path A — no conflict (happy path):** - Add extra group to pyproject.toml `[project.optional-dependencies]`: `<agent> = ["sdk>=x.y"]` - Map agent name → extra in browseruse_bench/cli/run.py (the `if/elif extra_name` block) - Registry entry uses only `venv: .venvs/<agent>` (no `requirements_file`) - Install: `uv venv .venvs/<agent> && uv pip install --python .venvs/<agent> -e ".[<agent>]"` **Path B — deps conflict with core project (e.g. older openai, older pydantic):** - Do NOT add to pyproject.toml extras (installing `.[extra]` would pull conflicting core deps) - Create `configs/requirements/<agent>.txt` with the SDK and minimum runtime deps: ``` <sdk-package> pydantic>=2.0 PyYAML>=6.0 python-dotenv>=1.0 ``` - Add `requirements_file: configs/requirements/<agent>.txt` to the registry entry - browseruse_bench itself is available via PYTHONPATH — do not add it to the requirements file - install_agent_dependencies() in venv.py auto-detects `requirements_file` and installs from it - No change needed in cli/run.py (extra_name falls through to None; requirements_file takes over) - Install: `uv venv .venvs/<agent> && uv pip install --python .venvs/<agent> -r configs/requirements/<agent>.txt` **How to detect a conflict before committing:** Run `uv pip install --python .venvs/<agent> -e ".[<agent>]"` in a scratch venv first. If uv says "X and Y are incompatible", use Path B. 7) Optional sanity run: - uv run bubench run --agent <agent> --data <benchmark> --mode first_n --count 1 ## Minimal Viable Variant (lean BaseAgent.run_task) - Config keys from the root config.yaml `models`/`browser`/`defaults` sections are **not normalized** at load time — write lowercase in both the YAML and in Python (`model_id`, `base_url`, `browser_id`, `max_steps`, `timeout`, and agent-specific flags like `use_vision`, `flash_mode`). - For common config keys use BaseAgent helpers (defined in `browseruse_bench/agents/base.py`, load when needed): `self.get_model_id(agent_config)`, `self.get_timeout(agent_config)`, `self.get_max_steps(agent_config)`, `self.get_api_key(agent_config, env_var="PROVIDER_API_KEY")`, `self.get_base_url(agent_config, env_var=...)`. These handle key aliases (`timeout`/`timeout_seconds`, `max_steps`/`max_turns`, etc.) and provide safe defaults. For agent-specific flags use `agent_config.get("flag_name")` directly. - LLM branch only on `model_type` → ChatBrowserUse / ChatOpenAI / ChatGoogle; avoid large parameter maps. - Browser session lifecycle must go through `open_browser_session(...)` from `browseruse_bench.browsers`. - Keep provider-specific session create/delete logic in `browseruse_bench/browsers/providers/*.py`; do not duplicate this in agent modules. - In agent code, branch by `session_context.transport` (`local` / `cdp` / `cloud_native`) instead of hardcoding provider SDK logic. - History handling: decode base64 screenshots to `trajectory/`, collect basic actions, steps, end-to-end ms; keep result dict small. - Trajectory screenshots are an expected artifact, not an optional extra: `AgentResult.screenshots` must list the files saved under `trajectory/`. If the agent framework can capture screenshots, make the default rules ask for at least one after reaching the main page and one after finding the answer (see the openclaw/hermes default rules). If capturing is deliberately disabled — for example the only screenshot path also triggers a vision-model call the bench model cannot serve (hermes `browser_vision`) — record that trade-off in the agent module's default rules or a module comment so a run with zero screenshots is explainable, and still keep the collection code path working for the day it is re-enabled. - For provider semantics, routing, workspace, and missing-file edge cases, follow the guidance in `SDK Integration Pitfalls` below instead of repeating those rules in the generated agent. - Error handling: catch specific expected failures (`asyncio.TimeoutError`, `TimeoutError`, `ValueError`, `RuntimeError`), set `status`/`error`; no bare `except`. - Still obey repo rules: no hardcoded secrets/URLs, use `logger`, no `sys.path.insert`, type hints, imports at top, no emojis, resolve paths via `REPO_ROOT` when touching files. ## SDK Integration Pitfalls (learned from SeeAct-style integrations) - Do not assume an SDK's documented provider support is sufficient for browseruse-bench needs. Verify whether it also supports: - custom `base_url` - non-default model IDs - OpenAI-compatible gateways - provider-specific API key env vars - If the SDK reads credentials only from environment variables, isolate that env injection in a narrow setup/restore block. Restore the previous environment values in `finally` so one task run does not leak credentials into another. - Prefer wrapping the SDK's inference engine/client instead of forking or patching the third-party package in-place. Keep browseruse-bench-specific provider normalization in our agent module. - Some SDKs assume task-local artifact subdirectories already exist (`screenshots/`, `dom/`, traces, etc.). If the SDK writes files under the task workspace, proactively create the expected subdirectories after initialization and re-check them before repeated callbacks if the SDK is fragile. - If you use LiteLLM (or a similar router), remember that it may infer the provider from the model name. Example: a model name like `gemini-2.5-pro` may be auto-routed to Vertex/Google even when the user explicitly configured an OpenAI-compatible gateway. In those cases, set the provider explicitly (for example `custom_llm_provider="openai"`) instead of relying on model-name inference. - When wiring official Gemini/Vertex-style multimodal paths, audit runtime-only dependencies required by the router stack (for example `Pillow`, `vertexai`, Google SDK packages). Add them to the isolated requirements file when they are genuinely needed by the selected provider path. - Conversely, do not install provider-specific dependencies just because the model name looks like that provider. If the request is intentionally routed through an OpenAI-compatible gateway, force the router down the OpenAI-compatible path instead of allowing it to import unrelated provider SDKs. - Audit third-party SDK loggers for duplicate terminal output. Some SDKs attach their own `StreamHandler` and also propagate to the root logger, causing every line to appear twice. In our wrapper layer, disable propagation or remove duplicate console handlers while keeping file handlers when needed. - After provider routing changes, run a real smoke task per provider path you claim to support (for example one OPENAI run, one OPENAI_COMPATIBLE run, one GEMINI run if direct Gemini is supported). Unit tests are necessary but not sufficient for SDK/router integrations. - Add focused tests for: - runtime config resolution (`model_type`, `model_id`, api/base selection) - bootstrap model fallback for SDKs with model whitelists - OpenAI-compatible/custom gateway routing - explicit provider override when the model name would otherwise trigger router auto-detection - task-local artifact directory creation - missing screenshot/file fallback behavior - duplicate logger handler deduplication ## Adding a New Browser Backend (required checklist) 1) Add provider implementation: - `browseruse_bench/browsers/providers/<provider>.py` - implement `open(agent_name, agent_config)` and `close(session_context)` 2) Register backend id: - update `browseruse_bench/browsers/registry.py` 3) Dependency and runtime: - optional provider SDK imports must be `ImportError`-safe - fail only when selected backend is used 4) Tests: - add/extend `tests/browseruse_bench/test_browsers.py` - include open-success, missing-credential/dependency, cleanup-failure-tolerated 5) Docs/config updates: - update `docs/en/agents/*.mdx`, `docs/zh/agents/*.mdx` - update quickstart env docs if new env vars are required ## BaseAgent Template (replace <agent_name> and <agent_module>) ```python from __future__ import annotations import logging import time from datetime import UTC, datetime from pathlib import Path from typing import Any, Dict from browseruse_bench.agents.base import BaseAgent from browseruse_bench.agents.registry import register_agent from browseruse_bench.schemas import AgentMetrics, AgentResult logger = logging.getLogger(__name__) @register_agent class <AgentName>(BaseAgent): name = "<agent_name>" def run_task( self, task_info: Dict[str, Any], agent_config: Dict[str, Any], task_workspace: Path, ) -> AgentResult: task_id = task_info.get("task_id", "unknown") task_prompt = self.build_task_prompt(task_info) timeout = self.get_timeout(agent_config) logger.info("Starting task %s", task_id) t0 = time.monotonic() # Implement logic using external SDK/docs. # Save artifacts under task_workspace. return AgentResult( task_id=task_id, timestamp=datetime.now(UTC), env_status="success", # "success" | "failed" agent_done="done", # "done" | "timeout" | "max_steps" | "error" agent_success=True, # True/False only when agent_done=="done", else None answer="", metrics=AgentMetrics(end_to_end_ms=int((time.monotonic() - t0) * 1000), steps=0), ) ``` ## Choose Your Pattern The `BaseAgent Template` above covers the sync/SDK case. Two more integration patterns are common; pick one before coding: | Pattern | Base class | When to use | Example agents | |---------|-----------|-------------|---------------| | **SDK embedding (sync)** | `BaseAgent` | Agent is a Python SDK you call directly, synchronous API | — | | **SDK embedding (async)** | `BaseAgent` + `_run_task_async` | Agent SDK is async (Playwright, httpx-based) | `browser_use.py`, `openai_cua.py`, `skyvern.py` | | **CLI subprocess** | `CLIAgent` | Agent is an external executable (npm, binary) | `agent_tars.py`, `claude_code.py` | Templates B and C below cover the non-sync variants. ## AgentResult Validation Rules `AgentResult` uses `extra="forbid"` — unknown fields cause validation errors. Constraints enforced by `model_validator`: - `agent_success` MUST be `None` when `agent_done != "done"` - `error` MUST be `None` when `env_status == "success"` AND `agent_done == "done"` - `env_status`: `"success"` | `"failed"` - `agent_done`: `"done"` | `"timeout"` | `"max_steps"` | `"error"` Status-setting pattern (use in all templates): ```python if error_msg and "Timeout" in error_msg: env_status, agent_done = "success", "timeout" elif error_msg: env_status, agent_done = "failed", "error" elif steps >= max_steps: env_status, agent_done = "success", "max_steps" else: env_status, agent_done = "success", "done" agent_success = None if agent_done == "done": agent_success = bool(final_answer) ``` ## Error Handling — SDK Exception Catch (critical) Templates only catch generic exceptions (`RuntimeError`, `OSError`, `ValueError`, `TimeoutError`). You **MUST** also catch the agent SDK's base API exception class, or a 401 / rate-limit / bad-request will crash the task runner and skip `result.json`. ```python import <sdk_module> # e.g. import openai as openai_mod try: # ... SDK calls ... except <sdk_module>.APIError as exc: # openai.APIError, stagehand.APIError, etc. error_msg = f"<SDK> API error: {exc}" logger.error("Task %s <SDK> API error: %s", task_id, exc) except (RuntimeError, OSError, ValueError) as exc: error_msg = str(exc) logger.error("Task %s error: %s", task_id, exc) ``` Check the SDK's exception hierarchy (usually `<sdk>.APIError` or `<sdk>.Error` as base) and catch the broadest SDK-specific class. ## Template B — Async BaseAgent For SDKs that are async (Playwright, httpx, modern browser-use SDKs). Wrap `asyncio.run()` in `run_task()`, put the real logic in `_run_task_async()`. ```python from __future__ import annotations import asyncio import logging import time from datetime import UTC, datetime from pathlib import Path from typing import Any
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub