baa-conductor


commit
b063524
parent
9f7e60a
author
im_wower
date
2026-04-01 23:35:36 +0800 CST
docs: add conductor ui implementation plan
1 files changed,  +668, -0
Raw patch view.
  1diff --git a/plans/CONDUCTOR_UI_IMPLEMENTATION_PLAN.md b/plans/CONDUCTOR_UI_IMPLEMENTATION_PLAN.md
  2new file mode 100644
  3index 0000000000000000000000000000000000000000..7f64b328d5e90ad678c4dea233df1a1d3a122dae
  4--- /dev/null
  5+++ b/plans/CONDUCTOR_UI_IMPLEMENTATION_PLAN.md
  6@@ -0,0 +1,668 @@
  7+# Conductor Web UI 工作台实施方案
  8+
  9+日期:`2026-04-01`
 10+
 11+## 状态
 12+
 13+- `基于当前代码与旧 baa-server UI 的实施方案`
 14+- 参考:
 15+  - `plans/CONDUCTOR_UI_MODULE_REQUIREMENTS.md`
 16+  - `/Users/george/code/baa-old-files/baa/baa-server/web/panel.html`
 17+  - `/Users/george/code/baa-old-files/baa/baa-server/web/panel.js`
 18+  - `/Users/george/code/baa-old-files/baa/baa-server/http-server.js`
 19+
 20+## 1. 结论
 21+
 22+可以给当前 `baa-conductor` 增加正式的 Web UI 工作台,但不应照抄旧 `baa-server` 的页面实现。
 23+
 24+推荐方案是:
 25+
 26+1. 新建 `apps/conductor-ui/`
 27+2. 由 `conductor-daemon` 同源托管到 `GET /app`
 28+3. 先交付 `Control` 工作区
 29+4. 再交付 `Channels` 工作区
 30+5. 旧 UI 只复用信息架构和交互模型,不复用旧后端合同
 31+
 32+原因:
 33+
 34+- 当前仓库的真相源和旧 `baa-server` 已经不是一套领域模型
 35+- 当前仓库已经有大量可直接喂 UI 的正式接口,不需要再回到 `/admin/status`、`/channels/*`、`/tools/*` 那套旧协议
 36+- 旧 `panel.js` 已经演变成大体量单文件 DOM 脚本;如果直接复制,只会把历史耦合带进新仓库
 37+
 38+## 2. 旧 UI 给当前方案的直接启发
 39+
 40+旧 `baa-server` UI 的价值不在技术栈,而在这几个结构:
 41+
 42+### 2.1 左侧为全局导航和运行态摘要
 43+
 44+旧 UI 左栏承载了:
 45+
 46+- 凭证状态
 47+- 节点
 48+- CLI 节点
 49+- 频道列表
 50+- 工具
 51+- 日志
 52+
 53+迁到当前仓库后,应该保留“左侧是全局工作区和运行态摘要”的结构,但内容要改成当前正式模型:
 54+
 55+- 系统模式
 56+- 浏览器 bridge / 登录态
 57+- 续命对话
 58+- 任务 / runs / Codex sessions
 59+- 频道列表
 60+
 61+### 2.2 中间主区域为业务线程
 62+
 63+旧 UI 中间区域最有价值的不是“聊天长得像聊天软件”,而是:
 64+
 65+- 有一个明确的“当前上下文”
 66+- 能围绕单个线程读消息、看成员、发消息、看结果
 67+
 68+这正是当前 `conductor-ui` 需要继承的核心。
 69+
 70+### 2.3 实时更新采用 SSE 或轻轮询
 71+
 72+旧 UI 的日志和频道消息都用 SSE;当前仓库也应保持这个方向,但首版不必把所有页面都做成强实时。
 73+
 74+推荐策略:
 75+
 76+- `Control` 首版以 `10s` 到 `15s` 轮询为主
 77+- `Channels` 详情页再补单独 SSE
 78+
 79+### 2.4 登录页是必要能力,不是装饰
 80+
 81+旧 UI 虽然实现粗糙,但至少承认了一个事实:
 82+
 83+- 正式工作台不能默认匿名开放
 84+
 85+当前仓库如果要上线 `/app`,必须把 UI 会话鉴权一起做掉。
 86+
 87+## 3. 当前仓库已具备的 UI 基础
 88+
 89+当前 `baa-conductor` 虽然还没有正式工作台,但已经具备下面这些条件:
 90+
 91+### 3.1 已有真相源 API
 92+
 93+`conductor-daemon` 已有正式接口,可直接给 UI 使用:
 94+
 95+- `GET /v1/system/state`
 96+- `GET /v1/browser`
 97+- `POST /v1/browser/actions`
 98+- `POST /v1/browser/request`
 99+- `GET /v1/tasks`
