From a9e552737e9cdc34e217d56c71f45e3b39cf9ad8 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Mon, 6 Apr 2026 14:17:36 +0800 Subject: [PATCH] docs: record metadata issue and task routing --- .../assistant-thread-target-model-20260328.md | 36 +++++++++++------ .../xworkmate-layered-architecture.md | 40 ++++++++++++++----- ...6-github-issue-invalid-request-metadata.md | 37 +++++++++++++++++ 3 files changed, 91 insertions(+), 22 deletions(-) create mode 100644 docs/reports/2026-04-06-github-issue-invalid-request-metadata.md diff --git a/docs/architecture/assistant-thread-target-model-20260328.md b/docs/architecture/assistant-thread-target-model-20260328.md index 71310274..4054a084 100644 --- a/docs/architecture/assistant-thread-target-model-20260328.md +++ b/docs/architecture/assistant-thread-target-model-20260328.md @@ -11,7 +11,7 @@ 3. UI 选中线程后,系统必须读取完整 `TaskThread`,而不是从页面状态拼装线程信息。 4. `TaskThread` 持久化 schema 保持不变,但 `workspaceBinding` 在 create/load 时必须完整;缺失 binding 的旧记录按非法数据处理并跳过加载。 5. 执行请求由 controller / runtime 根据 `ownerScope / workspaceBinding / executionBinding / contextState` 构造。 -6. controller / runtime 统一通过 `GoTaskService` 调度执行:OpenClaw task 走 `TaskThread -> GoTaskService -> GatewayRuntime / Web relay -> OpenClaw gateway`;`singleAgent / multiAgent` 走 `TaskThread -> GoTaskService -> ExternalCodeAgentAcp* -> ACP/provider route`。 +6. controller / runtime 统一通过 `GoTaskService` 调度执行,并遵循 `TaskThread` 驱动的任务分流语义:`OpenClaw task` 走 `TaskThread -> GoTaskService -> GatewayRuntime / Web relay -> OpenClaw gateway`;`singleAgent / multiAgent` 等 ACP lane 走 `TaskThread -> GoTaskService -> ExternalCodeAgentAcp* -> ACP/provider route`。 7. 执行结果先回写 `TaskThread.contextState`,主体区域同步显示;UI 与执行始终只读取当前 `TaskThread.workspaceBinding`,不再存在 runtime first-binding 或 fallback 到 `main`。 8. `contextState` 是线程上下文真相源;`lifecycleState` 只表达生命周期摘要;controller 侧缓存不承载线程持久语义。 @@ -78,7 +78,7 @@ ExecutionBinding - 定义线程当前执行模式 - 定义 provider / endpoint 绑定 -- 为 `GoTaskService / runtime` 协调层提供调度输入 +- 为 `GoTaskService / runtime` 的任务分流与执行通道选择提供调度输入 ### 2.4 contextState @@ -133,14 +133,18 @@ flowchart LR D3 --> E D4 --> E - E --> F["GoTaskService\nDesktop: GatewayRuntime / ExternalCodeAgentAcpDesktopTransport\nWeb: relay / ExternalCodeAgentAcpWebTransport"] - F --> G["执行结果"] + E --> F{"GoTaskService 任务分流"} + F -->|OpenClaw task| G["GatewayRuntime / Web relay -> OpenClaw gateway"] + F -->|singleAgent / multiAgent| H["ExternalCodeAgentAcp* -> ACP/provider route"] - G --> H["回写线程上下文\n(主体区域 同步显示)"] - G --> I["仅显式更新当前线程 workspaceBinding"] + G --> I["执行结果"] + H --> I - H --> J["右栏显示"] - I --> J + I --> J["回写线程上下文\n(主体区域 同步显示)"] + I --> K["仅显式更新当前线程 workspaceBinding"] + + J --> L["右栏显示"] + K --> L ``` 这条链路是当前唯一生命周期基准: @@ -148,10 +152,12 @@ flowchart LR 1. UI 仍保持现有形态,但只负责选择 `threadId` 与消费回写结果。 2. 线程的执行输入来自完整 `TaskThread`。 3. `构造执行请求` 属于 `GoTaskService / runtime` 协调层,不属于 UI。 -4. `GoTaskService` 是唯一执行调度面;Desktop / Web 共用同一套 session 语义,只在 transport 上有差异。 -5. `回写线程上下文` 是执行结束后的第一落点;主体区域同步显示依赖这一回写。 -6. `workspaceBinding` 不是运行时补齐对象;线程在 create/load 时必须已经完整。 -7. `右栏显示` 与执行请求都读取当前 `TaskThread.workspaceBinding`,因此它与主体区域共享同一线程事实来源。 +4. 当前任务流不是单一路由:`OpenClaw task` 与 ACP lane 在 `TaskThread` 读取之后立即分流。 +5. `OpenClaw task` 的规范路径是 `TaskThread -> GoTaskService -> GatewayRuntime / Web relay -> OpenClaw gateway`。 +6. `singleAgent / multiAgent` 的规范路径是 `TaskThread -> GoTaskService -> ExternalCodeAgentAcp* -> ACP/provider route`。 +7. `回写线程上下文` 是执行结束后的第一落点;主体区域同步显示依赖这一回写。 +8. `workspaceBinding` 不是运行时补齐对象;线程在 create/load 时必须已经完整。 +9. `右栏显示` 与执行请求都读取当前 `TaskThread.workspaceBinding`,因此它与主体区域共享同一线程事实来源。 ## 4. 当前设计约束 @@ -165,7 +171,9 @@ flowchart LR ### 4.2 GoTaskService / runtime 协调层约束 - 根据 `ownerScope / workspaceBinding / executionBinding / contextState` 构造执行请求。 -- 负责把线程请求调度到 `GoTaskService`,而不是让 Flutter UI 直接承担 runtime 职责。 +- 负责根据任务类型把线程请求分流到正确执行通道,而不是让 Flutter UI 直接承担 runtime 职责。 +- `OpenClaw task` 必须走 `TaskThread -> GoTaskService -> GatewayRuntime / Web relay -> OpenClaw gateway`。 +- `singleAgent / multiAgent` 必须走 `TaskThread -> GoTaskService -> ExternalCodeAgentAcp* -> ACP/provider route`。 - 接收执行结果并驱动 `TaskThread` 回写。 ### 4.3 TaskThread 约束 @@ -183,5 +191,7 @@ flowchart LR 说明线程信息如何进入 UI、`GoTaskService / runtime` 请求构造、结果回写和右栏展示。 - [xworkmate-internal-state-architecture.md](xworkmate-internal-state-architecture.md) 说明控制器、状态存储和派生 UI 状态如何围绕 `TaskThread` 组织。 +- [xworkmate-layered-architecture.md](xworkmate-layered-architecture.md) + 说明 `GoTaskService`、`GatewayRuntime / Web relay`、`ExternalCodeAgentAcp*` 与 `ACP/provider route` 的分层关系。 归档文档仍可保留作为历史背景,但不再参与当前设计说明。 diff --git a/docs/architecture/xworkmate-layered-architecture.md b/docs/architecture/xworkmate-layered-architecture.md index f6d7cfe3..f07cf262 100644 --- a/docs/architecture/xworkmate-layered-architecture.md +++ b/docs/architecture/xworkmate-layered-architecture.md @@ -9,7 +9,7 @@ Last Updated: 2026-03-29 - 本地用户、Web 用户、远程租户如何进入系统 - 任务线程如何成为 UI 与执行之间的控制面主对象 -- Desktop / Mobile / Web 三个界面层如何共用同一套 `GoTaskService` 执行主链 +- Desktop / Mobile / Web 三个界面层如何共用同一套 `GoTaskService` 执行主链与任务分流语义 - 本地 agent、OpenClaw Gateway、ACP endpoint、AI Gateway、Skills / MCP 等扩展能力应该落在哪一层 @@ -48,7 +48,7 @@ Last Updated: 2026-03-29 - UI 不是执行状态真值源 - `TaskThread` 才是线程级控制面真值源 -- `GoTaskService` 负责把线程状态翻译成可执行请求 +- `GoTaskService` 负责把线程状态翻译成可执行请求,并在 OpenClaw lane 与 ACP lane 之间分流 - 真正的 provider / gateway / ACP / Skills / MCP 都应放在 `GoTaskService` 之下 ## 整体架构 @@ -202,12 +202,21 @@ flowchart TB 因此,推荐把所有“切换线程、发消息、切换目标、切换 provider、回写远端目录” 都看成对线程控制面的更新,而不是页面局部状态切换。 -### 4. Agent-core 调度层 +### 4. GoTaskService 调度层 这是 XWorkmate 的核心中枢。 它不只是“某个 agent SDK”,而是一整套把线程控制面翻译成执行请求的调度层。 +这一层的上位语义应该理解为: + +- `OpenClaw task` + - `TaskThread -> GoTaskService -> GatewayRuntime / Web relay -> OpenClaw gateway` +- `ACP task` + - `TaskThread -> GoTaskService -> ExternalCodeAgentAcp* -> ACP/provider route` + +也就是说,`GoTaskService` 才是整层的上位名字;具体 transport 与 gateway/ACP lane 只是它的执行子路径。 + 当前代码里,这层最关键的组件是: - `AppControllerDesktop` @@ -233,6 +242,17 @@ flowchart TB - `MultiAgentOrchestrator` / `MultiAgentMountManager` 负责协作执行与挂载 - Config bridge 只负责受管配置写入,不越权持有 UI 真值 +## 术语表 + +| 术语 | 规范语义 | 当前作用 | +| --- | --- | --- | +| `TaskThread` | 线程级控制面主对象 | 承载线程身份、工作区、执行绑定、上下文与生命周期 | +| `OpenClaw task` | 面向本地或远端 OpenClaw gateway 的任务 | 规范路径:`TaskThread -> GoTaskService -> GatewayRuntime / Web relay -> OpenClaw gateway` | +| `ACP task` | 不走 OpenClaw gateway 的任务 | 规范路径:`TaskThread -> GoTaskService -> ExternalCodeAgentAcp* -> ACP/provider route` | +| `GatewayRuntime` | OpenClaw task 的 App 侧 runtime 门面 | 负责 gateway chat / session / pairing / history 等语义 | +| `ExternalCodeAgentAcp*` | ACP task 的 transport 组件 | 负责把任务送入 ACP/provider route | +| `ACP/provider route` | 非 OpenClaw provider 的执行通道 | 包括 ACP transport、provider endpoint、兼容 relay/provider 路径 | + ### 5. 对接服务与扩展层 这一层是实际被调用的执行对象和扩展对象,不应与 controller 混层。 @@ -294,9 +314,9 @@ flowchart LR C3 --> D C4 --> D - D --> E{"executionMode"} - E -->|openclaw task| G["GoTaskService -> GatewayRuntime / Web relay"] - E -->|singleAgent / multiAgent| H["GoTaskService -> ExternalCodeAgentAcp* / ACP route"] + D --> E{"任务类型分流"} + E -->|OpenClaw task| G["GoTaskService -> GatewayRuntime / Web relay -> OpenClaw gateway"] + E -->|singleAgent / multiAgent| H["GoTaskService -> ExternalCodeAgentAcp* -> ACP route"] G --> I H --> I @@ -313,7 +333,9 @@ flowchart LR - UI 先选线程,不是先选 provider - 线程先绑定,再执行 -- 执行模式由 `executionBinding` 决定 +- 执行模式与 provider 绑定共同决定最终任务分流 +- `OpenClaw task` 不再走 ACP 兼容桥,而是统一走 `GoTaskService -> GatewayRuntime / Web relay -> OpenClaw gateway` +- `singleAgent / multiAgent` 统一走 `GoTaskService -> ExternalCodeAgentAcp* -> ACP/provider route` - 结果先回写线程,再刷新 UI - 远端返回新的 working directory 时,只能显式回写当前已完整线程的 `workspaceBinding` - 这类回写不能创建 first binding,也不能改变线程身份 @@ -325,7 +347,7 @@ flowchart LR | 访问与归属层 | `ThreadOwnerScope`、`DeviceIdentityStore`、Web session identity | `lib/runtime/runtime_models_runtime_payloads.dart`, `lib/runtime/device_identity_store.dart`, `lib/web/web_session_repository.dart` | 定义线程归属、设备身份、远程会话身份 | | 多端 UI 层 | `AppShellDesktop`、`mobile_shell_*`、`AppShellWeb`、`AssistantPage`、`SettingsPage` | `lib/app/`, `lib/features/assistant/`, `lib/features/mobile/`, `lib/features/settings/` | 接收用户操作、展示线程与设置 | | 线程控制面 | `TaskThread` + thread records | `lib/runtime/runtime_models_runtime_payloads.dart`, `lib/runtime/settings_store.dart`, `lib/web/web_session_repository.dart` | 保存线程级真值状态 | -| `GoTaskService` 调度层 | `AppControllerDesktop/Web`、`GoTaskServiceClient`、`RuntimeCoordinator`、`CodeAgentNodeOrchestrator`、`MultiAgentOrchestrator` | `lib/app/`, `lib/runtime/`, `lib/web/` | 把线程状态翻译为执行请求并协调 transport | +| `GoTaskService` 调度层 | `AppControllerDesktop/Web`、`GoTaskServiceClient`、`RuntimeCoordinator`、`CodeAgentNodeOrchestrator`、`MultiAgentOrchestrator` | `lib/app/`, `lib/runtime/`, `lib/web/` | 把线程状态翻译为执行请求,并按 OpenClaw / ACP 路径分流执行 | | 对接服务与扩展层 | local agent、OpenClaw Gateway、ACP endpoint、AI Gateway、Skills / MCP / adapters | `lib/runtime/external_code_agent_acp_desktop_transport.dart`, `lib/web/external_code_agent_acp_web_transport.dart`, `lib/runtime/multi_agent_mounts.dart` | 真实执行与扩展接入 | | 安全与持久化基座 | `SettingsStore`、`SecretStore`、`SecureConfigStore`、`WebStore` | `lib/runtime/`, `lib/web/web_store.dart` | 提供持久化与 secret 保护 | @@ -333,7 +355,7 @@ flowchart LR | 平台 | UI 入口 | 线程控制面 | `GoTaskService` 重点 | 当前执行特点 | | --- | --- | --- | --- | --- | -| Desktop | `AppShellDesktop` + workspace 页面 | `TaskThread` 持久化最完整 | `AppControllerDesktop` + `RuntimeCoordinator` + Desktop transport | 支持本地 single-agent、gateway local、gateway remote | +| Desktop | `AppShellDesktop` + workspace 页面 | `TaskThread` 持久化最完整 | `AppControllerDesktop` + `GoTaskService` + `GatewayRuntime / ExternalCodeAgentAcp*` | 支持本地 single-agent、OpenClaw local / remote、ACP/provider route | | Mobile | `mobile_shell_*` | 复用同一线程模型 | 仍走 native host/controller 体系 | 当前以 remote gateway 场景为主 | | Web | `AppShellWeb` | 同 schema 的 thread records | `AppControllerWeb` + `ExternalCodeAgentAcpWebTransport` + relay/acp client | 远程 ACP / relay / AI Gateway 路径 | diff --git a/docs/reports/2026-04-06-github-issue-invalid-request-metadata.md b/docs/reports/2026-04-06-github-issue-invalid-request-metadata.md new file mode 100644 index 00000000..1f493be5 --- /dev/null +++ b/docs/reports/2026-04-06-github-issue-invalid-request-metadata.md @@ -0,0 +1,37 @@ +# GitHub Issue Record: INVALID_REQUEST on Single-Agent Task Mode + +- Date: 2026-04-06 +- Source: In-app error report from desktop app (Task chat mode -> Single Agent) +- Scope: Task conversation in `单机智能体` mode + +## Title + +`INVALID_REQUEST: invalid chat.send params: at root: unexpected property 'metadata'` + +## Reproduction Steps + +1. Open XWorkmate app. +2. Click **新对话**. +3. In task mode selector, choose **任务对话模式 -> 单机智能体**. +4. Send any message. +5. Observe error in conversation pane: + - `INVALID_REQUEST: invalid chat.send params: at root: unexpected property 'metadata'` + +## Actual Result + +The conversation fails immediately and returns request validation error because `chat.send` request payload contains an unexpected root-level `metadata` field. + +## Expected Result + +Single-agent task chat should send a provider-compatible payload and complete message dispatch without schema validation errors. + +## Impact + +- Users cannot reliably start new single-agent task conversations. +- Reproducible in normal workflow, blocks core single-agent usage path. + +## Notes for Follow-up + +- Inspect request assembly path for single-agent `chat.send` payload. +- Confirm whether metadata must be nested, filtered, or omitted for the current provider endpoint. +- Add regression tests for provider schema compatibility in single-agent mode.