这条在讲浏览器 agent 的多 workspace 协调,为什么不能只靠独立 profile。出处是 Volker Schukai 发在 dev.to 的 SessionDock 开发报告,9 月 5 日发的,8 号又补了一段。
我看这篇是奔着“多浏览器代理并行”去的。两个 agent 各处理一个项目,每个都要有带登录态的浏览器。如果某个 workspace 被占着,agent 得知道不能静默切到别的 profile 去。这个设定本身就比“开几个 Chrome 实例”多问了一件事:你怎么知道这个 workspace 属于哪个项目、当前谁在动它。独立 profile 答不了这个——它只隔数据,不隔权限。换句话说,独立 profile 是隔板,不是权限。
读到第三段我才决定留下来。作者开篇就写明白:SessionDock 到发稿这会儿还不是已发布、能端到端跑通的应用。这话放在 agent 基建类开发报告里,比九成“我已经做了 XX”的帖子值钱。而且他后面一直保持这个调子——“这里只是数据模型的概念”“那里还没做集成”。
机制本身不复杂。每个 slot 是一套预置的 Chromium workspace,带完整 user-data 目录、下载目录、独立 XDG 和 D-Bus 路径。调度器用 lease 做限时独占,lease 带 epoch,控制权交接一次 epoch 就递增一次。代理 A 在 epoch 41 持有 slot 控制权,人收回后变成 42,A 一个迟到的 epoch 41 动作派发前被状态机检查拦住,判过期拒掉。
这个检查有单元测试覆盖。作者也没把话说满:他说这不等于端到端受保护的浏览器动作。更关键的是他自己补上了漏掉的那半句——这类检查没法撤销已经到达网站的动作。本地控制权交接不能逆转 Web 服务已经接受的变更。
多数人写这种设计,停在“我们加了 epoch 检查”就完了。他接着往下走:那已经落地但没回报的动作怎么办。作者在评论区跟人来回了好几轮,带出一个我觉得最值钱的概念——OUTCOME_UNKNOWN。一次写入可能已经成功,但结果丢了,这时候不能拿“没结果”当“没效果”接着自动重试。得找可信的、特定于应用的证据去对账,而且有时候这种证据根本不存在。
读到这段我停了一下。我自己跑 agent 改代码,遇到过命令执行一半超时、不知道到底执行没有。当时我的直觉是重跑一遍,结果重复写。原作者主张让 OUTCOME_UNKNOWN 保持未知,交给人审。慢是慢,但比自动重试干净——这是我读这段最大的收获。
评论区把原文没兜住的洞挨个指了出来。最狠的是 Vinh Nguyen 一条:假如 Chromium 以远程调试端口启动,那个端点按设计是未认证的,GET /json 能列出目标页面和 URL,还能用 WebSocket 直接驱动页面。一个持有文件访问权但 epoch 已经过期的代理,完全可以绕过调度器、不碰 lease 直接操作浏览器。作者回应说当前不用远程调试端口,计划走扩展的 chrome.debugger 控制,但也同意需要验证实际运行的浏览器进程和 user-data-dir,把意外出现的 DevTools 监听器当硬失败。
另一个是 jkming 提的,我印象更深。共享 Chrome over CDP 时,你给别的 agent 已经导航走的标签准备一次点击或者 Runtime.evaluate,它还是会成功——落在错误的页面上,因为 target ID 跨导航仍然有效。他的临时做法是每次派发输入前重新查目标 URL。这正是我在 CDP 上踩过的坑:target 还在,页面已经不是那张了。
身份验证那块讨论也留下了。有人指出 expected_tenant 只是对远程服务状态的声明,手动登录时没把人绑到预期账号上。一个绑定租户 A 的 slot,你登录到了租户 B,它不会报错,而且登录态是持久化的,错误状态跨重启保留。作者同意的修正方向是:更合适的契约是“远程身份在 X 时间内被验证过”,而不是“slot 持续保证是租户 A”。这个区分听着绕,但架不住它是对的。
这篇我没法“顺手跑”,它是设计报告,不是方法贴,没有命令可执行。
不点链接也能带走的一句:给浏览器 agent 做权限层时,profile 隔离、lease 过期、epoch 检查各自管一段——本地数据、当前控制权、过期授权检测。任何一个都不能拿来替代另外两个。
这篇值得点开。不是因为它解决了什么,是因为它把“还没解决”的边界列得足够具体,具体到评论区有人复现了绕过路径。开发报告写到这个密度,比一批号称做了 agent 浏览器基础设施的东西更能让人认清:真正难的那层还没人跨过去。
