Docs: point message runtime docs and tests at plugin-owned code

This commit is contained in:
Gustavo Madeira Santana
2026-03-18 02:07:51 +00:00
parent 8165db758b
commit b5c38b1095
5 changed files with 47 additions and 22 deletions

View File

@@ -119,19 +119,24 @@ src/agents/
│ ├── browser-tool.ts
│ ├── canvas-tool.ts
│ ├── cron-tool.ts
│ ├── discord-actions*.ts
│ ├── gateway-tool.ts
│ ├── image-tool.ts
│ ├── message-tool.ts
│ ├── nodes-tool.ts
│ ├── session*.ts
│ ├── slack-actions.ts
│ ├── telegram-actions.ts
│ ├── web-*.ts
│ └── whatsapp-actions.ts
│ └── ...
└── ...
```
Channel-specific message action runtimes now live in the plugin-owned extension
directories instead of under `src/agents/tools`, for example:
- `extensions/discord/src/actions/runtime*.ts`
- `extensions/slack/src/action-runtime.ts`
- `extensions/telegram/src/action-runtime.ts`
- `extensions/whatsapp/src/action-runtime.ts`
## Core Integration Flow
### 1. Running an Embedded Agent

View File

@@ -228,6 +228,13 @@ 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.
For channel-owned execution helpers, bundled plugins should keep the execution
runtime inside their own extension modules. Core no longer owns the Discord,
Slack, Telegram, or WhatsApp message-action runtimes under `src/agents/tools`.
`agent-runtime` still re-exports the Discord and Telegram helpers for backward
compatibility, but we do not publish separate `plugin-sdk/*-action-runtime`
subpaths and new plugins should import their own local runtime code directly.
## Capability ownership model
OpenClaw treats a native plugin as the ownership boundary for a **company** or a

View File

@@ -7,11 +7,11 @@ const sendReactionSignal = vi.fn(async (..._args: unknown[]) => ({ ok: true }));
const removeReactionSignal = vi.fn(async (..._args: unknown[]) => ({ ok: true }));
const handleSlackAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../../../agents/tools/discord-actions.js", () => ({
vi.mock("../../../../extensions/discord/src/actions/runtime.js", () => ({
handleDiscordAction,
}));
vi.mock("../../../agents/tools/telegram-actions.js", () => ({
vi.mock("../../../../extensions/telegram/src/action-runtime.js", () => ({
handleTelegramAction,
}));
@@ -20,7 +20,7 @@ vi.mock("../../../../extensions/signal/src/send-reactions.js", () => ({
removeReactionSignal,
}));
vi.mock("../../../agents/tools/slack-actions.js", () => ({
vi.mock("../../../../extensions/slack/runtime-api.js", () => ({
handleSlackAction,
}));

View File

@@ -18,43 +18,54 @@ vi.mock("../config/config.js", async (importOriginal) => {
};
});
const resolveCommandSecretRefsViaGateway = vi.fn(async ({ config }: { config: unknown }) => ({
resolvedConfig: config,
diagnostics: [] as string[],
const { resolveCommandSecretRefsViaGateway, callGatewayMock } = vi.hoisted(() => ({
resolveCommandSecretRefsViaGateway: vi.fn(async ({ config }: { config: unknown }) => ({
resolvedConfig: config,
diagnostics: [] as string[],
})),
callGatewayMock: vi.fn(),
}));
vi.mock("../cli/command-secret-gateway.js", () => ({
resolveCommandSecretRefsViaGateway,
}));
const callGatewayMock = vi.fn();
vi.mock("../gateway/call.js", () => ({
callGateway: callGatewayMock,
callGatewayLeastPrivilege: callGatewayMock,
randomIdempotencyKey: () => "idem-1",
}));
const webAuthExists = vi.fn(async () => false);
const webAuthExists = vi.hoisted(() => vi.fn(async () => false));
vi.mock("../../extensions/whatsapp/src/session.js", () => ({
webAuthExists,
}));
const handleDiscordAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../agents/tools/discord-actions.js", () => ({
const handleDiscordAction = vi.hoisted(() =>
vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } })),
);
vi.mock("../../extensions/discord/src/actions/runtime.js", () => ({
handleDiscordAction,
}));
const handleSlackAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../agents/tools/slack-actions.js", () => ({
const handleSlackAction = vi.hoisted(() =>
vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } })),
);
vi.mock("../../extensions/slack/runtime-api.js", () => ({
handleSlackAction,
}));
const handleTelegramAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../agents/tools/telegram-actions.js", () => ({
const handleTelegramAction = vi.hoisted(() =>
vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } })),
);
vi.mock("../../extensions/telegram/src/action-runtime.js", () => ({
handleTelegramAction,
}));
const handleWhatsAppAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../agents/tools/whatsapp-actions.js", () => ({
const handleWhatsAppAction = vi.hoisted(() =>
vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } })),
);
vi.mock("../../extensions/whatsapp/runtime-api.js", () => ({
handleWhatsAppAction,
}));
@@ -66,10 +77,12 @@ const setRegistry = async (registry: ReturnType<typeof createTestRegistry>) => {
};
beforeEach(async () => {
vi.resetModules();
envSnapshot = captureEnv(["TELEGRAM_BOT_TOKEN", "DISCORD_BOT_TOKEN"]);
process.env.TELEGRAM_BOT_TOKEN = "";
process.env.DISCORD_BOT_TOKEN = "";
testConfig = {};
({ messageCommand } = await import("./message.js"));
await setRegistry(createTestRegistry([]));
callGatewayMock.mockClear();
webAuthExists.mockClear().mockResolvedValue(false);
@@ -184,7 +197,7 @@ const createTelegramPollPluginRegistration = () => ({
}),
});
const { messageCommand } = await import("./message.js");
let messageCommand: typeof import("./message.js").messageCommand;
function createTelegramSecretRawConfig() {
return {

View File

@@ -61,7 +61,7 @@ function listExtensionFiles(): {
function listHighRiskRuntimeCfgFiles(): string[] {
return [
"src/agents/tools/telegram-actions.ts",
"extensions/telegram/src/action-runtime.ts",
"extensions/discord/src/monitor/reply-delivery.ts",
"extensions/discord/src/monitor/thread-bindings.discord-api.ts",
"extensions/discord/src/monitor/thread-bindings.manager.ts",