Documentation
¶
Overview ¶
Package messaging implements VORTEX's messaging integration layer (build plan M11): two-way bots over Telegram, WhatsApp, and Slack, plus a unified notification router and an AI provider gateway. All platform APIs are reached over the standard library's net/http — no SDKs.
This file implements the Telegram Bot API integration.
Index ¶
- Constants
- Variables
- type AIGateway
- type AIGatewayConfig
- type AIProvider
- type ApprovalManager
- type CallbackResolver
- type ClarifyQuestion
- type CommandHooks
- type CostSnapshot
- type NotificationConfig
- type NotificationRule
- type Router
- type Severity
- type SlackBot
- type SlackConfig
- type TelegramBot
- func (t *TelegramBot) HandleWebhook(runtime *agents.Runtime) http.Handler
- func (t *TelegramBot) Poll(ctx context.Context, runtime *agents.Runtime, interval time.Duration)
- func (t *TelegramBot) SendApprovalRequest(ctx context.Context, chatID int64, ...) error
- func (t *TelegramBot) SendClarifyingQuestions(ctx context.Context, chatID int64, session string, qs []ClarifyQuestion) error
- func (t *TelegramBot) SendFile(ctx context.Context, chatID int64, filename string, data []byte, ...) error
- func (t *TelegramBot) SendMessage(ctx context.Context, chatID int64, text string) error
- func (t *TelegramBot) SetCallbackResolver(r CallbackResolver)
- func (t *TelegramBot) SetCommandHooks(h CommandHooks)
- func (t *TelegramBot) SetCommands(ctx context.Context) error
- func (t *TelegramBot) SetWebhook(ctx context.Context, url string) error
- type TelegramConfig
- type WhatsAppBot
- func (wb *WhatsAppBot) HandleWebhook(runtime *agents.Runtime) http.Handler
- func (wb *WhatsAppBot) SendApprovalRequest(ctx context.Context, to, description string) error
- func (wb *WhatsAppBot) SendImage(ctx context.Context, to string, imageData []byte, caption string) error
- func (wb *WhatsAppBot) SendText(ctx context.Context, to, text string) error
- type WhatsAppConfig
Constants ¶
const ( ProviderClaude = "claude" ProviderOpenAI = "openai" ProviderOllama = "ollama" ProviderDeepSeek = "deepseek" ProviderGemini = "gemini" )
Provider names.
const ( ChannelTelegram = "telegram" ChannelWhatsApp = "whatsapp" ChannelSlack = "slack" ChannelEmail = "email" )
Channel names.
const ApprovalTimeout = 10 * time.Minute
ApprovalTimeout is how long an approval request waits for a human response before it is treated as rejected.
Variables ¶
var ErrBudgetExceeded = fmt.Errorf("messaging: daily AI budget exceeded")
ErrBudgetExceeded is returned when the daily cost budget is reached.
Functions ¶
This section is empty.
Types ¶
type AIGateway ¶
type AIGateway struct {
// contains filtered or unexported fields
}
AIGateway routes completion requests across providers in priority order, implementing agents.AIGateway. It tracks token cost and enforces a daily budget.
func NewAIGateway ¶
func NewAIGateway(cfg AIGatewayConfig) (*AIGateway, error)
NewAIGateway builds the gateway. It requires at least one provider and sorts them by ascending priority.
func (*AIGateway) Complete ¶
Complete tries each provider in priority order until one succeeds, returning the response text. It enforces the daily budget before calling out.
func (*AIGateway) Cost ¶
Cost returns the total USD spent today, rolling over (to 0) first if the day boundary has passed since the last activity.
func (*AIGateway) CostToday ¶
func (g *AIGateway) CostToday() CostSnapshot
CostToday returns a snapshot of today's AI spend and budget.
func (*AIGateway) ProviderNames ¶
ProviderNames returns the configured provider names in priority order, for startup logging.
func (*AIGateway) ResetDailyCost ¶
func (g *AIGateway) ResetDailyCost()
ResetDailyCost zeroes today's spend (called at midnight by a supervisor).
type AIGatewayConfig ¶
type AIGatewayConfig struct {
Providers []AIProvider
DefaultModel string
CostPerToken map[string]float64 // model → USD per token (rough)
DailyBudget float64 // USD; 0 = unlimited
Client *http.Client
// contains filtered or unexported fields
}
AIGatewayConfig configures the gateway.
type AIProvider ¶
type AIProvider struct {
Name string // "claude" | "openai" | "ollama"
APIKey string // from env (empty for ollama)
Endpoint string // override base URL; for ollama defaults to localhost:11434
Models []string // available models; Models[0] is used by default
Priority int // lower = preferred
}
AIProvider describes one upstream model provider.
type ApprovalManager ¶
type ApprovalManager struct {
// contains filtered or unexported fields
}
ApprovalManager bridges agent ApprovalRequests to a messaging channel (Telegram) and back: it sends an approve/reject prompt, blocks until the user taps a button or the timeout elapses, and resolves the agents.ApprovalFunc.
func NewApprovalManager ¶
func NewApprovalManager(tg *TelegramBot, chatID int64, timeout time.Duration) *ApprovalManager
NewApprovalManager builds a manager that routes approvals to the given Telegram bot + chat. timeout <= 0 uses ApprovalTimeout.
func (*ApprovalManager) ApprovalFunc ¶
func (m *ApprovalManager) ApprovalFunc() agents.ApprovalFunc
ApprovalFunc returns an agents.ApprovalFunc bound to this manager. It is wired into the coordinator so run_command (and other gated actions) request human sign-off before executing.
func (*ApprovalManager) Resolve ¶
func (m *ApprovalManager) Resolve(callbackData string) bool
Resolve records an approve/reject decision for the approval with the given id (extracted from a Telegram callback_data "approve:<id>" / "reject:<id>"). It returns true if a pending approval matched.
type CallbackResolver ¶
CallbackResolver consumes an inline-button callback. It returns true if the callback was a recognised approval decision (and therefore should not be re-submitted to the agent runtime as a free-form directive). The ApprovalManager implements this.
type ClarifyQuestion ¶
ClarifyQuestion is a structured clarifying question for Telegram buttons.
type CommandHooks ¶
type CommandHooks struct {
Status func() string // /status reply
Routes func() string // /routes reply
Cost func() string // /cost reply
List func(path string) string // /ls reply
Approve func(sessionID string, ok bool) (string, bool) // /approve, /reject
// ClarifySubmit submits a combined clarifying answer for a session (used when
// all option buttons have been tapped).
ClarifySubmit func(sessionID, answer string)
}
CommandHooks supply data for the bot's built-in slash commands. Each is optional; a nil hook yields a "not available" reply. They keep telegram.go decoupled from the api/agents packages (wired in start.go).
type CostSnapshot ¶
type CostSnapshot struct {
Provider string `json:"provider"`
TotalUSD float64 `json:"total_usd"`
RequestsToday int `json:"requests_today"`
DailyBudget float64 `json:"daily_budget"`
RemainingBudget float64 `json:"remaining_budget"`
Free bool `json:"free"`
}
CostSnapshot summarises AI usage for the current day (for /api/ai/cost).
type NotificationConfig ¶
type NotificationConfig struct {
Rules []NotificationRule
Telegram *TelegramBot
WhatsApp *WhatsAppBot
Slack *SlackBot
DefaultChatID int64 // Telegram default recipient
DefaultPhone string // WhatsApp default recipient
}
NotificationConfig configures the router. Any bot may be nil (not configured).
type NotificationRule ¶
NotificationRule maps a severity to the channels it should reach.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router dispatches notifications to configured channels per severity rules.
func (*Router) ConfiguredChannels ¶
ConfiguredChannels returns the names of channels that have a backing bot, for startup logging.
func (*Router) Send ¶
Send dispatches a notification to every channel matching the severity rules, skipping silenced channels. It returns nil when there is nothing to send (no matching rule or no configured channel) and a combined error if any send fails.
type Severity ¶
type Severity string
Severity classifies a notification's importance.
type SlackBot ¶
type SlackBot struct {
// contains filtered or unexported fields
}
SlackBot is a Slack client + slash-command handler.
func NewSlackBot ¶
func NewSlackBot(cfg SlackConfig) (*SlackBot, error)
NewSlackBot constructs the bot.
func (*SlackBot) HandleSlashCommand ¶
HandleSlashCommand returns the http.Handler for POST /webhook/slack. It verifies the Slack signature, parses the slash command, and either submits to the runtime or performs a built-in action. It responds immediately with 200 and an ephemeral acknowledgement; longer results are delivered out of band.
type SlackConfig ¶
type SlackConfig struct {
WebhookURL string // incoming webhook for SendMessage/SendAlert
SigningSecret string // verifies slash-command requests
BotToken string // bot token for Web API (future use)
Client *http.Client
// contains filtered or unexported fields
}
SlackConfig configures the Slack integration (incoming webhook for outbound messages, slash commands for inbound). Secrets come from the environment.
type TelegramBot ¶
type TelegramBot struct {
// contains filtered or unexported fields
}
TelegramBot is a Telegram Bot API client + webhook handler.
func NewTelegramBot ¶
func NewTelegramBot(cfg TelegramConfig) (*TelegramBot, error)
NewTelegramBot constructs a bot. It returns an error if the token is empty.
func (*TelegramBot) HandleWebhook ¶
func (t *TelegramBot) HandleWebhook(runtime *agents.Runtime) http.Handler
HandleWebhook returns an http.Handler that parses Telegram updates, validates the secret token and chat allow-list, submits the message text to the agent runtime, and replies with the response. Inline-button callbacks (approve/ reject) are acknowledged and their data submitted as a directive.
func (*TelegramBot) Poll ¶
Poll runs long-poll mode: every interval it fetches new updates via getUpdates and dispatches them, until ctx is cancelled. No public URL is needed (for local testing). updateID tracks the offset across calls.
func (*TelegramBot) SendApprovalRequest ¶
func (t *TelegramBot) SendApprovalRequest(ctx context.Context, chatID int64, description, approveAction, rejectAction string) error
SendApprovalRequest sends a message with inline approve/reject buttons. The approveAction/rejectAction strings are the callback_data delivered back when the user taps a button (used by the human-in-the-loop flow).
func (*TelegramBot) SendClarifyingQuestions ¶
func (t *TelegramBot) SendClarifyingQuestions(ctx context.Context, chatID int64, session string, qs []ClarifyQuestion) error
SendClarifyingQuestions sends each structured question as a row of inline option buttons (callback_data "clarify:<session>:<key>:<value>"). Questions with no options are sent as plain text (the next text message is the answer). It registers a clarifySession so taps are collected until all are answered.
func (*TelegramBot) SendFile ¶
func (t *TelegramBot) SendFile(ctx context.Context, chatID int64, filename string, data []byte, caption string) error
SendFile uploads a document (APK, PDF, report) to chatID with a caption, using a multipart form (sendDocument).
func (*TelegramBot) SendMessage ¶
SendMessage sends a Markdown text message to chatID.
func (*TelegramBot) SetCallbackResolver ¶
func (t *TelegramBot) SetCallbackResolver(r CallbackResolver)
SetCallbackResolver wires a resolver (e.g. the ApprovalManager) that gets first refusal on inline-button callbacks.
func (*TelegramBot) SetCommandHooks ¶
func (t *TelegramBot) SetCommandHooks(h CommandHooks)
SetCommandHooks wires the built-in command data sources.
func (*TelegramBot) SetCommands ¶
func (t *TelegramBot) SetCommands(ctx context.Context) error
SetCommands registers the bot's command menu (/setMyCommands).
func (*TelegramBot) SetWebhook ¶
func (t *TelegramBot) SetWebhook(ctx context.Context, url string) error
SetWebhook registers the webhook URL with Telegram, including the secret token Telegram will echo back in the X-Telegram-Bot-Api-Secret-Token header.
type TelegramConfig ¶
type TelegramConfig struct {
Token string // bot token (from env)
AllowedIDs []int64 // allowed chat/user IDs; empty means allow none
WebhookURL string // public webhook URL (optional)
SecretToken string // X-Telegram-Bot-Api-Secret-Token expected on webhooks
// BaseURL overrides the Telegram API base (for tests). When empty the real
// https://api.telegram.org/bot<token> is used.
BaseURL string
// Client overrides the HTTP client (for tests / custom timeouts).
Client *http.Client
}
TelegramConfig configures the Telegram bot. The token comes from the environment (VORTEX_TELEGRAM_TOKEN), never from the config file.
type WhatsAppBot ¶
type WhatsAppBot struct {
// contains filtered or unexported fields
}
WhatsAppBot is a WhatsApp Cloud API client + webhook handler.
func NewWhatsAppBot ¶
func NewWhatsAppBot(cfg WhatsAppConfig) (*WhatsAppBot, error)
NewWhatsAppBot constructs the bot. It requires PhoneNumberID and AccessToken.
func (*WhatsAppBot) HandleWebhook ¶
func (wb *WhatsAppBot) HandleWebhook(runtime *agents.Runtime) http.Handler
HandleWebhook returns the http.Handler for the WhatsApp webhook. GET performs Meta's verification handshake; POST verifies the HMAC signature, extracts inbound messages, submits them to the runtime, and replies.
func (*WhatsAppBot) SendApprovalRequest ¶
func (wb *WhatsAppBot) SendApprovalRequest(ctx context.Context, to, description string) error
SendApprovalRequest sends an interactive button message (Approve / Reject) used by the human-in-the-loop flow.
type WhatsAppConfig ¶
type WhatsAppConfig struct {
PhoneNumberID string // from env VORTEX_WA_PHONE_ID
AccessToken string // from env VORTEX_WA_TOKEN
VerifyToken string // webhook GET verification (hub.verify_token)
AppSecret string // for X-Hub-Signature-256 HMAC verification
BaseURL string // override Graph API base (tests)
Client *http.Client
}
WhatsAppConfig configures the WhatsApp Business (Meta Cloud API) bot. The phone-number ID and access token come from the environment, never config.