fix(util): centralize reasoning effort normalization

This commit is contained in:
hkfires
2025-12-11 12:14:51 +08:00
parent 3ffd120ae9
commit d06d0eab2f
2 changed files with 52 additions and 16 deletions

View File

@@ -113,3 +113,45 @@ func defaultReasoningLevel(levels []string) string {
} }
return "" return ""
} }
// standardReasoningEfforts defines the canonical set of reasoning effort levels.
// This serves as the single source of truth for valid effort values.
var standardReasoningEfforts = []string{"none", "auto", "minimal", "low", "medium", "high", "xhigh"}
// IsValidReasoningEffort checks if the given effort string is a valid reasoning effort level.
// This is a registry-independent check against the standard effort levels.
func IsValidReasoningEffort(effort string) bool {
if effort == "" {
return false
}
lowered := strings.ToLower(strings.TrimSpace(effort))
for _, e := range standardReasoningEfforts {
if e == lowered {
return true
}
}
return false
}
// NormalizeReasoningEffort normalizes a reasoning effort string to its canonical form.
// It first tries registry-based normalization if a model is provided, then falls back
// to the standard effort levels. Returns empty string and false if invalid.
func NormalizeReasoningEffort(model, effort string) (string, bool) {
if effort == "" {
return "", false
}
lowered := strings.ToLower(strings.TrimSpace(effort))
if model != "" {
if normalized, ok := NormalizeReasoningEffortLevel(model, effort); ok {
return normalized, true
}
}
for _, e := range standardReasoningEfforts {
if e == lowered {
return e, true
}
}
return "", false
}

View File

@@ -58,8 +58,9 @@ func NormalizeThinkingModel(modelName string) (string, map[string]any) {
baseModel = modelName[:idx] baseModel = modelName[:idx]
budgetOverride = &parsed budgetOverride = &parsed
matched = true matched = true
} else if effort, okEffort := normalizeReasoningEffort(value); okEffort { } else if IsValidReasoningEffort(value) {
baseModel = modelName[:idx] baseModel = modelName[:idx]
effort := strings.ToLower(strings.TrimSpace(value))
reasoningEffort = &effort reasoningEffort = &effort
matched = true matched = true
} }
@@ -185,7 +186,9 @@ func ReasoningEffortFromMetadata(metadata map[string]any) (string, bool) {
return "", false return "", false
} }
if effort != nil && *effort != "" { if effort != nil && *effort != "" {
return *effort, true if IsValidReasoningEffort(*effort) {
return strings.ToLower(strings.TrimSpace(*effort)), true
}
} }
if budget != nil { if budget != nil {
switch *budget { switch *budget {
@@ -207,7 +210,11 @@ func ThinkingEffortToBudget(model, effort string) (int, bool) {
if effort == "" { if effort == "" {
return 0, false return 0, false
} }
switch strings.ToLower(effort) { normalized, ok := NormalizeReasoningEffort(model, effort)
if !ok {
return 0, false
}
switch normalized {
case "none": case "none":
return 0, true return 0, true
case "auto": case "auto":
@@ -312,16 +319,3 @@ func parseNumberToInt(raw any) (int, bool) {
} }
return 0, false return 0, false
} }
func normalizeReasoningEffort(value string) (string, bool) {
if value == "" {
return "", false
}
effort := strings.ToLower(strings.TrimSpace(value))
switch effort {
case "minimal", "low", "medium", "high", "xhigh", "auto", "none":
return effort, true
default:
return "", false
}
}