Skip to content

Commit b92213c

Browse files
committed
telegram: wire daily token budget into production flow
The DailyTokenBudget feature was fully implemented (SetDailyTokenBudget, CheckDailyBudget, config parsing, tests) but never called from production code. This commit wires it in: 1. telegramCmd: Call bot.SetDailyTokenBudget during startup when cfg.DailyTokenBudget > 0 (0 = unlimited, the default) 2. handleChatMessage — pre-flight check: Before creating the agent, call CheckDailyBudget(1) to detect if the budget is already exhausted, avoiding a wasted API call. Sends a clear error message. 3. handleChatMessage — post-run billing: After agent.RunWithMessages, bill actual input+output tokens via CheckDailyBudget. If exceeded, logs a warning and sends a notification to the chat but still delivers the response (the API call already happened). Docs: update TELEGRAM.md to describe pre-flight + post-run billing.
1 parent 834491f commit b92213c

2 files changed

Lines changed: 42 additions & 2 deletions

File tree

cmd/odek/telegram.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ func telegramCmd(args []string) error {
6868
bot.SetFallbackURLs(cfg.FallbackURLs)
6969
}
7070

71+
// 4d. Configure daily token budget (0 = unlimited, the default).
72+
if cfg.DailyTokenBudget > 0 {
73+
bot.SetDailyTokenBudget(cfg.DailyTokenBudget)
74+
botLog.Info("daily token budget set", "budget", cfg.DailyTokenBudget)
75+
}
76+
7177
// 5. Create session store on disk (~/.odek/sessions/).
7278
store, err := session.NewStore()
7379
if err != nil {
@@ -434,6 +440,21 @@ func handleChatMessage(
434440

435441
rend := render.New(os.Stderr, false).WithModel(modelLabel)
436442

443+
// ── Pre-flight budget check ────────────────────────────────────
444+
// Before running the agent, check if the daily budget is already
445+
// exhausted — avoids burning an API call just to be rejected.
446+
if resolved.Telegram.DailyTokenBudget > 0 {
447+
if err := bot.CheckDailyBudget(1); err != nil {
448+
reportError(bot, chatID, fmt.Sprintf(
449+
"Daily token budget exhausted: %v. "+
450+
"The budget resets at midnight UTC. "+
451+
"Set daily_token_budget to 0 in config for unlimited usage.",
452+
err,
453+
))
454+
return
455+
}
456+
}
457+
437458
// ── Typing Indicator ────────────────────────────────────────────
438459
// Send "typing" action every 4s while the agent runs (Telegram shows
439460
// it for ~5s). Fire-and-forget so a hanging HTTP call doesn't block
@@ -584,6 +605,22 @@ func handleChatMessage(
584605
return
585606
}
586607

608+
// Bill actual token usage against daily budget (if configured).
609+
tokensUsed := int64(runInfo.InputTokens + runInfo.OutputTokens)
610+
if tokensUsed > 0 {
611+
if err := bot.CheckDailyBudget(tokensUsed); err != nil {
612+
// Budget exceeded — report it but still deliver the response.
613+
log.Warn("daily token budget exceeded",
614+
"chat_id", chatID, "tokens", tokensUsed, "error", err)
615+
bot.SendMessage(chatID, fmt.Sprintf(
616+
"⚠️ *Token budget warning*\\n\\n%v\\n\\n"+
617+
"Further agent runs may be blocked until the daily budget resets. "+
618+
"Use `/stats` to check current usage.",
619+
err,
620+
), &telegram.SendOpts{ParseMode: telegram.ParseModeMarkdownV2})
621+
}
622+
}
623+
587624
// Save the updated session messages.
588625
cs.Messages = updatedMessages
589626
cs.TurnCount++

docs/TELEGRAM.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,11 @@ The `Bot` struct is a lightweight Telegram Bot API client built on the standard
8787
`SetDailyTokenBudget` and `CheckDailyBudget` implement a simple daily token usage tracker:
8888
- Usage is persisted to `~/.odek/telegram_token_usage_<YYYY-MM-DD>`
8989
- Budget resets automatically each calendar day
90-
- Returns an error if the total exceeds the configured budget
91-
- No-op when budget is 0 (unlimited)
90+
- **Pre-flight check**: before each agent run, a lightweight check verifies the budget isn't already exhausted, avoiding wasted API calls
91+
- **Post-run billing**: after each agent run, actual token usage (`input + output`) is deducted from the daily budget
92+
- Returns a warning message to the chat if the budget is exceeded, but still delivers the response
93+
- No-op when budget is 0 (unlimited, the default)
94+
- Configurable via `ODEK_TELEGRAM_DAILY_TOKEN_BUDGET` env var or `daily_token_budget` in `odek.json`
9295

9396
## Long-Polling (`poller.go`)
9497

0 commit comments

Comments
 (0)