From ff1ca4460d26d83f04a28ca2940a8535f746e34b Mon Sep 17 00:00:00 2001 From: tinkle-community Date: Sun, 8 Mar 2026 18:56:05 +0800 Subject: [PATCH] fix(telegram): use Markdown rendering + simplify language selection condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sendMarkdownMsg() helper: sends with ParseMode=Markdown, falls back to plain text - All formatted messages (langSelectionMsg, buildSetupGuide, helpMessage) now render bold text and code blocks correctly in Telegram - Simplify /start language check: isLangDefault(st) alone is sufficient (lang == 'en' && isLangDefault was redundant — GetLanguage returns 'en' when empty) --- telegram/bot.go | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/telegram/bot.go b/telegram/bot.go index 24cbccfe..c608b671 100644 --- a/telegram/bot.go +++ b/telegram/bot.go @@ -122,9 +122,9 @@ func runBot(token string, cfg *config.Config, st *store.Store) bool { if lang != "" { awaitingLang = false st.TelegramConfig().SetLanguage(lang) //nolint:errcheck - sendMsg(bot, chatID, buildSetupGuide(st, botUserID, cfg.APIServerPort, botToken, lang)) + sendMarkdownMsg(bot, chatID, buildSetupGuide(st, botUserID, cfg.APIServerPort, botToken, lang)) } else { - sendMsg(bot, chatID, langSelectionMsg()) + sendMarkdownMsg(bot, chatID, langSelectionMsg()) } continue } @@ -146,14 +146,13 @@ func runBot(token string, cfg *config.Config, st *store.Store) bool { } else { agents.Reset(chatID) } - // Show language selection if not chosen yet; otherwise go straight to guide. - lang := st.TelegramConfig().GetLanguage() - if lang == "en" && isLangDefault(st) { - // First time: ask language preference + // Show language selection if user has never chosen (Language == ""); go straight to guide otherwise. + if isLangDefault(st) { awaitingLang = true - sendMsg(bot, chatID, langSelectionMsg()) + sendMarkdownMsg(bot, chatID, langSelectionMsg()) } else { - sendMsg(bot, chatID, buildSetupGuide(st, botUserID, cfg.APIServerPort, botToken, lang)) + lang := st.TelegramConfig().GetLanguage() + sendMarkdownMsg(bot, chatID, buildSetupGuide(st, botUserID, cfg.APIServerPort, botToken, lang)) } continue } @@ -161,14 +160,14 @@ func runBot(token string, cfg *config.Config, st *store.Store) bool { // Handle /lang: change language at any time if text == "/lang" { awaitingLang = true - sendMsg(bot, chatID, langSelectionMsg()) + sendMarkdownMsg(bot, chatID, langSelectionMsg()) continue } // Handle /help if text == "/help" { lang := st.TelegramConfig().GetLanguage() - sendMsg(bot, chatID, helpMessage(lang)) + sendMarkdownMsg(bot, chatID, helpMessage(lang)) continue } @@ -188,13 +187,13 @@ func runBot(token string, cfg *config.Config, st *store.Store) bool { // Direct setup commands (no LLM needed): "configure deepseek sk-xxx" / "配置 deepseek sk-xxx" lang := st.TelegramConfig().GetLanguage() if reply, handled := tryHandleSetupCommand(text, cfg.APIServerPort, botToken, st, botUserID, lang); handled { - sendMsg(bot, chatID, reply) + sendMarkdownMsg(bot, chatID, reply) continue } // Guard: if no AI model configured, show setup guide instead of failing. if newLLMClient(st, botUserID) == nil { - sendMsg(bot, chatID, buildSetupGuide(st, botUserID, cfg.APIServerPort, botToken, lang)) + sendMarkdownMsg(bot, chatID, buildSetupGuide(st, botUserID, cfg.APIServerPort, botToken, lang)) continue } @@ -259,6 +258,17 @@ func sendMsg(bot *tgbotapi.BotAPI, chatID int64, text string) { bot.Send(msg) //nolint:errcheck } +// sendMarkdownMsg sends a message with Markdown formatting; falls back to plain text on parse error. +func sendMarkdownMsg(bot *tgbotapi.BotAPI, chatID int64, text string) { + msg := tgbotapi.NewMessage(chatID, text) + msg.ParseMode = "Markdown" + if _, err := bot.Send(msg); err != nil { + // Markdown rejected (e.g. unescaped special chars) — fall back to plain text. + plain := tgbotapi.NewMessage(chatID, text) + bot.Send(plain) //nolint:errcheck + } +} + // newLLMClient builds an LLM client for the agent using the bound user's enabled model. // Priority: bound user's DB model > environment variables. // Uses provider-specific constructors to ensure correct default base URLs and models.