Skip to main content

ds_api/raw/request/
model.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2
3/// The model to use for a chat completion request.
4///
5/// Use [`Model::DeepseekChat`] or [`Model::DeepseekReasoner`] for the standard
6/// DeepSeek models, or [`Model::Custom`] to pass any model string directly —
7/// useful for OpenAI-compatible providers or future DeepSeek models that have
8/// not yet been added as named variants.
9///
10/// # Examples
11///
12/// ```
13/// use ds_api::raw::Model;
14///
15/// let m = Model::DeepseekChat;
16/// let m = Model::Custom("gpt-4o".to_string());
17/// ```
18#[derive(Debug, Default, Clone, PartialEq, Eq)]
19pub enum Model {
20    /// `deepseek-chat` — fast, general-purpose DeepSeek model.
21    #[default]
22    DeepseekChat,
23    /// `deepseek-reasoner` — DeepSeek model optimised for deep reasoning.
24    DeepseekReasoner,
25    /// Any other model identifier, passed through as-is.
26    Custom(String),
27}
28
29impl Model {
30    /// Return the model identifier string as it will appear in the API request.
31    pub fn as_str(&self) -> &str {
32        match self {
33            Model::DeepseekChat => "deepseek-chat",
34            Model::DeepseekReasoner => "deepseek-reasoner",
35            Model::Custom(s) => s.as_str(),
36        }
37    }
38}
39
40impl Serialize for Model {
41    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
42        serializer.serialize_str(self.as_str())
43    }
44}
45
46impl<'de> Deserialize<'de> for Model {
47    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
48        let s = String::deserialize(deserializer)?;
49        Ok(match s.as_str() {
50            "deepseek-chat" => Model::DeepseekChat,
51            "deepseek-reasoner" => Model::DeepseekReasoner,
52            other => Model::Custom(other.to_string()),
53        })
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn serialize_deepseek_chat() {
63        let json = serde_json::to_string(&Model::DeepseekChat).unwrap();
64        assert_eq!(json, r#""deepseek-chat""#);
65    }
66
67    #[test]
68    fn serialize_deepseek_reasoner() {
69        let json = serde_json::to_string(&Model::DeepseekReasoner).unwrap();
70        assert_eq!(json, r#""deepseek-reasoner""#);
71    }
72
73    #[test]
74    fn serialize_custom() {
75        let json = serde_json::to_string(&Model::Custom("gpt-4o".to_string())).unwrap();
76        assert_eq!(json, r#""gpt-4o""#);
77    }
78
79    #[test]
80    fn deserialize_known_variants() {
81        let m: Model = serde_json::from_str(r#""deepseek-chat""#).unwrap();
82        assert_eq!(m, Model::DeepseekChat);
83
84        let m: Model = serde_json::from_str(r#""deepseek-reasoner""#).unwrap();
85        assert_eq!(m, Model::DeepseekReasoner);
86    }
87
88    #[test]
89    fn deserialize_unknown_becomes_custom() {
90        let m: Model = serde_json::from_str(r#""gpt-4o""#).unwrap();
91        assert_eq!(m, Model::Custom("gpt-4o".to_string()));
92    }
93
94    #[test]
95    fn default_is_deepseek_chat() {
96        assert_eq!(Model::default(), Model::DeepseekChat);
97    }
98
99    #[test]
100    fn as_str_roundtrips() {
101        assert_eq!(Model::DeepseekChat.as_str(), "deepseek-chat");
102        assert_eq!(Model::DeepseekReasoner.as_str(), "deepseek-reasoner");
103        assert_eq!(Model::Custom("o3".to_string()).as_str(), "o3");
104    }
105}