@@ -15,6 +15,35 @@ pub enum ToolChoiceType {
1515 ToolChoice { tool : Tool } ,
1616}
1717
18+ #[ derive( Debug , Serialize , Deserialize , Clone , PartialEq , Eq ) ]
19+ #[ serde( rename_all = "lowercase" ) ]
20+ pub enum ReasoningEffort {
21+ Low ,
22+ Medium ,
23+ High ,
24+ }
25+
26+ #[ derive( Debug , Serialize , Deserialize , Clone ) ]
27+ #[ serde( untagged) ]
28+ pub enum ReasoningMode {
29+ Effort {
30+ effort : ReasoningEffort ,
31+ } ,
32+ MaxTokens {
33+ max_tokens : i64 ,
34+ } ,
35+ }
36+
37+ #[ derive( Debug , Serialize , Deserialize , Clone ) ]
38+ pub struct Reasoning {
39+ #[ serde( flatten) ]
40+ pub mode : Option < ReasoningMode > ,
41+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
42+ pub exclude : Option < bool > ,
43+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
44+ pub enabled : Option < bool > ,
45+ }
46+
1847#[ derive( Debug , Serialize , Deserialize , Clone ) ]
1948pub struct ChatCompletionRequest {
2049 pub model : String ,
@@ -50,6 +79,8 @@ pub struct ChatCompletionRequest {
5079 #[ serde( skip_serializing_if = "Option::is_none" ) ]
5180 #[ serde( serialize_with = "serialize_tool_choice" ) ]
5281 pub tool_choice : Option < ToolChoiceType > ,
82+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
83+ pub reasoning : Option < Reasoning > ,
5384}
5485
5586impl ChatCompletionRequest {
@@ -72,6 +103,7 @@ impl ChatCompletionRequest {
72103 tools : None ,
73104 parallel_tool_calls : None ,
74105 tool_choice : None ,
106+ reasoning : None ,
75107 }
76108 }
77109}
@@ -92,7 +124,8 @@ impl_builder_methods!(
92124 seed: i64 ,
93125 tools: Vec <Tool >,
94126 parallel_tool_calls: bool ,
95- tool_choice: ToolChoiceType
127+ tool_choice: ToolChoiceType ,
128+ reasoning: Reasoning
96129) ;
97130
98131#[ derive( Debug , Deserialize , Serialize , Clone , PartialEq , Eq ) ]
@@ -318,3 +351,80 @@ pub struct Tool {
318351pub enum ToolType {
319352 Function ,
320353}
354+
355+ #[ cfg( test) ]
356+ mod tests {
357+ use super :: * ;
358+ use serde_json:: json;
359+
360+ #[ test]
361+ fn test_reasoning_effort_serialization ( ) {
362+ let reasoning = Reasoning {
363+ mode : Some ( ReasoningMode :: Effort {
364+ effort : ReasoningEffort :: High ,
365+ } ) ,
366+ exclude : Some ( false ) ,
367+ enabled : None ,
368+ } ;
369+
370+ let serialized = serde_json:: to_value ( & reasoning) . unwrap ( ) ;
371+ let expected = json ! ( {
372+ "effort" : "high" ,
373+ "exclude" : false
374+ } ) ;
375+
376+ assert_eq ! ( serialized, expected) ;
377+ }
378+
379+ #[ test]
380+ fn test_reasoning_max_tokens_serialization ( ) {
381+ let reasoning = Reasoning {
382+ mode : Some ( ReasoningMode :: MaxTokens {
383+ max_tokens : 2000 ,
384+ } ) ,
385+ exclude : None ,
386+ enabled : Some ( true ) ,
387+ } ;
388+
389+ let serialized = serde_json:: to_value ( & reasoning) . unwrap ( ) ;
390+ let expected = json ! ( {
391+ "max_tokens" : 2000 ,
392+ "enabled" : true
393+ } ) ;
394+
395+ assert_eq ! ( serialized, expected) ;
396+ }
397+
398+ #[ test]
399+ fn test_reasoning_deserialization ( ) {
400+ let json_str = r#"{"effort": "medium", "exclude": true}"# ;
401+ let reasoning: Reasoning = serde_json:: from_str ( json_str) . unwrap ( ) ;
402+
403+ match reasoning. mode {
404+ Some ( ReasoningMode :: Effort { effort } ) => {
405+ assert_eq ! ( effort, ReasoningEffort :: Medium ) ;
406+ }
407+ _ => panic ! ( "Expected effort mode" ) ,
408+ }
409+ assert_eq ! ( reasoning. exclude, Some ( true ) ) ;
410+ }
411+
412+ #[ test]
413+ fn test_chat_completion_request_with_reasoning ( ) {
414+ let mut req = ChatCompletionRequest :: new (
415+ "gpt-4" . to_string ( ) ,
416+ vec ! [ ] ,
417+ ) ;
418+
419+ req. reasoning = Some ( Reasoning {
420+ mode : Some ( ReasoningMode :: Effort {
421+ effort : ReasoningEffort :: Low ,
422+ } ) ,
423+ exclude : None ,
424+ enabled : None ,
425+ } ) ;
426+
427+ let serialized = serde_json:: to_value ( & req) . unwrap ( ) ;
428+ assert_eq ! ( serialized[ "reasoning" ] [ "effort" ] , "low" ) ;
429+ }
430+ }
0 commit comments