Skip to content

Commit c119e0d

Browse files
authored
Merge pull request #655 from adityakalro/main
Added a native WhatsApp channel implementation.
2 parents 90e49bc + f6c275f commit c119e0d

File tree

18 files changed

+725
-9
lines changed

18 files changed

+725
-9
lines changed

.goreleaser.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ builds:
3131
- loong64
3232
- arm
3333
goarm:
34-
- "7"
34+
- "7"
3535
main: ./cmd/picoclaw
3636
ignore:
3737
- goos: windows

Makefile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,46 @@ build: generate
8787
@echo "Build complete: $(BINARY_PATH)"
8888
@ln -sf $(BINARY_NAME)-$(PLATFORM)-$(ARCH) $(BUILD_DIR)/$(BINARY_NAME)
8989

90+
## build-whatsapp-native: Build with WhatsApp native (whatsmeow) support; larger binary
91+
build-whatsapp-native: generate
92+
## @echo "Building $(BINARY_NAME) with WhatsApp native for $(PLATFORM)/$(ARCH)..."
93+
@echo "Building for multiple platforms..."
94+
@mkdir -p $(BUILD_DIR)
95+
GOOS=linux GOARCH=amd64 $(GO) build -tags whatsapp_native $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 ./$(CMD_DIR)
96+
GOOS=linux GOARCH=arm GOARM=7 $(GO) build -tags whatsapp_native $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm ./$(CMD_DIR)
97+
GOOS=linux GOARCH=arm64 $(GO) build -tags whatsapp_native $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 ./$(CMD_DIR)
98+
GOOS=linux GOARCH=loong64 $(GO) build -tags whatsapp_native $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-loong64 ./$(CMD_DIR)
99+
GOOS=linux GOARCH=riscv64 $(GO) build -tags whatsapp_native $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-riscv64 ./$(CMD_DIR)
100+
GOOS=darwin GOARCH=arm64 $(GO) build -tags whatsapp_native $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-arm64 ./$(CMD_DIR)
101+
GOOS=windows GOARCH=amd64 $(GO) build -tags whatsapp_native $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-windows-amd64.exe ./$(CMD_DIR)
102+
## @$(GO) build $(GOFLAGS) -tags whatsapp_native $(LDFLAGS) -o $(BINARY_PATH) ./$(CMD_DIR)
103+
@echo "Build complete"
104+
## @ln -sf $(BINARY_NAME)-$(PLATFORM)-$(ARCH) $(BUILD_DIR)/$(BINARY_NAME)
105+
106+
## build-linux-arm: Build for Linux ARMv7 (e.g. Raspberry Pi Zero 2 W 32-bit)
107+
build-linux-arm: generate
108+
@echo "Building for linux/arm (GOARM=7)..."
109+
@mkdir -p $(BUILD_DIR)
110+
GOOS=linux GOARCH=arm GOARM=7 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm ./$(CMD_DIR)
111+
@echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)-linux-arm"
112+
113+
## build-linux-arm64: Build for Linux ARM64 (e.g. Raspberry Pi Zero 2 W 64-bit)
114+
build-linux-arm64: generate
115+
@echo "Building for linux/arm64..."
116+
@mkdir -p $(BUILD_DIR)
117+
GOOS=linux GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 ./$(CMD_DIR)
118+
@echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64"
119+
120+
## build-pi-zero: Build for Raspberry Pi Zero 2 W (32-bit and 64-bit)
121+
build-pi-zero: build-linux-arm build-linux-arm64
122+
@echo "Pi Zero 2 W builds: $(BUILD_DIR)/$(BINARY_NAME)-linux-arm (32-bit), $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 (64-bit)"
123+
90124
## build-all: Build picoclaw for all platforms
91125
build-all: generate
92126
@echo "Building for multiple platforms..."
93127
@mkdir -p $(BUILD_DIR)
94128
GOOS=linux GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 ./$(CMD_DIR)
129+
GOOS=linux GOARCH=arm GOARM=7 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm ./$(CMD_DIR)
95130
GOOS=linux GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 ./$(CMD_DIR)
96131
GOOS=linux GOARCH=loong64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-loong64 ./$(CMD_DIR)
97132
GOOS=linux GOARCH=riscv64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-riscv64 ./$(CMD_DIR)

README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,15 @@ make build
154154
# Build for multiple platforms
155155
make build-all
156156

