mirror of
https://github.com/openai/codex.git
synced 2026-05-29 23:40:29 +00:00
[codex] Require model for standalone web search (#25131)
## Why The standalone `/v1/alpha/search` request now requires a `model`, but the `web.run` extension currently omits it. Adds `model` to extension `ToolCall` invocation. Follow-up to #23823. ## What changed - Make `SearchRequest.model` required. - Expose the effective per-turn model on extension tool calls and pass it in standalone web-search requests. - Assert the model is forwarded in the app-server round-trip test. ## Testing - `just test -p codex-api -p codex-tools -p codex-web-search-extension -p codex-memories-extension -p codex-goal-extension` - `just test -p codex-core -E 'test(passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call)'` - `just test -p codex-app-server -E 'test(standalone_web_search_round_trips_encrypted_output)'`
This commit is contained in:
@@ -140,6 +140,7 @@ async fn standalone_web_search_round_trips_encrypted_output() -> Result<()> {
|
||||
);
|
||||
|
||||
let search_body = search_request_body(&server).await?;
|
||||
assert_eq!(search_body["model"], json!("mock-model"));
|
||||
assert_eq!(
|
||||
search_body["commands"],
|
||||
json!({
|
||||
|
||||
@@ -145,7 +145,7 @@ mod tests {
|
||||
.search(
|
||||
&SearchRequest {
|
||||
id: "search-session".to_string(),
|
||||
model: Some("gpt-test".to_string()),
|
||||
model: "gpt-test".to_string(),
|
||||
reasoning: None,
|
||||
input: Some(SearchInput::Items(vec![ResponseItem::Message {
|
||||
id: None,
|
||||
|
||||
@@ -7,8 +7,7 @@ use serde::Serialize;
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
pub struct SearchRequest {
|
||||
pub id: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub model: Option<String>,
|
||||
pub model: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub reasoning: Option<Reasoning>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
||||
@@ -147,6 +147,7 @@ async fn to_extension_call(invocation: &ToolInvocation) -> ExtensionToolCall {
|
||||
turn_id: invocation.turn.sub_id.clone(),
|
||||
call_id: invocation.call_id.clone(),
|
||||
tool_name: invocation.tool_name.clone(),
|
||||
model: invocation.turn.model_info.slug.clone(),
|
||||
truncation_policy: invocation.turn.truncation_policy,
|
||||
conversation_history,
|
||||
turn_item_emitter: Arc::new(CoreTurnItemEmitter {
|
||||
@@ -307,6 +308,7 @@ mod tests {
|
||||
let weak_session = Arc::downgrade(&session);
|
||||
let weak_turn = Arc::downgrade(&turn);
|
||||
let turn_id = turn.sub_id.clone();
|
||||
let model = turn.model_info.slug.clone();
|
||||
let truncation_policy = turn.truncation_policy;
|
||||
let history_item = ResponseItem::Message {
|
||||
id: None,
|
||||
@@ -350,6 +352,7 @@ mod tests {
|
||||
captured_call.tool_name,
|
||||
codex_tools::ToolName::plain("extension_echo")
|
||||
);
|
||||
assert_eq!(captured_call.model, model);
|
||||
assert_eq!(captured_call.truncation_policy, truncation_policy);
|
||||
assert_eq!(
|
||||
captured_call.conversation_history.items(),
|
||||
|
||||
@@ -1129,6 +1129,7 @@ fn tool_call(tool_name: &str, call_id: &str, arguments: serde_json::Value) -> To
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: call_id.to_string(),
|
||||
tool_name: codex_extension_api::ToolName::plain(tool_name),
|
||||
model: "gpt-test".to_string(),
|
||||
truncation_policy: TruncationPolicy::Bytes(1024),
|
||||
conversation_history: codex_extension_api::ConversationHistory::default(),
|
||||
turn_item_emitter: Arc::new(NoopTurnItemEmitter),
|
||||
|
||||
@@ -211,6 +211,7 @@ async fn add_ad_hoc_note_tool_creates_note_file() {
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: "call-1".to_string(),
|
||||
tool_name: memory_tool_name(crate::ADD_AD_HOC_NOTE_TOOL_NAME),
|
||||
model: "gpt-test".to_string(),
|
||||
truncation_policy: TruncationPolicy::Bytes(1024),
|
||||
conversation_history: codex_extension_api::ConversationHistory::default(),
|
||||
turn_item_emitter: Arc::new(NoopTurnItemEmitter),
|
||||
@@ -253,6 +254,7 @@ async fn add_ad_hoc_note_tool_rejects_paths_as_filenames() {
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: "call-1".to_string(),
|
||||
tool_name: memory_tool_name(crate::ADD_AD_HOC_NOTE_TOOL_NAME),
|
||||
model: "gpt-test".to_string(),
|
||||
truncation_policy: TruncationPolicy::Bytes(1024),
|
||||
conversation_history: codex_extension_api::ConversationHistory::default(),
|
||||
turn_item_emitter: Arc::new(NoopTurnItemEmitter),
|
||||
@@ -296,6 +298,7 @@ async fn read_tool_reads_memory_file() {
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: "call-1".to_string(),
|
||||
tool_name: memory_tool_name(crate::READ_TOOL_NAME),
|
||||
model: "gpt-test".to_string(),
|
||||
truncation_policy: TruncationPolicy::Bytes(1024),
|
||||
conversation_history: codex_extension_api::ConversationHistory::default(),
|
||||
turn_item_emitter: Arc::new(NoopTurnItemEmitter),
|
||||
@@ -342,6 +345,7 @@ async fn search_tool_accepts_multiple_queries() {
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: "call-1".to_string(),
|
||||
tool_name: memory_tool_name(crate::SEARCH_TOOL_NAME),
|
||||
model: "gpt-test".to_string(),
|
||||
truncation_policy: TruncationPolicy::Bytes(1024),
|
||||
conversation_history: codex_extension_api::ConversationHistory::default(),
|
||||
turn_item_emitter: Arc::new(NoopTurnItemEmitter),
|
||||
@@ -414,6 +418,7 @@ async fn search_tool_accepts_windowed_all_match_mode() {
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: "call-1".to_string(),
|
||||
tool_name: memory_tool_name(crate::SEARCH_TOOL_NAME),
|
||||
model: "gpt-test".to_string(),
|
||||
truncation_policy: TruncationPolicy::Bytes(1024),
|
||||
conversation_history: codex_extension_api::ConversationHistory::default(),
|
||||
turn_item_emitter: Arc::new(NoopTurnItemEmitter),
|
||||
@@ -466,6 +471,7 @@ async fn search_tool_rejects_legacy_single_query() {
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: "call-1".to_string(),
|
||||
tool_name: memory_tool_name(crate::SEARCH_TOOL_NAME),
|
||||
model: "gpt-test".to_string(),
|
||||
truncation_policy: TruncationPolicy::Bytes(1024),
|
||||
conversation_history: codex_extension_api::ConversationHistory::default(),
|
||||
turn_item_emitter: Arc::new(NoopTurnItemEmitter),
|
||||
|
||||
@@ -90,7 +90,7 @@ impl ToolExecutor<ToolCall> for WebSearchTool {
|
||||
);
|
||||
let request = SearchRequest {
|
||||
id: self.session_id.clone(),
|
||||
model: None,
|
||||
model: call.model.clone(),
|
||||
reasoning: None,
|
||||
input: recent_input(call.conversation_history.items()),
|
||||
commands: Some(commands),
|
||||
|
||||
@@ -87,6 +87,7 @@ pub struct ToolCall {
|
||||
pub turn_id: String,
|
||||
pub call_id: String,
|
||||
pub tool_name: ToolName,
|
||||
pub model: String,
|
||||
pub truncation_policy: TruncationPolicy,
|
||||
pub conversation_history: ConversationHistory,
|
||||
pub turn_item_emitter: Arc<dyn TurnItemEmitter>,
|
||||
@@ -99,6 +100,7 @@ impl std::fmt::Debug for ToolCall {
|
||||
.field("turn_id", &self.turn_id)
|
||||
.field("call_id", &self.call_id)
|
||||
.field("tool_name", &self.tool_name)
|
||||
.field("model", &self.model)
|
||||
.field("truncation_policy", &self.truncation_policy)
|
||||
.field("conversation_history", &self.conversation_history)
|
||||
.field("turn_item_emitter", &"<host turn item emitter>")
|
||||
|
||||
Reference in New Issue
Block a user