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::api_key_for_gemini_cli;
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.update(api_key_for_gemini_cli)?.await.ok() {
41 extra_env.insert("GEMINI_API_KEY".into(), api_key);
42 }
43 let (command, root_dir, login) = store
44 .update(cx, |store, cx| {
45 let agent = store
46 .get_external_agent(&GEMINI_NAME.into())
47 .context("Gemini CLI is not registered")?;
48 anyhow::Ok(agent.get_command(
49 root_dir.as_deref(),
50 extra_env,
51 delegate.status_tx,
52 delegate.new_version_available,
53 &mut cx.to_async(),
54 ))
55 })??
56 .await?;
57
58 let connection = crate::acp::connect(
59 name,
60 command,
61 root_dir.as_ref(),
62 default_mode,
63 default_model,
64 is_remote,
65 cx,
66 )
67 .await?;
68 Ok((connection, login))
69 })
70 }
71
72 fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
73 self
74 }
75}
76
77#[cfg(test)]
78pub(crate) mod tests {
79 use project::agent_server_store::AgentServerCommand;
80
81 use super::*;
82 use std::path::Path;
83
84 crate::common_e2e_tests!(async |_, _, _| Gemini, allow_option_id = "proceed_once");
85
86 pub fn local_command() -> AgentServerCommand {
87 let cli_path = Path::new(env!("CARGO_MANIFEST_DIR"))
88 .join("../../../gemini-cli/packages/cli")
89 .to_string_lossy()
90 .to_string();
91
92 AgentServerCommand {
93 path: "node".into(),
94 args: vec![cli_path],
95 env: None,
96 }
97 }
98}