From a69e19f751fbfbede314d6fd9d9da256127edf47 Mon Sep 17 00:00:00 2001 From: Sergey Kozyrenko Date: Fri, 26 Jun 2026 02:18:57 +0700 Subject: [PATCH] feat(providers): allow xhigh/max reasoning_effort on the OpenAI-compatible path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-agent options builder only emitted WithReasoning for low/medium/high, and the langchaingo fork clamped xhigh/max to high in GetEffort (treating them as adaptive-only). OpenAI GPT-5.5 and GLM-5.2 now expose xhigh/max as real reasoning_effort levels, so that clamp encodes a stale invariant. Extend the effort switch to pass xhigh/max through; the fork's GetEffort clamp is removed in the local langchaingo (propagated via vendor) so the OpenAI transport emits the real level. Adaptive (anthropic/bedrock) and budget paths are unaffected — GetEffort is called only by the OpenAI transport. Validity is gated per model by ModelReasoningInfo.Efforts. Co-Authored-By: Claude Sonnet 4.6 --- backend/pkg/providers/pconfig/config.go | 2 +- .../pconfig/reasoning_effort_test.go | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 backend/pkg/providers/pconfig/reasoning_effort_test.go diff --git a/backend/pkg/providers/pconfig/config.go b/backend/pkg/providers/pconfig/config.go index ce722c40..ddb27975 100644 --- a/backend/pkg/providers/pconfig/config.go +++ b/backend/pkg/providers/pconfig/config.go @@ -724,7 +724,7 @@ func (ac *AgentConfig) BuildOptions() []llms.CallOption { } default: switch ac.Reasoning.Effort { - case llms.ReasoningLow, llms.ReasoningMedium, llms.ReasoningHigh: + case llms.ReasoningLow, llms.ReasoningMedium, llms.ReasoningHigh, llms.ReasoningXHigh, llms.ReasoningMax: options = append(options, llms.WithReasoning(ac.Reasoning.Effort, 0)) } } diff --git a/backend/pkg/providers/pconfig/reasoning_effort_test.go b/backend/pkg/providers/pconfig/reasoning_effort_test.go new file mode 100644 index 00000000..54157bb2 --- /dev/null +++ b/backend/pkg/providers/pconfig/reasoning_effort_test.go @@ -0,0 +1,37 @@ +package pconfig + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/vxcontrol/langchaingo/llms" + "gopkg.in/yaml.v3" +) + +func TestReasoningConfig_GetEffortPreservesXHighAndMax(t *testing.T) { + for _, effort := range []llms.ReasoningEffort{llms.ReasoningXHigh, llms.ReasoningMax} { + rc := llms.ReasoningConfig{Effort: effort} + if got := rc.GetEffort(8192); got != effort { + t.Errorf("GetEffort(effort=%q) = %q, want %q: the xhigh/max clamp must stay removed so OpenAI-compatible reasoning_effort carries the real level", effort, got, effort) + } + } +} + +func TestProviderConfig_EmitsTopReasoningEffortOnEffortPath(t *testing.T) { + for _, effort := range []string{"low", "medium", "high", "xhigh", "max"} { + t.Run(effort, func(t *testing.T) { + var ac AgentConfig + require.NoError(t, yaml.Unmarshal([]byte("model: gpt-5.5\nreasoning:\n effort: "+effort+"\n"), &ac)) + + pc := &ProviderConfig{Simple: &ac} + var applied llms.CallOptions + for _, opt := range pc.GetOptionsForType(OptionsTypeSimple) { + opt(&applied) + } + + require.NotNil(t, applied.Reasoning, "effort %q must emit a reasoning option on the non-adaptive path", effort) + assert.Equal(t, llms.ReasoningEffort(effort), applied.Reasoning.Effort, "the configured effort must reach the call options unchanged") + }) + } +}