86 Commits

Author SHA1 Message Date
max
eb3e9c649b chore: fix vitest standalone configs and update package description (#11865)
* chore: fix vitest standalone configs and update package description

- vitest.live.config.ts and vitest.e2e.config.ts now extend root config
- Inherits testTimeout (120s), resolve.alias, pool, setupFiles, excludes
- ui/vitest.node.config.ts gets explicit 120s timeout
- package.json description updated for multi-channel AI gateway
- Removed unused src/utils/time-format.ts

* chore: filter inherited excludes in live/e2e vitest configs

* refactor: dedupe GroupPolicy/DmPolicy in extensions

Import from openclaw/plugin-sdk instead of re-declaring identical types.
2026-02-08 05:24:50 -08:00
Tyler Yust
1007d71f0c fix: comprehensive BlueBubbles and channel cleanup (#11093)
* feat(bluebubbles): auto-strip markdown from outbound messages (#7402)

* fix(security): add timeout to webhook body reading (#6762)

Adds 30-second timeout to readBody() in voice-call, bluebubbles, and nostr
webhook handlers. Prevents Slow-Loris DoS (CWE-400, CVSS 7.5).
Merged with existing maxBytes protection in voice-call.

* fix(security): unify Error objects and lint fixes in webhook timeouts (#6762)

* fix: prevent plugins from auto-enabling without user consent (#3961)

Changes default plugin enabled state from true to false in enablePluginEntry().
Preserves existing enabled:true values. Fixes #3932.

* fix: apply hierarchical mediaMaxMb config to all channels (#8749)

Generalizes resolveAttachmentMaxBytes() to use account → channel → global
config resolution for all channels, not just BlueBubbles. Fixes #7847.

* fix(bluebubbles): sanitize attachment filenames against header injection (#10333)

Strip ", \r, \n, and \\ from filenames after path.basename() to prevent
multipart Content-Disposition header injection (CWE-93, CVSS 5.4).
Also adds sanitization to setGroupIconBlueBubbles which had zero filename
sanitization.

* fix(lint): exclude extensions/ from Oxlint preflight check (#9313)

Extensions use PluginRuntime|null patterns that trigger
no-redundant-type-constituents because PluginRuntime resolves to any.
Excluding extensions/ from Oxlint unblocks user upgrades.
Re-applies the approach from closed PR #10087.

* fix(bluebubbles): add tempGuid to createNewChatWithMessage payload (#7745)

Non-Private-API mode (AppleScript) requires tempGuid in send payloads.
The main sendMessageBlueBubbles already had it, but createNewChatWithMessage
was missing it, causing 400 errors for new chat creation without Private API.

* fix: send stop-typing signal when run ends with NO_REPLY (#8785)

Adds onCleanup callback to the typing controller that fires when the
controller is cleaned up while typing was active (e.g., after NO_REPLY).
Channels using createTypingCallbacks automatically get stop-typing on
cleanup. This prevents the typing indicator from lingering in group chats
when the agent decides not to reply.

* fix(telegram): deduplicate skill commands in multi-agent setup (#5717)

Two fixes:
1. Skip duplicate workspace dirs when listing skill commands across agents.
   Multiple agents sharing the same workspace would produce duplicate commands
   with _2, _3 suffixes.
2. Clear stale commands via deleteMyCommands before registering new ones.
   Commands from deleted skills now get cleaned up on restart.

* fix: add size limits to unbounded in-memory caches (#4948)

Adds max-size caps with oldest-entry eviction to prevent OOM in
long-running deployments:
- BlueBubbles serverInfoCache: 64 entries (already has TTL)
- Google Chat authCache: 32 entries
- Matrix directRoomCache: 1024 entries
- Discord presenceCache: 5000 entries per account

* fix: address review concerns (#11093)

- Chain deleteMyCommands → setMyCommands to prevent race condition (#5717)
- Rename enablePluginEntry to registerPluginEntry (now sets enabled: false)
- Add Slow-Loris timeout test for readJsonBody (#6023)
2026-02-07 05:00:55 -08:00
Peter Steinberger
9f703a44dc chore(release): 2026.2.6-3 2026-02-07 00:44:32 -08:00
Peter Steinberger
ad4dd0422e chore(release): 2026.2.6-2 2026-02-07 00:30:43 -08:00
Peter Steinberger
677450cd9b chore(release): bump version to 2026.2.6 2026-02-06 15:37:31 -08:00
Peter Steinberger
5031b283a5 chore: bump version to 2026.2.4 2026-02-05 00:38:50 -08:00
Peter Steinberger
f895c9fba1 chore: sync plugin versions to 2026.2.3 2026-02-04 17:55:13 -08:00
mudrii
5d82c82313 feat: per-channel responsePrefix override (#9001)
* feat: per-channel responsePrefix override

Add responsePrefix field to all channel config types and Zod schemas,
enabling per-channel and per-account outbound response prefix overrides.

Resolution cascade (most specific wins):
  L1: channels.<ch>.accounts.<id>.responsePrefix
  L2: channels.<ch>.responsePrefix
  L3: (reserved for channels.defaults)
  L4: messages.responsePrefix (existing global)

Semantics:
  - undefined -> inherit from parent level
  - empty string -> explicitly no prefix (stops cascade)
  - "auto" -> derive [identity.name] from routed agent

Changes:
  - Core logic: resolveResponsePrefix() in identity.ts accepts
    optional channel/accountId and walks the cascade
  - resolveEffectiveMessagesConfig() passes channel context through
  - Types: responsePrefix added to WhatsApp, Telegram, Discord, Slack,
    Signal, iMessage, Google Chat, MS Teams, Feishu, BlueBubbles configs
  - Zod schemas: responsePrefix added for config validation
  - All channel handlers wired: telegram, discord, slack, signal,
    imessage, line, heartbeat runner, route-reply, native commands
  - 23 new tests covering backward compat, channel/account levels,
    full cascade, auto keyword, empty string stops, unknown fallthrough

Fully backward compatible - no existing config is affected.
Fixes #8857

* fix: address CI lint + review feedback

- Replace Record<string, any> with proper typed helpers (no-explicit-any)
- Add curly braces to single-line if returns (eslint curly)
- Fix JSDoc: 'Per-channel' → 'channel/account' on shared config types
- Extract getChannelConfig() helper for type-safe dynamic key access

* fix: finish responsePrefix overrides (#9001) (thanks @mudrii)

* fix: normalize prefix wiring and types (#9001) (thanks @mudrii)

---------

Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com>
2026-02-04 16:16:34 -05:00
Tyler Yust
9c4eab69cc iMessage: promote BlueBubbles and refresh docs/skills (#8415)
* feat: Make BlueBubbles the primary iMessage integration

- Remove old imsg skill (skills/imsg/SKILL.md)
- Create new BlueBubbles skill (skills/bluebubbles/SKILL.md) with message tool examples
- Add keep-alive script documentation for VM/headless setups to docs/channels/bluebubbles.md
  - AppleScript that pokes Messages.app every 5 minutes
  - LaunchAgent configuration for automatic execution
  - Prevents Messages.app from going idle in VM environments
- Update all documentation to prioritize BlueBubbles over legacy imsg:
  - Mark imsg channel as legacy throughout docs
  - Update README.md channel lists
  - Update wizard, hubs, pairing, and index docs
  - Update FAQ to recommend BlueBubbles for iMessage
  - Update RPC docs to note imsg as legacy pattern
  - Update Chinese documentation (zh-CN)
- Replace imsg examples with generic macOS skill examples where appropriate

BlueBubbles is now the recommended first-class iMessage integration,
with the legacy imsg integration marked for potential future removal.

* refactor: Update import paths and improve code formatting

- Adjusted import paths in session-status-tool.ts, whatsapp-heartbeat.ts, and heartbeat-runner.ts for consistency.
- Reformatted code for better readability by aligning and grouping related imports and function parameters.
- Enhanced error messages and conditional checks for clarity in heartbeat-runner.ts.

* skills: restore imsg skill and align bluebubbles skill

* docs: update FAQ for clarity and formatting

- Adjusted the formatting of the FAQ section to ensure consistent bullet point alignment.
- No content changes were made, only formatting improvements for better readability.

* style: oxfmt touched files

* fix: preserve BlueBubbles developer reference (#8415) (thanks @tyler6204)
2026-02-03 18:06:54 -08:00
Peter Steinberger
1c4db91593 chore: prepare 2026.2.2 release 2026-02-03 10:02:01 -08:00
Tyler Yust
8d2f98fb01 Fix subagent announce failover race (always emit lifecycle end + treat timeout=0 as no-timeout) (#6621)
* Fix subagent announce race and timeout handling

Bug 1: Subagent announce fires before model failover retries finish
- Problem: CLI provider emitted lifecycle error on each attempt, causing
  subagent registry to prematurely call beginSubagentCleanup() and announce
  with incorrect status before failover retries completed
- Fix: Removed lifecycle error emission from CLI provider's attempt-level
  .catch() in agent-runner-execution.ts. Errors still propagate to
  runWithModelFallback for retry, but no intermediate lifecycle events
  are emitted. Only the final outcome (after all retries) emits lifecycle
  events.

Bug 2: Hard 600s per-prompt timeout ignores runTimeoutSeconds=0
- Problem: When runTimeoutSeconds=0 (meaning 'no timeout'), the code
  returned the default 600s timeout instead of respecting the 0 setting
- Fix: Modified resolveAgentTimeoutMs() to treat 0 as 'no timeout' and
  return a very large timeout value (30 days) instead of the default.
  This avoids setTimeout issues with Infinity while effectively providing
  unlimited time for long-running tasks.

* fix: emit lifecycle:error for CLI failures (#6621) (thanks @tyler6204)

* chore: satisfy format/lint gates (#6621) (thanks @tyler6204)

* fix: restore build after upstream type changes (#6621) (thanks @tyler6204)

* test: fix createSystemPromptOverride tests to match new return type (#6621) (thanks @tyler6204)
2026-02-02 02:06:14 -08:00
Tyler Yust
9ef24fd400 fix: flush block streaming on paragraph boundaries for chunkMode=newline (#7014)
* feat: Implement paragraph boundary flushing in block streaming

- Added `flushOnParagraph` option to `BlockReplyChunking` for immediate flushing on paragraph breaks.
- Updated `EmbeddedBlockChunker` to handle paragraph boundaries during chunking.
- Enhanced `createBlockReplyCoalescer` to support flushing on enqueue.
- Added tests to verify behavior of flushing with and without `flushOnEnqueue` set.
- Updated relevant types and interfaces to include `flushOnParagraph` and `flushOnEnqueue` options.

* fix: Improve streaming behavior and enhance block chunking logic

- Resolved issue with stuck typing indicator after streamed BlueBubbles replies.
- Refactored `EmbeddedBlockChunker` to streamline fence-split handling and ensure maxChars fallback for newline chunking.
- Added tests to validate new chunking behavior, including handling of paragraph breaks and fence scenarios.
- Updated changelog to reflect these changes.

* test: Add test for clamping long paragraphs in EmbeddedBlockChunker

- Introduced a new test case to verify that long paragraphs are correctly clamped to maxChars when flushOnParagraph is enabled.
- Updated logic in EmbeddedBlockChunker to handle cases where the next paragraph break exceeds maxChars, ensuring proper chunking behavior.

* refactor: streamline logging and improve error handling in message processing

- Removed verbose logging statements from the `processMessage` function to reduce clutter.
- Enhanced error handling by using `runtime.error` for typing restart failures.
- Updated the `applySystemPromptOverrideToSession` function to accept a string directly instead of a function, simplifying the prompt application process.
- Adjusted the `runEmbeddedAttempt` function to directly use the system prompt override without invoking it as a function.
2026-02-02 01:22:41 -08:00
Peter Steinberger
85cd55e22b chore: bump to 2026.2.1 2026-02-02 08:51:54 +00:00
cpojer
935a0e5708 chore: Enable typescript/no-explicit-any rule. 2026-02-02 16:18:09 +09:00
cpojer
f06dd8df06 chore: Enable "experimentalSortImports" in Oxfmt and reformat all imorts. 2026-02-01 10:03:47 +09:00
cpojer
230ca789e2 chore: Lint extensions folder. 2026-01-31 22:42:45 +09:00
cpojer
aa91f6e700 chore: Add openclaw to devDependencies for all extensions so that types resolve. 2026-01-31 22:06:51 +09:00
cpojer
8cab78abbc chore: Run pnpm format:fix. 2026-01-31 21:13:13 +09:00
Peter Steinberger
247fab47ca chore: bump version to 2026.1.30 2026-01-31 11:37:36 +01:00
Yuri Chukhlib
65dedef65b fix(bluebubbles): debounce by messageId to preserve attachments in text+image messages (#4984)
* fix(bluebubbles): debounce by messageId to preserve attachments in text+image messages

BlueBubbles fires multiple webhook events for a single message - first
without attachment metadata, then ~350ms later with it. Previously,
messages with attachments bypassed debouncing and were processed
immediately, while the text-only version was also queued.

Now the debouncer uses messageId as the key when available, coalescing
all webhook events for the same message. The existing combineDebounceEntries
function merges attachments from all events.

Closes #4848

* fix: increase debounce and handle balloon messages

- Increase DEFAULT_INBOUND_DEBOUNCE_MS from 350ms to 500ms
- Update buildKey to use associatedMessageGuid for balloon messages
- Add regression test for debouncing behavior

Fixes issues identified in code review.

---------

Co-authored-by: Yurii Chukhlib <yurii.chukhlib@viber.com>
Co-authored-by: Tyler Yust <TYTYYUST@YAHOO.COM>
2026-01-30 15:53:14 -08:00
Peter Steinberger
62e4ad23d3 chore: release 2026.1.29 2026-01-30 06:25:45 +01:00
Peter Steinberger
9a7160786a refactor: rename to openclaw 2026-01-30 03:16:21 +01:00
Peter Steinberger
cb4b3f74b5 chore(release): bump versions to 2026.1.29 2026-01-29 16:48:13 +00:00
Peter Steinberger
7eb57b691c chore: prep 2026.1.27-beta.1 release 2026-01-28 01:35:58 +01:00
Peter Steinberger
6d16a658e5 refactor: rename clawdbot to moltbot with legacy compat 2026-01-27 12:21:02 +00:00
Peter Steinberger
72fea5e305 chore: bump version to 2026.1.26 2026-01-27 09:10:47 +00:00
Tyler Yust
9c0c5866db fix: coalesce BlueBubbles link previews (#1981) (thanks @tyler6204) 2026-01-26 14:12:22 -08:00
Tyler Yust
147842fadc refactor(bluebubbles): remove URL balloon message handling and improve error logging
This commit removes the URL balloon message handling logic from the monitor, simplifying the message processing flow. Additionally, it enhances error logging by including the account ID in the error messages for better traceability.
2026-01-26 14:12:22 -08:00
Tyler Yust
420e5299d2 fix(bluebubbles): increase inbound message debounce time for URL previews 2026-01-26 14:12:22 -08:00
Tyler Yust
6d26971051 fix(bluebubbles): add inbound message debouncing to coalesce URL link previews
When users send iMessages containing URLs, BlueBubbles sends separate
webhook events for the text message and the URL balloon/link preview.
This caused Clawdbot to receive them as separate queued messages.

This fix adds inbound debouncing (following the pattern from WhatsApp/MS Teams):

- Uses the existing createInboundDebouncer utility from plugin-sdk
- Adds debounceMs config option to BlueBubblesAccountConfig (default: 500ms)
- Routes inbound messages through debouncer before processing
- Combines messages from same sender/chat within the debounce window
- Handles URLBalloonProvider messages by coalescing with preceding text
- Skips debouncing for messages with attachments or control commands

Config example:
  channels.bluebubbles.debounceMs: 500  # milliseconds (0 to disable)

Fixes inbound URL message splitting issue.
2026-01-26 14:12:22 -08:00
Peter Steinberger
8f6542409a chore: bump versions for 2026.1.25 2026-01-25 22:13:04 +00:00
Peter Steinberger
a22ac64c47 chore: release 2026.1.24-1 2026-01-25 14:08:20 +00:00
Peter Steinberger
98cecc9c56 fix: harden message aborts + bluebubbles dm create (#1751) (thanks @tyler6204) 2026-01-25 10:20:14 +00:00
Tyler Yust
0f662c2935 fix(bluebubbles): route phone-number targets to direct chats; prevent internal IDs leaking in cross-context prefix (#1751)
* fix(bluebubbles): prefer DM resolution + hide routing markers

* fix(bluebubbles): prevent message routing to group chats when targeting phone numbers

When sending a message to a phone number like +12622102921, the
resolveChatGuidForTarget function was finding and returning a GROUP
CHAT containing that phone number instead of a direct DM chat.

The bug was in the participantMatch fallback logic which matched ANY
chat containing the phone number as a participant, including groups.

This fix adds a check to ensure participantMatch only considers DM
chats (identified by ';-;' separator in the chat GUID). Group chats
(identified by ';+;' separator) are now explicitly excluded from
handle-based matching.

If a phone number only exists in a group chat (no direct DM exists),
the function now correctly returns null, which causes the send to
fail with a clear error rather than accidentally messaging a group.

Added test case to verify this behavior.

* feat(bluebubbles): auto-create new DM chats when sending to unknown phone numbers

When sending to a phone number that doesn't have an existing chat,
instead of failing with 'chatGuid not found', now automatically creates
a new chat using the /api/v1/chat/new endpoint.

- Added createNewChatWithMessage() helper function
- When resolveChatGuidForTarget returns null for a handle target,
  uses the new chat endpoint with addresses array and message
- Includes helpful error message if Private API isn't enabled
- Only applies to handle targets (phone numbers), not group chats

* fix(bluebubbles): hide internal routing metadata in cross-context markers

When sending cross-context messages via BlueBubbles, the origin marker was
exposing internal chat_guid routing info like '[from bluebubbles:chat_guid:any;-;+19257864429]'.

This adds a formatTargetDisplay() function to the BlueBubbles plugin that:
- Extracts phone numbers from chat_guid formats (iMessage;-;+1234567890 -> +1234567890)
- Normalizes handles for clean display
- Avoids returning raw chat_guid formats containing internal routing metadata

Now cross-context markers show clean identifiers like '[from +19257864429]' instead
of exposing internal routing details to recipients.

* fix: prevent cross-context decoration on direct message tool sends

Two fixes:

1. Cross-context decoration (e.g., '[from +19257864429]' prefix) was being
   added to ALL messages sent to a different target, even when the agent
   was just composing a new message via the message tool. This decoration
   should only be applied when forwarding/relaying messages between chats.

   Fix: Added skipCrossContextDecoration flag to ChannelThreadingToolContext.
   The message tool now sets this flag to true, so direct sends don't get
   decorated. The buildCrossContextDecoration function checks this flag
   and returns null when set.

2. Aborted requests were still completing because the abort signal wasn't
   being passed through the message tool execution chain.

   Fix: Added abortSignal propagation from message tool → runMessageAction →
   executeSendAction → sendMessage → deliverOutboundPayloads. Added abort
   checks at key points in the chain to fail fast when aborted.

Files changed:
- src/channels/plugins/types.core.ts: Added skipCrossContextDecoration field
- src/infra/outbound/outbound-policy.ts: Check skip flag before decorating
- src/agents/tools/message-tool.ts: Set skip flag, accept and pass abort signal
- src/infra/outbound/message-action-runner.ts: Pass abort signal through
- src/infra/outbound/outbound-send-service.ts: Check and pass abort signal
- src/infra/outbound/message.ts: Pass abort signal to delivery

* fix(bluebubbles): preserve friendly display names in formatTargetDisplay
2026-01-25 10:03:08 +00:00
Tyler Yust
92e794dc18 feat: add chunking mode option for BlueBubbles (#1645)
* feat: add chunking mode for outbound messages

- Introduced `chunkMode` option in various account configurations to allow splitting messages by "length" or "newline".
- Updated message processing to handle chunking based on the selected mode.
- Added tests for new chunking functionality, ensuring correct behavior for both modes.

* feat: enhance chunking mode documentation and configuration

- Added `chunkMode` option to the BlueBubbles account configuration, allowing users to choose between "length" and "newline" for message chunking.
- Updated documentation to clarify the behavior of the `chunkMode` setting.
- Adjusted account merging logic to incorporate the new `chunkMode` configuration.

* refactor: simplify chunk mode handling for BlueBubbles

- Removed `chunkMode` configuration from various account schemas and types, centralizing chunk mode logic to BlueBubbles only.
- Updated `processMessage` to default to "newline" for BlueBubbles chunking.
- Adjusted tests to reflect changes in chunk mode handling for BlueBubbles, ensuring proper functionality.

* fix: update default chunk mode to 'length' for BlueBubbles

- Changed the default value of `chunkMode` from 'newline' to 'length' in the BlueBubbles configuration and related processing functions.
- Updated documentation to reflect the new default behavior for chunking messages.
- Adjusted tests to ensure the correct default value is returned for BlueBubbles chunk mode.
2026-01-25 00:47:10 +00:00
Peter Steinberger
ee2918c3b1 fix: preserve BlueBubbles reply tag GUIDs 2026-01-24 23:09:28 +00:00
Tyler Yust
445b58550c feat(bluebubbles): improve reaction handling and inline reply tags (#1641)
* refactor: update reply formatting to use inline [[reply_to:N]] tag and normalize message IDs

* test: add unit tests for tapback text parsing in BlueBubbles webhook

* refactor: update message ID handling to use GUIDs instead of UUIDs for consistency
2026-01-24 22:42:42 +00:00
Adam Holt
c07949a99c Channels: add per-group tool policies 2026-01-24 05:49:39 +00:00
Peter Steinberger
aeb6b2ffad refactor: standardize channel logging 2026-01-23 23:34:30 +00:00
Peter Steinberger
07ce1d73ff refactor: standardize control command gating 2026-01-23 23:34:30 +00:00
Peter Steinberger
d82ecaf9dc refactor: centralize inbound session updates 2026-01-23 23:33:32 +00:00
Peter Steinberger
cb8c8fee9a refactor: centralize ack reaction removal 2026-01-23 23:32:14 +00:00
Peter Steinberger
02bd6e4a24 refactor: centralize ack reaction gating 2026-01-23 22:24:31 +00:00
Peter Steinberger
4ee70be690 chore: bump version to 2026.1.23 2026-01-23 22:14:56 +00:00
Peter Steinberger
b77e730657 fix: add per-channel markdown table conversion (#1495) (thanks @odysseus0) 2026-01-23 18:39:25 +00:00
Peter Steinberger
6d2a1ce217 test: trim async waits in webhook tests 2026-01-23 18:34:33 +00:00
Peter Steinberger
784468d6c3 fix: harden BlueBubbles voice memos (#1477) (thanks @Nicell) 2026-01-23 04:38:08 +00:00
Clawd
02b5f403db feat(bluebubbles): add asVoice support for voice memos
Add asVoice parameter to sendBlueBubblesAttachment that converts audio
to iMessage voice memo format (Opus CAF at 48kHz) and sets isAudioMessage
flag in the BlueBubbles API.

This follows the existing asVoice pattern used by Telegram.

- Convert audio to Opus CAF format using ffmpeg when asVoice=true
- Set isAudioMessage=true in BlueBubbles attachment API
- Pass asVoice through action handler and media-send
2026-01-23 04:34:19 +00:00
Peter Steinberger
3993c9a3b4 fix: stop BlueBubbles typing on idle/no-reply (#1439) (thanks @Nicell) 2026-01-22 21:33:19 +00:00
Clawd
f552820a75 fix(bluebubbles): call stop typing on idle and NO_REPLY
Previously, typing stop was intentionally skipped because the
BlueBubbles Server DELETE endpoint was bugged (called startTyping
instead of stopTyping). Now that the server bug is fixed, we can
properly stop typing indicators.

- onIdle: now calls sendBlueBubblesTyping(false) to stop typing
- finally block: stops typing when no message sent (NO_REPLY case)
2026-01-22 21:20:35 +00:00