Document OpenClaw artifact dirs protocol boundary
This commit is contained in:
parent
ea67604986
commit
5f3dc974aa
@ -60,11 +60,12 @@ xworkmate-app xworkmate-bridge
|
||||
───────────── ────────────────
|
||||
lib/runtime/external_code_agent_acp_desktop_transport.dart
|
||||
ExternalCodeAgentAcpTransport
|
||||
→ session.start(provider="gateway")
|
||||
→ session.start(routing: gateway/openclaw,
|
||||
metadata.xworkmateTaskArtifactContract.expectedArtifactDirs)
|
||||
└─ lib/runtime/gateway_acp_client.dart
|
||||
→ POST /gateway/openclaw ────────────────► internal/acp/http_handler.go
|
||||
│ HandleOpenClawRPC()
|
||||
│ └─ internal/acp/gateway.go
|
||||
→ WebSocket /acp or POST /acp/rpc ───────► internal/acp/http_handler.go
|
||||
│ HandleWebSocket()/HandleRPC()
|
||||
│ └─ internal/acp/rpc_handler.go
|
||||
│ Orchestrator.Process()
|
||||
│ │
|
||||
│ ├─ 本地 gateway
|
||||
@ -99,6 +100,12 @@ lib/app/app_controller_openclaw_task_queue.dart
|
||||
→ 持久化 & 恢复 (pollOpenClawTaskAssociationInternal)
|
||||
```
|
||||
|
||||
Protocol boundary:
|
||||
- `expectedArtifactDirs` is not a `chat.send` root parameter.
|
||||
- App sends it only as `metadata.xworkmateTaskArtifactContract.expectedArtifactDirs` on `session.start`.
|
||||
- Bridge maps it only into `xworkmate.artifacts.export` and `xworkmate.artifacts.collect-and-snapshot`.
|
||||
- Bridge must reject old root/metadata compatibility paths instead of probing fallback keys.
|
||||
|
||||
### 涉及的 key files:
|
||||
| 层 | 文件 | 作用 |
|
||||
|----|------|------|
|
||||
@ -107,7 +114,7 @@ lib/app/app_controller_openclaw_task_queue.dart
|
||||
| app | `lib/runtime/go_task_service_desktop_service.dart` | 桌面任务服务 |
|
||||
| app | `lib/app/app_controller_openclaw_task_queue.dart` | 客户端任务队列 |
|
||||
| bridge | `internal/acp/gateway.go` | OpenClaw 集成 |
|
||||
| bridge | `internal/acp/http_handler.go` | `/gateway/openclaw` 端点 |
|
||||
| bridge | `internal/acp/http_handler.go` | `/acp` / `/acp/rpc` 端点 |
|
||||
| bridge | `internal/gatewayruntime/runtime.go` | 网关 WS 客户端 |
|
||||
| bridge | `internal/acp/distributed_forwarder.go` | 分布式转发 |
|
||||
| plugins | `index.ts` | 插件入口 |
|
||||
@ -198,49 +205,28 @@ lib/runtime/opencode_config_bridge.dart
|
||||
|
||||
---
|
||||
|
||||
## Chain 5: 多 Agent 编排 (Plugin → Bridge 反向调用)
|
||||
## Chain 5: 已移除的 Plugin → Bridge 反向调用
|
||||
|
||||
```
|
||||
openclaw-multi-session-plugins xworkmate-bridge
|
||||
───────────────────────────── ────────────────
|
||||
src/bridgeAgents.ts
|
||||
run(input)
|
||||
→ fetch(bridgeUrl, {
|
||||
method: "POST",
|
||||
body: { jsonrpc: "2.0",
|
||||
method: "session.start",
|
||||
params: {
|
||||
sessionId: "openclaw:<sessionKey>",
|
||||
multiAgent: true,
|
||||
mode: "multi-agent",
|
||||
routing: { orchestrationMode, steps, ... }
|
||||
}
|
||||
}
|
||||
})
|
||||
→ HTTP POST /acp/rpc ──────────────────────► internal/acp/rpc_handler.go
|
||||
handleRequest("session.start", ...)
|
||||
└─ internal/router/
|
||||
→ Orchestrator.Process()
|
||||
→ 多 agent 协作
|
||||
→ 结果返回插件
|
||||
旧链路:
|
||||
openclaw-multi-session-plugins/src/bridgeAgents.ts
|
||||
→ HTTP POST xworkmate-bridge /acp/rpc
|
||||
→ session.start(multiAgent=true)
|
||||
|
||||
src/exportArtifacts.ts
|
||||
→ 结果写入 artifactDirectory
|
||||
→ multi-agent-result.json
|
||||
→ multi-agent-result.md
|
||||
当前链路:
|
||||
xworkmate-bridge → OpenClaw Gateway → openclaw-multi-session-plugins
|
||||
→ xworkmate.artifacts.*
|
||||
```
|
||||
|
||||
### 涉及的 key files:
|
||||
| 层 | 文件 | 作用 |
|
||||
|----|------|------|
|
||||
| plugins | `src/bridgeAgents.ts` | Bridge HTTP 调用 |
|
||||
| bridge | `internal/acp/rpc_handler.go` | RPC 分发 |
|
||||
| bridge | `internal/acp/orchestrator.go` | 多 agent 编排 |
|
||||
| plugins | `index.ts` / `src/exportArtifacts.ts` | artifact scope adapter |
|
||||
| bridge | `internal/acp/orchestrator.go` | OpenClaw gateway orchestration |
|
||||
|
||||
### 协议: HTTP JSON-RPC (插件 → Bridge)
|
||||
### 协议: 无 Plugin→Bridge 运行时协议
|
||||
### 断点风险:
|
||||
- 插件配置中 bridgeUrl 指向错误 → 调用失败
|
||||
- 双向循环依赖: plugins 调 bridge, bridge 调 plugins
|
||||
- 旧版本插件若仍暴露 bridge agents 工具,会恢复循环依赖,应从 manifest 和 dist 中删除
|
||||
|
||||
---
|
||||
|
||||
@ -251,12 +237,11 @@ src/exportArtifacts.ts
|
||||
app bridge plugins
|
||||
┌───────┬───────┬───────┐
|
||||
app │ - │ ACP │ - │
|
||||
被调 bridge │ - │ - │ HTTP │
|
||||
被调 bridge │ - │ - │ - │
|
||||
方 plugins │ - │ GW │ - │
|
||||
└───────┴───────┴───────┘
|
||||
|
||||
ACP = JSON-RPC 2.0 over WebSocket/HTTP SSE
|
||||
HTTP = JSON-RPC 2.0 over HTTP POST
|
||||
GW = OpenClaw Gateway RPC over WebSocket (Ed25519)
|
||||
```
|
||||
|
||||
|
||||
@ -162,7 +162,7 @@ App → Bridge → Gateway: device.pair.approve / device.pair.reject
|
||||
| 方法 | 方向 | 描述 |
|
||||
|------|------|------|
|
||||
| `connect` | Bridge→Gateway | 认证连接 |
|
||||
| `chat.send` | Bridge→Gateway | 发送 agent 执行请求 |
|
||||
| `chat.send` | Bridge→Gateway | 发送 agent 执行请求;不得携带 `expectedArtifactDirs` |
|
||||
| `agent.wait` | Bridge→Gateway | 等待 agent 完成 |
|
||||
| `health` | Bridge→Gateway | 健康检查 |
|
||||
| `skills.status` | Bridge→Gateway | 技能状态 |
|
||||
@ -199,24 +199,21 @@ App → Bridge → Gateway: device.pair.approve / device.pair.reject
|
||||
"extensions": ["./dist/index.js"]
|
||||
},
|
||||
"gatewayMethods": [
|
||||
"xworkmate.tasks.get",
|
||||
"xworkmate.artifacts.prepare",
|
||||
"xworkmate.artifacts.export",
|
||||
"xworkmate.artifacts.collect-and-snapshot",
|
||||
"xworkmate.artifacts.list",
|
||||
"xworkmate.artifacts.read",
|
||||
"xworkmate.agents.run"
|
||||
"xworkmate.artifacts.read"
|
||||
],
|
||||
"tools": {
|
||||
"openclaw_multi_session_artifacts": { "sessionScoped": true },
|
||||
"openclaw_multi_session_agents": { "sessionScoped": true }
|
||||
"openclaw_multi_session_artifacts": { "sessionScoped": true }
|
||||
},
|
||||
"config": {
|
||||
"workspaceDir": "~/.openclaw/workspace",
|
||||
"maxFiles": 1000,
|
||||
"maxInlineBytes": 1048576,
|
||||
"artifactRefSigningSecret": "",
|
||||
"bridgeUrl": "",
|
||||
"bridgeToken": "",
|
||||
"bridgeTimeoutMs": 120000
|
||||
"artifactRefSigningSecret": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -226,10 +223,16 @@ App → Bridge → Gateway: device.pair.approve / device.pair.reject
|
||||
| 方法 | 输入 | 输出 |
|
||||
|------|------|------|
|
||||
| `xworkmate.artifacts.prepare` | `{sessionKey, runId, workspaceDir?}` | `{artifactScope, artifactDirectory, scopeKind}` |
|
||||
| `xworkmate.artifacts.export` | `{sessionKey, runId, artifactScope?, sinceUnixMs?, ...}` | `{artifacts[], manifestMarkdown, warnings[]}` |
|
||||
| `xworkmate.artifacts.export` | `{sessionKey, runId, artifactScope?, sinceUnixMs?, expectedArtifactDirs?}` | `{artifacts[], manifestMarkdown, warnings[]}` |
|
||||
| `xworkmate.artifacts.collect-and-snapshot` | `{sessionKey, runId, artifactScope?, sinceUnixMs?, expectedArtifactDirs?}` | `{artifacts[], warnings[]}` |
|
||||
| `xworkmate.artifacts.list` | `{sessionKey, runId, ...}` | `{artifacts[] (不含内容), manifestMarkdown}` |
|
||||
| `xworkmate.artifacts.read` | `{sessionKey, runId, artifactScope?, relativePath?, artifactRef?}` | `{artifacts[0], manifestMarkdown}` |
|
||||
| `xworkmate.agents.run` | `{sessionKey, runId, taskPrompt, mode, steps?, participants?, ...}` | `{bridgeResult, artifacts[]}` |
|
||||
| `xworkmate.tasks.get` | `{sessionKey, runId}` | `{taskStatus, status, artifacts[], warnings[]}` |
|
||||
|
||||
`expectedArtifactDirs` has a single upstream source:
|
||||
`session.start.metadata.xworkmateTaskArtifactContract.expectedArtifactDirs`.
|
||||
Bridge may pass it to artifact export/snapshot RPCs only. It is not accepted at
|
||||
`session.start` root, metadata root, `chat.send`, or `xworkmate.tasks.get`.
|
||||
|
||||
### 安全边界
|
||||
|
||||
@ -255,57 +258,16 @@ artifactRef = HMAC-SHA256(workspaceRoot, sessionKey, runId, relativePath, size,
|
||||
输出: { artifacts[]|manifestMarkdown }
|
||||
安全: sessionKey/runId 由 OpenClaw 运行时注入,
|
||||
Agent 无法覆盖 (在 tool factory 中解构排除)
|
||||
|
||||
工具: openclaw_multi_session_agents
|
||||
输入: { taskPrompt, mode, steps?, participants?, maxTurns? }
|
||||
输出: { result, artifacts[] }
|
||||
安全: sessionKey/runId 同样由运行时注入
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Plugin → Bridge 反向调用边界
|
||||
|
||||
### HTTP JSON-RPC 调用
|
||||
|
||||
```
|
||||
Plugin (bridgeAgents.ts)
|
||||
→ POST {bridgeUrl}/acp/rpc
|
||||
Headers:
|
||||
Authorization: Bearer <bridgeToken>
|
||||
Content-Type: application/json
|
||||
Body:
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "openclaw-<timestamp>",
|
||||
"method": "session.start",
|
||||
"params": {
|
||||
"sessionId": "openclaw:<sessionKey>",
|
||||
"threadId": "<sessionKey>",
|
||||
"taskPrompt": "...",
|
||||
"workingDirectory": "<artifactDirectory>",
|
||||
"multiAgent": true,
|
||||
"mode": "multi-agent",
|
||||
"routing": {
|
||||
"orchestrationMode": "...",
|
||||
"steps": [...]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 配置
|
||||
|
||||
```
|
||||
环境变量:
|
||||
XWORKMATE_BRIDGE_URL — bridge 基础 URL (自动追加 /acp/rpc)
|
||||
XWORKMATE_BRIDGE_TOKEN — bridge 认证 token
|
||||
|
||||
插件配置 (openclaw.plugin.json):
|
||||
bridgeUrl: "https://xworkmate-bridge.svc.plus"
|
||||
bridgeToken: "..."
|
||||
bridgeTimeoutMs: 120000
|
||||
```
|
||||
该边界已移除。插件不得通过 HTTP 调用 xworkmate-bridge,也不再暴露
|
||||
`xworkmate.agents.run` 或 `openclaw_multi_session_agents`。多 agent 编排由
|
||||
OpenClaw 原生 runtime 或 xworkmate-bridge 自身拥有,插件只保留 artifact
|
||||
scope、artifact manifest/read、task snapshot adapter 和 session key mapping。
|
||||
|
||||
---
|
||||
|
||||
@ -322,6 +284,5 @@ Plugin (bridgeAgents.ts)
|
||||
| Bridge↔Gateway | Ed25519 密钥轮换无自动化 | **低** |
|
||||
| Gateway↔Plugin | artifactRef 签名密钥不一致 | **高** |
|
||||
| Gateway↔Plugin | 24h 签名过期 → 历史工件不可读 | **中** |
|
||||
| Plugin→Bridge | bridgeUrl/bridgeToken 配置错误 | **高** |
|
||||
| Plugin→Bridge | 循环依赖 (plugin 调 bridge, bridge 调 plugin) | **高** |
|
||||
| Plugin→Bridge | 已移除;旧插件版本若残留会恢复循环依赖 | **高** |
|
||||
| 全部 | 多仓库版本耦合 (app 1.1.4 + bridge latest + plugins 0.1.15) | **中** |
|
||||
|
||||
@ -101,11 +101,14 @@ xworkmate-app
|
||||
→ openclaw: WebSocket → OpenClaw gateway (ws://127.0.0.1:18789)
|
||||
|
||||
xworkmate-app
|
||||
→ POST /gateway/openclaw (session.start, provider="gateway")
|
||||
→ acp/gateway.go → gatewayruntime/runtime.go
|
||||
→ /acp or /acp/rpc session.start (routing: gateway/openclaw)
|
||||
metadata.xworkmateTaskArtifactContract.expectedArtifactDirs
|
||||
→ acp/rpc_handler.go → orchestrator.go → gatewayruntime/runtime.go
|
||||
→ WebSocket → OpenClaw gateway
|
||||
→ chat.send → agent 执行
|
||||
→ xworkmate.artifacts.* → openclaw-multi-session-plugins
|
||||
→ chat.send → agent 执行 (no expectedArtifactDirs root field)
|
||||
→ xworkmate.artifacts.export/collect-and-snapshot
|
||||
with expectedArtifactDirs from the artifact contract
|
||||
→ openclaw-multi-session-plugins
|
||||
```
|
||||
|
||||
### 与其他仓库的关系
|
||||
@ -121,21 +124,20 @@ Go 1.25, gorilla/websocket, pion/webrtc v4, YAML 配置。无 gRPC。Docker 部
|
||||
## 3. openclaw-multi-session-plugins (TypeScript)
|
||||
|
||||
### 核心职责
|
||||
OpenClaw 插件 — 工件管理平面。为每个 session/run 对创建隔离工件目录,扫描文件,生成 HMAC 签名引用,提供多 agent 编排能力。
|
||||
OpenClaw 插件 — XWorkmate artifact 作用域适配层。为每个 session/run 对创建隔离工件目录,扫描文件,生成 HMAC 签名引用,并把 task snapshot 与 OpenClaw 原生 task/session 状态对齐。
|
||||
|
||||
### 入口模块
|
||||
| 入口 | 路径 | 作用 |
|
||||
|------|------|------|
|
||||
| plugin entry | `index.ts` | register() — 注册 5 个网关方法 + 2 个 agent 工具 |
|
||||
| plugin entry | `index.ts` | register() — 注册 task/artifact 网关方法 + artifact agent 工具 |
|
||||
| artifacts | `src/exportArtifacts.ts` | 工件准备/导出/读取逻辑 |
|
||||
| bridge agents | `src/bridgeAgents.ts` | 通过 HTTP 调用 bridge 的 session.start |
|
||||
| manifest | `openclaw.plugin.json` | 声明网关方法和工具配置 |
|
||||
|
||||
### 关键目录
|
||||
```
|
||||
src/
|
||||
exportArtifacts.ts — 核心: prepare/export/list/read
|
||||
bridgeAgents.ts — bridge 调用: session.start (multi-agent)
|
||||
taskState.ts — task snapshot + session key mapping adapter
|
||||
index.ts — 插件入口: register()
|
||||
openclaw.plugin.json — 插件清单: 网关方法 + 工具声明
|
||||
```
|
||||
@ -143,19 +145,16 @@ openclaw.plugin.json — 插件清单: 网关方法 + 工具声明
|
||||
### 主要调用链
|
||||
```
|
||||
OpenClaw 网关 (WebSocket RPC)
|
||||
→ xworkmate.tasks.get → 原生 task registry 状态 + artifact manifest
|
||||
→ xworkmate.artifacts.prepare → 创建 tasks/<session>/<run>/ 目录
|
||||
→ xworkmate.artifacts.export → 扫描文件, 计算 HMAC 签名, 输出清单
|
||||
→ xworkmate.artifacts.collect-and-snapshot → 收集 tool 输出并绑定到当前 artifact scope
|
||||
→ xworkmate.artifacts.read → 返回单个工件内容
|
||||
|
||||
Agent Tool Call (内部)
|
||||
→ openclaw_multi_session_agents
|
||||
→ bridgeAgents.run() → HTTP POST → bridge /acp/rpc (session.start, multiAgent: true)
|
||||
→ 结果写入 artifactDirectory → multi-agent-result.json
|
||||
```
|
||||
|
||||
### 与其他仓库的关系
|
||||
- **xworkmate-bridge**: 被 bridge 通过网关 RPC 调用(`xworkmate.artifacts.*`)。也主动调用 bridge 的 `/acp/rpc`(multi-agent 模式)。
|
||||
- **xworkmate-bridge**: 被 bridge 通过 OpenClaw 网关 RPC 间接调用(`xworkmate.tasks.get`, `xworkmate.artifacts.*`)。
|
||||
- **xworkmate-app**: 不直接通信。app 通过 bridge 的 `/artifacts/openclaw/download` 获取工件。
|
||||
|
||||
### 技术栈
|
||||
TypeScript (ESM), Node.js, OpenClaw Plugin SDK (2026.5.28)。无外部 HTTP 依赖。`bridgeAgents.ts` 中使用原生 `fetch`。
|
||||
TypeScript (ESM), Node.js, OpenClaw Plugin SDK。无外部 HTTP 依赖。
|
||||
|
||||
@ -131,6 +131,7 @@ Inputs:
|
||||
artifactRef?: string // alternative: read single artifact
|
||||
maxFiles?: number // default: 200
|
||||
maxInlineBytes?: number // default: 512KB, files larger are omitted
|
||||
expectedArtifactDirs?: string[] // from session.start metadata.xworkmateTaskArtifactContract only
|
||||
|
||||
Process:
|
||||
1. resolveScopeRoot(workspaceRoot, artifactScope)
|
||||
@ -144,6 +145,16 @@ Process:
|
||||
→ Skip: symlinks (security measure)
|
||||
→ Apply: artifact-ignore.md rules
|
||||
|
||||
2b. If the task scope has no candidates and `expectedArtifactDirs` is present:
|
||||
→ Scan only those explicit workspace-root subdirectories
|
||||
→ Keep exported entries bound to the current task artifactScope
|
||||
→ Do not scan the workspace root broadly and do not borrow older task scopes
|
||||
|
||||
Protocol boundary:
|
||||
`expectedArtifactDirs` is bridge artifact-contract data, not agent execution
|
||||
data. Bridge must not put it in `chat.send` params. Bridge must not probe old
|
||||
root-level or metadata-root compatibility keys.
|
||||
|
||||
3. For each file under maxFiles limit:
|
||||
→ Read content (up to maxInlineBytes)
|
||||
→ Compute SHA-256 hash
|
||||
|
||||
@ -76,7 +76,8 @@ xworkmate-bridge
|
||||
│ └─ scope: tasks/<sessionKey>/<runId>/
|
||||
│
|
||||
├─ gateway.request('chat.send')
|
||||
│ └─ payload: message, attachments, artifactSince, workingDirectory
|
||||
│ └─ payload: sessionKey, message, attachments, idempotencyKey
|
||||
│ (no expectedArtifactDirs root field)
|
||||
│
|
||||
├─ Create OpenClawTaskRecord
|
||||
│ ├─ SessionID, ThreadID, TurnID, RunID
|
||||
@ -135,6 +136,17 @@ openclaw-multi-session-plugins
|
||||
├─ signArtifactRef(sessionKey, runId, relativePath)
|
||||
└─ Return manifest + base64 file contents
|
||||
|
||||
`expectedArtifactDirs` source:
|
||||
session.start.metadata.xworkmateTaskArtifactContract.expectedArtifactDirs
|
||||
→ bridge artifact contract
|
||||
→ xworkmate.artifacts.collect-and-snapshot / export only
|
||||
|
||||
Forbidden compatibility paths:
|
||||
session.start.expectedArtifactDirs
|
||||
session.start.metadata.expectedArtifactDirs
|
||||
chat.send.expectedArtifactDirs
|
||||
xworkmate.tasks.get.expectedArtifactDirs
|
||||
|
||||
Receives gateway RPC: xworkmate.artifacts.collect-and-snapshot
|
||||
collectAndSnapshotXWorkmateArtifacts()
|
||||
├─ Scan ~/.openclaw/media/ and /tmp/openclaw/ for files changed since task start
|
||||
@ -207,8 +219,8 @@ etc.), not by extending the task execution lifecycle.
|
||||
|
||||
### openclaw-multi-session-plugins
|
||||
- `src/exportArtifacts.ts` — artifact prepare/export/read (963 lines)
|
||||
- `src/taskState.ts` — task snapshot adapter + SessionEntry.pluginExtensions mapping
|
||||
- `index.ts` — plugin entry + gateway method registration
|
||||
- `src/bridgeAgents.ts` — bridge agent orchestration
|
||||
|
||||
### openclaw.svc.plus (reference)
|
||||
- `src/config/paths.ts` — ~/.openclaw/ state directory
|
||||
|
||||
Loading…
Reference in New Issue
Block a user