fix(telegram): send attachment paths as media

This commit is contained in:
Keshav's Bot
2026-05-22 02:13:20 +05:30
committed by Peter Steinberger
parent c897384ae9
commit fdf01db62b
2 changed files with 117 additions and 9 deletions
@@ -561,6 +561,60 @@ describe("handleTelegramAction", () => {
expect(options.mediaUrl).toBe("https://example.com/image.jpg");
});
it.each(["path", "filePath"] as const)("uses top-level %s as sendMessage media", async (key) => {
const mediaPath = `/tmp/customer_support_${key}.png`;
await handleTelegramAction(
{
action: "sendMessage",
to: "telegram:-100123:topic:879",
message: "Productivity",
[key]: mediaPath,
},
telegramConfig(),
);
const call = mockCall(sendMessageTelegram, 0, `${key} media`);
expect(call[0]).toBe("telegram:-100123:topic:879");
expect(call[1]).toBe("Productivity");
const options = requireRecord(call[2], `${key} media options`);
expect(options.token).toBe("tok");
expect(options.mediaUrl).toBe(mediaPath);
});
it("sends all attachment paths as sendMessage media", async () => {
await handleTelegramAction(
{
action: "sendMessage",
to: "telegram:-100123:topic:879",
message: "1/2 Productivity",
attachments: [
{
type: "image",
path: "/tmp/customer_support_productivity.png",
name: "customer_support_productivity.png",
},
{
type: "image",
filePath: "/tmp/customer_support_resolution.png",
name: "customer_support_resolution.png",
},
],
},
telegramConfig(),
);
const call = mockCall(sendMessageTelegram, 0, "attachment media");
expect(call[0]).toBe("telegram:-100123:topic:879");
expect(call[1]).toBe("1/2 Productivity");
const options = requireRecord(call[2], "attachment media options");
expect(options.token).toBe("tok");
expect(options.mediaUrl).toBe("/tmp/customer_support_productivity.png");
const followUpCall = mockCall(sendMessageTelegram, 1, "second attachment media");
expect(followUpCall[0]).toBe("telegram:-100123:topic:879");
expect(followUpCall[1]).toBe("");
const followUpOptions = requireRecord(followUpCall[2], "second attachment media options");
expect(followUpOptions.token).toBe("tok");
expect(followUpOptions.mediaUrl).toBe("/tmp/customer_support_resolution.png");
});
it("sends a poll", async () => {
const result = await handleTelegramAction(
{
+63 -9
View File
@@ -16,6 +16,7 @@ import {
renderMessagePresentationFallbackText,
} from "openclaw/plugin-sdk/interactive-runtime";
import type { MessagePresentation } from "openclaw/plugin-sdk/interactive-runtime";
import { sendPayloadMediaSequenceOrFallback } from "openclaw/plugin-sdk/reply-payload";
import { createTelegramActionGate, resolveTelegramPollActionGateState } from "./accounts.js";
import { resolveTelegramInlineButtons } from "./button-types.js";
import { notifyTelegramInboundEventOutboundSuccess } from "./inbound-event-delivery.js";
@@ -132,6 +133,48 @@ function readTelegramReplyToMessageId(params: Record<string, unknown>) {
);
}
function pushTelegramMediaUrl(mediaUrls: string[], seen: Set<string>, value: unknown): void {
if (typeof value !== "string") {
return;
}
const normalized = value.trim();
if (!normalized || seen.has(normalized)) {
return;
}
seen.add(normalized);
mediaUrls.push(normalized);
}
function readTelegramSendMediaUrls(params: Record<string, unknown>) {
const mediaUrls: string[] = [];
const seen = new Set<string>();
pushTelegramMediaUrl(mediaUrls, seen, params.mediaUrl);
pushTelegramMediaUrl(mediaUrls, seen, params.media);
pushTelegramMediaUrl(mediaUrls, seen, params.path);
pushTelegramMediaUrl(mediaUrls, seen, params.filePath);
pushTelegramMediaUrl(mediaUrls, seen, params.fileUrl);
if (Array.isArray(params.mediaUrls)) {
for (const mediaUrl of params.mediaUrls) {
pushTelegramMediaUrl(mediaUrls, seen, mediaUrl);
}
}
if (Array.isArray(params.attachments)) {
for (const attachment of params.attachments) {
if (!attachment || typeof attachment !== "object" || Array.isArray(attachment)) {
continue;
}
const record = attachment as Record<string, unknown>;
pushTelegramMediaUrl(mediaUrls, seen, record.media);
pushTelegramMediaUrl(mediaUrls, seen, record.mediaUrl);
pushTelegramMediaUrl(mediaUrls, seen, record.path);
pushTelegramMediaUrl(mediaUrls, seen, record.filePath);
pushTelegramMediaUrl(mediaUrls, seen, record.fileUrl);
pushTelegramMediaUrl(mediaUrls, seen, record.url);
}
}
return mediaUrls;
}
function resolveTelegramButtonsFromParams(
params: Record<string, unknown>,
presentation = normalizeMessagePresentation(params.presentation),
@@ -350,16 +393,13 @@ export async function handleTelegramAction(
throw new Error("Telegram sendMessage is disabled.");
}
const to = readStringParam(params, "to", { required: true });
const mediaUrl =
readStringParam(params, "mediaUrl") ??
readStringParam(params, "media", {
trim: false,
});
const mediaUrls = readTelegramSendMediaUrls(params);
const firstMediaUrl = mediaUrls[0];
const presentation = normalizeMessagePresentation(params.presentation);
const buttons = resolveTelegramButtonsFromParams(params, presentation);
const content = readTelegramSendContent({
args: params,
mediaUrl: mediaUrl ?? undefined,
mediaUrl: firstMediaUrl,
hasButtons: Array.isArray(buttons) && buttons.length > 0,
interactive: params.interactive,
presentation,
@@ -401,15 +441,13 @@ export async function handleTelegramAction(
"Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.",
);
}
const result = await telegramActionRuntime.sendMessageTelegram(to, content, {
const sendOptions = {
cfg,
token,
accountId: accountId ?? undefined,
mediaUrl: mediaUrl || undefined,
mediaLocalRoots: options?.mediaLocalRoots,
mediaReadFile: options?.mediaReadFile,
gatewayClientScopes: options?.gatewayClientScopes,
buttons,
replyToMessageId: replyToMessageId ?? undefined,
messageThreadId: messageThreadId ?? undefined,
quoteText: quoteText ?? undefined,
@@ -419,6 +457,22 @@ export async function handleTelegramAction(
readBooleanParam(params, "forceDocument") ??
readBooleanParam(params, "asDocument") ??
false,
};
const result = await sendPayloadMediaSequenceOrFallback({
text: content,
mediaUrls,
fallbackResult: { messageId: "unknown", chatId: to },
sendNoMedia: async () =>
await telegramActionRuntime.sendMessageTelegram(to, content, {
...sendOptions,
buttons,
}),
send: async ({ text, mediaUrl, isFirst }) =>
await telegramActionRuntime.sendMessageTelegram(to, text, {
...sendOptions,
mediaUrl,
...(isFirst ? { buttons } : {}),
}),
});
notifyVisibleOutboundSuccess(to, messageThreadId);
await maybePinTelegramActionSend({