chore: rm web-search-eligible header (#10660)
default-enablement of web_search is now client-side, no need to send eligibility headers to backend. Tested locally, headers no longer sent. will wait for corresponding backend change to deploy before merging
This commit is contained in:
parent
901d5b8fd6
commit
5fdf6f5efa
7 changed files with 12 additions and 144 deletions
|
|
@ -4,9 +4,9 @@
|
|||
//! configuration and state needed to talk to a provider (auth, provider selection, conversation id,
|
||||
//! and feature-gated request behavior).
|
||||
//!
|
||||
//! Per-turn settings (model selection, reasoning controls, telemetry context, web search
|
||||
//! eligibility, and turn metadata) are passed explicitly to streaming and unary methods so that the
|
||||
//! turn lifetime is visible at the call site.
|
||||
//! Per-turn settings (model selection, reasoning controls, telemetry context, and turn metadata)
|
||||
//! are passed explicitly to streaming and unary methods so that the turn lifetime is visible at the
|
||||
//! call site.
|
||||
//!
|
||||
//! A [`ModelClientSession`] is created per turn and is used to stream one or more Responses API
|
||||
//! requests during that turn. It caches a Responses WebSocket connection (opened lazily) and
|
||||
|
|
@ -82,7 +82,6 @@ use crate::model_provider_info::ModelProviderInfo;
|
|||
use crate::model_provider_info::WireApi;
|
||||
use crate::tools::spec::create_tools_json_for_responses_api;
|
||||
|
||||
pub const WEB_SEARCH_ELIGIBLE_HEADER: &str = "x-oai-web-search-eligible";
|
||||
pub const X_CODEX_TURN_STATE_HEADER: &str = "x-codex-turn-state";
|
||||
pub const X_CODEX_TURN_METADATA_HEADER: &str = "x-codex-turn-metadata";
|
||||
pub const X_RESPONSESAPI_INCLUDE_TIMING_METRICS_HEADER: &str =
|
||||
|
|
@ -115,9 +114,8 @@ struct ModelClientState {
|
|||
/// WebSocket fallback is session-scoped: once a turn activates the HTTP fallback, subsequent turns
|
||||
/// will also use HTTP for the remainder of the session.
|
||||
///
|
||||
/// Turn-scoped settings (model selection, reasoning controls, telemetry context, web search
|
||||
/// eligibility, and turn metadata) are passed explicitly to the relevant methods to keep turn
|
||||
/// lifetime visible at the call site.
|
||||
/// Turn-scoped settings (model selection, reasoning controls, telemetry context, and turn metadata)
|
||||
/// are passed explicitly to the relevant methods to keep turn lifetime visible at the call site.
|
||||
///
|
||||
/// This type is cheap to clone.
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -349,7 +347,6 @@ impl ModelClientSession {
|
|||
model_info: &ModelInfo,
|
||||
effort: Option<ReasoningEffortConfig>,
|
||||
summary: ReasoningSummaryConfig,
|
||||
web_search_eligible: bool,
|
||||
turn_metadata_header: Option<&str>,
|
||||
compression: Compression,
|
||||
) -> ApiResponsesOptions {
|
||||
|
|
@ -404,7 +401,6 @@ impl ModelClientSession {
|
|||
session_source: Some(self.client.state.session_source.clone()),
|
||||
extra_headers: build_responses_headers(
|
||||
self.client.state.beta_features_header.as_deref(),
|
||||
web_search_eligible,
|
||||
Some(&self.turn_state),
|
||||
turn_metadata_header.as_ref(),
|
||||
),
|
||||
|
|
@ -529,7 +525,6 @@ impl ModelClientSession {
|
|||
otel_manager: &OtelManager,
|
||||
effort: Option<ReasoningEffortConfig>,
|
||||
summary: ReasoningSummaryConfig,
|
||||
web_search_eligible: bool,
|
||||
turn_metadata_header: Option<&str>,
|
||||
) -> Result<ResponseStream> {
|
||||
if let Some(path) = &*CODEX_RS_SSE_FIXTURE {
|
||||
|
|
@ -571,7 +566,6 @@ impl ModelClientSession {
|
|||
model_info,
|
||||
effort,
|
||||
summary,
|
||||
web_search_eligible,
|
||||
turn_metadata_header,
|
||||
compression,
|
||||
);
|
||||
|
|
@ -604,7 +598,6 @@ impl ModelClientSession {
|
|||
otel_manager: &OtelManager,
|
||||
effort: Option<ReasoningEffortConfig>,
|
||||
summary: ReasoningSummaryConfig,
|
||||
web_search_eligible: bool,
|
||||
turn_metadata_header: Option<&str>,
|
||||
) -> Result<ResponseStream> {
|
||||
let auth_manager = self.client.state.auth_manager.clone();
|
||||
|
|
@ -631,7 +624,6 @@ impl ModelClientSession {
|
|||
model_info,
|
||||
effort,
|
||||
summary,
|
||||
web_search_eligible,
|
||||
turn_metadata_header,
|
||||
compression,
|
||||
);
|
||||
|
|
@ -687,9 +679,9 @@ impl ModelClientSession {
|
|||
/// Streams a single model request within the current turn.
|
||||
///
|
||||
/// The caller is responsible for passing per-turn settings explicitly (model selection,
|
||||
/// reasoning settings, telemetry context, web search eligibility, and turn metadata). This
|
||||
/// method will prefer the Responses WebSocket transport when enabled and healthy, and will
|
||||
/// fall back to the HTTP Responses API transport otherwise.
|
||||
/// reasoning settings, telemetry context, and turn metadata). This method will prefer the
|
||||
/// Responses WebSocket transport when enabled and healthy, and will fall back to the HTTP
|
||||
/// Responses API transport otherwise.
|
||||
pub async fn stream(
|
||||
&mut self,
|
||||
prompt: &Prompt,
|
||||
|
|
@ -697,7 +689,6 @@ impl ModelClientSession {
|
|||
otel_manager: &OtelManager,
|
||||
effort: Option<ReasoningEffortConfig>,
|
||||
summary: ReasoningSummaryConfig,
|
||||
web_search_eligible: bool,
|
||||
turn_metadata_header: Option<&str>,
|
||||
) -> Result<ResponseStream> {
|
||||
let wire_api = self.client.state.provider.wire_api;
|
||||
|
|
@ -713,7 +704,6 @@ impl ModelClientSession {
|
|||
otel_manager,
|
||||
effort,
|
||||
summary,
|
||||
web_search_eligible,
|
||||
turn_metadata_header,
|
||||
)
|
||||
.await
|
||||
|
|
@ -724,7 +714,6 @@ impl ModelClientSession {
|
|||
otel_manager,
|
||||
effort,
|
||||
summary,
|
||||
web_search_eligible,
|
||||
turn_metadata_header,
|
||||
)
|
||||
.await
|
||||
|
|
@ -772,12 +761,10 @@ fn build_api_prompt(prompt: &Prompt, instructions: String, tools_json: Vec<Value
|
|||
/// These headers implement Codex-specific conventions:
|
||||
///
|
||||
/// - `x-codex-beta-features`: comma-separated beta feature keys enabled for the session.
|
||||
/// - `x-oai-web-search-eligible`: whether this turn is allowed to use web search.
|
||||
/// - `x-codex-turn-state`: sticky routing token captured earlier in the turn.
|
||||
/// - `x-codex-turn-metadata`: optional per-turn metadata for observability.
|
||||
fn build_responses_headers(
|
||||
beta_features_header: Option<&str>,
|
||||
web_search_eligible: bool,
|
||||
turn_state: Option<&Arc<OnceLock<String>>>,
|
||||
turn_metadata_header: Option<&HeaderValue>,
|
||||
) -> ApiHeaderMap {
|
||||
|
|
@ -788,10 +775,6 @@ fn build_responses_headers(
|
|||
{
|
||||
headers.insert("x-codex-beta-features", header_value);
|
||||
}
|
||||
headers.insert(
|
||||
WEB_SEARCH_ELIGIBLE_HEADER,
|
||||
HeaderValue::from_static(if web_search_eligible { "true" } else { "false" }),
|
||||
);
|
||||
if let Some(turn_state) = turn_state
|
||||
&& let Some(state) = turn_state.get()
|
||||
&& let Ok(header_value) = HeaderValue::from_str(state)
|
||||
|
|
|
|||
|
|
@ -4525,10 +4525,6 @@ async fn try_run_sampling_request(
|
|||
);
|
||||
|
||||
sess.persist_rollout_items(&[rollout_item]).await;
|
||||
let web_search_eligible = !matches!(
|
||||
turn_context.config.web_search_mode,
|
||||
Some(WebSearchMode::Disabled)
|
||||
);
|
||||
let mut stream = client_session
|
||||
.stream(
|
||||
prompt,
|
||||
|
|
@ -4536,7 +4532,6 @@ async fn try_run_sampling_request(
|
|||
&turn_context.otel_manager,
|
||||
turn_context.reasoning_effort,
|
||||
turn_context.reasoning_summary,
|
||||
web_search_eligible,
|
||||
turn_metadata_header,
|
||||
)
|
||||
.instrument(trace_span!("stream_request"))
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ use crate::truncate::TruncationPolicy;
|
|||
use crate::truncate::approx_token_count;
|
||||
use crate::truncate::truncate_text;
|
||||
use crate::util::backoff;
|
||||
use codex_protocol::config_types::WebSearchMode;
|
||||
use codex_protocol::items::ContextCompactionItem;
|
||||
use codex_protocol::items::TurnItem;
|
||||
use codex_protocol::models::ContentItem;
|
||||
|
|
@ -352,10 +351,6 @@ async fn drain_to_completed(
|
|||
turn_metadata_header: Option<&str>,
|
||||
prompt: &Prompt,
|
||||
) -> CodexResult<()> {
|
||||
let web_search_eligible = !matches!(
|
||||
turn_context.config.web_search_mode,
|
||||
Some(WebSearchMode::Disabled)
|
||||
);
|
||||
let mut stream = client_session
|
||||
.stream(
|
||||
prompt,
|
||||
|
|
@ -363,7 +358,6 @@ async fn drain_to_completed(
|
|||
&turn_context.otel_manager,
|
||||
turn_context.reasoning_effort,
|
||||
turn_context.reasoning_summary,
|
||||
web_search_eligible,
|
||||
turn_metadata_header,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ mod user_shell_command;
|
|||
pub mod util;
|
||||
|
||||
pub use apply_patch::CODEX_APPLY_PATCH_ARG1;
|
||||
pub use client::WEB_SEARCH_ELIGIBLE_HEADER;
|
||||
pub use client::X_CODEX_TURN_METADATA_HEADER;
|
||||
pub use command_safety::is_dangerous_command;
|
||||
pub use command_safety::is_safe_command;
|
||||
|
|
|
|||
|
|
@ -9,14 +9,12 @@ use codex_core::ModelProviderInfo;
|
|||
use codex_core::Prompt;
|
||||
use codex_core::ResponseEvent;
|
||||
use codex_core::ResponseItem;
|
||||
use codex_core::WEB_SEARCH_ELIGIBLE_HEADER;
|
||||
use codex_core::WireApi;
|
||||
use codex_core::models_manager::manager::ModelsManager;
|
||||
use codex_otel::OtelManager;
|
||||
use codex_otel::TelemetryAuthMode;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::config_types::ReasoningSummary;
|
||||
use codex_protocol::config_types::WebSearchMode;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use core_test_support::load_default_config_for_test;
|
||||
|
|
@ -87,7 +85,6 @@ async fn responses_stream_includes_subagent_header_on_review() {
|
|||
session_source.clone(),
|
||||
);
|
||||
|
||||
let web_search_eligible = !matches!(config.web_search_mode, Some(WebSearchMode::Disabled));
|
||||
let client = ModelClient::new(
|
||||
None,
|
||||
conversation_id,
|
||||
|
|
@ -113,15 +110,7 @@ async fn responses_stream_includes_subagent_header_on_review() {
|
|||
}];
|
||||
|
||||
let mut stream = client_session
|
||||
.stream(
|
||||
&prompt,
|
||||
&model_info,
|
||||
&otel_manager,
|
||||
effort,
|
||||
summary,
|
||||
web_search_eligible,
|
||||
None,
|
||||
)
|
||||
.stream(&prompt, &model_info, &otel_manager, effort, summary, None)
|
||||
.await
|
||||
.expect("stream failed");
|
||||
while let Some(event) = stream.next().await {
|
||||
|
|
@ -198,7 +187,6 @@ async fn responses_stream_includes_subagent_header_on_other() {
|
|||
session_source.clone(),
|
||||
);
|
||||
|
||||
let web_search_eligible = !matches!(config.web_search_mode, Some(WebSearchMode::Disabled));
|
||||
let client = ModelClient::new(
|
||||
None,
|
||||
conversation_id,
|
||||
|
|
@ -224,15 +212,7 @@ async fn responses_stream_includes_subagent_header_on_other() {
|
|||
}];
|
||||
|
||||
let mut stream = client_session
|
||||
.stream(
|
||||
&prompt,
|
||||
&model_info,
|
||||
&otel_manager,
|
||||
effort,
|
||||
summary,
|
||||
web_search_eligible,
|
||||
None,
|
||||
)
|
||||
.stream(&prompt, &model_info, &otel_manager, effort, summary, None)
|
||||
.await
|
||||
.expect("stream failed");
|
||||
while let Some(event) = stream.next().await {
|
||||
|
|
@ -248,66 +228,6 @@ async fn responses_stream_includes_subagent_header_on_other() {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn responses_stream_includes_web_search_eligible_header_true_by_default() {
|
||||
core_test_support::skip_if_no_network!();
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let response_body = responses::sse(vec![
|
||||
responses::ev_response_created("resp-1"),
|
||||
responses::ev_completed("resp-1"),
|
||||
]);
|
||||
|
||||
let request_recorder = responses::mount_sse_once_match(
|
||||
&server,
|
||||
header(WEB_SEARCH_ELIGIBLE_HEADER, "true"),
|
||||
response_body,
|
||||
)
|
||||
.await;
|
||||
|
||||
let test = test_codex().build(&server).await.expect("build test codex");
|
||||
test.submit_turn("hello").await.expect("submit test prompt");
|
||||
|
||||
let request = request_recorder.single_request();
|
||||
assert_eq!(
|
||||
request.header(WEB_SEARCH_ELIGIBLE_HEADER).as_deref(),
|
||||
Some("true")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn responses_stream_includes_web_search_eligible_header_false_when_disabled() {
|
||||
core_test_support::skip_if_no_network!();
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let response_body = responses::sse(vec![
|
||||
responses::ev_response_created("resp-1"),
|
||||
responses::ev_completed("resp-1"),
|
||||
]);
|
||||
|
||||
let request_recorder = responses::mount_sse_once_match(
|
||||
&server,
|
||||
header(WEB_SEARCH_ELIGIBLE_HEADER, "false"),
|
||||
response_body,
|
||||
)
|
||||
.await;
|
||||
|
||||
let test = test_codex()
|
||||
.with_config(|config| {
|
||||
config.web_search_mode = Some(WebSearchMode::Disabled);
|
||||
})
|
||||
.build(&server)
|
||||
.await
|
||||
.expect("build test codex");
|
||||
test.submit_turn("hello").await.expect("submit test prompt");
|
||||
|
||||
let request = request_recorder.single_request();
|
||||
assert_eq!(
|
||||
request.header(WEB_SEARCH_ELIGIBLE_HEADER).as_deref(),
|
||||
Some("false")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn responses_respects_model_info_overrides_from_config() {
|
||||
core_test_support::skip_if_no_network!();
|
||||
|
|
@ -368,7 +288,6 @@ async fn responses_respects_model_info_overrides_from_config() {
|
|||
session_source.clone(),
|
||||
);
|
||||
|
||||
let web_search_eligible = !matches!(config.web_search_mode, Some(WebSearchMode::Disabled));
|
||||
let client = ModelClient::new(
|
||||
None,
|
||||
conversation_id,
|
||||
|
|
@ -394,15 +313,7 @@ async fn responses_respects_model_info_overrides_from_config() {
|
|||
}];
|
||||
|
||||
let mut stream = client_session
|
||||
.stream(
|
||||
&prompt,
|
||||
&model_info,
|
||||
&otel_manager,
|
||||
effort,
|
||||
summary,
|
||||
web_search_eligible,
|
||||
None,
|
||||
)
|
||||
.stream(&prompt, &model_info, &otel_manager, effort, summary, None)
|
||||
.await
|
||||
.expect("stream failed");
|
||||
while let Some(event) = stream.next().await {
|
||||
|
|
|
|||
|
|
@ -1340,15 +1340,7 @@ async fn azure_responses_request_includes_store_and_reasoning_ids() {
|
|||
});
|
||||
|
||||
let mut stream = client_session
|
||||
.stream(
|
||||
&prompt,
|
||||
&model_info,
|
||||
&otel_manager,
|
||||
effort,
|
||||
summary,
|
||||
true,
|
||||
None,
|
||||
)
|
||||
.stream(&prompt, &model_info, &otel_manager, effort, summary, None)
|
||||
.await
|
||||
.expect("responses stream to start");
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ struct WebsocketTestHarness {
|
|||
model_info: ModelInfo,
|
||||
effort: Option<ReasoningEffortConfig>,
|
||||
summary: ReasoningSummary,
|
||||
web_search_eligible: bool,
|
||||
otel_manager: OtelManager,
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +197,6 @@ async fn responses_websocket_emits_reasoning_included_event() {
|
|||
&harness.otel_manager,
|
||||
harness.effort,
|
||||
harness.summary,
|
||||
harness.web_search_eligible,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
|
|
@ -269,7 +267,6 @@ async fn responses_websocket_emits_rate_limit_events() {
|
|||
&harness.otel_manager,
|
||||
harness.effort,
|
||||
harness.summary,
|
||||
harness.web_search_eligible,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
|
|
@ -455,7 +452,6 @@ async fn websocket_harness_with_runtime_metrics(
|
|||
.with_metrics(metrics);
|
||||
let effort = None;
|
||||
let summary = ReasoningSummary::Auto;
|
||||
let web_search_eligible = true;
|
||||
let client = ModelClient::new(
|
||||
None,
|
||||
conversation_id,
|
||||
|
|
@ -474,7 +470,6 @@ async fn websocket_harness_with_runtime_metrics(
|
|||
model_info,
|
||||
effort,
|
||||
summary,
|
||||
web_search_eligible,
|
||||
otel_manager,
|
||||
}
|
||||
}
|
||||
|
|
@ -491,7 +486,6 @@ async fn stream_until_complete(
|
|||
&harness.otel_manager,
|
||||
harness.effort,
|
||||
harness.summary,
|
||||
harness.web_search_eligible,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue