mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
Support model-specific function description prefixes (#51930)
## What changed Add `functions_namespace_functions_description_prefixes` to model tool messages, keyed by unqualified tool name. Prepend this guidance to descriptions in the `functions` namespace across direct declarations, Code Mode documentation, and tool-search results, including custom tools. Trim prefixes, ignore empty values and unavailable functions, and enforce a combined 256-byte UTF-8 limit including separators for reachable tools. Keep overrides local to each step, preserve search ranking text, and retain runtime caches for unaffected tools. ## Testing Extend coverage for direct and indirect descriptions, clearing prefixes when switching models, namespace scoping for deferred dynamic tools, and tool-search cache reuse and reset. GitOrigin-RevId: f434e37cec010764fe3e09fb12c339e933b3c21c
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
//! Prepares function descriptions before direct, Code Mode, or search rendering.
|
||||
//! Only the `functions` namespace is affected; runtime-owned specs stay unchanged.
|
||||
|
||||
use crate::ResponsesApiNamespaceTool;
|
||||
use crate::ToolName;
|
||||
use crate::ToolSpec;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Trimmed, size-bounded description prefixes for the available `functions.*` tools.
|
||||
#[derive(Default)]
|
||||
pub struct FunctionsNamespaceFunctionPrefixes(BTreeMap<String, String>);
|
||||
|
||||
impl FunctionsNamespaceFunctionPrefixes {
|
||||
pub fn new(
|
||||
prefixes: Option<&BTreeMap<String, String>>,
|
||||
available_tools: impl IntoIterator<Item = ToolName>,
|
||||
) -> Result<Self, &'static str> {
|
||||
let Some(prefixes) = prefixes.filter(|prefixes| !prefixes.is_empty()) else {
|
||||
return Ok(Self::default());
|
||||
};
|
||||
let mut remaining = 256usize;
|
||||
let mut normalized = BTreeMap::new();
|
||||
for tool in available_tools {
|
||||
if !tool.is_default_namespace() || normalized.contains_key(&tool.name) {
|
||||
continue;
|
||||
}
|
||||
let Some(prefix) = prefixes.get(&tool.name) else {
|
||||
continue;
|
||||
};
|
||||
let prefix = prefix.trim();
|
||||
if prefix.is_empty() {
|
||||
continue;
|
||||
}
|
||||
remaining = remaining
|
||||
.checked_sub(prefix.len())
|
||||
.and_then(|remaining| remaining.checked_sub(2))
|
||||
.ok_or(
|
||||
"Available functions' description prefixes exceed the 256-byte combined limit",
|
||||
)?;
|
||||
normalized.insert(tool.name, prefix.to_owned());
|
||||
}
|
||||
Ok(Self(normalized))
|
||||
}
|
||||
|
||||
/// Returns an owned replacement only for a configured function. Unaffected tools
|
||||
/// keep their original specs and derived caches, including large MCP schemas.
|
||||
pub fn prepare(&self, name: &ToolName, spec: impl FnOnce() -> ToolSpec) -> Option<ToolSpec> {
|
||||
if !name.is_default_namespace() || !self.0.contains_key(&name.name) {
|
||||
return None;
|
||||
}
|
||||
let mut spec = spec();
|
||||
match &mut spec {
|
||||
ToolSpec::Function(tool) => self.prepend(&tool.name, &mut tool.description),
|
||||
ToolSpec::Freeform(tool) => self.prepend(&tool.name, &mut tool.description),
|
||||
ToolSpec::Namespace(namespace) if namespace.name == "functions" => {
|
||||
for tool in &mut namespace.tools {
|
||||
match tool {
|
||||
ResponsesApiNamespaceTool::Function(tool) => {
|
||||
self.prepend(&tool.name, &mut tool.description);
|
||||
}
|
||||
ResponsesApiNamespaceTool::Custom(tool) => {
|
||||
self.prepend(&tool.name, &mut tool.description);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ToolSpec::Namespace(_) | ToolSpec::ToolSearch { .. } | ToolSpec::WebSearch { .. } => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(spec)
|
||||
}
|
||||
|
||||
fn prepend(&self, name: &str, description: &mut String) {
|
||||
if let Some(prefix) = self.0.get(name) {
|
||||
*description = if description.is_empty() {
|
||||
prefix.clone()
|
||||
} else {
|
||||
format!("{prefix}\n\n{description}")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
mod code_mode;
|
||||
mod dynamic_tool;
|
||||
mod function_call_error;
|
||||
mod functions_namespace_function_prefixes;
|
||||
mod image_detail;
|
||||
mod indirect_namespace_prefixes;
|
||||
mod json_schema;
|
||||
@@ -30,6 +31,7 @@ pub use code_mode::tool_spec_to_code_mode_tool_definition;
|
||||
pub use codex_protocol::ToolName;
|
||||
pub use dynamic_tool::parse_dynamic_tool;
|
||||
pub use function_call_error::FunctionCallError;
|
||||
pub use functions_namespace_function_prefixes::FunctionsNamespaceFunctionPrefixes;
|
||||
pub use image_detail::can_request_original_image_detail;
|
||||
pub use image_detail::normalize_output_image_detail;
|
||||
pub use image_detail::sanitize_original_image_detail;
|
||||
|
||||
Reference in New Issue
Block a user