项目 · 构建中
Browser Runtime
一个给 Agent 使用的本地浏览器运行时。核心不是“能不能点页面”,而是把 Profile / Tab 的控制权做成显式、受限、可撤销。
为什么做
浏览器自动化真正难的不是点击按钮,而是明确谁在什么时刻有权操作哪个 Profile / Tab。多 Profile、旧 session、页面跳转、重连、用户自己的 Tab、Agent 新开的 Tab,以及调用方意外中止,都可能让控制状态变得含糊。
之前怎么做
早期 workflow 已经能完成真实浏览器任务,但控制边界并不够可靠:当前任务到底拥有哪个 Chrome Profile / Tab,导航或重连以后旧权限还算不算数,任务突然停止后又该怎样安全回收,这些都需要明确答案。
我们当时的判断
如果 Profile / Tab 的 authority 必须显式获得、生命周期足够短并绑定具体任务;交互层只提供受限的语义操作;遇到不确定状态时直接 fail closed,而不是偷偷换一条控制路径,那么浏览器控制可以保持实用,同时避免变成无限制的远程控制 API。
怎么验证
只维护一套当前 Chrome runtime:先在真实多 Profile 环境验证隔离,再通过正常产品路径安装,然后持续用于真实 workflow。每次使用暴露问题后,先判断问题应该由哪一层负责;只有真正属于通用浏览器能力、authority 或 lifecycle 的缺口才进入 Core,并在最小修复后重新做 live acceptance。
做了什么
Rust 本地 Core + Chrome Extension,包含显式 Profile authority、TaskSession、ExecutionEpoch、TabLease,以及受限的 observe / scroll / activate / type 语义操作;同时定义 reconnect / freshness 规则和 Runtime 自主管理的 idle authority expiry。站点专用逻辑保持在 Core 之外。
真实使用里看到了什么
v0.2 已在真实 Chrome 上通过跨 Profile 隔离和连接验收。长时间线任务暴露出通用滚动能力缺口后,Core 增加了受限 scroll primitive,并真实用于继续读取 X profile timeline,而没有加入 X 专用命令。之后一次调用方意外中止又暴露 orphan authority,Runtime-managed idle expiry / safe reclamation 随后实现并通过 live acceptance。
现在的结果
Browser Runtime 已形成一套经过真实使用检验的 authority / lifecycle 模型,而不是只在 Demo 中成立。它仍处于构建中;新的 Core 能力只有在重复真实任务证明其确实属于浏览器通用层时才会加入。
学到了什么
- 能发现一个浏览器对象,不等于当前 workflow 有权操作它。
- 重连应该恢复连接,而不是悄悄把旧控制权带到新的浏览器上下文。
- 真实使用比预先列一张“功能齐全”清单更适合作为能力 backlog;先判断问题属于哪一层,再决定是否修改 Core。
- 自动化被中断后需要可回收的生命周期,但不能靠猜调用方已经死亡,也不能因此破坏用户自己打开的 Tab。
涉及的能力
macOS 产品工程 · 浏览器自动化 · Agent 基础设施 · Rust · 安全导向的系统设计
难点不是“点一下”
列出浏览器里的 Profile、Window 和 Tab 很容易。
真正困难的是另一个问题:当前这个 workflow 到底允许操作什么?什么时候这份权限应该失效?
所以 Browser Runtime 没有把“看得到”当成“可以控制”。Profile / Tab 的 authority 必须显式获得,并绑定到具体任务和执行阶段;外围浏览器状态变化以后,旧 authority 不会被默认继承。
Core 不应该知道每一个网站
Runtime 只提供少量通用语义操作,例如观察页面的一小块区域、继续滚动一个 viewport、激活刚刚观察到的目标、向刚刚确认过的输入点输入文字。
它不会内置“操作 X”“操作 ChatGPT”“操作某个发布平台”这类站点命令。站点知识放在 adapter / workflow 层;只有重复真实任务证明某个缺口确实是浏览器通用能力,才允许进入 Core。
这个边界很重要。否则每解决一个网站问题,Core 都会变大一点,最后又变成难以约束的通用遥控器。
真实使用暴露了两个通用缺口
第一次是在读取很长的 profile timeline 时。只有 observe 不够,任务需要一种受限的“继续往下看”的能力。最后加入的是 generic scroll,而不是一个 scroll X timeline 命令。
第二次来自一次意外中止。调用方已经停了,但原来的浏览器 authority 还活着。解决方式不是去猜“调用方是不是死了”,而是让 Runtime 自己发行的 authority 有明确的 idle lifetime:过期后可以安全回收,同时不碰用户自己拥有的浏览器状态。
因此目前的开发规则很克制:先拿去做真实任务,记录失败,判断应该由哪一层负责,只做最小的通用修复,通过 live acceptance 后,再把 Core 冻结下来继续使用。