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