Desktop: whatsapp integration#8462
Conversation
Machine-specific run.sh signing/libwebp fixes and local Swift compile tweaks. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds the desktop WhatsApp linking surface and wacli runtime staging so users can pair WhatsApp via QR and see connection status locally. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds Swift-backed wacli read and manual send tool execution so the agent can list chats, read/search threads, and send a guarded text reply. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds a stdio MCP server that exposes WhatsApp read and manual send tools through the existing Swift bridge. Co-authored-by: Cursor <cursoragent@cursor.com>
Registers the WhatsApp stdio MCP server alongside omi-tools so agent chats can invoke Swift-backed WhatsApp tools. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds the inbound WhatsApp reply coordinator and routes received sync events into an autonomous draft flow through the existing agent tools. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds reply-mode settings, allowlist checks, rate limiting, sensitive-content draft fallback, kill-switch enforcement, and audit logging for WhatsApp sends. Co-authored-by: Cursor <cursoragent@cursor.com>
Stores pending WhatsApp drafts, exposes approve/dismiss/always-auto actions, and surfaces draft-ready notifications through the floating bar. Co-authored-by: Cursor <cursoragent@cursor.com>
Builds a lightweight WhatsApp writing-style profile from sent messages and injects it into autonomous reply drafting with a tone-match opt-out. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds settings controls for reply mode, kill switch, drafts, auto-send allowlist, rate limits, quiet hours, tone matching, and audit history. Co-authored-by: Cursor <cursoragent@cursor.com>
Prefers the verified openclaw wacli build for local desktop runs and surfaces a clear error when an older binary lacks QR auth flags. Co-authored-by: Cursor <cursoragent@cursor.com>
Uses wacli sync webhook delivery for live inbound WhatsApp messages, resumes sync for authenticated stores, and parses wacli message JSON keys. Co-authored-by: Cursor <cursoragent@cursor.com>
Handles wacli live webhook keys like ID, Chat, and PushName so inbound messages reach the draft coordinator. Co-authored-by: Cursor <cursoragent@cursor.com>
Surface draft failures clearly and gate autonomous WhatsApp drafts on a fresh backend quota check while keeping transient sync reconnects from forcing reauth. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve the Messages page so WhatsApp chats stay current, drafts attach to the right conversations, and generated replies do not leak reasoning into visible or sent text. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
39 issues found across 35 files
Confidence score: 2/5
desktop/macos/Desktop/Sources/WhatsApp/WhatsAppWebhookServer.swifthas multiple merge-blocking request-handling flaws: negativeContent-Lengthcan crash parsing, rejected requests still return200 {"ok":true}(so upstream won’t retry), and inbound webhook origin is not authenticated. Merging as-is risks crashes, silent message loss, and spoofed local requests—add strict header validation, return non-2xx on internal rejection, and enforce request authentication before dispatch.- In
desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReplyCoordinator.swift,processedMessageIDsis updated before draft creation succeeds, so transient failures become permanent drops on redelivery. This can cause user-visible missed replies—only mark IDs processed after successful draft creation (or remove them on failure) before merging. desktop/macos/agent/src/wa-tools-stdio.tsanddesktop/macos/Desktop/Sources/WhatsApp/WhatsAppService.swiftboth have hang paths (wa-toolspending calls never time out/clean up, andrunOneShotcan deadlock on full pipes before output is drained). The consequence is stuck workflows and leaked in-flight state—add timeout/reject+cleanup on bridge loss and drain stdout/stderr concurrently beforewaitUntilExit().- There are correctness regressions in state/audit/dedup logic:
desktop/macos/Desktop/Sources/WhatsApp/WhatsAppService.swiftmay report false.connected,desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReplyGuardrails.swiftfails to decode audit entries due to date-strategy mismatch, anddesktop/macos/Desktop/Sources/WhatsApp/WhatsAppMemoryImportService.swiftuses unstablehashValuefor persisted dedup IDs. This can mislead connection state and corrupt operational history/dedup behavior—switch to structured state checks, match ISO-8601 decode strategy, and use a stable deterministic hash/ID scheme.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="desktop/macos/run.sh">
<violation number="1" location="desktop/macos/run.sh:592">
P1: Auto-detected signing identity now uses the SHA-1 hash, but the team-ID extraction still expects the display-name format, causing a false profile/team mismatch and an unintended fallback that strips the Sign In with Apple entitlement.</violation>
</file>
<file name="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift:3">
P2: `@MainActor` isolation keeps expensive JSON parsing on the main actor, risking UI stalls despite the CLI execution being detached.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| SIGN_IDENTITY=$(security find-identity -v -p codesigning | grep "Apple Development" | head -1 | sed 's/.*"\(.*\)"/\1/') | ||
| # Skip revoked certs and use the SHA-1 hash — duplicate display names (revoked + valid) | ||
| # make name-based signing ambiguous. | ||
| SIGN_IDENTITY=$(security find-identity -v -p codesigning | grep -v REVOKED | grep "Apple Development" | head -1 | awk '{print $2}') |
There was a problem hiding this comment.
P1: Auto-detected signing identity now uses the SHA-1 hash, but the team-ID extraction still expects the display-name format, causing a false profile/team mismatch and an unintended fallback that strips the Sign In with Apple entitlement.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/run.sh, line 592:
<comment>Auto-detected signing identity now uses the SHA-1 hash, but the team-ID extraction still expects the display-name format, causing a false profile/team mismatch and an unintended fallback that strips the Sign In with Apple entitlement.</comment>
<file context>
@@ -574,9 +587,11 @@ step "Signing app with hardened runtime..."
- SIGN_IDENTITY=$(security find-identity -v -p codesigning | grep "Apple Development" | head -1 | sed 's/.*"\(.*\)"/\1/')
+ # Skip revoked certs and use the SHA-1 hash — duplicate display names (revoked + valid)
+ # make name-based signing ambiguous.
+ SIGN_IDENTITY=$(security find-identity -v -p codesigning | grep -v REVOKED | grep "Apple Development" | head -1 | awk '{print $2}')
if [ -z "$SIGN_IDENTITY" ]; then
- SIGN_IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed 's/.*"\(.*\)"/\1/')
</file context>
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks for the contribution. I’m going to request changes rather than approve this because the PR introduces a broad, security/privacy-sensitive WhatsApp integration and bundles a new executable.
Blocking concerns:
desktop/macos/Desktop/Sources/Resources/wacliis a ~44 MB Mach-O universal executable added directly to the PR. I can’t treat an opaque binary from a first-time contributor as reviewable or safe to ship. Please remove the bundled binary from the PR and instead document or implement a trusted, reproducible supply-chain path for obtaining/building it, including version/source/provenance and maintainer-controlled release packaging.- The feature gives the desktop app access to WhatsApp messages/contacts, can import private messages into Omi memories, starts a local webhook, exposes WhatsApp tools to the agent, and includes message-sending/auto-reply flows. That needs explicit maintainer product/security/privacy review before merge.
- The change is very large and difficult to review as one unit (35 files / ~6k changed lines), with only a very small test addition. Please split this into smaller PRs, e.g. UI shell, wacli/runtime packaging, read-only message sync, memory import, and send/auto-reply guardrails, with focused tests for each.
- For any future version that can send or auto-send messages, please add tests and documentation around consent, allowlisting, kill switch behavior, rate limits, quiet hours, audit logs, and prompt/tool-call boundaries.
This is not a rejection of the idea; WhatsApp could be valuable for Omi. But this specific PR needs a much narrower, reviewable shape and maintainer-owned security/provenance decisions before it can proceed.
Fix validated WhatsApp webhook, draft, sync, and tool-runtime failure modes so local message handling is safer and avoids silent data loss, stale UI, and hung subprocesses. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
7 issues found across 17 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="desktop/macos/run.sh">
<violation number="1" location="desktop/macos/run.sh:592">
P1: Auto-detected signing identity now uses the SHA-1 hash, but the team-ID extraction still expects the display-name format, causing a false profile/team mismatch and an unintended fallback that strips the Sign In with Apple entitlement.</violation>
</file>
<file name="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift:3">
P2: `@MainActor` isolation keeps expensive JSON parsing on the main actor, risking UI stalls despite the CLI execution being detached.</violation>
<violation number="2" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift:41">
P1: New diagnostics log raw WhatsApp CLI arguments and output, leaking JIDs/phone numbers and potential message content into local logs and Sentry breadcrumbs.</violation>
<violation number="3" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift:181">
P2: New guard in collectMessages drops text-only messages that lack senderJid, timestamp, or explicit ID; previously they were retained with a synthesized fallback ID.</violation>
<violation number="4" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift:244">
P2: Strict JID suffix filtering may exclude legitimate WhatsApp chat types not in the hard-coded list.</violation>
</file>
<file name="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift:273">
P1: Restrictive JID allowlist silently rewrites valid explicit JIDs as phone-number `@s.whatsapp.net` recipients and may drop valid contacts from wacli output</violation>
</file>
<file name="desktop/macos/agent/src/wa-tools-stdio.ts">
<violation number="1" location="desktop/macos/agent/src/wa-tools-stdio.ts:131">
P1: Tool-call timeout rejects the caller without cancelling the Swift work or ensuring idempotency, risking duplicate side effects for mutating tools like wa_send_message.</violation>
</file>
<file name="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppMemoryImportService.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppMemoryImportService.swift:337">
P1: Deterministic fallback message ID can cause persistent false deduplication when messages lack both an explicit source ID and a timestamp. Any later message with the same chat, sender, and text will map to the same persisted dedupe key and be silently skipped.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
5 issues found across 9 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift:62">
P1: Recursive `detailLabel(for:)` follows `canonicalJid` pointers without cycle detection, which can stack-overflow on cyclic alias mappings from the cache or future `rememberAlias` calls.</violation>
<violation number="2" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift:82">
P2: canonicalJid(for:) performs only a one-hop alias lookup, while detailLabel(for:) recursively follows the same alias chain. displayName, phoneDigits, and resolveRecipient rely on canonicalJid and will therefore operate on an intermediate alias JID while detailLabel reaches the terminal canonical JID, producing inconsistent contact resolution and potentially returning a wrong recipient JID.</violation>
</file>
<file name="desktop/macos/Desktop/Sources/Messaging/WhatsAppMessagingProvider.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/Messaging/WhatsAppMessagingProvider.swift:24">
P1: Thread loading now introduces serial N+1 `wacli` child-process calls per refresh, which can cause significant UI stalls on the @MainActor provider.</violation>
<violation number="2" location="desktop/macos/Desktop/Sources/Messaging/WhatsAppMessagingProvider.swift:161">
P2: Recent-activity verification can regress `lastActivity` by overwriting the provider-supplied timestamp with an older value derived from a limited message sample.</violation>
<violation number="3" location="desktop/macos/Desktop/Sources/Messaging/WhatsAppMessagingProvider.swift:196">
P1: Heuristic `@lid` aliasing plus thread-ID rewriting can mis-associate conversations, risking wrong-thread draft/message routing when a weak heuristic produces a false match.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Replace generic message icons with the bundled WhatsApp brand mark across Messages and Settings, and stop double-dismissing the connect sheet so closing it no longer sends the app to the background. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
1 issue found across 9 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="desktop/macos/run.sh">
<violation number="1" location="desktop/macos/run.sh:592">
P1: Auto-detected signing identity now uses the SHA-1 hash, but the team-ID extraction still expects the display-name format, causing a false profile/team mismatch and an unintended fallback that strips the Sign In with Apple entitlement.</violation>
</file>
<file name="desktop/macos/Desktop/Sources/Messaging/MessagingProviderIcon.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/Messaging/MessagingProviderIcon.swift:9">
P2: WhatsApp icon selection is hard-coded against the magic string `"whatsapp"`, tying the view to the provider's exact ID spelling instead of a typed brand or shared constant. This is brittle and easy to break when adding or renaming providers.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks for continuing to iterate on this. I’m still requesting changes on the current head (ce8e263) rather than approving.
The main blockers remain:
desktop/macos/Desktop/Sources/Resources/wacliis still a bundled ~44 MB Mach-O executable (3667afdad78021daa6825780208b8e2459701a91582479d4ca18e27248ceed2c). An opaque binary from a first-time contributor is not reviewable enough for this repo. Please remove it from the PR and use a maintainer-controlled, reproducible/provenance-backed packaging path for any WhatsApp runtime dependency.- This PR adds a high-risk surface: WhatsApp message/contact access, importing private WhatsApp history into Omi memories, a local webhook, agent-exposed WhatsApp tools, direct sending, and auto-reply/draft flows. That needs explicit product, privacy, and security review before merge.
- The change is still too broad for safe review as one unit (38 files / ~6.6k changed lines) and has very limited tests relative to the risk. Please split this into narrower PRs such as runtime/provenance, UI shell, read-only sync, memory import, and send/auto-reply guardrails.
- Before any send or auto-reply functionality can be considered, it needs focused tests/docs around consent, allowlisting, kill switch behavior, rate limits/quiet hours, audit logs, prompt/tool-call boundaries, and wrong-recipient prevention.
The idea may be valuable for Omi, but this needs a much narrower, source-reviewable shape plus maintainer-owned security/provenance decisions before it can proceed.
|
@Git-on-my-level thanks for the feedback
|
…top-whatsapp Co-authored-by: Cursor <cursoragent@cursor.com>
Redact sensitive WhatsApp diagnostics, preserve valid JIDs/messages during parsing, and add cancellation plus idempotency protection for timed-out WhatsApp tool calls.
Avoid coupling messaging icon rendering to provider ID strings by exposing typed connector brand metadata. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
6 issues found across 10 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="desktop/macos/run.sh">
<violation number="1" location="desktop/macos/run.sh:592">
P1: Auto-detected signing identity now uses the SHA-1 hash, but the team-ID extraction still expects the display-name format, causing a false profile/team mismatch and an unintended fallback that strips the Sign In with Apple entitlement.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Keep provider-facing pi-mono schemas compatible with models that reject root-level composite keywords, while preserving privacy-safe WhatsApp diagnostics. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
7 issues found across 9 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReplyCoordinator.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReplyCoordinator.swift:549">
P1: The redacted JID label uses `String.hashValue`, which is randomized per-process launch and therefore not stable across app restarts. This makes the same WhatsApp chat/user/group appear under different pseudonyms in persistent logs, hindering log correlation and incident investigation. Replace it with a stable keyed digest (e.g., HMAC-SHA256).</violation>
</file>
<file name="desktop/macos/Desktop/Sources/Messaging/WhatsAppMessagingProvider.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/Messaging/WhatsAppMessagingProvider.swift:133">
P1: Persisted canonical alias is preferred over the unique phone-number match when resolving @lid draft threads, without validating that the alias is still correct. A stale or ambiguous cached alias can attach a pending draft to the wrong conversation.</violation>
</file>
<file name="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift:86">
P2: The first cycle-detection branch (`if let cycleStart = visitedIndex[current]`) is unreachable. It is redundant with the second branch and only adds dead code that may confuse maintenance of the alias-resolution logic.</violation>
<violation number="2" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift:340">
P1: Hard-coded WhatsApp JID server allowlist is missing valid server types defined by the underlying `whatsmeow` library, so contacts/JIDs from `msgr`, `interop`, `hosted`, `hosted.lid`, and `bot` servers will be silently rejected.</violation>
</file>
<file name="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift">
<violation number="1" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift:281">
P1: New WhatsApp JID server allowlist may silently drop valid chats whose server namespace is not enumerated</violation>
<violation number="2" location="desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift:365">
P1: Replacing ISO8601DateFormatter with strict ISO8601FormatStyle may fail to parse RFC3339 timestamps with colon-separated timezone offsets (e.g., `+02:00`), causing missing timestamps and duplicate fallback message IDs.</violation>
</file>
<file name="desktop/macos/agent/src/wa-tools-stdio.ts">
<violation number="1" location="desktop/macos/agent/src/wa-tools-stdio.ts:101">
P1: WhatsApp send idempotency is now tied to the JSON-RPC request id, breaking deduplication for MCP retries that use a different id and removing generated idempotency for idless tool calls.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| } else { | ||
| kind = "user" | ||
| } | ||
| return "\(kind)@\(server)#\(String(normalized.hashValue, radix: 16))" |
There was a problem hiding this comment.
P1: The redacted JID label uses String.hashValue, which is randomized per-process launch and therefore not stable across app restarts. This makes the same WhatsApp chat/user/group appear under different pseudonyms in persistent logs, hindering log correlation and incident investigation. Replace it with a stable keyed digest (e.g., HMAC-SHA256).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReplyCoordinator.swift, line 549:
<comment>The redacted JID label uses `String.hashValue`, which is randomized per-process launch and therefore not stable across app restarts. This makes the same WhatsApp chat/user/group appear under different pseudonyms in persistent logs, hindering log correlation and incident investigation. Replace it with a stable keyed digest (e.g., HMAC-SHA256).</comment>
<file context>
@@ -536,6 +534,21 @@ final class WhatsAppReplyCoordinator: ObservableObject {
+ } else {
+ kind = "user"
+ }
+ return "\(kind)@\(server)#\(String(normalized.hashValue, radix: 16))"
+ }
+
</file context>
| if let match = canonicalAliasMatchedThreadId(for: draft, in: threads) | ||
| ?? phoneMatchedThreadId(for: draft, in: threads) |
There was a problem hiding this comment.
P1: Persisted canonical alias is preferred over the unique phone-number match when resolving @lid draft threads, without validating that the alias is still correct. A stale or ambiguous cached alias can attach a pending draft to the wrong conversation.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/Desktop/Sources/Messaging/WhatsAppMessagingProvider.swift, line 133:
<comment>Persisted canonical alias is preferred over the unique phone-number match when resolving @lid draft threads, without validating that the alias is still correct. A stale or ambiguous cached alias can attach a pending draft to the wrong conversation.</comment>
<file context>
@@ -130,7 +130,9 @@ final class WhatsAppMessagingProvider: MessagingProvider {
for draft in drafts where draft.chatJid.contains("@lid") {
- if let match = phoneMatchedThreadId(for: draft, in: threads) {
+ if let match = canonicalAliasMatchedThreadId(for: draft, in: threads)
+ ?? phoneMatchedThreadId(for: draft, in: threads)
+ {
</file context>
| if let match = canonicalAliasMatchedThreadId(for: draft, in: threads) | |
| ?? phoneMatchedThreadId(for: draft, in: threads) | |
| if let match = phoneMatchedThreadId(for: draft, in: threads) | |
| ?? canonicalAliasMatchedThreadId(for: draft, in: threads) | |
| { |
|
|
||
| private func isKnownWhatsAppServer(_ server: String) -> Bool { | ||
| switch server { | ||
| case "s.whatsapp.net", "c.us", "g.us", "lid", "broadcast", "newsletter": |
There was a problem hiding this comment.
P1: Hard-coded WhatsApp JID server allowlist is missing valid server types defined by the underlying whatsmeow library, so contacts/JIDs from msgr, interop, hosted, hosted.lid, and bot servers will be silently rejected.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift, line 340:
<comment>Hard-coded WhatsApp JID server allowlist is missing valid server types defined by the underlying `whatsmeow` library, so contacts/JIDs from `msgr`, `interop`, `hosted`, `hosted.lid`, and `bot` servers will be silently rejected.</comment>
<file context>
@@ -326,7 +331,38 @@ final class WhatsAppContactResolver: ObservableObject {
+
+ private func isKnownWhatsAppServer(_ server: String) -> Bool {
+ switch server {
+ case "s.whatsapp.net", "c.us", "g.us", "lid", "broadcast", "newsletter":
+ return true
+ default:
</file context>
| case "s.whatsapp.net", "c.us", "g.us", "lid", "broadcast", "newsletter": | |
| case "s.whatsapp.net", "c.us", "g.us", "lid", "broadcast", "newsletter", "msgr", "interop", "hosted", "hosted.lid", "bot": |
| return nil | ||
| } | ||
|
|
||
| private static func parseISO8601Date(_ value: String) -> Date? { |
There was a problem hiding this comment.
P1: Replacing ISO8601DateFormatter with strict ISO8601FormatStyle may fail to parse RFC3339 timestamps with colon-separated timezone offsets (e.g., +02:00), causing missing timestamps and duplicate fallback message IDs.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift, line 365:
<comment>Replacing ISO8601DateFormatter with strict ISO8601FormatStyle may fail to parse RFC3339 timestamps with colon-separated timezone offsets (e.g., `+02:00`), causing missing timestamps and duplicate fallback message IDs.</comment>
<file context>
@@ -349,6 +362,13 @@ enum WhatsAppReader {
return nil
}
+ private static func parseISO8601Date(_ value: String) -> Date? {
+ if let date = try? iso8601FractionalDateStyle.parse(value) {
+ return date
</file context>
|
|
||
| private static func isKnownWhatsAppServer(_ server: String) -> Bool { | ||
| switch server { | ||
| case "s.whatsapp.net", "c.us", "g.us", "lid", "broadcast", "newsletter": |
There was a problem hiding this comment.
P1: New WhatsApp JID server allowlist may silently drop valid chats whose server namespace is not enumerated
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/Desktop/Sources/WhatsApp/WhatsAppReader.swift, line 281:
<comment>New WhatsApp JID server allowlist may silently drop valid chats whose server namespace is not enumerated</comment>
<file context>
@@ -269,7 +272,17 @@ enum WhatsAppReader {
+
+ private static func isKnownWhatsAppServer(_ server: String) -> Bool {
+ switch server {
+ case "s.whatsapp.net", "c.us", "g.us", "lid", "broadcast", "newsletter":
+ return true
+ default:
</file context>
| return input; | ||
| } | ||
| const scope = { | ||
| mcpRequestId, |
There was a problem hiding this comment.
P1: WhatsApp send idempotency is now tied to the JSON-RPC request id, breaking deduplication for MCP retries that use a different id and removing generated idempotency for idless tool calls.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/agent/src/wa-tools-stdio.ts, line 101:
<comment>WhatsApp send idempotency is now tied to the JSON-RPC request id, breaking deduplication for MCP retries that use a different id and removing generated idempotency for idless tool calls.</comment>
<file context>
@@ -67,18 +67,38 @@ function stableJSONStringify(value: unknown): string {
+ return input;
+ }
const scope = {
+ mcpRequestId,
requestId: context.requestId,
clientId: context.clientId,
</file context>
| while let canonical = contactsByJid[current]?.canonicalJid?.nilIfEmpty.map(normalizeJid), | ||
| canonical != current | ||
| { | ||
| if let cycleStart = visitedIndex[current] { |
There was a problem hiding this comment.
P2: The first cycle-detection branch (if let cycleStart = visitedIndex[current]) is unreachable. It is redundant with the second branch and only adds dead code that may confuse maintenance of the alias-resolution logic.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/Desktop/Sources/WhatsApp/WhatsAppContactResolver.swift, line 86:
<comment>The first cycle-detection branch (`if let cycleStart = visitedIndex[current]`) is unreachable. It is redundant with the second branch and only adds dead code that may confuse maintenance of the alias-resolution logic.</comment>
<file context>
@@ -78,14 +78,19 @@ final class WhatsAppContactResolver: ObservableObject {
{
- guard !visited.contains(current), !visited.contains(canonical) else {
- return current
+ if let cycleStart = visitedIndex[current] {
+ return stableCycleRepresentative(Array(path[cycleStart...]))
+ }
</file context>
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks for the continued iteration. I’m requesting changes on the current head (de83fa2) rather than approving.
The existing high-level blockers still apply: this is a broad WhatsApp integration touching private message/contact access, memory import, local webhook handling, agent-exposed WhatsApp tools, direct sending, auto-reply, runtime packaging, and an opaque bundled wacli executable. It needs maintainer product/security/privacy/provenance review and a much smaller split before merge.
One specific blocker I want to call out on this head:
WhatsAppReplyCoordinator.draftReplyexposes the fullChatToolExecutor.executetool surface to a model session whose prompt includes untrusted WhatsApp message text and recent thread content. Because that tool surface includeswa_send_message, a malicious incoming WhatsApp message could try to prompt-inject the drafting agent into sending messages during draft generation, before the UI approval/allowlist/auto-reply decision path. Draft generation should be read-only by construction: expose only safe read/context tools there, blockwa_send_messagefrom that session, and route all sends exclusively through explicit user approval or the separately reviewed auto-reply guardrail path.
Additional blockers remain:
desktop/macos/Desktop/Sources/Resources/wacliis still a bundled ~44 MB Mach-O universal executable (3667afdad78021daa6825780208b8e2459701a91582479d4ca18e27248ceed2c). Please remove opaque binaries from the PR and use a maintainer-controlled, reproducible/provenance-backed packaging path.- The PR is still too large for safe review as one unit (43 files / ~6.7k changed lines) with very limited tests relative to the risk. Please split into narrower PRs, e.g. runtime/provenance, UI shell, read-only sync, memory import, and send/auto-reply guardrails.
- Send/auto-reply functionality needs focused tests/docs for consent, prompt/tool-call boundaries, wrong-recipient prevention, allowlisting, kill switch behavior, rate limits/quiet hours, audit logs, and failure/retry semantics.
The product idea may be valuable for Omi, but this needs a much narrower and source-reviewable shape before it can proceed.
Summary
This PR adds WhatsApp support to Omi Desktop so users can connect WhatsApp, view their chats, and let Omi help draft or send replies in the user's own tone.
Main features:
Why
@openclaw/wacliThe goal is to make Omi act more like an AI clone that can understand the user's messaging style and reply on their behalf when allowed. For that, Omi needs access to WhatsApp chats, recent conversation context, and the user's own sent messages for tone matching.
@openclaw/wacligives us a simple local way to do this on desktop: the user just scans a WhatsApp QR code, like linking a normal WhatsApp device. We do not need to build backend WhatsApp infrastructure for this flow, and the WhatsApp session stays local to the desktop app.Design Notes
wacli.Review Notes
This is a privacy-sensitive feature because it touches WhatsApp messages, contacts, memory sync, and reply sending. The main review areas are product/privacy approval, send/auto-reply guardrails, and the packaging/provenance decision for the WhatsApp CLI dependency.