@@ -3,7 +3,7 @@ use serde_json::Value;
33use std:: collections:: HashMap ;
44
55pub const DEFAULT_MODEL_TIMEOUT_SECS : u64 = 1_800 ;
6- const OPENAI_THINKING_MODE_EXTRA : & str = "openai_thinking_mode" ;
6+ const THINKING_MODE_EXTRA : & str = "openai_thinking_mode" ;
77
88/// LLM configuration.
99///
@@ -62,41 +62,66 @@ impl Default for Model {
6262}
6363
6464impl Model {
65+ /// Configure an explicit provider thinking mode.
66+ ///
67+ /// The stored key retains its historical spelling for serialized-model
68+ /// compatibility. Request construction applies it only to protocols that
69+ /// support the `thinking.type` extension.
70+ pub fn set_thinking_mode ( & mut self , enabled : bool ) {
71+ self . extra
72+ . insert ( THINKING_MODE_EXTRA . to_string ( ) , Value :: Bool ( enabled) ) ;
73+ }
74+
75+ /// Return an explicitly configured provider thinking mode.
76+ pub fn thinking_mode ( & self ) -> Option < bool > {
77+ self . extra . get ( THINKING_MODE_EXTRA ) . and_then ( Value :: as_bool)
78+ }
79+
6580 /// Configure the OpenAI-compatible `thinking.type` request parameter.
6681 ///
6782 /// This is opt-in so generic OpenAI-compatible providers that do not
6883 /// recognize the extension keep receiving the historical request shape.
6984 pub fn set_openai_thinking_mode ( & mut self , enabled : bool ) {
70- self . extra
71- . insert ( OPENAI_THINKING_MODE_EXTRA . to_string ( ) , Value :: Bool ( enabled) ) ;
85+ self . set_thinking_mode ( enabled) ;
7286 }
7387
7488 /// Return an explicitly configured OpenAI-compatible thinking mode.
7589 pub fn openai_thinking_mode ( & self ) -> Option < bool > {
76- self . extra
77- . get ( OPENAI_THINKING_MODE_EXTRA )
78- . and_then ( Value :: as_bool)
90+ self . thinking_mode ( )
7991 }
8092}
8193
8294#[ cfg( test) ]
8395mod tests {
84- use super :: Model ;
96+ use super :: { Model , Protocol } ;
8597
8698 #[ test]
8799 fn model_default_timeout_allows_thirty_minute_requests ( ) {
88100 assert_eq ! ( Model :: default ( ) . timeout, 1_800 ) ;
89101 }
102+
103+ #[ test]
104+ fn deepseek_protocol_round_trips_through_serde ( ) {
105+ let serialized = serde_json:: to_string ( & Protocol :: DeepSeek ) . expect ( "serializes" ) ;
106+ assert_eq ! ( serialized, "\" deepseek\" " ) ;
107+ assert_eq ! (
108+ serde_json:: from_str:: <Protocol >( & serialized) . expect( "deserializes" ) ,
109+ Protocol :: DeepSeek
110+ ) ;
111+ }
90112}
91113
92114/// Wire protocol.
93115///
94- /// Three protocols are supported. Most providers are OpenAI-compatible;
95- /// use the `OpenAI` variant with a custom `endpoint`.
116+ /// Four protocols are supported. Most providers are OpenAI-compatible;
117+ /// use the `OpenAI` variant with a custom `endpoint`. DeepSeek has an
118+ /// explicit variant because its assistant-message schema differs at the
119+ /// thinking/tool-history boundary.
96120///
97121/// | Protocol | Examples |
98122/// |----------|---------|
99- /// | `OpenAI` | OpenAI, DeepSeek, Groq, Mistral, xAI, Ollama, OpenRouter ... |
123+ /// | `OpenAI` | OpenAI, Groq, Mistral, xAI, Ollama, OpenRouter ... |
124+ /// | `DeepSeek` | DeepSeek Chat Completions API |
100125/// | `Anthropic` | Anthropic Claude |
101126/// | `Gemini` | Google Gemini |
102127#[ derive( Debug , Clone , Copy , Default , PartialEq , Eq , Serialize , Deserialize ) ]
@@ -105,6 +130,8 @@ pub enum Protocol {
105130 /// OpenAI Chat Completions API.
106131 #[ default]
107132 OpenAI ,
133+ /// DeepSeek Chat Completions API.
134+ DeepSeek ,
108135 /// Anthropic Messages API.
109136 Anthropic ,
110137 /// Google Gemini API.
0 commit comments