Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename index-gated web search to indexed
  • Loading branch information
winston-openai committed Jun 18, 2026
commit 3dcc8a69fcf485ebc8528e450e02d5e2987e8139

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 34 additions & 6 deletions codex-rs/config/src/config_requirements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ fn is_glob_metacharacter(ch: char) -> bool {
pub enum WebSearchModeRequirement {
Disabled,
Cached,
IndexGated,
Indexed,
Live,
}

Expand All @@ -678,7 +678,7 @@ impl From<WebSearchMode> for WebSearchModeRequirement {
match mode {
WebSearchMode::Disabled => WebSearchModeRequirement::Disabled,
WebSearchMode::Cached => WebSearchModeRequirement::Cached,
WebSearchMode::IndexGated => WebSearchModeRequirement::IndexGated,
WebSearchMode::Indexed => WebSearchModeRequirement::Indexed,
WebSearchMode::Live => WebSearchModeRequirement::Live,
}
}
Expand All @@ -689,7 +689,7 @@ impl From<WebSearchModeRequirement> for WebSearchMode {
match mode {
WebSearchModeRequirement::Disabled => WebSearchMode::Disabled,
WebSearchModeRequirement::Cached => WebSearchMode::Cached,
WebSearchModeRequirement::IndexGated => WebSearchMode::IndexGated,
WebSearchModeRequirement::Indexed => WebSearchMode::Indexed,
WebSearchModeRequirement::Live => WebSearchMode::Live,
}
}
Expand All @@ -700,7 +700,7 @@ impl fmt::Display for WebSearchModeRequirement {
match self {
WebSearchModeRequirement::Disabled => write!(f, "disabled"),
WebSearchModeRequirement::Cached => write!(f, "cached"),
WebSearchModeRequirement::IndexGated => write!(f, "index_gated"),
WebSearchModeRequirement::Indexed => write!(f, "indexed"),
WebSearchModeRequirement::Live => write!(f, "live"),
}
}
Expand Down Expand Up @@ -1349,8 +1349,8 @@ impl TryFrom<ConfigRequirementsWithSources> for ConfigRequirements {

let initial_value = if accepted.contains(&WebSearchModeRequirement::Cached) {
WebSearchMode::Cached
} else if accepted.contains(&WebSearchModeRequirement::IndexGated) {
WebSearchMode::IndexGated
} else if accepted.contains(&WebSearchModeRequirement::Indexed) {
WebSearchMode::Indexed
} else if accepted.contains(&WebSearchModeRequirement::Live) {
WebSearchMode::Live
} else {
Expand Down Expand Up @@ -2933,6 +2933,34 @@ allowed_approvals_reviewers = ["user"]
Ok(())
}

#[test]
fn allowed_web_search_modes_supports_indexed() -> Result<()> {
let config: ConfigRequirementsToml = from_str(
r#"
allowed_web_search_modes = ["indexed"]
"#,
)?;
let requirements: ConfigRequirements = with_unknown_source(config).try_into()?;

assert_eq!(requirements.web_search_mode.value(), WebSearchMode::Indexed);
for mode in [WebSearchMode::Disabled, WebSearchMode::Indexed] {
assert!(requirements.web_search_mode.can_set(&mode).is_ok());
}
for mode in [WebSearchMode::Cached, WebSearchMode::Live] {
assert_eq!(
requirements.web_search_mode.can_set(&mode),
Err(ConstraintError::InvalidValue {
field_name: "web_search_mode",
candidate: format!("{mode:?}"),
allowed: "[Disabled, Indexed]".into(),
requirement_source: RequirementSource::Unknown,
})
);
}

Ok(())
}

#[test]
fn allowed_web_search_modes_allows_disabled() -> Result<()> {
let toml_str = r#"
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/config/src/config_toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ pub struct ConfigToml {
pub experimental_thread_store: Option<ThreadStoreToml>,
pub projects: Option<HashMap<String, ProjectConfig>>,

/// Controls the web search tool mode: disabled, cached, index-gated, or live.
/// Controls the web search tool mode: disabled, cached, indexed, or live.
pub web_search: Option<WebSearchMode>,

/// Nested tools section for feature toggles
Expand Down
6 changes: 3 additions & 3 deletions codex-rs/core/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4323,7 +4323,7 @@
"enum": [
"disabled",
"cached",
"index_gated",
"indexed",
"live"
],
"type": "string"
Expand Down Expand Up @@ -5267,7 +5267,7 @@
"$ref": "#/definitions/WebSearchMode"
}
],
"description": "Controls the web search tool mode: disabled, cached, index-gated, or live."
"description": "Controls the web search tool mode: disabled, cached, indexed, or live."
},
"windows": {
"allOf": [
Expand All @@ -5281,4 +5281,4 @@
},
"title": "ConfigToml",
"type": "object"
}
}
10 changes: 5 additions & 5 deletions codex-rs/core/src/config/config_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4975,11 +4975,11 @@ fn web_search_mode_disabled_overrides_legacy_request() {
}

