-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathqwen.go
More file actions
78 lines (70 loc) · 2.18 KB
/
Copy pathqwen.go
File metadata and controls
78 lines (70 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package main
import (
"strings"
)
// injectQwenThinkingDisabled adds chat_template_kwargs to disable thinking mode
// on Qwen3/3.5 models. Without this, the model wraps its output in <think> tags
// and produces no usable content.
func injectQwenThinkingDisabled(req *ChatRequest, backend *Backend) {
modelLower := strings.ToLower(backend.Config.ModelName)
if !strings.Contains(modelLower, "qwen3") {
return
}
if req.ChatTemplateKwargs == nil {
req.ChatTemplateKwargs = make(map[string]interface{})
}
req.ChatTemplateKwargs["enable_thinking"] = false
}
// stripThinkTags removes <think>...</think> blocks from LLM output.
// Handles both closed tags and unclosed tags (strips from <think> to end of string).
func stripThinkTags(s string) string {
for {
start := strings.Index(s, "<think>")
if start == -1 {
return s
}
end := strings.Index(s[start:], "</think>")
if end == -1 {
// Unclosed think tag: strip from <think> to end
return strings.TrimSpace(s[:start])
}
s = s[:start] + s[start+end+len("</think>"):]
}
}
// stripThinkTagsStreaming handles think tag stripping in SSE streaming mode.
// Returns the cleaned chunk, the updated inThinkBlock state, and the buffer.
func stripThinkTagsStreaming(
chunk string,
inThinkBlock bool,
thinkBuf strings.Builder,
) (string, bool, strings.Builder) {
if inThinkBlock {
// Look for closing tag in this chunk
endIdx := strings.Index(chunk, "</think>")
if endIdx == -1 {
// Still inside think block, buffer everything
return "", true, thinkBuf
}
// Found end of think block
remaining := chunk[endIdx+len("</think>"):]
thinkBuf.Reset()
return remaining, false, thinkBuf
}
// Check for opening think tag
startIdx := strings.Index(chunk, "<think>")
if startIdx == -1 {
return chunk, false, thinkBuf
}
// Found opening tag
before := chunk[:startIdx]
after := chunk[startIdx+len("<think>"):]
// Check if closing tag is in the same chunk
endIdx := strings.Index(after, "</think>")
if endIdx == -1 {
// Opening tag but no close -- enter think block mode
return before, true, thinkBuf
}
// Both open and close in same chunk
remaining := after[endIdx+len("</think>"):]
return before + remaining, false, thinkBuf
}