tools: simplify default tool search text (#27526)

## Why

Default tool search text currently derives identity from both `ToolName`
and `ToolSpec`. For function and namespace specs, this indexes the same
names more than once and also adds a flattened `{namespace}{name}` token
that is not model-visible.

## What changed

- Derive default search text entirely from `ToolSpec` while preserving
names, descriptions, namespace metadata, and recursive schema metadata.
- Keep the default search-text builder private and remove the unused
`ToolName` argument.
- Add coverage for the exact search text generated for a namespaced tool
with nested schema metadata.

## Example

For the `codex_app` namespace and `automation_update` tool (schema terms
omitted):

- Before: `codex_appautomation_update automation update codex_app
codex_app Manage Codex automations. automation_update automation update
...`
- After: `codex_app Manage Codex automations. automation_update
automation update ...`

## Testing

- `just test -p codex-tools`
This commit is contained in:
sayan-oai
2026-06-10 20:37:25 -07:00
committed by GitHub
Unverified
parent f1f9d0c3b5
commit 728b8243a9
4 changed files with 55 additions and 11 deletions
-1
View File
@@ -100,7 +100,6 @@ pub use tool_output::ToolOutput;
pub use tool_payload::ToolPayload;
pub use tool_search::ToolSearchEntry;
pub use tool_search::ToolSearchInfo;
pub use tool_search::default_tool_search_text;
pub use tool_spec::ResponsesApiWebSearchFilters;
pub use tool_spec::ResponsesApiWebSearchUserLocation;
pub use tool_spec::ToolSpec;
+1 -1
View File
@@ -58,7 +58,7 @@ pub trait ToolExecutor<Invocation>: Send + Sync {
fn search_info(&self) -> Option<ToolSearchInfo> {
let spec = self.spec();
ToolSearchInfo::from_tool_spec(&self.tool_name(), spec, /*source_info*/ None)
ToolSearchInfo::from_tool_spec(spec, /*source_info*/ None)
}
fn supports_parallel_tool_calls(&self) -> bool {
+6 -9
View File
@@ -2,7 +2,6 @@ use crate::JsonSchema;
use crate::LoadableToolSpec;
use crate::ResponsesApiNamespaceTool;
use crate::ResponsesApiTool;
use crate::ToolName;
use crate::ToolSearchSourceInfo;
use crate::ToolSpec;
use crate::default_namespace_description;
@@ -21,11 +20,10 @@ pub struct ToolSearchInfo {
impl ToolSearchInfo {
pub fn from_tool_spec(
tool_name: &ToolName,
spec: ToolSpec,
source_info: Option<ToolSearchSourceInfo>,
) -> Option<Self> {
let search_text = default_tool_search_text(tool_name, &spec);
let search_text = default_tool_search_text(&spec);
Self::from_spec(search_text, spec, source_info)
}
@@ -67,13 +65,8 @@ impl ToolSearchInfo {
}
}
pub fn default_tool_search_text(tool_name: &ToolName, spec: &ToolSpec) -> String {
fn default_tool_search_text(spec: &ToolSpec) -> String {
let mut parts = Vec::new();
push_search_part(&mut parts, tool_name.to_string());
push_search_part(&mut parts, tool_name.name.replace('_', " "));
if let Some(namespace) = &tool_name.namespace {
push_search_part(&mut parts, namespace.clone());
}
match spec {
ToolSpec::Function(tool) => append_function_search_text(tool, &mut parts),
@@ -137,3 +130,7 @@ fn push_search_part(parts: &mut Vec<String>, part: String) {
parts.push(part.to_string());
}
}
#[cfg(test)]
#[path = "tool_search_tests.rs"]
mod tests;
+48
View File
@@ -0,0 +1,48 @@
use super::*;
use pretty_assertions::assert_eq;
use std::collections::BTreeMap;
#[test]
fn default_search_text_uses_model_visible_namespace_metadata_once() {
let mut schedule_schema = JsonSchema::object(
BTreeMap::from([(
"timezone".to_string(),
JsonSchema::string(Some("IANA timezone.".to_string())),
)]),
/*required*/ None,
/*additional_properties*/ None,
);
schedule_schema.description = Some("Schedule settings.".to_string());
let mut parameters = JsonSchema::object(
BTreeMap::from([
(
"mode".to_string(),
JsonSchema::string(Some("Update mode.".to_string())),
),
("schedule".to_string(), schedule_schema),
]),
/*required*/ None,
/*additional_properties*/ None,
);
parameters.description = Some("Automation options.".to_string());
let spec = ToolSpec::Namespace(crate::ResponsesApiNamespace {
name: "codex_app".to_string(),
description: "Manage Codex automations.".to_string(),
tools: vec![ResponsesApiNamespaceTool::Function(ResponsesApiTool {
name: "automation_update".to_string(),
description: "Create or update automations.".to_string(),
strict: false,
defer_loading: None,
parameters,
output_schema: None,
})],
});
let search_info = ToolSearchInfo::from_tool_spec(spec, /*source_info*/ None)
.expect("namespace should be searchable");
assert_eq!(
search_info.entry.search_text,
"codex_app Manage Codex automations. automation_update automation update Create or update automations. Automation options. mode Update mode. schedule Schedule settings. timezone IANA timezone."
);
}