@@ -317,6 +317,29 @@ var _ = Describe("ExtractReasoning", func() {
317317 Expect (cleaned ).To (Equal ("Before " ))
318318 })
319319 })
320+
321+ Context ("when content has <|channel>thought tags (Gemma 4)" , func () {
322+ It ("should extract reasoning from channel thought block" , func () {
323+ content := "<|channel>thought\n This is my reasoning\n <channel|>Hello! How can I help?"
324+ reasoning , cleaned := ExtractReasoning (content , nil )
325+ Expect (reasoning ).To (Equal ("This is my reasoning" ))
326+ Expect (cleaned ).To (Equal ("Hello! How can I help?" ))
327+ })
328+
329+ It ("should handle unclosed channel thought block" , func () {
330+ content := "<|channel>thought\n Incomplete reasoning"
331+ reasoning , cleaned := ExtractReasoning (content , nil )
332+ Expect (reasoning ).To (Equal ("Incomplete reasoning" ))
333+ Expect (cleaned ).To (Equal ("" ))
334+ })
335+
336+ It ("should handle content before and after channel thought block" , func () {
337+ content := "Before <|channel>thought\n Gemma 4 reasoning\n <channel|> After"
338+ reasoning , cleaned := ExtractReasoning (content , nil )
339+ Expect (reasoning ).To (Equal ("Gemma 4 reasoning" ))
340+ Expect (cleaned ).To (Equal ("Before After" ))
341+ })
342+ })
320343})
321344
322345var _ = Describe ("DetectThinkingStartToken" , func () {
@@ -339,6 +362,12 @@ var _ = Describe("DetectThinkingStartToken", func() {
339362 Expect (token ).To (Equal ("<thinking>" ))
340363 })
341364
365+ It ("should detect <|channel>thought at the end (Gemma 4)" , func () {
366+ prompt := "Prompt text <|channel>thought"
367+ token := DetectThinkingStartToken (prompt , nil )
368+ Expect (token ).To (Equal ("<|channel>thought" ))
369+ })
370+
342371 It ("should detect <|inner_prefix|> at the end" , func () {
343372 prompt := "Prompt <|inner_prefix|>"
344373 token := DetectThinkingStartToken (prompt , nil )
@@ -817,6 +846,14 @@ var _ = Describe("ExtractReasoningWithConfig", func() {
817846 Expect (cleaned ).To (Equal ("Text More" ))
818847 })
819848
849+ It ("should strip reasoning from Gemma 4 channel tags when StripReasoningOnly is true" , func () {
850+ content := "<|channel>thought\n Gemma 4 reasoning\n <channel|>Response text"
851+ config := Config {StripReasoningOnly : boolPtr (true )}
852+ reasoning , cleaned := ExtractReasoningWithConfig (content , "<|channel>thought" , config )
853+ Expect (reasoning ).To (BeEmpty ())
854+ Expect (cleaned ).To (Equal ("Response text" ))
855+ })
856+
820857 It ("should strip reasoning with multiline content when StripReasoningOnly is true" , func () {
821858 content := "Start <thinking>Line 1\n Line 2\n Line 3</thinking> End"
822859 config := Config {StripReasoningOnly : boolPtr (true )}
0 commit comments