- commit
- 96c8601
- parent
- a2b1055
- author
- jiaozhiwang
- date
- 2026-03-27 15:09:42 +0800 CST
docs: replace PROPOSAL-BAA-INSTRUCTION-V3 with BAA_INSTRUCTION_SYSTEM (final merged spec)
1 files changed,
+908,
-0
+908,
-0
1@@ -0,0 +1,908 @@
2+# BAA 指令系统
3+
4+日期:2026-03-27
5+
6+> 让任何 AI 通过代码块驱动外部能力——shell、文件、浏览器代发、跨 AI 能力借用——不需要原生 function calling。
7+
8+---
9+
10+## 1. 核心规则
11+
12+### 1.1 一个代码块 = 一条指令
13+
14+一个 ` ```baa ``` ` 代码块只包含一条指令,多条指令用多个代码块表达。
15+
16+好处:
17+- 多个代码块 → 多条指令 → **并行执行**
18+- 语义清晰:一块一事
19+- 和 conductor 的异步模式一致(并行提交 → sleep → 单次 poll)
20+- 去重粒度稳定、风险边界清晰
21+
22+### 1.2 双平面模型
23+
24+**控制面**:` ```baa ` 代码块,可执行、可路由、可审计。
25+
26+**内容面**:普通 Markdown、自然语言、`[REQUEST_CONTEXT]`、`[STRESS_TEST]`、`[COUNTER_FACTUAL]`、`LOCKED` 等协作协议。
27+
28+两者配合但不混在一起。BAA 指令系统只负责控制面。
29+
30+### 1.3 conductor 是唯一解释中心
31+
32+插件不解析 baa 代码块。所有解析、路由、去重、权限、执行、结果总结、交付计划都在 conductor 内完成。
33+
34+插件只做四件事:
35+- **观察**:拦截 AI 最终回复,转发给 conductor
36+- **上传**:按 conductor 指示上传文件到 AI 对话
37+- **下载**:从 AI 对话下载文件给 conductor
38+- **注入**:按 conductor 指示注入文本并发送
39+
40+这样无论接多少个平台,插件逻辑不变,不会每个平台重复实现解析和格式化。
41+
42+### 1.4 语法极简,复杂度后移
43+
44+AI 最容易忘的是复杂格式,不容易忘的是代码块。语法层保持极简,复杂度后移到 conductor 内部。
45+
46+---
47+
48+## 2. 指令格式
49+
50+### 2.1 三段式:谁 :: 干什么 :: 怎么干
51+
52+```
53+@target::tool::params
54+```
55+
56+### 2.2 语法文法
57+
58+```ebnf
59+instruction_block = "```baa" , newline , instruction_text , newline? , "```" ;
60+instruction_text = first_line , ( newline , body )? ;
61+first_line = "@" , target , "::" , tool , ( "::" , inline_params )? ;
62+target = token , { "." , token } ;
63+tool = token , { "/" , token } ;
64+body = { any_char } ;
65+token = 1*( ALPHA / DIGIT / "_" / "-" ) ;
66+```
67+
68+### 2.3 四种参数形式
69+
70+**A. 单行字符串参数**
71+
72+ ```baa
73+ @conductor::exec::ls -la ~/code
74+ ```
75+
76+**B. 单行 JSON 参数**
77+
78+ ```baa
79+ @conductor::files/read::{"path": "~/Desktop/HANDOFF.md"}
80+ ```
81+
82+**C. 多行参数**
83+
84+第一行是 `@target::tool`(没有 `::params`),后续所有行拼接为这一条指令的参数:
85+
86+ ```baa
87+ @conductor::exec
88+ cd ~/code/baa-conductor
89+ git status
90+ git log --oneline -3
91+ ```
92+
93+**D. 无参数**
94+
95+ ```baa
96+ @conductor::describe
97+ ```
98+
99+### 2.4 并行执行示例
100+
101+AI 回复中出现 3 个 baa 代码块 = 3 条独立指令 = 并行提交:
102+
103+ 我来同时检查几个东西:
104+
105+ ```baa
106+ @conductor::exec::ls /tmp
107+ ```
108+
109+ ```baa
110+ @conductor::files/read::{"path":"~/Desktop/HANDOFF.md"}
111+ ```
112+
113+ ```baa
114+ @conductor::describe
115+ ```
116+
117+代码块之间的普通文本被忽略,只提取 baa 块。
118+
119+---
120+
121+## 3. 目标地址(target)
122+
123+### 3.1 精确 target
124+
125+| target | 含义 | 路由到 |
126+|---|---|---|
127+| `conductor` / `system` | conductor 本机 | conductor local API |
128+| `browser.claude` | Claude 平台 | `/v1/browser/request` platform=claude |
129+| `browser.chatgpt` | ChatGPT 平台 | `/v1/browser/request` platform=chatgpt |
130+| `browser.gemini` | Gemini 平台 | `/v1/browser/request` platform=gemini |
131+| `codex` | codexd 代理 | `/v1/codex/*` |
132+| `node.mini` / `node.mbp` | 指定机器节点 | SSH / tailscale 执行 |
133+
134+### 3.2 逻辑 target(Phase 4+)
135+
136+| target | 含义 | 路由方式 |
137+|---|---|---|
138+| `pool.image` | 能生图的节点 | conductor 按能力声明选择 |
139+| `pool.video` | 能生视频的节点 | 同上 |
140+| `pool.http` | 能发 HTTP 的节点 | 同上 |
141+| `role.reviewer` | 审阅角色 | conductor 按角色分配 |
142+| `role.coder` | 编码角色 | 同上 |
143+
144+精确寻址与能力路由共存。首版只做精确 target。
145+
146+---
147+
148+## 4. 工具映射(tool → conductor API)
149+
150+| tool | conductor API | 说明 |
151+|---|---|---|
152+| `exec` | `POST /v1/exec` | 执行 shell 命令 |
153+| `files/read` | `POST /v1/files/read` | 读文件 |
154+| `files/write` | `POST /v1/files/write` | 写文件 |
155+| `describe` | `GET /describe` | 系统自描述 |
156+| `describe/business` | `GET /describe/business` | 业务面 |
157+| `describe/control` | `GET /describe/control` | 控制面 |
158+| `status` | `GET /v1/status` | 状态视图 |
159+| `browser/status` | `GET /v1/browser` | 浏览器状态 |
160+| `browser/request` | `POST /v1/browser/request` | 通用代发 |
161+| `browser/actions` | `POST /v1/browser/actions` | 插件管理 |
162+| `send` | 平台对话发送 | browser target 专用 |
163+| `current` | 读当前对话 | browser target 专用 |
164+| `codex/sessions` | `POST /v1/codex/sessions` | 创建 codex session |
165+| `codex/turn` | `POST /v1/codex/turn` | 发 codex turn |
166+| `tasks` | `GET /v1/tasks` | 查看任务 |
167+
168+先实现 `describe / status / exec / files / send / current` 即可跑通闭环。
169+
170+---
171+
172+## 5. 能力互补:每个 AI 都是别人的手
173+
174+### 5.1 各 AI 的能力边界
175+
176+| AI | 能做 | 不能做 |
177+|---|---|---|
178+| Claude | 网络请求(GET/POST)、代码执行、文件操作 | 生图、生视频、生音频 |
179+| ChatGPT | 生图(DALL-E/GPT-Image)、代码执行、GET 请求 | POST 请求、直接操作远程服务器 |
180+| Gemini | 生图(Imagen)、生视频 | 网络请求、POST、访问外部 API |
181+
182+注意:这是当前经验,不是永恒事实。系统实现时应改成节点自描述 + conductor 路由,而不是硬编码。
183+
184+### 5.2 跨 AI 能力借用示例
185+
186+**Gemini 借 shell 能力**:
187+
188+ ```baa
189+ @conductor::exec::git status
190+ ```
191+
192+**ChatGPT 借 POST 能力**:
193+
194+ ```baa
195+ @conductor::exec::curl -X POST https://api.example.com/webhook -d '{"event":"deploy"}'
196+ ```
197+
198+**Claude 借生图能力**:
199+
200+ ```baa
201+ @browser.chatgpt::send::请生成一张赛博朋克风格的城市夜景图,4K 分辨率
202+ ```
203+
204+**Claude 借生视频能力**:
205+
206+ ```baa
207+ @browser.gemini::send::请生成一段 5 秒的视频:一只猫在键盘上打字
208+ ```
209+
210+### 5.3 架构角色
211+
212+```
213+conductor = 唯一中控,提取指令、路由、执行、总结、生成交付计划
214+Firefox 插件 = 薄网关,观察回复、上传文件、下载文件、注入文本
215+各 AI = 能力节点,各有所长,通过 baa 代码块互相借用
216+```
217+
218+---
219+
220+## 6. 端到端链路:从 AI 回复到结果回传
221+
222+### 6.1 现有基础设施
223+
224+插件已有完整的 SSE 拦截→WS 转发链路:
225+
226+```
227+页面 fetch()
228+→ page-interceptor.js hook(streamSse / streamProxyResponse)
229+→ 逐 chunk 通过 content-script 发给 controller.js
230+→ controller.js handlePageSse()
231+→ wsSend() 通过 WS 发给 conductor
232+```
233+
234+当前 `handlePageSse()` 对有机回复(用户正常聊天)只更新本地状态就 return 了。只需在 `done === true` 时加一个 `wsSend` 把完整回复文本转发给 conductor,整条链路就打通。
235+
236+### 6.2 完整闭环
237+
238+```
239+用户 / AI 在网页对话
240+→ 页面 fetch() 被 page-interceptor hook
241+→ SSE chunks 逐个转发给 controller.js
242+→ 回复完成(done=true)时,controller 拼接完整文本
243+→ wsSend({ type: "assistant_message_complete", text, platform, conversationId })
244+→ conductor 收到完整回复文本
245+→ conductor extractBaaBlocks()
246+→ conductor parseBaaBlock() × N
247+→ conductor 去重 + 权限校验
248+→ conductor 并行执行(exec / files / browser/request / codex)
249+→ conductor 汇总结果
250+→ conductor 生成 delivery plan(哪些走文件上传,哪些走文本注入)
251+→ WS 指示插件执行 delivery plan
252+→ 插件上传文件 / 注入文本 / 点击发送
253+→ AI 看到结果,继续工作
254+```
255+
256+### 6.3 插件侧改动量
257+
258+只需在 controller.js 的 `handlePageSse` 中加一段:
259+
260+```javascript
261+// 有机回复完成时,转发全文给 conductor
262+if (data.done && !pending) {
263+ const fullText = getAccumulatedSseText(context.platform, context.conversationId);
264+ if (fullText) {
265+ wsSend({
266+ type: "assistant_message_complete",
267+ platform: context.platform,
268+ conversationId: getConversationId(context),
269+ messageId: getLastAssistantMessageId(context),
270+ text: fullText
271+ });
272+ }
273+}
274+```
275+
276+其余所有逻辑(解析、执行、总结、交付计划)都在 conductor 侧。
277+
278+---
279+
280+## 7. 解析器(conductor 侧)
281+
282+### 7.1 提取 baa 代码块
283+
284+```javascript
285+function extractBaaBlocks(text) {
286+ const blocks = [];
287+ const re = /```baa\s*\n([\s\S]*?)```/g;
288+ let m;
289+ while ((m = re.exec(text)) !== null) {
290+ const body = m[1].trim();
291+ if (body) blocks.push(body);
292+ }
293+ return blocks;
294+}
295+```
296+
297+### 7.2 解析单条指令
298+
299+```javascript
300+function parseBaaBlock(blockText) {
301+ const lines = blockText.split('\n');
302+ const firstLine = lines[0].trim();
303+ const m = firstLine.match(/^@([^:\s]+)::([^:\s]+)(?:::([\s\S]*))?$/);
304+ if (!m) return null;
305+
306+ const target = m[1];
307+ const tool = m[2];
308+ const inlineParams = m[3] ? m[3].trim() : null;
309+
310+ if (inlineParams !== null) {
311+ return { target, tool, params: parseParamValue(inlineParams) };
312+ }
313+
314+ const rest = lines.slice(1).join('\n').trim();
315+ return rest
316+ ? { target, tool, params: { command: rest } }
317+ : { target, tool, params: {} };
318+}
319+
320+function parseParamValue(raw) {
321+ if (!raw) return {};
322+ if (raw.startsWith('{')) {
323+ try { return JSON.parse(raw); } catch { /* fall through */ }
324+ }
325+ return { command: raw };
326+}
327+```
328+
329+### 7.3 只解析最终权威消息
330+
331+不在 streaming 半截文本上执行。必须等 `assistant_message_complete` 到达 conductor 后再提取。
332+
333+---
334+
335+## 8. 结果交付:文件上传优先,文本兜底
336+
337+### 8.1 分层策略
338+
339+| 结果大小 | 交付方式 | 场景 |
340+|---|---|---|
341+| 小(< 500 字) | 文本注入 | pwd、describe、短输出 |
342+| 中/大(≥ 500 字) | 文件上传 + 索引文本 | 读文件、日志、git diff |
343+| 文件上传失败 | 降级为截断文本(2000 字 + 摘要) | 兜底 |
344+
345+### 8.2 为什么文件上传优于贴文本
346+
347+| 维度 | 文本注入 | 文件上传 |
348+|---|---|---|
349+| Context window 占用 | 直接吃上下文 | 走附件通道,占用更小 |
350+| 大结果处理 | 500 行日志撑爆对话 | 文件天然承载大内容 |
351+| 结构化 | 需要解析前缀 | 文件名即元数据 |
352+| 多结果并行 | 一大坨拼接文本 | 多个文件,清晰分离 |
353+
354+### 8.3 Artifact 生命周期(conductor 侧)
355+
356+```
357+raw execution results
358+→ summarize(每条指令生成一行摘要)
359+→ materialize artifacts(大结果写成文件)
360+→ build manifest(汇总所有 artifact 的索引)
361+→ build delivery plan(决定哪些上传、哪些文本注入)
362+→ WS 指示插件执行
363+→ 插件上传文件 → 返回 upload receipt
364+→ 所有上传确认后,conductor 生成索引文本
365+→ WS 指示插件注入索引文本并发送
366+```
367+
368+关键原则:**上传成功后才发送索引文本**。没有确认就注入,AI 会看到"结果见附件"但附件还没出现。
369+
370+### 8.4 文件上传实现(插件侧)
371+
372+各平台的 AI 对话输入框都有文件上传入口。插件通过模拟文件拖拽上传:
373+
374+```javascript
375+async function uploadResultFile(platform, filename, content) {
376+ const blob = new Blob([content], { type: 'text/plain' });
377+ const file = new File([blob], filename, { type: 'text/plain' });
378+
379+ const dropZone = findDropZone(platform);
380+ if (!dropZone) return false;
381+
382+ const dt = new DataTransfer();
383+ dt.items.add(file);
384+ dropZone.dispatchEvent(new DragEvent('drop', { dataTransfer: dt, bubbles: true }));
385+ return true;
386+}
387+```
388+
389+上传后需确认附件 chip 出现才算成功。
390+
391+### 8.5 文件命名规范
392+
393+```
394+baa-result_{tool}_{target}_{status}.md
395+```
396+
397+示例:`baa-result_exec_conductor_ok.md`、`baa-result_files-read_conductor_ok.md`
398+
399+### 8.6 推荐文件类型
400+
401+不强制所有结果都是 `.md`:
402+
403+| 内容 | 文件类型 |
404+|---|---|
405+| 日志 | `.log` |
406+| JSON | `.json` |
407+| diff | `.patch` |
408+| CSV | `.csv` |
409+| 摘要 | `.md` |
410+| 图片 | `.png` |
411+| 视频 | `.mp4` |
412+
413+### 8.7 索引文本格式
414+
415+上传完成后注入的文本:
416+
417+```
418+[BAA 结果索引]
419+- @conductor::exec::ls /tmp → 成功(结果见 baa-result_exec_conductor_ok.md)
420+- @conductor::files/read → 成功(结果见 baa-result_files-read_conductor_ok.md)
421+- @conductor::describe → 成功(内联)
422+
423+describe 结果:
424+{"deployment_mode": "single-node mini", ...}
425+```
426+
427+小结果内联在索引文本里,大结果只给摘要+文件名引用。
428+
429+### 8.8 文本兜底格式
430+
431+所有上传都失败时,降级为纯文本注入:
432+
433+```
434+[BAA 执行结果]
435+
436+--- @conductor::exec::ls /tmp ---
437+成功:
438+file1.txt
439+file2.txt
440+(输出已截断,完整结果 2.3KB)
441+```
442+
443+### 8.9 下载流
444+
445+当目标 AI 返回图片/视频/文件时:
446+
447+```
448+conductor 生成 download plan
449+→ WS 指示插件下载
450+→ 插件下载文件 → 回传本地路径
451+→ conductor 决定:存档 / 转发给其他 AI / 摘要
452+```
453+
454+---
455+
456+## 9. 执行闭环与状态机
457+
458+### 9.1 状态流转
459+
460+```
461+Idle
462+→ WaitingFinalMessage(assistant streaming)
463+→ Extracting(assistant_message_complete 到达 conductor)
464+ → Idle(no baa blocks)
465+ → Normalizing(found baa blocks)
466+→ DedupeCheck
467+ → Idle(all duplicate)
468+ → PolicyCheck(new instructions)
469+→ Dispatching(allowed)
470+→ WaitingResults
471+→ MaterializingArtifacts
472+→ BuildingManifest
473+→ BuildingDeliveryPlan
474+→ PluginUploading
475+→ WaitingUploadAck
476+ → InjectingIndex(all uploads confirmed)
477+ → DeliveryFailed(upload timeout / failed → 降级文本兜底)
478+→ CoolingDown
479+ → WaitingFinalMessage(auto-next-turn)
480+ → Idle(stop condition reached)
481+
482+Pause / Resume / Drain 可在任何活跃状态触发。
483+DeliveryFailed → Idle
484+```
485+
486+### 9.2 并行与顺序
487+
488+多个 baa block = 并行执行。有严格顺序依赖时用单个多行 exec 或分成多轮。
489+
490+### 9.3 终止条件
491+
492+满足任一条件停止自动循环:
493+- hop limit 达上限(默认 10)
494+- 连续失败达阈值(默认 3)
495+- 用户手动输入(人工抢占最高优先级)
496+- 系统 pause / drain
497+- 下一轮回复没有 baa 指令
498+- 路由器找不到合法目标
499+- artifact 上传持续失败
500+
501+### 9.4 冷却与节流
502+
503+- 每轮注入后冷却 2 秒
504+- 同轮最大并发数:8
505+- 结果注入总字符数限制:32KB(超出走文件上传)
506+- 单轮总上传大小限制:可配置
507+
508+### 9.5 核心规则
509+
510+1. **只解析最终权威消息**——不在 streaming 中途解析
511+2. **只解析 ` ```baa `**——不执行普通代码块
512+3. **每个 block 独立去重**——同一条消息的第 0 块和第 1 块分开跟踪
513+4. **结果先产物化,再决定怎么交付**——不直接把 raw output 塞回对话
514+5. **上传成功后才发送索引文本**——避免"结果见附件"但附件没到
515+6. **用户输入优先级最高**——用户开始打字时自动注入立即让路
516+
517+---
518+
519+## 10. 权限与安全
520+
521+### 10.1 风险分层
522+
523+| 层级 | 示例 | 默认策略 |
524+|---|---|---|
525+| Tier 0 只读 | describe, status, files/read, tasks | 自动执行 |
526+| Tier 1 低风险写 | 工作区 files/write, browser send | 自动执行 + 审计 |
527+| Tier 2 执行/网络 | exec, curl, git 写操作 | 白名单或 shared token |
528+| Tier 3 危险操作 | rm -rf, 系统 reload, credential 操作 | 必须人工批准 |
529+
530+### 10.2 三道边界
531+
532+- **语法边界**:只执行 ` ```baa `,不执行普通代码块
533+- **权限边界**:解析成功 ≠ 允许执行
534+- **环境边界**:token / sandbox / workspace path allowlist
535+
536+### 10.3 审计日志
537+
538+每条指令至少记录:instruction_id、source_node、target、tool、risk_tier、policy_decision、started_at、finished_at、result_summary、delivery_plan_id、upload_receipt_hash。
539+
540+### 10.4 人工接管点
541+
542+- 执行前(高风险)
543+- 结果注入前(可编辑)
544+- 路由失败后(人工改派)
545+- 连续失败熔断后
546+
547+---
548+
549+## 11. conductor 内部标准化
550+
551+### 11.1 Envelope
552+
553+conductor 收到 `assistant_message_complete`,提取 baa 块后转为标准化对象:
554+
555+```typescript
556+interface NormalizedInstruction {
557+ instructionId: string;
558+ traceId: string;
559+ conversationId: string | null;
560+ assistantMessageId: string | null;
561+ blockIndex: number;
562+ sourceNode: string;
563+ target: string;
564+ tool: string;
565+ params: Record<string, unknown>;
566+ riskTier: "tier0" | "tier1" | "tier2" | "tier3";
567+ dedupeKey: string;
568+ roundId: string | null;
569+ hop: number;
570+ createdAt: number;
571+}
572+```
573+
574+### 11.2 去重键
575+
576+```
577+dedupe_key = sha256(platform | conversation_id | assistant_message_id | block_index | normalized_block_text)
578+```
579+
580+### 11.3 路由决策
581+
582+```typescript
583+interface RouteDecision {
584+ resolvedTarget: string;
585+ resolvedNodeId?: string;
586+ routeReason: string[];
587+ fallbackCandidates: string[];
588+}
589+```
590+
591+首版只做精确路由(conductor / browser.* / codex),Phase 4 加能力池打分路由。
592+
593+### 11.4 Delivery Plan
594+
595+```typescript
596+interface DeliveryPlan {
597+ planId: string;
598+ traceId: string;
599+ conversationId: string | null;
600+ target: string;
601+ uploads: DeliveryUploadItem[];
602+ messageText: string;
603+ autoSend: boolean;
604+}
605+
606+interface DeliveryUploadItem {
607+ artifactId: string;
608+ filename: string;
609+ mimeType: string;
610+ localPath: string;
611+}
612+
613+interface UploadReceipt {
614+ artifactId: string;
615+ ok: boolean;
616+ remoteHandle?: string;
617+ errorCode?: string;
618+}
619+```
620+
621+---
622+
623+## 12. 与当前 baa-conductor 的对接
624+
625+### 12.1 当前已有的基础
626+
627+**插件侧(已到位)**:
628+- page-interceptor.js:fetch hook + SSE 拦截 + 逐 chunk 转发
629+- controller.js:handlePageSse + wsSend → WS 转发给 conductor
630+- 文本注入能力(injectText)
631+- 文件拖拽上传能力(DataTransfer 模拟)
632+
633+**conductor 侧(已到位)**:
634+- local API:exec / files / browser / codex / tasks / describe / status / pause/resume/drain
635+- firefox-ws.ts:WS 消息接收和分发
636+- firefox-bridge.ts:stream session(seq tracking、buffer overflow、idle timeout)
637+- browser-request-policy.ts:限流/抖动/退避/熔断
638+- packages/db:SQLite 存储
639+- packages/auth:token 验证
640+
641+### 12.2 需要新增的
642+
643+**插件侧(改动极小)**:
644+- handlePageSse 中 `done === true` 且非代理请求时,`wsSend` 转发完整回复文本
645+- 接收 conductor 的 delivery plan 并执行(上传文件 + 注入文本)
646+
647+**conductor 侧(新增模块)**:
648+
649+```
650+apps/conductor-daemon/src/instructions/
651+ extract.ts ← extractBaaBlocks
652+ parse.ts ← parseBaaBlock
653+ normalize.ts ← 标准化 envelope + 去重键
654+ dedupe.ts ← 去重缓存
655+ policy.ts ← 风险分层 + 权限校验
656+ router.ts ← 精确路由 + 能力池(Phase 4)
657+ executor.ts ← 并行执行 + 结果汇总
658+ artifact.ts ← 产物化 + manifest
659+ delivery.ts ← delivery plan 生成
660+ loop.ts ← 状态机 + 自动循环控制
661+```
662+
663+firefox-ws.ts 新增消息类型:
664+- 接收:`assistant_message_complete`(插件转发的 AI 完整回复)
665+- 发送:`delivery_plan`(指示插件上传/注入)
666+- 接收:`upload_receipt`(插件上传结果确认)
667+
668+---
669+
670+## 13. AI 侧提示词
671+
672+### 通用提示词(适用于 Claude / ChatGPT / Gemini)
673+
674+```
675+你可以通过 baa 代码块请求外部能力。
676+
677+规则:
678+1. 只在确实需要外部操作时输出 ```baa 代码块。
679+2. 一个代码块只包含一条指令。
680+3. 多条独立指令用多个代码块,默认并行执行。
681+4. 优先读操作,再写操作,再高风险执行。
682+5. 展示示例代码时不要用 baa 代码块。
683+6. 借别的平台能力用精确 target(如 @browser.chatgpt::send)。
684+
685+基本格式:
686+
687+ ```baa
688+ @conductor::exec::pwd
689+ ```
690+
691+ ```baa
692+ @conductor::files/read::{"path":"~/code/README.md"}
693+ ```
694+
695+多行命令:
696+
697+ ```baa
698+ @conductor::exec
699+ cd ~/code/baa-conductor
700+ npm test
701+ ```
702+
703+执行结果会自动回传(小结果文本注入,大结果文件上传),继续分析即可。
704+```
705+
706+---
707+
708+## 14. 渐进式落地阶段
709+
710+### Phase 0:冻结语法
711+
712+确认语法规范,生成通用 prompt 模板,验证三个平台都能稳定输出 ` ```baa `。
713+
714+### Phase 1:conductor 解析中心 + 薄插件
715+
716+插件加一行 wsSend 转发完整回复。conductor 新增 instructions/ 模块(extract → parse → route → execute → delivery plan)。先跑通 Claude 链路:能稳定自动执行 3~5 轮,不重复执行,用户输入能打断,失败会熔断。
717+
718+### Phase 2:artifact 交付
719+
720+大结果产物化 + manifest + 文件上传 + upload receipt barrier + 索引文本。上传成功后才发索引。多结果并行时 manifest 稳定。
721+
722+### Phase 3:ChatGPT / Gemini 正式接入
723+
724+`/v1/browser/chatgpt/*` + `/v1/browser/gemini/*` 正式 surface。验收:Claude 能借 ChatGPT 生图,ChatGPT 能借 conductor 做 shell。
725+
726+### Phase 4:能力池与角色池
727+
728+pool.image / pool.video / pool.exec / role.reviewer / role.coder。验收:`@pool.image::generate` 能自动选可用节点。
729+
730+### Phase 5:多 AI 自洽协作层
731+
732+round / chain / gossip / consensus 纳入统一编排。
733+
734+### Phase 6:任务池与后台长流程
735+
736+task/create + task/poll,复杂流程不再挤在一个聊天轮次里。
737+
738+### 每阶段回归项
739+
740+- 不解析普通代码块
741+- 不在 streaming 半截执行
742+- 不重复执行同一块
743+- 用户输入能抢占
744+- pause / resume / drain 稳定
745+- 结果不泄露敏感信息
746+- 上传 / 下载失败能重试或降级
747+
748+---
749+
750+## 15. 直接可用示例
751+
752+### 本机操作
753+
754+ ```baa
755+ @conductor::exec::ls ~/code
756+ ```
757+
758+ ```baa
759+ @conductor::files/read::{"path":"~/Desktop/HANDOFF.md"}
760+ ```
761+
762+ ```baa
763+ @conductor::exec
764+ cd ~/code/baa-conductor
765+ pnpm test
766+ ```
767+
768+### 能力借用
769+
770+ ```baa
771+ @browser.chatgpt::send::请生成一张赛博朋克风格城市夜景图
772+ ```
773+
774+ ```baa
775+ @browser.gemini::send::请生成一段 5 秒的视频:一只猫在键盘上打字
776+ ```
777+
778+### 系统管理
779+
780+ ```baa
781+ @conductor::describe
782+ ```
783+
784+ ```baa
785+ @conductor::browser/actions::{"action":"plugin_status"}
786+ ```
787+
788+---
789+
790+## 附录 A:TypeScript 类型定义
791+
792+```typescript
793+export type RiskTier = "tier0" | "tier1" | "tier2" | "tier3";
794+export type DeliveryMode = "inline" | "inline_and_artifact" | "artifact_only";
795+
796+export interface ParsedBaaInstruction {
797+ rawBlock: string;
798+ blockIndex: number;
799+ target: string;
800+ tool: string;
801+ params: Record<string, unknown>;
802+}
803+
804+export interface NormalizedInstruction extends ParsedBaaInstruction {
805+ instructionId: string;
806+ traceId: string;
807+ conversationId: string | null;
808+ assistantMessageId: string | null;
809+ sourceNode: string;
810+ roundId: string | null;
811+ hop: number;
812+ riskTier: RiskTier;
813+ dedupeKey: string;
814+ createdAt: number;
815+}
816+
817+export interface RouteDecision {
818+ resolvedTarget: string;
819+ resolvedNodeId?: string;
820+ routeReason: string[];
821+ fallbackCandidates: string[];
822+}
823+
824+export interface ArtifactRef {
825+ artifactId: string;
826+ kind: "summary" | "payload" | "manifest" | "preview" | "log" | "image" | "video" | "other";
827+ filename: string;
828+ mimeType: string;
829+ sizeBytes?: number;
830+ sha256?: string;
831+ localPath?: string;
832+ remoteHandle?: string | null;
833+}
834+
835+export interface ExecutionResult {
836+ instructionId: string;
837+ ok: boolean;
838+ target: string;
839+ tool: string;
840+ summary: string;
841+ data?: unknown;
842+ truncated?: boolean;
843+ deliveryMode: DeliveryMode;
844+ artifactRefs?: ArtifactRef[];
845+ errorCode?: string;
846+}
847+
848+export interface DeliveryUploadItem {
849+ artifactId: string;
850+ filename: string;
851+ mimeType: string;
852+ localPath: string;
853+}
854+
855+export interface DeliveryPlan {
856+ planId: string;
857+ traceId: string;
858+ conversationId: string | null;
859+ target: string;
860+ uploads: DeliveryUploadItem[];
861+ messageText: string;
862+ autoSend: boolean;
863+}
864+
865+export interface UploadReceipt {
866+ artifactId: string;
867+ ok: boolean;
868+ remoteHandle?: string;
869+ errorCode?: string;
870+}
871+
872+export interface DownloadPlan {
873+ downloadPlanId: string;
874+ items: Array<{
875+ remoteHandle: string;
876+ suggestedFilename: string;
877+ savePath: string;
878+ }>;
879+}
880+```
881+
882+## 附录 B:结果交付决策伪代码
883+
884+```javascript
885+async function deliverResults(platform, results, wsChannel) {
886+ // conductor 侧决策
887+ const artifacts = materializeArtifacts(results);
888+ const manifest = buildManifest(results, artifacts);
889+ const plan = buildDeliveryPlan(results, artifacts, manifest);
890+
891+ // 通过 WS 指示插件执行
892+ wsChannel.send({ type: "delivery_plan", plan });
893+
894+ // 等待插件上传确认
895+ const receipts = await waitForUploadReceipts(plan.uploads, { timeoutMs: 30000 });
896+ const allUploaded = receipts.every(r => r.ok);
897+
898+ if (!allUploaded) {
899+ // 降级:未上传成功的改为截断文本
900+ const degradedText = formatDegradedTextResults(results, receipts);
901+ wsChannel.send({ type: "inject_text", text: degradedText, autoSend: true });
902+ return;
903+ }
904+
905+ // 全部上传成功,发送索引文本
906+ const indexText = renderIndexText(results, manifest);
907+ wsChannel.send({ type: "inject_text", text: indexText, autoSend: plan.autoSend });
908+}
909+```