reasoning_parser/parsers/
minimax.rs1use crate::{
6 parsers::BaseReasoningParser,
7 traits::{ParseError, ParserConfig, ParserResult, ReasoningParser},
8};
9
10pub struct MiniMaxParser {
15 base: BaseReasoningParser,
16 is_first_chunk: bool,
17}
18
19impl MiniMaxParser {
20 pub fn new() -> Self {
22 let config = ParserConfig {
23 think_start_token: "<think>".to_string(),
24 think_end_token: "</think>".to_string(),
25 stream_reasoning: true,
26 max_buffer_size: 65536,
27 initial_in_reasoning: false, };
29
30 Self {
31 base: BaseReasoningParser::new(config).with_model_type("minimax".to_string()),
32 is_first_chunk: true,
33 }
34 }
35}
36
37impl Default for MiniMaxParser {
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43impl ReasoningParser for MiniMaxParser {
44 fn detect_and_parse_reasoning(&mut self, text: &str) -> Result<ParserResult, ParseError> {
45 let modified_text = format!("<think>{}", text);
47 self.base.detect_and_parse_reasoning(&modified_text)
48 }
49
50 fn parse_reasoning_streaming_incremental(
51 &mut self,
52 text: &str,
53 ) -> Result<ParserResult, ParseError> {
54 let modified_text = if self.is_first_chunk {
56 self.is_first_chunk = false;
57 format!("<think>{}", text)
58 } else {
59 text.to_string()
60 };
61
62 self.base
63 .parse_reasoning_streaming_incremental(&modified_text)
64 }
65
66 fn reset(&mut self) {
67 self.base.reset();
68 self.is_first_chunk = true; }
70
71 fn model_type(&self) -> &str {
72 self.base.model_type()
73 }
74
75 fn is_in_reasoning(&self) -> bool {
76 self.base.is_in_reasoning()
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_minimax_append_think_oneshot() {
86 let mut parser = MiniMaxParser::new();
87
88 let result = parser
90 .detect_and_parse_reasoning("reasoning content</think>normal content")
91 .unwrap();
92 assert_eq!(result.normal_text, "normal content");
93 assert_eq!(result.reasoning_text, "reasoning content");
94 }
95
96 #[test]
97 fn test_minimax_without_end_token() {
98 let mut parser = MiniMaxParser::new();
99
100 let result = parser
102 .detect_and_parse_reasoning("all reasoning content")
103 .unwrap();
104 assert_eq!(result.normal_text, "");
105 assert_eq!(result.reasoning_text, "all reasoning content");
106 }
107
108 #[test]
109 fn test_minimax_streaming_first_chunk() {
110 let mut parser = MiniMaxParser::new();
111
112 let result1 = parser
114 .parse_reasoning_streaming_incremental("thinking about")
115 .unwrap();
116 assert_eq!(result1.reasoning_text, "thinking about");
117 assert_eq!(result1.normal_text, "");
118
119 let result2 = parser
121 .parse_reasoning_streaming_incremental(" the problem</think>answer")
122 .unwrap();
123 assert_eq!(result2.reasoning_text, "the problem"); assert_eq!(result2.normal_text, "answer");
125 }
126
127 #[test]
128 fn test_minimax_reset() {
129 let mut parser = MiniMaxParser::new();
130
131 let result1 = parser
133 .parse_reasoning_streaming_incremental("first")
134 .unwrap();
135 assert_eq!(result1.reasoning_text, "first");
136
137 parser.reset();
139
140 let result2 = parser
142 .parse_reasoning_streaming_incremental("second")
143 .unwrap();
144 assert_eq!(result2.reasoning_text, "second");
145 }
146
147 #[test]
148 fn test_minimax_already_has_think() {
149 let mut parser = MiniMaxParser::new();
150
151 let result = parser
154 .detect_and_parse_reasoning("<think>content</think>answer")
155 .unwrap();
156 assert_eq!(result.normal_text, "answer");
158 assert_eq!(result.reasoning_text, "content");
159 }
160
161 #[test]
162 fn test_model_type() {
163 let parser = MiniMaxParser::new();
164 assert_eq!(parser.model_type(), "minimax");
165 }
166}