use async_trait::async_trait;
use regex::Regex;
use serde_json::Value;
use crate::protocols::spec::Tool;
use crate::tool_parser::{
errors::{ToolParserError, ToolParserResult},
parsers::helpers,
partial_json::PartialJson,
traits::ToolParser,
types::{FunctionCall, StreamingParseResult, ToolCall},
};
/// Qwen format parser for tool calls
///
/// Handles the Qwen 2.5/3 specific format:
/// `\n{"name": "func", "arguments": {...}}\n`
///
/// Features:
/// - XML-style tags with JSON content
/// - Support for multiple sequential tool calls
/// - Newline-aware parsing
/// - Buffering for partial end tokens
pub struct QwenParser {
/// Parser for handling incomplete JSON during streaming
partial_json: PartialJson,
/// Regex for extracting tool calls in parse_complete
extractor: Regex,
/// Buffer for accumulating incomplete patterns across chunks
buffer: String,
/// Stores complete tool call info (name and arguments) for each tool being parsed
prev_tool_call_arr: Vec,
/// Index of currently streaming tool call (-1 means no active tool)
current_tool_id: i32,
/// Flag for whether current tool's name has been sent to client
current_tool_name_sent: bool,
/// Tracks raw JSON string content streamed to client for each tool's arguments
streamed_args_for_tool: Vec,
/// Buffer for normal text that might precede partial end tokens
normal_text_buffer: String,
/// Token configuration
bot_token: &'static str,
eot_token: &'static str,
tool_call_separator: &'static str,
}
impl QwenParser {
/// Create a new Qwen parser
pub fn new() -> Self {
// Use (?s) flag for DOTALL mode to handle newlines
let pattern = r"(?s)\n(.*?)\n";
let extractor = Regex::new(pattern).expect("Valid regex pattern");
Self {
partial_json: PartialJson::default(),
extractor,
buffer: String::new(),
prev_tool_call_arr: Vec::new(),
current_tool_id: -1,
current_tool_name_sent: false,
streamed_args_for_tool: Vec::new(),
normal_text_buffer: String::new(),
bot_token: "\n",
eot_token: "\n",
tool_call_separator: "\n",
}
}
/// Parse a single JSON object into a ToolCall
fn parse_single_object(&self, obj: &Value) -> ToolParserResult