objectiveai_sdk/agent/openrouter/
provider.rs1use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8use std::collections::HashSet;
9
10#[derive(
15 Debug,
16 Clone,
17 Serialize,
18 Deserialize,
19 PartialEq,
20 Hash,
21 JsonSchema,
22 arbitrary::Arbitrary,
23)]
24#[schemars(rename = "agent.openrouter.Provider")]
25pub struct Provider {
26 #[serde(skip_serializing_if = "Option::is_none")]
29 #[schemars(extend("omitempty" = true))]
30 pub allow_fallbacks: Option<bool>,
31 #[serde(skip_serializing_if = "Option::is_none")]
34 #[schemars(extend("omitempty" = true))]
35 pub require_parameters: Option<bool>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 #[schemars(extend("omitempty" = true))]
39 pub order: Option<Vec<String>>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 #[schemars(extend("omitempty" = true))]
43 pub only: Option<Vec<String>>,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 #[schemars(extend("omitempty" = true))]
47 pub ignore: Option<Vec<String>>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 #[schemars(extend("omitempty" = true))]
51 pub quantizations: Option<Vec<ProviderQuantization>>,
52}
53
54impl Provider {
55 pub fn prepare(mut self) -> Option<Self> {
59 if let Some(true) = self.allow_fallbacks {
60 self.allow_fallbacks = None;
61 }
62 if let Some(false) = self.require_parameters {
63 self.require_parameters = None;
64 }
65 if let Some(order) = &mut self.order {
66 if order.is_empty() {
67 self.order = None;
68 } else {
69 let mut dedup = HashSet::with_capacity(order.len());
70 order.retain(|provider| dedup.insert(provider.clone()));
71 }
72 }
73 if let Some(only) = &mut self.only {
74 if only.is_empty() {
75 self.only = None;
76 } else {
77 only.sort();
78 only.dedup();
79 }
80 }
81 if let Some(ignore) = &mut self.ignore {
82 if ignore.is_empty() {
83 self.ignore = None;
84 } else {
85 ignore.sort();
86 ignore.dedup();
87 }
88 }
89 if let Some(quantizations) = &mut self.quantizations {
90 if quantizations.is_empty() {
91 self.quantizations = None;
92 } else {
93 quantizations.sort();
94 quantizations.dedup();
95 }
96 }
97 if self.allow_fallbacks.is_some()
98 || self.require_parameters.is_some()
99 || self.order.is_some()
100 || self.only.is_some()
101 || self.ignore.is_some()
102 || self.quantizations.is_some()
103 {
104 Some(self)
105 } else {
106 None
107 }
108 }
109
110 pub fn validate(&self) -> Result<(), String> {
112 if self.order.iter().any(|s| s.is_empty()) {
113 Err("`provider.order` strings cannot be empty".to_string())
114 } else if self.only.iter().any(|s| s.is_empty()) {
115 Err("`provider.only` strings cannot be empty".to_string())
116 } else if self.ignore.iter().any(|s| s.is_empty()) {
117 Err("`provider.ignore` strings cannot be empty".to_string())
118 } else {
119 Ok(())
120 }
121 }
122}
123
124#[derive(
129 Debug,
130 Clone,
131 Copy,
132 Serialize,
133 Deserialize,
134 PartialEq,
135 Eq,
136 Hash,
137 JsonSchema,
138 arbitrary::Arbitrary,
139)]
140#[serde(rename_all = "snake_case")]
141#[schemars(rename = "agent.openrouter.ProviderQuantization")]
142pub enum ProviderQuantization {
143 #[schemars(title = "Int4")]
145 Int4,
146 #[schemars(title = "Int8")]
148 Int8,
149 #[schemars(title = "Fp4")]
151 Fp4,
152 #[schemars(title = "Fp6")]
154 Fp6,
155 #[schemars(title = "Fp8")]
157 Fp8,
158 #[schemars(title = "Fp16")]
160 Fp16,
161 #[schemars(title = "Bf16")]
163 Bf16,
164 #[schemars(title = "Fp32")]
166 Fp32,
167 #[schemars(title = "Unknown")]
169 Unknown,
170}
171
172impl PartialOrd for ProviderQuantization {
173 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
174 Some((*self as u16).cmp(&(*other as u16)))
175 }
176}
177
178impl Ord for ProviderQuantization {
179 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
180 self.partial_cmp(other).unwrap()
181 }
182}