Skip to content

feat(whatsapp): WhatsApp Business Cloud API adapter - #43921

Merged
2 commits merged into
mainfrom
feat/whatsapp-cloud-api-merged
Jun 12, 2026
Merged

feat(whatsapp): WhatsApp Business Cloud API adapter#43921
2 commits merged into
mainfrom
feat/whatsapp-cloud-api-merged

Conversation

@jquesnelle

Copy link
Copy Markdown
Collaborator

Adds an official, production-grade WhatsApp integration via Meta's Business Cloud API, complementing the existing Baileys bridge. No bridge subprocess, no QR codes, no account-ban risk — at the cost of a Meta Business account and a public HTTPS webhook URL.

Why

The Baileys bridge is great for personal accounts but emulates WhatsApp Web, which carries ban risk and isn't viable for business bots. This adapter is the Meta-supported path. The two adapters can run in parallel against different phone numbers.

What's included

Adapter (gateway/platforms/whatsapp_cloud.py)

  • Inbound: text, images (native-vision routing), voice notes (STT), documents (small text inlined, larger cached), reply context
  • Outbound: WhatsApp-flavored markdown, images, videos, documents, opus voice notes via ffmpeg (MP3 fallback)
  • Native interactive buttons for clarify, dangerous-command approval, and slash-command confirmation — matches Telegram/Discord UX, degrades gracefully to plain text
  • Read receipts + typing indicator via Meta's combined endpoint (single API call)

Shared behavior extraction (gateway/platforms/whatsapp_common.py)

  • New WhatsAppBehaviorMixin carrying gating (dm/group policy), mention parsing, markdown conversion, and chunking shared by both adapters — Baileys adapter slimmed by ~280 lines, no behavior change

