diff --git a/model/parsers/qwen35.go b/model/parsers/qwen35.go
index b3e672c5d3..6a6f54b69a 100644
--- a/model/parsers/qwen35.go
+++ b/model/parsers/qwen35.go
@@ -21,6 +21,7 @@ const (
const (
qwen35ThinkingOpenTag = ""
qwen35ThinkingCloseTag = ""
+ qwen35ToolCallOpenTag = ""
)
// Qwen35Parser handles qwen3.5 reasoning extraction and delegates post-thinking
@@ -202,6 +203,14 @@ func (p *Qwen35Parser) eat() ([]qwen35Event, bool) {
events = append(events, qwen35EventThinkingContent{content: unambiguous})
}
return events, false
+ } else if strings.Contains(acc, qwen35ToolCallOpenTag) {
+ // qwen3.5:9b model forgets sometimes to use tag before the block starts
+ // this condition ends the Think block and continues with the when the tag
+ // is found
+ thinking, tooling := p.splitAtTag(qwen35ToolCallOpenTag, true)
+ p.buffer.Reset()
+ p.buffer.WriteString(thinking + qwen35ThinkingCloseTag + qwen35ToolCallOpenTag + tooling)
+ return events, true
}
whitespaceLen := trailingWhitespaceLen(acc)
diff --git a/model/parsers/qwen35_test.go b/model/parsers/qwen35_test.go
index 94a3f26fed..abedfe8f4d 100644
--- a/model/parsers/qwen35_test.go
+++ b/model/parsers/qwen35_test.go
@@ -108,7 +108,7 @@ func TestQwen35ParserAssistantPrefillStartsInContent(t *testing.T) {
}
}
-func TestQwen35ParserToolCallEmittedInThinkingIsNotParsed(t *testing.T) {
+func TestQwen35ParserToolCallEmittedInThinkingIsParsed(t *testing.T) {
parser := ParserForName("qwen3.5")
if parser == nil {
t.Fatal("expected qwen3.5 parser")
@@ -141,14 +141,20 @@ SF
if content != "" {
t.Fatalf("expected empty content, got %q", content)
}
- expectedThinking := `Need weather lookup
-SF
-`
- if thinking != expectedThinking {
- t.Fatalf("expected thinking %q, got %q", expectedThinking, thinking)
+ if thinking != "Need weather lookup" {
+ t.Fatalf("expected thinking %q, got %q", "Need weather lookup", thinking)
}
- if len(calls) != 0 {
- t.Fatalf("expected no tool calls before , got %d", len(calls))
+ if len(calls) != 1 {
+ t.Fatalf("expected 1 tool call, got %d", len(calls))
+ }
+
+ if calls[0].Function.Name != "get_weather" {
+ t.Fatalf("expected tool name %q, got %q", "get_weather", calls[0].Function.Name)
+ }
+
+ location, ok := calls[0].Function.Arguments.Get("location")
+ if !ok || location != "SF" {
+ t.Fatalf("expected location %q, got %v", "SF", location)
}
}