[codex] support executor registry remote environments (#21323)

## Summary

Support registry-backed remote executors end to end so downstream
services can resolve an executor id into an exec-server URL and make
that environment available to Codex without relying on the legacy cloud
environments flow.

## What changed

- switch remote executor registration to the executor registry bootstrap
contract
- allow named remote environments to be inserted into
`EnvironmentManager` at runtime
- add the experimental app-server RPC `environment/add` so initialized
experimental clients can register those remote environments for later
`thread/start` and `turn/start` selection

## Validation

Ran focused validation locally:
- `cargo test -p codex-exec-server environment_manager_`
- `cargo test -p codex-exec-server
register_executor_posts_with_bearer_token_header`
- `cargo test -p codex-app-server-protocol`
This commit is contained in:
Michael Zeng
2026-05-08 16:30:07 -07:00
committed by GitHub
Unverified
parent 80a408e201
commit 8f4020846e
11 changed files with 222 additions and 85 deletions
@@ -18,6 +18,7 @@ use crate::request_processors::AppsRequestProcessor;
use crate::request_processors::CatalogRequestProcessor;
use crate::request_processors::CommandExecRequestProcessor;
use crate::request_processors::ConfigRequestProcessor;
use crate::request_processors::EnvironmentRequestProcessor;
use crate::request_processors::ExternalAgentConfigRequestProcessor;
use crate::request_processors::FeedbackRequestProcessor;
use crate::request_processors::FsRequestProcessor;
@@ -161,6 +162,7 @@ pub(crate) struct MessageProcessor {
command_exec_processor: CommandExecRequestProcessor,
process_exec_processor: ProcessExecRequestProcessor,
config_processor: ConfigRequestProcessor,
environment_processor: EnvironmentRequestProcessor,
external_agent_config_processor: ExternalAgentConfigRequestProcessor,
feedback_processor: FeedbackRequestProcessor,
fs_processor: FsRequestProcessor,
@@ -446,6 +448,8 @@ impl MessageProcessor {
arg0_paths,
config.codex_home.to_path_buf(),
);
let environment_processor =
EnvironmentRequestProcessor::new(thread_manager.environment_manager());
let fs_processor = FsRequestProcessor::new(
thread_manager
.environment_manager()
@@ -467,6 +471,7 @@ impl MessageProcessor {
command_exec_processor,
process_exec_processor,
config_processor,
environment_processor,
external_agent_config_processor,
feedback_processor,
fs_processor,
@@ -878,6 +883,9 @@ impl MessageProcessor {
.config_requirements_read()
.await
.map(|response| Some(response.into())),
ClientRequest::EnvironmentAdd { params, .. } => {
self.environment_processor.environment_add(params).await
}
ClientRequest::FsReadFile { params, .. } => self
.fs_processor
.read_file(params)
@@ -49,6 +49,8 @@ use codex_app_server_protocol::ConversationGitInfo;
use codex_app_server_protocol::ConversationSummary;
use codex_app_server_protocol::DeprecationNoticeNotification;
use codex_app_server_protocol::DynamicToolSpec as ApiDynamicToolSpec;
use codex_app_server_protocol::EnvironmentAddParams;
use codex_app_server_protocol::EnvironmentAddResponse;
use codex_app_server_protocol::ExperimentalFeature as ApiExperimentalFeature;
use codex_app_server_protocol::ExperimentalFeatureListParams;
use codex_app_server_protocol::ExperimentalFeatureListResponse;
@@ -434,6 +436,7 @@ mod apps_processor;
mod catalog_processor;
mod command_exec_processor;
mod config_processor;
mod environment_processor;
mod external_agent_config_processor;
mod feedback_processor;
mod fs_processor;
@@ -454,6 +457,7 @@ pub(crate) use apps_processor::AppsRequestProcessor;
pub(crate) use catalog_processor::CatalogRequestProcessor;
pub(crate) use command_exec_processor::CommandExecRequestProcessor;
pub(crate) use config_processor::ConfigRequestProcessor;
pub(crate) use environment_processor::EnvironmentRequestProcessor;
pub(crate) use external_agent_config_processor::ExternalAgentConfigRequestProcessor;
pub(crate) use feedback_processor::FeedbackRequestProcessor;
pub(crate) use fs_processor::FsRequestProcessor;
@@ -0,0 +1,24 @@
use super::*;
#[derive(Clone)]
pub(crate) struct EnvironmentRequestProcessor {
environment_manager: Arc<EnvironmentManager>,
}
impl EnvironmentRequestProcessor {
pub(crate) fn new(environment_manager: Arc<EnvironmentManager>) -> Self {
Self {
environment_manager,
}
}
pub(crate) async fn environment_add(
&self,
params: EnvironmentAddParams,
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
self.environment_manager
.upsert_environment(params.environment_id, params.exec_server_url)
.map_err(|err| invalid_request(err.to_string()))?;
Ok(Some(EnvironmentAddResponse {}.into()))
}
}