Files
codex-app-server/cloud/skills/browser-automation/SKILL.md
T
host da7a9950fb feat: platform browser multi-tab, navigation allowlist, close cleanup, egress filter, allowlist worker wiring
- Multi-tab: browser_new_page / browser_list_pages /
  browser_switch_page / browser_close_page in playwright_mcp.py;
  each new page gets a fresh Playwright context, so cookies and
  storage are isolated between pages. Single-page tools act on
  the current page; switching to a missing index is an error,
  not a crash; closing the last page is an error (use
  browser_close).
- Navigation allowlist: BROWSER_ALLOWED_HOSTS (comma list,
  leading-dot suffix match, case/port-insensitive) checked in
  _check_allowed_url before launching Chromium; unset (or empty)
  means no check, the old behaviour. file:// always allowed;
  localhost/127.0.0.1 have no special treatment.
- Close cleanup: browser_close closes all pages and best-effort
  removes cwd browser-live.png / browser-live.json; custom
  screenshot files are untouched. list_pages needs no launch.
- Egress filter: 10 programming-source Tinyproxy BASIC rules
  (python.org, nodejs.org, go.dev, pkg.go.dev, rust-lang.org,
  developer.mozilla.org, crates.io, stackoverflow.com,
  cve.mitre.org, nvd.nist.gov); already-present github.com /
  pypi.org / npmjs.org not duplicated; searx.diante.me stays
  exact-only, no diante.me wildcard.
- Allowlist worker wiring: _docker_task_context now passes a
  set, non-empty BROWSER_ALLOWED_HOSTS from the worker env into
  [mcp_servers.playwright.env] in the tenant config, so the MCP
  process actually sees it (container -e alone does not reach
  MCP subprocesses, 2026-10-30). Unset/empty writes nothing and
  never overwrites; the value never goes into logs; it is not
  added to the websearch env block or the container env.
  ensure_playwright_mcp_env now returns False without rewriting
  when the result would be identical (canonical join: one blank
  line before the block), so a second prep leaves an unchanged
  tenant config alone; other sections untouched.
- Skill + docs: browser-automation SKILL.md multi-tab/allowlist
  section; docs/platform-browser.md comparison doc (new file).
- Tests (mock/fake only, no network, no real Chromium, no real
  credentials): cloud.tests.test_playwright +
  cloud.tests.test_websearch_worker, 48 tests OK, including 6
  new wiring tests (switch off passes no variable, switch on
  reaches MCP env verbatim, empty never written, old-tenant
  merge idempotent + no-rewrite, ensure no-op when identical,
  allowlist enforces only after wiring).
- NOT done (see PR body): no persistent profile, no credential
  vault, no approval card, no CAPTCHA bypass, in-page link
  navigation does not pass the allowlist, no real-Chromium live
  verification, host tinyproxy filter not reloaded.
2026-11-01 08:34:13 +00:00

