Skip to content

standalone websearch extension#23823

Open
sayan-oai wants to merge 2 commits into
mainfrom
codex/standalone-web-search-extension
Open

standalone websearch extension#23823
sayan-oai wants to merge 2 commits into
mainfrom
codex/standalone-web-search-extension

Conversation

@sayan-oai
Copy link
Copy Markdown
Collaborator

Summary

Add the extension-backed standalone web.run tool so Codex can call the standalone search endpoint through the codex-api search client and return its encrypted output to Responses.

  • gate the new tool behind standalone_web_search
  • install the extension in the app-server thread registry and hide hosted web_search when standalone search is enabled for OpenAI providers so the two paths stay mutually exclusive
  • build search context from persisted history using a small tail heuristic: previous user message, assistant text between the last two user turns capped at about 1k tokens, and current user message

Test Plan

  • cargo test -p codex-web-search-extension
  • cargo test -p codex-api
  • cargo test -p codex-core hosted_tools_follow_provider_auth_model_and_config_gates

@sayan-oai sayan-oai marked this pull request as ready for review May 21, 2026 04:41
@sayan-oai sayan-oai requested a review from a team as a code owner May 21, 2026 04:41
@sayan-oai sayan-oai changed the title [codex] Add standalone web search extension standalone websearch extension May 21, 2026
Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cdd92100c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +34 to +35
enabled: config.features.enabled(Feature::StandaloneWebSearch)
&& config.model_provider.is_openai(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor disabled web search before exposing web.run

For OpenAI threads with standalone_web_search enabled and web_search_mode = disabled (including requirement-constrained configs), this still marks the extension enabled, so tools() exposes web.run. The existing hosted path intentionally returns no web_search tool for WebSearchMode::Disabled, so this re-enables web access in contexts that configured it off.

Useful? React with 👍 / 👎.

Comment thread codex-rs/ext/web-search/src/tool.rs Outdated
reasoning: None,
input: recent_input(&history.items),
commands: Some(commands),
settings: None,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Forward configured search settings to alpha/search

When the standalone tool replaces hosted web_search, this sends settings: None, dropping the configured cached/live mode and web_search_config constraints such as allowed domains, user location, and context size. In environments with allowed_domains or cached-only web search configured, web.run calls go to the standalone endpoint without those constraints, unlike create_web_search_tool which applies them to the hosted tool.

Useful? React with 👍 / 👎.

Comment on lines +92 to +94
if role != "assistant" {
return true;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Badge Cap user messages in search context

When a user prompt contains a large paste or data-URL image, this early return excludes user messages from the only token budget even though recent_input includes the previous and current user messages. That sends unbounded model-visible input to alpha/search and can exceed the repository's hard context caps; cap or filter user content as well as assistant text.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I let you judge this one but that sounds interesting

Comment thread codex-rs/Cargo.toml
"ext/goal",
"ext/guardian",
"ext/memories",
"ext/web-search",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the Bazel lockfile for the new crate

Adding ext/web-search and the new workspace dependency changes the Rust dependency graph, but this commit does not update MODULE.bazel.lock. The repo guidance requires just bazel-lock-update after Rust dependency changes; without the refreshed lockfile, Bazel lock checks/builds will see drift once this new crate/dependency is resolved.

Useful? React with 👍 / 👎.

let provider_capabilities = turn_context.provider.capabilities();
let web_search_mode = provider_capabilities
.web_search
let standalone_web_search = turn_context
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is you want this logic to stand, you also need to install the extension on the core-api for example + sync with training depending on how they spawn codex through the bridge


---

## Decision boundary
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we have this section. It does not really seem related to the extension...

Comment on lines +92 to +94
if role != "assistant" {
return true;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I let you judge this one but that sounds interesting

}

impl WebSearchExtensionConfig {
fn from_config(config: &Config) -> Self {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be a proper impl From<>?


const ASSISTANT_CONTEXT_TOKEN_LIMIT: usize = 1_000;

/// Builds the persisted conversation tail for standalone web search.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like most of this code should live closer to RolloutItem and the protocol in general no?

pub fn install(
registry: &mut ExtensionRegistryBuilder<Config>,
auth_manager: Arc<AuthManager>,
thread_store: Arc<dyn ThreadStore>,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want first-party tool extensions to reach back into ThreadStore to reconstruct model context themselves? The existing extension-api already pushes thread/turn/... states through scoped ExtensionData, and web.run only needs the recent search context tail here. If persisted history is intentionally part of the tool-extension contract, this seems better making explicit. Otherwise I think the API should expose the relevant recent context instead of making this extension depend on the full thread store

Copy link
Copy Markdown

@usgenes39-dotcom usgenes39-dotcom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found two blocking standalone-search semantics issues on the current head.

Current head fixes the earlier disabled-mode and settings-forwarding problems, but recent_input still sends unbounded user text/image content to alpha/search, and hosted web_search is hidden for OpenAI providers even in ThreadManager paths that do not install the standalone extension. That creates both unbounded search-context/cost risk and a product regression where web search disappears outside app-server. CI is not fully green on this head because the Bazel workflow was cancelled, and the PR is currently reported as not mergeable.

};
if role != "assistant" {
return true;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current head still leaves the user side outside the only context budget. cap_assistant_text caps assistant output, but both recent user messages are retained verbatim, and the test below explicitly preserves InputImage data URLs. recent_input then sends those items to alpha/search, so a large paste or base64 image in either the previous or current user message can bypass the 1k-token cap, exceed the standalone search request budget, and leak irrelevant/high-cost payloads into every web.run call. Please cap user text too and drop or summarize non-text/image content before building SearchInput; cover huge previous/current user messages and data URL images.

.features
.enabled(Feature::StandaloneWebSearch)
&& turn_context.provider.info().is_openai();
let web_search_mode = (!standalone_web_search && provider_capabilities.web_search)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suppresses hosted web_search based only on the feature flag and OpenAI provider, but the standalone extension is only installed by app-server’s thread_extensions. Other ThreadManager entry points still use empty_extension_registry() (for example mcp-server/src/message_processor.rs, core/src/prompt_debug.rs, and thread-manager-sample / core-api-style callers), so when the feature is enabled there, hosted search is hidden and no web.run tool is contributed. That silently removes web search for those surfaces. Please either install the web-search extension in every ThreadManager path that can enable the feature, or only hide hosted web_search when the standalone tool is actually present; add coverage for feature-enabled OpenAI config with an empty extension registry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants