feat: goose serve (#8209)
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -4453,7 +4453,6 @@ dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"clap",
|
||||
"fs-err",
|
||||
"futures",
|
||||
"goose",
|
||||
@@ -4475,7 +4474,6 @@ dependencies = [
|
||||
"tokio-util",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"uuid",
|
||||
"wiremock",
|
||||
@@ -4496,6 +4494,7 @@ dependencies = [
|
||||
"anstream 0.6.21",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64 0.22.1",
|
||||
"bat",
|
||||
"bzip2",
|
||||
|
||||
@@ -7,10 +7,6 @@ license.workspace = true
|
||||
repository.workspace = true
|
||||
description.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "goose-acp-server"
|
||||
path = "src/bin/server.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "generate-acp-schema"
|
||||
path = "src/bin/generate_acp_schema.rs"
|
||||
@@ -44,10 +40,8 @@ url = { workspace = true }
|
||||
|
||||
# HTTP server dependencies
|
||||
axum = { workspace = true, features = ["ws"] }
|
||||
clap = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tower-http = { workspace = true, features = ["cors"] }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
|
||||
async-stream = { workspace = true }
|
||||
http-body-util = "0.1.3"
|
||||
uuid = { workspace = true, features = ["v7"] }
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use goose::builtin_extension::register_builtin_extensions;
|
||||
use goose::config::paths::Paths;
|
||||
use goose_acp::server_factory::{AcpServer, AcpServerFactoryConfig};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use tracing::info;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "goose-acp-server")]
|
||||
#[command(about = "ACP server for goose over HTTP and WebSocket")]
|
||||
struct Cli {
|
||||
#[arg(long, default_value = "127.0.0.1")]
|
||||
host: String,
|
||||
|
||||
#[arg(long, default_value = "3284")]
|
||||
port: u16,
|
||||
|
||||
#[arg(long = "builtin", action = clap::ArgAction::Append)]
|
||||
builtins: Vec<String>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
|
||||
tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
.with(tracing_subscriber::fmt::layer().with_target(true))
|
||||
.init();
|
||||
|
||||
register_builtin_extensions(goose_mcp::BUILTIN_EXTENSIONS.clone());
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
let builtins = if cli.builtins.is_empty() {
|
||||
vec!["developer".to_string()]
|
||||
} else {
|
||||
cli.builtins
|
||||
};
|
||||
|
||||
let server = Arc::new(AcpServer::new(AcpServerFactoryConfig {
|
||||
builtins,
|
||||
data_dir: Paths::data_dir(),
|
||||
config_dir: Paths::config_dir(),
|
||||
}));
|
||||
let router = goose_acp::transport::create_router(server);
|
||||
|
||||
let addr: SocketAddr = format!("{}:{}", cli.host, cli.port).parse()?;
|
||||
info!("Starting goose-acp-server on {}", addr);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(addr).await?;
|
||||
axum::serve(listener, router).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -63,6 +63,7 @@ clap_complete = "4.5.62"
|
||||
comfy-table = "7.2.2"
|
||||
sha2 = { workspace = true }
|
||||
sigstore-verify = { version = "0.6", default-features = false }
|
||||
axum.workspace = true
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { workspace = true }
|
||||
|
||||
@@ -732,6 +732,26 @@ enum Command {
|
||||
builtins: Vec<String>,
|
||||
},
|
||||
|
||||
/// Start ACP server over HTTP and WebSocket
|
||||
#[command(about = "Start ACP server over HTTP and WebSocket")]
|
||||
Serve {
|
||||
#[arg(long, default_value = "127.0.0.1")]
|
||||
host: String,
|
||||
|
||||
#[arg(long, default_value = "3284")]
|
||||
port: u16,
|
||||
|
||||
#[arg(
|
||||
long = "with-builtin",
|
||||
value_name = "NAME",
|
||||
help = "Add builtin extensions by name (e.g., 'developer' or multiple: 'developer,github')",
|
||||
long_help = "Add one or more builtin extensions that are bundled with goose by specifying their names, comma-separated",
|
||||
value_delimiter = ',',
|
||||
action = clap::ArgAction::Append
|
||||
)]
|
||||
builtins: Vec<String>,
|
||||
},
|
||||
|
||||
/// Start or resume interactive chat sessions
|
||||
#[command(
|
||||
about = "Start or resume interactive chat sessions",
|
||||
@@ -1009,6 +1029,7 @@ fn get_command_name(command: &Option<Command>) -> &'static str {
|
||||
Some(Command::Info { .. }) => "info",
|
||||
Some(Command::Mcp { .. }) => "mcp",
|
||||
Some(Command::Acp { .. }) => "acp",
|
||||
Some(Command::Serve { .. }) => "serve",
|
||||
Some(Command::Session { .. }) => "session",
|
||||
Some(Command::Project {}) => "project",
|
||||
Some(Command::Projects) => "projects",
|
||||
@@ -1038,6 +1059,35 @@ async fn handle_mcp_command(server: McpCommand) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_serve_command(host: String, port: u16, builtins: Vec<String>) -> Result<()> {
|
||||
use goose::config::paths::Paths;
|
||||
use goose_acp::server_factory::{AcpServer, AcpServerFactoryConfig};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use tracing::info;
|
||||
|
||||
let builtins = if builtins.is_empty() {
|
||||
vec!["developer".to_string()]
|
||||
} else {
|
||||
builtins
|
||||
};
|
||||
|
||||
let server = Arc::new(AcpServer::new(AcpServerFactoryConfig {
|
||||
builtins,
|
||||
data_dir: Paths::data_dir(),
|
||||
config_dir: Paths::config_dir(),
|
||||
}));
|
||||
let router = goose_acp::transport::create_router(server);
|
||||
|
||||
let addr: SocketAddr = format!("{}:{}", host, port).parse()?;
|
||||
info!("Starting ACP server on {}", addr);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(addr).await?;
|
||||
axum::serve(listener, router).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_session_subcommand(command: SessionCommand) -> Result<()> {
|
||||
match command {
|
||||
SessionCommand::List {
|
||||
@@ -1708,6 +1758,11 @@ pub async fn cli() -> anyhow::Result<()> {
|
||||
Some(Command::Info { verbose }) => handle_info(verbose),
|
||||
Some(Command::Mcp { server }) => handle_mcp_command(server).await,
|
||||
Some(Command::Acp { builtins }) => goose_acp::server::run(builtins).await,
|
||||
Some(Command::Serve {
|
||||
host,
|
||||
port,
|
||||
builtins,
|
||||
}) => handle_serve_command(host, port, builtins).await,
|
||||
Some(Command::Session {
|
||||
command: Some(cmd), ..
|
||||
}) => handle_session_subcommand(cmd).await,
|
||||
|
||||
Reference in New Issue
Block a user