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
.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>()
.unwrap_or(20);
.unwrap_or(120);
if threshold == 0 {
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>"));
pub fn strip_think_tags(content: &str) -> String {
if let Ok(re) = &*THINK_TAG_REGEX {
re.replace_all(content, "").to_string()
} else {
content.to_string()
// We want to strip <think>...</think> OR <think> until end of string (streaming)
let mut result = content.to_string();
if let Some(start_idx) = result.find("<think>") {
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)]

View file

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

View file

@ -35,7 +35,7 @@ pub fn get_handler(model_path: &str) -> Box<dyn ModelHandler> {
Box::new(gpt_oss_120b::GptOss120bHandler::new())
} else if path.contains("20b") {
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())
} else {
Box::new(PassthroughHandler)