Add indexed web search mode (#28489)

## Summary

- Add `web_search = "indexed"` alongside `disabled`, `cached`, and
`live`.
- Use that same resolved mode for both hosted and standalone web search.
- For hosted search, send `index_gated_web_access: true` with external
web access enabled only when `indexed` is selected.
- For standalone search, preserve the existing boolean wire values for
existing modes (`cached` maps to `false` and `live` to `true`) and send
`"indexed"` only for `indexed`; `disabled` keeps the tool unavailable.
- Carry the mode through managed configuration requirements and
generated schemas.

## Why

Indexed search provides a middle ground between cached-only search and
unrestricted live page fetching. Search queries can remain live while
direct page fetches are limited to URLs admitted by the server.

The existing `web_search` setting remains the single source of truth, so
hosted and standalone executors cannot drift into different access
modes. Without an explicit `indexed` selection, the existing
model-visible tool and request shapes are unchanged.

```toml
web_search = "indexed"

[features]
standalone_web_search = true
```

## Validation

- `just fmt`
- `just test -p codex-api` (`126 passed`)
- `just test -p codex-web-search-extension` (`7 passed`)
- `just test -p codex-core
code_mode_can_call_indexed_standalone_web_search` (`1 passed`)
- Focused configuration, hosted request, standalone request, and
managed-requirement coverage is included in the PR; remaining suites run
in CI.

The full workspace test suite was not run locally.
This commit is contained in:
Winston Howes
2026-06-19 05:35:57 -07:00
committed by GitHub
Unverified
parent 7951397e4a
commit 3a2712ea14
24 changed files with 204 additions and 23 deletions
+2 -1
View File
@@ -55,6 +55,7 @@ mod tests {
use crate::provider::RetryConfig;
use crate::search::AllowedCaller;
use crate::search::ApproximateLocation;
use crate::search::ExternalWebAccess;
use crate::search::LocationType;
use crate::search::OpenOperation;
use crate::search::SearchCommands;
@@ -193,7 +194,7 @@ mod tests {
caption: Some(true),
}),
allowed_callers: Some(vec![AllowedCaller::Direct]),
external_web_access: Some(true),
external_web_access: Some(ExternalWebAccess::Boolean(true)),
}),
max_output_tokens: Some(2500),
},
+2
View File
@@ -81,6 +81,8 @@ pub use crate::requests::Compression;
pub use crate::search::AllowedCaller;
pub use crate::search::ApproximateLocation;
pub use crate::search::ClickOperation;
pub use crate::search::ExternalWebAccess;
pub use crate::search::ExternalWebAccessMode;
pub use crate::search::FinanceAssetType;
pub use crate::search::FinanceOperation;
pub use crate::search::FindOperation;
+16 -1
View File
@@ -211,6 +211,21 @@ pub enum SearchResponseLength {
Long,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExternalWebAccessMode {
Offline,
Indexed,
Online,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(untagged)]
pub enum ExternalWebAccess {
Boolean(bool),
Mode(ExternalWebAccessMode),
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
pub struct SearchSettings {
#[serde(skip_serializing_if = "Option::is_none")]
@@ -224,7 +239,7 @@ pub struct SearchSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub allowed_callers: Option<Vec<AllowedCaller>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub external_web_access: Option<bool>,
pub external_web_access: Option<ExternalWebAccess>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]