diff --git a/packages/channel-connector/src/adapters/TelegramAdapter.ts b/packages/channel-connector/src/adapters/TelegramAdapter.ts index 9ad3e39..14a0e37 100644 --- a/packages/channel-connector/src/adapters/TelegramAdapter.ts +++ b/packages/channel-connector/src/adapters/TelegramAdapter.ts @@ -59,7 +59,8 @@ export class TelegramAdapter implements ChannelAdapter { async sendMessage(chatId: string, text: string): Promise { const chunks = chunkMessage(text, TELEGRAM_MAX_MESSAGE_LENGTH); for (const chunk of chunks) { - await this.bot.telegram.sendMessage(chatId, chunk); + const html = markdownToHtml(chunk); + await this.bot.telegram.sendMessage(chatId, html, { parse_mode: 'HTML' }); } } @@ -108,3 +109,44 @@ function chunkMessage(text: string, maxLen: number): string[] { return chunks; } + +function escapeHtml(text: string): string { + return text.replace(/&/g, '&').replace(//g, '>'); +} + +/** + * Convert standard Markdown to Telegram HTML. + * Handles code blocks first to prevent formatting inside them. + */ +function markdownToHtml(text: string): string { + const codeBlocks: string[] = []; + const inlineCodes: string[] = []; + + let result = text.replace(/```(\w*)\n?([\s\S]*?)```/g, (_, lang, code) => { + const escaped = escapeHtml(code.trimEnd()); + const block = lang + ? `
${escaped}
` + : `
${escaped}
`; + codeBlocks.push(block); + return `\x00CODE${codeBlocks.length - 1}\x00`; + }); + + result = result.replace(/`([^`]+)`/g, (_, code) => { + inlineCodes.push(`${escapeHtml(code)}`); + return `\x00INLINE${inlineCodes.length - 1}\x00`; + }); + + result = escapeHtml(result); + + result = result + .replace(/\*\*(.+?)\*\*/g, '$1') + .replace(/__(.+?)__/g, '$1') + .replace(/\*(.+?)\*/g, '$1') + .replace(/_(.+?)_/g, '$1') + .replace(/~~(.+?)~~/g, '$1'); + + result = result.replace(/\x00CODE(\d+)\x00/g, (_, i) => codeBlocks[parseInt(i)]); + result = result.replace(/\x00INLINE(\d+)\x00/g, (_, i) => inlineCodes[parseInt(i)]); + + return result; +} diff --git a/packages/cli/src/commands/channel.ts b/packages/cli/src/commands/channel.ts index 2b1fdc0..4a18bb8 100644 --- a/packages/cli/src/commands/channel.ts +++ b/packages/cli/src/commands/channel.ts @@ -105,6 +105,23 @@ function setupInputHandler( }); } +const SYSTEM_TAGS = [ + 'command-name', + 'command-message', + 'command-args', + 'local-command-stdout', + 'system-reminder', + 'user-prompt-submit-hook', +]; + +function stripSystemTags(content: string): string { + let result = content; + for (const tag of SYSTEM_TAGS) { + result = result.replace(new RegExp(`<${tag}[^>]*>[\\s\\S]*?<\\/${tag}>`, 'g'), ''); + } + return result.trim(); +} + function startOutputPolling( telegram: TelegramAdapter, agentAdapter: AgentAdapter, @@ -137,8 +154,10 @@ function startOutputPolling( for (const msg of newMessages) { if (msg.role !== 'user' && msg.content) { - await telegram.sendMessage(chatIdRef.value, msg.content); - debug(`Sent agent response to Telegram (role: ${msg.role}, length: ${msg.content.length})`); + const cleaned = stripSystemTags(msg.content); + if (!cleaned) continue; + await telegram.sendMessage(chatIdRef.value, cleaned); + debug(`Sent agent response to Telegram (role: ${msg.role}, length: ${cleaned.length})`); } } } catch {