- Replace orange accent (#f59f4a) with signature red (#ff4d4d)
- Switch from IBM Plex/Unbounded/Work Sans to Inter/JetBrains Mono
- Replace emoji icons with Lucide-style SVG icons throughout
- Add comprehensive CSS design tokens (colors, borders, semantic states)
- Update tool-display.json to use icon names instead of emoji
- Rebuild control-ui dist bundle
* 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
When the primary model supports vision natively (e.g., Claude Opus 4.5),
skip the image understanding call entirely. The image will be injected
directly into the model context instead, saving an API call and avoiding
redundant descriptions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(tts): support custom OpenAI-compatible TTS endpoints
Add OPENAI_TTS_BASE_URL environment variable to allow using self-hosted
or third-party OpenAI-compatible TTS services like Kokoro, LocalAI, or
OpenedAI-Speech.
Changes:
- Add OPENAI_TTS_BASE_URL env var (defaults to OpenAI official API)
- Relax model/voice validation when using custom endpoints
- Add tts-1 and tts-1-hd to the model allowlist
This enables users to:
- Use local TTS for privacy and cost savings
- Use models with better non-English language support (Chinese, Japanese)
- Reduce latency with local inference
Example usage:
OPENAI_TTS_BASE_URL=http://localhost:8880/v1
Tested with Kokoro-FastAPI.
* fix: strip trailing slashes from OPENAI_TTS_BASE_URL
Address review feedback: normalize the base URL by removing trailing
slashes to prevent double-slash paths like /v1//audio/speech which
cause 404 errors on some OpenAI-compatible servers.
* style: format code with oxfmt
* test: update tests for expanded OpenAI TTS model list
- Accept tts-1 and tts-1-hd as valid models
- Update OPENAI_TTS_MODELS length expectation to 3
---------
Co-authored-by: zhixian <zhixian@bunker.local>
Add channels.telegram.linkPreview config to control whether link previews
are shown in outbound messages. When set to false, uses Telegram's
link_preview_options.is_disabled to suppress URL previews.
- Add linkPreview to TelegramAccountConfig type
- Add Zod schema validation for linkPreview
- Pass link_preview_options to sendMessage in send.ts and bot/delivery.ts
- Propagate linkPreview config through deliverReplies callers
- Add tests for link preview behavior
Fixes#1675
Co-Authored-By: Claude <noreply@anthropic.com>
Follow-up to #1609 fix:
- Remove formUnsafe check from canSave (was blocking save even with valid changes)
- Suppress disconnect message for code 1012 (service restart is expected during config save)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add documentation for running Clawdbot in a sandboxed macOS VM
using Lume. This provides an alternative to buying dedicated
hardware or using cloud instances.
The guide covers:
- Installing Lume on Apple Silicon Macs
- Creating and configuring a macOS VM
- Installing Clawdbot inside the VM
- Running headlessly for 24/7 operation
- iMessage integration via BlueBubbles
- Saving golden images for easy reset
Adds support for Brave Search API's freshness parameter to filter results
by discovery time:
- 'pd' - Past 24 hours
- 'pw' - Past week
- 'pm' - Past month
- 'py' - Past year
- 'YYYY-MM-DDtoYYYY-MM-DD' - Custom date range
Useful for cron jobs and monitoring tasks that need recent results.
Note: Perplexity provider ignores this parameter (Brave only).
---
🤖 AI-assisted: This PR was created with Claude (Opus). Lightly tested via
build script. The change follows existing patterns for optional parameters
(country, search_lang, ui_lang).