ralph_telegram/lib.rs
1//! # ralph-telegram
2//!
3//! Telegram integration for human-in-the-loop orchestration in Ralph.
4//!
5//! This crate provides bidirectional communication between AI agents and humans
6//! during orchestration loops via Telegram:
7//!
8//! - **AI → Human**: Agents emit `human.interact` events; the bot sends questions to Telegram
9//! - **Human → AI**: Humans reply or send proactive guidance via Telegram messages
10//!
11//! ## Key Components
12//!
13//! - [`StateManager`] — Persists chat ID, pending questions, and reply routing
14//! - [`MessageHandler`] — Processes incoming messages and writes events to JSONL
15//! - [`TelegramService`] — Lifecycle management for the bot within the event loop
16//! - [`error`] — Error types for startup, send, and receive failures
17
18mod bot;
19pub mod commands;
20pub mod daemon;
21mod error;
22mod handler;
23mod loop_lock;
24mod service;
25mod state;
26
27pub use bot::{BotApi, TelegramBot, escape_html, markdown_to_telegram_html};
28pub use daemon::TelegramDaemon;
29pub use error::{TelegramError, TelegramResult};
30pub use handler::MessageHandler;
31pub use service::{
32 BASE_RETRY_DELAY, CheckinContext, MAX_SEND_RETRIES, TelegramService, retry_with_backoff,
33};
34pub use state::{PendingQuestion, StateManager, TelegramState};
35
36/// Apply an optional custom API URL to a teloxide Bot instance.
37///
38/// Parses the URL and calls `set_api_url` on the bot. Warns on invalid URLs
39/// and returns the bot unchanged.
40pub(crate) fn apply_api_url(mut bot: teloxide::Bot, api_url: Option<&str>) -> teloxide::Bot {
41 if let Some(raw) = api_url {
42 match url::Url::parse(raw) {
43 Ok(parsed) => {
44 bot = bot.set_api_url(parsed);
45 }
46 Err(e) => {
47 tracing::warn!(url = %raw, error = %e, "Invalid Telegram API URL — using default");
48 }
49 }
50 }
51 bot
52}