100+- `GET /v1/tasks/:task_id`
101+- `GET /v1/tasks/:task_id/logs`
102+- `GET /v1/runs`
103+- `GET /v1/runs/:run_id`
104+- `GET /v1/codex`
105+- `GET /v1/codex/sessions`
106+- `GET /v1/codex/sessions/:session_id`
107+- `POST /v1/codex/sessions`
108+- `POST /v1/codex/turn`
109+- `GET /v1/messages`
110+- `GET /v1/messages/:message_id`
111+- `GET /v1/executions`
112+- `GET /v1/executions/:instruction_id`
113+- `GET /v1/sessions`
114+- `GET /v1/sessions/latest`
115+- `GET /v1/renewal/conversations`
116+- `GET /v1/renewal/conversations/:local_conversation_id`
117+- `GET /v1/renewal/links`
118+- `GET /v1/renewal/jobs`
119+
120+### 3.2 已有极窄 HTML 页
121+
122+`status-api` 已经证明:
123+
124+- 当前仓库可以生成 HTML
125+- `conductor-daemon` 可以复用别的 app 的构建产物
126+
127+但 `GET /v1/status/ui` 只是健康页,不应扩成工作台。
128+
129+### 3.3 已有浏览器控制台页面
130+
131+Firefox 插件里的 `controller.html` 已经覆盖了一部分管理面需求:
132+
133+- system mode
134+- WS / HTTP 状态
135+- shell runtime
136+- 登录态元数据
137+- plugin action result
138+
139+所以新 `Control` 工作区不需要从零定义需求,只需要把插件调试页里的正式能力迁到 `/app/control`。
140+
141+## 4. 当前仓库缺失的关键能力
142+
143+工作台真正的阻塞点不在前端,而在这四块:
144+
145+### 4.1 没有正式 `/app` 静态资源托管
146+
147+当前 `conductor-daemon` 没有前端静态站点路由。
148+
149+至少需要新增:
150+
151+- `GET /app`
152+- `GET /app/assets/*`
153+- `GET /app/*` 回退到 `index.html`
154+
155+### 4.2 没有浏览器工作台会话鉴权
156+
157+当前仓库的 host-ops 只有 `BAA_SHARED_TOKEN` 鉴权,但这不适合浏览器 UI。
158+
159+如果 `/app` 面向人类操作,必须新增:
160+
161+- `browser_session` 或 `readonly` 会话
162+- 登录/登出/会话检查接口
163+- 基于 cookie 或短期 token 的浏览器会话
164+
165+建议不要复用旧 UI 的 `localStorage` token 模式。
166+
167+### 4.3 没有“频道”正式领域模型
168+
169+当前仓库已有:
170+
171+- platform message / execution / session artifact
172+- renewal local conversation
173+- browser route link
174+
175+但没有旧 `baa-server` 那种“人类线程主体”:
176+
177+- 没有 `channel`
178+- 没有 `channel_member`
179+- 没有“人从频道发消息,再回流到同一线程”的正式模型
180+
181+这是 `Channels` 工作区最大的后端缺口。
182+
183+### 4.4 没有通用 UI 事件流
184+
185+当前控制页可以靠轮询先上线,但如果要做成真正工作台,还需要:
186+
187+- channel timeline 增量更新
188+- system / browser action 完成回推
189+- task / codex 状态变化回推
190+
191+首版可以延后统一事件总线,但方案里必须预留。
192+
193+## 5. 不应该照搬的旧 UI 能力
194+
195+旧 UI 有些能力不能原样迁移:
196+
197+### 5.1 `/tools/*` 不应直接迁移
198+
199+旧 `baa-server` 有 toolbox 自举和工具注册表。
200+
201+当前 `baa-conductor` 主线不是这个模型,所以:
202+
203+- 不建议在首版 UI 里保留“工具列表”一级区域
204+- 可以用 `Capabilities`、`Artifacts`、`Executions` 替代
205+
206+### 5.2 `CLI 节点` 不应按旧语义迁移
207+
208+旧 UI 的 CLI 节点管理对应旧 `baa-cli` 世界。
209+
210+当前仓库应该迁成:
211+
212+- `controllers`
213+- `tasks`
214+- `runs`
215+- `codexd`
216+- `claude-coded`
217+
218+也就是“执行能力与运行态”,而不是“手工创建 CLI 节点”。
219+
220+### 5.3 旧日志面板不应直接复制
221+
222+旧 UI 的服务端日志面板适合小系统,但当前主仓库里更重要的是结构化状态和 artifact。
223+
224+首版建议不做“裸日志墙”为主入口,而改为:
225+
226+- 最近 action result
227+- renewal jobs
228+- task logs
229+- codex recent events
230+- artifact links
231+
232+## 6. 推荐技术方案
233+
234+### 6.1 前端栈
235+
236+推荐:
237+
238+- `Vite`
239+- `TypeScript`
240+- `Vue 3`
241+- `Vue Router`
242+
243+不推荐继续沿用旧 UI 的“一个 HTML + 一个巨型 JS 文件 + 手工 DOM diff”。
244+
245+原因:
246+
247+- 旧 `panel.js` 已经证明这种结构在工作台规模下会失控
248+- 当前工作台至少包含 `Control`、`Channels`、详情页、抽屉、SSE、鉴权态、轮询态
249+- 不值得为了“少一个依赖”重演一次单文件脚本膨胀
250+
251+同时也不建议上过重栈:
252+
253+- 不需要独立 SSR
254+- 不需要单独 Node UI server
255+- 不需要 Next.js
256+
257+所以前端建议停在“`Vite + Vue 3` 的同源 SPA”。
258+
259+### 6.2 目录结构
260+
261+建议:
262+
263+```text
264+apps/
265+  conductor-ui/
266+    index.html
267+    package.json
268+    tsconfig.json
269+    vite.config.ts
270+    src/
271+      main.ts
272+      App.vue
273+      app/
274+      api/
275+      auth/
276+      routes/
277+      features/
278+        control/
279+        channels/
280+        artifacts/
281+        codex/
282+      components/
283+      styles/
284+```
285+
286+状态管理建议:
287+
288+- 首版优先用 `Composition API`
289+- 跨页面共享状态再引入 `Pinia`
290+
291+### 6.3 运行模式
292+
293+开发态:
294+
295+- `apps/conductor-ui` 独立 dev server
296+- 代理 `/v1/*`、`/describe/*` 到 `http://100.71.210.78:4317`
297+
298+生产态:
299+
300+- `vite build`
301+- 产物落到 `apps/conductor-ui/dist`
302+- `conductor-daemon` 直接同源托管 `/app`
303+
304+### 6.4 静态资源托管
305+
306+`conductor-daemon` 需要新增一个极小的静态站点托管层:
307+
308+- `GET /app` -> `index.html`
309+- `GET /app/` -> `index.html`
310+- `GET /app/assets/*` -> 对应产物
311+- `GET /app/*` -> `index.html`
312+
313+缓存策略:
314+
315+- `index.html`: `no-store`
316+- hashed assets: `max-age=31536000, immutable`
317+
318+## 7. 信息架构
319+
320+沿用已有需求文档中的两大一级工作区:
321+
322+### 7.1 `Control`
323+
324+这是首版必须先交付的工作区。
325+
326+内容建议:
327+
328+- `Overview`
329+  - mode
330+  - leader
331+  - active runs
332+  - queue depth
333+  - browser fresh/stale/lost 计数
334+- `Browser`
335+  - bridge clients
336+  - shell runtime
337+  - 登录态记录
338+  - action buttons
339+- `Renewal`
340+  - local conversations
341+  - active links
342+  - jobs
343+  - `manual / auto / paused`
344+- `Tasks & Runs`
345+  - task list
346+  - run list
347+  - task logs
348+- `Codex`
349+  - codexd status
350+  - sessions
351+  - recent events
352+- `Artifacts`
353+  - recent sessions
354+  - recent messages
355+  - recent executions
356+
357+### 7.2 `Channels`
358+
359+这是正式业务工作区,但应分两阶段做:
360+
361+- 阶段 1:先做 conversation explorer
362+- 阶段 2:再做真正的 channel domain
363+
364+内容建议:
365+
366+- 频道列表
367+- 频道详情
368+- 成员面板
369+- 消息流
370+- 执行结果 / artifact
371+- 目标平台与 route 摘要
372+
373+## 8. 后端分阶段方案
374+
375+### 8.1 Phase 0: UI 基础设施
376+
377+目标:
378+
379+- 让 `/app` 能加载
380+- 让浏览器会话有最小鉴权
381+- 让 UI 有统一 API client 和布局壳
382+
383+需要做的后端工作:
384+
385+1. `conductor-daemon` 增加静态文件托管
386+2. 增加 UI 会话接口
387+3. 基于 `packages/auth` 接入最小 `browser_session`
388+4. 给 `/app` 和未来的 UI 写接口加浏览器会话保护
389+
390+建议新增接口:
391+
392+- `POST /v1/ui/session/login`
393+- `POST /v1/ui/session/logout`
394+- `GET /v1/ui/session/me`
395+
396+建议会话介质:
397+
398+- HttpOnly cookie
399+- SameSite=Lax
400+- 短时过期,可滚动续期
401+
402+不建议:
403+
404+- 像旧 UI 一样把长期 bearer token 放 `localStorage`
405+
406+### 8.2 Phase 1: 先交付 `Control`
407+
408+这是最适合当前仓库的第一版,因为大部分后端已存在。
409+
410+前端直接消费现有接口:
411+
412+- `/v1/system/state`
413+- `/v1/browser`
414+- `/v1/browser/actions`
415+- `/v1/renewal/*`
416+- `/v1/tasks*`
417+- `/v1/runs*`
418+- `/v1/codex*`
419+- `/v1/messages`
420+- `/v1/executions`
421+- `/v1/sessions/latest`
422+
423+Phase 1 原则:
424+
425+- 先不用统一 SSE 总线
426+- 以轮询为主
427+- 写动作只覆盖已有正式控制面
428+
429+这样交付后,可以先把“正式人类入口”从插件页中剥出来。
430+
431+### 8.3 Phase 2: 做 `Channels` 的只读探索器
432+
433+在真正 `channel` 模型完成之前,可以先做一个只读版:
434+
435+- 左栏显示最近活跃会话
436+- 详情页按 `platform + conversation_id` 展示 timeline
437+- 从 `/v1/messages` 拉消息
438+- 从 `/v1/executions?message_id=...` 拉指令结果
439+- 从 `/v1/renewal/conversations/:id` 和 `/v1/renewal/links` 显示本地对话和页面 route
440+
441+这个阶段的价值:
442+
443+- 先把“线程阅读”和“artifact 阅读”做起来
444+- 不阻塞 UI 上线
445+- 也能先验证页面布局和交互模型
446+
447+### 8.4 Phase 3: 引入正式 `channel` 域模型
448+
449+这是旧 UI 真正迁移的关键阶段。
450+
451+建议在 `packages/artifact-db` 中新增频道相关表,而不是放回旧式松散 JSON 文件。
452+
453+推荐原因:
454+
455+- 当前消息、执行、session、renewal conversation 已在 `artifact-db`
456+- 频道要和这些记录做强关联
457+- 放在同一存储里更容易做 timeline 聚合和静态 artifact 链接
458+
459+建议新增表:
460+
461+- `channels`
462+- `channel_members`
463+- `channel_message_links`
464+
465+其中:
466+
467+- `channels` 保存标题、说明、创建时间、最近活动时间
468+- `channel_members` 保存成员类型和目标绑定
469+- `channel_message_links` 负责把 artifact message / execution 归并到 channel timeline
470+
471+成员类型建议至少支持:
472+
473+- `browser_conversation`
474+- `renewal_conversation`
475+- `codex_session`
476+- `claude_coded_session`
477+- `human`
478+
479+建议新增接口:
480+
481+- `GET /v1/channels`
482+- `POST /v1/channels`
483+- `GET /v1/channels/:channel_id`
484+- `PATCH /v1/channels/:channel_id`
485+- `DELETE /v1/channels/:channel_id`
486+- `GET /v1/channels/:channel_id/members`
487+- `POST /v1/channels/:channel_id/members`
488+- `DELETE /v1/channels/:channel_id/members/:member_id`
489+- `GET /v1/channels/:channel_id/thread`
490+- `POST /v1/channels/:channel_id/messages`
491+- `GET /v1/channels/:channel_id/events`
492+
493+### 8.5 Phase 4: 建立统一 timeline 和写路径
494+
495+频道的核心不是表结构,而是统一 timeline。
496+
497+建议 timeline 事件统一成几类:
498+
499+- `human_message`
500+- `assistant_message`
501+- `execution`
502+- `artifact`
503+- `system_event`
504+- `control_event`
505+
506+写路径建议:
507+
508+1. 人在 `/app/channels/:id` 发消息
509+2. `conductor` 根据成员绑定和路由策略选择目标
510+3. 调用现有 browser request / codex / future delivery pipeline
511+4. 回复与执行结果落入 artifact store
512+5. timeline 聚合层把相关记录挂回同一 `channel`
513+6. `/v1/channels/:id/events` 推给 UI
514+
515+## 9. UI 页面拆分建议
516+
517+### 9.1 Shell 布局
518+
519+建议固定为三段:
520+
521+- 左栏:工作区导航 + 快照
522+- 中间:主内容
523+- 右栏:详情抽屉
524+
525+这就是旧 UI 里真正有效的骨架,应该保留。
526+
527+### 9.2 `Control` 页面拆分
528+
529+- `/app/control`
530+  - 系统总览
531+- `/app/control/browser`
532+  - browser records + actions
533+- `/app/control/renewal`
534+  - conversation / links / jobs
535+- `/app/control/tasks`
536+  - tasks + runs
537+- `/app/control/codex`
538+  - codex sessions
539+
540+### 9.3 `Channels` 页面拆分
541+
542+- `/app/channels`
543+  - 列表 + 筛选
544+- `/app/channels/:id`
545+  - timeline
546+  - members
547+  - route summary
548+  - artifact summary
549+
550+### 9.4 登录页
551+
552+- `/app/login`
553+
554+比旧 UI 改进点:
555+
556+- 不在浏览器端保存长期敏感 token
557+- 用 session cookie
558+- 登录态和角色明确区分 `browser_admin` / `readonly`
559+
560+## 10. 旧 UI 能力到新工作台的映射
561+
562+| 旧 UI | 当前仓库映射 | 方案 |
563+| --- | --- | --- |
564+| 凭证状态 | `/v1/browser` | 直接迁到 `Control > Browser` |
565+| 节点 | `/v1/controllers` + `/v1/browser` | 迁到 `Control > Overview` |
566+| CLI 节点 | tasks / runs / codexd / claude-coded | 不按旧概念迁;换成执行工作区 |
567+| 工具 | capabilities / executions | 首版不做旧式工具页 |
568+| 频道列表 | 未来 `/v1/channels` | 需要新增正式模型 |
569+| 频道消息 | `/v1/messages` / future channel thread | 先只读,后统一 timeline |
570+| 日志 | task logs / recent events / optional system logs | 不复制旧日志墙 |
571+| 设置 | `/v1/ui/session/me` + app settings | 保留,但改成会话与环境信息 |
572+
573+## 11. 关键设计选择
574+
575+### 11.1 为什么先做 `Control`
576+
577+因为这部分后端基本已经存在,投资最小,收益最大。
578+
579+交付后立刻能解决:
580+
581+- 插件页被误当主入口
582+- 人类没有正式操作台
583+- 系统状态只分散在接口和插件调试页里
584+
585+### 11.2 为什么 `Channels` 不能直接照搬旧 `/channels/*`
586+
587+因为当前系统的消息来源已经变成:
588+
589+- artifact message
590+- execution result
591+- renewal conversation
592+- browser route
593+- codex session
594+
595+旧 `baa-server` 的频道协议无法直接覆盖这些对象。
596+
597+### 11.3 为什么不推荐继续写纯 DOM 脚本
598+
599+旧 UI 的单文件脚本模式已经证明:
600+
601+- 代码会快速膨胀
602+- 状态同步和 SSE diff 很难维护
603+- 后期改页面结构成本高
604+
605+新工作台必须避免重复这个问题。
606+
607+### 11.4 为什么频道数据建议放进 `artifact-db`
608+
609+因为当前最接近“工作线程”的记录已经在这里:
610+
611+- local conversations
612+- conversation links
613+- messages
614+- executions
615+- sessions
616+- renewal jobs
617+
618+把 `channel` 建在这里,比跨 `db` 和 `artifact-db` 做聚合更稳。
619+
620+## 12. 实施顺序
621+
622+推荐按下面顺序推进:
623+
624+1. `apps/conductor-ui` 脚手架
625+2. `/app` 静态资源托管
626+3. UI 会话鉴权
627+4. `Control` 工作区
628+5. 只读 `Channels Explorer`
629+6. 正式 `channel` 域模型
630+7. `Channels` 写路径与事件流
631+8. 把插件页降级为诊断页
632+
633+## 13. 验收标准
634+
635+### Phase 1 验收
636+
637+- 打开 `/app` 能进入正式工作台
638+- 未登录用户不能直接执行控制写动作
639+- `Control` 页面可以读取:
640+  - system state
641+  - browser status
642+  - renewal status
643+  - tasks / runs
644+  - codex status
645+- `Pause / Resume / Drain` 和 browser actions 可直接从工作台完成
646+
647+### Phase 2 验收
648+
649+- 可以在 `/app/channels` 浏览最近活跃线程
650+- 可以在详情页查看消息、执行结果和 artifact 链接
651+- 页面无需跳回插件页或平台页才能完成主要阅读
652+
653+### Phase 3 验收
654+
655+- 可以创建频道
656+- 可以管理成员
657+- 可以把 browser conversation / renewal conversation / codex session 绑定到频道
658+- 可以从频道内发起正式消息与查看回流结果
659+
660+## 14. 最终建议
661+
662+如果只做一个本轮结论,应当是:
663+
664+- **先把 `Control` 工作区做出来**
665+- **同时补上 UI 会话鉴权和 `/app` 托管**
666+- **`Channels` 先只读,后正式建模**
667+
668+这是当前仓库里风险最低、最符合既有 API 面的路线。
669+
670+如果下一步立刻进入实现,建议拆成三张任务卡:
671+
672+1. `UI-001 /app 静态托管 + conductor-ui 脚手架`
673+2. `UI-002 UI session 鉴权 + /app/login`
674+3. `UI-003 Control 工作区首版`