vercel-labs/remote-agent-browser

GitHub: vercel-labs/remote-agent-browser

一个基于 Vercel Sandbox 的云端可编程浏览器,为 AI Agent 提供隔离的、有状态的网页自动化执行环境。

Stars: 79 | Forks: 3

# remote-agent-browser 通过隔离的 [Vercel Sandbox](https://vercel.com/docs/vercel-sandbox) 在云端运行 [agent-browser](https://github.com/vercel-labs/agent-browser)。 ## 安装 ``` pnpm add remote-agent-browser ``` ## 使用 `AgentBrowser.create()` 会从预构建的浏览器镜像启动一个全新的 Vercel Sandbox。同一个客户端中的命令会共享相同的页面、cookies、标签页和元素引用。`close()` 会关闭 Chromium 并停止该 Sandbox。 ## 示例 - [捕获屏幕截图](./examples/screenshot/README.md) — 捕获整页 PNG 并将其保存在本地。 - [Agent Bash 工具集成](./examples/agent-bash-tool/README.md) — 让 agent 通过其 Bash 工具使用常规的 `agent-browser ` 调用。 - [为可信自动化绕过 BotID](./examples/botid-bypass/README.md) — 将 Vercel 自动化绕过 token 作为 origin 作用域的 header 传入。 - [通过代理路由流量](./examples/proxy/README.md) — 配置带有身份验证的代理并验证浏览器的出口地址。 ## 身份验证 在 Vercel 上通过 `VERCEL_OIDC_TOKEN` 运行时,身份验证是自动完成的。 对于本地开发,请关联一个 Vercel 项目并拉取其环境配置: ``` vercel link vercel env pull .env.local node --env-file=.env.local examples/screenshot/index.mjs ``` ## API ### `AgentBrowser.create()` 在一个一次性的 Vercel Sandbox 中启动全新的浏览器。完成后请务必调用 `browser.close()`。 通过 `args` 传递 agent-browser 的全局选项。它们会被放置在每条命令之前,这对于颜色配置、用户配置以及初始化脚本等启动设置是必需的: ``` const browser = await AgentBrowser.create({ args: ['--color-scheme', 'dark', '--enable', 'react-devtools'], }) ``` ### 代理 使用 `proxy` 为浏览器客户端的生命周期设置代理。使用对象形式来配置需要直接连接的主机: ``` const browser = await AgentBrowser.create({ proxy: { url: 'http://user:password@proxy.example.com:8080', bypass: ['localhost', '*.internal.example.com'], }, }) ``` 对于没有绕过规则的代理,请直接传递其 URL: ``` const browser = await AgentBrowser.create({ proxy: 'http://proxy.example.com:8080', }) ``` ### `browser.run(commands)` 在同一会话中运行多个 agent-browser 命令: ``` const result = await browser.run([ ['open', 'https://my-preview.vercel.app'], ['wait', '--load', 'networkidle'], ['snapshot', '-i', '--json'], ['click', '@e3'], ]) ``` ### `browser.exec(command, options?)` 运行带有参数和标志的单一命令: ``` await browser.exec('find', { args: ['role', 'button', 'click'], flags: { name: 'Submit' }, }) ``` ### `browser.shell(command, options?)` 当需要转发 Bash-tool 命令或将 `agent-browser` 与常规 shell 工具组合使用时,请使用此方法。该命令会原封不动地执行,因此引号、管道、重定向和控制操作符都会保留其 shell 语义。对于不需要 shell 的浏览器命令,首选 `exec()` 或 `run()`。每次 `agent-browser` 调用都会通过 `AGENT_BROWSER_SESSION` 继承客户端的 CLI 会话。 ``` const result = await browser.shell( 'agent-browser read "https://example.com" | grep -io "example" | wc -l', ) console.log(result.stdout) ``` 客户端全局的 `args` 不会被插入到 shell 字符串中,因为这样做需要重写任意的 shell 语法。在使用 `shell()` 时,请将全局 CLI 参数直接放在命令中。 ### Typed JSON 对于支持 `--json` 的命令,请设置 `output: 'json'`。`exec()` 会添加该标志,解包 CLI 响应信封,并将常规命令字段与类型化的 `data` 值一并保留: ``` type UrlResult = { url: string } const result = await browser.exec('get', { args: ['url'], output: 'json', }) console.log(result.data.url, result.ok) ``` ### 文件传输 通过页面的文件输入框上传本地缓冲区数据,或者收集浏览器下载文件,而无需暴露 Sandbox 文件系统: ``` await browser.upload('#avatar', [ { name: 'avatar.png', bytes: await readFile('avatar.png') }, ]) const { file } = await browser.download('#export', { filename: 'report.csv' }) await writeFile('report.csv', file.bytes) ``` 如果未提供输出路径,其他生成文件的命令会将其产物收集到 `result.file` 中。这包括屏幕截图、PDF、追踪记录、性能分析、HAR 文件、保存的浏览器状态以及录像: ``` await browser.exec('network', { args: ['har', 'start'] }) // ...interact with the page... const result = await browser.exec('network', { args: ['har', 'stop'] }) await writeFile('capture.har', result.file.bytes) ``` 当命令已经包含明确的远程输出路径时,无需更改命令即可直接读取: ``` await browser.shell( 'agent-browser screenshot /tmp/verification.png', ) const file = await browser.readFile('/tmp/verification.png', 'image/png') await writeFile('verification.png', file.bytes) ``` ### 便捷方法 - `browser.snapshot(url?)` 可选地打开一个页面,然后返回其交互式快照。省略 URL 则检查当前页面。 - `browser.screenshot(url?, { fullPage: true })` 可选地打开一个页面,然后返回一个 PNG 缓冲区。将 options 对象放在第一个参数以捕获当前页面。 - `browser.close()` 关闭会话并停止 Sandbox。 所有方法都会使用同一个一次性浏览器会话,直到调用 `close()`。 ### 稳定的浏览器 ID 当浏览器身份需要跨越进程边界保留时,请使用 `AgentBrowser.session()`。它返回一个惰性句柄:构造它或启动 keepalive 并不会创建 Sandbox。第一个浏览器命令会找到或创建一个派生自调用者定义 ID 的 runtime,而另一个使用相同 ID 的进程会再次找到该 runtime。 ``` const browser = AgentBrowser.session({ id: `environment:${chatId}` }) const stopKeepalive = browser.keepalive() try { await browser.exec('open', { args: ['https://example.com'] }) } finally { stopKeepalive() } ``` ID 是项目作用域的。当同一个应用程序在多个环境中使用一个 Vercel 项目时,请包含部署环境或其他命名空间。 底层的 Sandbox 名称是私有的,并派生自该 ID 的哈希值。 如果已过期的 Sandbox 恢复运行,其 Chromium 进程将全新启动。当调用者需要提示页面、cookies、引用、标签页和控制台历史记录已丢失时,请在运行命令前订阅 `reset`: ``` browser.on('reset', ({ reason }) => { console.log(`Browser runtime reset: ${reason}`) }) ``` `browser.destroy()` 会永久移除具名的 runtime。停止 keepalive 仅允许其按照正常的空闲超时时间过期。 ### Keepalive 在长时间运行的任务中,让 Sandbox 在空闲期间保持存活。请务必在 `finally` 块中停止心跳;停止后,除非提前关闭,否则 Sandbox 将在其正常超时时间到期: ``` const stopKeepalive = browser.keepalive() try { await runLongAgentTurn(browser) } finally { stopKeepalive() } ``` 默认情况下,每次心跳都会恢复由 `AgentBrowser.create()` 配置的墙上时钟超时(wall-clock timeout),并在该时间窗口过半时运行,且最长不超过五分钟。可以通过 `timeoutMs` 和 `intervalMs` 覆盖这两个值。续订操作是尽力而为的;可通过传递 `onError` 来观察失败情况。 容器镜像和开发详情请参阅 [docs.md](./docs.md)。
标签:AI智能体, GNU通用公共许可证, MITM代理, Node.js, Vercel沙箱, 云浏览器, 无头浏览器, 自动化攻击