1use std::collections::BTreeMap;
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Deserialize)]
9pub struct HealthcheckDef {
10 pub method: String,
11 #[serde(default)]
12 pub path: Option<String>,
13 #[serde(default)]
14 pub url: Option<String>,
15 #[serde(default)]
16 pub body: Option<String>,
17}
18
19#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
20pub struct LocalRuntimeDef {
21 #[serde(default, skip_serializing_if = "Option::is_none")]
24 pub kind: Option<String>,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
27 pub command: Option<String>,
28 #[serde(default, skip_serializing_if = "Vec::is_empty")]
31 pub prefix_args: Vec<String>,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
35 pub model_source: Option<String>,
36 #[serde(default, skip_serializing_if = "Option::is_none")]
38 pub model_source_env: Option<String>,
39 #[serde(default, skip_serializing_if = "Option::is_none")]
41 pub default_port: Option<u16>,
42 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub model_arg: Option<String>,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub served_model_arg: Option<String>,
47 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub host_arg: Option<String>,
49 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub port_arg: Option<String>,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
52 pub ctx_arg: Option<String>,
53 #[serde(default, skip_serializing_if = "Option::is_none")]
54 pub parallel_arg: Option<String>,
55 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub gpu_layers_arg: Option<String>,
57 #[serde(default, skip_serializing_if = "Option::is_none")]
58 pub cache_type_k_arg: Option<String>,
59 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub cache_type_v_arg: Option<String>,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub cache_ram_arg: Option<String>,
63 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub enable_lora_arg: Option<String>,
66 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub lora_modules_arg: Option<String>,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
71 pub lora_modules_value_format: Option<String>,
72 #[serde(default, skip_serializing_if = "Option::is_none")]
74 pub max_lora_rank_arg: Option<String>,
75 #[serde(default, skip_serializing_if = "Vec::is_empty")]
77 pub default_args: Vec<String>,
78 #[serde(default, skip_serializing_if = "Option::is_none")]
80 pub stop: Option<String>,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
83 pub source_url: Option<String>,
84 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub last_verified: Option<String>,
87 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub notes: Option<String>,
90}
91
92#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
93pub struct LocalMemoryDef {
94 #[serde(default, skip_serializing_if = "Option::is_none")]
96 pub measured_resident_gib: Option<f64>,
97 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub measured_context_window: Option<u64>,
100 #[serde(default, skip_serializing_if = "Option::is_none")]
102 pub measured_cache_type: Option<String>,
103 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub base_resident_gib: Option<f64>,
106 #[serde(default, skip_serializing_if = "Option::is_none")]
109 pub kv_cache_gib_per_1k_ctx: Option<f64>,
110 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
112 pub cache_type_multipliers: BTreeMap<String, f64>,
113 #[serde(default, skip_serializing_if = "Option::is_none")]
115 pub default_cache_type: Option<String>,
116 #[serde(default, skip_serializing_if = "Option::is_none")]
118 pub safety_margin_gib: Option<f64>,
119 #[serde(default, skip_serializing_if = "Option::is_none")]
121 pub max_recommended_context: Option<u64>,
122 #[serde(default, skip_serializing_if = "Option::is_none")]
124 pub source_url: Option<String>,
125 #[serde(default, skip_serializing_if = "Option::is_none")]
127 pub last_verified: Option<String>,
128 #[serde(default, skip_serializing_if = "Option::is_none")]
130 pub notes: Option<String>,
131}
132
133impl LocalMemoryDef {
134 pub fn is_empty(&self) -> bool {
135 self.measured_resident_gib.is_none()
136 && self.measured_context_window.is_none()
137 && self.measured_cache_type.is_none()
138 && self.base_resident_gib.is_none()
139 && self.kv_cache_gib_per_1k_ctx.is_none()
140 && self.cache_type_multipliers.is_empty()
141 && self.default_cache_type.is_none()
142 && self.safety_margin_gib.is_none()
143 && self.max_recommended_context.is_none()
144 && self.source_url.is_none()
145 && self.last_verified.is_none()
146 && self.notes.is_none()
147 }
148}
149
150#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
151pub struct AliasDef {
152 pub id: String,
153 pub provider: String,
154 #[serde(default)]
159 pub tool_format: Option<String>,
160}
161
162#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
163pub struct AliasToolCallingDef {
164 #[serde(default)]
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub native: Option<String>,
167 #[serde(default)]
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub text: Option<String>,
170 #[serde(default)]
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub streaming_native: Option<String>,
173 #[serde(default)]
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub fallback_mode: Option<String>,
176 #[serde(default)]
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub failure_reason: Option<String>,
179 #[serde(default)]
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub last_probe_at: Option<String>,
182}
183
184#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
185pub struct ModelPricing {
186 pub input_per_mtok: f64,
187 pub output_per_mtok: f64,
188 #[serde(default)]
189 pub cache_read_per_mtok: Option<f64>,
190 #[serde(default)]
191 pub cache_write_per_mtok: Option<f64>,
192}
193
194#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
197pub struct RateLimitsDef {
198 #[serde(default, skip_serializing_if = "Option::is_none")]
200 pub rpm: Option<u32>,
201 #[serde(default, skip_serializing_if = "Option::is_none")]
203 pub rph: Option<u32>,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub rpd: Option<u32>,
207 #[serde(default, skip_serializing_if = "Option::is_none")]
209 pub tpm: Option<u64>,
210 #[serde(default, skip_serializing_if = "Option::is_none")]
212 pub tph: Option<u64>,
213 #[serde(default, skip_serializing_if = "Option::is_none")]
215 pub tpd: Option<u64>,
216 #[serde(default, skip_serializing_if = "Option::is_none")]
218 pub input_tpm: Option<u64>,
219 #[serde(default, skip_serializing_if = "Option::is_none")]
221 pub output_tpm: Option<u64>,
222 #[serde(default, skip_serializing_if = "Option::is_none")]
224 pub concurrency: Option<u32>,
225 #[serde(default, skip_serializing_if = "Option::is_none")]
227 pub tier: Option<String>,
228 #[serde(default, skip_serializing_if = "Option::is_none")]
230 pub source_url: Option<String>,
231 #[serde(default, skip_serializing_if = "Option::is_none")]
233 pub last_verified: Option<String>,
234 #[serde(default, skip_serializing_if = "Option::is_none")]
236 pub notes: Option<String>,
237}
238
239impl RateLimitsDef {
240 pub fn is_empty(&self) -> bool {
241 self.rpm.is_none()
242 && self.rph.is_none()
243 && self.rpd.is_none()
244 && self.tpm.is_none()
245 && self.tph.is_none()
246 && self.tpd.is_none()
247 && self.input_tpm.is_none()
248 && self.output_tpm.is_none()
249 && self.concurrency.is_none()
250 && self.tier.is_none()
251 && self.source_url.is_none()
252 && self.last_verified.is_none()
253 && self.notes.is_none()
254 }
255
256 pub fn with_rpm_fallback(mut self, rpm: Option<u32>) -> Option<Self> {
257 if self.rpm.is_none() {
258 self.rpm = rpm;
259 }
260 (!self.is_empty()).then_some(self)
261 }
262}
263
264#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
268pub struct ServingPerformanceDef {
269 #[serde(default, skip_serializing_if = "Option::is_none")]
271 pub observed_ttft_ms: Option<u64>,
272 #[serde(default, skip_serializing_if = "Option::is_none")]
274 pub output_tokens_per_sec: Option<f64>,
275 #[serde(default, skip_serializing_if = "Option::is_none")]
278 pub time_to_answer_s: Option<f64>,
279 #[serde(default, skip_serializing_if = "Option::is_none")]
282 pub source: Option<String>,
283 #[serde(default, skip_serializing_if = "Option::is_none")]
285 pub source_url: Option<String>,
286 #[serde(default, skip_serializing_if = "Option::is_none")]
288 pub last_verified: Option<String>,
289 #[serde(default, skip_serializing_if = "Option::is_none")]
291 pub sample_size: Option<u32>,
292 #[serde(default, skip_serializing_if = "Option::is_none")]
294 pub notes: Option<String>,
295}
296
297impl ServingPerformanceDef {
298 pub fn is_empty(&self) -> bool {
299 self.observed_ttft_ms.is_none()
300 && self.output_tokens_per_sec.is_none()
301 && self.time_to_answer_s.is_none()
302 && self.source.is_none()
303 && self.source_url.is_none()
304 && self.last_verified.is_none()
305 && self.sample_size.is_none()
306 && self.notes.is_none()
307 }
308}
309
310#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
314pub struct ModelArchitectureDef {
315 #[serde(default, skip_serializing_if = "Option::is_none")]
317 pub parameter_count_b: Option<f64>,
318 #[serde(default, skip_serializing_if = "Option::is_none")]
320 pub active_parameter_count_b: Option<f64>,
321 #[serde(default, skip_serializing_if = "Option::is_none")]
323 pub moe: Option<bool>,
324 #[serde(default, skip_serializing_if = "Option::is_none")]
326 pub quantization: Option<String>,
327 #[serde(default, skip_serializing_if = "Option::is_none")]
329 pub precision: Option<String>,
330 #[serde(default, skip_serializing_if = "Option::is_none")]
332 pub license: Option<String>,
333 #[serde(default, skip_serializing_if = "Option::is_none")]
335 pub tokenizer: Option<String>,
336 #[serde(default, skip_serializing_if = "Option::is_none")]
338 pub knowledge_cutoff: Option<String>,
339 #[serde(default, skip_serializing_if = "Option::is_none")]
341 pub source_url: Option<String>,
342 #[serde(default, skip_serializing_if = "Option::is_none")]
344 pub last_verified: Option<String>,
345}
346
347impl ModelArchitectureDef {
348 pub fn is_empty(&self) -> bool {
349 self.parameter_count_b.is_none()
350 && self.active_parameter_count_b.is_none()
351 && self.moe.is_none()
352 && self.quantization.is_none()
353 && self.precision.is_none()
354 && self.license.is_none()
355 && self.tokenizer.is_none()
356 && self.knowledge_cutoff.is_none()
357 && self.source_url.is_none()
358 && self.last_verified.is_none()
359 }
360}
361
362#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
373pub struct FastModeDef {
374 pub param: String,
377 pub value: String,
379 #[serde(default)]
382 pub beta_header: Option<String>,
383 #[serde(default)]
385 pub otps_speedup: Option<f64>,
386 #[serde(default)]
389 pub status: Option<String>,
390 #[serde(default)]
393 pub pricing: Option<ModelPricing>,
394 #[serde(default)]
396 pub note: Option<String>,
397}
398
399#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
410pub struct ModelLadderDef {
411 #[serde(default)]
413 pub steps: Vec<ModelLadderStepDef>,
414 #[serde(default)]
416 pub label: Option<String>,
417}
418
419#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
424pub struct ModelLadderStepDef {
425 pub model: String,
426 #[serde(default)]
427 pub provider: Option<String>,
428 #[serde(default)]
429 pub label: Option<String>,
430}
431
432#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
433pub struct ModelDef {
434 pub name: String,
435 pub provider: String,
436 pub context_window: u64,
437 #[serde(default)]
440 pub logical_model: Option<String>,
441 #[serde(default)]
445 pub equivalence_group: Option<String>,
446 #[serde(default)]
449 pub served_variant: Option<String>,
450 #[serde(default)]
454 pub wire_model: Option<String>,
455 #[serde(default)]
458 pub api_dialect: Option<String>,
459 #[serde(default)]
461 pub rate_limits: Option<RateLimitsDef>,
462 #[serde(default)]
464 pub performance: Option<ServingPerformanceDef>,
465 #[serde(default)]
467 pub architecture: Option<ModelArchitectureDef>,
468 #[serde(default)]
470 pub local_memory: Option<LocalMemoryDef>,
471 #[serde(default)]
472 pub runtime_context_window: Option<u64>,
473 #[serde(default)]
474 pub stream_timeout: Option<f64>,
475 #[serde(default)]
476 pub capabilities: Vec<String>,
477 #[serde(default)]
478 pub pricing: Option<ModelPricing>,
479 #[serde(default)]
480 pub deprecated: bool,
481 #[serde(default)]
482 pub deprecation_note: Option<String>,
483 #[serde(default)]
491 pub superseded_by: Option<String>,
492 #[serde(default)]
496 pub fast_mode: Option<FastModeDef>,
497 #[serde(default)]
498 pub quality_tags: Vec<String>,
499 #[serde(default)]
505 pub availability: ModelAvailability,
506 #[serde(default)]
513 pub tier: Option<String>,
514 #[serde(default)]
519 pub open_weight: Option<bool>,
520 #[serde(default)]
525 pub strengths: Vec<String>,
526 #[serde(default)]
532 pub benchmarks: BTreeMap<String, f64>,
533 #[serde(default)]
538 pub family: Option<String>,
539 #[serde(default)]
541 pub lineage: Option<String>,
542 #[serde(default)]
544 pub complementary_with: Vec<String>,
545 #[serde(default)]
548 pub avoid_as_reviewer_for: Vec<String>,
549}
550
551#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default)]
552#[serde(rename_all = "snake_case")]
553pub enum ModelAvailability {
554 #[default]
558 Serverless,
559 Dedicated,
563 Unknown,
567}
568
569impl ModelAvailability {
570 pub fn as_str(self) -> &'static str {
571 match self {
572 Self::Serverless => "serverless",
573 Self::Dedicated => "dedicated",
574 Self::Unknown => "unknown",
575 }
576 }
577
578 pub fn parse(value: &str) -> Option<Self> {
579 match value {
580 "serverless" => Some(Self::Serverless),
581 "dedicated" => Some(Self::Dedicated),
582 "unknown" => Some(Self::Unknown),
583 _ => None,
584 }
585 }
586}