fix: critical Telegram integration issues

- Add Telegram handling to relay command when selected via pickProvider
- Add Telegram delivery support to agent --deliver command
- Add telegram: prefix to sender identifiers to prevent session ID collisions
- Update detectProvider to properly handle telegram: prefixed identifiers
- Document provider detection logic and session ID collision prevention

Fixes session ID collisions where Telegram users without usernames (numeric IDs
or phone numbers) were being misidentified as WhatsApp users, causing cross-
provider session leakage.
This commit is contained in:
Arne Moor 2025-12-06 02:34:44 +01:00
parent a67243dd49
commit 6da26f3f21
4 changed files with 66 additions and 8 deletions

View File

@ -587,6 +587,11 @@ Examples:
}
}
if (provider === "telegram") {
await monitorTelegramProvider(Boolean(opts.verbose), defaultRuntime);
return;
}
ensureTwilioEnv();
logTwilioFrom();
await monitorTwilio(intervalSeconds, lookbackMinutes);

View File

@ -22,9 +22,12 @@ import {
type SessionEntry,
saveSessionStore,
} from "../config/sessions.js";
import { readEnv } from "../env.js";
import { ensureTwilioEnv } from "../env.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { pickProvider } from "../provider-web.js";
import { createInitializedProvider } from "../providers/factory.js";
import type { TelegramProviderConfig } from "../providers/base/types.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import type { Provider } from "../utils.js";
import { sendViaIpc } from "../web/ipc.js";
@ -349,7 +352,9 @@ export async function agentCommand(
provider =
provider === "twilio"
? "twilio"
: await pickProvider((provider ?? "auto") as Provider | "auto");
: provider === "telegram"
? "telegram"
: await pickProvider((provider ?? "auto") as Provider | "auto");
if (provider === "twilio") ensureTwilioEnv();
}
@ -392,6 +397,38 @@ export async function agentCommand(
});
}
}
} else if (provider === "telegram") {
const env = readEnv(runtime);
if (!env.telegram?.apiId || !env.telegram?.apiHash) {
throw new Error(
"Telegram not configured. Set TELEGRAM_API_ID and TELEGRAM_API_HASH in .env",
);
}
const telegramConfig: TelegramProviderConfig = {
kind: "telegram",
apiId: Number.parseInt(env.telegram.apiId, 10),
apiHash: env.telegram.apiHash,
sessionDir: undefined,
verbose: false,
};
const telegramProvider =
await createInitializedProvider("telegram", telegramConfig);
const chunks = chunkText(text, 4096);
if (chunks.length > 0 || media.length > 0) {
const firstChunk = chunks.length > 0 ? chunks[0] : "";
const firstMedia = media[0];
await telegramProvider.send(opts.to, firstChunk, {
media: firstMedia ? [{ type: "image", url: firstMedia }] : undefined,
});
}
for (let i = 1; i < chunks.length; i++) {
await telegramProvider.send(opts.to, chunks[i]);
}
for (let i = 1; i < media.length; i++) {
await telegramProvider.send(opts.to, "", {
media: [{ type: "image", url: media[i] }],
});
}
} else {
const chunks = chunkText(text, 1600);
const resolvedMedia = await Promise.all(

View File

@ -58,12 +58,23 @@ export async function saveSessionStore(
/**
* Detect provider from message context.
*
* IMPORTANT: This function is only called when the provider isn't explicitly known.
* For messages coming through the Provider interface, the provider should already
* be indicated via the message context (e.g., From field with telegram: prefix).
*
* Telegram messages should ALWAYS use "telegram:" prefix in the From field to avoid
* being misidentified as WhatsApp.
*/
function detectProvider(from: string): "whatsapp" | "telegram" | "twilio" {
// Telegram format: "telegram:123456789" or "@username"
if (from.startsWith("telegram:") || from.startsWith("@")) {
// Telegram format: "telegram:123456789" or "telegram:@username"
if (from.startsWith("telegram:")) {
return "telegram";
}
// WhatsApp username format: "@username" (but NOT telegram:@username)
if (from.startsWith("@")) {
return "whatsapp"; // WhatsApp also supports @username format
}
// WhatsApp/Twilio use E.164 phone numbers
// Default to whatsapp for phone numbers
return "whatsapp";

View File

@ -57,19 +57,24 @@ export async function convertTelegramMessage(
}
/**
* Extract sender identifier (@username or phone).
* Extract sender identifier with telegram: prefix to prevent session ID collisions.
*
* Returns:
* - telegram:@username (if username available)
* - telegram:+phone (if phone available)
* - telegram:id (numeric Telegram ID as fallback)
*/
function extractSenderIdentifier(sender: Api.User | Api.Chat): string {
if ("username" in sender && sender.username) {
return `@${sender.username}`;
return `telegram:@${sender.username}`;
}
if ("phone" in sender && sender.phone) {
return sender.phone;
return `telegram:${sender.phone}`;
}
if ("id" in sender && sender.id) {
return sender.id.toString();
return `telegram:${sender.id.toString()}`;
}
return "unknown";
return "telegram:unknown";
}
/**