1use std::rc::Rc;
2use std::{any::Any, path::Path};
3
4use crate::{AgentServer, AgentServerDelegate, load_proxy_env};
5use acp_thread::AgentConnection;
6use anyhow::{Context as _, Result};
7use gpui::{App, SharedString, Task};
8use language_models::provider::google::GoogleLanguageModelProvider;
9use project::agent_server_store::GEMINI_NAME;
10
11#[derive(Clone)]
12pub struct Gemini;
13
14impl AgentServer for Gemini {
15 fn name(&self) -> SharedString {
16 "Gemini CLI".into()
17 }
18
19 fn logo(&self) -> ui::IconName {
20 ui::IconName::AiGemini
21 }
22
23 fn connect(
24 &self,
25 root_dir: Option<&Path>,
26 delegate: AgentServerDelegate,
27 cx: &mut App,
28 ) -> Task<Result<(Rc<dyn AgentConnection>, Option<task::SpawnInTerminal>)>> {
29 let name = self.name();
30 let root_dir = root_dir.map(|root_dir| root_dir.to_string_lossy().into_owned());
31 let is_remote = delegate.project.read(cx).is_via_remote_server();
32 let store = delegate.store.downgrade();
33 let mut extra_env = load_proxy_env(cx);
34 let default_mode = self.default_mode(cx);
35 let default_model = self.default_model(cx);
36
37 cx.spawn(async move |cx| {
38 extra_env.insert("SURFACE".to_owned(), "zed".to_owned());
39
40 if let Some(api_key) = cx
41 .update(GoogleLanguageModelProvider::api_key_for_gemini_cli)?
42 .await
43 .ok()
44 {
45 extra_env.insert("GEMINI_API_KEY".into(), api_key);
46 }
47 let (command, root_dir, login) = store
48 .update(cx, |store, cx| {
49 let agent = store
50 .get_external_agent(&GEMINI_NAME.into())
51 .context("Gemini CLI is not registered")?;
52 anyhow::Ok(agent.get_command(
53 root_dir.as_deref(),
54 extra_env,
55 delegate.status_tx,
56 delegate.new_version_available,
57 &mut cx.to_async(),
58 ))
59 })??
60 .await?;
61
62 let connection = crate::acp::connect(
63 name,
64 command,
65 root_dir.as_ref(),
66 default_mode,
67 default_model,
68 is_remote,
69 cx,
70 )
71 .await?;
72 Ok((connection, login))
73 })
74 }
75
76 fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
77 self
78 }
79}
80
81#[cfg(test)]
82pub(crate) mod tests {
83 use project::agent_server_store::AgentServerCommand;
84
85 use super::*;
86 use std::path::Path;
87
88 crate::common_e2e_tests!(async |_, _, _| Gemini, allow_option_id = "proceed_once");
89
90 pub fn local_command() -> AgentServerCommand {
91 let cli_path = Path::new(env!("CARGO_MANIFEST_DIR"))
92 .join("../../../gemini-cli/packages/cli")
93 .to_string_lossy()
94 .to_string();
95
96 AgentServerCommand {
97 path: "node".into(),
98 args: vec![cli_path],
99 env: None,
100 }
101 }
102}