mirror of
https://github.com/openai/codex.git
synced 2026-10-23 18:08:45 +00:00
Add Guardian V3 feature configuration (#56459)
## What changed Register `guardianv3` as an under-development feature disabled by default. Accept either a boolean toggle or a table with an optional `enabled` field, and include both forms in the configuration schema. ## Testing Add coverage for boolean and table configuration, default behavior, and profile overrides, including inheritance when a profile omits `enabled`. GitOrigin-RevId: 75333be61b2e336e22fef907d6363b70f9f7225b
This commit is contained in:
@@ -90,6 +90,15 @@ pub fn features_schema(schema_gen: &mut SchemaGenerator) -> Schema {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if feature.id == codex_features::Feature::GuardianV3 {
|
||||
validation.properties.insert(
|
||||
feature.key.to_string(),
|
||||
schema_gen.subschema_for::<codex_features::FeatureToml<
|
||||
codex_features::GuardianV3ConfigToml,
|
||||
>>(),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if feature.id == codex_features::Feature::MultiAgentV2 {
|
||||
validation.properties.insert(
|
||||
feature.key.to_string(),
|
||||
|
||||
@@ -988,6 +988,9 @@
|
||||
"guardianv2_decisions_comparison": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"guardianv3": {
|
||||
"$ref": "#/definitions/FeatureToml_for_GuardianV3ConfigToml"
|
||||
},
|
||||
"hooks": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -1694,6 +1697,16 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"FeatureToml_for_GuardianV3ConfigToml": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/GuardianV3ConfigToml"
|
||||
}
|
||||
]
|
||||
},
|
||||
"FeatureToml_for_MultiAgentV2ConfigToml": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -2145,6 +2158,16 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"GuardianV3ConfigToml": {
|
||||
"additionalProperties": false,
|
||||
"description": "User-configurable settings for Guardian V3.",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"History": {
|
||||
"additionalProperties": false,
|
||||
"description": "Settings that govern if and what will be written to `~/.codex/history.jsonl`.",
|
||||
@@ -7506,6 +7529,9 @@
|
||||
"guardianv2_decisions_comparison": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"guardianv3": {
|
||||
"$ref": "#/definitions/FeatureToml_for_GuardianV3ConfigToml"
|
||||
},
|
||||
"hooks": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -284,6 +284,20 @@ where
|
||||
Ok(feature)
|
||||
}
|
||||
|
||||
/// User-configurable settings for Guardian V3.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct GuardianV3ConfigToml {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
impl FeatureConfig for GuardianV3ConfigToml {
|
||||
fn enabled(&self) -> Option<bool> {
|
||||
self.enabled
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct MultiAgentV2ConfigToml {
|
||||
|
||||
@@ -28,6 +28,7 @@ pub use feature_configs::GuardianV2ConfigToml;
|
||||
pub use feature_configs::GuardianV2ReviewScopeConfigToml;
|
||||
pub use feature_configs::GuardianV2TranscriptConfigToml;
|
||||
pub use feature_configs::GuardianV2TranscriptSource;
|
||||
pub use feature_configs::GuardianV3ConfigToml;
|
||||
pub use feature_configs::MultiAgentV2ConfigToml;
|
||||
pub use feature_configs::NetworkProxyConfigToml;
|
||||
pub use feature_configs::NetworkProxyDomainPermissionToml;
|
||||
@@ -401,6 +402,8 @@ pub enum Feature {
|
||||
GuardianV2,
|
||||
/// Run Decisions alongside Guardian V2 for measurement without changing approvals.
|
||||
GuardianV2DecisionsComparison,
|
||||
/// Enable Guardian V3 integrations.
|
||||
GuardianV3,
|
||||
/// Removed compatibility flag for the unused Guardian extension prototype.
|
||||
GuardianExt,
|
||||
/// Enable persisted thread goals and automatic goal continuation.
|
||||
@@ -900,6 +903,8 @@ pub struct FeaturesToml {
|
||||
)]
|
||||
pub guardianv2: Option<FeatureToml<GuardianV2ConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub guardianv3: Option<FeatureToml<GuardianV3ConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub multi_agent_v2: Option<FeatureToml<MultiAgentV2ConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub token_budget: Option<FeatureToml<TokenBudgetConfigToml>>,
|
||||
@@ -962,6 +967,9 @@ impl FeaturesToml {
|
||||
{
|
||||
entries.insert(Feature::GuardianThreadContext.key().to_string(), enabled);
|
||||
}
|
||||
if let Some(enabled) = self.guardianv3.as_ref().and_then(FeatureToml::enabled) {
|
||||
entries.insert(Feature::GuardianV3.key().to_string(), enabled);
|
||||
}
|
||||
if let Some(enabled) = self.multi_agent_v2.as_ref().and_then(FeatureToml::enabled) {
|
||||
entries.insert(Feature::MultiAgentV2.key().to_string(), enabled);
|
||||
}
|
||||
@@ -1964,6 +1972,12 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::GuardianV3,
|
||||
key: "guardianv3",
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::GuardianExt,
|
||||
key: "guardian_ext",
|
||||
|
||||
@@ -211,6 +211,43 @@ fn guardian_v2_feature_config_preserves_boolean_toggle() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guardian_v3_feature_config_resolves_base_and_profile_toggles() {
|
||||
for (base, profile, enabled) in [
|
||||
("guardianv3 = true", "", true),
|
||||
("guardianv3 = false", "", false),
|
||||
("[guardianv3]", "", false),
|
||||
("[guardianv3]\nenabled = true", "", true),
|
||||
("[guardianv3]\nenabled = false", "", false),
|
||||
(
|
||||
"[guardianv3]\nenabled = true",
|
||||
"[guardianv3]\nenabled = false",
|
||||
false,
|
||||
),
|
||||
(
|
||||
"[guardianv3]\nenabled = false",
|
||||
"[guardianv3]\nenabled = true",
|
||||
true,
|
||||
),
|
||||
("[guardianv3]\nenabled = true", "[guardianv3]", true),
|
||||
] {
|
||||
let base = toml::from_str::<FeaturesToml>(base).expect("base features");
|
||||
let profile = toml::from_str::<FeaturesToml>(profile).expect("profile features");
|
||||
let features = Features::from_sources(
|
||||
FeatureConfigSource {
|
||||
features: Some(&base),
|
||||
..Default::default()
|
||||
},
|
||||
FeatureConfigSource {
|
||||
features: Some(&profile),
|
||||
..Default::default()
|
||||
},
|
||||
FeatureOverrides::default(),
|
||||
);
|
||||
assert_eq!(features.enabled(Feature::GuardianV3), enabled);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guardian_thread_context_is_ignored_with_a_migration_notice() {
|
||||
let enabled_context = "[guardianv2]\nthread_context = true";
|
||||
|
||||
Reference in New Issue
Block a user