native_agent_server.rs

  1use std::{any::Any, path::Path, rc::Rc, sync::Arc};
  2
  3use agent_servers::AgentServer;
  4use anyhow::Result;
  5use fs::Fs;
  6use gpui::{App, Entity, SharedString, Task};
  7use project::Project;
  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 name(&self) -> SharedString {
 26        "Zed Agent".into()
 27    }
 28
 29    fn empty_state_headline(&self) -> SharedString {
 30        self.name()
 31    }
 32
 33    fn empty_state_message(&self) -> SharedString {
 34        "".into()
 35    }
 36
 37    fn logo(&self) -> ui::IconName {
 38        ui::IconName::ZedAgent
 39    }
 40
 41    fn connect(
 42        &self,
 43        _root_dir: &Path,
 44        project: &Entity<Project>,
 45        cx: &mut App,
 46    ) -> Task<Result<Rc<dyn acp_thread::AgentConnection>>> {
 47        log::debug!(
 48            "NativeAgentServer::connect called for path: {:?}",
 49            _root_dir
 50        );
 51        let project = project.clone();
 52        let fs = self.fs.clone();
 53        let history = self.history.clone();
 54        let prompt_store = PromptStore::global(cx);
 55        cx.spawn(async move |cx| {
 56            log::debug!("Creating templates for native agent");
 57            let templates = Templates::new();
 58            let prompt_store = prompt_store.await?;
 59
 60            log::debug!("Creating native agent entity");
 61            let agent =
 62                NativeAgent::new(project, history, templates, Some(prompt_store), fs, cx).await?;
 63
 64            // Create the connection wrapper
 65            let connection = NativeAgentConnection(agent);
 66            log::debug!("NativeAgentServer connection established successfully");
 67
 68            Ok(Rc::new(connection) as Rc<dyn acp_thread::AgentConnection>)
 69        })
 70    }
 71
 72    fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
 73        self
 74    }
 75}
 76
 77#[cfg(test)]
 78mod tests {
 79    use super::*;
 80
 81    use assistant_context::ContextStore;
 82    use gpui::AppContext;
 83
 84    agent_servers::e2e_tests::common_e2e_tests!(
 85        async |fs, project, cx| {
 86            let auth = cx.update(|cx| {
 87                prompt_store::init(cx);
 88                terminal::init(cx);
 89
 90                let registry = language_model::LanguageModelRegistry::read_global(cx);
 91                let auth = registry
 92                    .provider(&language_model::ANTHROPIC_PROVIDER_ID)
 93                    .unwrap()
 94                    .authenticate(cx);
 95
 96                cx.spawn(async move |_| auth.await)
 97            });
 98
 99            auth.await.unwrap();
100
101            cx.update(|cx| {
102                let registry = language_model::LanguageModelRegistry::global(cx);
103
104                registry.update(cx, |registry, cx| {
105                    registry.select_default_model(
106                        Some(&language_model::SelectedModel {
107                            provider: language_model::ANTHROPIC_PROVIDER_ID,
108                            model: language_model::LanguageModelId("claude-sonnet-4-latest".into()),
109                        }),
110                        cx,
111                    );
112                });
113            });
114
115            let history = cx.update(|cx| {
116                let context_store = cx.new(move |cx| ContextStore::fake(project.clone(), cx));
117                cx.new(move |cx| HistoryStore::new(context_store, cx))
118            });
119
120            NativeAgentServer::new(fs.clone(), history)
121        },
122        allow_option_id = "allow"
123    );
124}