Files
LocalAI/core/config/thinking_disabled_test.go
T
xianshujun 45d7a967c7 fix(openai): keep answers in content when thinking is disabled
qwen3's chat template wraps <think> in {% if enable_thinking %}, but the
prefill detectors scan the raw template without evaluating the condition.
With streaming and no tools, the synthetic prefill made the Go-side extractor
classify the whole answer as reasoning whenever the client sent
metadata.enable_thinking=false.

Skip prefill detection when the request disables thinking. Real
<think>...</think> blocks that a model emits anyway are still extracted from
the content itself.

Fixes #12939

Assisted-by: ZCode:deepseek-flash
Signed-off-by: xianshujun <xianshupang@gmail.com>
(cherry picked from commit cee7ed4b32)
(cherry picked from commit 29618866d07a05624934bf9f595c95a68c938461)
2026-11-03 19:21:12 +00:00

77 lines
2.6 KiB
Go

package config_test
import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/mudler/LocalAI/core/config"
)
// ReasoningDisabled decides whether the streaming reasoning extractor may
// prefill a synthetic thinking-start token. It has to resolve enable_thinking
// exactly like the backend: request metadata over the operator's reasoning
// config, over the model's chat_template_kwargs.
var _ = Describe("ModelConfig.ReasoningDisabled", func() {
It("is false when nothing disables reasoning", func() {
Expect((&config.ModelConfig{}).ReasoningDisabled()).To(BeFalse())
})
It("is true when the operator disabled reasoning", func() {
disabled := true
cfg := &config.ModelConfig{}
cfg.ReasoningConfig.DisableReasoning = &disabled
Expect(cfg.ReasoningDisabled()).To(BeTrue())
})
It("is false when the operator explicitly enabled reasoning", func() {
enabled := false
cfg := &config.ModelConfig{}
cfg.ReasoningConfig.DisableReasoning = &enabled
Expect(cfg.ReasoningDisabled()).To(BeFalse())
})
It("honors a client enable_thinking=false", func() {
cfg := &config.ModelConfig{RequestMetadata: map[string]string{"enable_thinking": "false"}}
Expect(cfg.ReasoningDisabled()).To(BeTrue())
})
It("stays enabled for enable_thinking=true", func() {
cfg := &config.ModelConfig{RequestMetadata: map[string]string{"enable_thinking": "true"}}
Expect(cfg.ReasoningDisabled()).To(BeFalse())
})
It("stays enabled for an unparsable metadata value", func() {
cfg := &config.ModelConfig{RequestMetadata: map[string]string{"enable_thinking": "sometimes"}}
Expect(cfg.ReasoningDisabled()).To(BeFalse())
})
It("lets request metadata re-enable thinking over the operator's disable", func() {
disabled := true
cfg := &config.ModelConfig{
RequestMetadata: map[string]string{"enable_thinking": "true"},
}
cfg.ReasoningConfig.DisableReasoning = &disabled
Expect(cfg.ReasoningDisabled()).To(BeFalse())
})
It("honors the model chat_template_kwargs enable_thinking=false", func() {
cfg := &config.ModelConfig{
ChatTemplateKwargs: map[string]any{"enable_thinking": false},
}
Expect(cfg.ReasoningDisabled()).To(BeTrue())
})
It("lets request metadata override the model chat_template_kwargs", func() {
cfg := &config.ModelConfig{
ChatTemplateKwargs: map[string]any{"enable_thinking": false},
RequestMetadata: map[string]string{"enable_thinking": "true"},
}
Expect(cfg.ReasoningDisabled()).To(BeFalse())
})
It("tolerates a nil receiver", func() {
var cfg *config.ModelConfig
Expect(cfg.ReasoningDisabled()).To(BeFalse())
})
})