feat: search_tool migrate to bring you own tool of Responses API (#14274)

## Why

to support a new bring your own search tool in Responses
API(https://developers.openai.com/api/docs/guides/tools-tool-search#client-executed-tool-search)
we migrating our bm25 search tool to use official way to execute search
on client and communicate additional tools to the model.

## What
- replace the legacy `search_tool_bm25` flow with client-executed
`tool_search`
- add protocol, SSE, history, and normalization support for
`tool_search_call` and `tool_search_output`
- return namespaced Codex Apps search results and wire namespaced
follow-up tool calls back into MCP dispatch
This commit is contained in:
Anton Panasenko
2026-03-11 17:51:51 -07:00
committed by GitHub
parent 72631755e0
commit 77b0c75267
52 changed files with 2619 additions and 1890 deletions

View File

@@ -637,6 +637,16 @@ impl JsReplManager {
summary.result_is_error = Some(!output.success());
summary
}
ResponseInputItem::ToolSearchOutput { tools, .. } => JsReplToolCallResponseSummary {
response_type: Some("tool_search_output".to_string()),
payload_kind: Some(JsReplToolCallPayloadKind::FunctionText),
payload_text_preview: Some(serde_json::Value::Array(tools.clone()).to_string()),
payload_text_length: Some(
serde_json::Value::Array(tools.clone()).to_string().len(),
),
payload_item_count: Some(tools.len()),
..Default::default()
},
}
}
@@ -1360,26 +1370,30 @@ impl JsReplManager {
exec.turn.dynamic_tools.as_slice(),
);
let payload =
if let Some((server, tool)) = exec.session.parse_mcp_tool_name(&req.tool_name).await {
crate::tools::context::ToolPayload::Mcp {
server,
tool,
raw_arguments: req.arguments.clone(),
}
} else if is_freeform_tool(&router.specs(), &req.tool_name) {
crate::tools::context::ToolPayload::Custom {
input: req.arguments.clone(),
}
} else {
crate::tools::context::ToolPayload::Function {
arguments: req.arguments.clone(),
}
};
let payload = if let Some((server, tool)) = exec
.session
.parse_mcp_tool_name(&req.tool_name, &None)
.await
{
crate::tools::context::ToolPayload::Mcp {
server,
tool,
raw_arguments: req.arguments.clone(),
}
} else if is_freeform_tool(&router.specs(), &req.tool_name) {
crate::tools::context::ToolPayload::Custom {
input: req.arguments.clone(),
}
} else {
crate::tools::context::ToolPayload::Function {
arguments: req.arguments.clone(),
}
};
let tool_name = req.tool_name.clone();
let call = crate::tools::router::ToolCall {
tool_name: tool_name.clone(),
tool_namespace: None,
call_id: req.id.clone(),
payload,
};