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 +293 -0
- package/README.md +76 -0
- package/dist/core-bridge.d.ts +39 -0
- package/dist/core-bridge.js +96 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +365 -0
- package/openclaw.plugin.json +120 -0
- package/package.json +52 -0
- package/python/requirements-minimal.txt +6 -0
- package/python/requirements.txt +33 -0
- package/python/setup.py +54 -0
- package/python/sip_voice_plugin/__init__.py +13 -0
- package/python/sip_voice_plugin/audio_processor.py +418 -0
- package/python/sip_voice_plugin/call_manager.py +250 -0
- package/python/sip_voice_plugin/config.py +147 -0
- package/python/sip_voice_plugin/conversation.py +361 -0
- package/python/sip_voice_plugin/llm_backends.py +202 -0
- package/python/sip_voice_plugin/main.py +117 -0
- package/python/sip_voice_plugin/openclaw_bridge.py +387 -0
- package/python/sip_voice_plugin/openclaw_connector.py +269 -0
- package/python/sip_voice_plugin/plugin.py +219 -0
- package/python/sip_voice_plugin/rtp_handler.py +557 -0
- package/python/sip_voice_plugin/sip_client.py +224 -0
- package/python/sip_voice_plugin/sip_server.py +537 -0
- package/python/sip_voice_plugin/standalone.py +397 -0
- package/python/sip_voice_plugin/tts_backends.py +232 -0
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
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -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;
|