ort_openrouter_cli/common/
data.rs1use core::fmt;
8use core::str::FromStr;
9
10extern crate alloc;
11use alloc::string::{String, ToString};
12use alloc::vec;
13use alloc::vec::Vec;
14
15const DEFAULT_SHOW_REASONING: bool = false;
16const DEFAULT_QUIET: bool = false;
17pub const DEFAULT_MODEL: &str = "google/gemma-3n-e4b-it:free";
18
19pub struct ChatCompletionsResponse {
46 pub provider: Option<String>,
47 pub model: Option<String>,
48 pub choices: Vec<Choice>,
49 pub usage: Option<Usage>,
50}
51
52pub struct Choice {
53 pub delta: Message,
54}
55
56pub struct Usage {
57 pub cost: f32, }
59
60pub struct LastData {
61 pub opts: PromptOpts,
62 pub messages: Vec<Message>,
63}
64
65#[derive(Clone)]
66pub struct PromptOpts {
67 pub prompt: Option<String>,
68 pub models: Vec<String>,
70 pub provider: Option<String>,
72 pub system: Option<String>,
74 pub priority: Option<Priority>,
76 pub reasoning: Option<ReasoningConfig>,
78 pub show_reasoning: Option<bool>,
80 pub quiet: Option<bool>,
82 pub merge_config: bool,
84}
85
86impl Default for PromptOpts {
87 fn default() -> Self {
88 Self {
89 prompt: None,
90 models: vec![DEFAULT_MODEL.to_string()],
91 provider: None,
92 system: None,
93 priority: None,
94 reasoning: Some(ReasoningConfig::default()),
95 show_reasoning: Some(false),
96 quiet: Some(false),
97 merge_config: true,
98 }
99 }
100}
101
102impl PromptOpts {
103 pub fn merge(&mut self, o: PromptOpts) {
107 self.prompt.get_or_insert(o.prompt.unwrap_or_default());
108 self.quiet.get_or_insert(o.quiet.unwrap_or(DEFAULT_QUIET));
109 if self.models.is_empty() {
110 self.models = o.models;
113 }
114 if let Some(provider) = o.provider {
115 self.provider.get_or_insert(provider);
116 }
117 if let Some(system) = o.system {
118 self.system.get_or_insert(system);
119 }
120 if let Some(priority) = o.priority {
121 self.priority.get_or_insert(priority);
122 }
123 self.reasoning
124 .get_or_insert(o.reasoning.unwrap_or_default());
125 self.show_reasoning
126 .get_or_insert(o.show_reasoning.unwrap_or(DEFAULT_SHOW_REASONING));
127 }
128}
129
130#[derive(Default, Debug, Clone, Copy)]
131pub enum Priority {
132 Price,
133 #[default]
134 Latency,
135 Throughput,
136}
137
138impl Priority {
139 pub fn as_str(&self) -> &'static str {
140 match self {
141 Priority::Price => "price",
142 Priority::Latency => "latency",
143 Priority::Throughput => "throughput",
144 }
145 }
146}
147
148impl FromStr for Priority {
149 type Err = fmt::Error;
150
151 fn from_str(s: &str) -> Result<Self, Self::Err> {
152 match s.to_lowercase().as_str() {
153 "price" => Ok(Priority::Price),
154 "latency" => Ok(Priority::Latency),
155 "throughput" => Ok(Priority::Throughput),
156 _ => Err(fmt::Error), }
158 }
159}
160
161impl fmt::Display for Priority {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 match self {
164 Priority::Price => write!(f, "price"),
165 Priority::Latency => write!(f, "latency"),
166 Priority::Throughput => write!(f, "throughput"),
167 }
168 }
169}
170
171#[derive(Default, Debug, Clone)]
172pub struct ReasoningConfig {
173 pub enabled: bool,
174 pub effort: Option<ReasoningEffort>,
175 pub tokens: Option<u32>,
176}
177
178impl ReasoningConfig {
179 pub fn off() -> Self {
180 Self {
181 enabled: false,
182 ..Default::default()
183 }
184 }
185}
186
187#[derive(Default, Debug, Clone, Copy, PartialEq)]
188pub enum ReasoningEffort {
189 None, Low,
191 #[default]
192 Medium,
193 High,
194 XHigh, }
196
197impl ReasoningEffort {
198 pub fn as_str(&self) -> &'static str {
199 match self {
200 ReasoningEffort::None => "none",
201 ReasoningEffort::Low => "low",
202 ReasoningEffort::Medium => "medium",
203 ReasoningEffort::High => "high",
204 ReasoningEffort::XHigh => "xhigh",
205 }
206 }
207}
208
209impl fmt::Display for ReasoningEffort {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 match self {
212 ReasoningEffort::None => write!(f, "none"),
213 ReasoningEffort::Low => write!(f, "low"),
214 ReasoningEffort::Medium => write!(f, "medium"),
215 ReasoningEffort::High => write!(f, "high"),
216 ReasoningEffort::XHigh => write!(f, "xhigh"),
217 }
218 }
219}
220
221#[derive(Debug, Clone)]
222pub struct Message {
223 pub role: Role,
224 pub content: Option<String>,
225 pub reasoning: Option<String>,
226}
227
228impl Message {
229 pub fn new(role: Role, content: Option<String>, reasoning: Option<String>) -> Self {
230 Message {
231 role,
232 content,
233 reasoning,
234 }
235 }
236 pub fn system(content: String) -> Self {
237 Self::new(Role::System, Some(content), None)
238 }
239 pub fn user(content: String) -> Self {
240 Self::new(Role::User, Some(content), None)
241 }
242 pub fn assistant(content: String) -> Self {
243 Self::new(Role::Assistant, Some(content), None)
244 }
245
246 pub fn size(&self) -> u32 {
248 self.content
249 .as_ref()
250 .or(self.reasoning.as_ref())
251 .map(|c| c.len())
252 .unwrap_or(0) as u32
253 + 10
254 }
255}
256
257#[derive(Debug, Copy, Clone)]
258pub enum Role {
259 System,
260 User,
261 Assistant,
262}
263
264impl Role {
265 pub fn as_str(&self) -> &'static str {
266 match self {
267 Role::System => "system",
268 Role::User => "user",
269 Role::Assistant => "assistant",
270 }
271 }
272}
273
274impl FromStr for Role {
275 type Err = &'static str;
276 fn from_str(s: &str) -> Result<Self, Self::Err> {
277 match s.to_lowercase().as_str() {
278 "system" => Ok(Role::System),
279 "user" => Ok(Role::User),
280 "assistant" => Ok(Role::Assistant),
281 _ => Err("Invalid role"),
282 }
283 }
284}
285
286impl fmt::Display for Role {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 match self {
289 Role::System => write!(f, "system"),
290 Role::User => write!(f, "user"),
291 Role::Assistant => write!(f, "assistant"),
292 }
293 }
294}
295
296#[derive(Clone, Default)]
297pub enum Response {
298 Start,
300 Think(ThinkEvent),
302 Content(String),
304 Stats(super::stats::Stats),
306 Error(String),
308 #[default]
310 None,
311}
312
313#[derive(Debug, Clone)]
314pub enum ThinkEvent {
315 Start,
316 Content(String),
317 Stop,
318}