+Codex

Conrad Irwin created

Change summary

crates/agent_servers/src/codex.rs | 118 +++++++++++++++++++++++++++++++++
1 file changed, 118 insertions(+)

Detailed changes

crates/agent_servers/src/codex.rs 🔗

@@ -0,0 +1,118 @@
+use crate::stdio_agent_server::{StdioAgentServer, find_bin_in_path};
+use crate::{AgentServerCommand, AgentServerVersion};
+use anyhow::{Context as _, Result};
+use gpui::{AsyncApp, Entity};
+use project::Project;
+use settings::SettingsStore;
+
+use crate::AllAgentServersSettings;
+
+#[derive(Clone)]
+pub struct Codex;
+
+const ACP_ARG: &str = "acp";
+
+impl StdioAgentServer for Codex {
+    fn name(&self) -> &'static str {
+        "Codex"
+    }
+
+    fn empty_state_headline(&self) -> &'static str {
+        "Welcome to Codex"
+    }
+
+    fn empty_state_message(&self) -> &'static str {
+        "Ask questions, edit files, run commands.\nBe specific for the best results."
+    }
+
+    fn logo(&self) -> ui::IconName {
+        ui::IconName::AiOpenAi
+    }
+
+    async fn command(
+        &self,
+        project: &Entity<Project>,
+        cx: &mut AsyncApp,
+    ) -> Result<AgentServerCommand> {
+        let custom_command = cx.read_global(|settings: &SettingsStore, _| {
+            let settings = settings.get::<AllAgentServersSettings>(None);
+            settings
+                .codex
+                .as_ref()
+                .map(|codex_settings| AgentServerCommand {
+                    path: codex_settings.command.path.clone(),
+                    args: codex_settings
+                        .command
+                        .args
+                        .iter()
+                        .cloned()
+                        .chain(std::iter::once(ACP_ARG.into()))
+                        .collect(),
+                    env: codex_settings.command.env.clone(),
+                })
+        })?;
+
+        if let Some(custom_command) = custom_command {
+            return Ok(custom_command);
+        }
+
+        if let Some(path) = find_bin_in_path("codex", project, cx).await {
+            return Ok(AgentServerCommand {
+                path,
+                args: vec![ACP_ARG.into()],
+                env: None,
+            });
+        }
+
+        todo!()
+        // let (fs, node_runtime) = project.update(cx, |project, _| {
+        //     (project.fs().clone(), project.node_runtime().cloned())
+        // })?;
+        // let node_runtime = node_runtime.context("codex not found on path")?;
+
+        // let directory = ::paths::agent_servers_dir().join("codex");
+        // fs.create_dir(&directory).await?;
+        // node_runtime
+        //     .npm_install_packages(&directory, &[("@google/gemini-cli", "latest")])
+        //     .await?;
+        // let path = directory.join("node_modules/.bin/gemini");
+
+        // Ok(AgentServerCommand {
+        //     path,
+        //     args: vec![ACP_ARG.into()],
+        //     env: None,
+        // })
+    }
+
+    async fn version(&self, command: &AgentServerCommand) -> Result<AgentServerVersion> {
+        let version_fut = util::command::new_smol_command(&command.path)
+            .args(command.args.iter())
+            .arg("--version")
+            .kill_on_drop(true)
+            .output();
+
+        let help_fut = util::command::new_smol_command(&command.path)
+            .args(command.args.iter())
+            .arg("--help")
+            .kill_on_drop(true)
+            .output();
+
+        let (version_output, help_output) = futures::future::join(version_fut, help_fut).await;
+
+        let current_version = String::from_utf8(version_output?.stdout)?;
+        let supported = String::from_utf8(help_output?.stdout)?.contains(ACP_ARG);
+
+        if supported {
+            Ok(AgentServerVersion::Supported)
+        } else {
+            Ok(AgentServerVersion::Unsupported {
+                error_message: format!(
+                    "Your installed version of Codex {} doesn't support the Agentic Coding Protocol (ACP).",
+                    current_version
+                ).into(),
+                upgrade_message: "Upgrade Codex to Latest".into(),
+                upgrade_command: "npm install -g @openai/codex@latest".into(),
+            })
+        }
+    }
+}