mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-06 20:43:27 -05:00
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)
77 lines
2.6 KiB
Go
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())
|
|
})
|
|
})
|