From 42dec1ddd4e83957ad4c6747067eb6e8351d3a4d Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Sat, 13 Dec 2025 00:54:36 -0500 Subject: telegram: intelligent group response (LLM decides when to speak) - Remove mention-based filtering, bot sees all group messages - Add response rules to system prompt for group chats: - tool invocation = always respond - direct question = respond - factual correction = maybe respond - casual banter = stay silent - Empty response in group = intentional silence (no fallback msg) - Add chat type context to system prompt --- Omni/Agent/Telegram.hs | 57 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 22 deletions(-) (limited to 'Omni') diff --git a/Omni/Agent/Telegram.hs b/Omni/Agent/Telegram.hs index ffad4c7..f8afcb7 100644 --- a/Omni/Agent/Telegram.hs +++ b/Omni/Agent/Telegram.hs @@ -151,9 +151,21 @@ telegramSystemPrompt = "", "use the 'recall' tool to search your memory for relevant context when needed.", "", + "## when to respond (GROUP CHATS)", + "", + "you see all messages in the group. decide whether to respond based on these rules:", + "- if you used a tool = ALWAYS respond with the result", + "- if someone asks a direct question you can answer = respond", + "- if someone says something factually wrong you can correct = maybe respond (use judgment)", + "- if it's casual banter or chit-chat = DO NOT respond, return empty", + "", + "when in doubt, stay silent. you don't need to participate in every conversation.", + "if you choose not to respond, return an empty message (just don't say anything).", + "", "## important", "", - "ALWAYS include a text response to the user after using tools. never end your turn with only tool calls." + "in private chats, ALWAYS respond. in group chats, follow the rules above.", + "when you DO respond, include a text response after using tools." ] getUpdates :: Types.TelegramConfig -> Int -> IO [Types.TelegramMessage] @@ -288,24 +300,18 @@ handleMessage :: Text -> Types.TelegramMessage -> IO () -handleMessage tgConfig provider engineCfg botUsername msg = do +handleMessage tgConfig provider engineCfg _botUsername msg = do let userName = Types.tmUserFirstName msg <> maybe "" (" " <>) (Types.tmUserLastName msg) chatId = Types.tmChatId msg usrId = Types.tmUserId msg - unless (Types.shouldRespondInGroup botUsername msg) <| do - when (Types.isGroupChat msg) - <| putText - <| "Ignoring group message (not mentioned): " - <> Text.take 50 (Types.tmText msg) - unless (Types.isUserAllowed tgConfig usrId) <| do putText <| "Unauthorized user: " <> tshow usrId <> " (" <> userName <> ")" sendMessage tgConfig chatId "sorry, you're not authorized to use this bot." - when (Types.shouldRespondInGroup botUsername msg && Types.isUserAllowed tgConfig usrId) <| do + when (Types.isUserAllowed tgConfig usrId) <| do sendTypingAction tgConfig chatId user <- Memory.getOrCreateUserByTelegramId usrId userName @@ -440,10 +446,15 @@ handleAuthorizedMessage tgConfig provider engineCfg msg uid userName chatId = do let localTime = utcToLocalTime tz now timeStr = Text.pack (formatTime defaultTimeLocale "%A, %B %d, %Y at %H:%M" localTime) - let systemPrompt = + let chatContext = + if Types.isGroupChat msg + then "\n\n## Chat Type\nThis is a GROUP CHAT. Apply the group response rules - only respond if appropriate." + else "\n\n## Chat Type\nThis is a PRIVATE CHAT. Always respond to the user." + systemPrompt = telegramSystemPrompt <> "\n\n## Current Date and Time\n" <> timeStr + <> chatContext <> "\n\n## Current User\n" <> "You are talking to: " <> userName @@ -505,18 +516,20 @@ handleAuthorizedMessage tgConfig provider engineCfg msg uid userName chatId = do if Text.null response then do - putText "Warning: empty response from agent" - sendMessage tgConfig chatId "hmm, i don't have a response for that" - else sendMessage tgConfig chatId response - - checkAndSummarize (Types.tgOpenRouterApiKey tgConfig) uid chatId - - putText - <| "Responded to " - <> userName - <> " (cost: " - <> tshow (Engine.resultTotalCost agentResult) - <> " cents)" + if Types.isGroupChat msg + then putText "Agent chose not to respond (group chat)" + else do + putText "Warning: empty response from agent" + sendMessage tgConfig chatId "hmm, i don't have a response for that" + else do + sendMessage tgConfig chatId response + checkAndSummarize (Types.tgOpenRouterApiKey tgConfig) uid chatId + putText + <| "Responded to " + <> userName + <> " (cost: " + <> tshow (Engine.resultTotalCost agentResult) + <> " cents)" maxConversationTokens :: Int maxConversationTokens = 4000 -- cgit v1.2.3