mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-01 01:30:22 +00:00
* 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>
157 lines
4.7 KiB
TypeScript
157 lines
4.7 KiB
TypeScript
import { Type } from "@sinclair/typebox";
|
|
import {
|
|
createUnionActionGate,
|
|
listTokenSourcedAccounts,
|
|
resolveReactionMessageId,
|
|
} from "openclaw/plugin-sdk/channel-actions";
|
|
import { createMessageToolButtonsSchema } from "openclaw/plugin-sdk/channel-actions";
|
|
import type {
|
|
ChannelMessageActionAdapter,
|
|
ChannelMessageActionName,
|
|
ChannelMessageToolDiscovery,
|
|
ChannelMessageToolSchemaContribution,
|
|
} from "openclaw/plugin-sdk/channel-contract";
|
|
import type { TelegramActionConfig } from "openclaw/plugin-sdk/config-runtime";
|
|
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
|
|
import {
|
|
createTelegramActionGate,
|
|
listEnabledTelegramAccounts,
|
|
resolveTelegramPollActionGateState,
|
|
} from "./accounts.js";
|
|
import { handleTelegramAction } from "./action-runtime.js";
|
|
import { isTelegramInlineButtonsEnabled } from "./inline-buttons.js";
|
|
import { createTelegramPollExtraToolSchemas } from "./message-tool-schema.js";
|
|
|
|
export const telegramMessageActionRuntime = {
|
|
handleTelegramAction,
|
|
};
|
|
|
|
const TELEGRAM_MESSAGE_ACTION_MAP = {
|
|
delete: "deleteMessage",
|
|
edit: "editMessage",
|
|
poll: "poll",
|
|
react: "react",
|
|
send: "sendMessage",
|
|
sticker: "sendSticker",
|
|
"sticker-search": "searchSticker",
|
|
"topic-create": "createForumTopic",
|
|
"topic-edit": "editForumTopic",
|
|
} as const satisfies Partial<Record<ChannelMessageActionName, string>>;
|
|
|
|
function resolveTelegramMessageActionName(action: ChannelMessageActionName) {
|
|
return TELEGRAM_MESSAGE_ACTION_MAP[action as keyof typeof TELEGRAM_MESSAGE_ACTION_MAP];
|
|
}
|
|
|
|
function resolveTelegramActionDiscovery(cfg: Parameters<typeof listEnabledTelegramAccounts>[0]) {
|
|
const accounts = listTokenSourcedAccounts(listEnabledTelegramAccounts(cfg));
|
|
if (accounts.length === 0) {
|
|
return null;
|
|
}
|
|
const unionGate = createUnionActionGate(accounts, (account) =>
|
|
createTelegramActionGate({
|
|
cfg,
|
|
accountId: account.accountId,
|
|
}),
|
|
);
|
|
const pollEnabled = accounts.some((account) => {
|
|
const accountGate = createTelegramActionGate({
|
|
cfg,
|
|
accountId: account.accountId,
|
|
});
|
|
return resolveTelegramPollActionGateState(accountGate).enabled;
|
|
});
|
|
const buttonsEnabled = accounts.some((account) =>
|
|
isTelegramInlineButtonsEnabled({ cfg, accountId: account.accountId }),
|
|
);
|
|
return {
|
|
isEnabled: (key: keyof TelegramActionConfig, defaultValue = true) =>
|
|
unionGate(key, defaultValue),
|
|
pollEnabled,
|
|
buttonsEnabled,
|
|
};
|
|
}
|
|
|
|
function describeTelegramMessageTool({
|
|
cfg,
|
|
}: Parameters<
|
|
NonNullable<ChannelMessageActionAdapter["describeMessageTool"]>
|
|
>[0]): ChannelMessageToolDiscovery {
|
|
const discovery = resolveTelegramActionDiscovery(cfg);
|
|
if (!discovery) {
|
|
return {
|
|
actions: [],
|
|
capabilities: [],
|
|
schema: null,
|
|
};
|
|
}
|
|
const actions = new Set<ChannelMessageActionName>(["send"]);
|
|
if (discovery.pollEnabled) {
|
|
actions.add("poll");
|
|
}
|
|
if (discovery.isEnabled("reactions")) {
|
|
actions.add("react");
|
|
}
|
|
if (discovery.isEnabled("deleteMessage")) {
|
|
actions.add("delete");
|
|
}
|
|
if (discovery.isEnabled("editMessage")) {
|
|
actions.add("edit");
|
|
}
|
|
if (discovery.isEnabled("sticker", false)) {
|
|
actions.add("sticker");
|
|
actions.add("sticker-search");
|
|
}
|
|
if (discovery.isEnabled("createForumTopic")) {
|
|
actions.add("topic-create");
|
|
}
|
|
if (discovery.isEnabled("editForumTopic")) {
|
|
actions.add("topic-edit");
|
|
}
|
|
const schema: ChannelMessageToolSchemaContribution[] = [];
|
|
if (discovery.buttonsEnabled) {
|
|
schema.push({
|
|
properties: {
|
|
buttons: createMessageToolButtonsSchema(),
|
|
},
|
|
});
|
|
}
|
|
if (discovery.pollEnabled) {
|
|
schema.push({
|
|
properties: createTelegramPollExtraToolSchemas(),
|
|
visibility: "all-configured",
|
|
});
|
|
}
|
|
return {
|
|
actions: Array.from(actions),
|
|
capabilities: discovery.buttonsEnabled ? ["interactive", "buttons"] : [],
|
|
schema,
|
|
};
|
|
}
|
|
|
|
export const telegramMessageActions: ChannelMessageActionAdapter = {
|
|
describeMessageTool: describeTelegramMessageTool,
|
|
extractToolSend: ({ args }) => {
|
|
return extractToolSend(args, "sendMessage");
|
|
},
|
|
handleAction: async ({ action, params, cfg, accountId, mediaLocalRoots, toolContext }) => {
|
|
const telegramAction = resolveTelegramMessageActionName(action);
|
|
if (!telegramAction) {
|
|
throw new Error(`Unsupported Telegram action: ${action}`);
|
|
}
|
|
return await telegramMessageActionRuntime.handleTelegramAction(
|
|
{
|
|
...params,
|
|
action: telegramAction,
|
|
accountId: accountId ?? undefined,
|
|
...(action === "react"
|
|
? {
|
|
messageId: resolveReactionMessageId({ args: params, toolContext }),
|
|
}
|
|
: {}),
|
|
},
|
|
cfg,
|
|
{ mediaLocalRoots },
|
|
);
|
|
},
|
|
};
|