Skip to content

Commit 06df079

Browse files
committed
think stripping
1 parent eafeb6a commit 06df079

File tree

3 files changed

+47
-5
lines changed

3 files changed

+47
-5
lines changed

crates/openfang-api/src/openai_compat.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ pub async fn chat_completions(
335335
index: 0,
336336
message: ChoiceMessage {
337337
role: "assistant",
338-
content: Some(result.response),
338+
content: Some(crate::ws::strip_think_tags(&result.response)),
339339
tool_calls: None,
340340
},
341341
finish_reason: "stop",

crates/openfang-api/src/routes.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,16 +321,19 @@ pub async fn send_message(
321321
.await
322322
{
323323
Ok(result) => {
324+
// Strip <think>...</think> blocks from model output
325+
let cleaned = crate::ws::strip_think_tags(&result.response);
326+
324327
// Guard: ensure we never return an empty response to the client
325-
let response = if result.response.trim().is_empty() {
328+
let response = if cleaned.trim().is_empty() {
326329
format!(
327330
"[The agent completed processing but returned no text response. ({} in / {} out | {} iter)]",
328331
result.total_usage.input_tokens,
329332
result.total_usage.output_tokens,
330333
result.iterations,
331334
)
332335
} else {
333-
result.response
336+
cleaned
334337
};
335338
(
336339
StatusCode::OK,

crates/openfang-api/src/ws.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -621,16 +621,20 @@ async fn handle_text_message(
621621
return;
622622
}
623623

624+
// Strip <think>...</think> blocks from model output
625+
// (e.g. MiniMax, DeepSeek reasoning tokens)
626+
let cleaned_response = strip_think_tags(&result.response);
627+
624628
// Guard: ensure we never send an empty response
625-
let content = if result.response.trim().is_empty() {
629+
let content = if cleaned_response.trim().is_empty() {
626630
format!(
627631
"[The agent completed processing but returned no text response. ({} in / {} out | {} iter)]",
628632
result.total_usage.input_tokens,
629633
result.total_usage.output_tokens,
630634
result.iterations,
631635
)
632636
} else {
633-
result.response
637+
cleaned_response
634638
};
635639

636640
// Estimate context pressure from last call
@@ -1156,6 +1160,27 @@ fn extract_status_code(s: &str) -> Option<u16> {
11561160
None
11571161
}
11581162

1163+
/// Strip `<think>...</think>` blocks from model output.
1164+
///
1165+
/// Some models (MiniMax, DeepSeek, etc.) wrap their reasoning in `<think>` tags.
1166+
/// These are internal chain-of-thought and shouldn't be shown to the user.
1167+
pub fn strip_think_tags(text: &str) -> String {
1168+
let mut result = String::with_capacity(text.len());
1169+
let mut remaining = text;
1170+
while let Some(start) = remaining.find("<think>") {
1171+
result.push_str(&remaining[..start]);
1172+
if let Some(end) = remaining[start..].find("</think>") {
1173+
remaining = &remaining[(start + end + 8)..]; // 8 = "</think>".len()
1174+
} else {
1175+
// Unclosed <think> tag — strip to end
1176+
remaining = "";
1177+
break;
1178+
}
1179+
}
1180+
result.push_str(remaining);
1181+
result
1182+
}
1183+
11591184
// ---------------------------------------------------------------------------
11601185
// Tests
11611186
// ---------------------------------------------------------------------------
@@ -1232,4 +1257,18 @@ mod tests {
12321257
fn test_sanitize_trims_whitespace() {
12331258
assert_eq!(sanitize_user_input(" hello "), "hello");
12341259
}
1260+
1261+
#[test]
1262+
fn test_strip_think_tags() {
1263+
assert_eq!(
1264+
strip_think_tags("<think>reasoning here</think>The answer is 42."),
1265+
"The answer is 42."
1266+
);
1267+
assert_eq!(
1268+
strip_think_tags("Hello <think>\nsome thinking\n</think> world"),
1269+
"Hello world"
1270+
);
1271+
assert_eq!(strip_think_tags("No thinking here"), "No thinking here");
1272+
assert_eq!(strip_think_tags("<think>all thinking</think>"), "");
1273+
}
12351274
}

0 commit comments

Comments
 (0)