WhatsAppBaileysChannel -- bidirectional WhatsApp messaging via Baileys protocol.
Spawns a Node.js subprocess that runs the Baileys bridge (JSON-line protocol
on stdio). The bridge handles QR-code authentication, message sending, and
incoming-message forwarding.
Classes
WhatsAppBaileysChannel
WhatsAppBaileysChannel(*, auth_dir: str = '', assistant_name: str = 'Jarvis', assistant_has_own_number: bool = False, bus: Optional[EventBus] = None)
Bases: BaseChannel
Bidirectional WhatsApp channel using the Baileys protocol.
Communicates with a Node.js bridge subprocess over JSON-line stdio.
| PARAMETER |
DESCRIPTION |
auth_dir
|
Directory for Baileys auth state persistence. Defaults to
~/.openjarvis/whatsapp_baileys_bridge/auth.
TYPE:
str
DEFAULT:
''
|
assistant_name
|
Display name used by the assistant in conversations.
TYPE:
str
DEFAULT:
'Jarvis'
|
assistant_has_own_number
|
If True the assistant has a dedicated WhatsApp number and will
not filter out its own messages.
TYPE:
bool
DEFAULT:
False
|
bus
|
Optional event bus for publishing channel events.
TYPE:
Optional[EventBus]
DEFAULT:
None
|
Source code in src/openjarvis/channels/whatsapp_baileys.py
| def __init__(
self,
*,
auth_dir: str = "",
assistant_name: str = "Jarvis",
assistant_has_own_number: bool = False,
bus: Optional[EventBus] = None,
) -> None:
self._auth_dir = auth_dir
self._assistant_name = assistant_name
self._assistant_has_own_number = assistant_has_own_number
self._bus = bus
self._handlers: List[ChannelHandler] = []
self._status = ChannelStatus.DISCONNECTED
self._process: Optional[subprocess.Popen] = None
self._reader_thread: Optional[threading.Thread] = None
self._stop_event = threading.Event()
self._runtime_dir = _DEFAULT_RUNTIME_DIR
self._last_qr: str = ""
|
Functions
connect
Spawn the Node.js bridge subprocess and start the reader thread.
Source code in src/openjarvis/channels/whatsapp_baileys.py
| def connect(self) -> None:
"""Spawn the Node.js bridge subprocess and start the reader thread."""
if self._status == ChannelStatus.CONNECTED:
return
self._status = ChannelStatus.CONNECTING
try:
bridge_js = self._ensure_bridge()
except RuntimeError as exc:
logger.error("Bridge setup failed: %s", exc)
self._status = ChannelStatus.ERROR
return
auth = self._auth_dir or str(self._runtime_dir / "auth")
try:
self._stop_event.clear()
self._process = subprocess.Popen(
["node", str(bridge_js), "--auth-dir", auth],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
bufsize=1,
)
self._reader_thread = threading.Thread(
target=self._reader_loop, daemon=True,
)
self._reader_thread.start()
logger.info(
"WhatsApp Baileys bridge started (pid=%s)",
self._process.pid,
)
except Exception:
logger.exception("Failed to start bridge subprocess")
self._status = ChannelStatus.ERROR
|
disconnect
Send disconnect command to the bridge and terminate the subprocess.
Source code in src/openjarvis/channels/whatsapp_baileys.py
| def disconnect(self) -> None:
"""Send disconnect command to the bridge and terminate the subprocess."""
self._stop_event.set()
if self._process is not None and self._process.stdin is not None:
try:
self._write_command({"type": "disconnect"})
except Exception:
logger.debug("Could not send disconnect command", exc_info=True)
if self._process is not None:
try:
self._process.terminate()
self._process.wait(timeout=5.0)
except Exception:
logger.debug("Bridge process termination error", exc_info=True)
self._process = None
if self._reader_thread is not None:
self._reader_thread.join(timeout=5.0)
self._reader_thread = None
self._status = ChannelStatus.DISCONNECTED
|
send
send(channel: str, content: str, *, conversation_id: str = '', metadata: Dict[str, Any] | None = None) -> bool
Send a message to a WhatsApp JID via the bridge subprocess.
Source code in src/openjarvis/channels/whatsapp_baileys.py
| def send(
self,
channel: str,
content: str,
*,
conversation_id: str = "",
metadata: Dict[str, Any] | None = None,
) -> bool:
"""Send a message to a WhatsApp JID via the bridge subprocess."""
if self._process is None or self._status != ChannelStatus.CONNECTED:
logger.warning("Cannot send: bridge not connected")
return False
try:
self._write_command({
"type": "send",
"jid": channel,
"text": content,
})
self._publish_sent(channel, content, conversation_id)
return True
except Exception:
logger.debug("WhatsApp Baileys send failed", exc_info=True)
return False
|
status
Return the current connection status.
Source code in src/openjarvis/channels/whatsapp_baileys.py
| def status(self) -> ChannelStatus:
"""Return the current connection status."""
return self._status
|
list_channels
list_channels() -> List[str]
Return available channel identifiers.
Source code in src/openjarvis/channels/whatsapp_baileys.py
| def list_channels(self) -> List[str]:
"""Return available channel identifiers."""
return ["whatsapp_baileys"]
|
on_message
on_message(handler: ChannelHandler) -> None
Register a callback for incoming messages.
Source code in src/openjarvis/channels/whatsapp_baileys.py
| def on_message(self, handler: ChannelHandler) -> None:
"""Register a callback for incoming messages."""
self._handlers.append(handler)
|