- commit
- 04fbd60
- parent
- 0df67e3
- author
- codex@macbookpro
- date
- 2026-03-31 20:35:54 +0800 CST
docs: define automation arbitration rules
4 files changed,
+291,
-14
+184,
-0
1@@ -0,0 +1,184 @@
2+# 自动化仲裁需求
3+
4+> 日期:2026-03-31
5+> 状态:需求讨论
6+
7+## 背景
8+
9+当前系统已经有两类自动化能力:
10+
11+- BAA 指令系统:在 final-message 中提取 ` ```baa ` 指令并执行
12+- 续命系统:在 final-message 结束后,通过 timed-jobs 生成并发送续命任务
13+
14+两者都会在 SSE / final-message 结束后开始工作。如果没有统一仲裁规则,就会出现同一对话中“指令执行”和“续命发送”同时争抢出站机会的问题。
15+
16+## 目标
17+
18+定义同一对话上的自动化优先级、互斥规则、暂停语义和救援语义,避免:
19+
20+- 一条 final-message 同时触发 BAA 与 renewal
21+- BAA 正在执行时 renewal 继续向同一对话发消息
22+- 对话进入死循环或持续报错时没有显式停机方式
23+
24+## 核心原则
25+
26+### 1. 显式控制优先于一切
27+
28+如果 final-message 中包含控制类指令,先处理控制,不再进入本轮普通 BAA 执行或续命。
29+
30+控制类指令包括:
31+
32+- 暂停当前对话
33+- 恢复当前对话
34+- 切换当前对话到 `manual / auto / paused`
35+- 系统级暂停 / 恢复
36+- 标记等待救援
37+
38+### 2. 显式执行优先于隐式续命
39+
40+如果 final-message 中包含普通 BAA 指令,则:
41+
42+- 先执行 BAA 指令
43+- 本轮不生成续命任务
44+
45+续命只在“这一轮没有显式工作”时才运行。
46+
47+### 3. 同一对话同一时刻只能有一个自动化出站者
48+
49+对同一 local conversation,任一时刻只能处于以下之一:
50+
51+- `idle`
52+- `instruction_running`
53+- `renewal_running`
54+
55+不能同时存在两个自动化出站动作。
56+
57+### 4. 续命是空闲时的后台兜底,不是主逻辑
58+
59+续命只在以下条件同时满足时才允许运行:
60+
61+- 对话自动化状态为 `auto`
62+- 系统级状态允许执行
63+- 当前没有执行中的 BAA 指令
64+- 当前没有执行中的 renewal
65+- 没有命中熔断 / 救援等待状态
66+
67+## 同一条 final-message 的处理顺序
68+
69+收到最终权威消息后,按顺序处理:
70+
71+1. 控制类指令
72+2. 普通 BAA 指令
73+3. 续命判断
74+
75+也就是:
76+
77+- 有控制类指令:只做控制
78+- 无控制类指令但有普通 BAA 指令:只做指令
79+- 两者都没有:才考虑续命
80+
81+## 状态模型建议
82+
83+### 系统级
84+
85+- `running`
86+- `paused`
87+- `draining`
88+
89+### 对话级自动化状态
90+
91+- `manual`
92+- `auto`
93+- `paused`
94+
95+### 对话级暂停原因
96+
97+建议额外记录 `pause_reason`,至少支持:
98+
99+- `user_pause`
100+- `ai_pause`
101+- `system_pause`
102+- `error_loop`
103+- `rescue_wait`
104+
105+### 对话级执行锁
106+
107+建议运行态表达为:
108+
109+- `idle`
110+- `instruction_running`
111+- `renewal_running`
112+
113+## AI 自行停机与救援语义
114+
115+AI 需要能够在“持续出错、陷入死循环、需要人工或其他 AI 接手”时显式停机。
116+
117+这里不依赖自然语言猜测,而是要求 AI 发出明确控制指令。
118+
119+推荐语义:
120+
121+- AI 发现自己无法继续安全推进时:
122+ - 暂停当前对话
123+ - 原因设为 `rescue_wait`
124+- 其他 AI 或人工介入后:
125+ - 显式恢复该对话
126+ - 或切到 `manual`
127+ - 或重新切回 `auto`
128+
129+## 建议的 BAA 控制指令草案
130+
131+沿用旧 `baa` 的 `@target::tool::params` 风格,优先采用显式 JSON 参数。
132+
133+### 系统级
134+
135+```text
136+@conductor::system::pause
137+@conductor::system::resume
138+```
139+
140+### 当前对话
141+
142+```text
143+@conductor::conversation::pause::{"scope":"current","reason":"rescue_wait"}
144+@conductor::conversation::resume::{"scope":"current"}
145+@conductor::conversation::mode::{"scope":"current","mode":"manual"}
146+@conductor::conversation::mode::{"scope":"current","mode":"auto"}
147+@conductor::conversation::mode::{"scope":"current","mode":"paused"}
148+```
149+
150+### 指令约束
151+
152+- `scope:"current"` 表示当前 final-message 所属对话
153+- `pause` 和 `mode:"paused"` 都可以让对话停机,但 `pause` 更适合带原因
154+- `resume` 只解除当前对话暂停,不改系统级状态
155+- `system::resume` 只恢复系统级闸门,不改各对话原有状态
156+
157+## 熔断建议
158+
159+当出现下面情况时,系统应允许自动进入 `paused` 或 `rescue_wait`:
160+
161+- 同一对话短时间连续失败
162+- 续命内容高度重复,疑似死循环
163+- BAA 指令连续报错
164+- 指令和续命交替触发,形成无意义回路
165+
166+熔断后:
167+
168+- 停止继续续命
169+- 不再自动触发新的对话级执行
170+- 记录原因和最近错误
171+- 等待人工或其他 AI 恢复
172+
173+## 与现有需求文档的关系
174+
175+- 页面/对话级统一控制:见 `UNIFIED_OVERLAY_AUTOMATION_CONTROL.md`
176+- 系统级暂停:见 `SYSTEM_LEVEL_PAUSE_REQUIREMENTS.md`
177+- 本文档只回答“同一对话在 SSE 结束后先做什么、谁优先、什么时候该停机”
178+
179+## 验收标准
180+
181+- 同一条 final-message 不会同时触发 BAA 执行和 renewal 发送
182+- 控制类指令优先于普通 BAA 与 renewal
183+- BAA 指令执行时,renewal 不会抢同一对话的出站机会
184+- 对话可被 AI 显式切到 `rescue_wait` / `paused`
185+- 系统恢复和对话恢复不会互相覆盖状态
+22,
-0
1@@ -13,6 +13,7 @@
2
3 - [`./ARTIFACT_STATIC_SERVICE.md`](./ARTIFACT_STATIC_SERVICE.md)(下一阶段主线)
4 - [`./BAA_INSTRUCTION_SYSTEM.md`](./BAA_INSTRUCTION_SYSTEM.md)
5+- [`./AUTOMATION_ARBITRATION_REQUIREMENTS.md`](./AUTOMATION_ARBITRATION_REQUIREMENTS.md)
6 - [`./STATUS_SUMMARY.md`](./STATUS_SUMMARY.md)
7 - [`./archive/BAA_BROWSER_PROXY_DELIVERY_REQUIREMENTS.md`](./archive/BAA_BROWSER_PROXY_DELIVERY_REQUIREMENTS.md)
8
9@@ -68,6 +69,7 @@
10 未来可扩的 tool 面包括:
11
12 - 更完整的 `browser.*`
13+- automation control plane(系统级暂停、对话级 pause/resume/mode)
14 - `codex/sessions`
15 - `codex/turn`
16 - `tasks`
17@@ -79,6 +81,26 @@
18 - 插件仍保持 thin-plugin
19 - 解析、路由、权限、审计都不回流到插件
20
21+### 4.1 自动化控制面
22+
23+未来的 BAA 指令系统应补齐显式控制能力,而不是继续依赖自然语言猜测“现在该暂停还是继续”。
24+
25+优先方向:
26+
27+- `@conductor::system::pause`
28+- `@conductor::system::resume`
29+- `@conductor::conversation::pause`
30+- `@conductor::conversation::resume`
31+- `@conductor::conversation::mode`
32+
33+这些控制指令与 renewal 的关系不是“谁替代谁”,而是共享同一套 automation control plane。
34+
35+仲裁原则固定为:
36+
37+- 控制类指令优先于普通 BAA 指令
38+- 普通 BAA 指令优先于续命
39+- 续命只在对话空闲时运行
40+
41 ## 5. 编排层路线
42
43 当前主线仍是单节点、单轮主线。后续路线图包括:
+23,
-2
1@@ -9,6 +9,8 @@
2
3 需要一个系统级暂停,一键暂停所有自动化行为。
4
5+同一对话在 SSE 结束后的优先级与互斥规则,另见 `AUTOMATION_ARBITRATION_REQUIREMENTS.md`。
6+
7 ## 当前现状
8
9 | 控制层级 | BAA 指令 | 续命系统 |
10@@ -20,6 +22,8 @@
11
12 增加系统级暂停能力,一键暂停/恢复所有自动化(BAA 指令 + 续命)。
13
14+这里的系统级暂停是独立于页面/对话级状态的上层闸门,不与 `manual / auto / paused` 合并。
15+
16 ## 设计要点
17
18 ### 系统级暂停语义
19@@ -29,6 +33,12 @@
20 - 系统暂停不改变各对话的 automation_status,只是在更上层阻断执行
21 - 系统恢复后,各对话按自己的 automation_status 恢复原有行为
22
23+换句话说:
24+
25+- 系统级暂停是“先别跑任何自动化”
26+- 对话级暂停是“只有这个对话别跑”
27+- 两者可以同时存在,但绝不能互相覆盖状态
28+
29 ### 与页面/对话级的关系
30
31 ```
32@@ -37,6 +47,16 @@
33 对话级暂停 → 只影响该对话,其他对话不受影响
34 ```
35
36+执行顺序固定为:
37+
38+1. 先看系统级状态
39+2. 再看页面/对话级状态
40+
41+这意味着:
42+
43+- 系统级恢复不会把 `manual` 或 `paused` 的对话自动改成 `auto`
44+- 页面级恢复不会把系统级 `paused` 改成 `running`
45+
46 ### 实现方向
47
48 - 复用现有 `system_state` 表的 `automation` key
49@@ -46,8 +66,9 @@
50 ### 控制入口
51
52 - 浮层里保留系统级控制按钮(当前已有)
53+- 浮层可以与页面级控制放在同一块 UI 里,但必须分成两个区域,不共用一个按钮或一个状态值
54 - REST API:复用现有 `/v1/control/state` 或新增 `/v1/system/pause`、`/v1/system/resume`
55-- 后续可通过 BAA 指令 `@conductor::system::pause` 控制
56+- 后续可通过 BAA 指令 `@conductor::system::pause` / `@conductor::system::resume` 控制
57
58 ## 验收标准
59
60@@ -59,4 +80,4 @@
61
62 ## 优先级
63
64-中。当前页面/对话级控制合并是优先项,系统级暂停可以后做。
65+中。当前优先项是“统一浮层入口但保持分层状态模型”;系统级暂停在此之后实现。
+62,
-12
1@@ -7,7 +7,9 @@
2
3 当前 Firefox 插件右下角浮层控制的是 BAA 指令处理的暂停/恢复。续命系统的对话自动化状态(manual/auto/paused)完全独立,只能通过 REST API 操作。用户无法从浮层上看到或控制续命行为。
4
5-这两套自动化本质上都是"这个页面/对话是否允许 conductor 自动处理",应该合并为一个统一的控制入口。
6+这两套自动化本质上都是“这个页面/对话是否允许 conductor 自动处理”,应该统一到一个控制入口里;但它们和系统级暂停不是同一层语义,不能压成一个总状态机。
7+
8+同一对话在 SSE 结束后的执行优先级,另见 `AUTOMATION_ARBITRATION_REQUIREMENTS.md`。
9
10 ## 当前现状
11
12@@ -30,32 +32,72 @@
13
14 ## 目标
15
16-将 BAA 指令处理和续命自动化合并为一个统一的页面/对话级控制,从浮层一个按钮控制。
17+将 BAA 指令处理和续命自动化统一到一个页面/对话级控制入口,从浮层一个位置查看和操作。
18+
19+明确不做的事:
20+
21+- 不把系统级 `running / paused / draining` 和对话级 `manual / auto / paused` 合并成一个状态值
22+- 不让“恢复本页”顺手解除系统级暂停
23+- 不让“系统恢复”顺手修改各对话原有的 `manual / auto / paused`
24+
25+## 分层状态模型
26+
27+### 系统级(保持独立)
28
29-## 合并后的语义
30+- `running`
31+- `paused`
32+- `draining`
33
34-页面/对话级统一自动化状态:
35+系统级状态继续作为最外层闸门,控制整机自动化是否允许执行。
36+
37+### 页面/对话级(统一控制)
38+
39+页面/对话级继续使用统一自动化状态:
40
41 - **自动**(auto):BAA 指令正常处理 + 续命系统正常运行
42 - **暂停**(paused):BAA 指令暂停 + 续命系统暂停(不生成新任务,待执行任务不推进,执行中任务自然结束)
43 - **手动**(manual):BAA 指令暂停 + 续命系统不生成任务
44
45+页面/对话级只回答“当前页面/对话是否允许自动化”;系统级只回答“整个 conductor 现在是否允许自动化”。
46+
47+## 执行判定顺序
48+
49+执行时按下面顺序判断:
50+
51+1. 先看系统级状态
52+2. 再看页面/对话级状态
53+
54+也就是:
55+
56+- 系统级 `paused` 时,不管当前对话是 `auto` 还是 `manual / paused`,都统一不执行
57+- 系统级恢复后,再按当前对话自己的 `manual / auto / paused` 决定是否继续
58+
59 ## 控制入口
60
61 ### 浮层(首要入口)
62
63-- 当前"暂停本页"/"恢复本页"按钮改为同时控制两套系统
64-- 浮层显示当前对话的统一状态(auto/paused/manual)
65-- 点击切换时,同时更新 page_control 和 renewal automation_status
66+- 当前“暂停本页”/“恢复本页”按钮改为同时控制页面级 BAA 与 renewal
67+- 浮层同时显示两类状态:
68+ - 系统:运行中 / 系统暂停 / draining
69+ - 当前对话:auto / paused / manual
70+- 按钮文案保持分层:
71+ - 系统级按钮:`系统暂停` / `系统恢复`
72+ - 页面级按钮:`暂停本页` / `恢复本页` / `设为手动`
73+- 点击页面级按钮时,只更新 page_control 和 renewal automation_status,不修改系统级状态
74
75 ### REST API(保留)
76
77 - `/v1/renewal/conversations/:id/auto` 等接口保留
78-- 但状态变更需要同步到 page_control,保持一致
79+- 但状态变更需要同步到 page_control,保持页面级一致
80+- REST API 如果改的是系统级状态,只能改系统级,不碰各对话状态
81
82 ### BAA 指令(后续)
83
84-- 后期可以通过 `@conductor::renewal::auto` 等指令控制,但不是当前任务
85+- 后期可以通过显式 BAA 控制指令控制,例如:
86+ - `@conductor::conversation::pause::{"scope":"current","reason":"rescue_wait"}`
87+ - `@conductor::conversation::resume::{"scope":"current"}`
88+ - `@conductor::conversation::mode::{"scope":"current","mode":"auto"}`
89+- 具体仲裁规则见 `AUTOMATION_ARBITRATION_REQUIREMENTS.md`
90
91 ## 实现要点
92
93@@ -76,17 +118,25 @@
94 REST API → conductor → 广播 WS → controller → 浮层刷新
95 ```
96
97+系统级同步方向保持独立:
98+
99+```
100+系统暂停/恢复按钮 or REST API → conductor → 更新 system_state.automation → 广播 WS → 浮层刷新
101+```
102+
103 ## 需要注意
104
105 - 新对话默认 `manual`,用户必须主动设为 `auto` 才会续命
106-- "暂停本页"同时暂停两套系统,"恢复本页"恢复到暂停前的状态
107+- “暂停本页”同时暂停页面级 BAA 和 renewal
108+- “恢复本页”只恢复当前对话,不解除系统级暂停
109+- “系统恢复”只恢复系统级闸门,不改各对话原有状态
110 - 如果对话还没有 local_conversation 记录(从没有 final-message),浮层只控制 page_control
111-- 系统级暂停(全局暂停所有自动化)不在本需求范围内,见 `SYSTEM_LEVEL_PAUSE_REQUIREMENTS.md`
112+- 系统级暂停仍是独立需求,见 `SYSTEM_LEVEL_PAUSE_REQUIREMENTS.md`
113
114 ## 验收标准
115
116 - 浮层点击"暂停本页"后,BAA 指令和续命同时暂停
117 - 浮层点击"恢复本页"后,两者同时恢复
118-- 浮层显示当前对话的统一状态
119+- 浮层能同时显示系统状态和当前对话状态
120 - REST API 修改状态后,浮层能实时反映
121 - 不影响现有 BAA 指令主链路