baa-conductor

git clone 

baa-conductor / plans / archive
im_wower  ·  2026-03-28

FIREFOX_BRIDGE_CONTROL_REQUIREMENTS.md

  1# Firefox 桥接控制与代发需求
  2
  3## 状态
  4
  5- `已落地(T-S021``T-S024` 已收口主线实现)`
  6- 优先级:`high`
  7- 记录时间:`2026-03-26`
  8
  9## 关联文档
 10
 11- [BROWSER_BRIDGE_PERSISTENCE_REQUIREMENTS.md](/Users/george/code/baa-conductor/plans/archive/BROWSER_BRIDGE_PERSISTENCE_REQUIREMENTS.md)
 12- [DISCUSS-FIREFOX-BRIDGE-CONTROL.md](/Users/george/code/baa-conductor/plans/discuss/DISCUSS-FIREFOX-BRIDGE-CONTROL.md)
 13
 14## 背景
 15
 16浏览器桥接持久化已经把登录态元数据、`account`、凭证指纹和 API 端点收口到 `conductor` 17
 18下一阶段需要把 Firefox 桥接正式分成两个模块:
 19
 20- `conductor`:控制平面和全局调度平面
 21- Firefox 插件:本地执行平面和页面桥接平面
 22
 23目标是把“插件管理能力”和“浏览器代发能力”都定义成正式需求,而不是继续停留在诊断路径或页面对话能力上。
 24
 25## 核心结论
 26
 27- 浏览器桥接正式分为两个模块:`conductor` 和 Firefox 插件
 28- AI 侧能力发现不再新增 `browser describe``plugin describe`
 29- `conductor` 只保留两层正式 describe:
 30  - `/describe/business`
 31  - `/describe/control`
 32- 首批正式能力必须同时覆盖:
 33  - 管理类
 34  - 功能类
 35- `SSE` 必须是首批正式能力,不是后续增强项
 36- 原始凭证始终只留在浏览器本地
 37- 抖动、限流、并发控制、失败退避等主策略放在 `conductor`
 38- Firefox 插件只负责本地执行和最后一道保护,不承担全局调度职责
 39- 首版以 `client_id` 作为唯一执行侧标识,不把多 client 最优调度当作首版交付目标
 40
 41## 首版范围
 42
 43- 首版主要面向单 Firefox client 场景
 44- 首版每个平台最多维护一个空壳页
 45- 首版以 `client_id` 作为执行目标选择键
 46- `host` / `browser` / `account` 先保留为元数据,不进入复杂调度决策
 47- 多 client、多浏览器协调只做结构预留,不做首版强承诺
 48
 49## Describe 收口
 50
 51### 目标
 52
 53- 不再为浏览器桥接单独引入第三层 describe
 54- 不让 AI 调用方额外理解“browser/plugin 是不是单独能力面”
 55- 保持当前能力发现模型简单稳定:只有业务类和控制类
 56
 57### 正式结构
 58
 59- `GET /describe`
 60  - 只作为入口索引
 61  - 告诉调用方下一步应读 `business` 还是 `control`
 62- `GET /describe/business`
 63  - 承载业务查询和业务动作
 64  - 也承载浏览器功能类能力
 65- `GET /describe/control`
 66  - 承载系统控制和本机控制动作
 67  - 也承载插件管理类能力
 68- `GET /v1/capabilities`
 69  - 保留为机器可读摘要
 70  - 不承担额外的分层解释职责
 71
 72### 归类原则
 73
 74#### 放进 `/describe/business`
 75
 76- 浏览器登录态读面
 77- 浏览器可用平台和可用账户读面
 78- 浏览器代发请求能力
 79- SSE 流式能力
 80- Claude 及后续平台的业务型浏览器调用
 81- `codex` 会话与 turn 能力
 82- tasks、controllers、业务查询能力
 83
 84#### 放进 `/describe/control`
 85
 86- 插件状态读面
 87- WS 重连
 88- 管理页重载
 89- 平台页打开、聚焦、重载、恢复
 90- 系统 `pause` / `resume` / `drain`
 91- `exec`
 92- `files/read`
 93- `files/write`
 94
 95### 明确不做
 96
 97- 不新增 `/describe/browser`
 98- 不新增 `/describe/plugin`
 99- 不要求 AI 直接理解 Firefox WS bridge 协议
100- 不把底层 bridge message 暴露成 describe 主模型
101
102## 接口迁移策略
103
104### 现状
105
106- 当前正式浏览器业务接口仍以 Claude 专用路径为主:
107  - `POST /v1/browser/claude/open`
108  - `POST /v1/browser/claude/send`
109  - `GET /v1/browser/claude/current`
110  - `POST /v1/browser/claude/reload`
111
112### 目标
113
114- 新能力收口到平台无关的通用浏览器接口
115- 过渡期允许 Claude 专用接口和新接口并存
116- Claude 专用接口在新接口稳定后降为 legacy 包装层
117
118### 通用接口方向
119
120- `GET /v1/browser`
121  - 统一读面
122- `POST /v1/browser/actions`
123  - 管理类动作入口
124- `POST /v1/browser/request`
125  - 通用浏览器请求入口
126- `POST /v1/browser/request/cancel`
127  - 请求或流取消入口
128
129### 兼容策略
130
131- `POST /v1/browser/claude/open`
132  - 等价包装到 `POST /v1/browser/actions`
133- `POST /v1/browser/claude/send`
134  - 等价包装到 `POST /v1/browser/request`
135- `POST /v1/browser/claude/reload`
136  - 等价包装到 `POST /v1/browser/actions`
137- `GET /v1/browser/claude/current`
138  - 首版继续保留为 Claude 辅助读接口
139  - 不再作为未来通用模型的核心入口
140
141### 迁移完成条件
142
143- 通用接口覆盖现有 Claude 主路径
144- smoke 和文档改为默认引用通用接口
145- Claude 专用接口全部标记为 legacy 后,再进入后续清理
146
147## 模块一:`conductor`
148
149### 目标
150
151- 作为 Firefox 桥接的统一控制面
152- 作为浏览器请求代发的全局调度面
153- 作为浏览器登录态和端点元数据的持久化读写面
154
155### 管理类需求
156
157- 查询插件状态:
158  - 在线/离线
159  - WS 是否连接
160  - 管理页是否在线
161  - 各平台 shell 页是否存在
162  - 最近错误和最近重连时间
163- 支持远程控制动作:
164  - 重连 WS
165  - 重载管理页
166  - 打开或聚焦平台 shell 页
167  - 重载平台 shell 页
168  - 恢复缺失的平台 shell 页
169- 支持浏览器断连后的状态保留和重连后的状态恢复
170
171### Tab 状态模型
172
173- `conductor` 维护平台级期望状态 `desired`
174- Firefox 插件持续上报实际状态 `actual`
175- 首版期望状态粒度是“每个平台一个空壳页”
176- `tab_restore` 的含义是:
177  - 重建 `desired` 中存在但 `actual` 中缺失的空壳页
178- `actual` tab 状态首版保留内存态,不做长期持久化
179- 浏览器重连后由插件重新上报 `actual`,`conductor` 再做调和
180
181### 功能类需求
182
183- 下发 API 请求,由浏览器侧代发
184- 接收结构化普通响应:
185  - 成功
186  - 失败
187  - 超时
188  - 取消
189- 接收结构化 SSE 响应:
190  - `stream_open`
191  - `stream_event`
192  - `stream_end`
193  - `stream_error`
194- 支持请求取消
195- 支持按平台、浏览器 client、`account` 选择代发目标
196
197### SSE 可靠性设计
198
199- 每条流都有稳定 `stream_id`
200- 每个 `stream_event` 都带递增 `seq`
201- 首版不做跨 WS 断连的 event 重传
202- 如果流过程中断连、超时或本地执行失败:
203  - `conductor` 向调用方返回 `stream_error`
204  - 已成功收到的 partial events 仍然有效
205- 默认超时建议:
206  - `stream_open` 超时:`10s`
207  - `stream_open` 后空闲超时:`30s`
208- 默认缓冲上限建议:
209  - `256` 个 events
210  -`512KB` 累积流数据
211- 超时阈值和缓冲上限应可配置
212- 如果本地缓冲溢出或回传跟不上,优先失败并返回 `stream_error`,不 silently drop
213
214### 调度与风控需求
215
216- 统一做平台级限流
217- 统一做账号级限流
218- 统一做并发控制
219- 统一做失败退避
220- 统一做熔断和恢复
221- 统一做人类化抖动,例如高斯延迟
222- 保留请求和流事件日志,便于审计和排障
223
224### 默认策略参数
225
226- 参数都应由 `conductor` 配置驱动,不写死在插件里
227- 首版默认值建议:
228  - 抖动:高斯延迟,`mu=2s`、`sigma=0.5s`、夹到 `[1s, 5s]`
229  - 平台限流:`10 req/min/platform`
230  - 平台并发:`1 in-flight/client/platform`
231  - 失败退避:指数退避,`base=1s`、`max=60s`
232  - 熔断:连续 `5` 次失败后打开,`60s` 后半开试探
233- 当前有效策略摘要应能通过 `/describe/control` 或等价控制读面读取
234
235### 明确不做
236
237- 不保存原始 `cookie`、`token`、header 值
238- 不直接脱离浏览器持凭证调用上游 API
239- 不把页面对话 UI 自动化当主能力
240
241## 模块二:Firefox 插件
242
243### 目标
244
245- 作为浏览器本地 runtime
246- 作为页面环境和真实登录态的持有者
247- 作为 API 请求和 SSE 的本地执行器
248
249### 管理类需求
250
251- 常驻管理页可自恢复
252- 能建立、保持和重建与 `conductor` 的 WS 连接
253- 能打开、聚焦、重载和恢复平台 shell 页
254- 能回报本地页面真实状态,而不是只回报期望状态
255
256### 空壳页定义
257
258- 空壳页必须是目标平台的一方页面,不能用 `about:blank`
259- 空壳页需要同时满足:
260  - 共享目标平台 cookie 和登录态
261  - 允许插件注入 fetch/SSE 执行环境
262  - 不把真实对话 UI 当作主能力
263- 首版每个平台只维持一个空壳页
264- 插件需要持续检测空壳页是否仍存在、是否已失效,并及时上报
265- 默认健康检查应至少覆盖:
266  - tab 生命周期事件
267  - `30s` 周期巡检
268
269### 功能类需求
270
271- 使用浏览器本地登录态代发 API 请求
272- 在页面内拦截并转发 SSE 流
273- 回传结构化请求结果和流事件
274- 支持本地超时和本地取消
275- 支持空壳平台页,不依赖真实对话 UI
276
277### 本地保护需求
278
279- 页面未就绪时拒绝执行请求
280- 缺失 shell 页时先恢复再执行
281- 单页或单平台可串行化执行
282- 保留最小发送间隔
283- 连续失败时进入短暂自我保护
284
285### 明确不做
286
287- 不承载全局限流策略
288- 不承载全局抖动策略
289- 不承载跨浏览器或跨账号调度
290- 不要求实现真正的“浏览器扩展重启”
291
292## 管理类正式能力
293
294- `plugin_status`
295- `ws_reconnect`
296- `controller_reload`
297- `tab_open`
298- `tab_focus`
299- `tab_reload`
300- `tab_restore`
301
302说明:
303
304- “重启插件”在正式需求里改写为“软重启 runtime”
305- 软重启 runtime 的含义是:
306  - 重载管理页
307  - 重建 WS
308  - 重新扫描和恢复平台页
309  - 重新上报状态
310
311## 功能类正式能力
312
313- `api_request`
314- `api_response`
315- `stream_open`
316- `stream_event`
317- `stream_end`
318- `stream_error`
319- `request_cancel`
320
321说明:
322
323- 普通请求和 SSE 请求使用同一条正式代发链路
324- SSE 不要求透传原始字节流,但要求稳定回传事件流语义
325
326## 职责划分结论
327
328### 应放在 `conductor`
329
330- 抖动策略
331- 限流策略
332- 并发控制
333- 队列调度
334- 失败退避
335- 熔断恢复
336- 跨浏览器、跨平台、跨账号协调
337
338### 应放在 Firefox 插件
339
340- 页面真实执行
341- 页面就绪检查
342- 本地超时
343- 本地取消
344- 最小安全发送间隔
345- 连续失败后的短暂本地保护
346
347## 执行链路选择原则
348
349- `codexd`
350  - 用于代码、文件系统、工作区相关任务
351- browser bridge
352  - 用于依赖真实网站登录态和浏览器页面环境的任务
353- 首版不要求两条链路自动互相替代
354- task 或 step 应显式声明执行后端,由 `conductor` 按声明选择链路
355
356## 一句话方案
357
358`conductor` 负责“怎么调度、怎么控风险、怎么选执行目标”,Firefox 插件负责“是否已就绪、如何在真实浏览器环境里把请求发出去并把 SSE 带回来”。
359
360## 对现有 describe 的改造判断
361
362- 这次优化重点是“重组现有 describe”,不是“新增第三层 describe”
363- 如果只调整 `/describe`、`/describe/business`、`/describe/control` 的文案和返回结构,复杂度较低
364- 真正复杂的部分不在 describe,而在后续正式浏览器管理接口和通用 SSE 接口实现
365- 推荐顺序:
366  1. 先收口 describe 分层
367  2. 再逐步把新的浏览器管理能力挂进 `control`
368  3. 再把新的浏览器代发和 SSE 能力挂进 `business`
369
370## 当前开发顺序
371
372- 当前主线先完成:
373  - `T-S023`
374  - `T-S024`
375- 当前不把大文件拆分当作本轮浏览器桥接开发的 blocker
376- 以下文件的模块化拆分顺延到下一轮专门重构任务:
377  - `apps/conductor-daemon/src/local-api.ts`
378  - `plugins/baa-firefox/controller.js`
379  - `packages/db/src/index.ts`
380  - `apps/conductor-daemon/src/index.ts`
381  - `apps/conductor-daemon/src/index.test.js`
382- 如当前功能开发被单个超大文件明显阻塞,只允许做最小必要拆分,不做整轮全面重构