mirror of
https://github.com/openai/codex.git
synced 2026-04-29 08:56:38 +00:00
fix: enable per-turn updates to web search mode (#10040)
web_search can now be updated per-turn, for things like changes to sandbox policy. `SandboxPolicy::DangerFullAccess` now sets web_search to `live`, and the default is still `cached`. Added integration tests.
This commit is contained in:
@@ -38,7 +38,7 @@ async fn collect_tool_identifiers_for_model(model: &str) -> Vec<String> {
|
||||
.with_model(model)
|
||||
// Keep tool expectations stable when the default web_search mode changes.
|
||||
.with_config(|config| {
|
||||
config.web_search_mode = WebSearchMode::Cached;
|
||||
config.web_search_mode = Some(WebSearchMode::Cached);
|
||||
config.features.enable(Feature::CollaborationModes);
|
||||
});
|
||||
let test = builder
|
||||
|
||||
@@ -92,7 +92,7 @@ async fn prompt_tools_are_consistent_across_requests() -> anyhow::Result<()> {
|
||||
config.user_instructions = Some("be consistent and helpful".to_string());
|
||||
config.model = Some("gpt-5.1-codex-max".to_string());
|
||||
// Keep tool expectations stable when the default web_search mode changes.
|
||||
config.web_search_mode = WebSearchMode::Cached;
|
||||
config.web_search_mode = Some(WebSearchMode::Cached);
|
||||
config.features.enable(Feature::CollaborationModes);
|
||||
})
|
||||
.build(&server)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use codex_core::features::Feature;
|
||||
use codex_core::protocol::SandboxPolicy;
|
||||
use codex_protocol::config_types::WebSearchMode;
|
||||
use core_test_support::load_sse_fixture_with_id;
|
||||
use core_test_support::responses;
|
||||
@@ -25,7 +26,7 @@ fn find_web_search_tool(body: &Value) -> &Value {
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn web_search_mode_cached_sets_external_web_access_false_in_request_body() {
|
||||
async fn web_search_mode_cached_sets_external_web_access_false() {
|
||||
skip_if_no_network!();
|
||||
|
||||
let server = start_mock_server().await;
|
||||
@@ -35,7 +36,7 @@ async fn web_search_mode_cached_sets_external_web_access_false_in_request_body()
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5-codex")
|
||||
.with_config(|config| {
|
||||
config.web_search_mode = WebSearchMode::Cached;
|
||||
config.web_search_mode = Some(WebSearchMode::Cached);
|
||||
});
|
||||
let test = builder
|
||||
.build(&server)
|
||||
@@ -56,7 +57,7 @@ async fn web_search_mode_cached_sets_external_web_access_false_in_request_body()
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn web_search_mode_takes_precedence_over_legacy_flags_in_request_body() {
|
||||
async fn web_search_mode_takes_precedence_over_legacy_flags() {
|
||||
skip_if_no_network!();
|
||||
|
||||
let server = start_mock_server().await;
|
||||
@@ -67,7 +68,7 @@ async fn web_search_mode_takes_precedence_over_legacy_flags_in_request_body() {
|
||||
.with_model("gpt-5-codex")
|
||||
.with_config(|config| {
|
||||
config.features.enable(Feature::WebSearchRequest);
|
||||
config.web_search_mode = WebSearchMode::Cached;
|
||||
config.web_search_mode = Some(WebSearchMode::Cached);
|
||||
});
|
||||
let test = builder
|
||||
.build(&server)
|
||||
@@ -86,3 +87,90 @@ async fn web_search_mode_takes_precedence_over_legacy_flags_in_request_body() {
|
||||
"web_search mode should win over legacy web_search_request"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn web_search_mode_defaults_to_cached_when_unset() {
|
||||
skip_if_no_network!();
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let sse = sse_completed("resp-1");
|
||||
let resp_mock = responses::mount_sse_once(&server, sse).await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5-codex")
|
||||
.with_config(|config| {
|
||||
config.web_search_mode = None;
|
||||
config.features.disable(Feature::WebSearchCached);
|
||||
config.features.disable(Feature::WebSearchRequest);
|
||||
});
|
||||
let test = builder
|
||||
.build(&server)
|
||||
.await
|
||||
.expect("create test Codex conversation");
|
||||
|
||||
test.submit_turn_with_policy("hello default cached web search", SandboxPolicy::ReadOnly)
|
||||
.await
|
||||
.expect("submit turn");
|
||||
|
||||
let body = resp_mock.single_request().body_json();
|
||||
let tool = find_web_search_tool(&body);
|
||||
assert_eq!(
|
||||
tool.get("external_web_access").and_then(Value::as_bool),
|
||||
Some(false),
|
||||
"default web_search should be cached when unset"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn web_search_mode_updates_between_turns_with_sandbox_policy() {
|
||||
skip_if_no_network!();
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = responses::mount_sse_sequence(
|
||||
&server,
|
||||
vec![sse_completed("resp-1"), sse_completed("resp-2")],
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5-codex")
|
||||
.with_config(|config| {
|
||||
config.web_search_mode = None;
|
||||
config.features.disable(Feature::WebSearchCached);
|
||||
config.features.disable(Feature::WebSearchRequest);
|
||||
});
|
||||
let test = builder
|
||||
.build(&server)
|
||||
.await
|
||||
.expect("create test Codex conversation");
|
||||
|
||||
test.submit_turn_with_policy("hello cached", SandboxPolicy::ReadOnly)
|
||||
.await
|
||||
.expect("submit first turn");
|
||||
test.submit_turn_with_policy("hello live", SandboxPolicy::DangerFullAccess)
|
||||
.await
|
||||
.expect("submit second turn");
|
||||
|
||||
let requests = resp_mock.requests();
|
||||
assert_eq!(requests.len(), 2, "expected two response requests");
|
||||
|
||||
let first_body = requests[0].body_json();
|
||||
let first_tool = find_web_search_tool(&first_body);
|
||||
assert_eq!(
|
||||
first_tool
|
||||
.get("external_web_access")
|
||||
.and_then(Value::as_bool),
|
||||
Some(false),
|
||||
"read-only policy should default web_search to cached"
|
||||
);
|
||||
|
||||
let second_body = requests[1].body_json();
|
||||
let second_tool = find_web_search_tool(&second_body);
|
||||
assert_eq!(
|
||||
second_tool
|
||||
.get("external_web_access")
|
||||
.and_then(Value::as_bool),
|
||||
Some(true),
|
||||
"danger-full-access policy should default web_search to live"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user