Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/agent_servers/src/agent_servers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod acp;
mod claude;
mod custom;
mod gemini;
mod goose;

#[cfg(any(test, feature = "test-support"))]
pub mod e2e_tests;
Expand All @@ -12,6 +13,7 @@ use collections::HashMap;
pub use custom::*;
use fs::Fs;
pub use gemini::*;
pub use goose::*;
use http_client::read_no_proxy_from_env;
use project::agent_server_store::AgentServerStore;

Expand Down
71 changes: 71 additions & 0 deletions crates/agent_servers/src/goose.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use std::rc::Rc;
use std::{any::Any, path::Path};

use crate::{AgentServer, AgentServerDelegate};
use acp_thread::AgentConnection;
use anyhow::Result;
use gpui::{App, SharedString, Task};

#[derive(Clone)]
pub struct GooseAcp;

impl AgentServer for GooseAcp {
fn telemetry_id(&self) -> &'static str {
"goose-acp"
}

fn name(&self) -> SharedString {
"Goose".into()
}

fn logo(&self) -> ui::IconName {
ui::IconName::Terminal
}

fn connect(
&self,
root_dir: Option<&Path>,
delegate: AgentServerDelegate,
cx: &mut App,
) -> Task<Result<(Rc<dyn AgentConnection>, Option<task::SpawnInTerminal>)>> {
let name = self.name();
let root_dir = root_dir.map(|root_dir| root_dir.to_string_lossy().to_string());
let is_remote = delegate.project.read(cx).is_via_remote_server();
let default_mode = self.default_mode(cx);

cx.spawn(async move |cx| {
// Create a command to run "goose acp"
let command = project::agent_server_store::AgentServerCommand {
path: "goose".into(),
args: vec!["acp".to_string()],
env: None,
};

let root_dir = std::path::PathBuf::from(root_dir.as_deref().unwrap_or("."));

let connection =
crate::acp::connect(name, command, &root_dir, default_mode, is_remote, cx).await?;
Ok((connection, None))
})
}

fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
self
}
}

#[cfg(test)]
pub(crate) mod tests {
use project::agent_server_store::AgentServerCommand;

use super::*;
use std::path::Path;

pub fn local_command() -> AgentServerCommand {
AgentServerCommand {
path: "goose".into(),
args: vec!["acp".to_string()],
env: None,
}
}
}
35 changes: 35 additions & 0 deletions crates/agent_ui/src/agent_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ pub enum AgentType {
TextThread,
Gemini,
ClaudeCode,
GooseAcp,
NativeAgent,
Custom {
name: SharedString,
Expand All @@ -227,6 +228,7 @@ impl AgentType {
Self::NativeAgent => "Agent 2".into(),
Self::Gemini => "Gemini CLI".into(),
Self::ClaudeCode => "Claude Code".into(),
Self::GooseAcp => "Goose".into(),
Self::Custom { name, .. } => name.into(),
}
}
Expand All @@ -236,6 +238,7 @@ impl AgentType {
Self::Zed | Self::NativeAgent | Self::TextThread => None,
Self::Gemini => Some(IconName::AiGemini),
Self::ClaudeCode => Some(IconName::AiClaude),
Self::GooseAcp => Some(IconName::Terminal),
Self::Custom { .. } => Some(IconName::Terminal),
}
}
Expand All @@ -246,6 +249,7 @@ impl From<ExternalAgent> for AgentType {
match value {
ExternalAgent::Gemini => Self::Gemini,
ExternalAgent::ClaudeCode => Self::ClaudeCode,
ExternalAgent::GooseAcp => Self::GooseAcp,
ExternalAgent::Custom { name, command } => Self::Custom { name, command },
ExternalAgent::NativeAgent => Self::NativeAgent,
}
Expand Down Expand Up @@ -1380,6 +1384,11 @@ impl AgentPanel {
cx,
)
}
AgentType::GooseAcp => {
self.selected_agent = AgentType::GooseAcp;
self.serialize(cx);
self.external_thread(Some(crate::ExternalAgent::GooseAcp), None, None, window, cx)
}
AgentType::Custom { name, command } => self.external_thread(
Some(crate::ExternalAgent::Custom { name, command }),
None,
Expand Down Expand Up @@ -1950,6 +1959,32 @@ impl AgentPanel {
}
}),
)
.item(
ContextMenuEntry::new("New Goose Thread")
.icon(IconName::Terminal)
.disabled(is_via_collab)
.icon_color(Color::Muted)
.handler({
let workspace = workspace.clone();
move |window, cx| {
if let Some(workspace) = workspace.upgrade() {
workspace.update(cx, |workspace, cx| {
if let Some(panel) =
workspace.panel::<AgentPanel>(cx)
{
panel.update(cx, |panel, cx| {
panel.new_agent_thread(
AgentType::GooseAcp,
window,
cx,
);
});
}
});
}
}
}),
)
.map(|mut menu| {
let agent_names = agent_server_store
.read(cx)
Expand Down
3 changes: 3 additions & 0 deletions crates/agent_ui/src/agent_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ enum ExternalAgent {
#[default]
Gemini,
ClaudeCode,
GooseAcp,
NativeAgent,
Custom {
name: SharedString,
Expand All @@ -190,6 +191,7 @@ impl ExternalAgent {
Self::NativeAgent => "zed",
Self::Gemini => "gemini-cli",
Self::ClaudeCode => "claude-code",
Self::GooseAcp => "goose-acp",
Self::Custom { .. } => "custom",
}
}
Expand All @@ -202,6 +204,7 @@ impl ExternalAgent {
match self {
Self::Gemini => Rc::new(agent_servers::Gemini),
Self::ClaudeCode => Rc::new(agent_servers::ClaudeCode),
Self::GooseAcp => Rc::new(agent_servers::GooseAcp),
Self::NativeAgent => Rc::new(agent2::NativeAgentServer::new(fs, history)),
Self::Custom { name, command: _ } => {
Rc::new(agent_servers::CustomAgentServer::new(name.clone()))
Expand Down