Revert "feat: support template interpolation in multi-agent usage hints" (#21337)

Reverts openai/codex#20973
This commit is contained in:
jif-oai
2026-05-06 12:33:37 +02:00
committed by GitHub
Unverified
parent 06e5dfa4dd
commit cc84e6bc6d
4 changed files with 85 additions and 313 deletions
+85 -4
View File
@@ -1,12 +1,19 @@
use anyhow::Context;
use codex_config::config_toml::ConfigLockfileToml;
use codex_config::config_toml::ConfigToml;
use codex_config::types::MemoriesToml;
use codex_features::AppsMcpPathOverrideConfigToml;
use codex_features::Feature;
use codex_features::FeatureToml;
use codex_features::FeaturesToml;
use codex_features::MultiAgentV2ConfigToml;
use codex_protocol::ThreadId;
use crate::config::template_interpolation::materialized_config_toml;
use crate::config::Config;
use crate::config_lock::ConfigLockReplayOptions;
use crate::config_lock::clear_config_lock_debug_controls;
use crate::config_lock::config_lockfile;
use crate::config_lock::toml_round_trip;
use crate::config_lock::validate_config_lock_replay;
use super::SessionConfiguration;
@@ -74,12 +81,20 @@ fn session_configuration_to_lock_config_toml(
sc: &SessionConfiguration,
) -> anyhow::Result<ConfigToml> {
let config = sc.original_config_do_not_use.as_ref();
let mut lock_config = materialized_config_toml(config)?;
// Start from the resolved layer stack, then patch in values that are only
// known after session setup. Export and replay validation both use this
// path, so every field here is part of the lockfile contract.
let mut lock_config: ConfigToml = config
.config_layer_stack
.effective_config()
.try_into()
.context("failed to deserialize effective config for config lock")?;
if config.config_lock_save_fields_resolved_from_model_catalog {
save_session_resolved_fields(sc, &mut lock_config);
}
save_config_resolved_fields(config, &mut lock_config)?;
drop_lockfile_inputs(&mut lock_config);
Ok(lock_config)
@@ -103,6 +118,64 @@ fn save_session_resolved_fields(sc: &SessionConfiguration, lock_config: &mut Con
lock_config.approvals_reviewer = Some(sc.approvals_reviewer);
}
/// Saves values stored on `Config` after higher-level resolution,
/// normalization, defaulting, or feature materialization.
///
/// Persist the resolved representation so replay compares against the behavior
/// Codex actually ran with, not only the user-authored TOML inputs.
fn save_config_resolved_fields(
config: &Config,
lock_config: &mut ConfigToml,
) -> anyhow::Result<()> {
lock_config.web_search = Some(config.web_search_mode.value());
lock_config.model_provider = Some(config.model_provider_id.clone());
lock_config.plan_mode_reasoning_effort = config.plan_mode_reasoning_effort;
lock_config.model_verbosity = config.model_verbosity;
lock_config.include_permissions_instructions = Some(config.include_permissions_instructions);
lock_config.include_apps_instructions = Some(config.include_apps_instructions);
lock_config.include_environment_context = Some(config.include_environment_context);
lock_config.background_terminal_max_timeout = Some(config.background_terminal_max_timeout);
// Feature aliases and feature configs need to be written in their resolved
// form; otherwise replay can drift when a legacy key maps to the same
// runtime feature.
let features = lock_config
.features
.get_or_insert_with(FeaturesToml::default);
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(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)),
path: config.apps_mcp_path_override.clone(),
}));
lock_config.memories = Some(resolved_config_to_toml::<MemoriesToml>(
&config.memories,
"memories",
)?);
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 config.features.enabled(Feature::MultiAgentV2) {
None
} else {
config.agent_max_threads
};
agents.max_depth = Some(config.agent_max_depth);
agents.job_max_runtime_seconds = config.agent_job_max_runtime_seconds;
agents.interrupt_message = Some(config.agent_interrupt_message_enabled);
lock_config
.skills
.get_or_insert_with(Default::default)
.include_instructions = Some(config.include_skill_instructions);
Ok(())
}
fn drop_lockfile_inputs(lock_config: &mut ConfigToml) {
// The lockfile should contain replayable values, not the profile,
// debug-control, file-include, and environment-specific inputs that
@@ -122,11 +195,19 @@ fn drop_lockfile_inputs(lock_config: &mut ConfigToml) {
lock_config.experimental_use_freeform_apply_patch = None;
}
fn resolved_config_to_toml<Toml>(
value: &impl serde::Serialize,
label: &'static str,
) -> anyhow::Result<Toml>
where
Toml: serde::de::DeserializeOwned + serde::Serialize,
{
toml_round_trip(value, label).map_err(anyhow::Error::from)
}
#[cfg(test)]
mod tests {
use super::*;
use codex_features::FeatureToml;
use codex_features::MultiAgentV2ConfigToml;
use pretty_assertions::assert_eq;
use std::sync::Arc;