feat: add plugin architecture

This commit is contained in:
Peter Steinberger
2026-01-11 12:11:12 +00:00
parent f2b8f7bd5b
commit cf0c72a557
37 changed files with 2408 additions and 8 deletions

View File

@@ -0,0 +1,64 @@
# Voice Call Plugin (Placeholder)
This is a **stub** plugin used to validate the Clawdbot plugin API.
It does not place real calls yet.
## Install (local dev)
Option 1: copy into your global extensions folder:
```bash
mkdir -p ~/.clawdbot/extensions
cp -R extensions/voice-call ~/.clawdbot/extensions/voice-call
cd ~/.clawdbot/extensions/voice-call && pnpm install
```
Option 2: add via config:
```json5
{
plugins: {
load: { paths: ["/absolute/path/to/extensions/voice-call"] },
entries: {
"voice-call": { enabled: true, config: { provider: "twilio" } }
}
}
}
```
Restart the Gateway after changes.
## CLI
```bash
clawdbot voicecall status
clawdbot voicecall start --to "+15555550123" --message "Hello"
```
## Tool
Tool name: `voice_call`
Parameters:
- `mode`: `"call" | "status"`
- `to`: target string
- `message`: optional intro text
## Gateway RPC
- `voicecall.status`
## Skill
The repo includes `skills/voice-call/SKILL.md` for agent guidance. Enable it by
setting:
```json5
{ plugins: { entries: { "voice-call": { enabled: true } } } }
```
## Notes
- This plugin is a placeholder. Implement your real call flow in the tool and
RPC handlers.
- Use `voicecall.*` for RPC names and `voice_call` for tool naming consistency.

View File

@@ -0,0 +1,122 @@
import { Type } from "@sinclair/typebox";
const voiceCallConfigSchema = {
parse(value) {
if (value === undefined) return {};
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error("voice-call config must be an object");
}
return value;
},
};
const voiceCallPlugin = {
id: "voice-call",
name: "Voice Call",
description: "Voice-call plugin stub (placeholder)",
configSchema: voiceCallConfigSchema,
register(api) {
api.registerGatewayMethod("voicecall.status", ({ respond }) => {
respond(true, {
status: "idle",
provider: api.pluginConfig?.provider ?? "unset",
});
});
api.registerTool(
{
name: "voice_call",
label: "Voice Call",
description: "Start or inspect a voice call via the voice-call plugin",
parameters: Type.Object({
mode: Type.Optional(
Type.Union([Type.Literal("call"), Type.Literal("status")]),
),
to: Type.Optional(Type.String({ description: "Call target" })),
message: Type.Optional(
Type.String({ description: "Optional intro message" }),
),
}),
async execute(_toolCallId, params) {
if (params.mode === "status") {
return {
content: [
{
type: "text",
text: JSON.stringify({ status: "idle" }, null, 2),
},
],
details: { status: "idle" },
};
}
return {
content: [
{
type: "text",
text: JSON.stringify(
{
status: "not_implemented",
to: params.to ?? null,
message: params.message ?? null,
},
null,
2,
),
},
],
details: {
status: "not_implemented",
to: params.to ?? null,
message: params.message ?? null,
},
};
},
},
{ name: "voice_call" },
);
api.registerCli(({ program }) => {
const voicecall = program
.command("voicecall")
.description("Voice call plugin commands");
voicecall
.command("status")
.description("Show voice-call status")
.action(() => {
console.log(JSON.stringify({ status: "idle" }, null, 2));
});
voicecall
.command("start")
.description("Start a voice call (placeholder)")
.option("--to <target>", "Target to call")
.option("--message <text>", "Optional intro message")
.action((opts) => {
console.log(
JSON.stringify(
{
status: "not_implemented",
to: opts.to ?? null,
message: opts.message ?? null,
},
null,
2,
),
);
});
}, { commands: ["voicecall"] });
api.registerService({
id: "voicecall",
start: () => {
api.logger.info("voice-call service ready (placeholder)");
},
stop: () => {
api.logger.info("voice-call service stopped (placeholder)");
},
});
},
};
export default voiceCallPlugin;

View File

@@ -0,0 +1,13 @@
{
"name": "voice-call",
"version": "0.0.0",
"private": true,
"type": "module",
"description": "Clawdbot voice-call plugin (example)",
"dependencies": {
"@sinclair/typebox": "0.34.47"
},
"clawdbot": {
"extensions": ["./index.ts"]
}
}