fix: update Minimax and DeepSeek handlers to strip unclosed thinking tags
Some checks failed
BotServer CI/CD / build (push) Has been cancelled

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2026-04-14 16:13:41 -03:00
parent a6f825526f
commit 8ccc4e1c5e
4 changed files with 29 additions and 10 deletions

View file

@ -44,9 +44,9 @@ async fn process_episodic_memory(
let history_to_keep = config_manager let history_to_keep = config_manager
.get_config(&session.bot_id, "history-limit", Some("20")) // Respect history-limit if present .get_config(&session.bot_id, "history-limit", Some("20")) // Respect history-limit if present
.unwrap_or_else(|_| "20".to_string()) .unwrap_or_else(|_| "120".to_string())
.parse::<usize>() .parse::<usize>()
.unwrap_or(20); .unwrap_or(120);
if threshold == 0 { if threshold == 0 {
continue; // Skip this session, episodic memory is disabled for this bot continue; // Skip this session, episodic memory is disabled for this bot

View file

@ -6,11 +6,24 @@ static THINK_TAG_REGEX: LazyLock<Result<Regex, regex::Error>> =
LazyLock::new(|| Regex::new(r"(?s)<think>.*?</think>")); LazyLock::new(|| Regex::new(r"(?s)<think>.*?</think>"));
pub fn strip_think_tags(content: &str) -> String { pub fn strip_think_tags(content: &str) -> String {
if let Ok(re) = &*THINK_TAG_REGEX { // We want to strip <think>...</think> OR <think> until end of string (streaming)
re.replace_all(content, "").to_string() let mut result = content.to_string();
} else { if let Some(start_idx) = result.find("<think>") {
content.to_string() if let Some(end_idx) = result[start_idx..].find("</think>") {
// Case 1: Fully enclosed
result = format!(
"{}{}",
&result[..start_idx],
&result[start_idx + end_idx + 8..]
);
// Recursive call to catch multiple blocks
return strip_think_tags(&result);
} else {
// Case 2: Unclosed (streaming)
result = result[..start_idx].to_string();
}
} }
result
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -3,7 +3,7 @@ use super::ModelHandler;
pub fn strip_think_tags(content: &str) -> String { pub fn strip_think_tags(content: &str) -> String {
let mut result = content.to_string(); let mut result = content.to_string();
// Chinese: (分析).../分析) // Chinese: (分析).../分析) or unclosed (分析)...
while let Some(start_idx) = result.find("(分析)") { while let Some(start_idx) = result.find("(分析)") {
if let Some(end_idx) = result[start_idx..].find("/分析)") { if let Some(end_idx) = result[start_idx..].find("/分析)") {
result = format!( result = format!(
@ -12,11 +12,13 @@ pub fn strip_think_tags(content: &str) -> String {
&result[start_idx + end_idx + 4..] &result[start_idx + end_idx + 4..]
); );
} else { } else {
// Unclosed - strip to the end
result = result[..start_idx].to_string();
break; break;
} }
} }
// English: <think>...</think> // English: <think>...</think> or unclosed <think>...
while let Some(start_idx) = result.find("<think>") { while let Some(start_idx) = result.find("<think>") {
if let Some(end_idx) = result[start_idx..].find("</think>") { if let Some(end_idx) = result[start_idx..].find("</think>") {
result = format!( result = format!(
@ -25,11 +27,13 @@ pub fn strip_think_tags(content: &str) -> String {
&result[start_idx + end_idx + 8..] &result[start_idx + end_idx + 8..]
); );
} else { } else {
// Unclosed - strip to the end
result = result[..start_idx].to_string();
break; break;
} }
} }
// Chinese alternative: 【分析】...【/分析】 // Chinese alternative: 【分析】...【/分析】 or unclosed 【分析】...
while let Some(start_idx) = result.find("【分析】") { while let Some(start_idx) = result.find("【分析】") {
if let Some(end_idx) = result[start_idx..].find("【/分析】") { if let Some(end_idx) = result[start_idx..].find("【/分析】") {
result = format!( result = format!(
@ -38,6 +42,8 @@ pub fn strip_think_tags(content: &str) -> String {
&result[start_idx + end_idx + 5..] &result[start_idx + end_idx + 5..]
); );
} else { } else {
// Unclosed - strip to the end
result = result[..start_idx].to_string();
break; break;
} }
} }

View file

@ -35,7 +35,7 @@ pub fn get_handler(model_path: &str) -> Box<dyn ModelHandler> {
Box::new(gpt_oss_120b::GptOss120bHandler::new()) Box::new(gpt_oss_120b::GptOss120bHandler::new())
} else if path.contains("20b") { } else if path.contains("20b") {
Box::new(gpt_oss_20b::GptOss20bHandler) Box::new(gpt_oss_20b::GptOss20bHandler)
} else if path.contains("minimax") || path.contains("minimax-m") { } else if path.contains("minimax") || path.contains("minimax-m") || path.contains("kimi") {
Box::new(minimax::MinimaxHandler::new()) Box::new(minimax::MinimaxHandler::new())
} else { } else {
Box::new(PassthroughHandler) Box::new(PassthroughHandler)