native_agent_server.rs

  1use std::{any::Any, path::Path, rc::Rc, sync::Arc};
  2
  3use agent_servers::{AgentServer, AgentServerDelegate};
  4use anyhow::Result;
  5use collections::HashMap;
  6use fs::Fs;
  7use gpui::{App, Entity, SharedString, Task};
  8use prompt_store::PromptStore;
  9
 10use crate::{HistoryStore, NativeAgent, NativeAgentConnection, templates::Templates};
 11
 12#[derive(Clone)]
 13pub struct NativeAgentServer {
 14    fs: Arc<dyn Fs>,
 15    history: Entity<HistoryStore>,
 16}
 17
 18impl NativeAgentServer {
 19    pub fn new(fs: Arc<dyn Fs>, history: Entity<HistoryStore>) -> Self {
 20        Self { fs, history }
 21    }
 22}
 23
 24impl AgentServer for NativeAgentServer {
 25    fn telemetry_id(&self) -> &'static str {
 26        "zed"
 27    }
 28
 29    fn name(&self) -> SharedString {
 30        "Zed Agent".into()
 31    }
 32
 33    fn logo(&self) -> ui::IconName {
 34        ui::IconName::ZedAgent
 35    }
 36
 37    fn local_login_commands(&self) -> Vec<String> {
 38        vec![]
 39    }
 40
 41    fn remote_login_commands(&self) -> Vec<String> {
 42        vec![]
 43    }
 44
 45    fn local_logout_commands(&self) -> Vec<String> {
 46        vec![]
 47    }
 48
 49    fn remote_logout_commands(&self) -> Vec<String> {
 50        vec![]
 51    }
 52
 53    fn connect(
 54        &self,
 55        _root_dir: Option<&Path>,
 56        delegate: AgentServerDelegate,
 57        cx: &mut App,
 58    ) -> Task<
 59        Result<(
 60            Rc<dyn acp_thread::AgentConnection>,
 61            HashMap<String, task::SpawnInTerminal>,
 62        )>,
 63    > {
 64        log::debug!(
 65            "NativeAgentServer::connect called for path: {:?}",
 66            _root_dir
 67        );
 68        let project = delegate.project().clone();
 69        let fs = self.fs.clone();
 70        let history = self.history.clone();
 71        let prompt_store = PromptStore::global(cx);
 72        cx.spawn(async move |cx| {
 73            log::debug!("Creating templates for native agent");
 74            let templates = Templates::new();
 75            let prompt_store = prompt_store.await?;
 76
 77            log::debug!("Creating native agent entity");
 78            let agent =
 79                NativeAgent::new(project, history, templates, Some(prompt_store), fs, cx).await?;
 80
 81            // Create the connection wrapper
 82            let connection = NativeAgentConnection(agent);
 83            log::debug!("NativeAgentServer connection established successfully");
 84
 85            Ok((
 86                Rc::new(connection) as Rc<dyn acp_thread::AgentConnection>,
 87                HashMap::default(),
 88            ))
 89        })
 90    }
 91
 92    fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
 93        self
 94    }
 95}
 96
 97#[cfg(test)]
 98mod tests {
 99    use super::*;
100
101    use assistant_context::ContextStore;
102    use gpui::AppContext;
103
104    agent_servers::e2e_tests::common_e2e_tests!(
105        async |fs, project, cx| {
106            let auth = cx.update(|cx| {
107                prompt_store::init(cx);
108                terminal::init(cx);
109
110                let registry = language_model::LanguageModelRegistry::read_global(cx);
111                let auth = registry
112                    .provider(&language_model::ANTHROPIC_PROVIDER_ID)
113                    .unwrap()
114                    .authenticate(cx);
115
116                cx.spawn(async move |_| auth.await)
117            });
118
119            auth.await.unwrap();
120
121            cx.update(|cx| {
122                let registry = language_model::LanguageModelRegistry::global(cx);
123
124                registry.update(cx, |registry, cx| {
125                    registry.select_default_model(
126                        Some(&language_model::SelectedModel {
127                            provider: language_model::ANTHROPIC_PROVIDER_ID,
128                            model: language_model::LanguageModelId("claude-sonnet-4-latest".into()),
129                        }),
130                        cx,
131                    );
132                });
133            });
134
135            let history = cx.update(|cx| {
136                let context_store = cx.new(move |cx| ContextStore::fake(project.clone(), cx));
137                cx.new(move |cx| HistoryStore::new(context_store, cx))
138            });
139
140            NativeAgentServer::new(fs.clone(), history)
141        },
142        allow_option_id = "allow"
143    );
144}