mirror of
https://github.com/ollama/ollama.git
synced 2026-09-19 03:32:12 -04:00
122 lines
3.7 KiB
Go
122 lines
3.7 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"slices"
|
|
|
|
"github.com/ollama/ollama/internal/cloud"
|
|
"github.com/ollama/ollama/model/renderers"
|
|
"github.com/ollama/ollama/types/model"
|
|
)
|
|
|
|
func (s *Server) thinkingInputError(ctx context.Context, name string, inputErr error) error {
|
|
ref, err := parseAndValidateModelRef(name)
|
|
if err != nil {
|
|
return inputErr
|
|
}
|
|
var thinking *model.Thinking
|
|
if ref.Source == modelSourceCloud {
|
|
if disabled, _ := cloud.Status(); disabled {
|
|
return inputErr
|
|
}
|
|
cache := newModelShowCache()
|
|
if s.modelCaches != nil && s.modelCaches.show != nil {
|
|
cache = s.modelCaches.show
|
|
}
|
|
key := modelShowCloudKeyForModel(ref.Base, false)
|
|
info, ok := cache.getCloud(key)
|
|
if !ok {
|
|
info, err = cache.fetchCloudShow(ctx, ref.Base, false)
|
|
if err != nil {
|
|
return inputErr
|
|
}
|
|
cache.setCloud(key, info)
|
|
}
|
|
thinking = info.Thinking
|
|
} else if name, err := getExistingName(ref.Name); err == nil {
|
|
if m, err := GetModel(name.String()); err == nil {
|
|
thinking = m.Thinking()
|
|
}
|
|
}
|
|
if !thinking.Valid() {
|
|
return inputErr
|
|
}
|
|
values, _ := json.Marshal(thinking.Values)
|
|
return fmt.Errorf("%w; supported values: %s", inputErr, values)
|
|
}
|
|
|
|
// Exact template identities keep legacy metadata from leaking to custom templates.
|
|
// These entries describe the existing local endpoint behavior, without migrations.
|
|
var legacyThinking = map[string]model.Thinking{
|
|
// Qwen3 template with explicit /think and /no_think controls.
|
|
"sha256:ae370d884f108d16e7cc8fd5259ebc5773a0afa6e078b11f4ed7e39a27e0dfc4": {Values: []any{false, true}, Default: true},
|
|
// Older Qwen3 template always opens a thinking block.
|
|
"sha256:2d54db2b9bb29ce7db54fea63a891f5859603813c555b1f88b5e0994652897f9": {Values: []any{true}, Default: true},
|
|
// Llama3.2 tool-use template.
|
|
"sha256:966de95ca8a62200913e3f8bfbf84c8494536f1b94b49166851e76644e966396": {Values: []any{false}, Default: false},
|
|
}
|
|
|
|
// Thinking returns the effective local serving contract. Remote models obtain
|
|
// their current contract from the remote show response.
|
|
func (m *Model) Thinking() *model.Thinking {
|
|
if m == nil || m.Config.RemoteHost != "" {
|
|
return nil
|
|
}
|
|
if shouldUseHarmony(m) {
|
|
return renderers.ThinkingForRenderer("harmony")
|
|
}
|
|
if name := resolveRendererName(m); name != "" {
|
|
thinking := renderers.ThinkingForRenderer(name)
|
|
if thinking == nil {
|
|
return nil
|
|
}
|
|
// Discovery must match the controls accepted by the serving boundary.
|
|
if !slices.Contains(m.Capabilities(), model.CapabilityThinking) {
|
|
return &model.Thinking{Values: []any{false}, Default: false}
|
|
}
|
|
// Preserve the local endpoint's historical default-on behavior.
|
|
if thinking.Default == false && thinking.Supports(true) {
|
|
thinking.Default = true
|
|
}
|
|
// true currently reaches Qwen3.8 as medium via ThinkValue.String().
|
|
if name == "qwen3.8" {
|
|
thinking.Default = "medium"
|
|
}
|
|
return thinking
|
|
}
|
|
if shouldUseGoTemplate(m) {
|
|
if thinking, ok := legacyThinking[m.templateDigest]; ok {
|
|
return thinking.Clone()
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// genericThinking excludes Harmony and template-only paths from new fallback rules.
|
|
func (m *Model) genericThinking() *model.Thinking {
|
|
if m == nil || m.Config.Renderer == "" || shouldUseHarmony(m) {
|
|
return nil
|
|
}
|
|
return m.Thinking()
|
|
}
|
|
|
|
// lookupThinking lets compatibility middleware preserve named efforts only for
|
|
// local generic renderers. Other models keep the existing protocol conversions.
|
|
func lookupThinking(name string) *model.Thinking {
|
|
ref, err := parseAndValidateModelRef(name)
|
|
if err != nil || ref.Source == modelSourceCloud {
|
|
return nil
|
|
}
|
|
canonical, err := getExistingName(ref.Name)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
m, err := GetModel(canonical.String())
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return m.genericThinking()
|
|
}
|