Use capabilities

This commit is contained in:
Jack Amadeo
2026-02-25 11:50:37 -05:00
parent 2554e58dde
commit 23dbed73fa
7 changed files with 78 additions and 28 deletions
-1
View File
@@ -44,7 +44,6 @@ async fn main() -> Result<()> {
builtins,
data_dir: Paths::data_dir(),
config_dir: Paths::config_dir(),
acp_editor_tools: false,
}));
let router = goose_acp::transport::create_router(server);
+33 -11
View File
@@ -1,5 +1,6 @@
use crate::custom_requests::*;
use crate::tools::AcpTools;
use agent_client_protocol_schema::ClientCapabilities;
use anyhow::Result;
use fs_err as fs;
use goose::agents::extension::{Envs, PLATFORM_EXTENSIONS};
@@ -60,7 +61,7 @@ pub struct GooseAcpAgent {
goose_mode: goose::config::GooseMode,
disable_session_naming: bool,
builtins: Vec<String>,
acp_editor_tools: bool,
client_capabilities: Mutex<ClientCapabilities>,
}
fn mcp_server_to_extension_config(mcp_server: McpServer) -> Result<ExtensionConfig, String> {
@@ -306,7 +307,6 @@ impl GooseAcpAgent {
config_dir: std::path::PathBuf,
goose_mode: goose::config::GooseMode,
disable_session_naming: bool,
acp_editor_tools: bool,
) -> Result<Self> {
let session_manager = Arc::new(SessionManager::new(data_dir));
let permission_manager = Arc::new(PermissionManager::new(config_dir.clone()));
@@ -320,7 +320,7 @@ impl GooseAcpAgent {
goose_mode,
disable_session_naming,
builtins,
acp_editor_tools,
client_capabilities: Mutex::new(ClientCapabilities::default()),
})
}
@@ -335,12 +335,19 @@ impl GooseAcpAgent {
));
let agent = Arc::new(agent);
if !self.acp_editor_tools {
let config_path = self.config_dir.join(CONFIG_YAML_NAME);
if let Ok(config_file) = Config::new(&config_path, "goose") {
let extensions = get_enabled_extensions_with_config(&config_file);
add_extensions(&agent, extensions).await;
let exclude_developer = {
let capabilities = self.client_capabilities.lock().await;
capabilities.terminal
|| capabilities.fs.read_text_file
|| capabilities.fs.write_text_file
};
let config_path = self.config_dir.join(CONFIG_YAML_NAME);
if let Ok(config_file) = Config::new(&config_path, "goose") {
let mut extensions = get_enabled_extensions_with_config(&config_file);
if exclude_developer {
extensions.retain(|ext| ext.name() != "developer");
}
add_extensions(&agent, extensions).await;
}
add_builtins(&agent, self.builtins.clone()).await;
@@ -676,6 +683,11 @@ impl GooseAcpAgent {
) -> Result<InitializeResponse, sacp::Error> {
debug!(?args, "initialize request");
{
let mut client_capabilities = self.client_capabilities.lock().await;
*client_capabilities = args.client_capabilities;
}
let capabilities = AgentCapabilities::new()
.load_session(true)
.prompt_capabilities(
@@ -737,11 +749,22 @@ impl GooseAcpAgent {
}
}
if self.acp_editor_tools {
let (fs_read, fs_write, terminal) = {
let capabilities = self.client_capabilities.lock().await;
(
capabilities.fs.read_text_file,
capabilities.fs.write_text_file,
capabilities.terminal,
)
};
if fs_read || fs_write || terminal {
let acp_tools = Arc::new(AcpTools::new(
cx,
SessionId::new(goose_session.id.clone()),
args.cwd.clone(),
fs_read,
fs_write,
terminal,
));
agent
.extension_manager
@@ -1365,7 +1388,7 @@ where
})
}
pub async fn run(builtins: Vec<String>, acp_editor_tools: bool) -> Result<()> {
pub async fn run(builtins: Vec<String>) -> Result<()> {
register_builtin_extensions(goose_mcp::BUILTIN_EXTENSIONS.clone());
info!("listening on stdio");
@@ -1377,7 +1400,6 @@ pub async fn run(builtins: Vec<String>, acp_editor_tools: bool) -> Result<()> {
builtins,
data_dir: Paths::data_dir(),
config_dir: Paths::config_dir(),
acp_editor_tools,
});
let agent = server.create_agent().await?;
serve(agent, incoming, outgoing).await
-2
View File
@@ -9,7 +9,6 @@ pub struct AcpServerFactoryConfig {
pub builtins: Vec<String>,
pub data_dir: std::path::PathBuf,
pub config_dir: std::path::PathBuf,
pub acp_editor_tools: bool,
}
pub struct AcpServer {
@@ -51,7 +50,6 @@ impl AcpServer {
self.config.config_dir.clone(),
goose_mode,
disable_session_naming,
self.config.acp_editor_tools,
)
.await?;
info!("Created new ACP agent");
+44 -4
View File
@@ -18,10 +18,17 @@ use schemars::{schema_for, JsonSchema};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tokio_util::sync::CancellationToken;
struct Capabilities {
filesystem_read: bool,
filesystem_write: bool,
terminal: bool,
}
pub struct AcpTools {
cx: JrConnectionCx<AgentToClient>,
session_id: sacp::schema::SessionId,
working_dir: PathBuf,
capabilities: Capabilities,
}
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
@@ -74,9 +81,11 @@ macro_rules! schema {
};
}
static TOOL_DEFS: LazyLock<Vec<Tool>> = LazyLock::new(|| {
static FILESYSTEM_READ_TOOL_DEFS: LazyLock<Vec<Tool>> =
LazyLock::new(|| vec![Tool::new("read", "Read files", schema!(ReadParams))]);
static FILESYSTEM_WRITE_TOOL_DEFS: LazyLock<Vec<Tool>> = LazyLock::new(|| {
vec![
Tool::new("read", "Read files", schema!(ReadParams)),
Tool::new("write", "Write files", schema!(WriteParams)),
Tool::new(
"str_replace",
@@ -84,10 +93,17 @@ static TOOL_DEFS: LazyLock<Vec<Tool>> = LazyLock::new(|| {
schema!(StrReplaceParams),
),
Tool::new("insert", "Insert strings into files", schema!(InsertParams)),
Tool::new("shell", "Execute shell commands", schema!(ShellParams)),
]
});
static TERMINAL_TOOL_DEFS: LazyLock<Vec<Tool>> = LazyLock::new(|| {
vec![Tool::new(
"shell",
"Execute shell commands",
schema!(ShellParams),
)]
});
async fn handle_tool_call<Req, Fut>(
mut func: impl FnMut(Req) -> Fut,
request: JsonObject,
@@ -149,11 +165,19 @@ impl AcpTools {
cx: JrConnectionCx<AgentToClient>,
session_id: sacp::schema::SessionId,
working_dir: PathBuf,
filesystem_read: bool,
filesystem_write: bool,
terminal: bool,
) -> Self {
AcpTools {
cx,
session_id,
working_dir,
capabilities: Capabilities {
filesystem_read,
filesystem_write,
terminal,
},
}
}
@@ -369,7 +393,23 @@ impl McpClientTrait for AcpTools {
_next_cursor: Option<String>,
_cancel_token: CancellationToken,
) -> Result<ListToolsResult, ServiceError> {
Ok(ListToolsResult::with_all_items(TOOL_DEFS.clone()))
let tools = [
(
self.capabilities.filesystem_read,
&*FILESYSTEM_READ_TOOL_DEFS,
),
(
self.capabilities.filesystem_write,
&*FILESYSTEM_WRITE_TOOL_DEFS,
),
(self.capabilities.terminal, &*TERMINAL_TOOL_DEFS),
]
.into_iter()
.filter(|(enabled, _)| *enabled)
.flat_map(|(_, defs)| defs.clone())
.collect();
Ok(ListToolsResult::with_all_items(tools))
}
async fn call_tool(
@@ -73,7 +73,6 @@ pub async fn run_initialize_without_provider() {
temp_dir.path().to_path_buf(),
GooseMode::Auto,
false,
false,
)
.await
.unwrap(),
-1
View File
@@ -228,7 +228,6 @@ pub async fn spawn_acp_server_in_process(
data_root.to_path_buf(),
goose_mode,
true,
false,
)
.await
.unwrap(),
+1 -8
View File
@@ -691,10 +691,6 @@ enum Command {
value_delimiter = ','
)]
builtins: Vec<String>,
/// Enable ACP editor tools
#[arg(long)]
acp_editor_tools: bool,
},
/// Start or resume interactive chat sessions
@@ -1667,10 +1663,7 @@ pub async fn cli() -> anyhow::Result<()> {
Some(Command::Configure {}) => handle_configure().await,
Some(Command::Info { verbose }) => handle_info(verbose),
Some(Command::Mcp { server }) => handle_mcp_command(server).await,
Some(Command::Acp {
builtins,
acp_editor_tools,
}) => goose_acp::server::run(builtins, acp_editor_tools).await,
Some(Command::Acp { builtins }) => goose_acp::server::run(builtins).await,
Some(Command::Session {
command: Some(cmd), ..
}) => handle_session_subcommand(cmd).await,