on main help sign in
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).

commit2faa467ab08de94aaa7583836491c6d4f7fabcf8 authorAndrey Nering <andreynering@users.noreply.github.com> dateFri 22 May 2026, 11:04 (5 months ago) parentb9eb082
2 files changed+13−6
internal/agent/coordinator.go+8−5 internal/agent/coordinator_test.go+5−1
internal/agent/coordinator.go+8−5
@@ -283,10 +283,13 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy.
283283 return options
284284 }
285285
286+ shouldSetEffort := model.CatwalkCfg.CanReason &&
287+ slices.Contains(model.CatwalkCfg.ReasoningLevels, model.ModelCfg.ReasoningEffort)
288+
286289 switch providerCfg.Type {
287290 case openai.Name, azure.Name:
288291 _, hasReasoningEffort := mergedOptions["reasoning_effort"]
289− if !hasReasoningEffort && model.ModelCfg.ReasoningEffort != "" && model.CatwalkCfg.CanReason {
292+ if !hasReasoningEffort && shouldSetEffort {
290293 mergedOptions["reasoning_effort"] = model.ModelCfg.ReasoningEffort
291294 }
292295 if openai.IsResponsesModel(model.CatwalkCfg.ID) {
@@ -310,7 +313,7 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy.
310313 _, hasThink = mergedOptions["thinking"]
311314 )
312315 switch {
313− case !hasEffort && model.ModelCfg.ReasoningEffort != "" && model.CatwalkCfg.CanReason:
316+ case !hasEffort && shouldSetEffort:
314317 mergedOptions["effort"] = model.ModelCfg.ReasoningEffort
315318 case !hasThink && model.ModelCfg.Think:
316319 mergedOptions["thinking"] = map[string]any{"budget_tokens": 2000}
@@ -322,7 +325,7 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy.
322325
323326 case openrouter.Name:
324327 _, hasReasoning := mergedOptions["reasoning"]
325− if !hasReasoning && model.ModelCfg.ReasoningEffort != "" {
328+ if !hasReasoning && shouldSetEffort {
326329 mergedOptions["reasoning"] = map[string]any{
327330 "enabled": true,
328331 "effort": model.ModelCfg.ReasoningEffort,
@@ -334,7 +337,7 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy.
334337 }
335338 case vercel.Name:
336339 _, hasReasoning := mergedOptions["reasoning"]
337− if !hasReasoning && model.ModelCfg.ReasoningEffort != "" {
340+ if !hasReasoning && shouldSetEffort {
338341 mergedOptions["reasoning"] = map[string]any{
339342 "enabled": true,
340343 "effort": model.ModelCfg.ReasoningEffort,
@@ -367,7 +370,7 @@ func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy.
367370 extraBody := make(map[string]any)
368371
369372 _, hasReasoningEffort := mergedOptions["reasoning_effort"]
370− if !hasReasoningEffort && model.ModelCfg.ReasoningEffort != "" && model.CatwalkCfg.CanReason {
373+ if !hasReasoningEffort && shouldSetEffort {
371374 switch providerCfg.ID {
372375 case string(catwalk.InferenceProviderIoNet):
373376 extraBody["reasoning"] = map[string]string{"effort": model.ModelCfg.ReasoningEffort}
internal/agent/coordinator_test.go+5−1
@@ -399,7 +399,11 @@ func TestGetProviderOptionsReasoningEffort(t *testing.T) {
399399 for _, tc := range tests {
400400 t.Run(tc.name, func(t *testing.T) {
401401 model := Model{
402− CatwalkCfg: catwalk.Model{ID: "claude-opus-4-7", CanReason: true},
402+ CatwalkCfg: catwalk.Model{
403+ ID: "claude-opus-4-7",
404+ CanReason: true,
405+ ReasoningLevels: []string{"max"},
406+ },
403407 ModelCfg: config.SelectedModel{
404408 Provider: "test",
405409 ReasoningEffort: "max",