mirror of
https://github.com/openai/codex.git
synced 2026-11-03 19:53:25 +00:00
Default Guardian v2 to computer-use reviews with images (#40846)
## What changed - Default Guardian v2's review scope to computer-use tools. Set `features.guardianv2.review_scope.computer_use_only = false` to retain the broader tool review scope. - Include images in Guardian transcripts by default. Set `features.guardianv2.transcript.include_images = false` to disable them. ## Testing - Update configuration and app-server coverage for the new defaults and explicit broader-scope overrides. GitOrigin-RevId: 88c3cfe6dd2a96df052111794ad59c5c9ea39b78
This commit is contained in:
@@ -536,10 +536,11 @@ async fn guardian_v2_routes_scoped_tool_approvals(
|
||||
("approvals_reviewer = \"user\"", ApprovalsReviewer::User)
|
||||
}
|
||||
};
|
||||
let guardian_scope_config = if matches!(scope, GuardianToolScope::ComputerUseOnly { .. }) {
|
||||
"\n\n[features.guardianv2]\nenabled = true\n\n[features.guardianv2.review_scope]\ncomputer_use_only = true"
|
||||
} else {
|
||||
""
|
||||
let guardian_scope_config = match scope {
|
||||
GuardianToolScope::AllTools => {
|
||||
"\n\n[features.guardianv2]\nenabled = true\n\n[features.guardianv2.review_scope]\ncomputer_use_only = false"
|
||||
}
|
||||
GuardianToolScope::ComputerUseOnly { .. } => "\n\n[features.guardianv2]\nenabled = true",
|
||||
};
|
||||
let mut mock_config = MockResponsesConfig::new(&responses_url)
|
||||
.with_model(MODEL)
|
||||
@@ -550,9 +551,6 @@ async fn guardian_v2_routes_scoped_tool_approvals(
|
||||
"[mcp_servers.{server_name}]\nurl = \"{mcp_server_url}/mcp\"\ndefault_tools_approval_mode = \"prompt\"\n\n[analytics]\nenabled = true\n\n[otel]\nmetrics_exporter = {{ otlp-http = {{ endpoint = \"{responses_url}/metrics\", protocol = \"json\" }} }}{guardian_scope_config}"
|
||||
))
|
||||
.enable_feature(Feature::GuardianApproval);
|
||||
if matches!(scope, GuardianToolScope::AllTools) {
|
||||
mock_config = mock_config.enable_feature(Feature::GuardianV2);
|
||||
}
|
||||
if lifecycle.has_user_input() || lifecycle.has_root_user_input() {
|
||||
mock_config = mock_config.enable_feature(Feature::DefaultModeRequestUserInput);
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ impl GuardianV2Config {
|
||||
.review_scope
|
||||
.as_ref()
|
||||
.and_then(|review_scope| review_scope.computer_use_only)
|
||||
.unwrap_or(false)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
GuardianV2ReviewScope::ComputerUseOnly
|
||||
} else {
|
||||
@@ -265,7 +265,7 @@ impl GuardianV2Config {
|
||||
}),
|
||||
include_images: transcript_config
|
||||
.and_then(|transcript| transcript.include_images)
|
||||
.unwrap_or(false),
|
||||
.unwrap_or(true),
|
||||
max_message_entry_tokens,
|
||||
max_tool_entry_tokens,
|
||||
max_message_transcript_tokens,
|
||||
|
||||
@@ -13,22 +13,17 @@ use super::GuardianV2ReviewScope;
|
||||
use crate::async_scorer::transcript::truncate_entry;
|
||||
|
||||
#[test]
|
||||
fn sandboxed_exec_commands_are_excluded_by_default() {
|
||||
fn review_scope_is_computer_use_only_by_default() {
|
||||
let config = GuardianV2Config::from_overrides(GuardianV2ConfigToml::default()).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.review_scope,
|
||||
GuardianV2ReviewScope::Standard {
|
||||
sandboxed_exec_commands: false,
|
||||
}
|
||||
);
|
||||
assert_eq!(config.review_scope, GuardianV2ReviewScope::ComputerUseOnly);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sandboxed_exec_commands_can_be_included() {
|
||||
let config = GuardianV2Config::from_overrides(GuardianV2ConfigToml {
|
||||
review_scope: Some(GuardianV2ReviewScopeConfigToml {
|
||||
computer_use_only: None,
|
||||
computer_use_only: Some(false),
|
||||
sandboxed_exec_commands: Some(true),
|
||||
}),
|
||||
..Default::default()
|
||||
|
||||
@@ -142,7 +142,7 @@ async fn installed_extension_reconnects_after_auth_refresh() -> Result<()> {
|
||||
.get::<GuardianV2ScoreProgress>()
|
||||
.expect("Guardian v2 should initialize");
|
||||
let turn_store = ExtensionData::new("turn-1");
|
||||
let tool_name = ToolName::plain("read_file");
|
||||
let tool_name = ToolName::namespaced("mcp__node_repl__", "js");
|
||||
let payload = ToolPayload::Function {
|
||||
arguments: r#"{"path":"README.md"}"#.to_owned(),
|
||||
};
|
||||
@@ -175,7 +175,7 @@ async fn installed_extension_reconnects_after_auth_refresh() -> Result<()> {
|
||||
.fast_approval_decision(
|
||||
&session_store,
|
||||
thread_store,
|
||||
"review action",
|
||||
r#"{"tool":"mcp_tool_call","server":"node_repl"}"#,
|
||||
/*extension_metrics*/ None,
|
||||
)
|
||||
.await,
|
||||
@@ -675,7 +675,9 @@ async fn sample_configured_conversation_history(
|
||||
) -> Result<(serde_json::Value, TestCodex, ExtensionRegistry<Config>)> {
|
||||
let thread_server = responses::start_mock_server().await;
|
||||
let guardian_policy = guardian_policy.map(str::to_owned);
|
||||
let guardian_config = guardian_config.to_owned();
|
||||
let guardian_config = format!(
|
||||
"{guardian_config}\n[features.guardianv2.review_scope]\ncomputer_use_only = false\n"
|
||||
);
|
||||
let has_model_defaults = model_defaults.is_some();
|
||||
let builder = test_codex()
|
||||
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
@@ -692,10 +694,8 @@ async fn sample_configured_conversation_history(
|
||||
.with_model("gpt-5.5")
|
||||
.with_config(move |config| config.guardian_policy_config = guardian_policy)
|
||||
.with_pre_build_hook(move |home| {
|
||||
if !guardian_config.is_empty() {
|
||||
std::fs::write(home.join("config.toml"), guardian_config)
|
||||
.expect("Guardian v2 configuration should be written");
|
||||
}
|
||||
std::fs::write(home.join("config.toml"), guardian_config)
|
||||
.expect("Guardian v2 configuration should be written");
|
||||
});
|
||||
let mut builder = if let Some(model_defaults) = model_defaults {
|
||||
builder.with_model_info_override("gpt-5.5", move |model| {
|
||||
@@ -1387,7 +1387,7 @@ max_recent_non_user_entries = 8
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn contributor_includes_configured_transcript_images() -> Result<()> {
|
||||
async fn contributor_includes_transcript_images_by_default() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let history = vec![
|
||||
@@ -1426,9 +1426,6 @@ async fn contributor_includes_configured_transcript_images() -> Result<()> {
|
||||
let configuration = r#"
|
||||
[features.guardianv2]
|
||||
enabled = true
|
||||
|
||||
[features.guardianv2.transcript]
|
||||
include_images = true
|
||||
"#;
|
||||
let (request, _test, _registry) = sample_configured_conversation_history(
|
||||
history,
|
||||
@@ -1869,7 +1866,7 @@ async fn contributor_skips_models_requiring_managed_guardian_review() -> Result<
|
||||
.fast_approval_decision(
|
||||
&session_store,
|
||||
thread_store,
|
||||
"review action",
|
||||
r#"{"tool":"mcp_tool_call","server":"node_repl"}"#,
|
||||
/*extension_metrics*/ None,
|
||||
)
|
||||
.await,
|
||||
@@ -1877,7 +1874,7 @@ async fn contributor_skips_models_requiring_managed_guardian_review() -> Result<
|
||||
);
|
||||
|
||||
let turn_store = ExtensionData::new("turn-1");
|
||||
let tool_name = ToolName::plain("read_file");
|
||||
let tool_name = ToolName::namespaced("mcp__node_repl__", "js");
|
||||
let payload = ToolPayload::Function {
|
||||
arguments: json!({ "path": "protected.md" }).to_string(),
|
||||
};
|
||||
@@ -2262,7 +2259,7 @@ async fn contributor_reuses_the_latest_compatible_parent_compaction() -> Result<
|
||||
.with_pre_build_hook(|home| {
|
||||
std::fs::write(
|
||||
home.join("config.toml"),
|
||||
"[features.guardianv2]\nenabled = true\nmax_parent_compaction_tokens = 256\n",
|
||||
"[features.guardianv2]\nenabled = true\nmax_parent_compaction_tokens = 256\n\n[features.guardianv2.review_scope]\ncomputer_use_only = false\n",
|
||||
)
|
||||
.expect("Guardian v2 parent compaction configuration should be written");
|
||||
})
|
||||
|
||||
@@ -69,7 +69,7 @@ impl Default for TranscriptConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sources: vec![TranscriptSource::ToolCalls, TranscriptSource::ToolOutputs],
|
||||
include_images: false,
|
||||
include_images: true,
|
||||
max_message_entry_tokens: MAX_MESSAGE_ENTRY_TOKENS,
|
||||
max_tool_entry_tokens: MAX_TOOL_ENTRY_TOKENS,
|
||||
max_message_transcript_tokens: MAX_MESSAGE_TRANSCRIPT_TOKENS,
|
||||
|
||||
Reference in New Issue
Block a user