fix: document Telegram asDocument alias (#52461) (thanks @bakhtiersizhaev)

* 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>
This commit is contained in:
Bakhtier Sizhaev
2026-03-23 17:02:46 +05:00
committed by GitHub
parent 47db5abece
commit a0cb443aa3
6 changed files with 45 additions and 3 deletions

View File

@@ -101,6 +101,7 @@ Docs: https://docs.openclaw.ai
- Docs/plugins: add the community DingTalk plugin listing to the docs catalog. (#29913) Thanks @sliverp.
- Docs/plugins: add the community QQbot plugin listing to the docs catalog. (#29898) Thanks @sliverp.
- Docs/plugins: add the community wecom plugin listing to the docs catalog. (#29905) Thanks @sliverp.
- Telegram/message tool: add `asDocument` as a user-facing alias for `forceDocument` on image and GIF sends, while preserving explicit `forceDocument` precedence when both flags are present. (#52461) Thanks @bakhtiersizhaev.
### Fixes

View File

@@ -354,7 +354,10 @@ export async function handleTelegramAction(
quoteText: quoteText ?? undefined,
asVoice: readBooleanParam(params, "asVoice"),
silent: readBooleanParam(params, "silent"),
forceDocument: readBooleanParam(params, "forceDocument") ?? false,
forceDocument:
readBooleanParam(params, "forceDocument") ??
readBooleanParam(params, "asDocument") ??
false,
});
return jsonResult({
ok: true,

View File

@@ -111,7 +111,7 @@ function describeTelegramMessageTool({
if (discovery.buttonsEnabled) {
schema.push({
properties: {
buttons: Type.Optional(createMessageToolButtonsSchema()),
buttons: createMessageToolButtonsSchema(),
},
});
}

View File

@@ -122,6 +122,12 @@ function buildSendSchema(options: { includeInteractive: boolean }) {
description: "Send image/GIF as document to avoid Telegram compression (Telegram only).",
}),
),
asDocument: Type.Optional(
Type.Boolean({
description:
"Send image/GIF as document to avoid Telegram compression. Alias for forceDocument (Telegram only).",
}),
),
interactive: Type.Optional(interactiveMessageSchema),
};
if (!options.includeInteractive) {

View File

@@ -737,6 +737,37 @@ describe("telegramMessageActions", () => {
asVoice: true,
}),
},
{
name: "media-only send preserves asDocument",
action: "send" as const,
params: {
to: "123",
media: "https://example.com/photo.jpg",
asDocument: true,
},
expectedPayload: expect.objectContaining({
action: "sendMessage",
to: "123",
media: "https://example.com/photo.jpg",
asDocument: true,
}),
},
{
name: "explicit forceDocument false beats asDocument alias",
action: "send" as const,
params: {
to: "123",
media: "https://example.com/photo.jpg",
forceDocument: false,
asDocument: true,
},
expectedPayload: expect.objectContaining({
action: "sendMessage",
to: "123",
media: "https://example.com/photo.jpg",
forceDocument: false,
}),
},
{
name: "silent send forwards silent flag",
action: "send" as const,

View File

@@ -472,7 +472,8 @@ async function handleSendAction(ctx: ResolvedActionContext): Promise<MessageActi
}
params.message = message;
const gifPlayback = readBooleanParam(params, "gifPlayback") ?? false;
const forceDocument = readBooleanParam(params, "forceDocument") ?? false;
const forceDocument =
readBooleanParam(params, "forceDocument") ?? readBooleanParam(params, "asDocument") ?? false;
const bestEffort = readBooleanParam(params, "bestEffort");
const silent = readBooleanParam(params, "silent");