pub mod context;
pub mod model;
pub mod sessions;
pub mod tree;
use teloxide::prelude::*;
use teloxide::utils::command::BotCommands;
use crate::bot::handler::HandlerState;
#[derive(BotCommands, Clone, Debug)]
#[command(rename_rule = "lowercase")]
pub enum Command {
#[command(description = "Welcome & session info")]
Start,
#[command(description = "Show usage guide")]
Help,
#[command(description = "Create a new session")]
New,
#[command(description = "List and switch sessions")]
Sessions,
#[command(description = "Resume session in terminal")]
Handback,
#[command(description = "Cancel running operation")]
Abort,
#[command(description = "Re-send last prompt")]
Retry,
#[command(description = "Switch AI model")]
Model,
#[command(description = "View conversation tree")]
Tree,
#[command(description = "Show context window usage")]
Context,
}
pub async fn register_menu(bot: &Bot) -> Result<(), teloxide::RequestError> {
bot.set_my_commands(Command::bot_commands()).await?;
Ok(())
}
pub async fn dispatch(bot: Bot, msg: Message, cmd: Command, state: HandlerState) -> ResponseResult<()> {
match cmd {
Command::Start | Command::Help => {
let user = msg.from.as_ref().map(|u| u.id.0).unwrap_or(0);
if !state.config.is_allowed_user(user) {
bot.send_message(msg.chat.id, "⛔ You are not authorized.").await?;
return Ok(());
}
send_welcome(&bot, &msg, &state).await?;
}
Command::New => sessions::cmd_new(bot, msg, state).await?,
Command::Sessions => sessions::cmd_sessions(bot, msg, state).await?,
Command::Handback => sessions::cmd_handback(bot, msg, state).await?,
Command::Abort => {
crate::bot::handler::abort_handler(bot, msg, state).await?;
}
Command::Retry => {
crate::bot::handler::retry_handler(bot, msg, state).await?;
}
Command::Model => model::cmd_model(bot, msg, state).await?,
Command::Tree => tree::cmd_tree(bot, msg, state).await?,
Command::Context => context::cmd_context(bot, msg, state).await?,
}
Ok(())
}
async fn send_welcome(bot: &Bot, msg: &Message, state: &HandlerState) -> ResponseResult<()> {
let mut text = String::from(
"👋 <b>Welcome to TelePi</b>\n\n\
Telegram bridge for the Pi coding agent.\n\n"
);
let ctx = crate::bot::state::chat_key_to_context(
&crate::bot::state::chat_key(msg.chat.id.0, msg.thread_id.clone())
);
if let Ok(session) = state.sessions.get_or_create(&ctx).await {
let info = session.info();
text.push_str(&format!(
"📌 <b>Current session:</b> <code>{}</code>\n\n",
info.session_id
));
}
text.push_str(
"<b>Commands:</b>\n\
/new — Create a new session\n\
/sessions — List and switch sessions\n\
/handback — Resume session in terminal\n\
/model — Switch AI model\n\
/tree — View conversation tree\n\
/context — Show context window usage\n\
/retry — Re-send last prompt\n\
/abort — Cancel running operation\n\
/help — Show this message\n\n\
Send me a text message, voice note, or photo to interact with Pi."
);
bot.send_message(msg.chat.id, text)
.parse_mode(teloxide::types::ParseMode::Html)
.await?;
Ok(())
}