import type { MessengerAdapter, MessageContext, ButtonCallback, ApprovalCardPrompt, ApprovalCardOutcome, ChoiceCardPrompt } from '../../../core/types.js'; export declare class TelegramAdapter implements MessengerAdapter { readonly name = "telegram"; private bot; private config; private messageHandler?; private buttonHandler?; private isRunning; private typingIntervals; private watchdogTimer?; private consecutivePingFailures; private static readonly WATCHDOG_INTERVAL_MS; private static readonly WATCHDOG_FAILURE_THRESHOLD; private mediaCleanupTimer?; private static readonly MEDIA_CLEANUP_INTERVAL_MS; start(): Promise; /** Run media cleanup once now (so a long-running agim doesn't accumulate * files indefinitely when restarts are infrequent) and then hourly. The * hourly cadence matches the typical 7-day TTL with plenty of slack. */ private startMediaCleanup; private runPollingLoop; private startWatchdog; stop(): Promise; onMessage(handler: (ctx: MessageContext) => Promise): void; /** * Download a TG photo / image-document, save it under MEDIA_ROOT, and surface * the result to messageHandler as a Message whose `text` includes the * caption (if any) plus a "[图片附件:/path/x.jpg]" marker — claude-code * picks that up and uses Read to view it. * * On download failure we still call messageHandler with a "[图片下载失败]" * marker so the user's interaction isn't silently dropped — they can resend * or be told what went wrong. */ private handleMediaUpload; /** * Download a TG voice / audio message, transcribe it via whichever provider * is configured (OpenAI Whisper or whisper.cpp), and surface the transcript * to messageHandler as Message.text. The downloaded audio file path is * also included so the agent can reference it (e.g. send it back, replay). * * Failures are surfaced as text markers, not silent drops: * - download failure → "[语音附件下载失败:…]" * - no provider configured → "[语音附件未转写:未配置 OPENAI_API_KEY 或 AGIM_WHISPERCPP_BIN]" * - transcribe error → "[语音转写失败(${provider}):…]" * * Since transcription can take 5-30s on a slow CPU + whisper.cpp medium, * we fire-and-forget the entire operation so grammy's update queue keeps * draining for other chats. Within this chat, ordering is still serialized * by grammy. */ private handleVoiceUpload; /** * Download an arbitrary file (PDF / Word / archive / binary) and surface * `[文件附件:${path} (${displayName}, ${size})]` to the agent. Same * download infra as media/voice; differs only in marker format and * filename handling — we keep the user's `file_name` (sanitised) so the * on-disk file stays recognisable, falling back to `${msgId}.${ext}` when * Telegram doesn't supply one. */ private handleFileUpload; /** * Download a video / video_note / animation and surface * `[视频附件:${path} (${dur}s, ${size})]` to the agent. Same caveats as * handleFileUpload; we don't attempt frame extraction or transcription. */ private handleVideoUpload; sendMessage(threadId: string, text: string): Promise; onButtonCallback(handler: (cb: ButtonCallback) => Promise): void; sendApprovalCard(threadId: string, prompt: ApprovalCardPrompt): Promise<{ messageId: string; }>; editApprovalCard(threadId: string, messageId: string, outcome: ApprovalCardOutcome): Promise; sendChoiceCard(threadId: string, prompt: ChoiceCardPrompt): Promise<{ messageId: string; }>; /** * Re-render a choice card in place keeping its buttons — used for stateful * multi-select (each ☐/☑️ toggle tap). Tries editMessageText first; on * "not modified" (body unchanged) falls back to editing just the keyboard, * which is the common case since a toggle only changes button labels. * Routine Telegram errors (gone / too-old / rate-limit) are swallowed. */ updateChoiceCard(threadId: string, messageId: string, prompt: ChoiceCardPrompt): Promise; editChoiceCard(threadId: string, messageId: string, finalText: string): Promise; sendTyping(threadId: string, isTyping: boolean): Promise; } export declare const telegramAdapter: TelegramAdapter; //# sourceMappingURL=telegram-adapter.d.ts.map