feat: goose serve (#8209)
This commit is contained in:
Generated
+1
-2
@@ -4453,7 +4453,6 @@ dependencies = [
|
|||||||
"async-stream",
|
"async-stream",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
"clap",
|
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"futures",
|
"futures",
|
||||||
"goose",
|
"goose",
|
||||||
@@ -4475,7 +4474,6 @@ dependencies = [
|
|||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
"wiremock",
|
"wiremock",
|
||||||
@@ -4496,6 +4494,7 @@ dependencies = [
|
|||||||
"anstream 0.6.21",
|
"anstream 0.6.21",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"axum",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bat",
|
"bat",
|
||||||
"bzip2",
|
"bzip2",
|
||||||
|
|||||||
@@ -7,10 +7,6 @@ license.workspace = true
|
|||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
description.workspace = true
|
description.workspace = true
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "goose-acp-server"
|
|
||||||
path = "src/bin/server.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "generate-acp-schema"
|
name = "generate-acp-schema"
|
||||||
path = "src/bin/generate_acp_schema.rs"
|
path = "src/bin/generate_acp_schema.rs"
|
||||||
@@ -44,10 +40,8 @@ url = { workspace = true }
|
|||||||
|
|
||||||
# HTTP server dependencies
|
# HTTP server dependencies
|
||||||
axum = { workspace = true, features = ["ws"] }
|
axum = { workspace = true, features = ["ws"] }
|
||||||
clap = { workspace = true }
|
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
tower-http = { workspace = true, features = ["cors"] }
|
tower-http = { workspace = true, features = ["cors"] }
|
||||||
tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
|
|
||||||
async-stream = { workspace = true }
|
async-stream = { workspace = true }
|
||||||
http-body-util = "0.1.3"
|
http-body-util = "0.1.3"
|
||||||
uuid = { workspace = true, features = ["v7"] }
|
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"
|
comfy-table = "7.2.2"
|
||||||
sha2 = { workspace = true }
|
sha2 = { workspace = true }
|
||||||
sigstore-verify = { version = "0.6", default-features = false }
|
sigstore-verify = { version = "0.6", default-features = false }
|
||||||
|
axum.workspace = true
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { workspace = true }
|
winapi = { workspace = true }
|
||||||
|
|||||||
@@ -732,6 +732,26 @@ enum Command {
|
|||||||
builtins: Vec<String>,
|
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
|
/// Start or resume interactive chat sessions
|
||||||
#[command(
|
#[command(
|
||||||
about = "Start or resume interactive chat sessions",
|
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::Info { .. }) => "info",
|
||||||
Some(Command::Mcp { .. }) => "mcp",
|
Some(Command::Mcp { .. }) => "mcp",
|
||||||
Some(Command::Acp { .. }) => "acp",
|
Some(Command::Acp { .. }) => "acp",
|
||||||
|
Some(Command::Serve { .. }) => "serve",
|
||||||
Some(Command::Session { .. }) => "session",
|
Some(Command::Session { .. }) => "session",
|
||||||
Some(Command::Project {}) => "project",
|
Some(Command::Project {}) => "project",
|
||||||
Some(Command::Projects) => "projects",
|
Some(Command::Projects) => "projects",
|
||||||
@@ -1038,6 +1059,35 @@ async fn handle_mcp_command(server: McpCommand) -> Result<()> {
|
|||||||
Ok(())
|
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<()> {
|
async fn handle_session_subcommand(command: SessionCommand) -> Result<()> {
|
||||||
match command {
|
match command {
|
||||||
SessionCommand::List {
|
SessionCommand::List {
|
||||||
@@ -1708,6 +1758,11 @@ pub async fn cli() -> anyhow::Result<()> {
|
|||||||
Some(Command::Info { verbose }) => handle_info(verbose),
|
Some(Command::Info { verbose }) => handle_info(verbose),
|
||||||
Some(Command::Mcp { server }) => handle_mcp_command(server).await,
|
Some(Command::Mcp { server }) => handle_mcp_command(server).await,
|
||||||
Some(Command::Acp { builtins }) => goose_acp::server::run(builtins).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 {
|
Some(Command::Session {
|
||||||
command: Some(cmd), ..
|
command: Some(cmd), ..
|
||||||
}) => handle_session_subcommand(cmd).await,
|
}) => handle_session_subcommand(cmd).await,
|
||||||
|
|||||||
Reference in New Issue
Block a user