# 任务执行链路统一收敛
Last Updated: 2026-04-11
## 背景
当前仓库里已经存在 `GoTaskService`、Go ACP `Router.Resolve`、`Skills.Resolve`、
`Memory` 与 `buildResolvedExecutionParams`,说明统一控制面已经具备核心骨架。
但旧设计文档长期把不同实现通道写成并列主链,导致:
- Desktop / Web / Mobile 的现状与目标混在一起
- controller 层的历史分流被误认为长期规范
- `local / remote / multi-agent` 被描述成 app 侧一级执行路径
本文件把官方口径统一为:
- UI 不变
- `GoTaskService.executeTask` 是唯一公开入口
- ACP 是统一控制面
- `bridge` 是 app 客户端的发现 / 配置 / 连接 / 对话枢纽
- app 当前只保留 `agent / gateway` 两条路径
- ACP Server list / gateway upstream 由 `xworkmate-bridge` 动态发现与维护
- `$INTERNAL_SERVICE_TOKEN` 仅属于 bridge / internal service 注入责任
- 账户同步只同步 bridge 相关配置属性与安全引用,不做自动连接
## 目标态
```mermaid
flowchart TD
subgraph APP["App surfaces"]
A["Desktop / Web / Mobile UI"]
B["sendMessage
Task Envelope"]
C["GoTaskService.executeTask
唯一公开入口"]
A --> B --> C
end
subgraph ACP["ACP control plane"]
D["ACP.session.start / session.message"]
E["Router.Resolve"]
F["Skills.Resolve"]
G["Memory.Inject"]
H["buildResolvedExecutionParams"]
I{"resolvedExecutionPath"}
D --> E --> F --> G --> H --> I
end
subgraph BRIDGE["xworkmate-bridge"]
J["agent route"]
K["gateway route"]
L["bridge routing hub
dynamic discovery / policy / auth injection"]
M["Provider adapters
codex / opencode / claude / gemini"]
N["Gateway adapters
openclaw / aris / hosted gateway capability"]
J --> L
K --> L
L --> M
L --> N
end
subgraph RETURN["Return path"]
O["stream events / result"]
P["Memory.Record"]
Q["Update Thread State"]
R["UI stream render"]
O --> P --> Q --> R
end
C --> D
I -->|"agent"| J
I -->|"gateway"| K
M --> O
N --> O
```
## Provider 真源
Single-agent provider catalog and availability are owned by
`xworkmate-bridge`, not by local endpoint presets inside the app.
ACP server addresses and gateway upstreams are also bridge-owned dynamic
discovery data. The app must not treat concrete endpoints such as
`https://acp-server.svc.plus/*` or `wss://openclaw.svc.plus` as app-side
hardcoded truth sources.
```mermaid
flowchart TD
subgraph INPUT["Config / discovery input"]
A["Settings UI
仅管理 bridge 连接参数
与账号同步元数据"]
B["acp.capabilities"]
C["bridge capability snapshot
providerCatalog / agent / gateway
dynamic upstream discovery"]
A --> B --> C
end
subgraph APPSTATE["App-side truth sources"]
D["refreshSingleAgentCapabilitiesRuntimeInternal()"]
E["bridgeProviderCatalogInternal
App 内唯一 provider 名单源"]
F["singleAgentCapabilitiesByProviderInternal
App 内唯一 provider 可用性源"]
G["refreshAcpCapabilitiesRuntimeInternal()"]
H["GatewayAcpCapabilities"]
I["mergeAcpCapabilitiesIntoMountTargetsRuntimeInternal()"]
J["ManagedMountTargetState
gateway capability / discovery state"]
C --> D --> E
D --> F
C --> G --> H --> I --> J
end
subgraph UISTATE["UI affordances"]
K["bridgeProviderCatalog
Composer / Thread Picker provider source"]
L["availableSingleAgentProviders
agent path visibility"]
M["visible gateway affordances
只看 bridge capabilities / discovery"]
E --> K
F --> L
J --> M
end
subgraph EXEC["Execution resolution"]
N["setSingleAgentProvider(providerId)
仅写入 thread executionBinding.providerId"]
O["singleAgentProviderForSession()"]
P["buildExternalAcpRoutingForSessionInternal()"]
Q["xworkmate.routing.resolve"]
R["resolvedProviderId / unavailableMessage"]
S{"unavailable?"}
T["executeTask(... resolved routing ...)"]
U["provider unavailable UX
直接使用 bridge unavailable message"]
K --> N --> O --> P --> Q --> R --> S
S -->|"no"| T
S -->|"yes"| U
```
## 端侧桥接规则
### Desktop App
- Desktop App 直接桥接 Go 代码
- Desktop 正常执行链路不以“先启动一个本地 HTTP server,再由 Desktop 自己回连”作为目标架构
- Desktop 的 `sendMessage -> GoTaskService.executeTask -> ACP` 应理解为进程内或直接桥接语义
- Production cloud mode does not call `xworkmate.providers.sync`
- Production provider upstreams are bridge-owned, not app-owned
- Production ACP server list / gateway upstreams are bridge-owned, not app-owned
- `$INTERNAL_SERVICE_TOKEN` 只允许在 bridge / internal service 层使用,app 不持有
- 对 app 来说,bridge 是 discovery / config / connect / dialogue 的统一枢纽
### Web / Mobile
- Web / Mobile UI 连接的是 Go 代码启动出来的 server
- Web / Mobile 通过标准 ACP contract 与该 server 通信
- 对 Web / Mobile 来说,`/acp` 与 `/acp/rpc` 是稳定的网络协议入口
## 协议约束
### 传输协议
- app 侧当前不再把 `local / remote` 作为执行路径语义
- Desktop 只区分 `agent / gateway` 两条路径,二者都经由 `xworkmate-bridge` 路由
- 如果 bridge endpoint 是网络地址,则必须遵守 TLS 要求
- loopback / non-TLS 只允许作为底层 adapter / 开发态传输细节,不能重新上升为产品执行路径语义
- app 不直接持有 ACP server upstream 或 gateway upstream 的授权头
- `Authorization: Bearer $INTERNAL_SERVICE_TOKEN` 属于 bridge / internal service 注入责任
### ACP contract
- websocket endpoint 规范路径:`/acp`
- RPC endpoint 规范路径:`/acp/rpc`
- base URL 派生时必须避免重复拼接 `/acp`
- 以上 endpoint contract 主要适用于 Web / Mobile 与外部 ACP server 的通信语义
- Desktop 目标态不要求为自身 UI 再额外启动一层本地 HTTP ACP server
## 收敛原则
### Current implementation note
- 当前实现可能仍残留历史分流代码
- 这些实现痕迹不再代表规范
### Target architecture rule
- 所有正常发送请求都先进入 `GoTaskService.executeTask`
- 所有任务都先进入 ACP 控制面,再解析到 executor
- Desktop 采用直接桥接 Go 代码的控制面接入方式
- Web / Mobile 采用连接 Go server 的控制面接入方式
- app 侧一级执行路径只保留 `agent / gateway`
- `multi-agent` 是 bridge / gateway 内部能力,不再作为 app 侧一级路径
- app 不直接调用 `acp-server.svc.plus/*` 或 `openclaw.svc.plus`
- 如果需要补全或变更 ACP / gateway upstream,优先在 `xworkmate-bridge` 仓库实现动态发现能力
### Compatibility route (removed from target)
- `openClawTask` 不再属于目标架构
- `GatewayRuntime`、`Web relay`、`GatewayAcpClient` 只作为 adapter/executor 能力存在
## 分阶段方向
1. 文档口径收敛
2. Dart 请求模型统一
3. route 决策内收到 `GoTaskService` / ACP
4. app 侧 bridge 枢纽与 provider / gateway 适配关系收敛
5. `multi-agent` 下沉为 bridge 内部能力,而不是 app 一级路径