* feat(telegram): add asDocument param to message tool
Adds `asDocument` as a user-facing alias for the existing `forceDocument`
parameter in the message tool. When set to `true`, media files (images,
videos, GIFs) are sent via `sendDocument` instead of `sendPhoto`/
`sendVideo`/`sendAnimation`, preserving the original file quality
without Telegram compression.
This is useful when agents need to deliver high-resolution images or
uncompressed files to users via Telegram.
`asDocument` is intentionally an alias rather than a replacement — the
existing `forceDocument` continues to work unchanged.
Changes:
- src/agents/tools/message-tool.ts: add asDocument to send schema
- src/agents/tools/telegram-actions.ts: OR asDocument into forceDocument
- src/infra/outbound/message-action-runner.ts: same OR logic for outbound path
- extensions/telegram/src/channel-actions.ts: read and forward asDocument
- src/channels/plugins/actions/actions.test.ts: add test case
* fix: restore channel-actions.ts to main version (rebase conflict fix)
* fix(test): match asDocument test payload to actual params structure
* fix(telegram): preserve forceDocument alias semantics
* fix: document Telegram asDocument alias (#52461) (thanks @bakhtiersizhaev)
---------
Co-authored-by: Бахтиер Сижаев <bkh@MacBook-Air.local>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
When `replyLike.text` or `replyLike.caption` is an unexpected
non-string value (edge case from some Telegram API responses),
the reply body was coerced to "[object Object]" via string
concatenation. Add a `typeof === "string"` guard to gracefully
fall back to empty string, matching the existing pattern used
for `quoteText` in the same function.
Co-authored-by: Penchan <penchan@penchan.co>
The Telegram plugin injects a `buttons` property into the message tool
schema via `createMessageToolButtonsSchema()`, but without wrapping it
in `Type.Optional()`. This causes TypeBox to include `buttons` in the
JSON Schema `required` array.
In isolated sessions (e.g. cron jobs) where no `currentChannel` is set,
all plugin schemas are merged into the message tool. When the LLM calls
the message tool without a `buttons` parameter, AJV validation fails
with: `buttons: must have required property 'buttons'`.
Wrap the buttons schema in `Type.Optional()` so it is not required.
Update exact-match test assertions in send.test.ts to include the new
allow_sending_without_reply: true parameter. Tests using objectContaining
already pass, but several tests use exact object matching.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a Telegram message that OpenClaw is replying to gets deleted before
delivery, the Telegram API rejects the entire sendMessage call with
"message to be replied not found". This causes the bot's response to be
silently lost and stuck in the failed delivery queue permanently.
Setting allow_sending_without_reply: true tells Telegram to deliver the
message as a standalone message if the reply target no longer exists,
instead of failing the entire request.
Applied to all 6 locations across 4 source files where
reply_to_message_id is set:
- send.ts: buildTelegramReplyParams (both reply_parameters and plain reply)
- bot/delivery.send.ts: buildTelegramSendParams
- draft-stream.ts: draft stream reply params
- bot-handlers.runtime.ts: error reply messages (file too large, media download failed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>