diff --git a/docs/ai-context/chain-map.md b/docs/ai-context/chain-map.md index 7c12eea6..8e92274a 100644 --- a/docs/ai-context/chain-map.md +++ b/docs/ai-context/chain-map.md @@ -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:", - 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) ``` diff --git a/docs/ai-context/module-boundary.md b/docs/ai-context/module-boundary.md index c69042ac..8c647d5d 100644 --- a/docs/ai-context/module-boundary.md +++ b/docs/ai-context/module-boundary.md @@ -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 - Content-Type: application/json - Body: - { - "jsonrpc": "2.0", - "id": "openclaw-", - "method": "session.start", - "params": { - "sessionId": "openclaw:", - "threadId": "", - "taskPrompt": "...", - "workingDirectory": "", - "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) | **中** | diff --git a/docs/ai-context/repo-summary.md b/docs/ai-context/repo-summary.md index 48acf7ab..1f8545f0 100644 --- a/docs/ai-context/repo-summary.md +++ b/docs/ai-context/repo-summary.md @@ -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/// 目录 → 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 依赖。 diff --git a/docs/architecture/chain-map-artifact-lifecycle.md b/docs/architecture/chain-map-artifact-lifecycle.md index 0a9ca38c..0d036e95 100644 --- a/docs/architecture/chain-map-artifact-lifecycle.md +++ b/docs/architecture/chain-map-artifact-lifecycle.md @@ -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 diff --git a/docs/architecture/chain-map-task-execution.md b/docs/architecture/chain-map-task-execution.md index 6a53673d..c399d415 100644 --- a/docs/architecture/chain-map-task-execution.md +++ b/docs/architecture/chain-map-task-execution.md @@ -76,7 +76,8 @@ xworkmate-bridge │ └─ scope: tasks/// │ ├─ 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