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
최근 소스 활동
2026년 7월 13일 16:37
감지된 SKILL.md 언어
영어
스타
19
포크
5

설치 방법

기본적으로 소스를 먼저 확인하는 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에서 보기