From 90a79a2750a41d088dedc2c2f120827437fd1c67 Mon Sep 17 00:00:00 2001 From: Ajeet Upadhyay Date: Sat, 10 Oct 2026 12:26:38 +0530 Subject: [PATCH] model/renderers: stop injecting /nothink for glm-ocr when thinking is off ResolveThinking fills Default:false on omission; those markers were derailing table recognition. Fixes #18810. --- model/renderers/glmocr.go | 17 ++++---------- model/renderers/glmocr_test.go | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/model/renderers/glmocr.go b/model/renderers/glmocr.go index e7910f6a5..2888750ac 100644 --- a/model/renderers/glmocr.go +++ b/model/renderers/glmocr.go @@ -46,12 +46,11 @@ func (r *GlmOcrRenderer) Render(messages []api.Message, tools []api.Tool, thinkV sb.WriteString("{function-name}{arg-key-1}{arg-value-1}{arg-key-2}{arg-value-2}...") } - enableThinking := false - thinkingExplicitlySet := false - if thinkValue != nil { - enableThinking = thinkValue.Bool() - thinkingExplicitlySet = true - } + // thinkValue is accepted for renderer interface parity. Do not inject + // /nothink or an empty generation when thinking is off — + // ResolveThinking fills Default:false on omission, and those markers + // derail glm-ocr table recognition (#18810). + _ = thinkValue imageOffset := 0 for i, message := range messages { @@ -61,9 +60,6 @@ func (r *GlmOcrRenderer) Render(messages []api.Message, tools []api.Tool, thinkV content, nextOffset := r.renderContent(message, imageOffset) imageOffset = nextOffset sb.WriteString(content) - if thinkingExplicitlySet && !enableThinking && !strings.HasSuffix(message.Content, "/nothink") { - sb.WriteString("/nothink") - } case "assistant": sb.WriteString("<|assistant|>\n") if message.Thinking != "" { @@ -99,9 +95,6 @@ func (r *GlmOcrRenderer) Render(messages []api.Message, tools []api.Tool, thinkV } sb.WriteString("<|assistant|>\n") - if thinkingExplicitlySet && !enableThinking { - sb.WriteString("\n") - } return sb.String(), nil } diff --git a/model/renderers/glmocr_test.go b/model/renderers/glmocr_test.go index 1f8b9c038..ab87eb2b7 100644 --- a/model/renderers/glmocr_test.go +++ b/model/renderers/glmocr_test.go @@ -1,6 +1,7 @@ package renderers import ( + "strings" "testing" "github.com/google/go-cmp/cmp" @@ -97,3 +98,45 @@ func TestGlmOcrRenderer_Images(t *testing.T) { }) } } + +// ResolveThinking fills Default:false when the client omits think. That must not +// inject /nothink or an empty generation — those markers derail +// glm-ocr table recognition (see #18810). +func TestGlmOcrRenderer_NoNothinkWhenThinkingOff(t *testing.T) { + messages := []api.Message{ + { + Role: "user", + Content: "Table Recognition:", + Images: []api.ImageData{api.ImageData("img1")}, + }, + } + want := "[gMASK]<|user|>\n[img-0] Table Recognition:<|assistant|>\n" + + tests := []struct { + name string + think *api.ThinkValue + }{ + {name: "think_omitted", think: nil}, + {name: "think_false", think: &api.ThinkValue{Value: false}}, + {name: "think_true", think: &api.ThinkValue{Value: true}}, + } + + renderer := &GlmOcrRenderer{useImgTags: true} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := renderer.Render(messages, nil, tt.think) + if err != nil { + t.Fatalf("Render() error = %v", err) + } + if diff := cmp.Diff(want, got); diff != "" { + t.Fatalf("Render() mismatch (-want +got):\n%s", diff) + } + if strings.Contains(got, "/nothink") { + t.Fatalf("prompt unexpectedly contains /nothink: %q", got) + } + if strings.HasSuffix(got, "\n") { + t.Fatalf("prompt unexpectedly ends with empty think block: %q", got) + } + }) + } +}