feat(thinking): normalize effort levels in adaptive thinking requests to prevent validation errors

This commit is contained in:
hkfires
2026-03-03 15:10:47 +08:00
parent 0452b869e8
commit ce87714ef1
7 changed files with 40 additions and 39 deletions
@@ -120,6 +120,8 @@ func ConvertGeminiRequestToClaude(modelName string, inputRawJSON []byte, stream
supportsAdaptive := mi != nil && mi.Thinking != nil && len(mi.Thinking.Levels) > 0
supportsMax := supportsAdaptive && thinking.HasLevel(mi.Thinking.Levels, string(thinking.LevelMax))
// MapToClaudeEffort normalizes levels (e.g. minimal→low, xhigh→high) to avoid
// validation errors since validate treats same-provider unsupported levels as errors.
thinkingLevel := thinkingConfig.Get("thinkingLevel")
if !thinkingLevel.Exists() {
thinkingLevel = thinkingConfig.Get("thinking_level")
@@ -134,12 +136,12 @@ func ConvertGeminiRequestToClaude(modelName string, inputRawJSON []byte, stream
out, _ = sjson.Delete(out, "thinking.budget_tokens")
out, _ = sjson.Delete(out, "output_config.effort")
default:
effort, ok := thinking.MapToClaudeEffort(level, supportsMax)
if ok {
out, _ = sjson.Set(out, "thinking.type", "adaptive")
out, _ = sjson.Delete(out, "thinking.budget_tokens")
out, _ = sjson.Set(out, "output_config.effort", effort)
if mapped, ok := thinking.MapToClaudeEffort(level, supportsMax); ok {
level = mapped
}
out, _ = sjson.Set(out, "thinking.type", "adaptive")
out, _ = sjson.Delete(out, "thinking.budget_tokens")
out, _ = sjson.Set(out, "output_config.effort", level)
}
} else {
switch level {
@@ -173,12 +175,12 @@ func ConvertGeminiRequestToClaude(modelName string, inputRawJSON []byte, stream
default:
level, ok := thinking.ConvertBudgetToLevel(budget)
if ok {
effort, ok := thinking.MapToClaudeEffort(level, supportsMax)
if ok {
out, _ = sjson.Set(out, "thinking.type", "adaptive")
out, _ = sjson.Delete(out, "thinking.budget_tokens")
out, _ = sjson.Set(out, "output_config.effort", effort)
if mapped, okM := thinking.MapToClaudeEffort(level, supportsMax); okM {
level = mapped
}
out, _ = sjson.Set(out, "thinking.type", "adaptive")
out, _ = sjson.Delete(out, "thinking.budget_tokens")
out, _ = sjson.Set(out, "output_config.effort", level)
}
}
} else {
@@ -74,6 +74,8 @@ func ConvertOpenAIRequestToClaude(modelName string, inputRawJSON []byte, stream
supportsMax := supportsAdaptive && thinking.HasLevel(mi.Thinking.Levels, string(thinking.LevelMax))
// Claude 4.6 supports adaptive thinking with output_config.effort.
// MapToClaudeEffort normalizes levels (e.g. minimal→low, xhigh→high) to avoid
// validation errors since validate treats same-provider unsupported levels as errors.
if supportsAdaptive {
switch effort {
case "none":
@@ -85,7 +87,6 @@ func ConvertOpenAIRequestToClaude(modelName string, inputRawJSON []byte, stream
out, _ = sjson.Delete(out, "thinking.budget_tokens")
out, _ = sjson.Delete(out, "output_config.effort")
default:
// Map non-Claude effort levels into Claude 4.6 effort vocabulary.
if mapped, ok := thinking.MapToClaudeEffort(effort, supportsMax); ok {
effort = mapped
}
@@ -62,6 +62,8 @@ func ConvertOpenAIResponsesRequestToClaude(modelName string, inputRawJSON []byte
supportsMax := supportsAdaptive && thinking.HasLevel(mi.Thinking.Levels, string(thinking.LevelMax))
// Claude 4.6 supports adaptive thinking with output_config.effort.
// MapToClaudeEffort normalizes levels (e.g. minimal→low, xhigh→high) to avoid
// validation errors since validate treats same-provider unsupported levels as errors.
if supportsAdaptive {
switch effort {
case "none":
@@ -73,7 +75,6 @@ func ConvertOpenAIResponsesRequestToClaude(modelName string, inputRawJSON []byte
out, _ = sjson.Delete(out, "thinking.budget_tokens")
out, _ = sjson.Delete(out, "output_config.effort")
default:
// Map non-Claude effort levels into Claude 4.6 effort vocabulary.
if mapped, ok := thinking.MapToClaudeEffort(effort, supportsMax); ok {
effort = mapped
}