mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-03-21 16:40:22 +00:00
feat(thinking): improve provider family checks and clamp unsupported levels
This commit is contained in:
@@ -53,7 +53,17 @@ func ValidateConfig(config ThinkingConfig, modelInfo *registry.ModelInfo, fromFo
|
|||||||
return &config, nil
|
return &config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
allowClampUnsupported := isBudgetBasedProvider(fromFormat) && isLevelBasedProvider(toFormat)
|
// allowClampUnsupported determines whether to clamp unsupported levels instead of returning an error.
|
||||||
|
// This applies when crossing provider families (e.g., openai→gemini, claude→gemini) and the target
|
||||||
|
// model supports discrete levels. Same-family conversions require strict validation.
|
||||||
|
toCapability := detectModelCapability(modelInfo)
|
||||||
|
toHasLevelSupport := toCapability == CapabilityLevelOnly || toCapability == CapabilityHybrid
|
||||||
|
allowClampUnsupported := toHasLevelSupport && !isSameProviderFamily(fromFormat, toFormat)
|
||||||
|
|
||||||
|
// strictBudget determines whether to enforce strict budget range validation.
|
||||||
|
// This applies when: (1) config comes from request body (not suffix), (2) source format is known,
|
||||||
|
// and (3) source and target are in the same provider family. Cross-family or suffix-based configs
|
||||||
|
// are clamped instead of rejected to improve interoperability.
|
||||||
strictBudget := !fromSuffix && fromFormat != "" && isSameProviderFamily(fromFormat, toFormat)
|
strictBudget := !fromSuffix && fromFormat != "" && isSameProviderFamily(fromFormat, toFormat)
|
||||||
budgetDerivedFromLevel := false
|
budgetDerivedFromLevel := false
|
||||||
|
|
||||||
@@ -352,11 +362,21 @@ func isGeminiFamily(provider string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isOpenAIFamily(provider string) bool {
|
||||||
|
switch provider {
|
||||||
|
case "openai", "openai-response", "codex":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func isSameProviderFamily(from, to string) bool {
|
func isSameProviderFamily(from, to string) bool {
|
||||||
if from == to {
|
if from == to {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return isGeminiFamily(from) && isGeminiFamily(to)
|
return (isGeminiFamily(from) && isGeminiFamily(to)) ||
|
||||||
|
(isOpenAIFamily(from) && isOpenAIFamily(to))
|
||||||
}
|
}
|
||||||
|
|
||||||
func abs(x int) int {
|
func abs(x int) int {
|
||||||
|
|||||||
@@ -386,15 +386,17 @@ func TestThinkingE2EMatrix_Suffix(t *testing.T) {
|
|||||||
includeThoughts: "true",
|
includeThoughts: "true",
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
// Case 30: Effort xhigh → not in low/high → error
|
// Case 30: Effort xhigh → clamped to high
|
||||||
{
|
{
|
||||||
name: "30",
|
name: "30",
|
||||||
from: "openai",
|
from: "openai",
|
||||||
to: "gemini",
|
to: "gemini",
|
||||||
model: "gemini-mixed-model(xhigh)",
|
model: "gemini-mixed-model(xhigh)",
|
||||||
inputJSON: `{"model":"gemini-mixed-model(xhigh)","messages":[{"role":"user","content":"hi"}]}`,
|
inputJSON: `{"model":"gemini-mixed-model(xhigh)","messages":[{"role":"user","content":"hi"}]}`,
|
||||||
expectField: "",
|
expectField: "generationConfig.thinkingConfig.thinkingLevel",
|
||||||
expectErr: true,
|
expectValue: "high",
|
||||||
|
includeThoughts: "true",
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
// Case 31: Effort none → clamped to low (min supported) → includeThoughts=false
|
// Case 31: Effort none → clamped to low (min supported) → includeThoughts=false
|
||||||
{
|
{
|
||||||
@@ -1668,15 +1670,17 @@ func TestThinkingE2EMatrix_Body(t *testing.T) {
|
|||||||
includeThoughts: "true",
|
includeThoughts: "true",
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
// Case 30: reasoning_effort=xhigh → error (not in low/high)
|
// Case 30: reasoning_effort=xhigh → clamped to high
|
||||||
{
|
{
|
||||||
name: "30",
|
name: "30",
|
||||||
from: "openai",
|
from: "openai",
|
||||||
to: "gemini",
|
to: "gemini",
|
||||||
model: "gemini-mixed-model",
|
model: "gemini-mixed-model",
|
||||||
inputJSON: `{"model":"gemini-mixed-model","messages":[{"role":"user","content":"hi"}],"reasoning_effort":"xhigh"}`,
|
inputJSON: `{"model":"gemini-mixed-model","messages":[{"role":"user","content":"hi"}],"reasoning_effort":"xhigh"}`,
|
||||||
expectField: "",
|
expectField: "generationConfig.thinkingConfig.thinkingLevel",
|
||||||
expectErr: true,
|
expectValue: "high",
|
||||||
|
includeThoughts: "true",
|
||||||
|
expectErr: false,
|
||||||
},
|
},
|
||||||
// Case 31: reasoning_effort=none → clamped to low → includeThoughts=false
|
// Case 31: reasoning_effort=none → clamped to low → includeThoughts=false
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user