8.5 KiB
8.5 KiB
YCode 落地方案
历史初始方案。当前运行架构优先使用 OMP RPC sidecar,自建网关保留为回退;现行目标是借助 REA 进行视觉、交互与功能 1:1 复刻。实际完成度见
接手状态-2026-10-15.md;本文件旧里程碑和排除项不作为缩减范围的依据。
日期:2026-10-14 范围:Electron 桌面应用 · 第一个里程碑 = 最小端到端闭环(能对话 + 能跑一个工具)· 自建 OpenAI 兼容网关
0. 前置决策(已确认)
| 项 | 决策 | 理由 |
|---|---|---|
| 产品形态 | Electron 桌面应用 | 与对标形态一致,可复用同批开源 UI 栈 |
| 首里程碑 | 最小端到端闭环 | 一次打通 UI ↔ Agent ↔ 网关 ↔ 工具,最快验证价值 |
| 模型接入 | 自建网关(自有 API Key,OpenAI 兼容) | 协议可控、供应商可换、密钥不出主进程 |
| 产物策略 | clean-room | 不复制对标产品的源码 / CSS / 资源,只用其公开架构与交互模式 |
1. 目标架构
┌──────────────────────────────────────────────────────┐
│ Renderer(React 19 + Zustand) │
│ 对话区 · 右栏上下文 · 设置弹窗 │
│ ⚠ 无 Node / fs / 网络能力 │
└───────────────┬──────────────────────────────────────┘
│ contextBridge(preload 白名单 API)
│ invoke: config/session/chat
│ event : chat:event(流式增量)
┌───────────────▼──────────────────────────────────────┐
│ Main(Electron 主进程 · ESM) │
│ ├ ipc.ts 唯一对外边界 │
│ ├ config.ts safeStorage 加密 Key │
│ ├ sessions.ts 会话与消息持久化 │
│ ├ agent/loop.ts Agent 循环(模型 ↔ 工具) │
│ └ gateway/ 自建网关(OpenAI 兼容 + SSE) │
└───────────────┬──────────────────────────────────────┘
│ HTTPS Bearer(Key 只在此处出现)
▼
自有上游(OpenAI 兼容 /chat/completions)
关键设计点
- 单向分层:
renderer → preload → ipc → agent → gateway → 上游。反向只有chat:event一条流式通道。 - 密钥不出主进程:渲染进程只能拿到
{ hasApiKey, keyStorage },永远拿不到明文。 - 循环与工具解耦:
loop.ts只管编排,工具是纯函数(args, ctx) => ToolResult,新增工具只需改tools/index.ts注册表。 - 网关只管协议:模型路由、上下文裁剪、重试策略不放网关,后续可独立演进。
2. 一次回合的完整链路
用户按 Enter
→ renderer: chat.send({sessionId, text})
→ ipc: 落库用户消息 + 占位助手消息,返回 {runId, assistantMessageId}
→ loop: 拼 system + 历史 + 本轮 → gateway.stream()
→ gateway: POST /chat/completions (stream:true) → 解析 SSE
├ delta.content → emit {type:'text'} → 界面逐字追加
└ delta.tool_calls → 按 index 归并分片
→ 若产生工具调用:
emit tool_call → 执行工具 → emit tool_result
→ 把 assistant(tool_calls) + tool(result) 回填上下文 → 继续下一轮
→ 无工具调用 → emit done → 更新助手消息终态
取消:chat:cancel(runId) → AbortController.abort() → 网关抛 AbortError → emit cancelled。
3. 里程碑拆解
M1 · 最小端到端闭环(本次已落地)
- Electron 壳(
contextIsolation: true/sandbox: true/ 无nodeIntegration) - preload 白名单 API(CJS,因为沙盒要求)
- 自建网关:OpenAI 兼容 + SSE 流式 + 流式工具调用组装
- Agent 循环:多轮工具调用、终止条件、取消
- 工具:
list_dir、read_file(只读 + 工作区逃逸防护) - 配置持久化:
safeStorage加密 Key,明文降级时 UI 告警 - 会话持久化 + 首条消息自动命名
- 界面:会话列表 / 对话区 / 右栏上下文 / 设置弹窗 / 明暗主题
- 类型检查 + 构建通过
M2 · 体验与可靠性
- Markdown 渲染(代码高亮、表格、KaTeX)
- 消息级操作:复制、编辑重发、重新生成
- 工具卡分组折叠(连续调用合并成摘要)
- 断流重试与错误分类提示
- 会话搜索与重命名
M3 · 能力扩展
- 工具扩展:
write_file/edit_file/run_shell(带权限确认) - 审批流:写操作与命令执行需用户确认
- MCP 客户端接入
- Skill 加载(
SKILL.md约定)
M4 · 平台化
- 迁移到 SQLite
- 项目 / 工作目录多实例
- 右栏真实面板(产物预览、文件树、任务)
- 打包分发(electron-builder,Windows 优先)
4. 安全基线
| 风险 | 处置 |
|---|---|
| 渲染进程被注入后提权 | sandbox: true、无 nodeIntegration、CSP 限制 script-src 'self' |
| 密钥泄露 | 只在主进程;safeStorage 加密;日志不打印 |
| 工具越权读写 | 路径解析后做 relative() 逃逸检查,越界直接拒绝 |
| 外链钓鱼 | setWindowOpenHandler 一律 deny + shell.openExternal |
| 任意命令执行 | M1 不提供 shell 工具;M3 引入时必须走审批 |
5. 视觉对齐依据(对标实测值)
配色与排版不再自拟,全部取自两项实测证据:
- 真实 WorkBuddy 运行时布局实测 ——
docs/reference/workbuddy-chat-layout.md(CDP computed style / 元素矩形) - 安装包 token 表 ——
tokens-Df-i-zsO.css、contexts-BkjwYSZT.css
调色板(浅色)
| 用途 | 值 |
|---|---|
| 正文 / 主文字 | #000 |
| 次级 / 三级文字 | rgba(0,0,0,.7) / rgba(0,0,0,.5) |
| 主背景 / 次背景 | #fff / #f2f2f2 |
| hover / active | #ebebeb / #e6e6e6 |
| 边框(主/次/三级) | #e6e6e6 / #ebebeb / #f2f2f2 |
| 品牌 / 成功 / 警告 / 危险 / 信息 | #00c29a / #0cbf5b / #ff7800 / #f64041 / #3370ff |
注意:UI 主体是中性黑白灰,品牌绿只用于状态点缀,不用于主按钮或大面积色块。
圆角与间距
- 圆角:
sm 4px/md 6px/lg 8px/ 气泡16px/ 输入框24px - 间距基准 4px;对话内容列左右内边距
40px
字号
| 角色 | 值 |
|---|---|
| caption / body | 12px / 14px(行高 18 / 21) |
| 用户气泡 | 13px / 19px |
| Markdown 根 | 17.143px,行高 1.75;段落 .875em → 15px / 26.25px |
| 代码块 | 12.857px / 22.5px,padding 12px 16px |
| 表头 | 底色 #f7f7f7,单元格 padding 8px 12px |
结构尺寸
- 左栏
280px;对话内容列max-width 832px居中,左右padding 40px(正文列 752px) - 助手头部:
24px圆形标识 +10px间距,行高24.5px,名称14px/600,下间距12px - 用户气泡:
#f2f2f2、padding8px 12px、圆角16px 16px 0、min-width 40px、max-height 310px - 输入容器:
1px solid #e6e6e6、圆角24px、白底 + 双层轻阴影;编辑区min-height 64px、横向padding 16px;工具栏56px、按钮32px - 滚动:消息列表
flex:1 + min-height:0 + overflow-y:auto,输入区flex-shrink:0固定底部
落地方式:CSS 使用自有类名(
.msg--assistant、.bubble等),仅取实测数值, 不复制对标产品的类名与样式表结构。
6. 与对标分析的关系
docs/ 下三份分析报告(WorkBuddy-AI-实现分析报告、WorkBuddy-AI-复刻可行性评估、WorkBuddy-UI复刻可行性评估)用于指导选型与交互模式,不作为复制来源:
- 可用:组件划分思路、交互状态机、协议约定、开源库清单
- 不可用:对方源码、CSS、图标与图片资源、文案
7. 首次运行清单
npm install && npm run dev- ⚙ 设置:填 baseUrl / 模型名 / API Key;选工作目录
- 提问「列出工作目录里有哪些文件」→ 应看到工具卡出现、执行、结果回填、模型总结