* fix(telegram): fall back to text when voice messages forbidden
When TTS auto mode is enabled, slash commands like /status would fail
silently because sendVoice was rejected with VOICE_MESSAGES_FORBIDDEN.
The entire reply would fail without any text being sent.
This adds error handling to catch VOICE_MESSAGES_FORBIDDEN specifically
and fall back to sending the text content as a regular message instead
of failing completely.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: handle telegram voice fallback errors (#1725) (thanks @foeken)
---------
Co-authored-by: Echo <andre.foeken@Donut.local>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
When a cron job runs in isolated mode, the sessions_spawn tool now correctly
inherits the allowAgents permissions from the parent agent's config.
The fix adds a requesterAgentIdOverride parameter that flows through the
tool creation chain:
- resolveEffectiveToolPolicy() extracts the correct agentId from the session key
- This agentId is passed to sessions_spawn and agents_list tools
- The tools use this override instead of re-parsing the session key
This fixes#1767
Fixes#1765
- Extract client ID and secret from Gemini CLI's bundled oauth2.js
- Cross-platform binary lookup (no shell commands)
- Fallback to env vars for user override
- Add tests for credential extraction
The previous check used includes("win") which incorrectly matched
"darwin" (macOS) because it contains "win". This caused cmd.exe to be
used on macOS instead of /bin/sh.
* feat: audit fixes and documentation improvements
- Refactored model selection to drop legacy fallback and add warning
- Improved heartbeat content validation
- Added Skill Creation guide
- Updated CONTRIBUTING.md with roadmap
* style: fix formatting in model-selection.ts
* style: fix formatting and improve model selection logic with tests
* fix(voice-call): prevent audio overlap with TTS queue
Add a TTS queue to serialize audio playback and prevent overlapping
speech during voice calls. Previously, concurrent speak() calls could
send audio chunks simultaneously, causing garbled/choppy output.
Changes:
- Add queueTts() to MediaStreamHandler for sequential TTS playback
- Wrap playTtsViaStream() audio sending in the queue
- Clear queue on barge-in (when user starts speaking)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(voice-call): use iterative queue processing to prevent heap exhaustion
The recursive processQueue() pattern accumulated stack frames, causing
JavaScript heap out of memory errors on macOS CI. Convert to while loop
for constant stack usage regardless of queue depth.
* fix: prevent voice-call TTS overlap (#1713) (thanks @dguido)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
The proxy configuration (`channels.telegram.proxy`) was only used for
the gateway monitor (polling), but not for outbound sends (sendMessage,
reactMessage, deleteMessage). This caused outbound messages to bypass
the configured proxy, which is problematic for users behind corporate
proxies or those who want to route all traffic through a specific proxy.
This change ensures that all three outbound functions use the same
proxy configuration as the monitor:
- sendMessageTelegram
- reactMessageTelegram
- deleteMessageTelegram
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes#1743
The settings page was unable to scroll because .config-layout has
overflow:hidden which blocks child scrolling. Added min-height:0 and
overflow-y:auto to .config-main to enable scrolling within the grid
layout.
When installing the Gateway daemon via LaunchAgent (macOS) or systemd (Linux),
environment variables defined in config.env.vars were not being included in
the service environment. This caused API keys and other env vars configured
in clawdbot.json5 to be unavailable when the Gateway ran as a service.
The fix adds a configEnvVars parameter to buildGatewayInstallPlan() which
merges config.env.vars into the service environment. Service-specific
variables (CLAWDBOT_*, HOME, PATH) take precedence over config env vars.
Fixes the issue where users had to manually edit the LaunchAgent plist
to add environment variables like GOOGLE_API_KEY.
- 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>