xworkmate-app/docs/ai-context/refactor-notes.md
2026-06-05 21:25:29 +08:00

291 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Refactor Notes — 重构建议与架构审核
> 生成日期: 2026-06-05 | 基于 chain-map 和 module-boundary 的架构分析
---
## 总体评估
三个仓库形成了一个**清晰的 3 层架构**App → Bridge → (Providers + Gateway + Plugins)。架构在职责拆分上是合理的,但在以下几个方面存在可改进的空间:
1. **循环依赖已收敛**: Plugin → Bridge (HTTP) 反向调用已从目标架构中移除Plugin 只保留被 Gateway 调用的 artifact adapter 职责
2. **协议层过多**: Chain 2 经过 4 层跳转 (App → Bridge → Gateway → Plugin)
3. **容错不足**: 多处依赖未处理的状态丢失场景
4. **配置分散**: App/Bridge/Plugin 各自维护连接配置,缺乏统一管理
---
## 问题 1: Plugin ↔ Bridge 循环依赖
### 现状
```
Bridge → (Gateway RPC) → Plugin (xworkmate.artifacts.*)
Plugin → (HTTP JSON-RPC) → Bridge (session.start, multiAgent)
```
### 问题
- 两个方向使用不同协议 (Gateway RPC vs HTTP JSON-RPC),增加调试难度
- 循环引用导致: Bridge 故障 → Plugin 不可用 → Bridge 的 agent 调用失败 → Plugin 的 bridge agent 反向调用也无法工作
- 版本升级需要同步两个方向
### 建议
**方案 A (推荐): 统一为单向调用**
删除 Plugin 中的 `bridgeAgents.ts` 反向 HTTP 客户端;多 agent 编排归 Bridge 或 OpenClaw 原生 runtime
```
Bridge
internal/
acp/
orchestrator.go ← 拥有 bridge 侧编排逻辑
gateway.go ← 保留 xworkmate.artifacts.* 调用
```
Plugin 变为纯工件管理 (只被调,不反向调用):
```
Plugin (简化后)
src/exportArtifacts.ts ← 只保留 prepare/export/list/read
删除 src/bridgeAgents.ts ← 不再从插件反向调用 Bridge
```
**方案 B: 统一协议方向**
Plugin ↔ Bridge 全部走 Gateway RPC (去掉 Plugin 中的 HTTP 调用):
- Bridge 新增 `xworkmate.bridge.*` 网关方法供 Plugin 调用
- Plugin 通过 `api.callGatewayMethod()` 而非 `fetch()` 调用 Bridge
### 影响范围
- 方案 A: 删除 Plugin 的 bridgeAgents.tsBridge/OpenClaw 原生 runtime 拥有编排
- 方案 B: 改动 Bridge (新增网关方法) + Plugin (改用网关调用)
---
## 问题 2: Chain 2 协议层过多
### 现状
```
App ──(ACP/WS)──► Bridge ──(GW RPC/WS)──► Gateway ──(Plugin API)──► Plugin
跳数: 4 协议变换: 2 次
```
### 问题
- 每层增加延迟和故障点
- 错误信息层层包装,难以定位根因
- Gateway 层是性能瓶颈 (WebSocket 单连接复用)
### 建议
**短期优化**:
在 Bridge 中增加 Gateway 连接池(当前为单连接):
```go
// gatewayruntime/pool.go (新增)
type GatewayPool struct {
conns []*GatewayRuntime
maxSize int
mu sync.Mutex
}
func (p *GatewayPool) Acquire() *GatewayRuntime { ... }
func (p *GatewayPool) Release(rt *GatewayRuntime) { ... }
```
**中期优化**:
Bridge 缓存工件元数据,减少实时 Gateway 调用:
```go
// internal/acp/artifact_cache.go (新增)
type ArtifactCache struct {
cache map[string]*CachedArtifact
ttl time.Duration
}
// 命中缓存时跳过 Gateway→Plugin 调用
func (c *ArtifactCache) GetOrFetch(sessionKey, runId string) { ... }
```
**长期考虑**:
如果 Plugin 始终与 Bridge 在同一主机,考虑内嵌 Plugin 为 Bridge 内部模块(避免 Gateway RPC 中转)。
---
## 问题 3: 容错与恢复
### 3.1 SSE 流中断降级为轮询
**现状** (`external_code_agent_acp_desktop_transport.dart`):
```
SSE 流中断 → 降级为 xworkmate.tasks.get 轮询 → 非实时
```
**建议**:
- 在 Bridge 中维护任务状态的增量日志,支持断点续传
- App 重连时发送 `session.resume` 而非重新 `session.start`
### 3.2 Gateway WebSocket 断连 → 任务状态丢失
**现状** (`gatewayruntime/runtime.go`): 断连后未持久化任务状态。
**建议**:
- Bridge 中维护 `tasks` map断连时标记为 `STALE`
- 重连后自动查询任务最新状态
- 超过 TTL 的 STALE 任务发出 `session.cancel` 通知 App
### 3.3 Gemini/Hermes 子进程崩溃
**现状**: 子进程崩溃后无自动重启。
**建议**:
```go
// internal/geminiadapter/process_manager.go (增强)
type ProcessManager struct {
cmd *exec.Cmd
restartMax int // 最大重启次数
backoff time.Duration // 退避策略
}
func (pm *ProcessManager) Start() {
for i := 0; i < pm.restartMax; i++ {
if err := pm.run(); err != nil {
time.Sleep(pm.backoff * time.Duration(1<<i))
continue
}
break
}
}
```
---
## 问题 4: 配置管理分散
### 现状
| 组件 | 配置位置 | 管理方式 |
|------|---------|---------|
| App | `config/settings.yaml` | 本地文件 |
| App | `config/feature_flags.yaml` | 本地文件 |
| Bridge | 环境变量 / `config.yaml` | Ansible 部署 |
| Plugin | `openclaw.plugin.json` / 环境变量 | 插件清单 |
### 问题
- 旧版 Plugin 的 `bridgeUrl``bridgeToken` 已从目标架构中移除;剩余连接配置集中在 App/Bridge/Gateway
- 配置不一致导致调试困难
- 无版本化配置管理
### 建议
**集中配置源**: 使用 accounts.svc.plus 作为配置中心。
```
accounts.svc.plus
GET /api/config/bridge → { serverUrl, authToken, providers... }
GET /api/config/plugin → { workspaceDir, artifact policy... }
```
**本地配置缓存**:
- App 首次启动从 accounts 拉取配置
- Bridge 启动时从 accounts 拉取 providers 配置
- Plugin 从 OpenClaw 网关配置中继承 bridge 连接信息
---
## 问题 5: 无版本兼容性检查
### 现状
三个仓库独立发布,无版本契约:
- xworkmate-app: 1.1.4
- xworkmate-bridge: (无显式版本)
- openclaw-multi-session-plugins: 0.1.15
### 建议
**在 ACP 协议中增加版本协商**:
```json
// acp.capabilities 响应中增加
{
"protocolVersion": "1.0.0",
"minCompatibleVersion": "1.0.0",
"componentVersions": {
"app": "1.1.4",
"bridge": "0.2.0",
"gateway": "2026.5.28",
"plugins": "0.1.15"
}
}
```
**App 启动时校验**:
```dart
// gateway_runtime_core.dart
final caps = await gatewayRuntime.getCapabilities();
if (!isCompatible(caps.minCompatibleVersion)) {
showUpdateDialog();
return;
}
```
---
## 重构优先级矩阵
| 优先级 | 问题 | 改动量 | 影响 | 建议时序 |
|--------|------|--------|------|---------|
| **P0** | Plugin↔Bridge 循环依赖 | 中 (删除 bridgeAgents) | 消除循环 + 简化协议 | 已落实为目标架构 |
| **P0** | Gateway 断连任务丢失 | 小 (增加持久化) | 核心可靠性 | 本周 |
| **P1** | Gemini/Hermes 进程崩溃 | 小 (增加重启) | 提供商可用性 | 本周 |
| **P1** | 配置管理分散 | 大 (集中配置) | 运维效率 | 本月 |
| **P2** | Chain 2 协议层过多 | 大 (连接池+缓存) | 性能 + 延迟 | 本月 |
| **P2** | 版本兼容性检查 | 小 (协议扩展) | 升级安全 | 本月 |
| **P3** | SSE 降级轮询优化 | 中 (增量日志) | 用户体验 | 下月 |
---
## 各仓库具体改动清单
### xworkmate-app
- [ ] `lib/runtime/gateway_acp_client.dart`: 增加版本兼容性检查
- [ ] `lib/runtime/external_code_agent_acp_desktop_transport.dart`: 支持 session.resume
- [ ] `lib/runtime/runtime_models_account.dart`: 从 accounts 拉取集中配置
- [ ] `config/settings.yaml`: 减少硬编码 URL改为从 accounts 获取
### xworkmate-bridge
- [ ] `internal/acp/orchestrator.go`: 保持 Bridge 侧编排归属,不从 Plugin 反向调用 Bridge
- [ ] `internal/gatewayruntime/runtime.go`: 增加连接池 + 任务状态持久化
- [ ] `internal/gatewayruntime/pool.go`: 新增连接池
- [ ] `internal/acp/artifact_cache.go`: 新增工件缓存
- [ ] `internal/geminiadapter/` + `internal/hermesadapter/`: 增加子进程自动重启
- [ ] `internal/acp/rpc_handler.go`: 支持 session.resume
### openclaw-multi-session-plugins
- [x] `src/bridgeAgents.ts`: 删除反向 HTTP 调用边界
- [ ] `openclaw.plugin.json`: 简化配置(从网关继承 bridge 信息)
- [ ] `src/exportArtifacts.ts`: 增加 artifactRef TTL 可配置
---
## 不做的事情
| 项目 | 原因 |
|------|------|
| 引入 gRPC 替代 JSON-RPC | 现有协议工作正常,切换成本高于收益 |
| 合并 App 和 Bridge 为单体 | 拆分有明确的价值 (独立部署、技术栈隔离) |
| 引入消息队列 | 当前规模不需要,会增加运维复杂度 |
| 统一为单一编程语言 | Dart/Go/TS 各有适用场景,不必强行统一 |