From fee736933bce82a8ae1b42089a64c714d0852006 Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Tue, 24 Mar 2026 14:21:12 +0800 Subject: [PATCH] feat(openai-compat): add per-model thinking support --- config.example.yaml | 4 +++- internal/config/config.go | 5 +++++ internal/registry/model_registry.go | 10 +++++----- sdk/cliproxy/service.go | 7 ++++++- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/config.example.yaml b/config.example.yaml index c393bb7a..df249246 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -206,7 +206,9 @@ nonstream-keepalive-interval: 0 # - api-key: "sk-or-v1-...b781" # without proxy-url # models: # The models supported by the provider. # - name: "moonshotai/kimi-k2:free" # The actual model name. -# alias: "kimi-k2" # The alias used in the API. +# alias: "kimi-k2" # The alias used in the API. +# thinking: # optional: omit to default to levels ["low","medium","high"] +# levels: ["low", "medium", "high"] # # You may repeat the same alias to build an internal model pool. # # The client still sees only one alias in the model list. # # Requests to that alias will round-robin across the upstream names below, diff --git a/internal/config/config.go b/internal/config/config.go index 04822b61..29f4eb2a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -13,6 +13,7 @@ import ( "strings" "syscall" + "github.com/router-for-me/CLIProxyAPI/v6/internal/registry" log "github.com/sirupsen/logrus" "golang.org/x/crypto/bcrypt" "gopkg.in/yaml.v3" @@ -511,6 +512,10 @@ type OpenAICompatibilityModel struct { // Alias is the model name alias that clients will use to reference this model. Alias string `yaml:"alias" json:"alias"` + + // Thinking configures the thinking/reasoning capability for this model. + // If nil, the model defaults to level-based reasoning with levels ["low", "medium", "high"]. + Thinking *registry.ThinkingSupport `yaml:"thinking,omitempty" json:"thinking,omitempty"` } func (m OpenAICompatibilityModel) GetName() string { return m.Name } diff --git a/internal/registry/model_registry.go b/internal/registry/model_registry.go index 74ad6acf..3f3f530d 100644 --- a/internal/registry/model_registry.go +++ b/internal/registry/model_registry.go @@ -71,16 +71,16 @@ type availableModelsCacheEntry struct { // Values are interpreted in provider-native token units. type ThinkingSupport struct { // Min is the minimum allowed thinking budget (inclusive). - Min int `json:"min,omitempty"` + Min int `json:"min,omitempty" yaml:"min,omitempty"` // Max is the maximum allowed thinking budget (inclusive). - Max int `json:"max,omitempty"` + Max int `json:"max,omitempty" yaml:"max,omitempty"` // ZeroAllowed indicates whether 0 is a valid value (to disable thinking). - ZeroAllowed bool `json:"zero_allowed,omitempty"` + ZeroAllowed bool `json:"zero_allowed,omitempty" yaml:"zero-allowed,omitempty"` // DynamicAllowed indicates whether -1 is a valid value (dynamic thinking budget). - DynamicAllowed bool `json:"dynamic_allowed,omitempty"` + DynamicAllowed bool `json:"dynamic_allowed,omitempty" yaml:"dynamic-allowed,omitempty"` // Levels defines discrete reasoning effort levels (e.g., "low", "medium", "high"). // When set, the model uses level-based reasoning instead of token budgets. - Levels []string `json:"levels,omitempty"` + Levels []string `json:"levels,omitempty" yaml:"levels,omitempty"` } // ModelRegistration tracks a model's availability diff --git a/sdk/cliproxy/service.go b/sdk/cliproxy/service.go index 3ca765c6..55b9df39 100644 --- a/sdk/cliproxy/service.go +++ b/sdk/cliproxy/service.go @@ -960,6 +960,10 @@ func (s *Service) registerModelsForAuth(a *coreauth.Auth) { if modelID == "" { modelID = m.Name } + thinking := m.Thinking + if thinking == nil { + thinking = ®istry.ThinkingSupport{Levels: []string{"low", "medium", "high"}} + } ms = append(ms, &ModelInfo{ ID: modelID, Object: "model", @@ -967,7 +971,8 @@ func (s *Service) registerModelsForAuth(a *coreauth.Auth) { OwnedBy: compat.Name, Type: "openai-compatibility", DisplayName: modelID, - UserDefined: true, + UserDefined: false, + Thinking: thinking, }) } // Register and return