Support external agent config detect and import (#12660)

Migration Behavior

* Config
  *  Migrates settings.json into config.toml
* Only adds fields when config.toml is missing, or when those fields are
missing from the existing file
  *  Supported mappings:
    env -> shell_environment_policy
     sandbox.enabled = true -> sandbox_mode = "workspace-write"

* Skills
  *  Copies home and repo .claude/skills into .agents/skills
  *  Existing skill directories are not overwritten
  *  SKILL.md content is rewritten from Claude-related terms to Codex

* AgentsMd
  *  Repo only
  *  Migrates CLAUDE.md into AGENTS.md
* Detect/import only proceed when AGENTS.md is missing or present but
empty
  *  Content is rewritten from Claude-related terms to Codex
This commit is contained in:
alexsong-oai
2026-02-25 02:11:51 -08:00
committed by GitHub
parent f46b767b7e
commit 6d6570d89d
23 changed files with 1575 additions and 1 deletions

View File

@@ -822,6 +822,10 @@ impl CodexMessageProcessor {
ClientRequest::ConfigRequirementsRead { .. } => {
warn!("ConfigRequirementsRead request reached CodexMessageProcessor unexpectedly");
}
ClientRequest::ExternalAgentConfigDetect { .. }
| ClientRequest::ExternalAgentConfigImport { .. } => {
warn!("ExternalAgentConfig request reached CodexMessageProcessor unexpectedly");
}
ClientRequest::GetAccountRateLimits {
request_id,
params: _,

View File

@@ -0,0 +1,106 @@
use crate::error_code::INTERNAL_ERROR_CODE;
use codex_app_server_protocol::ExternalAgentConfigDetectParams;
use codex_app_server_protocol::ExternalAgentConfigDetectResponse;
use codex_app_server_protocol::ExternalAgentConfigImportParams;
use codex_app_server_protocol::ExternalAgentConfigImportResponse;
use codex_app_server_protocol::ExternalAgentConfigMigrationItem;
use codex_app_server_protocol::ExternalAgentConfigMigrationItemType;
use codex_app_server_protocol::JSONRPCErrorError;
use codex_core::external_agent_config::ExternalAgentConfigDetectOptions;
use codex_core::external_agent_config::ExternalAgentConfigMigrationItem as CoreMigrationItem;
use codex_core::external_agent_config::ExternalAgentConfigMigrationItemType as CoreMigrationItemType;
use codex_core::external_agent_config::ExternalAgentConfigService;
use std::io;
use std::path::PathBuf;
#[derive(Clone)]
pub(crate) struct ExternalAgentConfigApi {
migration_service: ExternalAgentConfigService,
}
impl ExternalAgentConfigApi {
pub(crate) fn new(codex_home: PathBuf) -> Self {
Self {
migration_service: ExternalAgentConfigService::new(codex_home),
}
}
pub(crate) async fn detect(
&self,
params: ExternalAgentConfigDetectParams,
) -> Result<ExternalAgentConfigDetectResponse, JSONRPCErrorError> {
let items = self
.migration_service
.detect(ExternalAgentConfigDetectOptions {
include_home: params.include_home,
cwds: params.cwds,
})
.map_err(map_io_error)?;
Ok(ExternalAgentConfigDetectResponse {
items: items
.into_iter()
.map(|migration_item| ExternalAgentConfigMigrationItem {
item_type: match migration_item.item_type {
CoreMigrationItemType::Config => {
ExternalAgentConfigMigrationItemType::Config
}
CoreMigrationItemType::Skills => {
ExternalAgentConfigMigrationItemType::Skills
}
CoreMigrationItemType::AgentsMd => {
ExternalAgentConfigMigrationItemType::AgentsMd
}
CoreMigrationItemType::McpServerConfig => {
ExternalAgentConfigMigrationItemType::McpServerConfig
}
},
description: migration_item.description,
cwd: migration_item.cwd,
})
.collect(),
})
}
pub(crate) async fn import(
&self,
params: ExternalAgentConfigImportParams,
) -> Result<ExternalAgentConfigImportResponse, JSONRPCErrorError> {
self.migration_service
.import(
params
.migration_items
.into_iter()
.map(|migration_item| CoreMigrationItem {
item_type: match migration_item.item_type {
ExternalAgentConfigMigrationItemType::Config => {
CoreMigrationItemType::Config
}
ExternalAgentConfigMigrationItemType::Skills => {
CoreMigrationItemType::Skills
}
ExternalAgentConfigMigrationItemType::AgentsMd => {
CoreMigrationItemType::AgentsMd
}
ExternalAgentConfigMigrationItemType::McpServerConfig => {
CoreMigrationItemType::McpServerConfig
}
},
description: migration_item.description,
cwd: migration_item.cwd,
})
.collect(),
)
.map_err(map_io_error)?;
Ok(ExternalAgentConfigImportResponse {})
}
}
fn map_io_error(err: io::Error) -> JSONRPCErrorError {
JSONRPCErrorError {
code: INTERNAL_ERROR_CODE,
message: err.to_string(),
data: None,
}
}

View File

@@ -57,6 +57,7 @@ mod codex_message_processor;
mod config_api;
mod dynamic_tools;
mod error_code;
mod external_agent_config_api;
mod filters;
mod fuzzy_file_search;
mod message_processor;

View File

@@ -8,6 +8,7 @@ use crate::codex_message_processor::CodexMessageProcessor;
use crate::codex_message_processor::CodexMessageProcessorArgs;
use crate::config_api::ConfigApi;
use crate::error_code::INVALID_REQUEST_ERROR_CODE;
use crate::external_agent_config_api::ExternalAgentConfigApi;
use crate::outgoing_message::ConnectionId;
use crate::outgoing_message::ConnectionRequestId;
use crate::outgoing_message::OutgoingMessageSender;
@@ -22,6 +23,8 @@ use codex_app_server_protocol::ConfigReadParams;
use codex_app_server_protocol::ConfigValueWriteParams;
use codex_app_server_protocol::ConfigWarningNotification;
use codex_app_server_protocol::ExperimentalApi;
use codex_app_server_protocol::ExternalAgentConfigDetectParams;
use codex_app_server_protocol::ExternalAgentConfigImportParams;
use codex_app_server_protocol::InitializeResponse;
use codex_app_server_protocol::JSONRPCError;
use codex_app_server_protocol::JSONRPCErrorError;
@@ -126,6 +129,7 @@ pub(crate) struct MessageProcessor {
outgoing: Arc<OutgoingMessageSender>,
codex_message_processor: CodexMessageProcessor,
config_api: ConfigApi,
external_agent_config_api: ExternalAgentConfigApi,
config: Arc<Config>,
config_warnings: Arc<Vec<ConfigWarningNotification>>,
}
@@ -197,11 +201,13 @@ impl MessageProcessor {
loader_overrides,
cloud_requirements,
);
let external_agent_config_api = ExternalAgentConfigApi::new(config.codex_home.clone());
Self {
outgoing,
codex_message_processor,
config_api,
external_agent_config_api,
config,
config_warnings: Arc::new(config_warnings),
}
@@ -363,6 +369,26 @@ impl MessageProcessor {
)
.await;
}
ClientRequest::ExternalAgentConfigDetect { request_id, params } => {
self.handle_external_agent_config_detect(
ConnectionRequestId {
connection_id,
request_id,
},
params,
)
.await;
}
ClientRequest::ExternalAgentConfigImport { request_id, params } => {
self.handle_external_agent_config_import(
ConnectionRequestId {
connection_id,
request_id,
},
params,
)
.await;
}
ClientRequest::ConfigValueWrite { request_id, params } => {
self.handle_config_value_write(
ConnectionRequestId {
@@ -492,4 +518,26 @@ impl MessageProcessor {
Err(error) => self.outgoing.send_error(request_id, error).await,
}
}
async fn handle_external_agent_config_detect(
&self,
request_id: ConnectionRequestId,
params: ExternalAgentConfigDetectParams,
) {
match self.external_agent_config_api.detect(params).await {
Ok(response) => self.outgoing.send_response(request_id, response).await,
Err(error) => self.outgoing.send_error(request_id, error).await,
}
}
async fn handle_external_agent_config_import(
&self,
request_id: ConnectionRequestId,
params: ExternalAgentConfigImportParams,
) {
match self.external_agent_config_api.import(params).await {
Ok(response) => self.outgoing.send_response(request_id, response).await,
Err(error) => self.outgoing.send_error(request_id, error).await,
}
}
}