Setup wizard (hermes whatsapp-cloud)

  • Walks through every credential with paste-time validation (catches the Terminal tool #1 trap: pasting a phone number into the Phone Number ID field), generates a verify token, and ends with copy-paste instructions for the cloudflared / Meta-dashboard pieces that can't be automated

Integration

  • Platform.WHATSAPP_CLOUD wired into gateway adapter creation, authz allowlists (WHATSAPP_CLOUD_ALLOWED_USERS / _ALLOW_ALL_USERS), and cron delivery (WHATSAPP_CLOUD_HOME_CHANNEL)
  • STT surfaced in Nous subscription feature detection (voice notes need transcription) — rides the existing managed openai-audio gateway, sharing the TTS entitlement category
  • Docs: full setup guide (messaging/whatsapp-cloud.md), cross-links from the Baileys page, sidebar entry

Merge with main

Branch was rebased-by-merge against current main (2,100+ commits). Notable integration points:

  • Main's new mixin-adjacent additions (supports_code_blocks, enforces_own_access_policy, text-debounce batching) hoisted into / kept alongside WhatsAppBehaviorMixin so both adapters inherit them
  • STT feature detection migrated to main's new per-category entitlement model (_entitled_for, MANAGED_FEATURE_COVERAGE_CATEGORY)
  • STT tests migrated from the removed get_nous_auth_status mock API to get_nous_portal_account_info

Testing

  • tests/gateway/test_whatsapp_cloud.py (2,250 lines) + tests/hermes_cli/test_whatsapp_cloud_setup.py (406 lines): 132/132 passing
  • test_nous_subscription.py + test_scheduler.py: 169/169 passing
  • Full tests/gateway/ suite: failure set identical to main baseline (no regressions; +94 new passing tests)
  • CLI smoke: hermes whatsapp-cloud --help, parser registration, adapter imports verified

Add an official, production-grade WhatsApp integration via Meta's
Business Cloud API as a complement to the existing Baileys bridge.
No bridge subprocess, no QR codes, no account-ban risk — at the cost
of a Meta Business account and a public HTTPS webhook URL.

Setup is fully wizard-driven: 'hermes whatsapp-cloud' walks through
every credential with paste-time validation (catches the #1 trap of
pasting a phone number into the Phone Number ID field), generates a
verify token, and ends with copy-paste instructions for the
cloudflared / Meta-dashboard / Business Manager pieces that can't be
automated. The wizard also points users at Meta's Business Manager
for setting the bot's display name and profile picture.

Feature set:

- Inbound: text, images (with native-vision routing), voice notes
  (STT), documents (small text inlined, larger cached), reply context.
- Outbound: text with WhatsApp-flavored markdown conversion, images,
  videos, documents, opus voice notes via ffmpeg with MP3 fallback.
- Native interactive buttons for clarify, dangerous-command approval,
  and slash-command confirmation flows — matches the Telegram /
  Discord UX, graceful degrades to plain text.
- Read receipts (blue double-checkmarks) and typing indicator,
  using Meta's combined endpoint so they fire in a single API call.
- Webhook security: X-Hub-Signature-256 HMAC verification (raw body,
  constant-time), wamid deduplication, group-shaped-message refusal
  (groups deferred to v2 — Baileys still covers them).
- Full integration with the gateway's session, cron, display-tier,
  prompt-hint, and auth-allowlist systems. Cloud and Baileys can run
  side-by-side against different phone numbers.

Also wires STT (speech-to-text) through Nous's managed audio gateway
for Nous subscribers — previously the default stt.provider=local
required a separate faster-whisper install. New subscribers now get
voice-note transcription out of the box.

Docs: 418-line user guide at website/docs/user-guide/messaging/
whatsapp-cloud.md, sidebar entry, environment-variables reference,
ADDING_A_PLATFORM.md updated with the optional interactive-UX
contract for future adapter authors.

Tests: 100 dedicated tests for the adapter, 32 for the setup wizard,
20 for the Nous subscription STT wiring, plus regression coverage
across display_config, prompt_builder, and the cron scheduler.

Known limitations (deferred until clear demand signal):
- Group chats — use the Baileys bridge if you need them.
- Message templates for 24-hour-window outside-conversation sends —
  reactive chat is unaffected; cron / delegate_task with gaps > 24h
  will fail with a clear error. The agent's system prompt warns the
  model about this so it knows to mention it when scheduling delayed
  messages.
@jquesnelle jquesnelle changed the title feat(whatsap): WhatsApp Business Cloud API adapter feat(whatsapp): WhatsApp Business Cloud API adapter Jun 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: feat/whatsapp-cloud-api-merged vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 10725 on HEAD, 10654 on base (🆕 +71)

🆕 New issues (65):

Rule Count
invalid-argument-type 23
unresolved-attribute 23
unsupported-operator 7
invalid-method-override 5
unresolved-import 4
invalid-return-type 2
invalid-assignment 1
First entries
gateway/run.py:13684: [invalid-argument-type] invalid-argument-type: Argument to function `resolve_display_setting` is incorrect: Expected `str`, found `Literal["cli", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/slash_commands.py:633: [unresolved-attribute] unresolved-attribute: Attribute `lower` is not defined on `set[Unknown]` in union `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/platforms/whatsapp_common.py:103: [unresolved-attribute] unresolved-attribute: Object of type `Self@_whatsapp_free_response_chats` has no attribute `config`
tests/hermes_cli/test_whatsapp_cloud_setup.py:87: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["OpenAI"]` and `str | None`
gateway/slash_commands.py:1692: [invalid-argument-type] invalid-argument-type: Argument to function `_home_thread_env_var` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/slash_commands.py:3425: [invalid-argument-type] invalid-argument-type: Argument to bound method `PlatformRegistry.get` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/platforms/whatsapp_common.py:90: [unresolved-attribute] unresolved-attribute: Object of type `Self@_whatsapp_require_mention` has no attribute `config`
gateway/platforms/whatsapp_cloud.py:1076: [invalid-method-override] invalid-method-override: Invalid override of method `send_document`: Definition is incompatible with `BasePlatformAdapter.send_document`
tests/hermes_cli/test_whatsapp_cloud_setup.py:49: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["Phone number ID"]` and `str | None`
gateway/authz_mixin.py:198: [invalid-argument-type] invalid-argument-type: Argument to bound method `PlatformRegistry.get` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/run.py:13830: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `Literal["cli", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/run.py:6360: [invalid-argument-type] invalid-argument-type: Argument to bound method `PairingStore._record_rate_limit` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
tests/hermes_cli/test_whatsapp_cloud_setup.py:102: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["EAA"]` and `str | None`
gateway/platforms/whatsapp_common.py:252: [unresolved-attribute] unresolved-attribute: Object of type `Self@_message_matches_mention_patterns` has no attribute `_mention_patterns`
gateway/platforms/whatsapp_common.py:164: [unresolved-attribute] unresolved-attribute: Object of type `Self@_is_group_allowed` has no attribute `_group_allow_from`
tests/hermes_cli/test_whatsapp_cloud_setup.py:22: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
gateway/run.py:11363: [invalid-argument-type] invalid-argument-type: Argument to function `set_session_vars` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/channel_directory.py:87: [invalid-assignment] invalid-assignment: Invalid subscript assignment with key of type `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]` and value of type `list[dict[str, str]]` on object of type `dict[str, list[dict[str, str]]]`
gateway/session.py:269: [unresolved-attribute] unresolved-attribute: Attribute `title` is not defined on `set[Unknown]` in union `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/platforms/whatsapp_cloud.py:317: [unresolved-attribute] unresolved-attribute: Attribute `AsyncClient` is not defined on `None` in union `Unknown | None`
tests/hermes_cli/test_whatsapp_cloud_setup.py:122: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["32"]` and `str | None`
gateway/channel_directory.py:87: [invalid-argument-type] invalid-argument-type: Argument to function `_build_from_sessions` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/run.py:6339: [invalid-argument-type] invalid-argument-type: Argument to bound method `PairingStore.generate_code` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/run.py:6030: [invalid-argument-type] invalid-argument-type: Argument to bound method `PlatformRegistry.create_adapter` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | set[Unknown]`
gateway/run.py:7332: [invalid-argument-type] invalid-argument-type: Argument to function `get_disabled_skill_names` is incorrect: Expected `str | None`, found `Literal["local", "telegram", "discord", "whatsapp", "whatsapp_cloud", ... omitted 18 literals] | (set[Unknown] & ~AlwaysFalsy)`
... and 40 more

✅ Fixed issues (29):

Rule Count
invalid-argument-type 22
unresolved-attribute 4
invalid-return-type 2
invalid-assignment 1
First entries
tests/gateway/test_whatsapp_group_gating.py:372: [invalid-argument-type] invalid-argument-type: Argument to function `WhatsAppAdapter._is_broadcast_chat` is incorrect: Expected `str`, found `None`
gateway/session.py:257: [invalid-argument-type] invalid-argument-type: Argument to bound method `PlatformRegistry.get` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/session.py:269: [unresolved-attribute] unresolved-attribute: Attribute `title` is not defined on `set[Unknown]` in union `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/run.py:11349: [invalid-argument-type] invalid-argument-type: Argument to function `set_session_vars` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/platforms/base.py:2179: [unresolved-attribute] unresolved-attribute: Attribute `title` is not defined on `set[Unknown]` in union `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/run.py:6325: [invalid-argument-type] invalid-argument-type: Argument to bound method `PairingStore.generate_code` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/slash_commands.py:1692: [invalid-argument-type] invalid-argument-type: Argument to function `_home_thread_env_var` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/run.py:11681: [invalid-argument-type] invalid-argument-type: Argument to bound method `PlatformRegistry.is_registered` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/run.py:11322: [invalid-argument-type] invalid-argument-type: Argument to bound method `set.add` is incorrect: Expected `tuple[str, str, str | None]`, found `tuple[Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown], str, str | None]`
hermes_cli/web_server.py:3564: [invalid-argument-type] invalid-argument-type: Argument to bound method `set.add` is incorrect: Expected `str`, found `Literal["telegram", "discord", "whatsapp", "slack", "signal", ... omitted 16 literals] | set[Unknown]`
gateway/run.py:7318: [invalid-argument-type] invalid-argument-type: Argument to function `get_disabled_skill_names` is incorrect: Expected `str | None`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | (set[Unknown] & ~AlwaysFalsy)`
gateway/delivery.py:172: [invalid-return-type] invalid-return-type: Return type does not match returned value: expected `str`, found `Literal["telegram", "discord", "whatsapp", "slack", "signal", ... omitted 16 literals] | set[Unknown]`
gateway/run.py:5590: [invalid-argument-type] invalid-argument-type: Argument to bound method `GatewayRunner._update_platform_runtime_status` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/channel_directory.py:87: [invalid-assignment] invalid-assignment: Invalid subscript assignment with key of type `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]` and value of type `list[dict[str, str]]` on object of type `dict[str, list[dict[str, str]]]`
gateway/run.py:13816: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `Literal["cli", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
hermes_cli/web_server.py:3565: [invalid-argument-type] invalid-argument-type: Argument to function `_build_catalog_entry` is incorrect: Expected `str`, found `Literal["telegram", "discord", "whatsapp", "slack", "signal", ... omitted 16 literals] | set[Unknown]`
gateway/slash_commands.py:3425: [invalid-argument-type] invalid-argument-type: Argument to bound method `PlatformRegistry.get` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
hermes_cli/commands.py:1656: [unresolved-attribute] unresolved-attribute: Attribute `startswith` is not defined on `set[Unknown]` in union `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
tests/gateway/test_title_command.py:174: [invalid-argument-type] invalid-argument-type: Argument to bound method `SessionDB.create_session` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/authz_mixin.py:196: [invalid-argument-type] invalid-argument-type: Argument to bound method `PlatformRegistry.get` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/slash_commands.py:1691: [invalid-argument-type] invalid-argument-type: Argument to function `_home_target_env_var` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/channel_directory.py:87: [invalid-argument-type] invalid-argument-type: Argument to function `_build_from_sessions` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/run.py:1579: [invalid-return-type] invalid-return-type: Return type does not match returned value: expected `str`, found `Literal["cli", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/run.py:6028: [invalid-argument-type] invalid-argument-type: Argument to bound method `PlatformRegistry.create_adapter` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
gateway/run.py:6322: [invalid-argument-type] invalid-argument-type: Argument to bound method `PairingStore._is_rate_limited` is incorrect: Expected `str`, found `Literal["local", "telegram", "discord", "whatsapp", "slack", ... omitted 17 literals] | set[Unknown]`
... and 4 more

Unchanged: 5533 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@alt-glitch alt-glitch added type/feature New feature or request P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/whatsapp WhatsApp Business adapter labels Jun 11, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Comment (high-surface-area, full review deferred)

Feature: WhatsApp Business Cloud API adapter

This is a very large PR (6,383 additions / 292 deletions, 7,258 diff lines) — a major new platform adapter. In cron batch mode I cannot do a thorough deep review within available resources.

Surface area concerns (require human review):

  • WhatsApp Business Cloud API authentication and token handling
  • Message format translation between Baileys (legacy) and Business Cloud API
  • Group message handling and participant ID mapping
  • Webhook security and signature verification
  • Error handling and reconnection logic

This is a significant architectural addition. Please treat this as an informational comment — the PR warrants a focused human review and potentially a dedicated testing session before merge.


Reviewed by Hermes Agent (batch mode — high-surface-area, full review deferred)

@teknium1 teknium1 closed this pull request by merging all changes into main in db7714d Jun 12, 2026
@teknium1
teknium1 deleted the feat/whatsapp-cloud-api-merged branch June 12, 2026 05:48
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #44331 — your commits were merged forward onto current main with your authorship preserved in git history.

On top of your work we added a small follow-up commit addressing review findings: STT managed-default flip now gated on openai-audio entitlement (and skipped when a local faster-whisper/custom backend works), WHATSAPP_CLOUD_* policy env overrides + wa_id allowlist normalization so both adapters can run in parallel with independent policies, per-message webhook try/except (avoids silent message loss on Meta batch retries), media id validation, opus temp-file cleanup, bounded interactive-state caches, and getpass for wizard secrets.

Excellent adapter — the webhook security (raw-body HMAC, constant-time compares, refuse-when-unconfigured) and the mixin extraction were both exactly right. Thanks!

Setsuna-Yukirin pushed a commit to Setsuna-Yukirin/hermes-agent that referenced this pull request Jun 12, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
AIalliAI pushed a commit to AIalliAI/Hermes that referenced this pull request Jun 14, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
AIalliAI pushed a commit to AIalliAI/Hermes that referenced this pull request Jun 14, 2026
…-6b48295e

feat(whatsapp): WhatsApp Business Cloud API adapter (salvage NousResearch#43921)
T02200059 pushed a commit to T02200059/hermes-agent that referenced this pull request Jun 18, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
T02200059 pushed a commit to T02200059/hermes-agent that referenced this pull request Jun 18, 2026
…-6b48295e

feat(whatsapp): WhatsApp Business Cloud API adapter (salvage NousResearch#43921)
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…-6b48295e

feat(whatsapp): WhatsApp Business Cloud API adapter (salvage NousResearch#43921)
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
…-6b48295e

feat(whatsapp): WhatsApp Business Cloud API adapter (salvage NousResearch#43921)
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
…-6b48295e

feat(whatsapp): WhatsApp Business Cloud API adapter (salvage NousResearch#43921)
donbowman pushed a commit to donbowman/hermes-agent that referenced this pull request Jul 13, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
…-6b48295e

feat(whatsapp): WhatsApp Business Cloud API adapter (salvage NousResearch#43921)
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
- nous_subscription: gate the STT managed-default flip on openai-audio
  entitlement and skip when a local backend (faster-whisper or custom
  command) works; new _local_stt_backend_available() helper + tests
- whatsapp_cloud: WHATSAPP_CLOUD_{DM_POLICY,ALLOW_FROM,GROUP_POLICY,
  GROUP_ALLOW_FROM} env overrides so both adapters can run in parallel;
  normalize allowlist entries (JID/punctuation) to bare wa_id
- whatsapp_cloud: wrap per-message event build in try/except (dedup-marked
  wamids would be silently dropped on Meta's batch retry otherwise)
- whatsapp_cloud: validate media_id before URL/filename interpolation,
  delete transient .ogg after voice upload, FIFO-cap interactive-button
  state dicts and per-chat wamid cache
- whatsapp_common: '# **Title**' headers no longer double-wrap asterisks
- setup wizard: read access token / app secret via getpass on TTYs
- docs: new WHATSAPP_CLOUD_* gating env vars
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
…-6b48295e

feat(whatsapp): WhatsApp Business Cloud API adapter (salvage NousResearch#43921)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/whatsapp WhatsApp Business adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants