Skip to content

v2.3.0 — 每个 agent 一块自己的地方

Choose a tag to compare

@Glittering Glittering released this 28 Oct 06:08
· 51 commits to main since this release

v2.3.0 — 每个 agent 一块自己的地方

上一版让每个连接有了自己的目标,这一版把它补成自己的空间:一个组、一个上限、一个
标签栏上看得见的位置。

为什么还要再改一次

用户的原话:"我看 agent 还是不知道去操作其它标签,只会弄当前激活的显示的那个标签。"

这是三个原因叠在一起,只修一个都不够:

  1. 默认行为:会话还没有绑定时,目标回落到 activeTab —— 也就是人正在看的那一页。
    单 agent 时它碰巧等于"agent 该干的活",多 agent 时就是灾难。
  2. 没人告诉它:工具描述和技能里只有一句"省略 tab 就是你自己的页",而"你自己还没有页"
    这件事从来没有被说出来过。
  3. 习惯:模型在别处学到的浏览器操作就是"操作当前页",没有理由自己想到去开一页。

所以这一版把"给自己开一页"从要求变成事实。

自动工作区

MCP / CLI 建连后立刻自报家门(ui.hello)。声明自己是 agent 的连接,第一次要动页面而还没
指定目标时,浏览器给它开一页空白标签、归进它自己的组,并在这次结果里附一次提示:

{"workspace": {"tab": 7, "group": "Claude", "created": true, "hint": "..."}}

Agent 于是永远不会默认开在人眼前那一页上。想看人的页面仍然便宜:list 里
group: "human" 那条,显式传 tab —— 读一下不会把它抢走。

四条不触发:① 没发 ui.hello(裸 WS / e2e / 脚本保持老行为);② 方法本身在管标签页;
③ 显式点了 tab 或已有绑定;④ AI_BROWSER_AUTO_WORKSPACE=0。CLI 发
auto_workspace:false —— 人坐在终端前敲命令时,"不传 tab 就打当前页"才是他要的。

组与上限

group = 'human' | 'agent:<会话>'

每组默认 8 页(AI_BROWSER_TAB_LIMIT)。new_tab 撞上限时拒绝,不回"悄悄挤掉一页":
挤掉是破坏性的(agent 可能正在那一页跑流程),拒绝是一次必须做的决定 —— 这正是上限的
理由:后台运行时没人看得见它的标签页。

-32001 your tab group is full (8/8) — close one before opening another
data: { reason: "group-full", limit: 8, tabs: [{tab, url}, ...] }

页面自己弹的窗口没法拒绝(站点脚本在等它),只能牺牲:本组里"最久没用、不在人眼前、
没有挂着对话框"的那一页,并在 list 的 evicted 里回采一次。

上限只约束声明过自己是 agent 的连接。裸 WS 拿到的组只是归属标签,不限量 —— 否则那些
一次性开二十个标签的回归套件会突然全红。

标签栏

人的标签页平铺;每个 agent 组折叠成一个 pill(组色 + 名字 + 页数,满额变暖色)。悬停展开,
点击钉住;正在看的那一组强制展开,否则人切过去就找不到自己在看什么。点开组里的页只是
"你看",不改 agent 的目标。

没有做成"竖着掉下来的下拉菜单":标签栏是固定高度的 BrowserView,往下弹会被自己裁掉;要能弹
就得每次悬停把标签栏长高、把页面下推 —— 那正是本项目历史上闪烁/几何脱节的来源。就地展开
拿到同样的折叠效果,不动布局。

验证

  • 新增 tests/test_tab_group.js(12 条)与 tests/test_tab_bar_layout.js(10 条):
    上限判定、弹窗牺牲顺序(不许牺牲正在看的、正在被开的、挂着对话框的)、折叠状态机。
    交互逻辑抽成纯函数才测得了 —— 靠人肉把鼠标移上去验证等于没验证。
  • npm run multiagent 从 32 条断言扩到 46 条:M7 自动工作区(含"人的页面没被换掉")、
    M8 上限与拒绝回执、M9 组间互不影响。
  • 全量:vitest 73 文件 / 1024 条;e2e:all 22 套件 / 743 断言。

顺手修掉的一个老 bug:打开的目标页会自己跳回首页

npm run background 这次开始稳定失败,追下去发现不是新代码的问题 ——
在 v2.2.0 的 tag 上跑同样稳定失败:

新标签页的占位页(loading.html)后面挂着一个"垫片装好后就去加载目标地址"的延迟
动作。垫片安装偶尔会挂十几秒,这期间 agent 已经把这一页导航走了;等它终于 resolve,
那个延迟动作又把启动页加载回来 —— 现象是"打开的是目标页,下一刻自己跳回首页",
读到的树也成了首页的。

修法是一句判据:延迟动作执行前先看"现在还在占位页上吗",不在就什么都不做。
(page_manager.newTab 的 proceed()。)

升级注意

  • 以前"不传 tab 就打当前页"的 agent 行为变了:第一次调用会得到一页空白工作页。
    这是刻意的(隔离的前提),回执里有提示;要恢复老行为设 AI_BROWSER_AUTO_WORKSPACE=0。
  • 一个 agent 同时开超过 8 页会被拒绝,需要先关。