mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-10-18 23:20:10 +00:00
feat: add bot and self-chat mode selection for WhatsApp bridge
This commit is contained in:
parent
bb8961ab73
commit
a12183ba6e
7 changed files with 57 additions and 6 deletions
|
|
@ -22,6 +22,7 @@ The WhatsApp session persists across restarts in `usr/whatsapp/sessions/`. No re
|
|||
| Setting | Description | Default |
|
||||
|---------|-------------|---------|
|
||||
| `enabled` | Enable bridge and polling | `false` |
|
||||
| `mode` | `bot` (separate number) or `self-chat` (personal number) | `bot` |
|
||||
| `bridge_port` | Local HTTP port for bridge | `3100` |
|
||||
| `poll_interval_seconds` | Poll frequency (min 2) | `3` |
|
||||
| `allowed_users` | Phone numbers without + prefix | `[]` (all) |
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class QrCode(ApiHandler):
|
|||
session_dir = files.get_abs_path("usr/whatsapp/sessions")
|
||||
cache_dir = files.get_abs_path("usr/whatsapp/media")
|
||||
allowed_users = config.get("allowed_users") or []
|
||||
mode = config.get("mode", "bot")
|
||||
|
||||
from plugins._whatsapp_integration.helpers.bridge_manager import (
|
||||
ensure_bridge_http_up,
|
||||
|
|
@ -30,7 +31,7 @@ class QrCode(ApiHandler):
|
|||
if not is_process_alive():
|
||||
try:
|
||||
ok = await ensure_bridge_http_up(
|
||||
port, session_dir, cache_dir, allowed_users,
|
||||
port, session_dir, cache_dir, allowed_users, mode=mode,
|
||||
)
|
||||
if not ok:
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
enabled: false
|
||||
mode: bot
|
||||
# bot: separate phone number — people message the bot directly
|
||||
# self-chat: personal number — you message yourself to talk to the agent
|
||||
bridge_port: 3100
|
||||
poll_interval_seconds: 3
|
||||
allowed_users: []
|
||||
|
|
|
|||
|
|
@ -55,12 +55,13 @@ async def _poll_loop() -> None:
|
|||
session_dir = files.get_abs_path("usr/whatsapp/sessions")
|
||||
cache_dir = files.get_abs_path("usr/whatsapp/media")
|
||||
allowed_users = config.get("allowed_users") or []
|
||||
mode = config.get("mode", "bot")
|
||||
|
||||
# Start bridge if needed
|
||||
if not bridge_started or not bridge_manager.is_process_alive():
|
||||
try:
|
||||
bridge_started = await bridge_manager.start_bridge(
|
||||
port, session_dir, cache_dir, allowed_users,
|
||||
port, session_dir, cache_dir, allowed_users, mode=mode,
|
||||
)
|
||||
except Exception as e:
|
||||
PrintStyle.error(f"WhatsApp bridge start error: {format_error(e)}")
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ async def start_bridge(
|
|||
session_dir: str,
|
||||
cache_dir: str,
|
||||
allowed_users: list[str] | None = None,
|
||||
mode: str = "bot",
|
||||
) -> bool:
|
||||
global _bridge_process
|
||||
async with _bridge_lock:
|
||||
|
|
@ -43,6 +44,7 @@ async def start_bridge(
|
|||
"--port", str(port),
|
||||
"--session", session_dir,
|
||||
"--cache-dir", cache_dir,
|
||||
"--mode", mode,
|
||||
]
|
||||
if allowed_users:
|
||||
cmd += ["--allowed-users", ",".join(allowed_users)]
|
||||
|
|
@ -101,6 +103,7 @@ async def ensure_bridge_http_up(
|
|||
session_dir: str,
|
||||
cache_dir: str,
|
||||
allowed_users: list[str] | None = None,
|
||||
mode: str = "bot",
|
||||
) -> bool:
|
||||
"""Start bridge if needed and wait for HTTP server only (not WA connection)."""
|
||||
global _bridge_process
|
||||
|
|
@ -116,6 +119,7 @@ async def ensure_bridge_http_up(
|
|||
"--port", str(port),
|
||||
"--session", session_dir,
|
||||
"--cache-dir", cache_dir,
|
||||
"--mode", mode,
|
||||
]
|
||||
if allowed_users:
|
||||
cmd += ["--allowed-users", ",".join(allowed_users)]
|
||||
|
|
|
|||
|
|
@ -102,6 +102,32 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="field-label">
|
||||
<div class="field-title">Mode</div>
|
||||
<div class="field-description">How the agent connects to WhatsApp</div>
|
||||
</div>
|
||||
<div class="field-control">
|
||||
<select x-model="config.mode">
|
||||
<option value="bot">Separate bot number</option>
|
||||
<option value="self-chat">Personal number (self-chat)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template x-if="config.mode === 'bot'">
|
||||
<div style="padding: 8px 12px; border-radius: 6px; font-size: 0.85rem; opacity: 0.7;
|
||||
border: 1px solid var(--border-color, #333); margin-bottom: 8px;">
|
||||
People message the bot's number directly. Requires a second phone number with WhatsApp.
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="config.mode === 'self-chat'">
|
||||
<div style="padding: 8px 12px; border-radius: 6px; font-size: 0.85rem; opacity: 0.7;
|
||||
border: 1px solid var(--border-color, #333); margin-bottom: 8px;">
|
||||
You message yourself to talk to the agent. Quick to set up but less intuitive UX.
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- WhatsApp Link section (shown when enabled) -->
|
||||
<template x-if="config.enabled">
|
||||
<div style="margin: 12px 0;">
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ const PORT = parseInt(getArg('port', '3100'), 10);
|
|||
const SESSION_DIR = getArg('session', path.join(process.env.HOME || '~', '.agent-zero', 'whatsapp', 'session'));
|
||||
const CACHE_DIR = getArg('cache-dir', path.join(process.env.HOME || '~', '.agent-zero', 'whatsapp', 'media'));
|
||||
const PAIR_ONLY = args.includes('--pair-only');
|
||||
const MODE = getArg('mode', 'bot'); // "bot" or "self-chat"
|
||||
const ALLOWED_USERS = (getArg('allowed-users', '') || '').split(',').map(s => s.trim()).filter(Boolean);
|
||||
|
||||
mkdirSync(SESSION_DIR, { recursive: true });
|
||||
|
|
@ -158,14 +159,28 @@ async function startSocket() {
|
|||
const isGroup = chatId.endsWith('@g.us');
|
||||
const senderNumber = senderId.replace(/@.*/, '');
|
||||
|
||||
// Bot mode: all fromMe messages are echo-backs — skip
|
||||
if (msg.key.fromMe) continue;
|
||||
// Handle fromMe messages based on mode
|
||||
if (msg.key.fromMe) {
|
||||
if (isGroup || chatId.includes('status')) continue;
|
||||
|
||||
if (MODE === 'bot') {
|
||||
// Bot mode: separate number — all fromMe are echo-backs, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
// Self-chat mode: only accept messages in the user's own self-chat
|
||||
const myNumber = (sock.user?.id || '').replace(/:.*@/, '@').replace(/@.*/, '');
|
||||
const myLid = (sock.user?.lid || '').replace(/:.*@/, '@').replace(/@.*/, '');
|
||||
const chatNumber = chatId.replace(/@.*/, '');
|
||||
const isSelfChat = (myNumber && chatNumber === myNumber) || (myLid && chatNumber === myLid);
|
||||
if (!isSelfChat) continue;
|
||||
}
|
||||
|
||||
// Skip status broadcasts
|
||||
if (chatId === 'status@broadcast') continue;
|
||||
|
||||
// Check allowlist (resolve LID -> phone if needed)
|
||||
if (ALLOWED_USERS.length > 0) {
|
||||
if (!msg.key.fromMe && ALLOWED_USERS.length > 0) {
|
||||
const resolvedNumber = lidToPhone[senderNumber] || senderNumber;
|
||||
if (!ALLOWED_USERS.includes(resolvedNumber)) continue;
|
||||
}
|
||||
|
|
@ -458,7 +473,7 @@ if (PAIR_ONLY) {
|
|||
startSocket();
|
||||
} else {
|
||||
app.listen(PORT, '127.0.0.1', () => {
|
||||
console.log(`[bridge] WhatsApp bridge listening on port ${PORT}`);
|
||||
console.log(`[bridge] WhatsApp bridge listening on port ${PORT} (mode: ${MODE})`);
|
||||
console.log(`[bridge] Session: ${SESSION_DIR}`);
|
||||
if (ALLOWED_USERS.length > 0) {
|
||||
console.log(`[bridge] Allowed users: ${ALLOWED_USERS.join(', ')}`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue