mirror of
https://github.com/openai/codex.git
synced 2026-10-26 18:38:47 +00:00
## Why `features.multi_agent_v2` can be represented as either a legacy boolean toggle or a table with an `enabled` field and nested settings. Layering or editing configs that mix these forms could replace one form with the other and discard the enabled state or nested settings. ## What changed - Normalize boolean toggles to the table's `enabled` field when merging config layers, applying CLI overrides, and editing user or profile config. - Preserve nested multi-agent settings when toggling the feature, while keeping ordinary replacement semantics for unrelated paths. - Attribute normalized `enabled` values to the layer that supplied the boolean toggle so config write results report overrides correctly. ## Testing Added coverage for layered config, CLI overrides, config edits, app-server writes, and origin metadata using both root and profile feature paths. GitOrigin-RevId: 38b248c949b9ea5d6340a73d754f91c1834ac486
100 lines
3.9 KiB
Rust
100 lines
3.9 KiB
Rust
use crate::merge::is_multi_agent_v2_feature_path;
|
|
use crate::merge::merge_toml_values;
|
|
use toml::Value as TomlValue;
|
|
|
|
pub(crate) fn default_empty_table() -> TomlValue {
|
|
TomlValue::Table(Default::default())
|
|
}
|
|
|
|
pub fn build_cli_overrides_layer(cli_overrides: &[(String, TomlValue)]) -> TomlValue {
|
|
let mut root = default_empty_table();
|
|
for (path, value) in cli_overrides {
|
|
apply_toml_override(&mut root, path, value.clone());
|
|
}
|
|
root
|
|
}
|
|
|
|
/// Apply a single dotted-path override onto a TOML value.
|
|
fn apply_toml_override(root: &mut TomlValue, path: &str, value: TomlValue) {
|
|
use toml::value::Table;
|
|
|
|
let mut current = root;
|
|
let mut segments_iter = path.split('.').peekable();
|
|
let mut traversed_segments = Vec::new();
|
|
|
|
while let Some(segment) = segments_iter.next() {
|
|
traversed_segments.push(segment);
|
|
let is_last = segments_iter.peek().is_none();
|
|
|
|
if is_last {
|
|
match current {
|
|
TomlValue::Table(table) => {
|
|
if is_multi_agent_v2_feature_path(&traversed_segments)
|
|
&& let Some(existing) = table.get_mut(segment)
|
|
{
|
|
match (&mut *existing, &value) {
|
|
(TomlValue::Table(feature), TomlValue::Boolean(enabled)) => {
|
|
feature.insert("enabled".to_string(), TomlValue::Boolean(*enabled));
|
|
return;
|
|
}
|
|
(TomlValue::Boolean(enabled), TomlValue::Table(_)) => {
|
|
*existing = TomlValue::Table(Table::from_iter([(
|
|
"enabled".to_string(),
|
|
TomlValue::Boolean(*enabled),
|
|
)]));
|
|
merge_toml_values(existing, &value);
|
|
return;
|
|
}
|
|
(TomlValue::Table(_), TomlValue::Table(_)) => {
|
|
merge_toml_values(existing, &value);
|
|
return;
|
|
}
|
|
(
|
|
TomlValue::String(_)
|
|
| TomlValue::Integer(_)
|
|
| TomlValue::Float(_)
|
|
| TomlValue::Boolean(_)
|
|
| TomlValue::Datetime(_)
|
|
| TomlValue::Array(_)
|
|
| TomlValue::Table(_),
|
|
_,
|
|
) => {}
|
|
}
|
|
}
|
|
table.insert(segment.to_string(), value);
|
|
}
|
|
_ => {
|
|
let mut table = Table::new();
|
|
table.insert(segment.to_string(), value);
|
|
*current = TomlValue::Table(table);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
match current {
|
|
TomlValue::Table(table) => {
|
|
current = table
|
|
.entry(segment.to_string())
|
|
.or_insert_with(|| TomlValue::Table(Table::new()));
|
|
if is_multi_agent_v2_feature_path(&traversed_segments)
|
|
&& let TomlValue::Boolean(enabled) = current
|
|
{
|
|
*current = TomlValue::Table(Table::from_iter([(
|
|
"enabled".to_string(),
|
|
TomlValue::Boolean(*enabled),
|
|
)]));
|
|
}
|
|
}
|
|
_ => {
|
|
*current = TomlValue::Table(Table::new());
|
|
if let TomlValue::Table(tbl) = current {
|
|
current = tbl
|
|
.entry(segment.to_string())
|
|
.or_insert_with(|| TomlValue::Table(Table::new()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|