157+
# Build for Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
158+
make build-pi-zero
159+
157160
# Build And Install
158161
make install
159162
```
160163

164+
**Raspberry Pi Zero 2 W:** Use the binary that matches your OS: 32-bit Raspberry Pi OS → `make build-linux-arm` (output: `build/picoclaw-linux-arm`); 64-bit → `make build-linux-arm64` (output: `build/picoclaw-linux-arm64`). Or run `make build-pi-zero` to build both.
165+
161166
## 🐳 Docker Compose
162167

163168
You can also run PicoClaw using Docker Compose without installing anything locally.
@@ -288,12 +293,13 @@ That's it! You have a working AI assistant in 2 minutes.
288293

289294
## 💬 Chat Apps
290295

291-
Talk to your picoclaw through Telegram, Discord, DingTalk, LINE, or WeCom
296+
Talk to your picoclaw through Telegram, Discord, WhatsApp, DingTalk, LINE, or WeCom
292297

293298
| Channel | Setup |
294299
| ------------ | ---------------------------------- |
295300
| **Telegram** | Easy (just a token) |
296301
| **Discord** | Easy (bot token + intents) |
302+
| **WhatsApp** | Easy (native: QR scan; or bridge URL) |
297303
| **QQ** | Easy (AppID + AppSecret) |
298304
| **DingTalk** | Medium (app credentials) |
299305
| **LINE** | Medium (credentials + webhook URL) |
@@ -384,6 +390,33 @@ picoclaw gateway
384390

385391
</details>
386392

393+
<details>
394+
<summary><b>WhatsApp</b> (native via whatsmeow)</summary>
395+
396+
PicoClaw can connect to WhatsApp in two ways:
397+
398+
- **Native (recommended):** In-process using [whatsmeow](https://github.com/tulir/whatsmeow). No separate bridge. Set `"use_native": true` and leave `bridge_url` empty. On first run, scan the QR code with WhatsApp (Linked Devices). Session is stored under your workspace (e.g. `workspace/whatsapp/`). The native channel is **optional** to keep the default binary small; build with `-tags whatsapp_native` (e.g. `make build-whatsapp-native` or `go build -tags whatsapp_native ./cmd/...`).
399+
- **Bridge:** Connect to an external WebSocket bridge. Set `bridge_url` (e.g. `ws://localhost:3001`) and keep `use_native` false.
400+
401+
**Configure (native)**
402+
403+
```json
404+
{
405+
"channels": {
406+
"whatsapp": {
407+
"enabled": true,
408+
"use_native": true,
409+
"session_store_path": "",
410+
"allow_from": []
411+
}
412+
}
413+
}
414+
```
415+
416+
If `session_store_path` is empty, the session is stored in `&lt;workspace&gt;/whatsapp/`. Run `picoclaw gateway`; on first run, scan the QR code printed in the terminal with WhatsApp → Linked Devices.
417+
418+
</details>
419+
387420
<details>
388421
<summary><b>QQ</b></summary>
389422

@@ -1070,7 +1103,11 @@ picoclaw agent -m "Hello"
10701103
"allow_from": [""]
10711104
},
10721105
"whatsapp": {
1073-
"enabled": false
1106+
"enabled": false,
1107+
"bridge_url": "ws://localhost:3001",
1108+
"use_native": false,
1109+
"session_store_path": "",
1110+
"allow_from": []
10741111
},
10751112
"feishu": {
10761113
"enabled": false,

cmd/picoclaw/internal/gateway/helpers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
_ "github.com/sipeed/picoclaw/pkg/channels/telegram"
2525
_ "github.com/sipeed/picoclaw/pkg/channels/wecom"
2626
_ "github.com/sipeed/picoclaw/pkg/channels/whatsapp"
27+
_ "github.com/sipeed/picoclaw/pkg/channels/whatsapp_native"
2728
"github.com/sipeed/picoclaw/pkg/config"
2829
"github.com/sipeed/picoclaw/pkg/cron"
2930
"github.com/sipeed/picoclaw/pkg/devices"

config/config.example.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
"whatsapp": {
8080
"enabled": false,
8181
"bridge_url": "ws://localhost:3001",
82+
"use_native": false,
83+
"session_store_path": "",
8284
"allow_from": [],
8385
"reasoning_channel_id": ""
8486
},
@@ -263,4 +265,4 @@
263265
"host": "127.0.0.1",
264266
"port": 18790
265267
}
266-
}
268+
}

