#[ cfg( feature = "enhanced_function_calling" ) ]
mod private
{
use std::collections::HashMap;
use std::fmt;
pub type ToolResult = Result< String, String >;
pub trait ToolExecutor : Send + Sync
{
fn name( &self ) -> &str;
fn description( &self ) -> &str;
fn parameter_schema( &self ) -> serde_json::Value
{
serde_json ::json!
({
"type" : "object",
"properties" : {},
"required" : []
})
}
fn execute( &self, params : serde_json::Value ) -> ToolResult;
fn definition( &self ) -> crate::ToolDefinition
{
crate ::ToolDefinition
{
name : self.name().to_string(),
description : self.description().to_string(),
parameters : self.parameter_schema(),
}
}
}
pub struct ToolRegistry
{
tools : HashMap< String, Box< dyn ToolExecutor > >,
}
impl ToolRegistry
{
#[ inline ]
#[ must_use ]
pub fn new() -> Self
{
Self
{
tools : HashMap::new(),
}
}
#[ inline ]
pub fn register( &mut self, tool : Box< dyn ToolExecutor > )
{
let name = tool.name().to_string();
assert!( !self.tools.contains_key( &name ), "Tool '{}' is already registered", name );
self.tools.insert( name, tool );
}
#[ inline ]
#[ must_use ]
pub fn definitions( &self ) -> Vec< crate::ToolDefinition >
{
self.tools.values()
.map( | tool | tool.definition() )
.collect()
}
#[ inline ]
pub fn execute( &self, tool_call : &crate::ToolCall ) -> ToolResult
{
let function_name = tool_call.function
.get( "name" )
.and_then( | v | v.as_str() )
.ok_or_else( || "Missing function name in tool call".to_string() )?;
let tool = self.tools.get( function_name )
.ok_or_else( || format!( "Tool '{}' not found in registry", function_name ) )?;
let params = tool_call.function
.get( "arguments" )
.cloned()
.unwrap_or( serde_json::json!( {} ) );
tool.execute( params )
}
#[ inline ]
#[ must_use ]
pub fn len( &self ) -> usize
{
self.tools.len()
}
#[ inline ]
#[ must_use ]
pub fn is_empty( &self ) -> bool
{
self.tools.is_empty()
}
#[ inline ]
#[ must_use ]
pub fn contains( &self, name : &str ) -> bool
{
self.tools.contains_key( name )
}
}
impl Default for ToolRegistry
{
#[ inline ]
fn default() -> Self
{
Self::new()
}
}
impl fmt::Debug for ToolRegistry
{
fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> fmt::Result
{
f.debug_struct( "ToolRegistry" )
.field( "tool_count", &self.tools.len() )
.field( "tool_names", &self.tools.keys().collect::< Vec< _ > >() )
.finish()
}
}
pub mod helpers
{
use serde_json::json;
#[ inline ]
#[ must_use ]
pub fn create_simple_tool(
name : &str,
description : &str,
parameters : &[ ( &str, &str, &str ) ], required : &[ &str ],
) -> crate::ToolDefinition
{
let mut properties = serde_json::Map::new();
for ( param_name, param_type, param_desc ) in parameters
{
properties.insert(
( *param_name ).to_string(),
json!
({
"type" : param_type,
"description" : param_desc,
})
);
}
crate ::ToolDefinition
{
name : name.to_string(),
description : description.to_string(),
parameters : json!
({
"type" : "object",
"properties" : properties,
"required" : required,
}),
}
}
#[ inline ]
#[ must_use ]
pub fn create_enum_tool(
name : &str,
description : &str,
parameters : &[ ( &str, &[ &str ], &str ) ], required : &[ &str ],
) -> crate::ToolDefinition
{
let mut properties = serde_json::Map::new();
for ( param_name, enum_values, param_desc ) in parameters
{
properties.insert(
( *param_name ).to_string(),
json!
({
"type" : "string",
"enum" : enum_values,
"description" : param_desc,
})
);
}
crate ::ToolDefinition
{
name : name.to_string(),
description : description.to_string(),
parameters : json!
({
"type" : "object",
"properties" : properties,
"required" : required,
}),
}
}
}
pub mod orchestration
{
#[ cfg( all( feature = "vision_support", feature = "tool_calling" ) ) ]
#[ inline ]
pub fn extract_tool_calls( message : &crate::ChatMessage ) -> Option< &Vec< crate::ToolCall > >
{
message.tool_calls.as_ref()
}
#[ cfg( feature = "tool_calling" ) ]
#[ inline ]
pub fn execute_tools_sequential(
registry : &crate::enhanced_function_calling::ToolRegistry,
tool_calls : &[ crate::ToolCall ]
) -> Vec< String >
{
tool_calls
.iter()
.map( | call |
{
match registry.execute( call )
{
Ok( result ) => result,
Err( e ) => format!( "Error : {}", e ),
}
})
.collect()
}
#[ cfg( all( feature = "vision_support", feature = "tool_calling" ) ) ]
#[ inline ]
pub fn format_tool_results(
tool_calls : &[ crate::ToolCall ],
results : Vec< String >
) -> Vec< crate::ToolMessage >
{
tool_calls
.iter()
.zip( results )
.map( | ( call, result ) |
{
crate::ToolMessage
{
role : crate::MessageRole::Tool,
content : result,
tool_call_id : call.id.clone(),
}
})
.collect()
}
#[ cfg( all( feature = "vision_support", feature = "tool_calling" ) ) ]
#[ inline ]
pub fn orchestrate_tool_calls(
registry : &crate::enhanced_function_calling::ToolRegistry,
response_message : &crate::ChatMessage
) -> Vec< crate::ToolMessage >
{
if let Some( tool_calls ) = extract_tool_calls( response_message )
{
let results = execute_tools_sequential( registry, tool_calls );
format_tool_results( tool_calls, results )
}
else
{
Vec::new()
}
}
}
}
#[ cfg( feature = "enhanced_function_calling" ) ]
crate ::mod_interface!
{
exposed use private::ToolExecutor;
exposed use private::ToolRegistry;
exposed use private::ToolResult;
exposed use private::helpers;
exposed use private::orchestration;
}