mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
codex: keep config lock independent of runtime lock
This commit is contained in:
@@ -8,7 +8,6 @@ use codex_features::FeatureToml;
|
||||
use codex_features::FeaturesToml;
|
||||
use codex_features::MultiAgentV2ConfigToml;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::MultiAgentVersion;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::config_lock::ConfigLockReplayOptions;
|
||||
@@ -21,7 +20,6 @@ use super::SessionConfiguration;
|
||||
|
||||
pub(crate) async fn validate_config_lock_if_configured(
|
||||
session_configuration: &SessionConfiguration,
|
||||
multi_agent_version: Option<MultiAgentVersion>,
|
||||
) -> anyhow::Result<()> {
|
||||
if session_configuration.session_source.is_non_root_agent() {
|
||||
return Ok(());
|
||||
@@ -33,8 +31,7 @@ pub(crate) async fn validate_config_lock_if_configured(
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
let actual = session_configuration
|
||||
.to_config_lockfile_toml_with_multi_agent_version(multi_agent_version)?;
|
||||
let actual = session_configuration.to_config_lockfile_toml()?;
|
||||
let config = session_configuration.original_config_do_not_use.as_ref();
|
||||
let options = ConfigLockReplayOptions {
|
||||
allow_codex_version_mismatch: config.config_lock_allow_codex_version_mismatch,
|
||||
@@ -47,15 +44,13 @@ pub(crate) async fn validate_config_lock_if_configured(
|
||||
pub(crate) async fn export_config_lock_if_configured(
|
||||
session_configuration: &SessionConfiguration,
|
||||
conversation_id: ThreadId,
|
||||
multi_agent_version: Option<MultiAgentVersion>,
|
||||
) -> anyhow::Result<()> {
|
||||
let config = session_configuration.original_config_do_not_use.as_ref();
|
||||
let Some(export_dir) = config.config_lock_export_dir.as_ref() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let lock = session_configuration
|
||||
.to_config_lockfile_toml_with_multi_agent_version(multi_agent_version)?;
|
||||
let lock = session_configuration.to_config_lockfile_toml()?;
|
||||
let lock = toml::to_string_pretty(&lock).context("failed to serialize config lock")?;
|
||||
let path = export_dir.join(format!("{conversation_id}.config.lock.toml"));
|
||||
|
||||
@@ -75,28 +70,15 @@ pub(crate) async fn export_config_lock_if_configured(
|
||||
}
|
||||
|
||||
impl SessionConfiguration {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn to_config_lockfile_toml(&self) -> anyhow::Result<ConfigLockfileToml> {
|
||||
self.to_config_lockfile_toml_with_multi_agent_version(
|
||||
self.original_config_do_not_use
|
||||
.multi_agent_version_from_features(),
|
||||
)
|
||||
}
|
||||
|
||||
fn to_config_lockfile_toml_with_multi_agent_version(
|
||||
&self,
|
||||
multi_agent_version: Option<MultiAgentVersion>,
|
||||
) -> anyhow::Result<ConfigLockfileToml> {
|
||||
Ok(config_lockfile(session_configuration_to_lock_config_toml(
|
||||
self,
|
||||
multi_agent_version,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
fn session_configuration_to_lock_config_toml(
|
||||
sc: &SessionConfiguration,
|
||||
multi_agent_version: Option<MultiAgentVersion>,
|
||||
) -> anyhow::Result<ConfigToml> {
|
||||
let config = sc.original_config_do_not_use.as_ref();
|
||||
// Start from the resolved layer stack, then patch in values that are only
|
||||
@@ -112,7 +94,7 @@ fn session_configuration_to_lock_config_toml(
|
||||
save_session_resolved_fields(sc, &mut lock_config);
|
||||
}
|
||||
|
||||
save_config_resolved_fields(config, multi_agent_version, &mut lock_config)?;
|
||||
save_config_resolved_fields(config, &mut lock_config)?;
|
||||
drop_lockfile_inputs(&mut lock_config);
|
||||
|
||||
Ok(lock_config)
|
||||
@@ -143,7 +125,6 @@ fn save_session_resolved_fields(sc: &SessionConfiguration, lock_config: &mut Con
|
||||
/// Codex actually ran with, not only the user-authored TOML inputs.
|
||||
fn save_config_resolved_fields(
|
||||
config: &Config,
|
||||
multi_agent_version: Option<MultiAgentVersion>,
|
||||
lock_config: &mut ConfigToml,
|
||||
) -> anyhow::Result<()> {
|
||||
lock_config.web_search = Some(config.web_search_mode.value());
|
||||
@@ -163,16 +144,10 @@ fn save_config_resolved_fields(
|
||||
let features = lock_config
|
||||
.features
|
||||
.get_or_insert_with(FeaturesToml::default);
|
||||
let mut materialized_features = config.features.get().clone();
|
||||
materialized_features.set_enabled(Feature::Collab, multi_agent_version.is_some());
|
||||
materialized_features.set_enabled(
|
||||
Feature::MultiAgentV2,
|
||||
multi_agent_version == Some(MultiAgentVersion::V2),
|
||||
);
|
||||
features.materialize_resolved_enabled(&materialized_features);
|
||||
features.materialize_resolved_enabled(config.features.get());
|
||||
let mut multi_agent_v2: MultiAgentV2ConfigToml =
|
||||
resolved_config_to_toml(&config.multi_agent_v2, "features.multi_agent_v2")?;
|
||||
multi_agent_v2.enabled = Some(multi_agent_version == Some(MultiAgentVersion::V2));
|
||||
multi_agent_v2.enabled = Some(config.features.enabled(Feature::MultiAgentV2));
|
||||
features.multi_agent_v2 = Some(FeatureToml::Config(multi_agent_v2));
|
||||
features.apps_mcp_path_override = Some(FeatureToml::Config(AppsMcpPathOverrideConfigToml {
|
||||
enabled: Some(config.features.enabled(Feature::AppsMcpPathOverride)),
|
||||
@@ -186,10 +161,10 @@ fn save_config_resolved_fields(
|
||||
let agents = lock_config.agents.get_or_insert_with(Default::default);
|
||||
// Multi-agent v2 owns thread fanout through its feature config. Preserve
|
||||
// the legacy agents.max_threads setting only when v2 is disabled.
|
||||
agents.max_threads = if multi_agent_version == Some(MultiAgentVersion::V2) {
|
||||
agents.max_threads = if config.features.enabled(Feature::MultiAgentV2) {
|
||||
None
|
||||
} else {
|
||||
config.effective_agent_max_threads(multi_agent_version)?
|
||||
config.agent_max_threads
|
||||
};
|
||||
agents.max_depth = Some(config.agent_max_depth);
|
||||
agents.job_max_runtime_seconds = config.agent_job_max_runtime_seconds;
|
||||
@@ -298,46 +273,6 @@ mod tests {
|
||||
assert_eq!(lockfile.version, crate::config_lock::CONFIG_LOCK_VERSION);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn lock_projects_multi_agent_version_over_current_feature_flags() {
|
||||
let mut sc = crate::session::tests::make_session_configuration_for_tests().await;
|
||||
let mut config = (*sc.original_config_do_not_use).clone();
|
||||
config
|
||||
.features
|
||||
.enable(Feature::MultiAgentV2)
|
||||
.expect("test config should allow feature update");
|
||||
sc.original_config_do_not_use = Arc::new(config);
|
||||
|
||||
for (multi_agent_version, collab, multi_agent_v2) in [
|
||||
(None, false, false),
|
||||
(Some(MultiAgentVersion::V1), true, false),
|
||||
(Some(MultiAgentVersion::V2), true, true),
|
||||
] {
|
||||
let lockfile = sc
|
||||
.to_config_lockfile_toml_with_multi_agent_version(multi_agent_version)
|
||||
.expect("lock should serialize");
|
||||
let lock = &lockfile.config;
|
||||
let entries = lock
|
||||
.features
|
||||
.as_ref()
|
||||
.expect("lock should materialize features")
|
||||
.entries();
|
||||
assert_eq!(entries.get(Feature::Collab.key()), Some(&collab));
|
||||
assert_eq!(
|
||||
entries.get(Feature::MultiAgentV2.key()),
|
||||
Some(&multi_agent_v2)
|
||||
);
|
||||
assert_eq!(
|
||||
lock.agents
|
||||
.as_ref()
|
||||
.expect("lock should materialize agent config")
|
||||
.max_threads
|
||||
.is_none(),
|
||||
multi_agent_version == Some(MultiAgentVersion::V2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn lock_skips_session_values_when_model_catalog_fields_are_not_saved() {
|
||||
let mut sc = crate::session::tests::make_session_configuration_for_tests().await;
|
||||
|
||||
@@ -888,17 +888,8 @@ impl Session {
|
||||
))
|
||||
.await;
|
||||
session_configuration.thread_name = thread_name.clone();
|
||||
validate_config_lock_if_configured(
|
||||
&session_configuration,
|
||||
initial_multi_agent_version,
|
||||
)
|
||||
.await?;
|
||||
export_config_lock_if_configured(
|
||||
&session_configuration,
|
||||
thread_id,
|
||||
initial_multi_agent_version,
|
||||
)
|
||||
.await?;
|
||||
validate_config_lock_if_configured(&session_configuration).await?;
|
||||
export_config_lock_if_configured(&session_configuration, thread_id).await?;
|
||||
let state = SessionState::new(session_configuration.clone());
|
||||
let managed_network_requirements_configured = config
|
||||
.config_layer_stack
|
||||
|
||||
Reference in New Issue
Block a user