diff --git a/docs/help/testing.md b/docs/help/testing.md index 2055db4373f..0d14f507bc9 100644 --- a/docs/help/testing.md +++ b/docs/help/testing.md @@ -52,6 +52,17 @@ Think of the suites as “increasing realism” (and increasing flakiness/cost): - Runs in CI - No real keys required - Should be fast and stable +- Embedded runner note: + - When you change message-tool discovery inputs or compaction runtime context, + keep both levels of coverage. + - Add focused helper regressions for pure routing/normalization seams. + - Also keep the embedded runner integration suites healthy: + `src/agents/pi-embedded-runner/compact.hooks.test.ts`, + `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, and + `src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`. + - Those suites verify that scoped ids and compaction behavior still flow + through the real `run.ts` / `compact.ts` paths; helper-only tests are not a + sufficient substitute for those seams. - Pool note: - OpenClaw uses Vitest `vmForks` on Node 22, 23, and 24 for faster unit shards. - On Node 25+, OpenClaw automatically falls back to regular `forks` until the repo is re-validated there. diff --git a/docs/tools/plugin.md b/docs/tools/plugin.md index 27979dcb125..af4cd1bf6ac 100644 --- a/docs/tools/plugin.md +++ b/docs/tools/plugin.md @@ -188,6 +188,46 @@ The important design boundary: That split lets OpenClaw validate config, explain missing/disabled plugins, and build UI/schema hints before the full runtime is active. +### Channel plugins and the shared message tool + +Channel plugins do not need to register a separate send/edit/react tool for +normal chat actions. OpenClaw keeps one shared `message` tool in core, and +channel plugins own the channel-specific discovery and execution behind it. + +The current boundary is: + +- core owns the shared `message` tool host, prompt wiring, session/thread + bookkeeping, and execution dispatch +- channel plugins own scoped action discovery, capability discovery, and any + channel-specific schema fragments +- channel plugins execute the final action through their action adapter + +For channel plugins, the preferred SDK surface is +`ChannelMessageActionAdapter.describeMessageTool(...)`. That unified discovery +call lets a plugin return its visible actions, capabilities, and schema +contributions together so those pieces do not drift apart. + +Core passes runtime scope into that discovery step. Important fields include: + +- `accountId` +- `currentChannelId` +- `currentThreadTs` +- `currentMessageId` +- `sessionKey` +- `sessionId` +- `agentId` +- trusted inbound `requesterSenderId` + +That matters for context-sensitive plugins. A channel can hide or expose +message actions based on the active account, current room/thread/message, or +trusted requester identity without hardcoding channel-specific branches in the +core `message` tool. + +This is why embedded-runner routing changes are still plugin work: the runner is +responsible for forwarding the current chat/session identity into the plugin +discovery boundary so the shared `message` tool exposes the right channel-owned +surface for the current turn. + ## Capability ownership model OpenClaw treats a native plugin as the ownership boundary for a **company** or a