Skip to main content

sac/model/
types.rs

1use super::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum)]
4#[serde(rename_all = "kebab-case")]
5#[value(rename_all = "kebab-case")]
6pub enum BackendKind {
7    Auto,
8    #[serde(rename = "deepseek-chat")]
9    #[value(name = "deepseek-chat")]
10    DeepSeekChat,
11    FireworksChat,
12    #[serde(rename = "openai-responses")]
13    #[value(name = "openai-responses")]
14    OpenAiResponses,
15    #[serde(rename = "chatgpt-codex-responses")]
16    #[value(name = "chatgpt-codex-responses")]
17    ChatGptCodexResponses,
18}
19
20impl BackendKind {
21    pub fn as_str(self) -> &'static str {
22        match self {
23            Self::Auto => "auto",
24            Self::DeepSeekChat => "deepseek-chat",
25            Self::FireworksChat => "fireworks-chat",
26            Self::OpenAiResponses => "openai-responses",
27            Self::ChatGptCodexResponses => "chatgpt-codex-responses",
28        }
29    }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub enum ReasoningEffort {
34    None,
35    Minimal,
36    Low,
37    Medium,
38    High,
39    Xhigh,
40    /// A model-defined effort value that this client does not know yet.
41    Custom(String),
42}
43
44impl ReasoningEffort {
45    pub fn as_str(&self) -> &str {
46        match self {
47            Self::None => "none",
48            Self::Minimal => "minimal",
49            Self::Low => "low",
50            Self::Medium => "medium",
51            Self::High => "high",
52            Self::Xhigh => "xhigh",
53            Self::Custom(s) => s.as_str(),
54        }
55    }
56}
57
58impl std::fmt::Display for ReasoningEffort {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        f.write_str(self.as_str())
61    }
62}
63
64impl std::str::FromStr for ReasoningEffort {
65    type Err = String;
66    fn from_str(s: &str) -> Result<Self, Self::Err> {
67        match s {
68            "none" => Ok(Self::None),
69            "minimal" => Ok(Self::Minimal),
70            "low" => Ok(Self::Low),
71            "medium" => Ok(Self::Medium),
72            "high" => Ok(Self::High),
73            "xhigh" => Ok(Self::Xhigh),
74            "" => Err("reasoning effort must not be empty".to_string()),
75            other => Ok(Self::Custom(other.to_string())),
76        }
77    }
78}
79
80impl serde::Serialize for ReasoningEffort {
81    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
82        serializer.serialize_str(self.as_str())
83    }
84}
85
86impl<'de> serde::Deserialize<'de> for ReasoningEffort {
87    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
88        let s = String::deserialize(deserializer)?;
89        s.parse().map_err(serde::de::Error::custom)
90    }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
94#[serde(rename_all = "lowercase")]
95pub enum ReasoningSummary {
96    Auto,
97    Concise,
98    Detailed,
99}
100
101impl ReasoningSummary {
102    pub fn as_str(&self) -> &str {
103        match self {
104            Self::Auto => "auto",
105            Self::Concise => "concise",
106            Self::Detailed => "detailed",
107        }
108    }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
112#[serde(rename_all = "snake_case")]
113pub enum ReasoningContext {
114    CurrentTurn,
115    AllTurns,
116}
117
118impl ReasoningContext {
119    pub fn as_str(&self) -> &str {
120        match self {
121            Self::CurrentTurn => "current_turn",
122            Self::AllTurns => "all_turns",
123        }
124    }
125}
126
127#[derive(Debug, Clone, Default)]
128pub struct ClientOverrides {
129    pub base_url: Option<String>,
130    pub model: Option<String>,
131    pub backend: Option<BackendKind>,
132    pub reasoning_effort: Option<ReasoningEffort>,
133    pub reasoning_summary: Option<ReasoningSummary>,
134    pub reasoning_context: Option<ReasoningContext>,
135    pub api_key_env: Option<String>,
136    pub api_key: Option<String>,
137}
138
139pub struct TextCompletion {
140    pub content: String,
141    pub usage: Usage,
142}
143
144#[derive(Debug, Clone)]
145pub struct AssistantTurn {
146    pub content: Option<String>,
147    pub reasoning_text: Option<String>,
148    pub reasoning_details: Option<Value>,
149    pub tool_calls: Option<Vec<ToolCall>>,
150}
151
152#[derive(Debug, Clone)]
153pub struct ModelTurnResponse {
154    pub assistant: AssistantTurn,
155    pub finish_reason: Option<String>,
156    pub usage: Usage,
157}