Skip to content

Added a native WhatsApp channel implementation.#655

Merged
alexhoshina merged 19 commits intosipeed:refactor/channel-systemfrom
adityakalro:main
Feb 27, 2026
Merged

Added a native WhatsApp channel implementation.#655
alexhoshina merged 19 commits intosipeed:refactor/channel-systemfrom
adityakalro:main

Conversation

@adityakalro
Copy link

📝 Description

Added a native implementation of Whatsapp channel

🗣️ Type of Change

  • 🐞 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 📖 Documentation update
  • ⚡ Code refactoring (no functional changes, no api changes)

🤖 AI Code Generation

  • 🤖 Fully AI-generated (100% AI, 0% Human)
  • 🛠️ Mostly AI-generated (AI draft, Human verified/modified)
  • 👨‍💻 Mostly Human-written (Human lead, AI assisted or none)

🔗 Related Issue

📚 Technical Context (Skip for Docs)

  • Reference URL:
  • Reasoning:

🧪 Test Environment

  • Hardware:: Raspberry Pi Zero 2 W
  • OS: DietPi (Debian)
  • Model/Provider: OpenRouter (nemotron, gpt oss_
  • Channels: Whatsapp

📸 Evidence (Optional)

Click to view Logs/Screenshots

--
2026/02/22 12:27:26 [2026-02-22T20:27:26Z] [INFO] agent: Agent initialized {tools_count=14, skills_total=6, skills_available=6}
2026/02/22 12:27:26 [2026-02-22T20:27:26Z] [INFO] channels: Initializing channel manager
2026/02/22 12:27:26 [2026-02-22T20:27:26Z] [INFO] channels: WhatsApp native channel enabled successfully
2026/02/22 12:27:26 [2026-02-22T20:27:26Z] [INFO] channels: Channel initialization completed {enabled_channels=1}
✓ Channels enabled: [whatsapp]
✓ Gateway started on 0.0.0.0:18790

☑️ Checklist

  • My code/docs follow the style of this project.
  • I have performed a self-review of my own changes.
  • I have updated the documentation accordingly.

Copy link

@nikolasdehor nikolasdehor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good initiative adding native WhatsApp support. The whatsmeow-based approach removes the need for an external bridge, which is a significant UX improvement. However, there are several issues that need addressing before this is merge-ready.

Critical issues

  1. agentMu serialization bottleneck: The new agentMu sync.Mutex in loop.go serializes ALL message processing (processMessage, processSystemMessage, ProcessHeartbeat) across ALL channels through a single global mutex. This means if a Telegram message takes 30 seconds to process, every WhatsApp/Discord/Slack message queues behind it. This is a major regression for multi-channel deployments. The original design processes messages concurrently by design. If the goal is to prevent heartbeat/message races, scope the lock to per-session or per-agent rather than global.

  2. Security: message content logged in base.go: The added log.Printf("Not Allowed: Received message from %s: %s", senderID, content) logs the full message content of rejected senders. This leaks user message content into logs. At minimum, truncate the content or remove it entirely.

  3. Security: no message content validation: handleIncoming passes raw WhatsApp message content directly to the agent without any sanitization. While the existing channels do the same, WhatsApp messages can contain zero-width characters, RTL overrides, and other Unicode control characters that could confuse the LLM or cause display issues.

  4. Empty messages forwarded: If both GetConversation() and ExtendedTextMessage.GetText() return empty (e.g., image-only, sticker, location messages), the empty string is still forwarded to the bus and processed by the agent. Add a if content == "" { return } guard.

Architecture concerns

  1. log.Printf vs logger.InfoCF: The native channel uses raw log.Printf while the rest of the codebase uses the structured logger package. This should be consistent.

  2. No reconnection handling: The whatsmeow client can disconnect (network issues, WhatsApp server restarts). There is no reconnection logic. The events.Disconnected event should be handled to attempt reconnection with backoff.

  3. No media support: The comment says "for now we only forward text" but WhatsApp is heavily media-oriented. At minimum, document this as a known limitation or file a follow-up issue.

  4. Heavy dependency footprint: whatsmeow + modernc.org/sqlite adds ~25 new transitive dependencies (visible in go.sum). For a project called "picoclaw" (ultra-lightweight), this is worth calling out. The whatsmeow approach is valid, but consider making it a build tag (e.g., //go:build whatsapp_native) so users who do not need it do not carry the binary size cost.

Minor

  1. The agentMu changes in loop.go are unrelated to WhatsApp and should be a separate PR. Mixing concurrency model changes with a new channel implementation makes both harder to review and revert.

Please address items 1 (global mutex), 2 (content logging), and 4 (empty message) at minimum.

@adityakalro
Copy link
Author

Thank you for the insightful comments. I've addressed most of them.

Copy link

@nikolasdehor nikolasdehor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing most of the feedback. Checked the new diff:

Fixed:

  • Empty message guard is in place (if content == "" { return }) — good.
  • Content sanitization via SanitizeMessageContent is a solid addition, and the test coverage is appreciated.
  • Structured logging via logger.InfoCF replaces raw log.Printf — good.
  • Reconnection with backoff in handleDisconnect looks solid.

Still outstanding:

  1. Global mutex in loop.go — The comment on line 265 says "It uses the same mutex as processMessage so heartbeat and user messages never run concurrently." But I don't see the actual agentMu field or Lock()/Unlock() calls in the diff for loop.go. Either this was addressed differently (via runAgentLoop serialization?) or the comment is stale. Could you clarify how heartbeat/message concurrency is handled now? The original concern was about a single global mutex serializing ALL channels — if that's been scoped to per-session, that's fine.

  2. content_preview still logged at INFO — Both base.go (line 572, 80-char truncated) and the WhatsApp handler (line 924, 50-char truncated) log message content previews at INFO level. While truncation helps, INFO-level logs are often shipped to external log aggregators where message content shouldn't appear. Consider moving these to DEBUG level, or making content logging opt-in via config. This was item 2 in the original review (slightly different form — now it's truncated rather than full content, which is an improvement, but still INFO).

  3. shell_test.go permission literal changes — The 07550o755 and interface{}any changes in shell_test.go are cosmetic and unrelated to WhatsApp. They should go in a separate cleanup PR to keep this diff focused. (Same feedback as item 9 in original review about mixing concerns.)

Items 1 and 2 are the remaining blockers from the original review. Item 3 is minor but worth splitting out.

Removing extrnaeous comments about mutex in loop.go

Made-with: Cursor
@adityakalro
Copy link
Author

Item 1: Sorry, it was a lingering comment. I went back to the original mechanism that was implemented in the agent and removed the global mutex

Item 2: Move both of those logs to DEBUG

@alexhoshina
Copy link
Collaborator

Hey! We are currently refactoring the channel system and already have a refactoring branch. If possible, please base your development on this branch. Thank you.

@adityakalro
Copy link
Author

Rebased using the channel refactor branch

@alexhoshina alexhoshina changed the base branch from main to refactor/channel-system February 26, 2026 05:01
@alexhoshina
Copy link
Collaborator

I have changed your PR target to the refactor branch

Copy link
Collaborator

@alexhoshina alexhoshina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't thoroughly reviewed the code because there are many non-compliant areas in the directory and the scope of changes.
We hope to minimize the scope of changes for each PR. This PR modifies packages including build, agent, utils, etc., which are unrelated to the channel.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A separate subpackage directory should be created under channels, for example, channels/whatsapp/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the changes here require a new PR, as modifications in a PR should ideally be confined to a single module (package)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the new PR

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the new PR

@alexhoshina alexhoshina added this to the Refactor Channel milestone Feb 26, 2026
@alexhoshina alexhoshina force-pushed the refactor/channel-system branch 2 times, most recently from 8b1e667 to ba98069 Compare February 26, 2026 16:26
@alexhoshina
Copy link
Collaborator

The refactor branch is scheduled to be merged during the daytime of February 28, 2026, Beijing Time (GMT+8), with the exact time yet to be determined. You may wait until after the merge to request a PR review Or complete the review before finishing the merge; I will review your PR as quickly as possible We have provided comprehensive migration documentation for the new channel system.

@adityakalro
Copy link
Author

I've redone the implementation based on the new channel system and cleaned up some of the code as well.
There were a lot of upstream changes that I haven't reviewed and tried not to touch.

@alexhoshina
Copy link
Collaborator

I've redone the implementation based on the new channel system and cleaned up some of the code as well. There were a lot of upstream changes that I haven't reviewed and tried not to touch.

Perhaps you need to rebase onto the latest upstream, as I have rebased and reordered commits on the upstream. Sorry for the extra work. Rebasing main is a necessary preparation before merging. During the refactoring, I tried my best to avoid modifications related to channels from entering main, but some changes still slipped through. Therefore, I performed a rebase yesterday.

Apply go fmt to files that had formatting inconsistencies
(alignment, indentation) after rebasing onto refactor/channel-system.
@alexhoshina alexhoshina merged commit c119e0d into sipeed:refactor/channel-system Feb 27, 2026
2 checks passed
alexhoshina added a commit to alexhoshina/picoclaw that referenced this pull request Feb 27, 2026
…ifecycle

- Move runCtx/runCancel creation before event handler registration and
  QR loop so Stop() can cancel at any point during startup
- Replace blocking QR event loop in Start() with a background goroutine
  that selects on runCtx.Done(), preventing Start() from hanging
  indefinitely when waiting for QR scan
- Track all background goroutines (QR handler, reconnect) with
  sync.WaitGroup; Stop() waits for them to finish before releasing
  client/container resources
- Cancel runCtx on error paths in Start() to avoid leaked contexts

Fixes resource leak introduced in sipeed#655.
@nikolasdehor
Copy link

Good to see this progressing through the channel refactor rebase. @alexhoshina mentioned the refactor branch is scheduled to merge during Feb 28 Beijing time — @adityakalro you may want to hold off on further rebases until that lands to avoid churn.

One thing to watch: the refactor branch (PR #877, merged Feb 27) significantly restructured the channel abstraction layer. Make sure the WhatsApp-specific connection lifecycle (reconnect on disconnect, QR re-auth flow) is compatible with the new Channel interface and capability system (PlaceholderRecorder, StartTyping, etc.).

@Orgmar
Copy link
Contributor

Orgmar commented Feb 28, 2026

@adityakalro A native WhatsApp channel is a great addition to PicoClaw. Getting it running on a Pi Zero 2 W is a solid proof that it works well even on constrained hardware. This opens up a lot of use cases for people who prefer WhatsApp over Discord or Telegram.

We're building a PicoClaw Dev Group on Discord for contributors to connect and collaborate. If you'd like to join, send an email to support@sipeed.com with the subject [Join PicoClaw Dev Group] adityakalro and we'll get you the invite link.

liangzhang-keepmoving pushed a commit to liangzhang-keepmoving/picoclaw that referenced this pull request Mar 2, 2026
…ifecycle

- Move runCtx/runCancel creation before event handler registration and
  QR loop so Stop() can cancel at any point during startup
- Replace blocking QR event loop in Start() with a background goroutine
  that selects on runCtx.Done(), preventing Start() from hanging
  indefinitely when waiting for QR scan
- Track all background goroutines (QR handler, reconnect) with
  sync.WaitGroup; Stop() waits for them to finish before releasing
  client/container resources
- Cancel runCtx on error paths in Start() to avoid leaked contexts

Fixes resource leak introduced in sipeed#655.
jrussellsmyth pushed a commit to jrussellsmyth/picoclaw that referenced this pull request Mar 3, 2026
…ifecycle

- Move runCtx/runCancel creation before event handler registration and
  QR loop so Stop() can cancel at any point during startup
- Replace blocking QR event loop in Start() with a background goroutine
  that selects on runCtx.Done(), preventing Start() from hanging
  indefinitely when waiting for QR scan
- Track all background goroutines (QR handler, reconnect) with
  sync.WaitGroup; Stop() waits for them to finish before releasing
  client/container resources
- Cancel runCtx on error paths in Start() to avoid leaked contexts

Fixes resource leak introduced in sipeed#655.
hyperwd pushed a commit to hyperwd/picoclaw that referenced this pull request Mar 5, 2026
Added a native WhatsApp channel implementation.
hyperwd pushed a commit to hyperwd/picoclaw that referenced this pull request Mar 5, 2026
…ifecycle

- Move runCtx/runCancel creation before event handler registration and
  QR loop so Stop() can cancel at any point during startup
- Replace blocking QR event loop in Start() with a background goroutine
  that selects on runCtx.Done(), preventing Start() from hanging
  indefinitely when waiting for QR scan
- Track all background goroutines (QR handler, reconnect) with
  sync.WaitGroup; Stop() waits for them to finish before releasing
  client/container resources
- Cancel runCtx on error paths in Start() to avoid leaked contexts

Fixes resource leak introduced in sipeed#655.
Pluckypan pushed a commit to Pluckypan/picoclaw that referenced this pull request Mar 6, 2026
Added a native WhatsApp channel implementation.
Pluckypan pushed a commit to Pluckypan/picoclaw that referenced this pull request Mar 6, 2026
…ifecycle

- Move runCtx/runCancel creation before event handler registration and
  QR loop so Stop() can cancel at any point during startup
- Replace blocking QR event loop in Start() with a background goroutine
  that selects on runCtx.Done(), preventing Start() from hanging
  indefinitely when waiting for QR scan
- Track all background goroutines (QR handler, reconnect) with
  sync.WaitGroup; Stop() waits for them to finish before releasing
  client/container resources
- Cancel runCtx on error paths in Start() to avoid leaked contexts

Fixes resource leak introduced in sipeed#655.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants