feat: gateway to chat to goose - telegram etc (#7199)

This commit is contained in:
Michael Neale
2026-02-25 17:49:55 +11:00
committed by GitHub
parent d1f4dc947d
commit 19dc192efe
25 changed files with 2794 additions and 18 deletions
+60
View File
@@ -592,6 +592,37 @@ enum SchedulerCommand {
CronHelp {},
}
#[derive(Subcommand)]
enum GatewayCommand {
#[command(about = "Show gateway status")]
Status {},
#[command(about = "Start a gateway")]
Start {
#[arg(help = "Gateway type (e.g., 'telegram')")]
gateway_type: String,
#[arg(
long = "bot-token",
help = "Bot token for the gateway platform",
long_help = "Authentication token for the gateway platform (e.g., Telegram bot token)"
)]
bot_token: String,
},
#[command(about = "Stop a running gateway")]
Stop {
#[arg(help = "Gateway type to stop (e.g., 'telegram')")]
gateway_type: String,
},
#[command(about = "Generate a pairing code for a gateway")]
Pair {
#[arg(help = "Gateway type to generate pairing code for")]
gateway_type: String,
},
}
#[derive(Subcommand)]
enum RecipeCommand {
/// Validate a recipe file
@@ -785,6 +816,16 @@ enum Command {
command: SchedulerCommand,
},
/// Manage gateways for external platform integrations (e.g., Telegram)
#[command(
about = "Manage gateways for external platform integrations",
visible_alias = "gw"
)]
Gateway {
#[command(subcommand)]
command: GatewayCommand,
},
/// Update the goose CLI version
#[command(about = "Update the goose CLI version")]
Update {
@@ -998,6 +1039,7 @@ fn get_command_name(command: &Option<Command>) -> &'static str {
Some(Command::Project {}) => "project",
Some(Command::Projects) => "projects",
Some(Command::Run { .. }) => "run",
Some(Command::Gateway { .. }) => "gateway",
Some(Command::Schedule { .. }) => "schedule",
Some(Command::Update { .. }) => "update",
Some(Command::Recipe { .. }) => "recipe",
@@ -1390,6 +1432,23 @@ async fn handle_run_command(
}
}
async fn handle_gateway_command(command: GatewayCommand) -> Result<()> {
use crate::commands::gateway;
match command {
GatewayCommand::Status {} => gateway::handle_gateway_status().await,
GatewayCommand::Start {
gateway_type,
bot_token,
} => {
let platform_config = serde_json::json!({ "bot_token": bot_token });
gateway::handle_gateway_start(gateway_type, platform_config).await
}
GatewayCommand::Stop { gateway_type } => gateway::handle_gateway_stop(gateway_type).await,
GatewayCommand::Pair { gateway_type } => gateway::handle_gateway_pair(gateway_type).await,
}
}
async fn handle_schedule_command(command: SchedulerCommand) -> Result<()> {
match command {
SchedulerCommand::Add {
@@ -1714,6 +1773,7 @@ pub async fn cli() -> anyhow::Result<()> {
)
.await
}
Some(Command::Gateway { command }) => handle_gateway_command(command).await,
Some(Command::Schedule { command }) => handle_schedule_command(command).await,
Some(Command::Update {
canary,
+82
View File
@@ -0,0 +1,82 @@
use anyhow::Result;
use goose::execution::manager::AgentManager;
use goose::gateway::manager::GatewayManager;
use std::sync::Arc;
pub async fn handle_gateway_status() -> Result<()> {
let agent_manager = AgentManager::instance().await?;
let gateway_manager = Arc::new(GatewayManager::new(agent_manager)?);
let statuses = gateway_manager.status().await;
if statuses.is_empty() {
println!("No gateways configured.");
return Ok(());
}
for status in statuses {
let state = if status.running { "running" } else { "stopped" };
println!(
"{}: {} ({} paired users)",
status.gateway_type,
state,
status.paired_users.len()
);
for user in &status.paired_users {
println!(
" - {}/{} (session: {})",
user.platform,
user.display_name.as_deref().unwrap_or(&user.user_id),
user.session_id
);
}
}
Ok(())
}
pub async fn handle_gateway_start(
gateway_type: String,
platform_config: serde_json::Value,
) -> Result<()> {
let agent_manager = AgentManager::instance().await?;
let gateway_manager = Arc::new(GatewayManager::new(agent_manager)?);
let mut config = goose::gateway::GatewayConfig {
gateway_type,
platform_config,
max_sessions: 0,
};
let gw = goose::gateway::create_gateway(&mut config)?;
gateway_manager.start_gateway(config, gw).await?;
println!("Gateway started. Press Ctrl+C to stop.");
tokio::signal::ctrl_c().await?;
gateway_manager.stop_all().await;
Ok(())
}
pub async fn handle_gateway_stop(gateway_type: String) -> Result<()> {
let agent_manager = AgentManager::instance().await?;
let gateway_manager = Arc::new(GatewayManager::new(agent_manager)?);
gateway_manager.stop_gateway(&gateway_type).await?;
println!("Gateway '{}' stopped.", gateway_type);
Ok(())
}
pub async fn handle_gateway_pair(gateway_type: String) -> Result<()> {
let agent_manager = AgentManager::instance().await?;
let gateway_manager = Arc::new(GatewayManager::new(agent_manager)?);
let (code, expires_at) = gateway_manager.generate_pairing_code(&gateway_type).await?;
let expires = chrono::DateTime::from_timestamp(expires_at, 0)
.map(|dt| dt.format("%H:%M:%S").to_string())
.unwrap_or_else(|| "unknown".to_string());
println!("Pairing code: {}", code);
println!("Expires at: {}", expires);
Ok(())
}
+1
View File
@@ -1,4 +1,5 @@
pub mod configure;
pub mod gateway;
pub mod info;
pub mod project;
pub mod recipe;