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