OpenClaw version
2026.4.26 (be8c246) on macOS 25.4.0 (Darwin / Apple Silicon), Node 25.9.0.
What I expected
POST /tools/invoke with {"tool":"message","args":{"action":"send","channel":"telegram","target":"<chat-id>","message":"…"}} should deliver a Telegram message via the configured bot, the same way agent chat replies do.
What actually happens
The gateway responds:
{"ok":false,"error":{"type":"not_found","message":"Tool not available: message"}}
…even though:
channels.telegram.enabled = true and channels.telegram.botToken is set in openclaw.json
- The Telegram channel logs
[telegram] starting provider and [telegram] sendMessage ok chat=<id> message=N for normal agent chat replies
- A valid
bindings[] entry maps agentId: "main" to match.channel: "telegram" + match.peer.id: "<chat-id>"
I tried sessionKey: "agent:main:telegram:direct:<chat-id>", agentId: "main", and the bare request — all three return the same Tool not available: message error.
Why this matters
The workflow runtime's human_approval nodes call tools.invoke('message', { action: 'send', channel, target, … }) to deliver approval prompts. With this regression, approval messages never reach Telegram and operators only learn an approval is pending if they happen to open the kitchen UI. The durable approval.json file is still written, so the run is recoverable, but the human-loop notification is silently dropped.
Reproduction
- Configure a
bindings[] entry like:
{ "agentId": "main", "match": { "channel": "telegram", "peer": { "kind": "dm", "id": "<chat-id>" } } }
with channels.telegram enabled + bot token set.
- Verify direct bot delivery works:
curl -sS https://api.telegram.org/bot<token>/sendMessage \
-d chat_id=<chat-id> -d text=hello
→ ok:true.
- Try the message tool through the gateway:
curl -sS -X POST -H "authorization: Bearer <gateway-token>" \
-H "content-type: application/json" \
-d '{"tool":"message","args":{"action":"send","channel":"telegram","target":"<chat-id>","message":"diag"}}' \
http://127.0.0.1:18789/tools/invoke
→ {"ok":false,"error":{"type":"not_found","message":"Tool not available: message"}}.
Notes
dist/attempt.tool-run-context-BO5J6jJJ.js still has if (toolName === "message") return action === "send" || action === "thread-reply" — the symbol exists, but /tools/invoke doesn't surface it. Possibly the tool now requires a context the public HTTP path no longer provides (allowlist / agent session), but I couldn't find a knob to enable it.
- Same behavior with
tool: "telegram.send" and tool: "telegram_send".
- Internal cooperator workaround landed in our
recipes extension that falls back to a direct Telegram bot API POST when this returns not_found. That keeps approvals flowing locally while this is being investigated.
Happy to dig deeper if pointed at the right module — wasn't sure whether to look at the channel-side adapter or the gateway tool registration.
OpenClaw version
2026.4.26 (be8c246) on macOS 25.4.0 (Darwin / Apple Silicon), Node 25.9.0.
What I expected
POST /tools/invokewith{"tool":"message","args":{"action":"send","channel":"telegram","target":"<chat-id>","message":"…"}}should deliver a Telegram message via the configured bot, the same way agent chat replies do.What actually happens
The gateway responds:
{"ok":false,"error":{"type":"not_found","message":"Tool not available: message"}}…even though:
channels.telegram.enabled = trueandchannels.telegram.botTokenis set inopenclaw.json[telegram] starting providerand[telegram] sendMessage ok chat=<id> message=Nfor normal agent chat repliesbindings[]entry mapsagentId: "main"tomatch.channel: "telegram"+match.peer.id: "<chat-id>"I tried
sessionKey: "agent:main:telegram:direct:<chat-id>",agentId: "main", and the bare request — all three return the sameTool not available: messageerror.Why this matters
The workflow runtime's
human_approvalnodes calltools.invoke('message', { action: 'send', channel, target, … })to deliver approval prompts. With this regression, approval messages never reach Telegram and operators only learn an approval is pending if they happen to open the kitchen UI. The durableapproval.jsonfile is still written, so the run is recoverable, but the human-loop notification is silently dropped.Reproduction
bindings[]entry like:{ "agentId": "main", "match": { "channel": "telegram", "peer": { "kind": "dm", "id": "<chat-id>" } } }channels.telegramenabled + bot token set.ok:true.{"ok":false,"error":{"type":"not_found","message":"Tool not available: message"}}.Notes
dist/attempt.tool-run-context-BO5J6jJJ.jsstill hasif (toolName === "message") return action === "send" || action === "thread-reply"— the symbol exists, but/tools/invokedoesn't surface it. Possibly the tool now requires a context the public HTTP path no longer provides (allowlist / agent session), but I couldn't find a knob to enable it.tool: "telegram.send"andtool: "telegram_send".recipesextension that falls back to a direct Telegram bot API POST when this returnsnot_found. That keeps approvals flowing locally while this is being investigated.Happy to dig deeper if pointed at the right module — wasn't sure whether to look at the channel-side adapter or the gateway tool registration.