- Add ReDoS protection using safe-regex validation for contentPattern
- Add token bucket rate limiting (10/min per handler) to prevent cost explosions
- Require at least one match condition in Zod schema (reject empty match)
- Change error logging from logVerbose to logWarn for visibility
Includes tests for rate limiter and ReDoS protection.
Add `hooks.internal.messageHandlers` config array for triggering agent
execution when inbound messages match specified conditions. This solves
the problem of important messages (like bug reports) being queued and
potentially missed when cron jobs wake the agent.
Features:
- Match conditions: channelId, conversationId, from, contentPattern (regex),
contentContains (keywords)
- Priority modes: "immediate" (bypass queue) or "queue" (normal flow)
- Execution modes: "exclusive" (handler only) or "parallel" (handler + normal)
- Message transformation: prefix, suffix, or full template with placeholders
- Configurable model and thinking level per handler
Implementation:
- src/config/types.hooks.ts: MessageHandlerConfig and MessageHandlerMatch types
- src/config/zod-schema.hooks.ts: Zod validation schemas
- src/hooks/message-handler-match.ts: Condition matching logic
- src/hooks/message-handler-run.ts: Handler executor using runCronIsolatedAgentTurn
- src/auto-reply/reply/dispatch-from-config.ts: Integration point
- docs/hooks.md: Full documentation with examples
- 28 unit tests for matcher logic
- Add MessageReceivedHookContext type with full message metadata
- Add isMessageReceivedEvent() type guard for type-safe handling
- Trigger hook in dispatchReplyFromConfig() after plugin hooks
- Fire-and-forget execution to avoid blocking message processing
- Works across all 12 channels (whatsapp, telegram, discord, etc.)
- Add comprehensive tests for type guard and hook triggering
- Document message events, context fields, and filtering examples
The pairing CLI calls listPairingChannels() at registration time,
which requires the plugin registry to be populated. Without this,
plugin-provided channels like Matrix fail with "does not support
pairing" even though they have pairing adapters defined.
This mirrors the existing pattern used by the plugins CLI entry.
Co-authored-by: Shakker <165377636+shakkernerd@users.noreply.github.com>
Add mappings for audio/x-m4a, audio/mp4, and video/quicktime to ensure
media files sent as documents are saved with proper extensions, enabling
automatic transcription/analysis tools to work correctly.
- audio/x-m4a → .m4a
- audio/mp4 → .m4a
- video/quicktime → .mov
Also adds comprehensive test coverage for extensionForMime().
Adds `messages` config option to session-memory hook (default: 15).
Fixes filter order bug - now filters user/assistant messages first,
then slices to get exactly N messages. Previously sliced first which
could result in fewer messages when non-message entries were present.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new dmScope option that includes accountId in session keys,
enabling isolated sessions per channel account for multi-bot setups.
- Add 'per-account-channel-peer' to DmScope type
- Update session key generation to include accountId
- Pass accountId through routing chain
- Add tests for new routing behavior (13/13 passing)
Closes#3094
Co-authored-by: Sebastian Almeida <89653954+SebastianAlmeida@users.noreply.github.com>
The MiniMax provider config was updated to use api.minimax.chat
instead of api.minimax.io in PR #3064, but the test expectation
was not updated.
🤖 Generated with Claude Code
- Re-export DirectoryConfigParams and ChannelDirectoryEntry from channels/targets
- Remove unused ChannelDirectoryEntry and resolveDiscordAccount imports
- Fix parseDiscordTarget calls to not pass incompatible options type
- Fix unused catch parameter
Fixes CI build failures on main.
🤖 Generated with Claude Code
Regular Telegram groups (without Topics/Forums enabled) can send
message_thread_id when users reply to messages. This was incorrectly
being used to create separate session keys like '-123:topic:42',
causing each reply chain to get its own conversation context.
Now resolveTelegramForumThreadId only returns a thread ID when the
chat is actually a forum (is_forum=true). For regular groups, the
thread ID is ignored, ensuring all messages share the same session.
DMs continue to use messageThreadId for thread sessions as before.
When sending Discord messages via cron jobs or the message tool,
usernames like "john.doe" were incorrectly treated as channel names,
causing silent delivery failures.
This fix adds a resolveDiscordTarget() function that:
- Queries Discord directory to resolve usernames to user IDs
- Falls back to standard parsing for known formats
- Enables sending DMs by username without requiring explicit user:ID format
Changes:
- Added resolveDiscordTarget() in targets.ts with directory lookup
- Added parseAndResolveRecipient() in send.shared.ts
- Updated all outbound send functions to use username resolution
Fixes#2627
MiniMax has updated their API. The previous configuration used an
incorrect endpoint (api.minimax.io/anthropic) with anthropic-messages
format, which no longer works.
Changes:
- Update MINIMAX_API_BASE_URL to https://api.minimax.chat/v1
- Change API format from anthropic-messages to openai-completions
- Remove minimax from isAnthropicApi check in transcript-policy
This fixes the issue where MiniMax API calls return no results.
Wraps plugin.actions.listActions() in a try/catch so a single
broken channel plugin cannot crash the entire agent boot sequence.
Errors are logged once per plugin+message (deduped) via
defaultRuntime.error() and the call gracefully returns an empty
array instead of propagating the exception.
Fixes: 'Cannot read properties of undefined (reading listActions)'
after the clawdbot→moltbot rename left some plugin state undefined.