Skip to content

Commit 82610d3

Browse files
authored
feat(whatsapp): add requester-bound MeowCaller calls (#99635)
* feat(whatsapp): add requester-bound MeowCaller calls * fix(whatsapp): align MeowCaller CLI contract * test(whatsapp): narrow MeowCaller audio path * fix(whatsapp): budget MeowCaller setup phases * feat(whatsapp): gate experimental calls * fix(whatsapp): use managed call temp storage * fix(whatsapp): preserve channel entry boundary
1 parent be95bb7 commit 82610d3

12 files changed

Lines changed: 813 additions & 4 deletions

docs/channels/whatsapp.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,108 @@ from a remote machine. For remote/headless hosts, prefer a direct QR image
116116
handoff path over manual terminal capture.
117117
</Warning>
118118

119+
## Call the current requester with MeowCaller (experimental)
120+
121+
The WhatsApp plugin can expose `whatsapp_call` in WhatsApp-originated agent turns. The tool
122+
uses [MeowCaller](https://github.com/purpshell/meowcaller) to place a WhatsApp voice call to
123+
the current authorized requester and plays an OpenClaw TTS message after they answer. The tool
124+
does not accept a destination number, so a prompt cannot redirect the call to a third party.
125+
This experimental capability is disabled by default.
126+
127+
<Warning>
128+
MeowCaller is experimental, has no tagged release, and uses a separately paired whatsmeow
129+
linked-device session. It cannot reuse the WhatsApp plugin's Baileys credentials. Pairing adds
130+
another linked device to the same WhatsApp account. Scan with the WhatsApp identity used by
131+
OpenClaw. Personal-number/self-chat mode cannot call itself; use a dedicated OpenClaw number
132+
to call your personal number.
133+
</Warning>
134+
135+
<Steps>
136+
<Step title="Enable experimental calls">
137+
138+
Add `actions.calls: true` to the WhatsApp channel in `openclaw.json`:
139+
140+
```json
141+
{
142+
"channels": {
143+
"whatsapp": {
144+
"actions": {
145+
"calls": true
146+
}
147+
}
148+
}
149+
}
150+
```
151+
152+
Merge this into your existing WhatsApp configuration, then restart the gateway. When the
153+
setting is absent or `false`, OpenClaw does not expose the `whatsapp_call` tool to the agent.
154+
155+
</Step>
156+
157+
<Step title="Install the reviewed MeowCaller CLI">
158+
159+
The adapter expects an executable named `meowcaller` on the gateway host's `PATH`.
160+
Until [MeowCaller PR #7](https://github.com/purpshell/meowcaller/pull/7) merges, build
161+
the reviewed branch at commit `752050471fc2bf7a8cdfbf7dbd3cd4e865d85d3f`:
162+
163+
```bash
164+
git clone --branch feat/send-only-notify https://github.com/steipete/meowcaller.git
165+
cd meowcaller
166+
git checkout 752050471fc2bf7a8cdfbf7dbd3cd4e865d85d3f
167+
mkdir -p "$HOME/.local/bin"
168+
go build -o "$HOME/.local/bin/meowcaller" ./cmd/meowcaller
169+
```
170+
171+
Ensure `$HOME/.local/bin` is also on the gateway service's `PATH`. This revision provides
172+
explicit `pair` and send-only `notify` commands. `notify` opens no microphone, speaker,
173+
video device, inbound audio sink, or diagnostic capture. Do not substitute the example
174+
CLI's `play` command.
175+
176+
</Step>
177+
178+
<Step title="Pair the MeowCaller linked device">
179+
180+
Ask the WhatsApp agent to check call setup. The `whatsapp_call` status action reports the
181+
account-specific state directory and pairing command. For the default account:
182+
183+
```bash
184+
state_dir="$HOME/.openclaw/credentials/whatsapp-calls/default"
185+
mkdir -p "$state_dir"
186+
chmod 700 "$state_dir"
187+
meowcaller pair --store "$state_dir/wa-voip.db"
188+
```
189+
190+
Run the command in an interactive terminal. Scan its QR from **WhatsApp > Linked devices**
191+
and wait for `MeowCaller linked device ready`. The command then exits. Keep `wa-voip.db`
192+
private; it is the MeowCaller linked-device session. The `whatsapp_call` status action
193+
returns the account-specific command and shell when you use a non-default account. On
194+
Windows, run its PowerShell command; MeowCaller creates the store directory.
195+
196+
</Step>
197+
198+
<Step title="Configure TTS and call from WhatsApp">
199+
200+
Configure a telephony-capable [TTS provider](/tools/tts), restart the gateway, then send a
201+
WhatsApp request such as `Call me and say the build finished.` The tool resolves the sender
202+
from trusted inbound context, synthesizes a temporary private WAV file, runs MeowCaller for a
203+
bounded call window, and deletes the audio file afterward. OpenClaw passes the account's
204+
store explicitly, waits for a zero exit status after answer, playback, and hangup, and treats
205+
a timeout or nonzero exit as a failed tool call.
206+
207+
</Step>
208+
</Steps>
209+
210+
Current limits:
211+
212+
- one-to-one outbound audio calls only
213+
- no arbitrary destination numbers
214+
- no shared auth with the chat connection
215+
- no self-calls from personal-number/self-chat mode
216+
- synthesized audio is limited to 60 seconds
217+
- no handset-side audibility receipt beyond MeowCaller's answer/playback/hangup completion
218+
- OpenClaw stops the companion process after a bounded 115–175 second window, including
219+
MeowCaller's connection, answer, playback, and shutdown phases
220+
119221
## Deployment patterns
120222

121223
<AccordionGroup>

docs/docs_map.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
10051005
- Headings:
10061006
- H2: Install (on demand)
10071007
- H2: Quick setup
1008+
- H2: Call the current requester with MeowCaller (experimental)
10081009
- H2: Deployment patterns
10091010
- H2: Runtime model
10101011
- H2: Approval prompts
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// WhatsApp call tool facade keeps the bundled entrypoint light during discovery.
2+
export { registerWhatsAppCallTool } from "./src/agent-tools-call.js";

extensions/whatsapp/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
// Whatsapp plugin entrypoint registers its OpenClaw integration.
2-
import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2+
import {
3+
defineBundledChannelEntry,
4+
loadBundledEntryExportSync,
5+
} from "openclaw/plugin-sdk/channel-entry-contract";
6+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/channel-entry-contract";
7+
8+
function registerWhatsAppCallTool(api: OpenClawPluginApi): void {
9+
const registerTool = loadBundledEntryExportSync<(api: OpenClawPluginApi) => void>(
10+
import.meta.url,
11+
{
12+
specifier: "./call-tool-api.js",
13+
exportName: "registerWhatsAppCallTool",
14+
},
15+
);
16+
registerTool(api);
17+
}
318

419
export default defineBundledChannelEntry({
520
id: "whatsapp",
@@ -14,4 +29,5 @@ export default defineBundledChannelEntry({
1429
specifier: "./runtime-setter-api.js",
1530
exportName: "setWhatsAppRuntime",
1631
},
32+
registerFull: registerWhatsAppCallTool,
1733
});

extensions/whatsapp/openclaw.plugin.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
"activation": {
88
"onStartup": false
99
},
10+
"contracts": {
11+
"tools": ["whatsapp_call"]
12+
},
1013
"channels": ["whatsapp"],
1114
"configSchema": {
1215
"type": "object",

0 commit comments

Comments
 (0)