98 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: browser-automation
description: >
Use when a task needs a real browser: pages that render with
JavaScript, clicking through pagination or forms, filling and
submitting input, or taking a screenshot of what a page
actually looks like. For a plain static page or a quick fact,
use web_fetch / web_search first; open the browser only when
static fetch cannot see the content.
---
## 工具
`browser_navigate`(打开 URL,返回最终 URL 与标题)、
`browser_snapshot`(当前页标题、URL、正文,超 8000 字截断并标记)、
`browser_click`(按 CSS 选择器或 `text=...` 点击)、
`browser_fill`(按选择器填表)、
`browser_evaluate`(在页内跑 JS 表达式,返回字符串,限 4000 字)、
`browser_screenshot`(把当前页存成工作区内的 PNG,返回绝对路径与字节数)、
`browser_click_at`(按视口坐标点击,坐标系为 1280x800、原点左上角,
是 live 视图里用户点击的落点)、
`browser_live_shot`(把当前画面存成固定文件 browser-live.png,
附带 browser-live.json 状态:URL、标题、时间戳,供 watcher 轮询)、
`browser_close`(关闭浏览器,可重复调用)。
浏览器是单页的:一次 navigate,之后 snapshot / click / fill /
screenshot 都针对同一页;要换页再 navigate。
## live 视图(第一期)
有人在看浏览器时,每次 navigate / click / fill / click_at 之后
都要调一次 `browser_live_shot`,让 browser-live.png 保持最新;
不要只在最后截图一次。用户在 live 图上点的坐标会以 x/y 到达
`browser_click_at`,点完必须再 snapshot 一次确认变化,再调
`browser_live_shot` 刷新画面。
## 远控接管(第二期)
用户可以在控制台接管浏览器:接管期间(holder=user)你的
所有 browser_* 工具都会直接报错“user holds browser control”,
不要重试、不要 close 浏览器,停下来等用户交还;交还后
(holder 回到 agent)下一条继续消息会让你续跑,续跑前先
snapshot 一次看清用户改动到哪了。
新工具:`browser_snapshot_refs`(带 ref 的元素清单,点
`browser_click_ref` 比 CSS 选择器稳,页面重渲染后先重新
snapshot_refs 再点);`browser_mouse_move` / `browser_key_press` /
`browser_type_text`(键盘与鼠标,远控输入与 agent 工具同源)。
## 规则
1. 先 navigate,再 snapshot 看实际渲染结果;click / fill 后
必须再 snapshot 一次确认变化,不要凭猜测汇报。
2. 截图产出后用 shell / PIL 重新打开验证(格式、尺寸、非 0
字节)再交给用户;失败时贴出工具报错,不要换一张别的图顶替。
3. 网络走 egress 代理:不在 Tinyproxy 白名单里的域名会报
代理 403,这时如实说明,不要绕过白名单。
4. file:// URL 可用于打开工作区内已写好的测试页(验证 JS
执行、表单行为),是比外网更可靠的自测手段。
5. 不要用浏览器做静态抓取能做的事;不要用 evaluate 绕过
click / fill 的正常路径去改页面状态,除非 snapshot 已证明
正常路径走不通。
## 多页与域名白名单(本期新增)
多页工具:`browser_new_page`(开新页并切到它,每次
new_page 都是全新 Playwright context,cookie 与存储天然
隔离,适合同时登录两个账号或对照两个页面)、
`browser_list_pages`(列出全部页:index、URL、标题、
哪一页是当前页;浏览器未启动时不启动,只返回空列表)、
`browser_switch_page`(按 index 切到指定页,之后
navigate / snapshot / click / fill / screenshot 都针对该页;
切到不存在的 index 会明确报错,不会崩掉 MCP,当前页不变;
切换后旧页的 snapshot_refs 全部失效,要重新 snapshot_refs)、
`browser_close_page`(关一页,缺省关当前页;关当前页后
自动切到上一页;关最后一页会明确报错,改用
`browser_close` 关整个浏览器)。
域名白名单:环境变量 `BROWSER_ALLOWED_HOSTS`(逗号列表,
如 `example.com,.python.org`)。未设置时行为完全不变,
只靠 egress 代理白名单;设置后 navigate 在启动浏览器之前
就检查:`file://` 一律放行,`http(s)` 的 host 必须命中列表
(前导点条目做后缀匹配:`.python.org` 同时放行
`python.org` 与 `docs.python.org`,不放行
`notpython.org`),大小写与端口不影响匹配,未命中直接
报错且不启动 Chromium。`localhost` / `127.0.0.1` 没有
特殊待遇:本地开发服务器要自己把它列进变量,否则会被挡。
清理:`browser_close` 会关掉全部页,并尽力删除工作区里的
`browser-live.png` 与 `browser-live.json`(删不掉也不报错),
所以 close 之后不要再拿旧 live 文件当“当前画面”汇报;
单个截图(`browser_screenshot` 的 `shot-*.png`)不受影响。
不在本轨范围:下载没有落盘清单(下载仍只落工作区文件,
无统一清单可查);没有持久 profile(每次 MCP 进程结束
cookie 即丢);没有登录保险库(账号密码仍不进浏览器工具)。
需要这些时不要假装已有,先如实说明缺口。