[model-gateway]: Tool parser for glm47 (#15520)

This commit is contained in:
Haoran Wang
2025-12-20 18:07:51 -10:00
committed by GitHub
parent 43b7c17474
commit 26704c23c0
8 changed files with 179 additions and 26 deletions
+5 -3
View File
@@ -239,7 +239,8 @@ impl ParserFactory {
registry.register_parser("pythonic", || Box::new(PythonicParser::new()));
registry.register_parser("llama", || Box::new(LlamaParser::new()));
registry.register_parser("deepseek", || Box::new(DeepSeekParser::new()));
registry.register_parser("glm4_moe", || Box::new(Glm4MoeParser::new()));
registry.register_parser("glm45_moe", || Box::new(Glm4MoeParser::glm45()));
registry.register_parser("glm47_moe", || Box::new(Glm4MoeParser::glm47()));
registry.register_parser("step3", || Box::new(Step3Parser::new()));
registry.register_parser("kimik2", || Box::new(KimiK2Parser::new()));
registry.register_parser("minimax_m2", || Box::new(MinimaxM2Parser::new()));
@@ -281,8 +282,9 @@ impl ParserFactory {
registry.map_model("deepseek-*", "pythonic");
// GLM models
registry.map_model("glm-4.5*", "glm4_moe");
registry.map_model("glm-4.6*", "glm4_moe");
registry.map_model("glm-4.5*", "glm45_moe");
registry.map_model("glm-4.6*", "glm45_moe");
registry.map_model("glm-4.7*", "glm47_moe");
registry.map_model("glm-*", "json");
// Step3 models
@@ -14,8 +14,9 @@ use crate::{
/// GLM-4 MoE format parser for tool calls
///
/// Handles the GLM-4 MoE specific format:
/// `<tool_call>{name}\n<arg_key>{key}</arg_key>\n<arg_value>{value}</arg_value>\n</tool_call>`
/// Handles both GLM-4 MoE and GLM-4.7 MoE formats:
/// - GLM-4: `<tool_call>{name}\n<arg_key>{key}</arg_key>\n<arg_value>{value}</arg_value>\n</tool_call>`
/// - GLM-4.7: `<tool_call>{name}<arg_key>{key}</arg_key><arg_value>{value}</arg_value></tool_call>`
///
/// Features:
/// - XML-style tags for tool calls
@@ -47,13 +48,17 @@ pub struct Glm4MoeParser {
}
impl Glm4MoeParser {
/// Create a new GLM-4 MoE parser
pub fn new() -> Self {
/// Create a new generic GLM MoE parser with a custom func_detail_extractor pattern
///
/// # Arguments
/// - `func_detail_pattern`: Regex pattern for extracting function name and arguments
/// - For GLM-4: `r"(?s)<tool_call>([^\n]*)\n(.*)</tool_call>"`
/// - For GLM-4.7: `r"(?s)<tool_call>\s*([^<\s]+)\s*(.*?)</tool_call>"`
pub(crate) fn new(func_detail_pattern: &str) -> Self {
// Use (?s) flag for DOTALL mode to handle newlines
let tool_call_pattern = r"(?s)<tool_call>.*?</tool_call>";
let tool_call_extractor = Regex::new(tool_call_pattern).expect("Valid regex pattern");
let func_detail_pattern = r"(?s)<tool_call>([^\n]*)\n(.*)</tool_call>";
let func_detail_extractor = Regex::new(func_detail_pattern).expect("Valid regex pattern");
let arg_pattern = r"(?s)<arg_key>(.*?)</arg_key>\s*<arg_value>(.*?)</arg_value>";
@@ -72,6 +77,16 @@ impl Glm4MoeParser {
}
}
/// Create a new GLM-4.5/4.6 MoE parser (with newline-based format)
pub fn glm45() -> Self {
Self::new(r"(?s)<tool_call>([^\n]*)\n(.*)</tool_call>")
}
/// Create a new GLM-4.7 MoE parser (with whitespace-based format)
pub fn glm47() -> Self {
Self::new(r"(?s)<tool_call>\s*([^<\s]+)\s*(.*?)</tool_call>")
}
/// Parse arguments from key-value pairs
fn parse_arguments(&self, args_text: &str) -> ParserResult<serde_json::Map<String, Value>> {
let mut arguments = serde_json::Map::new();
@@ -136,7 +151,6 @@ impl Glm4MoeParser {
}
}
/// Parse and return StreamingParseResult (mirrors Python's detect_and_parse)
/// Parse all tool calls from text (shared logic for complete and incremental parsing)
fn parse_tool_calls_from_text(&self, text: &str) -> ParserResult<Vec<ToolCall>> {
let mut tools = Vec::new();
@@ -158,7 +172,7 @@ impl Glm4MoeParser {
impl Default for Glm4MoeParser {
fn default() -> Self {
Self::new()
Self::glm45()
}
}
@@ -257,7 +271,7 @@ impl ToolParser for Glm4MoeParser {
tracing::debug!("Invalid tool name '{}' - skipping", tool_call.function.name);
helpers::reset_current_tool_state(
&mut self.buffer,
&mut false, // glm4_moe doesn't track name_sent per tool
&mut false, // glm45_moe/glm47_moe doesn't track name_sent per tool
&mut self.streamed_args_for_tool,
&self.prev_tool_call_arr,
);