openclaw-sip-voice 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/INSTALL.md ADDED
@@ -0,0 +1,293 @@
1
+ # Installation Guide - OpenClaw SIP Voice Plugin
2
+
3
+ Complete installation instructions for the SIP Voice plugin.
4
+
5
+ ## Prerequisites
6
+
7
+ Before installing, ensure you have:
8
+
9
+ - ✅ **OpenClaw** ≥ 2026.0.0 installed and running
10
+ - ✅ **Python** 3.9 or higher (`python3 --version`)
11
+ - ✅ **pip** package manager (`pip3 --version`)
12
+ - ✅ **ffmpeg** for audio conversion (`ffmpeg -version`)
13
+ - ✅ **Whisper CLI** (optional, for local STT: `pip install openai-whisper`)
14
+
15
+ ## Installation
16
+
17
+ ### Simple One-Command Install ✨
18
+
19
+ ```bash
20
+ openclaw plugins install openclaw-sip-voice
21
+ openclaw gateway restart
22
+ ```
23
+
24
+ **That's it!** The plugin automatically installs Python dependencies on first startup.
25
+
26
+ ---
27
+
28
+ ## Alternative Installation Methods
29
+
30
+ ### From npm (Recommended)
31
+
32
+ ```bash
33
+ openclaw plugins install openclaw-sip-voice
34
+ ```
35
+
36
+ ### From GitHub (Development)
37
+
38
+ ```bash
39
+ git clone https://github.com/chrishodgkins/openclaw-sip-voice.git
40
+ cd openclaw-sip-voice/plugin
41
+ npm install
42
+ npm run build
43
+ openclaw plugins install -l .
44
+ ```
45
+
46
+ ### From Tarball
47
+
48
+ ```bash
49
+ # Download the tarball
50
+ curl -L https://github.com/chrishodgkins/openclaw-sip-voice/releases/download/v0.1.0/openclaw-sip-voice-0.1.0.tgz -o sip-voice.tgz
51
+
52
+ # Install
53
+ openclaw plugins install ./sip-voice.tgz
54
+ ```
55
+
56
+ ## Auto-Install Details
57
+
58
+ When you start the gateway after installing the plugin, it will:
59
+
60
+ 1. **Check** if Python dependencies are installed
61
+ 2. **Auto-install** them if needed (runs `pip3 install -e python/`)
62
+ 3. **Log progress** - First startup takes 30-60 seconds for dependency install
63
+ 4. **Start normally** on subsequent restarts (instant)
64
+
65
+ **Requirements:**
66
+ - Python 3.9 or higher must be installed
67
+ - `pip3` must be available in PATH
68
+
69
+ **Manual Install (if auto-install fails):**
70
+ ```bash
71
+ cd ~/.openclaw/extensions/sip-voice/python
72
+ pip3 install -e .
73
+ ```
74
+
75
+ ## Configuration
76
+
77
+ Edit your OpenClaw config (`~/.openclaw/config.json`):
78
+
79
+ ```json
80
+ {
81
+ "plugins": {
82
+ "entries": {
83
+ "sip-voice": {
84
+ "enabled": true,
85
+ "config": {
86
+ "sip": {
87
+ "port": 5060,
88
+ "rtpPortBase": 20000,
89
+ "codec": "PCMA"
90
+ },
91
+ "stt": {
92
+ "model": "base",
93
+ "language": "en"
94
+ },
95
+ "greeting": "Hello! You've reached my AI assistant. How can I help you today?"
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### Configuration Options
104
+
105
+ | Option | Default | Description |
106
+ |--------|---------|-------------|
107
+ | `sip.port` | 5060 | SIP listen port (UDP) |
108
+ | `sip.rtpPortBase` | 20000 | Base port for RTP media |
109
+ | `sip.codec` | PCMA | Audio codec (PCMA or PCMU) |
110
+ | `stt.model` | tiny | Whisper model (tiny/base/small/medium/large) |
111
+ | `stt.language` | en | Transcription language |
112
+ | `greeting` | "Hello!" | Initial greeting message |
113
+
114
+ ## Testing the Installation
115
+
116
+ ### Check Plugin Status
117
+
118
+ ```bash
119
+ openclaw plugins list | grep sip-voice
120
+ ```
121
+
122
+ You should see:
123
+ ```
124
+ ✓ sip-voice (enabled)
125
+ ```
126
+
127
+ ### Make a Test Call
128
+
129
+ Use any SIP client (desk phone, softphone, or mobile app):
130
+
131
+ 1. Configure SIP client to call: `sip:test@YOUR_IP_ADDRESS:5060`
132
+ 2. Make the call
133
+ 3. The agent should answer with your greeting message
134
+ 4. Have a conversation!
135
+
136
+ **Example SIP clients:**
137
+ - **Desktop:** MicroSIP, Linphone, Zoiper
138
+ - **Mobile:** Linphone (iOS/Android), Zoiper (iOS/Android)
139
+ - **Web:** JsSIP
140
+
141
+ ### Check Logs
142
+
143
+ If issues occur, check the OpenClaw logs:
144
+
145
+ ```bash
146
+ # Gateway logs
147
+ openclaw logs
148
+
149
+ # Plugin-specific logs (if available)
150
+ tail -f ~/.openclaw/logs/sip-voice.log
151
+ ```
152
+
153
+ ## Troubleshooting
154
+
155
+ ### "Module not found" or Import Errors
156
+
157
+ **Problem:** Python dependencies not installed.
158
+
159
+ **Solution:**
160
+ ```bash
161
+ cd ~/.openclaw/extensions/sip-voice/python
162
+ pip install -e .
163
+ ```
164
+
165
+ ### "Port 5060 already in use"
166
+
167
+ **Problem:** Another SIP service is using port 5060.
168
+
169
+ **Solution:** Change the port in config.json:
170
+ ```json
171
+ {
172
+ "plugins": {
173
+ "entries": {
174
+ "sip-voice": {
175
+ "config": {
176
+ "sip": {
177
+ "port": 5061
178
+ }
179
+ }
180
+ }
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ ### "No audio" or "One-way audio"
187
+
188
+ **Problem:** Firewall blocking RTP packets.
189
+
190
+ **Solution:**
191
+ - Open UDP ports 20000-20100 in your firewall
192
+ - If behind NAT, forward these ports to your machine
193
+ - Linux: `sudo ufw allow 20000:20100/udp`
194
+
195
+ ### "Whisper not found"
196
+
197
+ **Problem:** Whisper CLI not installed.
198
+
199
+ **Solution:**
200
+ ```bash
201
+ # Install Whisper CLI
202
+ pip install openai-whisper
203
+
204
+ # Verify installation
205
+ which whisper
206
+ ```
207
+
208
+ **Alternative:** Use OpenAI Whisper API instead (requires API key).
209
+
210
+ ### "ffmpeg not found"
211
+
212
+ **Problem:** ffmpeg not installed.
213
+
214
+ **Solution:**
215
+ ```bash
216
+ # macOS
217
+ brew install ffmpeg
218
+
219
+ # Ubuntu/Debian
220
+ sudo apt install ffmpeg
221
+
222
+ # Verify
223
+ ffmpeg -version
224
+ ```
225
+
226
+ ## Platform-Specific Notes
227
+
228
+ ### macOS
229
+ - ✅ Fully supported
230
+ - ✅ Native TTS via `say` command available
231
+ - ✅ All features tested
232
+
233
+ ### Linux
234
+ - ✅ Fully supported
235
+ - ⚠️ No native TTS (`say` command) - use cloud TTS (ElevenLabs/OpenAI)
236
+ - ✅ All other features work
237
+
238
+ ### Windows
239
+ - ⚠️ Untested
240
+ - 💡 May require WSL (Windows Subsystem for Linux)
241
+
242
+ ## Advanced Setup
243
+
244
+ ### Using with SIP Trunk Providers
245
+
246
+ Most SIP trunk providers (Twilio, Voip.ms, etc.) can route calls to your server:
247
+
248
+ 1. Get a phone number from your provider
249
+ 2. Configure routing to: `sip:YOUR_PUBLIC_IP:5060`
250
+ 3. Ensure port 5060 UDP is open to the internet
251
+ 4. Calls to that number will reach your agent!
252
+
253
+ ### Custom TTS Providers
254
+
255
+ Configure in OpenClaw's main config (not plugin config):
256
+ ```json
257
+ {
258
+ "tools": {
259
+ "media": {
260
+ "models": [
261
+ {
262
+ "provider": "elevenlabs",
263
+ "capabilities": ["audio"]
264
+ }
265
+ ]
266
+ }
267
+ }
268
+ }
269
+ ```
270
+
271
+ ### Using Behind NAT/Firewall
272
+
273
+ If your OpenClaw instance is behind a firewall or NAT:
274
+
275
+ 1. **Port forwarding:** Forward UDP 5060 and 20000-20100
276
+ 2. **External IP:** Plugin detects external IP automatically
277
+ 3. **Firewall rules:** Allow incoming UDP on those ports
278
+
279
+ ## Next Steps
280
+
281
+ - 📖 Read the [main README](../README.md) for features and architecture
282
+ - 🐛 Check [known issues](https://github.com/chrishodgkins/openclaw-sip-voice/issues)
283
+ - 🤝 Contribute via [CONTRIBUTING.md](../CONTRIBUTING.md)
284
+
285
+ ## Getting Help
286
+
287
+ - **Issues:** https://github.com/chrishodgkins/openclaw-sip-voice/issues
288
+ - **OpenClaw Docs:** https://docs.openclaw.ai
289
+ - **Discord:** https://discord.com/invite/clawd
290
+
291
+ ---
292
+
293
+ **Installation complete!** 🎉 Make a test call and talk to your AI agent!
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # OpenClaw SIP Voice Plugin
2
+
3
+ Answer SIP/VoIP calls with your OpenClaw AI agent.
4
+
5
+ **Version:** 0.1.0 (Beta)
6
+ **Author:** Chris Hodgkins
7
+ **License:** MIT
8
+
9
+ ## Quick Install
10
+
11
+ ```bash
12
+ # Install the plugin (Python dependencies auto-install on first run)
13
+ openclaw plugins install openclaw-sip-voice
14
+
15
+ # Restart gateway
16
+ openclaw gateway restart
17
+ ```
18
+
19
+ **That's it!** Python dependencies are automatically installed when the plugin starts for the first time.
20
+
21
+ See [INSTALL.md](./INSTALL.md) for detailed setup instructions.
22
+
23
+ ## What It Does
24
+
25
+ - 📞 Answers SIP calls with AI conversations
26
+ - 🎙️ Whisper STT → OpenClaw Agent → TTS pipeline
27
+ - 🔌 Full integration with OpenClaw tools and memory
28
+ - 🐍 Pure Python SIP server (no PJSIP dependency)
29
+ - 🎛️ G.711 PCMA/PCMU codec support
30
+
31
+ ## Requirements
32
+
33
+ - **OpenClaw** ≥ 2026.0.0
34
+ - **Python** ≥ 3.9
35
+ - **ffmpeg** (audio conversion)
36
+ - **Whisper CLI** (for local STT) OR OpenAI Whisper API
37
+
38
+ ## Configuration
39
+
40
+ Add to `~/.openclaw/config.json`:
41
+
42
+ ```json
43
+ {
44
+ "plugins": {
45
+ "entries": {
46
+ "sip-voice": {
47
+ "enabled": true,
48
+ "config": {
49
+ "sip": {
50
+ "port": 5060,
51
+ "codec": "PCMA"
52
+ },
53
+ "greeting": "Hello! How can I help you?"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## Documentation
62
+
63
+ - Full README: [../README.md](../README.md)
64
+ - Installation: [INSTALL.md](./INSTALL.md)
65
+ - Changelog: [../CHANGELOG.md](../CHANGELOG.md)
66
+ - Contributing: [../CONTRIBUTING.md](../CONTRIBUTING.md)
67
+
68
+ ## Support
69
+
70
+ - 🐛 [Report Issues](https://github.com/chrishodgkins/openclaw-sip-voice/issues)
71
+ - 📖 [OpenClaw Docs](https://docs.openclaw.ai)
72
+ - 💬 [OpenClaw Discord](https://discord.com/invite/clawd)
73
+
74
+ ## License
75
+
76
+ MIT - See [../LICENSE](../LICENSE) for details.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Core bridge for OpenClaw integration
3
+ *
4
+ * Provides access to OpenClaw's core agent functionality via dynamic import
5
+ * of the extension API.
6
+ */
7
+ export type CoreConfig = Record<string, unknown>;
8
+ export interface CoreAgentDeps {
9
+ resolveAgentWorkspaceDir: (cfg: CoreConfig, agentId: string) => string;
10
+ runEmbeddedPiAgent: (params: {
11
+ sessionId: string;
12
+ sessionFile: string;
13
+ workspaceDir: string;
14
+ config?: CoreConfig;
15
+ prompt: string;
16
+ timeoutMs: number;
17
+ runId: string;
18
+ lane?: string;
19
+ extraSystemPrompt?: string;
20
+ }) => Promise<{
21
+ payloads?: Array<{
22
+ text?: string;
23
+ isError?: boolean;
24
+ }>;
25
+ meta?: {
26
+ aborted?: boolean;
27
+ };
28
+ }>;
29
+ resolveAgentTimeoutMs: (opts: {
30
+ cfg: CoreConfig;
31
+ }) => number;
32
+ resolveSessionFilePath: (sessionId: string, entry: unknown, opts?: {
33
+ agentId?: string;
34
+ }) => string;
35
+ }
36
+ /**
37
+ * Load core agent dependencies (cached)
38
+ */
39
+ export declare function loadCoreAgentDeps(): Promise<CoreAgentDeps>;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Core bridge for OpenClaw integration
3
+ *
4
+ * Provides access to OpenClaw's core agent functionality via dynamic import
5
+ * of the extension API.
6
+ */
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { pathToFileURL } from "node:url";
10
+ import os from "node:os";
11
+ let coreDepsPromise = null;
12
+ let cachedOpenClawRoot = null;
13
+ /**
14
+ * Find the OpenClaw installation root directory
15
+ */
16
+ function findOpenClawRoot() {
17
+ // Check environment override first
18
+ const override = process.env.OPENCLAW_ROOT?.trim();
19
+ if (override && fs.existsSync(override)) {
20
+ return override;
21
+ }
22
+ // Common installation paths
23
+ const candidates = [
24
+ // Running from within OpenClaw
25
+ path.dirname(process.argv[1] || ""),
26
+ process.cwd(),
27
+ // Homebrew (macOS)
28
+ "/opt/homebrew/lib/node_modules/openclaw",
29
+ // Global npm
30
+ "/usr/local/lib/node_modules/openclaw",
31
+ // User-local npm
32
+ path.join(os.homedir(), ".npm/lib/node_modules/openclaw"),
33
+ path.join(os.homedir(), "node_modules/openclaw"),
34
+ // pnpm global
35
+ path.join(os.homedir(), ".local/share/pnpm/global/5/node_modules/openclaw"),
36
+ ];
37
+ // Walk up from script directory
38
+ let dir = path.dirname(process.argv[1] || process.cwd());
39
+ for (let i = 0; i < 10; i++) {
40
+ candidates.push(dir);
41
+ const parent = path.dirname(dir);
42
+ if (parent === dir)
43
+ break;
44
+ dir = parent;
45
+ }
46
+ for (const candidate of candidates) {
47
+ const pkgPath = path.join(candidate, "package.json");
48
+ try {
49
+ if (fs.existsSync(pkgPath)) {
50
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
51
+ if (pkg.name === "openclaw") {
52
+ return candidate;
53
+ }
54
+ }
55
+ }
56
+ catch {
57
+ // Ignore errors and try next candidate
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+ /**
63
+ * Import the OpenClaw extension API dynamically
64
+ */
65
+ async function importCoreExtensionAPI() {
66
+ if (!cachedOpenClawRoot) {
67
+ cachedOpenClawRoot = findOpenClawRoot();
68
+ }
69
+ if (!cachedOpenClawRoot) {
70
+ throw new Error("OpenClaw installation not found. " +
71
+ "Ensure OpenClaw is installed globally or set OPENCLAW_ROOT environment variable.");
72
+ }
73
+ const distPath = path.join(cachedOpenClawRoot, "dist", "extensionAPI.js");
74
+ if (!fs.existsSync(distPath)) {
75
+ throw new Error(`Missing OpenClaw extension API at ${distPath}. ` +
76
+ "Ensure OpenClaw is properly installed.");
77
+ }
78
+ // Dynamic import using file URL
79
+ const api = await import(pathToFileURL(distPath).href);
80
+ return {
81
+ resolveAgentWorkspaceDir: api.resolveAgentWorkspaceDir,
82
+ runEmbeddedPiAgent: api.runEmbeddedPiAgent,
83
+ resolveAgentTimeoutMs: api.resolveAgentTimeoutMs,
84
+ resolveSessionFilePath: api.resolveSessionFilePath,
85
+ };
86
+ }
87
+ /**
88
+ * Load core agent dependencies (cached)
89
+ */
90
+ export async function loadCoreAgentDeps() {
91
+ if (coreDepsPromise) {
92
+ return coreDepsPromise;
93
+ }
94
+ coreDepsPromise = importCoreExtensionAPI();
95
+ return coreDepsPromise;
96
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * OpenClaw SIP Voice Plugin
3
+ *
4
+ * Answers SIP calls with AI-powered conversations.
5
+ * Uses a Python SIP server subprocess for telephony,
6
+ * routing conversations through OpenClaw's agent system.
7
+ */
8
+ interface SipVoiceConfig {
9
+ enabled?: boolean;
10
+ sip?: {
11
+ port?: number;
12
+ rtpPortBase?: number;
13
+ codec?: "PCMA" | "PCMU";
14
+ };
15
+ stt?: {
16
+ model?: string;
17
+ language?: string;
18
+ };
19
+ greeting?: string;
20
+ pythonPath?: string;
21
+ sipServerPath?: string;
22
+ }
23
+ interface PluginApi {
24
+ config: Record<string, unknown>;
25
+ pluginConfig: unknown;
26
+ logger: {
27
+ info: (msg: string) => void;
28
+ warn: (msg: string) => void;
29
+ error: (msg: string) => void;
30
+ debug: (msg: string) => void;
31
+ };
32
+ runtime: {
33
+ tts: {
34
+ textToSpeechTelephony: (opts: {
35
+ text: string;
36
+ cfg: unknown;
37
+ }) => Promise<{
38
+ pcm: Buffer;
39
+ sampleRate: number;
40
+ } | null>;
41
+ };
42
+ };
43
+ registerService: (service: {
44
+ id: string;
45
+ start: () => void | Promise<void>;
46
+ stop: () => void | Promise<void>;
47
+ }) => void;
48
+ registerGatewayMethod: (method: string, handler: (ctx: {
49
+ params?: Record<string, unknown>;
50
+ respond: (success: boolean, data: unknown) => void;
51
+ }) => void | Promise<void>) => void;
52
+ }
53
+ /**
54
+ * Plugin definition
55
+ */
56
+ declare const sipVoicePlugin: {
57
+ id: string;
58
+ name: string;
59
+ description: string;
60
+ configSchema: {
61
+ parse(value: unknown): SipVoiceConfig;
62
+ };
63
+ register(api: PluginApi): void;
64
+ };
65
+ export default sipVoicePlugin;