fix: strip leaked Thinking/Final tags from OpenAI-compatible responses
Some OpenAI-compatible providers return chain-of-thought content mixed into the response field using XML-style tags. This internal reasoning text leaks to end users. This commit adds a sanitizer that: 1. Handles escaped Unicode forms (\u003c/\u003e) 2. Removes thinking blocks entirely (tags + content) 3. Removes <final> tag wrappers while preserving the final content 4. Cleans up leftover whitespace-only lines Uses direct regex calls instead of pattern array to avoid linter issues. Fixes #1235 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f0caa04f60
commit
2940264045
1 changed files with 27 additions and 20 deletions
|
|
@ -526,7 +526,7 @@ func supportsPromptCacheKey(apiBase string) bool {
|
||||||
// stripThinkingTags removes chain-of-thought tags from content that may be
|
// stripThinkingTags removes chain-of-thought tags from content that may be
|
||||||
// leaked by some OpenAI-compatible providers (e.g., MiniMax-style responses).
|
// leaked by some OpenAI-compatible providers (e.g., MiniMax-style responses).
|
||||||
// Handles both normal tags and escaped Unicode forms.
|
// Handles both normal tags and escaped Unicode forms.
|
||||||
// Tags removed: <think>, <thinking>, <thought>, <reasoning>, <final>
|
// Tags removed: </think>, <thinking>, <thought>, <reasoning>, <final>
|
||||||
func stripThinkingTags(content string) string {
|
func stripThinkingTags(content string) string {
|
||||||
if content == "" {
|
if content == "" {
|
||||||
return content
|
return content
|
||||||
|
|
@ -539,26 +539,33 @@ func stripThinkingTags(content string) string {
|
||||||
content = strings.ReplaceAll(content, `\\u003c`, "<")
|
content = strings.ReplaceAll(content, `\\u003c`, "<")
|
||||||
content = strings.ReplaceAll(content, `\\u003e`, ">")
|
content = strings.ReplaceAll(content, `\\u003e`, ">")
|
||||||
|
|
||||||
// Pattern to match thinking/reasoning tags (with optional inner content)
|
// Remove </think> tags and content (case-insensitive, multiline)
|
||||||
// Matches: <tag>content</tag>, <tag />, <tag></tag>
|
content = regexp.MustCompile(`(?is)<think\b[^>]*>.*?
|
||||||
patterns := []string{
|
|
||||||
`(?i)<think\b[^>]*>.*?</think>`, // <think>...</think>
|
|
||||||
`(?i)<thinking\b[^>]*>.*?</thinking>`, // <thinking>...</thinking>
|
|
||||||
`(?i)<thought\b[^>]*>.*?</thought>`, // <thought>...</thought>
|
|
||||||
`(?i)<reasoning\b[^>]*>.*?</reasoning>`, // <reasoning>...</reasoning>
|
|
||||||
`(?i)<final\b[^>*>(?:/>|>.*?</final>)`, // <final/> or <final>...</final> (remove tag, keep content)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pattern := range patterns {
|
|
||||||
re := regexp.MustCompile(pattern)
|
|
||||||
if strings.HasPrefix(pattern, `(?i)<final`) {
|
|
||||||
// For <final> tags, remove the tags but keep the inner content
|
|
||||||
content = re.ReplaceAllString(content, "$1")
|
|
||||||
} else {
|
|
||||||
// For thinking tags, remove both tags and content
|
|
||||||
content = re.ReplaceAllString(content, "")
|
|
||||||
}
|
|
||||||
}
|
`).ReplaceAllString(content, "")
|
||||||
|
|
||||||
|
// Remove <thinking> tags and content
|
||||||
|
content = regexp.MustCompile(`(?is)<thinking\b[^>]*>.*?</thinking>`).ReplaceAllString(content, "")
|
||||||
|
|
||||||
|
// Remove <thought> tags and content
|
||||||
|
content = regexp.MustCompile(`(?is)<thought\b[^>]*>.*?</thought>`).ReplaceAllString(content, "")
|
||||||
|
|
||||||
|
// Remove <reasoning> tags and content
|
||||||
|
content = regexp.MustCompile(`(?is)<reasoning\b[^>]*>.*?</reasoning>`).ReplaceAllString(content, "")
|
||||||
|
|
||||||
|
// For <final> tags, remove the tags but keep the inner content
|
||||||
|
// Handle both <final/> and <final>content</final>
|
||||||
|
content = regexp.MustCompile(`(?i)<final\b[^>]*/>`).ReplaceAllString(content, "")
|
||||||
|
content = regexp.MustCompile(`(?is)<final\b[^>]*>(.*?)</final>`).ReplaceAllString(content, "$1")
|
||||||
|
|
||||||
// Clean up any whitespace-only lines left after removing blocks
|
// Clean up any whitespace-only lines left after removing blocks
|
||||||
lines := strings.Split(content, "\n")
|
lines := strings.Split(content, "\n")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue