@@ -179,6 +179,106 @@ func TestDoGenerate_DefaultMaxTokens_ThinkingBudgetReserveAnswerBudget(t *testin
179179 }
180180}
181181
182+ func TestDoGenerate_ReasoningEffort_OutputConfig (t * testing.T ) {
183+ srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
184+ var body struct {
185+ MaxTokens int `json:"max_tokens"`
186+ Thinking * struct {
187+ Type string `json:"type"`
188+ } `json:"thinking"`
189+ OutputConfig * struct {
190+ Effort string `json:"effort"`
191+ } `json:"output_config"`
192+ }
193+ if err := json .NewDecoder (r .Body ).Decode (& body ); err != nil {
194+ t .Fatalf ("decode request: %v" , err )
195+ }
196+ if body .OutputConfig == nil || body .OutputConfig .Effort != "high" {
197+ t .Fatalf ("output_config.effort: got %+v, want high" , body .OutputConfig )
198+ }
199+ if body .Thinking != nil {
200+ t .Fatalf ("thinking should be absent without WithThinking, got %+v" , body .Thinking )
201+ }
202+ if body .MaxTokens != 32000 {
203+ t .Fatalf ("max_tokens: got %d, want 32000 (reasoning default)" , body .MaxTokens )
204+ }
205+ w .Header ().Set ("Content-Type" , "application/json" )
206+ json .NewEncoder (w ).Encode (map [string ]any {
207+ "id" : "msg_effort" , "type" : "message" , "model" : "claude-opus-4-8" , "role" : "assistant" ,
208+ "content" : []map [string ]any {{"type" : "text" , "text" : "OK" }},
209+ "stop_reason" : "end_turn" ,
210+ "usage" : map [string ]any {"input_tokens" : 5 , "output_tokens" : 2 },
211+ })
212+ }))
213+ defer srv .Close ()
214+
215+ p := messages .New (messages .WithAPIKey ("test-key" ), messages .WithBaseURL (srv .URL ))
216+ effort := "high"
217+ result , err := p .DoGenerate (context .Background (), sdk.GenerateParams {
218+ Model : & sdk.Model {ID : "claude-opus-4-8" },
219+ Messages : []sdk.Message {sdk .UserMessage ("Hi" )},
220+ ReasoningEffort : & effort ,
221+ })
222+ if err != nil {
223+ t .Fatalf ("DoGenerate failed: %v" , err )
224+ }
225+ if result .Text != "OK" {
226+ t .Errorf ("text: got %q" , result .Text )
227+ }
228+ }
229+
230+ func TestDoGenerate_AdaptiveThinking_EffortNoBudget (t * testing.T ) {
231+ srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
232+ var body struct {
233+ MaxTokens int `json:"max_tokens"`
234+ Thinking struct {
235+ Type string `json:"type"`
236+ BudgetTokens int `json:"budget_tokens"`
237+ } `json:"thinking"`
238+ OutputConfig struct {
239+ Effort string `json:"effort"`
240+ } `json:"output_config"`
241+ }
242+ if err := json .NewDecoder (r .Body ).Decode (& body ); err != nil {
243+ t .Fatalf ("decode request: %v" , err )
244+ }
245+ if body .Thinking .Type != "adaptive" {
246+ t .Fatalf ("thinking.type: got %q, want adaptive" , body .Thinking .Type )
247+ }
248+ if body .Thinking .BudgetTokens != 0 {
249+ t .Fatalf ("budget_tokens must be omitted for adaptive, got %d" , body .Thinking .BudgetTokens )
250+ }
251+ if body .OutputConfig .Effort != "xhigh" {
252+ t .Fatalf ("output_config.effort: got %q, want xhigh" , body .OutputConfig .Effort )
253+ }
254+ if body .MaxTokens != 32000 {
255+ t .Fatalf ("max_tokens: got %d, want 32000 (reasoning default)" , body .MaxTokens )
256+ }
257+ w .Header ().Set ("Content-Type" , "application/json" )
258+ json .NewEncoder (w ).Encode (map [string ]any {
259+ "id" : "msg_adaptive" , "type" : "message" , "model" : "claude-opus-4-8" , "role" : "assistant" ,
260+ "content" : []map [string ]any {{"type" : "text" , "text" : "OK" }},
261+ "stop_reason" : "end_turn" ,
262+ "usage" : map [string ]any {"input_tokens" : 5 , "output_tokens" : 2 },
263+ })
264+ }))
265+ defer srv .Close ()
266+
267+ p := messages .New (
268+ messages .WithAPIKey ("test-key" ),
269+ messages .WithBaseURL (srv .URL ),
270+ messages .WithThinking (messages.ThinkingConfig {Type : "adaptive" }),
271+ )
272+ effort := "xhigh"
273+ if _ , err := p .DoGenerate (context .Background (), sdk.GenerateParams {
274+ Model : & sdk.Model {ID : "claude-opus-4-8" },
275+ Messages : []sdk.Message {sdk .UserMessage ("Hi" )},
276+ ReasoningEffort : & effort ,
277+ }); err != nil {
278+ t .Fatalf ("DoGenerate failed: %v" , err )
279+ }
280+ }
281+
182282func TestDoGenerate_SystemMessage (t * testing.T ) {
183283 srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
184284 var body struct {
@@ -1068,7 +1168,7 @@ func TestDoGenerate_CacheControl_Tools(t *testing.T) {
10681168
10691169 p := messages .New (messages .WithAPIKey ("k" ), messages .WithBaseURL (srv .URL ))
10701170 _ , err := p .DoGenerate (context .Background (), sdk.GenerateParams {
1071- Model : & sdk.Model {ID : "claude-sonnet-4-20250514" },
1171+ Model : & sdk.Model {ID : "claude-sonnet-4-20250514" },
10721172 Messages : []sdk.Message {sdk .UserMessage ("Hi" )},
10731173 Tools : []sdk.Tool {
10741174 {Name : "search" , Description : "Search the web" , Parameters : map [string ]any {"type" : "object" }},
@@ -1093,10 +1193,10 @@ func TestDoGenerate_CacheControl_DetailedUsage(t *testing.T) {
10931193 "content" : []map [string ]any {{"type" : "text" , "text" : "OK" }},
10941194 "stop_reason" : "end_turn" ,
10951195 "usage" : map [string ]any {
1096- "input_tokens" : 10 ,
1097- "output_tokens" : 5 ,
1098- "cache_creation_input_tokens" : 556 ,
1099- "cache_read_input_tokens" : 200 ,
1196+ "input_tokens" : 10 ,
1197+ "output_tokens" : 5 ,
1198+ "cache_creation_input_tokens" : 556 ,
1199+ "cache_read_input_tokens" : 200 ,
11001200 "cache_creation" : map [string ]any {
11011201 "ephemeral_5m_input_tokens" : 456 ,
11021202 "ephemeral_1h_input_tokens" : 100 ,
0 commit comments