11package pconfig
22
33import (
4+ "context"
45 "encoding/json"
56 "os"
67 "path/filepath"
@@ -13,6 +14,89 @@ import (
1314 "gopkg.in/yaml.v3"
1415)
1516
17+ func TestProviderConfig_UsesAdaptiveThinking (t * testing.T ) {
18+ adaptiveOnly := ModelsConfig {{Name : "opus-4-8" , Reasoning : & ModelReasoningInfo {Mode : ModelReasoningAdaptiveOnly }}}
19+ adaptiveCapable := ModelsConfig {{Name : "opus-4-6" , Reasoning : & ModelReasoningInfo {Mode : ModelReasoningAdaptive }}}
20+ budgetOnly := ModelsConfig {{Name : "sonnet-4-5" , Reasoning : & ModelReasoningInfo {Mode : ModelReasoningBudget }}}
21+
22+ tests := []struct {
23+ name string
24+ models ModelsConfig
25+ agent * AgentConfig
26+ want bool
27+ }{
28+ {"adaptive-only model forces adaptive with no agent reasoning" ,
29+ adaptiveOnly , & AgentConfig {Model : "opus-4-8" }, true },
30+ {"adaptive-only model overrides an agent budget choice" ,
31+ adaptiveOnly , & AgentConfig {Model : "opus-4-8" , Reasoning : ReasoningConfig {Mode : ReasoningModeBudget , MaxTokens : 4096 }}, true },
32+ {"agent selects adaptive on an adaptive-capable model" ,
33+ adaptiveCapable , & AgentConfig {Model : "opus-4-6" , Reasoning : ReasoningConfig {Mode : ReasoningModeAdaptive }}, true },
34+ {"agent selects budget on an adaptive-capable model" ,
35+ adaptiveCapable , & AgentConfig {Model : "opus-4-6" , Reasoning : ReasoningConfig {Mode : ReasoningModeBudget , MaxTokens : 4096 }}, false },
36+ {"budget-only model with a budget agent" ,
37+ budgetOnly , & AgentConfig {Model : "sonnet-4-5" , Reasoning : ReasoningConfig {Mode : ReasoningModeBudget , MaxTokens : 4096 }}, false },
38+ {"no reasoning anywhere" ,
39+ budgetOnly , & AgentConfig {Model : "sonnet-4-5" }, false },
40+ }
41+ for _ , tt := range tests {
42+ t .Run (tt .name , func (t * testing.T ) {
43+ pc := & ProviderConfig {Simple : tt .agent }
44+ assert .Equal (t , tt .want , pc .UsesAdaptiveThinking (tt .models , OptionsTypeSimple ))
45+ })
46+ }
47+ }
48+
49+ func TestProviderConfig_PrepareAdaptiveCallOptions (t * testing.T ) {
50+ adaptiveOnly := ModelsConfig {{Name : "opus-4-8" , Reasoning : & ModelReasoningInfo {Mode : ModelReasoningAdaptiveOnly }}}
51+
52+ // adaptiveReasoning applies the returned options to a CallOptions and reports
53+ // the reasoning the provider would emit (nil if no adaptive option was added).
54+ adaptiveReasoning := func (options []llms.CallOption ) * llms.ReasoningConfig {
55+ var co llms.CallOptions
56+ for _ , o := range options {
57+ o (& co )
58+ }
59+ return co .Reasoning
60+ }
61+
62+ t .Run ("overrides an agent budget choice on an adaptive-only model" , func (t * testing.T ) {
63+ pc := & ProviderConfig {Simple : & AgentConfig {
64+ Model : "opus-4-8" ,
65+ Reasoning : ReasoningConfig {Mode : ReasoningModeBudget , Effort : llms .ReasoningHigh , MaxTokens : 4096 },
66+ }}
67+ _ , options := pc .PrepareAdaptiveCallOptions (context .Background (), adaptiveOnly , OptionsTypeSimple , nil )
68+ require .Len (t , options , 1 , "the adaptive call option must be appended" )
69+
70+ r := adaptiveReasoning (options )
71+ require .NotNil (t , r )
72+ assert .True (t , r .Adaptive , "a budget choice must be overridden to adaptive for an adaptive-only model" )
73+ assert .Equal (t , llms .ReasoningHigh , r .Effort )
74+ })
75+
76+ t .Run ("forces adaptive on an adaptive-only model with no agent reasoning block" , func (t * testing.T ) {
77+ pc := & ProviderConfig {Simple : & AgentConfig {Model : "opus-4-8" }}
78+ _ , options := pc .PrepareAdaptiveCallOptions (context .Background (), adaptiveOnly , OptionsTypeSimple , nil )
79+ require .Len (t , options , 1 )
80+
81+ r := adaptiveReasoning (options )
82+ require .NotNil (t , r )
83+ assert .True (t , r .Adaptive )
84+ assert .Equal (t , llms .ReasoningNone , r .Effort , "empty effort is left for the provider to default to high" )
85+ })
86+
87+ t .Run ("no-op for a budget-only model, preserving existing options" , func (t * testing.T ) {
88+ budgetOnly := ModelsConfig {{Name : "sonnet-4-5" , Reasoning : & ModelReasoningInfo {Mode : ModelReasoningBudget }}}
89+ pc := & ProviderConfig {Simple : & AgentConfig {
90+ Model : "sonnet-4-5" ,
91+ Reasoning : ReasoningConfig {Mode : ReasoningModeBudget , MaxTokens : 4096 },
92+ }}
93+ existing := []llms.CallOption {llms .WithTemperature (1 )}
94+ _ , options := pc .PrepareAdaptiveCallOptions (context .Background (), budgetOnly , OptionsTypeSimple , existing )
95+ require .Len (t , options , 1 , "a non-adaptive call must not append the adaptive option" )
96+ assert .Nil (t , adaptiveReasoning (options ), "no adaptive reasoning option should be present" )
97+ })
98+ }
99+
16100func TestReasoningConfig_UnmarshalJSON (t * testing.T ) {
17101 tests := []struct {
18102 name string
0 commit comments