mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
refactor(thinking): remove support for non-standard thinking configurations
This change removes the translation logic for several non-standard, proprietary extensions used to configure thinking/reasoning. Specifically, support for `extra_body.google.thinking_config` and the Anthropic-style `thinking` object has been dropped from the OpenAI request translators. This simplification streamlines the translators, focusing them on the standard `reasoning_effort` parameter. It also removes the need to look up model information from the registry within these components. BREAKING CHANGE: Support for non-standard thinking configurations via `extra_body.google.thinking_config` and the Anthropic-style `thinking` object has been removed. Clients should now use the standard `reasoning_effort` parameter to control reasoning.
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -38,7 +37,6 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
|
|||||||
|
|
||||||
// Apply thinking configuration: convert OpenAI reasoning_effort to Gemini CLI thinkingConfig.
|
// Apply thinking configuration: convert OpenAI reasoning_effort to Gemini CLI thinkingConfig.
|
||||||
// Inline translation-only mapping; capability checks happen later in ApplyThinking.
|
// Inline translation-only mapping; capability checks happen later in ApplyThinking.
|
||||||
modelInfo := registry.LookupModelInfo(modelName)
|
|
||||||
re := gjson.GetBytes(rawJSON, "reasoning_effort")
|
re := gjson.GetBytes(rawJSON, "reasoning_effort")
|
||||||
if re.Exists() {
|
if re.Exists() {
|
||||||
effort := strings.ToLower(strings.TrimSpace(re.String()))
|
effort := strings.ToLower(strings.TrimSpace(re.String()))
|
||||||
@@ -54,47 +52,6 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cherry Studio extension extra_body.google.thinking_config (effective only when official fields are absent)
|
|
||||||
// Only apply for models that use numeric budgets, not discrete levels.
|
|
||||||
if !re.Exists() && modelInfo != nil && modelInfo.Thinking != nil && len(modelInfo.Thinking.Levels) == 0 {
|
|
||||||
if tc := gjson.GetBytes(rawJSON, "extra_body.google.thinking_config"); tc.Exists() && tc.IsObject() {
|
|
||||||
var setBudget bool
|
|
||||||
var budget int
|
|
||||||
|
|
||||||
if v := tc.Get("thinkingBudget"); v.Exists() {
|
|
||||||
budget = int(v.Int())
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
|
||||||
setBudget = true
|
|
||||||
} else if v := tc.Get("thinking_budget"); v.Exists() {
|
|
||||||
budget = int(v.Int())
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingBudget.thinkingBudget", budget)
|
|
||||||
setBudget = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if v := tc.Get("includeThoughts"); v.Exists() {
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", v.Bool())
|
|
||||||
} else if v := tc.Get("include_thoughts"); v.Exists() {
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", v.Bool())
|
|
||||||
} else if setBudget && budget != 0 {
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claude/Anthropic API format: thinking.type == "enabled" with budget_tokens
|
|
||||||
// This allows Claude Code and other Claude API clients to pass thinking configuration
|
|
||||||
if !gjson.GetBytes(out, "request.generationConfig.thinkingConfig").Exists() && modelInfo != nil && modelInfo.Thinking != nil {
|
|
||||||
if t := gjson.GetBytes(rawJSON, "thinking"); t.Exists() && t.IsObject() {
|
|
||||||
if t.Get("type").String() == "enabled" {
|
|
||||||
if b := t.Get("budget_tokens"); b.Exists() && b.Type == gjson.Number {
|
|
||||||
budget := int(b.Int())
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temperature/top_p/top_k/max_tokens
|
// Temperature/top_p/top_k/max_tokens
|
||||||
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num)
|
out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -39,7 +38,6 @@ func ConvertOpenAIRequestToGeminiCLI(modelName string, inputRawJSON []byte, _ bo
|
|||||||
// Apply thinking configuration: convert OpenAI reasoning_effort to Gemini CLI thinkingConfig.
|
// Apply thinking configuration: convert OpenAI reasoning_effort to Gemini CLI thinkingConfig.
|
||||||
// Inline translation-only mapping; capability checks happen later in ApplyThinking.
|
// Inline translation-only mapping; capability checks happen later in ApplyThinking.
|
||||||
re := gjson.GetBytes(rawJSON, "reasoning_effort")
|
re := gjson.GetBytes(rawJSON, "reasoning_effort")
|
||||||
modelInfo := registry.LookupModelInfo(modelName)
|
|
||||||
if re.Exists() {
|
if re.Exists() {
|
||||||
effort := strings.ToLower(strings.TrimSpace(re.String()))
|
effort := strings.ToLower(strings.TrimSpace(re.String()))
|
||||||
if effort != "" {
|
if effort != "" {
|
||||||
@@ -54,33 +52,6 @@ func ConvertOpenAIRequestToGeminiCLI(modelName string, inputRawJSON []byte, _ bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cherry Studio extension extra_body.google.thinking_config (effective only when official fields are absent)
|
|
||||||
// Only apply for models that use numeric budgets, not discrete levels.
|
|
||||||
if !re.Exists() && modelInfo != nil && modelInfo.Thinking != nil && len(modelInfo.Thinking.Levels) == 0 {
|
|
||||||
if tc := gjson.GetBytes(rawJSON, "extra_body.google.thinking_config"); tc.Exists() && tc.IsObject() {
|
|
||||||
var setBudget bool
|
|
||||||
var budget int
|
|
||||||
|
|
||||||
if v := tc.Get("thinkingBudget"); v.Exists() {
|
|
||||||
budget = int(v.Int())
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
|
||||||
setBudget = true
|
|
||||||
} else if v := tc.Get("thinking_budget"); v.Exists() {
|
|
||||||
budget = int(v.Int())
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
|
||||||
setBudget = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if v := tc.Get("includeThoughts"); v.Exists() {
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", v.Bool())
|
|
||||||
} else if v := tc.Get("include_thoughts"); v.Exists() {
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", v.Bool())
|
|
||||||
} else if setBudget && budget != 0 {
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temperature/top_p/top_k
|
// Temperature/top_p/top_k
|
||||||
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num)
|
out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -38,7 +37,6 @@ func ConvertOpenAIRequestToGemini(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
|
|
||||||
// Apply thinking configuration: convert OpenAI reasoning_effort to Gemini thinkingConfig.
|
// Apply thinking configuration: convert OpenAI reasoning_effort to Gemini thinkingConfig.
|
||||||
// Inline translation-only mapping; capability checks happen later in ApplyThinking.
|
// Inline translation-only mapping; capability checks happen later in ApplyThinking.
|
||||||
modelInfo := registry.LookupModelInfo(modelName)
|
|
||||||
re := gjson.GetBytes(rawJSON, "reasoning_effort")
|
re := gjson.GetBytes(rawJSON, "reasoning_effort")
|
||||||
if re.Exists() {
|
if re.Exists() {
|
||||||
effort := strings.ToLower(strings.TrimSpace(re.String()))
|
effort := strings.ToLower(strings.TrimSpace(re.String()))
|
||||||
@@ -54,33 +52,6 @@ func ConvertOpenAIRequestToGemini(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cherry Studio extension extra_body.google.thinking_config (effective only when official fields are absent)
|
|
||||||
// Only apply for models that use numeric budgets, not discrete levels.
|
|
||||||
if !re.Exists() && modelInfo != nil && modelInfo.Thinking != nil && len(modelInfo.Thinking.Levels) == 0 {
|
|
||||||
if tc := gjson.GetBytes(rawJSON, "extra_body.google.thinking_config"); tc.Exists() && tc.IsObject() {
|
|
||||||
var setBudget bool
|
|
||||||
var budget int
|
|
||||||
|
|
||||||
if v := tc.Get("thinkingBudget"); v.Exists() {
|
|
||||||
budget = int(v.Int())
|
|
||||||
out, _ = sjson.SetBytes(out, "generationConfig.thinkingConfig.thinkingBudget", budget)
|
|
||||||
setBudget = true
|
|
||||||
} else if v := tc.Get("thinking_budget"); v.Exists() {
|
|
||||||
budget = int(v.Int())
|
|
||||||
out, _ = sjson.SetBytes(out, "generationConfig.thinkingConfig.thinkingBudget", budget)
|
|
||||||
setBudget = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if v := tc.Get("includeThoughts"); v.Exists() {
|
|
||||||
out, _ = sjson.SetBytes(out, "generationConfig.thinkingConfig.include_thoughts", v.Bool())
|
|
||||||
} else if v := tc.Get("include_thoughts"); v.Exists() {
|
|
||||||
out, _ = sjson.SetBytes(out, "generationConfig.thinkingConfig.include_thoughts", v.Bool())
|
|
||||||
} else if setBudget && budget != 0 {
|
|
||||||
out, _ = sjson.SetBytes(out, "generationConfig.thinkingConfig.include_thoughts", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temperature/top_p/top_k
|
// Temperature/top_p/top_k
|
||||||
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
||||||
out, _ = sjson.SetBytes(out, "generationConfig.temperature", tr.Num)
|
out, _ = sjson.SetBytes(out, "generationConfig.temperature", tr.Num)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
"github.com/tidwall/sjson"
|
"github.com/tidwall/sjson"
|
||||||
@@ -390,7 +389,6 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte
|
|||||||
|
|
||||||
// Apply thinking configuration: convert OpenAI Responses API reasoning.effort to Gemini thinkingConfig.
|
// Apply thinking configuration: convert OpenAI Responses API reasoning.effort to Gemini thinkingConfig.
|
||||||
// Inline translation-only mapping; capability checks happen later in ApplyThinking.
|
// Inline translation-only mapping; capability checks happen later in ApplyThinking.
|
||||||
modelInfo := registry.LookupModelInfo(modelName)
|
|
||||||
re := root.Get("reasoning.effort")
|
re := root.Get("reasoning.effort")
|
||||||
if re.Exists() {
|
if re.Exists() {
|
||||||
effort := strings.ToLower(strings.TrimSpace(re.String()))
|
effort := strings.ToLower(strings.TrimSpace(re.String()))
|
||||||
@@ -406,27 +404,6 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cherry Studio extension (applies only when official fields are missing)
|
|
||||||
// Only apply for models that use numeric budgets, not discrete levels.
|
|
||||||
if !re.Exists() && modelInfo != nil && modelInfo.Thinking != nil && len(modelInfo.Thinking.Levels) == 0 {
|
|
||||||
if tc := root.Get("extra_body.google.thinking_config"); tc.Exists() && tc.IsObject() {
|
|
||||||
var setBudget bool
|
|
||||||
var budget int
|
|
||||||
if v := tc.Get("thinking_budget"); v.Exists() {
|
|
||||||
budget = int(v.Int())
|
|
||||||
out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", budget)
|
|
||||||
setBudget = true
|
|
||||||
}
|
|
||||||
if v := tc.Get("include_thoughts"); v.Exists() {
|
|
||||||
out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", v.Bool())
|
|
||||||
} else if setBudget {
|
|
||||||
if budget != 0 {
|
|
||||||
out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := []byte(out)
|
result := []byte(out)
|
||||||
result = common.AttachDefaultSafetySettings(result, "safetySettings")
|
result = common.AttachDefaultSafetySettings(result, "safetySettings")
|
||||||
return result
|
return result
|
||||||
|
|||||||
Reference in New Issue
Block a user