[router] global tool parser registry (#9840)
This commit is contained in:
@@ -64,6 +64,7 @@ prost-types = "0.13"
|
||||
deadpool = { version = "0.12", features = ["managed", "rt_tokio_1"] }
|
||||
backoff = { version = "0.4", features = ["tokio"] }
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
once_cell = "1.21.3"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.12"
|
||||
|
||||
@@ -23,6 +23,8 @@ use crate::tool_parser::{
|
||||
pub struct PythonicParser {
|
||||
/// Regex to detect tool calls in Pythonic format
|
||||
tool_call_regex: Regex,
|
||||
/// Regex to parse function calls - cached for reuse
|
||||
call_regex: Regex,
|
||||
}
|
||||
|
||||
impl PythonicParser {
|
||||
@@ -33,7 +35,13 @@ impl PythonicParser {
|
||||
let pattern = r"\[[a-zA-Z_]\w*\(";
|
||||
let tool_call_regex = Regex::new(pattern).expect("Valid regex pattern");
|
||||
|
||||
Self { tool_call_regex }
|
||||
// Compile the function call regex once
|
||||
let call_regex = Regex::new(r"(?s)^([a-zA-Z_]\w*)\((.*)\)$").expect("Valid regex pattern");
|
||||
|
||||
Self {
|
||||
tool_call_regex,
|
||||
call_regex,
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract tool calls using bracket counting (similar to MistralParser)
|
||||
@@ -120,10 +128,8 @@ impl PythonicParser {
|
||||
|
||||
/// Parse a single function call from Python syntax
|
||||
fn parse_function_call(&self, call_str: &str) -> ToolParserResult<Option<ToolCall>> {
|
||||
// Match function_name(args) - use (?s) to make . match newlines
|
||||
let call_regex = Regex::new(r"(?s)^([a-zA-Z_]\w*)\((.*)\)$").unwrap();
|
||||
|
||||
if let Some(captures) = call_regex.captures(call_str.trim()) {
|
||||
// Use cached regex instead of creating new one
|
||||
if let Some(captures) = self.call_regex.captures(call_str.trim()) {
|
||||
let function_name = captures.get(1).unwrap().as_str();
|
||||
let args_str = captures.get(2).unwrap().as_str();
|
||||
|
||||
|
||||
@@ -3,9 +3,13 @@ use crate::tool_parser::parsers::{
|
||||
MistralParser, PythonicParser, QwenParser, Step3Parser,
|
||||
};
|
||||
use crate::tool_parser::traits::ToolParser;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Global singleton registry instance - created once and reused
|
||||
pub static GLOBAL_REGISTRY: Lazy<ParserRegistry> = Lazy::new(ParserRegistry::new_internal);
|
||||
|
||||
/// Registry for tool parsers and model mappings
|
||||
pub struct ParserRegistry {
|
||||
/// Map of parser name to parser instance
|
||||
@@ -17,8 +21,19 @@ pub struct ParserRegistry {
|
||||
}
|
||||
|
||||
impl ParserRegistry {
|
||||
/// Create a new parser registry with default mappings
|
||||
pub fn new() -> Self {
|
||||
/// Get the global singleton instance
|
||||
pub fn new() -> &'static Self {
|
||||
&GLOBAL_REGISTRY
|
||||
}
|
||||
|
||||
/// Create a new instance for testing (not the singleton)
|
||||
#[cfg(test)]
|
||||
pub fn new_for_testing() -> Self {
|
||||
Self::new_internal()
|
||||
}
|
||||
|
||||
/// Internal constructor for creating the singleton instance
|
||||
fn new_internal() -> Self {
|
||||
let mut registry = Self {
|
||||
parsers: HashMap::new(),
|
||||
model_mapping: HashMap::new(),
|
||||
@@ -202,8 +217,8 @@ impl ParserRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ParserRegistry {
|
||||
impl Default for &'static ParserRegistry {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
ParserRegistry::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ fn test_parser_registry() {
|
||||
|
||||
#[test]
|
||||
fn test_parser_registry_pattern_matching() {
|
||||
let mut registry = ParserRegistry::new();
|
||||
let mut registry = ParserRegistry::new_for_testing();
|
||||
|
||||
// Test that model mappings work by checking the list
|
||||
registry.map_model("test-model", "json");
|
||||
|
||||
Reference in New Issue
Block a user