From 2faa467ab08de94aaa7583836491c6d4f7fabcf8 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 22 May 2026 11:04:52 -0300 Subject: [PATCH] fix: fix sometimes sending reasoning effort when it shouldn't (#2982) For some reason, I sometimes see a reasoning effort set on `model.ModelCfg.ReasoningEffort` (like "high") when the model doesn't supports it. This may being set by a previous select model and not properly cleared. We should check if the model supports reasoning effort levels before setting it. Otherwise, we should set only `thinking` (if supported). --- internal/agent/coordinator.go | 13 ++++++++----- internal/agent/coordinator_test.go | 6 +++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/internal/agent/coordinator.go b/internal/agent/coordinator.go index 145665eee8d3bca81d054e8796d3ab80f4d85dd9..39332b60710cb2cb433dca2132acffbb89fa3441 100644 --- a/internal/agent/coordinator.go +++ b/internal/agent/coordinator.go @@ -283,10 +283,13 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy. return options } + shouldSetEffort := model.CatwalkCfg.CanReason && + slices.Contains(model.CatwalkCfg.ReasoningLevels, model.ModelCfg.ReasoningEffort) + switch providerCfg.Type { case openai.Name, azure.Name: _, hasReasoningEffort := mergedOptions["reasoning_effort"] - if !hasReasoningEffort && model.ModelCfg.ReasoningEffort != "" && model.CatwalkCfg.CanReason { + if !hasReasoningEffort && shouldSetEffort { mergedOptions["reasoning_effort"] = model.ModelCfg.ReasoningEffort } if openai.IsResponsesModel(model.CatwalkCfg.ID) { @@ -310,7 +313,7 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy. _, hasThink = mergedOptions["thinking"] ) switch { - case !hasEffort && model.ModelCfg.ReasoningEffort != "" && model.CatwalkCfg.CanReason: + case !hasEffort && shouldSetEffort: mergedOptions["effort"] = model.ModelCfg.ReasoningEffort case !hasThink && model.ModelCfg.Think: mergedOptions["thinking"] = map[string]any{"budget_tokens": 2000} @@ -322,7 +325,7 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy. case openrouter.Name: _, hasReasoning := mergedOptions["reasoning"] - if !hasReasoning && model.ModelCfg.ReasoningEffort != "" { + if !hasReasoning && shouldSetEffort { mergedOptions["reasoning"] = map[string]any{ "enabled": true, "effort": model.ModelCfg.ReasoningEffort, @@ -334,7 +337,7 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy. } case vercel.Name: _, hasReasoning := mergedOptions["reasoning"] - if !hasReasoning && model.ModelCfg.ReasoningEffort != "" { + if !hasReasoning && shouldSetEffort { mergedOptions["reasoning"] = map[string]any{ "enabled": true, "effort": model.ModelCfg.ReasoningEffort, @@ -367,7 +370,7 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy. extraBody := make(map[string]any) _, hasReasoningEffort := mergedOptions["reasoning_effort"] - if !hasReasoningEffort && model.ModelCfg.ReasoningEffort != "" && model.CatwalkCfg.CanReason { + if !hasReasoningEffort && shouldSetEffort { switch providerCfg.ID { case string(catwalk.InferenceProviderIoNet): extraBody["reasoning"] = map[string]string{"effort": model.ModelCfg.ReasoningEffort} diff --git a/internal/agent/coordinator_test.go b/internal/agent/coordinator_test.go index c1d5ede005e4d3f69cf9482c38d99c2ca8565d98..da0ddd0db2bf77c3c1e3eb6463549875a989a4ca 100644 --- a/internal/agent/coordinator_test.go +++ b/internal/agent/coordinator_test.go @@ -399,7 +399,11 @@ func TestGetProviderOptionsReasoningEffort(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { model := Model{ - CatwalkCfg: catwalk.Model{ID: "claude-opus-4-7", CanReason: true}, + CatwalkCfg: catwalk.Model{ + ID: "claude-opus-4-7", + CanReason: true, + ReasoningLevels: []string{"max"}, + }, ModelCfg: config.SelectedModel{ Provider: "test", ReasoningEffort: "max",