feat(channels): add WhatsApp messaging channel with QR pairing#3392
Conversation
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds WhatsApp as an in‑sandbox QR‑paired messaging channel and integrates it across agent manifests, onboarding and sandbox flows, a WhatsApp network‑policy preset and tier inclusion, Hermes/OpenClaw config and guards, documentation, tests, and CI. ChangesWhatsApp Channel Support
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
E2E Advisor RecommendationRequired E2E: Dispatch hint: Auto-dispatched E2E: Full advisor summaryE2E Recommendation AdvisorBase: Required E2E
Optional E2E
New E2E recommendations
Dispatch hint
|
|
🚀 Docs preview ready! |
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
docs/manage-sandboxes/messaging-channels.md (2)
27-28:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate opening sentence to include WhatsApp.
The opening paragraph lists "Telegram, Discord, and Slack" but omits WhatsApp. Update for consistency with the added WhatsApp support throughout this page.
📝 Suggested update
-Telegram, Discord, and Slack reach your agent through OpenShell-managed processes and gateway constructs. +Telegram, Discord, Slack, and WhatsApp reach your agent through OpenShell-managed processes and gateway constructs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/manage-sandboxes/messaging-channels.md` around lines 27 - 28, The opening sentence "Telegram, Discord, and Slack reach your agent through OpenShell-managed processes and gateway constructs." omits WhatsApp; update that sentence to include WhatsApp (e.g., "Telegram, Discord, Slack, and WhatsApp reach your agent...") so the paragraph and the rest of the page consistently reflect added WhatsApp support.
6-7:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate description to include WhatsApp.
The frontmatter descriptions mention "Telegram, Discord, or Slack" but omit WhatsApp, which is now a supported channel. Update both
description.mainanddescription.agentto include WhatsApp for consistency with the body content.📝 Suggested update
description: - main: "Connect Telegram, Discord, or Slack to your sandboxed OpenClaw agent using OpenShell-managed channel messaging." - agent: "Explains how Telegram, Discord, and Slack reach the sandboxed OpenClaw agent through OpenShell-managed processes and NemoClaw channel commands. Use when setting up messaging channels, chat interfaces, or integrations without relying on nemoclaw tunnel start for bridges." + main: "Connect Telegram, Discord, Slack, or WhatsApp to your sandboxed OpenClaw agent using OpenShell-managed channel messaging." + agent: "Explains how Telegram, Discord, Slack, and WhatsApp reach the sandboxed OpenClaw agent through OpenShell-managed processes and NemoClaw channel commands. Use when setting up messaging channels, chat interfaces, or integrations without relying on nemoclaw tunnel start for bridges."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/manage-sandboxes/messaging-channels.md` around lines 6 - 7, Update the frontmatter descriptions to include WhatsApp: modify the values for description.main and description.agent so they list "Telegram, Discord, Slack, or WhatsApp" (or "Telegram, Discord, Slack and WhatsApp") and ensure the second string also mentions WhatsApp alongside Telegram/Discord/Slack to match the body content and supported channels.
🧹 Nitpick comments (2)
docs/manage-sandboxes/messaging-channels.md (2)
77-78: 💤 Low valueConsider simplifying with a period instead of an em dash.
Line 77 uses an em dash to connect two independent clauses. The style guide recommends flagging em dashes used instead of commas or periods.
📝 Suggested simplification
-WhatsApp uses QR pairing instead of a host-side token, so the wizard does not prompt — it prints pairing instructions and you complete the pairing inside the sandbox after rebuild. +WhatsApp uses QR pairing instead of a host-side token, so the wizard does not prompt. +It prints pairing instructions, and you complete the pairing inside the sandbox after rebuild.As per coding guidelines: "Excessive em dashes. One per paragraph is fine; multiple per paragraph or em dashes used instead of commas/periods should be flagged."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/manage-sandboxes/messaging-channels.md` around lines 77 - 78, The sentence "WhatsApp uses QR pairing instead of a host-side token, so the wizard does not prompt — it prints pairing instructions and you complete the pairing inside the sandbox after rebuild." uses an em dash to join two independent clauses; replace the em dash with a period and capitalize the following clause (i.e., split into "...does not prompt. It prints pairing instructions...") to follow the style guide; also check the nearby sentence fragment "NemoClaw also selects the matching network policy preset during policy setup so the channel can reach its provider API." for similar em-dash or comma usage and adjust accordingly if present.
70-71: 💤 Low valueSplit into separate lines for diff readability.
Lines 70-71 contain two sentences separated by a semicolon. The style guide requires one sentence per line in source to make diffs readable.
📝 Suggested reformat
-Because session credentials are generated and stored inside the sandbox image, NemoClaw cannot detect cross-sandbox WhatsApp conflicts the way it does for token-based channels; pair only one sandbox per WhatsApp account at a time. +Because session credentials are generated and stored inside the sandbox image, NemoClaw cannot detect cross-sandbox WhatsApp conflicts the way it does for token-based channels. +Pair only one sandbox per WhatsApp account at a time.As per coding guidelines: "One sentence per line in source (makes diffs readable). Flag paragraphs where multiple sentences appear on the same line."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/manage-sandboxes/messaging-channels.md` around lines 70 - 71, The paragraph contains two sentences on the same source line; split them into separate lines so each sentence stands alone for diff readability — replace the single line "Because session credentials are generated and stored inside the sandbox image, NemoClaw cannot detect cross-sandbox WhatsApp conflicts the way it does for token-based channels; pair only one sandbox per WhatsApp account at a time." with two lines: one containing "Because session credentials are generated and stored inside the sandbox image, NemoClaw cannot detect cross-sandbox WhatsApp conflicts the way it does for token-based channels." and the next containing "Pair only one sandbox per WhatsApp account at a time."
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/actions/sandbox/policy-channel.ts`:
- Around line 420-429: The QR-paired channel is being persisted using the raw
user input (channelArg), which can be mixed-case and lead to non-canonical
registry entries; normalize the channel name to a canonical form (e.g.,
lower-case) before calling applyChannelAddToGatewayAndRegistry and before using
it in promptAndRebuild and log messages. Locate the block using
channelUsesQrPairing(channel) and replace uses of channelArg with a normalized
variable (e.g., normalizedChannel = channelArg.toLowerCase()) when calling
applyChannelAddToGatewayAndRegistry, console logs that reference the channel
name, and promptAndRebuild to ensure registry entries and subsequent
remove/start/stop logic use the canonical name.
In `@src/lib/onboard.ts`:
- Around line 9087-9092: The branch that logs QR-selected channels but continues
when channelHasStaticToken(ch) is false leaves tokenless (QR) channels visually
"enabled" yet not included in the runtime activation set; update the selection
logic so that when channelHasStaticToken(ch) is false you also mark the channel
as active for the sandbox (e.g., push ch into activeMessagingChannels or set the
same enabled flag used by sandbox config generation), ensuring the QR-selected
channel is preserved into the sandbox/Docker args rather than only being logged;
reference the channelHasStaticToken(ch) check, the ch variable, and the
activeMessagingChannels/sandbox activation path when making the change.
---
Outside diff comments:
In `@docs/manage-sandboxes/messaging-channels.md`:
- Around line 27-28: The opening sentence "Telegram, Discord, and Slack reach
your agent through OpenShell-managed processes and gateway constructs." omits
WhatsApp; update that sentence to include WhatsApp (e.g., "Telegram, Discord,
Slack, and WhatsApp reach your agent...") so the paragraph and the rest of the
page consistently reflect added WhatsApp support.
- Around line 6-7: Update the frontmatter descriptions to include WhatsApp:
modify the values for description.main and description.agent so they list
"Telegram, Discord, Slack, or WhatsApp" (or "Telegram, Discord, Slack and
WhatsApp") and ensure the second string also mentions WhatsApp alongside
Telegram/Discord/Slack to match the body content and supported channels.
---
Nitpick comments:
In `@docs/manage-sandboxes/messaging-channels.md`:
- Around line 77-78: The sentence "WhatsApp uses QR pairing instead of a
host-side token, so the wizard does not prompt — it prints pairing instructions
and you complete the pairing inside the sandbox after rebuild." uses an em dash
to join two independent clauses; replace the em dash with a period and
capitalize the following clause (i.e., split into "...does not prompt. It prints
pairing instructions...") to follow the style guide; also check the nearby
sentence fragment "NemoClaw also selects the matching network policy preset
during policy setup so the channel can reach its provider API." for similar
em-dash or comma usage and adjust accordingly if present.
- Around line 70-71: The paragraph contains two sentences on the same source
line; split them into separate lines so each sentence stands alone for diff
readability — replace the single line "Because session credentials are generated
and stored inside the sandbox image, NemoClaw cannot detect cross-sandbox
WhatsApp conflicts the way it does for token-based channels; pair only one
sandbox per WhatsApp account at a time." with two lines: one containing "Because
session credentials are generated and stored inside the sandbox image, NemoClaw
cannot detect cross-sandbox WhatsApp conflicts the way it does for token-based
channels." and the next containing "Pair only one sandbox per WhatsApp account
at a time."
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 01c5ca9b-70e1-4c20-a107-4393db8fdcda
📒 Files selected for processing (14)
agents/openclaw/manifest.yamldocs/manage-sandboxes/messaging-channels.mddocs/reference/network-policies.mdnemoclaw-blueprint/policies/presets/whatsapp.yamlnemoclaw-blueprint/policies/tiers.yamlsrc/lib/actions/sandbox/policy-channel.tssrc/lib/agent/defs.test.tssrc/lib/onboard.tssrc/lib/policy/index.tssrc/lib/sandbox/channels.test.tssrc/lib/sandbox/channels.tstest/policies.test.tstest/policy-tiers-onboard.test.tstest/policy-tiers.test.ts
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
test/onboard.test.ts (1)
4762-4767: ⚡ Quick winPrefer a behavioral QR-pairing regression test over this mega-regex.
This assertion now hard-codes a long slice of
onboard.tsimplementation detail, so harmless refactors will churn the test, but it still won't prove the new tokenless resume path works. A small spawned resume/create-sandbox test that recordsmessagingChannels: ["whatsapp"]with no messaging env vars would catch the QR-paired regression this PR is about more reliably.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/onboard.test.ts` around lines 4762 - 4767, Replace the brittle mega-regex assertion in onboard.test.ts with a focused behavioral regression test that spawns a resume/create-sandbox flow and verifies QR-pairing/tokenless resume behavior: instead of matching implementation text around startRecordedStep, getRecordedMessagingChannelsForResume, setupMessagingChannels, readMessagingChannelConfigFromEnv, onboardSession.updateSession, and createSandbox, write a test that records a session with messagingChannels: ["whatsapp"] while ensuring no messaging env vars are set, then resume and assert the resumed session uses the recorded messagingChannels and proceeds to call createSandbox (or equivalent completion) without requiring a token; this proves the tokenless resume path works and avoids fragile implementation-dependent regex matching.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/onboard.ts`:
- Around line 6024-6028: The current logic only builds disabledEnvKeys from
getChannelTokenKeys and misses QR-paired channels (e.g., WhatsApp) because
getChannelTokenKeys returns empty; as a result
qrSelectedChannels/activeMessagingChannels can re-enable channels explicitly
stopped. Update the selection logic that computes
activeMessagingChannels/qrSelectedChannels to also exclude any channel whose
name appears in disabledChannels (use registry.getDisabledChannels(sandboxName)
/ disabledChannels) in addition to checking disabledEnvKeys; specifically adjust
the code paths that use MESSAGING_CHANNELS.filter(...) and the
qrSelectedChannels construction so they check disabledChannels.includes(c.name)
before adding the channel.
---
Nitpick comments:
In `@test/onboard.test.ts`:
- Around line 4762-4767: Replace the brittle mega-regex assertion in
onboard.test.ts with a focused behavioral regression test that spawns a
resume/create-sandbox flow and verifies QR-pairing/tokenless resume behavior:
instead of matching implementation text around startRecordedStep,
getRecordedMessagingChannelsForResume, setupMessagingChannels,
readMessagingChannelConfigFromEnv, onboardSession.updateSession, and
createSandbox, write a test that records a session with messagingChannels:
["whatsapp"] while ensuring no messaging env vars are set, then resume and
assert the resumed session uses the recorded messagingChannels and proceeds to
call createSandbox (or equivalent completion) without requiring a token; this
proves the tokenless resume path works and avoids fragile
implementation-dependent regex matching.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 4bcdcced-1503-4cd3-8f70-b427f3a04c4f
📒 Files selected for processing (7)
docs/manage-sandboxes/messaging-channels.mdsrc/lib/actions/sandbox/policy-channel.tssrc/lib/onboard.tssrc/lib/policy/index.tssrc/lib/sandbox/channels.test.tstest/onboard.test.tstest/policies.test.ts
✅ Files skipped from review due to trivial changes (1)
- docs/manage-sandboxes/messaging-channels.md
🚧 Files skipped from review as they are similar to previous changes (2)
- src/lib/policy/index.ts
- src/lib/sandbox/channels.test.ts
Selective E2E Results — ✅ All requested jobs passedRun: 25747647716
|
|
Targeted E2E validation requested by the E2E Advisor has passed. Run: https://github.com/NVIDIA/NemoClaw/actions/runs/25747647716 Passed targeted jobs: PR review can proceed with that E2E signal in mind. |
…preset Stop re-enabling QR-only channels (WhatsApp) that the operator paused with `channels stop`, and recognise WhatsApp as a valid explicit policy preset selection so onboard suggests its egress rules. Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/onboard.ts (1)
6637-6649:⚠️ Potential issue | 🟠 Major | ⚡ Quick winQR-paired channel allowlists are dropped at build time.
This serialization still keys
messagingAllowedIdsoffenabledTokenEnvKeys, so anyuserIdEnvKeycollected for a tokenless QR channel never makes it into the sandbox config. After a rebuild, the channel comes back without the requested sender restrictions.Suggested fix
- const enabledTokenEnvKeys = new Set(messagingTokenDefs.map(({ envKey }) => envKey)); + const enabledTokenEnvKeys = new Set(messagingTokenDefs.map(({ envKey }) => envKey)); + const enabledChannelNames = new Set(activeMessagingChannels); for (const ch of MESSAGING_CHANNELS) { if ( - ch.envKey && - enabledTokenEnvKeys.has(ch.envKey) && + enabledChannelNames.has(ch.name) && ch.userIdEnvKey && process.env[ch.userIdEnvKey] ) { const ids = String(process.env[ch.userIdEnvKey]) .split(",")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/onboard.ts` around lines 6637 - 6649, The current loop only writes messagingAllowedIds when a channel's envKey is present in messagingTokenDefs (enabledTokenEnvKeys), which drops QR/tokenless channels that only have a userIdEnvKey; change the condition so channels with a configured userIdEnvKey are included regardless of whether ch.envKey is enabled: check first that ch.userIdEnvKey && process.env[ch.userIdEnvKey], then inside allow the channel if either ch.envKey is falsy (tokenless) OR enabledTokenEnvKeys.has(ch.envKey); populate messagingAllowedIds[ch.name] from that env var as before. Reference: messagingAllowedIds, messagingTokenDefs, MESSAGING_CHANNELS, ch.envKey, ch.userIdEnvKey, enabledTokenEnvKeys.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/onboard.ts`:
- Around line 9044-9059: The messaging-channel picker currently seeds enabled
state only from host tokens so QR-paired channels drop on rebuilds; update
setupMessagingChannels to accept an optional existingChannels (or
messagingChannels) parameter and use it when computing each channel's initial
enabled state: if getMessagingToken(envKey) is falsy but existingChannels
includes the channel name, treat it as enabled. Ensure availableChannels /
MESSAGING_CHANNELS filtering remains the same and update rebuild call sites to
pass the sandbox/session messagingChannels into setupMessagingChannels so
QR-only channels stay preselected.
---
Outside diff comments:
In `@src/lib/onboard.ts`:
- Around line 6637-6649: The current loop only writes messagingAllowedIds when a
channel's envKey is present in messagingTokenDefs (enabledTokenEnvKeys), which
drops QR/tokenless channels that only have a userIdEnvKey; change the condition
so channels with a configured userIdEnvKey are included regardless of whether
ch.envKey is enabled: check first that ch.userIdEnvKey &&
process.env[ch.userIdEnvKey], then inside allow the channel if either ch.envKey
is falsy (tokenless) OR enabledTokenEnvKeys.has(ch.envKey); populate
messagingAllowedIds[ch.name] from that env var as before. Reference:
messagingAllowedIds, messagingTokenDefs, MESSAGING_CHANNELS, ch.envKey,
ch.userIdEnvKey, enabledTokenEnvKeys.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 1cdeda13-4596-45d2-a993-30cf04e4aa73
📒 Files selected for processing (8)
docs/manage-sandboxes/messaging-channels.mdsrc/lib/actions/sandbox/policy-channel.tssrc/lib/onboard.tssrc/lib/policy/index.tssrc/lib/sandbox/channels.test.tstest/onboard.test.tstest/policies.test.tstest/policy-tiers-onboard.test.ts
✅ Files skipped from review due to trivial changes (2)
- test/policy-tiers-onboard.test.ts
- docs/manage-sandboxes/messaging-channels.md
🚧 Files skipped from review as they are similar to previous changes (2)
- src/lib/policy/index.ts
- src/lib/sandbox/channels.test.ts
Move getSuggestedPolicyPresets and the messaging-state helpers under src/lib/onboard/ to keep onboard.ts net-neutral. Seed setupMessagingChannels from the sandbox's recorded messaging channels so QR-only channels (WhatsApp) survive a non-interactive rebuild that has no host token to detect them with. Key messagingAllowedIds off activeMessagingChannels so any future QR channel with a userIdEnvKey can still serialise its allow-list, and skip the gateway requirement in channels add/remove when the channel has no bridge provider to touch. Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
test/onboard.test.ts (1)
6234-6238: ⚡ Quick winHarden these WhatsApp tests against inherited messaging env leakage.
Both helper scripts clear only a few token vars. To keep these tests fully hermetic, clear full messaging prefixes (
DISCORD_*,TELEGRAM_*,SLACK_*) beforecreateSandbox().♻️ Suggested tweak (apply in both helper scripts)
- delete process.env.DISCORD_BOT_TOKEN; - delete process.env.SLACK_BOT_TOKEN; - delete process.env.SLACK_APP_TOKEN; - delete process.env.TELEGRAM_BOT_TOKEN; + for (const key of Object.keys(process.env)) { + if ( + key.startsWith("DISCORD_") || + key.startsWith("TELEGRAM_") || + key.startsWith("SLACK_") + ) { + delete process.env[key]; + } + }Based on learnings: “delete/remove unrelated messaging env vars such as
DISCORD_*andTELEGRAM_*… to prevent inherited environment from activating additional channels.”Also applies to: 6403-6406
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/onboard.test.ts` around lines 6234 - 6238, The WhatsApp tests are not fully hermetic because helper scripts only delete a few specific tokens; update the setup that runs before createSandbox() to remove all environment variables with messaging prefixes so no inherited messaging tokens activate additional channels — e.g., iterate/remove any process.env keys starting with "DISCORD_", "TELEGRAM_", and "SLACK_" (in the same helper where process.env.OPENSHELL_GATEWAY = "nemoclaw" is set) so createSandbox() runs with those prefixes cleared.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/actions/sandbox/policy-channel.ts`:
- Around line 507-508: The success message always says "Removed {canonical}
bridge" but QR-paired channels (e.g., WhatsApp) don't create bridge providers;
update the code around the console.log in policy-channel.ts so you conditionally
choose the wording based on whether a bridge provider was actually created for
the channel: inspect the channel record or metadata used in the removal flow
(e.g., a provider type or a boolean like bridgeProvider/createdBridge) and if a
bridge exists print the current message, otherwise print a generic "Removed
{canonical} channel" (keep the await promptAndRebuild(sandboxName, `remove
'${canonical}'`) call unchanged).
---
Nitpick comments:
In `@test/onboard.test.ts`:
- Around line 6234-6238: The WhatsApp tests are not fully hermetic because
helper scripts only delete a few specific tokens; update the setup that runs
before createSandbox() to remove all environment variables with messaging
prefixes so no inherited messaging tokens activate additional channels — e.g.,
iterate/remove any process.env keys starting with "DISCORD_", "TELEGRAM_", and
"SLACK_" (in the same helper where process.env.OPENSHELL_GATEWAY = "nemoclaw" is
set) so createSandbox() runs with those prefixes cleared.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 4677ca16-a903-4823-92be-454d8aa0005a
📒 Files selected for processing (10)
docs/manage-sandboxes/messaging-channels.mdsrc/lib/actions/sandbox/policy-channel.tssrc/lib/onboard.tssrc/lib/onboard/messaging-state.tssrc/lib/onboard/policy-presets.tssrc/lib/policy/index.tssrc/lib/sandbox/channels.test.tstest/onboard.test.tstest/policies.test.tstest/policy-tiers-onboard.test.ts
✅ Files skipped from review due to trivial changes (1)
- src/lib/onboard/messaging-state.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- test/policy-tiers-onboard.test.ts
- src/lib/policy/index.ts
- src/lib/sandbox/channels.test.ts
…ntal flag Address review feedback by (1) hinting at the matching network policy preset after channels-add, (2) using "channel" instead of "bridge" for QR-only channels in the remove message, and (3) hiding WhatsApp from the picker, channels list, channels add, and the policy-preset suggester unless NEMOCLAW_EXPERIMENTAL=1 is set. Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Keeping the gate half-applied (picker and channels add gated, but the open tier, agent manifest, and channel metadata not) created an inconsistent surface that was riskier than the status quo. The post-add policy-preset hint, removal-message wording, and test hermeticity from the same commit are kept. Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
… fix/whatsapp-policy-preset
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/lib/onboard.ts (1)
10991-10994:⚠️ Potential issue | 🟠 Major | ⚡ Quick winSeed the picker from session state on interactive resume.
If an interactive run is interrupted after
current.messagingChannelsis saved but beforeregistry.registerSandbox(),existingis stillnullhere. Resuming then reopens the picker with QR-only channels unchecked, and pressing Enter silently drops them from the rebuilt sandbox.Suggested fix
- const existing = sandboxName - ? registry.getSandbox(sandboxName)?.messagingChannels ?? null - : null; + const existing = sandboxName + ? registry.getSandbox(sandboxName)?.messagingChannels ?? + session?.messagingChannels ?? + null + : session?.messagingChannels ?? null; selectedMessagingChannels = await setupMessagingChannels(agent, existing);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/onboard.ts` around lines 10991 - 10994, When seeding the messaging-channel picker, fall back to the saved session state on the agent if registry.getSandbox(sandboxName) is null; replace the current existing calculation so that if registry.getSandbox(sandboxName)?.messagingChannels is missing you use agent.current?.messagingChannels (or current.messagingChannels) before passing to setupMessagingChannels. Update the existing variable used before calling setupMessagingChannels(agent, existing) so the picker preserves previously saved channels even when registry.registerSandbox() hasn’t been called yet.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/onboard.ts`:
- Around line 5317-5318: The getMessagingToken helper currently prefers a saved
credential via getCredential(envKey) before honoring an explicitly exported
environment value, which can let stale saved tokens override exported ones;
update getMessagingToken (and the other similar helper used around the second
occurrence) to check process.env[envKey] /
normalizeCredentialValue(process.env[envKey]) first and only fall back to
getCredential(envKey) if that is missing, returning null otherwise so exported
env credentials always take precedence over stored credentials.
---
Duplicate comments:
In `@src/lib/onboard.ts`:
- Around line 10991-10994: When seeding the messaging-channel picker, fall back
to the saved session state on the agent if registry.getSandbox(sandboxName) is
null; replace the current existing calculation so that if
registry.getSandbox(sandboxName)?.messagingChannels is missing you use
agent.current?.messagingChannels (or current.messagingChannels) before passing
to setupMessagingChannels. Update the existing variable used before calling
setupMessagingChannels(agent, existing) so the picker preserves previously saved
channels even when registry.registerSandbox() hasn’t been called yet.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: f66f4ea3-9079-4e64-b32d-379ba341663a
📒 Files selected for processing (11)
docs/manage-sandboxes/messaging-channels.mdsrc/lib/actions/sandbox/policy-channel.tssrc/lib/onboard.tssrc/lib/onboard/messaging-state.tssrc/lib/onboard/policy-presets.tssrc/lib/policy/index.tssrc/lib/sandbox/channels.test.tssrc/lib/sandbox/channels.tstest/onboard.test.tstest/policies.test.tstest/policy-tiers-onboard.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- test/policy-tiers-onboard.test.ts
- src/lib/policy/index.ts
…t manifest generate-openclaw-config.py was dropping WhatsApp on the floor: _token_keys only covers Discord/Telegram/Slack so the loop skipped any QR-paired channel, leaving the baked image with no config.channels.whatsapp entry even after the rest of the pipeline registered it. Add a tokenless branch that emits the same enabled/healthMonitor shape minus the token placeholders, with a regression test that asserts the block exists and carries no token, botToken, or appToken. Channel commands and the onboard create path were also accepting channels the sandbox's agent does not advertise. Resolve the agent for the target sandbox in channels add/list and reject channels that are not in agent.messagingPlatforms, and filter enabledChannels by the same set inside createSandbox so a stale registry entry (or a recreate with a session.messagingChannels carrying an unsupported channel) cannot bake it into the new image. Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Conflict in network-policies.md: keep whatsapp in the Open tier (this PR adds it) and accept main's "brave when supported" clarification. Apply CodeRabbit's interactive-resume fix: fall back to session messagingChannels in setupMessagingChannels when the sandbox isn't yet in the registry. Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Selective E2E Results — ✅ All requested jobs passedRun: 26073405190
|
Selective E2E Results — ✅ All requested jobs passedRun: 26073403013
|
Selective E2E Results — ❌ Some jobs failedRun: 26073779854
|
Selective E2E Results — ❌ Some jobs failedRun: 26073818011
|
Selective E2E Results — ✅ All requested jobs passedRun: 26074804320
|
Selective E2E Results — ❌ Some jobs failedRun: 26074855642
|
Selective E2E Results — ✅ All requested jobs passedRun: 26075901899
|
Selective E2E Results — ✅ All requested jobs passedRun: 26075981044
|
Selective E2E Results — ✅ All requested jobs passedRun: 26078664110
|
## Summary Refreshes the NemoClaw docs for v0.0.46 by updating version metadata, release notes, and generated user skills. The refresh also keeps public docs aligned with the docs skip list by removing non-public experimental references from the generated output. ## Related Issue None. ## Changes - #3744 and #3824 -> `docs/about/release-notes.mdx`: Added Windows bootstrap and WSL express install coverage for v0.0.46. - #3392 -> `docs/manage-sandboxes/messaging-channels.mdx`, `docs/reference/commands.mdx`, `docs/reference/network-policies.mdx`, and policy examples: Refreshed public messaging channel docs around WhatsApp and matching policy presets. - #3742, #3767, #3732, #3786, #3777, and #3808 -> `docs/about/release-notes.mdx`: Added release-note coverage for Hermes managed tools, Bedrock Runtime endpoint detection, WSL Ollama proxying, Model Router Python fallback, plugin command registration, and tool-catalog latency improvements. - #3124 -> `docs/about/release-notes.mdx`: Added release-note coverage for hosted uninstall flag guidance. - Generated `nemoclaw-user-*` skills from the updated MDX docs for the v0.0.46 release. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [x] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Verification - [ ] `npx prek run --all-files` passes - [ ] `npm test` passes - [ ] Tests added or updated for new or changed behavior - [x] No secrets, API keys, or credentials committed - [x] Docs updated for user-facing behavior changes - [ ] `make docs` builds without warnings (doc changes only) - [x] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) Verification notes: - Commit hooks passed, including markdownlint, gitleaks, docs-to-skills verification, env-var docs, and skills YAML checks. - `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx` passed. - `bash test/e2e/e2e-cloud-experimental/check-docs.sh --only-links --local-only --with-skills` passed. - `git diff --check` passed. - `make docs` was attempted but blocked before MDX validation because `npx` received HTTP 403 fetching `fern-api` from npm. --- Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Released v0.0.46: improved Windows setup, WhatsApp messaging support, Hermes sandbox/tool routing, Anthropic endpoint compatibility, Ollama proxy routing, model-router fallback, OpenClaw plugin/backup compatibility, sandbox build tooling fixes, and updated uninstall flag behavior. * **Documentation** * Removed WeChat from messaging flows and presets across guides and CLI docs; clarified onboarding and channel setup for WhatsApp. Clarified runtime mutability and filesystem (Landlock) behavior — some changes require sandbox rebuilds; prefer host-side commands for durable config. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/NVIDIA/NemoClaw/pull/3911?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
Adds WhatsApp as a QR-paired messaging channel alongside Telegram/Discord/Slack, and ships the network policy preset that unblocks the consumer WhatsApp Web protocol from inside an OpenShell sandbox. WhatsApp uses Curve25519 QR pairing rather than a static token, so
ChannelDef.envKeybecomes optional and the wizard skips the token prompt for QR-paired channels.Related Issue
Fixes #361
Fixes #513
Changes
nemoclaw-blueprint/policies/presets/whatsapp.yaml:access: full, tls: skip) forweb.whatsapp.comand*.web.whatsapp.comso the proxy stops negotiating h2 on the/ws/chatupgrade and stops auto-terminating TLS on the Noise handshake.whatsapp.netand the*.whatsapp.netwildcard (coversmmg,static,cdn,pps,v,e1,f,s, etc. — all Meta-controlled; mirrors the*.atlassian.netprecedent in the jira preset).raw.githubusercontent.com/WhiskeySockets/Baileys/master/src/Defaults/index.tsso Baileys'fetchLatestBaileysVersion()succeeds at runtime. Without it Baileys advertises its bundled (stale) WA protocol constant and Meta rejects pairing with<failure reason="405"/>.tiers.yaml.ChannelDefgainsloginMethod("token-paste"/"host-qr"/"in-sandbox-qr");envKeybecomes optional. NewchannelUsesInSandboxQrPairingandchannelHasStaticTokenhelpers insandbox/channels.ts.onboard.ts: wizard prompt loop short-circuits for in-sandbox-QR channels (prints pairing instructions, skips token prompt).getMessagingToken, conflict-detection,enabledEnvKeys/disabledEnvKeys, and the userId loop now tolerate tokenless channels.setupMessagingChannelsfilters available channels by the active agent'smessagingPlatformsso each agent only sees what it advertises.activeMessagingChannelsnow includes QR-selected channels so the sandbox image, registry state, and policy bootstrap all preserve them.policy-channel.ts:addSandboxChannelandremoveSandboxChannelnormalisechannelArgbefore logging, registry writes, and rebuild reasons. The in-sandbox-QR path registers the channel in the registry without upserting a bridge provider. The matching built-in network policy preset is applied to the sandbox before the rebuild so the bridge has egress on first start; failures warn and tell the user to runpolicy-addmanually.agents/openclaw/manifest.yaml:whatsappmoves from the# Future:comment intosupported:and intostate_dirs:(Baileys session state is durable across rebuilds, not baked into the image). Hermes intentionally does not advertise WhatsApp, and the wizard filter respects that.policy/index.ts: messaging-preset warning text now uses generic "channel setup, pairing, and runtime configuration" wording so it reads correctly for QR-paired channels.scripts/nemoclaw-start.sh):openclaw channels loginandchannels statusare intentionally allowed; mutating ops stay blocked. The error message distinguishes WhatsApp's in-sandbox pairing path from WeChat's host-side QR.channels.test.tscovers the in-sandbox-QR shape, the threeloginMethodvalues, and mixed-case canonicalisation;policies.test.tsadds regression cases forwhatsapp.yaml(L4 +tls: skiponweb.whatsapp.com; apex+wildcardwhatsapp.netREST methods; the GET-pinnedraw.githubusercontent.comrule).messaging-channels.mddescribes the QR-pair flow, the durablewhatsappstate directory, and the three login modes;commands.mddescribestoken-paste/host-qr/in-sandbox-qrforchannels addand the auto-applied preset behaviour;network-policies.mdandintegration-policy-examples.mdfoldwechatandwhatsappinto the baseline-policy and matching-preset wording; user-reference skill regenerated.Type of Change
Verification
npx prek run --all-filespassesnpm testpassesmake docsbuilds without warnings (doc changes only)Signed-off-by: Tinson Lai tinsonl@nvidia.com
Summary by CodeRabbit
New Features
Documentation
Policy
Chores / CLI
Tests