Compare commits

...

5 Commits

Author SHA1 Message Date
Youssef Masmoudi
52d58b35e4 Merge remote-tracking branch 'origin/main' into codex/loadable-tool-spec-shared
# Conflicts:
#	codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json
#	codex-rs/core/src/tools/handlers/tool_search.rs
#	codex-rs/core/src/tools/tool_search_entry.rs
#	codex-rs/core/tests/suite/search_tool.rs
#	codex-rs/tools/src/dynamic_tool.rs
#	codex-rs/tools/src/lib.rs
#	codex-rs/tools/src/responses_api.rs
#	codex-rs/tools/src/tool_registry_plan.rs
#	codex-rs/tools/src/tool_registry_plan_tests.rs
2026-04-22 01:16:58 +05:30
Youssef Masmoudi
eeb6274641 codex: address PR review feedback (#18765) 2026-04-22 00:47:36 +05:30
Sayan Sisodiya
951e476386 Share loadable tool spec conversion 2026-04-20 16:13:33 -07:00
Sayan Sisodiya
ad02b1298e allow namespaces in code_mode + improvements to tests 2026-04-20 15:40:40 -07:00
pash
7a8eb680cb Add namespaces to dynamic tools 2026-04-18 21:36:26 -07:00
5 changed files with 24 additions and 9 deletions

View File

@@ -257,7 +257,7 @@ mod tests {
}),
LoadableToolSpec::Namespace(ResponsesApiNamespace {
name: "codex_app".to_string(),
description: "Tools in the codex_app namespace.".to_string(),
description: "Tools provided by the current Codex thread.".to_string(),
tools: vec![ResponsesApiNamespaceTool::Function(ResponsesApiTool {
name: "automation_update".to_string(),
description: "Create, update, view, or delete recurring automations."

View File

@@ -6,6 +6,8 @@ use codex_tools::dynamic_tool_to_loadable_tool_spec;
use codex_tools::tool_search_result_source_to_loadable_tool_spec;
use std::collections::HashMap;
const DYNAMIC_TOOL_NAMESPACE_DESCRIPTION: &str = "Tools provided by the current Codex thread.";
#[derive(Clone)]
pub(crate) struct ToolSearchEntry {
pub(crate) search_text: String,
@@ -68,9 +70,13 @@ fn mcp_tool_search_entry(info: &ToolInfo) -> Result<ToolSearchEntry, serde_json:
}
fn dynamic_tool_search_entry(tool: &DynamicToolSpec) -> Result<ToolSearchEntry, serde_json::Error> {
let output = dynamic_tool_to_loadable_tool_spec(tool, |_| {
DYNAMIC_TOOL_NAMESPACE_DESCRIPTION.to_string()
})?;
Ok(ToolSearchEntry {
search_text: build_dynamic_search_text(tool),
output: dynamic_tool_to_loadable_tool_spec(tool)?,
output,
limit_bucket: None,
})
}

View File

@@ -837,7 +837,7 @@ async fn tool_search_returns_deferred_dynamic_tool_and_routes_follow_up_call() -
vec![json!({
"type": "namespace",
"name": "codex_app",
"description": "Tools in the codex_app namespace.",
"description": "Tools provided by the current Codex thread.",
"tools": [{
"type": "function",
"name": tool_name,
@@ -881,6 +881,13 @@ async fn tool_search_indexes_only_enabled_non_app_mcp_tools() -> Result<()> {
let server = start_mock_server().await;
let apps_server = AppsTestServer::mount_searchable(&server).await?;
let rmcp_test_server_bin = match stdio_server_bin() {
Ok(bin) => bin,
Err(err) => {
eprintln!("test_stdio_server binary not available, skipping test: {err}");
return Ok(());
}
};
let echo_call_id = "tool-search-echo";
let image_call_id = "tool-search-image";
let mock = mount_sse_sequence(
@@ -913,7 +920,6 @@ async fn tool_search_indexes_only_enabled_non_app_mcp_tools() -> Result<()> {
)
.await;
let rmcp_test_server_bin = stdio_server_bin()?;
let mut builder =
configured_builder(apps_server.chatgpt_base_url.clone()).with_config(move |config| {
let mut servers = config.mcp_servers.get().clone();

View File

@@ -74,15 +74,18 @@ pub fn dynamic_tool_to_responses_api_tool(
)?))
}
pub fn dynamic_tool_to_loadable_tool_spec(
pub fn dynamic_tool_to_loadable_tool_spec<F>(
tool: &DynamicToolSpec,
) -> Result<LoadableToolSpec, serde_json::Error> {
namespace_description: F,
) -> Result<LoadableToolSpec, serde_json::Error>
where
F: FnOnce(&str) -> String,
{
let output_tool = dynamic_tool_to_responses_api_tool(tool)?;
Ok(match tool.namespace.as_ref() {
Some(namespace) => LoadableToolSpec::Namespace(ResponsesApiNamespace {
name: namespace.clone(),
// the user doesn't provide a description for dynamic tools, so we use the default
description: default_namespace_description(namespace),
description: namespace_description(namespace),
tools: vec![ResponsesApiNamespaceTool::Function(output_tool)],
}),
None => LoadableToolSpec::Function(output_tool),

View File

@@ -559,7 +559,7 @@ pub fn build_tool_registry_plan(
let mut dynamic_tool_specs = Vec::new();
for tool in params.dynamic_tools {
match dynamic_tool_to_loadable_tool_spec(tool) {
match dynamic_tool_to_loadable_tool_spec(tool, default_namespace_description) {
Ok(loadable_tool) => {
let handler_name = ToolName::new(tool.namespace.clone(), tool.name.clone());
dynamic_tool_specs.push(loadable_tool);