#[test]
fn web_search_mode_for_turn_preserves_index_gated_for_disabled_permissions() {
let web_search_mode = Constrained::allow_any(WebSearchMode::IndexGated);
fn web_search_mode_for_turn_preserves_indexed_for_disabled_permissions() {
let web_search_mode = Constrained::allow_any(WebSearchMode::Indexed);
let mode = resolve_web_search_mode_for_turn(&web_search_mode, &PermissionProfile::Disabled);

assert_eq!(mode, WebSearchMode::IndexGated);
assert_eq!(mode, WebSearchMode::Indexed);
}

#[test]
Expand Down Expand Up @@ -5029,11 +5029,11 @@ fn web_search_mode_for_turn_falls_back_when_live_is_disallowed() -> anyhow::Resu
}

#[test]
fn web_search_mode_for_turn_does_not_implicitly_select_index_gated() -> anyhow::Result<()> {
fn web_search_mode_for_turn_does_not_implicitly_select_indexed() -> anyhow::Result<()> {
let allowed = [
WebSearchMode::Disabled,
WebSearchMode::Cached,
WebSearchMode::IndexGated,
WebSearchMode::Indexed,
];
let web_search_mode = Constrained::new(WebSearchMode::Cached, move |candidate| {
if allowed.contains(candidate) {
Expand Down
5 changes: 1 addition & 4 deletions codex-rs/core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2513,10 +2513,7 @@ pub(crate) fn resolve_web_search_mode_for_turn(
let preferred = web_search_mode.value();

if matches!(permission_profile, PermissionProfile::Disabled)
&& !matches!(
preferred,
WebSearchMode::Disabled | WebSearchMode::IndexGated
)
&& !matches!(preferred, WebSearchMode::Disabled | WebSearchMode::Indexed)
{
for mode in [
WebSearchMode::Live,
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/core/src/tools/hosted_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub fn create_image_generation_tool(output_format: &str) -> ToolSpec {
pub fn create_web_search_tool(options: WebSearchToolOptions<'_>) -> Option<ToolSpec> {
let (external_web_access, index_gated_web_access) = match options.web_search_mode {
Some(WebSearchMode::Cached) => (false, None),
Some(WebSearchMode::IndexGated) => (true, Some(true)),
Some(WebSearchMode::Indexed) => (true, Some(true)),
Some(WebSearchMode::Live) => (true, None),
Some(WebSearchMode::Disabled) | None => return None,
};
Expand Down
19 changes: 0 additions & 19 deletions codex-rs/core/src/tools/hosted_spec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,6 @@ fn web_search_tool_preserves_configured_options() {
);
}

#[test]
fn index_gated_web_search_tool_sets_index_gate() {
assert_eq!(
create_web_search_tool(WebSearchToolOptions {
web_search_mode: Some(WebSearchMode::IndexGated),
web_search_config: None,
web_search_tool_type: WebSearchToolType::Text,
}),
Some(ToolSpec::WebSearch {
external_web_access: Some(true),
index_gated_web_access: Some(true),
filters: None,
user_location: None,
search_context_size: None,
search_content_types: None,
})
);
}

#[test]
fn web_search_tool_is_absent_when_disabled() {
assert_eq!(
Expand Down
113 changes: 12 additions & 101 deletions codex-rs/core/tests/suite/code_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,108 +219,19 @@ async fn run_code_mode_turn_with_model_and_config(

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_can_call_standalone_web_search() -> Result<()> {
skip_if_no_network!(Ok(()));

let server = responses::start_mock_server().await;
Mock::given(method("POST"))
.and(path("/v1/alpha/search"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"output": "Search result",
})))
.expect(1)
.mount(&server)
.await;

responses::mount_sse_once(
&server,
sse(vec![
ev_response_created("resp-1"),
ev_custom_tool_call(
"call-1",
"exec",
r#"
const result = await tools.web__run({
search_query: [{ q: "standalone web search" }],
});
text(result);
"#,
),
ev_completed("resp-1"),
]),
)
.await;
let follow_up_mock = responses::mount_sse_once(
&server,
sse(vec![
ev_assistant_message("msg-1", "done"),
ev_completed("resp-2"),
]),
)
.await;

let auth = CodexAuth::from_api_key("dummy");
let auth_manager = codex_core::test_support::auth_manager_from_auth(auth.clone());
let mut extension_builder = ExtensionRegistryBuilder::<Config>::new();
install_web_search_extension(&mut extension_builder, auth_manager);
let mut builder = test_codex()
.with_auth(auth)
.with_extensions(Arc::new(extension_builder.build()))
.with_model("test-gpt-5.1-codex")
.with_config(|config| {
config
.features
.enable(Feature::CodeMode)
.expect("code mode should be enabled");
config
.features
.enable(Feature::StandaloneWebSearch)
.expect("standalone web search should be enabled");
config
.web_search_mode
.set(WebSearchMode::Live)
.expect("web search mode should be accepted");
});
let test = builder.build(&server).await?;

test.submit_turn("Search the web from code mode").await?;
assert_code_mode_standalone_web_search(WebSearchMode::Live, serde_json::json!(true)).await
}

let search_request = server
.received_requests()
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_can_call_indexed_standalone_web_search() -> Result<()> {
assert_code_mode_standalone_web_search(WebSearchMode::Indexed, serde_json::json!("index_only"))
.await
.expect("received requests should be available")
.into_iter()
.find(|request| request.url.path() == "/v1/alpha/search")
.expect("standalone search request should be sent");
let search_body = search_request
.body_json::<Value>()
.expect("search request body should be JSON");
assert_eq!(
search_body["model"],
serde_json::json!("test-gpt-5.1-codex")
);
assert_eq!(
search_body["commands"],
serde_json::json!({
"search_query": [{"q": "standalone web search"}],
})
);
assert_eq!(
search_body["settings"],
serde_json::json!({
"allowed_callers": ["direct"],
"external_web_access": true,
})
);
assert_eq!(
custom_tool_output_last_non_empty_text(&follow_up_mock.single_request(), "call-1"),
Some("Search result".to_string())
);

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_can_call_index_gated_standalone_web_search() -> Result<()> {
async fn assert_code_mode_standalone_web_search(
web_search_mode: WebSearchMode,
expected_external_web_access: Value,
) -> Result<()> {
skip_if_no_network!(Ok(()));

let server = responses::start_mock_server().await;
Expand Down Expand Up @@ -368,7 +279,7 @@ text(result);
.with_auth(auth)
.with_extensions(Arc::new(extension_builder.build()))
.with_model("test-gpt-5.1-codex")
.with_config(|config| {
.with_config(move |config| {
config
.features
.enable(Feature::CodeMode)
Expand All @@ -379,7 +290,7 @@ text(result);
.expect("standalone web search should be enabled");
config
.web_search_mode
.set(WebSearchMode::IndexGated)
.set(web_search_mode)
.expect("web search mode should be accepted");
});
let test = builder.build(&server).await?;
Expand Down Expand Up @@ -410,7 +321,7 @@ text(result);
search_body["settings"],
serde_json::json!({
"allowed_callers": ["direct"],
"external_web_access": "index_only",
"external_web_access": expected_external_web_access,
})
);
assert_eq!(
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/core/tests/suite/deprecation_notice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ async fn emits_deprecation_notice_for_web_search_feature_flag_values() -> anyhow
assert_eq!(
details.as_deref(),
Some(
"Set `web_search` to `\"live\"`, `\"index_gated\"`, `\"cached\"`, or `\"disabled\"` at the top level (or under a profile) in config.toml if you want to override it."
"Set `web_search` to `\"live\"`, `\"indexed\"`, `\"cached\"`, or `\"disabled\"` at the top level (or under a profile) in config.toml if you want to override it."
),
);
}
Expand Down
Loading
Loading