Closes: https://github.com/zed-industries/zed/issues/37089 Instead of looking for the gemini command on `$PATH`, by default we'll install our own copy on demand under our data dir, as we already do for language servers and debug adapters. This also means we can handle keeping the binary up to date instead of prompting the user to upgrade. Notes: - The download is only triggered if you open a new Gemini thread - Custom commands from `agent_servers.gemini` in settings are respected as before - A new `agent_servers.gemini.ignore_system_version` setting is added, similar to the existing settings for language servers. It's `true` by default, and setting it to `false` disables the automatic download and makes Zed search `$PATH` as before. - If `agent_servers.gemini.ignore_system_version` is `false` and no binary is found on `$PATH`, we'll fall back to automatic installation. If it's `false` and a binary is found, but the version is older than v0.2.1, we'll show an error. Release Notes: - acp: By default, Zed will now download and use a private copy of the Gemini CLI binary, instead of searching your `$PATH`. To make Zed search your `$PATH` for Gemini CLI before attempting to download it, use the following setting: ``` { "agent_servers": { "gemini": { "ignore_system_version": false } } } ```
120 lines
3.5 KiB
Rust
120 lines
3.5 KiB
Rust
use std::{any::Any, path::Path, rc::Rc, sync::Arc};
|
|
|
|
use agent_servers::{AgentServer, AgentServerDelegate};
|
|
use anyhow::Result;
|
|
use fs::Fs;
|
|
use gpui::{App, Entity, SharedString, Task};
|
|
use prompt_store::PromptStore;
|
|
|
|
use crate::{HistoryStore, NativeAgent, NativeAgentConnection, templates::Templates};
|
|
|
|
#[derive(Clone)]
|
|
pub struct NativeAgentServer {
|
|
fs: Arc<dyn Fs>,
|
|
history: Entity<HistoryStore>,
|
|
}
|
|
|
|
impl NativeAgentServer {
|
|
pub fn new(fs: Arc<dyn Fs>, history: Entity<HistoryStore>) -> Self {
|
|
Self { fs, history }
|
|
}
|
|
}
|
|
|
|
impl AgentServer for NativeAgentServer {
|
|
fn telemetry_id(&self) -> &'static str {
|
|
"zed"
|
|
}
|
|
|
|
fn name(&self) -> SharedString {
|
|
"Zed Agent".into()
|
|
}
|
|
|
|
fn logo(&self) -> ui::IconName {
|
|
ui::IconName::ZedAgent
|
|
}
|
|
|
|
fn connect(
|
|
&self,
|
|
_root_dir: &Path,
|
|
delegate: AgentServerDelegate,
|
|
cx: &mut App,
|
|
) -> Task<Result<Rc<dyn acp_thread::AgentConnection>>> {
|
|
log::debug!(
|
|
"NativeAgentServer::connect called for path: {:?}",
|
|
_root_dir
|
|
);
|
|
let project = delegate.project().clone();
|
|
let fs = self.fs.clone();
|
|
let history = self.history.clone();
|
|
let prompt_store = PromptStore::global(cx);
|
|
cx.spawn(async move |cx| {
|
|
log::debug!("Creating templates for native agent");
|
|
let templates = Templates::new();
|
|
let prompt_store = prompt_store.await?;
|
|
|
|
log::debug!("Creating native agent entity");
|
|
let agent =
|
|
NativeAgent::new(project, history, templates, Some(prompt_store), fs, cx).await?;
|
|
|
|
// Create the connection wrapper
|
|
let connection = NativeAgentConnection(agent);
|
|
log::debug!("NativeAgentServer connection established successfully");
|
|
|
|
Ok(Rc::new(connection) as Rc<dyn acp_thread::AgentConnection>)
|
|
})
|
|
}
|
|
|
|
fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
|
|
self
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
use assistant_context::ContextStore;
|
|
use gpui::AppContext;
|
|
|
|
agent_servers::e2e_tests::common_e2e_tests!(
|
|
async |fs, project, cx| {
|
|
let auth = cx.update(|cx| {
|
|
prompt_store::init(cx);
|
|
terminal::init(cx);
|
|
|
|
let registry = language_model::LanguageModelRegistry::read_global(cx);
|
|
let auth = registry
|
|
.provider(&language_model::ANTHROPIC_PROVIDER_ID)
|
|
.unwrap()
|
|
.authenticate(cx);
|
|
|
|
cx.spawn(async move |_| auth.await)
|
|
});
|
|
|
|
auth.await.unwrap();
|
|
|
|
cx.update(|cx| {
|
|
let registry = language_model::LanguageModelRegistry::global(cx);
|
|
|
|
registry.update(cx, |registry, cx| {
|
|
registry.select_default_model(
|
|
Some(&language_model::SelectedModel {
|
|
provider: language_model::ANTHROPIC_PROVIDER_ID,
|
|
model: language_model::LanguageModelId("claude-sonnet-4-latest".into()),
|
|
}),
|
|
cx,
|
|
);
|
|
});
|
|
});
|
|
|
|
let history = cx.update(|cx| {
|
|
let context_store = cx.new(move |cx| ContextStore::fake(project.clone(), cx));
|
|
cx.new(move |cx| HistoryStore::new(context_store, cx))
|
|
});
|
|
|
|
NativeAgentServer::new(fs.clone(), history)
|
|
},
|
|
allow_option_id = "allow"
|
|
);
|
|
}
|