Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions crates/project/src/agent_server_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ use std::{
};

use anyhow::{Context as _, Result, bail};
use client::Client;
use collections::HashMap;
use feature_flags::FeatureFlagAppExt as _;
use fs::{Fs, RemoveOptions, RenameOptions};
use futures::StreamExt as _;
use gpui::{
App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription, Task,
};
use http_client::github::AssetKind;
use http_client::{HttpClient, github::AssetKind};
use node_runtime::NodeRuntime;
use remote::RemoteClient;
use rpc::{AnyProtoClient, TypedEnvelope, proto};
Expand Down Expand Up @@ -114,6 +113,7 @@ enum AgentServerStoreState {
project_environment: Entity<ProjectEnvironment>,
downstream_client: Option<(u64, AnyProtoClient)>,
settings: Option<AllAgentServersSettings>,
http_client: Arc<dyn HttpClient>,
_subscriptions: [Subscription; 1],
},
Remote {
Expand Down Expand Up @@ -174,6 +174,7 @@ impl AgentServerStore {
project_environment,
downstream_client,
settings: old_settings,
http_client,
..
} = &mut self.state
else {
Expand Down Expand Up @@ -227,6 +228,8 @@ impl AgentServerStore {
.codex
.clone()
.and_then(|settings| settings.custom_command()),
http_client: http_client.clone(),
is_remote: downstream_client.is_some(),
}),
);
}
Expand All @@ -253,7 +256,6 @@ impl AgentServerStore {
names: self
.external_agents
.keys()
.filter(|name| name.0 != CODEX_NAME)
.map(|name| name.to_string())
.collect(),
})
Expand All @@ -266,6 +268,7 @@ impl AgentServerStore {
node_runtime: NodeRuntime,
fs: Arc<dyn Fs>,
project_environment: Entity<ProjectEnvironment>,
http_client: Arc<dyn HttpClient>,
cx: &mut Context<Self>,
) -> Self {
let subscription = cx.observe_global::<SettingsStore>(|this, cx| {
Expand All @@ -283,6 +286,7 @@ impl AgentServerStore {
node_runtime,
fs,
project_environment,
http_client,
downstream_client: None,
settings: None,
_subscriptions: [subscription],
Expand All @@ -297,12 +301,12 @@ impl AgentServerStore {
pub(crate) fn remote(
project_id: u64,
upstream_client: Entity<RemoteClient>,
_cx: &mut Context<Self>,
cx: &mut Context<Self>,
) -> Self {
// Set up the builtin agents here so they're immediately available in
// remote projects--we know that the HeadlessProject on the other end
// will have them.
let external_agents = [
let mut external_agents = [
(
GEMINI_NAME.into(),
Box::new(RemoteExternalAgentServer {
Expand All @@ -325,7 +329,21 @@ impl AgentServerStore {
),
]
.into_iter()
.collect();
.collect::<HashMap<ExternalAgentServerName, Box<dyn ExternalAgentServer>>>();

use feature_flags::FeatureFlagAppExt as _;
if cx.has_flag::<feature_flags::CodexAcpFeatureFlag>() {
external_agents.insert(
CODEX_NAME.into(),
Box::new(RemoteExternalAgentServer {
project_id,
upstream_client: upstream_client.clone(),
name: CODEX_NAME.into(),
status_tx: None,
new_version_available_tx: None,
}) as Box<dyn ExternalAgentServer>,
);
}

Self {
state: AgentServerStoreState::Remote {
Expand Down Expand Up @@ -1003,7 +1021,9 @@ impl ExternalAgentServer for LocalClaudeCode {
struct LocalCodex {
fs: Arc<dyn Fs>,
project_environment: Entity<ProjectEnvironment>,
http_client: Arc<dyn HttpClient>,
custom_command: Option<AgentServerCommand>,
is_remote: bool,
}

impl ExternalAgentServer for LocalCodex {
Expand All @@ -1017,11 +1037,13 @@ impl ExternalAgentServer for LocalCodex {
) -> Task<Result<(AgentServerCommand, String, Option<task::SpawnInTerminal>)>> {
let fs = self.fs.clone();
let project_environment = self.project_environment.downgrade();
let http = self.http_client.clone();
let custom_command = self.custom_command.clone();
let root_dir: Arc<Path> = root_dir
.map(|root_dir| Path::new(root_dir))
.unwrap_or(paths::home_dir())
.into();
let is_remote = self.is_remote;

cx.spawn(async move |cx| {
let mut env = project_environment
Expand All @@ -1030,6 +1052,9 @@ impl ExternalAgentServer for LocalCodex {
})?
.await
.unwrap_or_default();
if is_remote {
env.insert("NO_BROWSER".to_owned(), "1".to_owned());
}

let mut command = if let Some(mut custom_command) = custom_command {
env.extend(custom_command.env.unwrap_or_default());
Expand All @@ -1040,7 +1065,6 @@ impl ExternalAgentServer for LocalCodex {
fs.create_dir(&dir).await?;

// Find or install the latest Codex release (no update checks for now).
let http = cx.update(|cx| Client::global(cx).http_client())?;
let release = ::http_client::github::latest_github_release(
CODEX_ACP_REPO,
true,
Expand Down
8 changes: 7 additions & 1 deletion crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,13 @@ impl Project {
});

let agent_server_store = cx.new(|cx| {
AgentServerStore::local(node.clone(), fs.clone(), environment.clone(), cx)
AgentServerStore::local(
node.clone(),
fs.clone(),
environment.clone(),
client.http_client(),
cx,
)
});

cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
Expand Down
9 changes: 7 additions & 2 deletions crates/remote_server/src/headless_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,13 @@ impl HeadlessProject {
});

let agent_server_store = cx.new(|cx| {
let mut agent_server_store =
AgentServerStore::local(node_runtime.clone(), fs.clone(), environment, cx);
let mut agent_server_store = AgentServerStore::local(
node_runtime.clone(),
fs.clone(),
environment,
http_client.clone(),
cx,
);
agent_server_store.shared(REMOTE_SERVER_PROJECT_ID, session.clone(), cx);
agent_server_store
});
Expand Down
4 changes: 2 additions & 2 deletions crates/remote_server/src/remote_editing_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1792,7 +1792,7 @@ async fn test_remote_external_agent_server(
.map(|name| name.to_string())
.collect::<Vec<_>>()
});
pretty_assertions::assert_eq!(names, ["gemini", "claude"]);
pretty_assertions::assert_eq!(names, ["gemini", "codex", "claude"]);
server_cx.update_global::<SettingsStore, _>(|settings_store, cx| {
settings_store
.set_server_settings(
Expand Down Expand Up @@ -1822,7 +1822,7 @@ async fn test_remote_external_agent_server(
.map(|name| name.to_string())
.collect::<Vec<_>>()
});
pretty_assertions::assert_eq!(names, ["gemini", "foo", "claude"]);
pretty_assertions::assert_eq!(names, ["gemini", "codex", "claude", "foo"]);
let (command, root, login) = project
.update(cx, |project, cx| {
project.agent_server_store().update(cx, |store, cx| {
Expand Down
Loading