mirror of
https://github.com/openai/codex.git
synced 2026-04-27 09:51:03 +03:00
changes
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use crate::bespoke_event_handling::apply_bespoke_event_handling;
|
||||
use crate::config_api::ConfigApi;
|
||||
use crate::error_code::INTERNAL_ERROR_CODE;
|
||||
use crate::error_code::INVALID_REQUEST_ERROR_CODE;
|
||||
use crate::fuzzy_file_search::run_fuzzy_file_search;
|
||||
@@ -215,6 +216,7 @@ pub(crate) struct CodexMessageProcessor {
|
||||
outgoing: Arc<OutgoingMessageSender>,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
config: Arc<Config>,
|
||||
config_api: ConfigApi,
|
||||
cli_overrides: Vec<(String, TomlValue)>,
|
||||
conversation_listeners: HashMap<Uuid, oneshot::Sender<()>>,
|
||||
active_login: Arc<Mutex<Option<ActiveLogin>>>,
|
||||
@@ -265,12 +267,14 @@ impl CodexMessageProcessor {
|
||||
cli_overrides: Vec<(String, TomlValue)>,
|
||||
feedback: CodexFeedback,
|
||||
) -> Self {
|
||||
let config_api = ConfigApi::new(config.codex_home.clone(), cli_overrides.clone());
|
||||
Self {
|
||||
auth_manager,
|
||||
conversation_manager,
|
||||
outgoing,
|
||||
codex_linux_sandbox_exe,
|
||||
config,
|
||||
config_api,
|
||||
cli_overrides,
|
||||
conversation_listeners: HashMap::new(),
|
||||
active_login: Arc::new(Mutex::new(None)),
|
||||
@@ -282,13 +286,7 @@ impl CodexMessageProcessor {
|
||||
}
|
||||
|
||||
async fn load_latest_config(&self) -> Result<Config, JSONRPCErrorError> {
|
||||
Config::load_with_cli_overrides(self.cli_overrides.clone())
|
||||
.await
|
||||
.map_err(|err| JSONRPCErrorError {
|
||||
code: INTERNAL_ERROR_CODE,
|
||||
message: format!("failed to reload config: {err}"),
|
||||
data: None,
|
||||
})
|
||||
self.config_api.load_latest_thread_agnostic_config().await
|
||||
}
|
||||
|
||||
fn review_request_from_target(
|
||||
|
||||
@@ -7,6 +7,8 @@ use codex_app_server_protocol::ConfigValueWriteParams;
|
||||
use codex_app_server_protocol::ConfigWriteErrorCode;
|
||||
use codex_app_server_protocol::ConfigWriteResponse;
|
||||
use codex_app_server_protocol::JSONRPCErrorError;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
use codex_core::config::ConfigService;
|
||||
use codex_core::config::ConfigServiceError;
|
||||
use serde_json::json;
|
||||
@@ -15,13 +17,17 @@ use toml::Value as TomlValue;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ConfigApi {
|
||||
codex_home: PathBuf,
|
||||
cli_overrides: Vec<(String, TomlValue)>,
|
||||
service: ConfigService,
|
||||
}
|
||||
|
||||
impl ConfigApi {
|
||||
pub(crate) fn new(codex_home: PathBuf, cli_overrides: Vec<(String, TomlValue)>) -> Self {
|
||||
Self {
|
||||
service: ConfigService::new(codex_home, cli_overrides),
|
||||
service: ConfigService::new(codex_home.clone(), cli_overrides.clone()),
|
||||
codex_home,
|
||||
cli_overrides,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +51,22 @@ impl ConfigApi {
|
||||
) -> Result<ConfigWriteResponse, JSONRPCErrorError> {
|
||||
self.service.batch_write(params).await.map_err(map_error)
|
||||
}
|
||||
|
||||
pub(crate) async fn load_latest_thread_agnostic_config(
|
||||
&self,
|
||||
) -> Result<Config, JSONRPCErrorError> {
|
||||
ConfigBuilder::default()
|
||||
.codex_home(self.codex_home.clone())
|
||||
.cli_overrides(self.cli_overrides.clone())
|
||||
.thread_agnostic()
|
||||
.build()
|
||||
.await
|
||||
.map_err(|err| JSONRPCErrorError {
|
||||
code: INTERNAL_ERROR_CODE,
|
||||
message: format!("failed to reload config: {err}"),
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn map_error(err: ConfigServiceError) -> JSONRPCErrorError {
|
||||
|
||||
@@ -363,6 +363,7 @@ pub struct ConfigBuilder {
|
||||
cli_overrides: Option<Vec<(String, TomlValue)>>,
|
||||
harness_overrides: Option<ConfigOverrides>,
|
||||
loader_overrides: Option<LoaderOverrides>,
|
||||
thread_agnostic: bool,
|
||||
}
|
||||
|
||||
impl ConfigBuilder {
|
||||
@@ -371,6 +372,13 @@ impl ConfigBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Load a "thread-agnostic" config stack, which intentionally ignores any
|
||||
/// in-repo `.codex/` config layers (because there is no cwd/project context).
|
||||
pub fn thread_agnostic(mut self) -> Self {
|
||||
self.thread_agnostic = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cli_overrides(mut self, cli_overrides: Vec<(String, TomlValue)>) -> Self {
|
||||
self.cli_overrides = Some(cli_overrides);
|
||||
self
|
||||
@@ -392,18 +400,22 @@ impl ConfigBuilder {
|
||||
cli_overrides,
|
||||
harness_overrides,
|
||||
loader_overrides,
|
||||
thread_agnostic,
|
||||
} = self;
|
||||
let codex_home = codex_home.map_or_else(find_codex_home, std::io::Result::Ok)?;
|
||||
let cli_overrides = cli_overrides.unwrap_or_default();
|
||||
let harness_overrides = harness_overrides.unwrap_or_default();
|
||||
let loader_overrides = loader_overrides.unwrap_or_default();
|
||||
let cwd = match harness_overrides.cwd.as_deref() {
|
||||
Some(path) => AbsolutePathBuf::try_from(path)?,
|
||||
None => AbsolutePathBuf::current_dir()?,
|
||||
let cwd = if thread_agnostic {
|
||||
None
|
||||
} else {
|
||||
Some(match harness_overrides.cwd.as_deref() {
|
||||
Some(path) => AbsolutePathBuf::try_from(path)?,
|
||||
None => AbsolutePathBuf::current_dir()?,
|
||||
})
|
||||
};
|
||||
let config_layer_stack =
|
||||
load_config_layers_state(&codex_home, Some(cwd), &cli_overrides, loader_overrides)
|
||||
.await?;
|
||||
load_config_layers_state(&codex_home, cwd, &cli_overrides, loader_overrides).await?;
|
||||
let merged_toml = config_layer_stack.effective_config();
|
||||
|
||||
// Note that each layer in ConfigLayerStack should have resolved
|
||||
@@ -2082,6 +2094,43 @@ trust_level = "trusted"
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn config_builder_thread_agnostic_ignores_project_layers() -> anyhow::Result<()> {
|
||||
let tmp = TempDir::new()?;
|
||||
let codex_home = tmp.path().join("codex_home");
|
||||
std::fs::create_dir_all(&codex_home)?;
|
||||
std::fs::write(codex_home.join(CONFIG_TOML_FILE), "model = \"from-user\"\n")?;
|
||||
|
||||
let project = tmp.path().join("project");
|
||||
std::fs::create_dir_all(project.join(".codex"))?;
|
||||
std::fs::write(
|
||||
project.join(".codex").join(CONFIG_TOML_FILE),
|
||||
"model = \"from-project\"\n",
|
||||
)?;
|
||||
|
||||
let harness_overrides = ConfigOverrides {
|
||||
cwd: Some(project),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let with_project_layers = ConfigBuilder::default()
|
||||
.codex_home(codex_home.clone())
|
||||
.harness_overrides(harness_overrides.clone())
|
||||
.build()
|
||||
.await?;
|
||||
assert_eq!(with_project_layers.model.as_deref(), Some("from-project"));
|
||||
|
||||
let thread_agnostic = ConfigBuilder::default()
|
||||
.codex_home(codex_home)
|
||||
.harness_overrides(harness_overrides)
|
||||
.thread_agnostic()
|
||||
.build()
|
||||
.await?;
|
||||
assert_eq!(thread_agnostic.model.as_deref(), Some("from-user"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn load_global_mcp_servers_returns_empty_if_missing() -> anyhow::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
|
||||
Reference in New Issue
Block a user