acp: Pass project environment to external agent servers (#37568)

Cole Miller , Richard Feldman , and Nia Espera created

Closes #37469 

Release Notes:

- agent: The project shell environment is now passed to external agent
processes.

Co-authored-by: Richard Feldman <oss@rtfeldman.com>
Co-authored-by: Nia Espera <nia-e@haecceity.cc>

Change summary

crates/agent_servers/src/claude.rs |  9 +++++++++
crates/agent_servers/src/gemini.rs | 14 ++++++++++----
2 files changed, 19 insertions(+), 4 deletions(-)

Detailed changes

crates/agent_servers/src/claude.rs 🔗

@@ -80,8 +80,15 @@ impl AgentServer for ClaudeCode {
         let settings = cx.read_global(|settings: &SettingsStore, _| {
             settings.get::<AllAgentServersSettings>(None).claude.clone()
         });
+        let project = delegate.project().clone();
 
         cx.spawn(async move |cx| {
+            let mut project_env = project
+                .update(cx, |project, cx| {
+                    project.directory_environment(root_dir.as_path().into(), cx)
+                })?
+                .await
+                .unwrap_or_default();
             let mut command = if let Some(settings) = settings {
                 settings.command
             } else {
@@ -97,6 +104,8 @@ impl AgentServer for ClaudeCode {
                 })?
                 .await?
             };
+            project_env.extend(command.env.take().unwrap_or_default());
+            command.env = Some(project_env);
 
             command
                 .env

crates/agent_servers/src/gemini.rs 🔗

@@ -41,12 +41,19 @@ impl AgentServer for Gemini {
         let settings = cx.read_global(|settings: &SettingsStore, _| {
             settings.get::<AllAgentServersSettings>(None).gemini.clone()
         });
+        let project = delegate.project().clone();
 
         cx.spawn(async move |cx| {
             let ignore_system_version = settings
                 .as_ref()
                 .and_then(|settings| settings.ignore_system_version)
                 .unwrap_or(true);
+            let mut project_env = project
+                .update(cx, |project, cx| {
+                    project.directory_environment(root_dir.as_path().into(), cx)
+                })?
+                .await
+                .unwrap_or_default();
             let mut command = if let Some(settings) = settings
                 && let Some(command) = settings.custom_command()
             {
@@ -67,13 +74,12 @@ impl AgentServer for Gemini {
             if !command.args.contains(&ACP_ARG.into()) {
                 command.args.push(ACP_ARG.into());
             }
-
             if let Some(api_key) = cx.update(GoogleLanguageModelProvider::api_key)?.await.ok() {
-                command
-                    .env
-                    .get_or_insert_default()
+                project_env
                     .insert("GEMINI_API_KEY".to_owned(), api_key.key);
             }
+            project_env.extend(command.env.take().unwrap_or_default());
+            command.env = Some(project_env);
 
             let root_dir_exists = fs.is_dir(&root_dir).await;
             anyhow::ensure!(