Summary
channel_send tool unconditionally lowercases the channel parameter before adapter lookup. If a [[sidecar_channels]] entry has any uppercase letter in name (e.g. bot-A), channel_send(channel="bot-A", ...) fails with "channel not found" because the registered adapter key preserves the original case while the lookup key is folded to bot-a.
Plain text replies through the agent loop (incoming → outgoing same channel via sidecar) are unaffected — only the explicit channel_send tool path fails. This is most visible for voice / file attachments because they have no other delivery route.
Reproducer
- Add a sidecar with a name containing uppercase:
[[sidecar_channels]]
name = "bot-A"
channel_type = "telegram"
...
- From an agent with
channel_send capability, call:
channel_send(channel="bot-A", recipient="<chat_id>", file_path="/path/to/audio.ogg")
- Tool returns
Channel Send failed — adapter "bot-A" not found.
- Rename to lowercase (
name = "bot-a") and the same call succeeds.
Root cause (verified by inspection at v2026.6.10-beta.17)
crates/librefang-runtime/src/tool_runner/channel.rs:140:
let channel = input["channel"]
.as_str()
.ok_or("Missing 'channel' parameter")?
.trim()
.to_lowercase(); // ← folds caller-supplied name
The lowercased value is then passed to kh.send_channel_media(&channel, ...) / kh.send_channel_text(...) which look up the adapter by exact key. Adapter registration (channel_bridge.rs, post-#5996) keeps sidecar_config.name.clone() as the account_id with its original case → lookup mismatch.
Suggested fix
Either:
- A. Drop the
.to_lowercase() on caller input — caller-supplied case should match registration. (Simpler; behavior-preserving for already-lowercase setups.)
- B. Lowercase both sides consistently — fold at registration AND at lookup. Requires touching the registration path so existing in-the-wild capital-cased sidecars don't break silently.
(A) is minimal and matches the intent visible in #5996 (preserve sidecar name as the routing key).
Impact
- Multi-bot Telegram setups that use any capital in sidecar
name cannot send voice/file via channel_send.
- Workaround: rename sidecar
name to lowercase. Trade-off: dashboards / config remain harder to read.
Environment
Related
Summary
channel_sendtool unconditionally lowercases thechannelparameter before adapter lookup. If a[[sidecar_channels]]entry has any uppercase letter inname(e.g.bot-A),channel_send(channel="bot-A", ...)fails with "channel not found" because the registered adapter key preserves the original case while the lookup key is folded tobot-a.Plain text replies through the agent loop (incoming → outgoing same channel via sidecar) are unaffected — only the explicit
channel_sendtool path fails. This is most visible for voice / file attachments because they have no other delivery route.Reproducer
channel_sendcapability, call:Channel Send failed— adapter "bot-A" not found.name = "bot-a") and the same call succeeds.Root cause (verified by inspection at v2026.6.10-beta.17)
crates/librefang-runtime/src/tool_runner/channel.rs:140:The lowercased value is then passed to
kh.send_channel_media(&channel, ...)/kh.send_channel_text(...)which look up the adapter by exact key. Adapter registration (channel_bridge.rs, post-#5996) keepssidecar_config.name.clone()as the account_id with its original case → lookup mismatch.Suggested fix
Either:
.to_lowercase()on caller input — caller-supplied case should match registration. (Simpler; behavior-preserving for already-lowercase setups.)(A) is minimal and matches the intent visible in #5996 (preserve sidecar name as the routing key).
Impact
namecannot send voice/file viachannel_send.nameto lowercase. Trade-off: dashboards / config remain harder to read.Environment
2026.6.10-beta.17librefang-sidecar-telegram(Rust, bundled)Related
account_idpropagation that made this surface visible (qualifiedchannel: telegram:<name>keys now preserve case at registration)