docs/troubleshooting.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Troubleshooting
2+
3+
## "model ... not found in model_list" or OpenRouter "free is not a valid model ID"
4+
5+
**Symptom:** You see either:
6+
7+
- `Error creating provider: model "openrouter/free" not found in model_list`
8+
- OpenRouter returns 400: `"free is not a valid model ID"`
9+
10+
**Cause:** The `model` field in your `model_list` entry is what gets sent to the API. For OpenRouter you must use the **full** model ID, not a shorthand.
11+
12+
- **Wrong:** `"model": "free"` → OpenRouter receives `free` and rejects it.
13+
- **Right:** `"model": "openrouter/free"` → OpenRouter receives `openrouter/free` (auto free-tier routing).
14+
15+
**Fix:** In `~/.picoclaw/config.json` (or your config path):
16+
17+
1. **agents.defaults.model** must match a `model_name` in `model_list` (e.g. `"openrouter-free"`).
18+
2. That entry’s **model** must be a valid OpenRouter model ID, for example:
19+
- `"openrouter/free"` – auto free-tier
20+
- `"google/gemini-2.0-flash-exp:free"`
21+
- `"meta-llama/llama-3.1-8b-instruct:free"`
22+
23+
Example snippet:
24+
25+
```json
26+
{
27+
"agents": {
28+
"defaults": {
29+
"model": "openrouter-free"
30+
}
31+
},
32+
"model_list": [
33+
{
34+
"model_name": "openrouter-free",
35+
"model": "openrouter/free",
36+
"api_key": "sk-or-v1-YOUR_OPENROUTER_KEY",
37+
"api_base": "https://openrouter.ai/api/v1"
38+
}
39+
]
40+
}
41+
```
42+
43+
Get your key at [OpenRouter Keys](https://openrouter.ai/keys).

go.mod

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,48 @@ require (
1111
github.com/google/uuid v1.6.0
1212
github.com/gorilla/websocket v1.5.3
1313
github.com/larksuite/oapi-sdk-go/v3 v3.5.3
14+
github.com/mdp/qrterminal/v3 v3.2.1
1415
github.com/mymmrac/telego v1.6.0
1516
github.com/open-dingtalk/dingtalk-stream-sdk-go v0.9.1
1617
github.com/openai/openai-go/v3 v3.22.0
1718
github.com/slack-go/slack v0.17.3
1819
github.com/spf13/cobra v1.10.2
1920
github.com/stretchr/testify v1.11.1
2021
github.com/tencent-connect/botgo v0.2.1
22+
go.mau.fi/whatsmeow v0.0.0-20260219150138-7ae702b1eed4
2123
golang.org/x/oauth2 v0.35.0
2224
golang.org/x/time v0.14.0
25+
google.golang.org/protobuf v1.36.11
26+
modernc.org/sqlite v1.46.1
2327
)
2428

2529
require (
30+
filippo.io/edwards25519 v1.1.0 // indirect
31+
github.com/beeper/argo-go v1.1.2 // indirect
32+
github.com/coder/websocket v1.8.14 // indirect
2633
github.com/davecgh/go-spew v1.1.1 // indirect
34+
github.com/dustin/go-humanize v1.0.1 // indirect
35+
github.com/elliotchance/orderedmap/v3 v3.1.0 // indirect
2736
github.com/inconshreveable/mousetrap v1.1.0 // indirect
37+
github.com/mattn/go-colorable v0.1.14 // indirect
38+
github.com/mattn/go-isatty v0.0.20 // indirect
39+
github.com/ncruces/go-strftime v1.0.0 // indirect
40+
github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect
2841
github.com/pmezard/go-difflib v1.0.0 // indirect
42+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
43+
github.com/rs/zerolog v1.34.0 // indirect
2944
github.com/spf13/pflag v1.0.10 // indirect
45+
github.com/vektah/gqlparser/v2 v2.5.27 // indirect
46+
go.mau.fi/libsignal v0.2.1 // indirect
47+
go.mau.fi/util v0.9.6 // indirect
48+
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect
49+
golang.org/x/term v0.40.0 // indirect
50+
golang.org/x/text v0.34.0 // indirect
3051
gopkg.in/yaml.v3 v3.0.1 // indirect
52+
modernc.org/libc v1.67.6 // indirect
53+
modernc.org/mathutil v1.7.1 // indirect
54+
modernc.org/memory v1.11.0 // indirect
55+
rsc.io/qr v0.2.0 // indirect
3156
)
3257

3358
require (

0 commit comments

Comments
 (0)