# 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.ts;Bridge/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<