diff options
| author | Ben Sima <ben@bensima.com> | 2025-12-13 22:01:49 -0500 |
|---|---|---|
| committer | Ben Sima <ben@bensima.com> | 2025-12-13 22:01:49 -0500 |
| commit | 23edd144ed952802f9ea0fd1103a1e83db916b89 (patch) | |
| tree | 9f36979a654d5be69570ecbda2c79801968d786b /Omni/Agent/Telegram.hs | |
| parent | fe5e8064a4f7311c8e3fe6eb4d9e95d16e1d0250 (diff) | |
Add hledger tools to Telegram bot
- New Omni/Agent/Tools/Hledger.hs with 5 tools:
- hledger_balance: query account balances
- hledger_register: show transaction history
- hledger_add: create new transactions
- hledger_income_statement: income vs expenses
- hledger_balance_sheet: net worth view
- All tools support currency parameter (default: USD)
- Balance, register, income_statement support period parameter
- Period uses hledger syntax (thismonth, 2024, from X to Y)
- Shell escaping fixed for multi-word period strings
- Authorization: only Ben and Kate get hledger tools
- Max iterations increased from 5 to 10
- Transactions written to ~/fund/telegram-transactions.journal
Diffstat (limited to 'Omni/Agent/Telegram.hs')
| -rw-r--r-- | Omni/Agent/Telegram.hs | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/Omni/Agent/Telegram.hs b/Omni/Agent/Telegram.hs index 148bb6a..977e590 100644 --- a/Omni/Agent/Telegram.hs +++ b/Omni/Agent/Telegram.hs @@ -86,6 +86,7 @@ import qualified Omni.Agent.Telegram.Messages as Messages import qualified Omni.Agent.Telegram.Reminders as Reminders import qualified Omni.Agent.Telegram.Types as Types import qualified Omni.Agent.Tools.Calendar as Calendar +import qualified Omni.Agent.Tools.Hledger as Hledger import qualified Omni.Agent.Tools.Notes as Notes import qualified Omni.Agent.Tools.Pdf as Pdf import qualified Omni.Agent.Tools.Todos as Todos @@ -827,11 +828,27 @@ processEngagedMessage tgConfig provider engineCfg msg uid userName chatId userMe 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." + hledgerContext = + if isHledgerAuthorized userName + then + Text.unlines + [ "", + "## hledger (personal finance)", + "", + "you have access to hledger tools for querying and recording financial transactions.", + "account naming: ex (expenses), as (assets), li (liabilities), in (income), eq (equity).", + "level 2 is owner: 'me' (personal) or 'us' (shared/family).", + "level 3 is type: need (necessary), want (discretionary), cash, cred (credit), vest (investments).", + "examples: ex:me:want:grooming, as:us:cash:checking, li:us:cred:chase.", + "when user says 'i spent $X at Y', use hledger_add with appropriate accounts." + ] + else "" systemPrompt = telegramSystemPrompt <> "\n\n## Current Date and Time\n" <> timeStr <> chatContext + <> hledgerContext <> "\n\n## Current User\n" <> "You are talking to: " <> userName @@ -872,13 +889,17 @@ processEngagedMessage tgConfig provider engineCfg msg uid userName chatId userMe Messages.listPendingMessagesTool uid chatId, Messages.cancelMessageTool ] - tools = memoryTools <> searchTools <> webReaderTools <> pdfTools <> notesTools <> calendarTools <> todoTools <> messageTools + hledgerTools = + if isHledgerAuthorized userName + then Hledger.allHledgerTools + else [] + tools = memoryTools <> searchTools <> webReaderTools <> pdfTools <> notesTools <> calendarTools <> todoTools <> messageTools <> hledgerTools let agentCfg = Engine.defaultAgentConfig { Engine.agentSystemPrompt = systemPrompt, Engine.agentTools = tools, - Engine.agentMaxIterations = 5, + Engine.agentMaxIterations = 10, Engine.agentGuardrails = Engine.defaultGuardrails { Engine.guardrailMaxCostCents = 10.0, @@ -930,6 +951,11 @@ maxConversationTokens = 4000 summarizationThreshold :: Int summarizationThreshold = 3000 +isHledgerAuthorized :: Text -> Bool +isHledgerAuthorized userName = + let lowerName = Text.toLower userName + in "ben" `Text.isInfixOf` lowerName || "kate" `Text.isInfixOf` lowerName + checkAndSummarize :: Text -> Text -> Int -> IO () checkAndSummarize openRouterKey uid chatId = do (_, currentTokens) <- Memory.getConversationContext uid chatId maxConversationTokens |
