Skip to main content

yapi_types/
models.rs

1//! `models.json`: custom providers, models and overrides.
2//!
3//! Mirrors the TypeBox schema in `packages/coding-agent/src/core/model-config.ts` in
4//! pi `v1.0.0`. pi reads this file but never writes it. Provider `compat` options
5//! stay raw JSON until the wire APIs that use them exist.
6#![allow(
7    missing_docs,
8    reason = "fields mirror pi's TypeScript types; contracts are noted where they differ from the name"
9)]
10
11use indexmap::IndexMap;
12use serde::{Deserialize, Serialize};
13use serde_json::{Map, Value};
14
15#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
16pub struct ModelsConfig {
17    pub providers: IndexMap<String, ProviderConfig>,
18}
19
20/// A new provider, or overrides for a built-in one. `apiKey` and header values use
21/// the same `$VAR` and `!command` forms as `auth.json`.
22#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub struct ProviderConfig {
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub name: Option<String>,
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub base_url: Option<String>,
29    #[serde(default, skip_serializing_if = "Option::is_none")]
30    pub api_key: Option<String>,
31    #[serde(default, skip_serializing_if = "Option::is_none")]
32    pub api: Option<String>,
33    /// Only `"radius"`.
34    #[serde(default, skip_serializing_if = "Option::is_none")]
35    pub oauth: Option<String>,
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub headers: Option<IndexMap<String, String>>,
38    #[serde(default, skip_serializing_if = "Option::is_none")]
39    pub compat: Option<Map<String, Value>>,
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub auth_header: Option<bool>,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub models: Option<Vec<ModelDefinition>>,
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub model_overrides: Option<IndexMap<String, ModelOverride>>,
46}
47
48#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct ModelDefinition {
51    pub id: String,
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub name: Option<String>,
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub api: Option<String>,
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub base_url: Option<String>,
58    /// `"image"` or `"classifier"` in an extension provider's models; absent
59    /// or `"chat"` otherwise. `models.json` defines chat models only.
60    #[serde(default, rename = "type", skip_serializing_if = "Option::is_none")]
61    pub kind: Option<String>,
62    /// An image model's output modalities.
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub output: Option<Vec<InputKind>>,
65    #[serde(flatten)]
66    pub options: ModelOptions,
67}
68
69/// Fields shared by model definitions and overrides.
70#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
71#[serde(rename_all = "camelCase")]
72pub struct ModelOptions {
73    #[serde(default, skip_serializing_if = "Option::is_none")]
74    pub reasoning: Option<bool>,
75    /// pi thinking level to provider value; `None` marks the level unsupported.
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub thinking_level_map: Option<IndexMap<String, Option<String>>>,
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub input: Option<Vec<InputKind>>,
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    pub input_limits: Option<InputLimits>,
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub prompt_cache: Option<PromptCache>,
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub context_window: Option<u64>,
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub max_tokens: Option<u64>,
88    #[serde(default, skip_serializing_if = "Option::is_none")]
89    pub sampling_params: Option<Map<String, Value>>,
90    #[serde(default, skip_serializing_if = "Option::is_none")]
91    pub headers: Option<IndexMap<String, String>>,
92    #[serde(default, skip_serializing_if = "Option::is_none")]
93    pub compat: Option<Map<String, Value>>,
94    /// Required rates in a definition; any subset in an override.
95    #[serde(default, skip_serializing_if = "Option::is_none")]
96    pub cost: Option<ModelCost>,
97}
98
99/// Changes to a built-in model; every field is optional.
100#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
101pub struct ModelOverride {
102    #[serde(default, skip_serializing_if = "Option::is_none")]
103    pub name: Option<String>,
104    #[serde(flatten)]
105    pub options: ModelOptions,
106}
107
108#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
109#[serde(rename_all = "lowercase")]
110pub enum InputKind {
111    Text,
112    Image,
113}
114
115#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
116#[serde(rename_all = "camelCase")]
117pub struct InputLimits {
118    #[serde(default, skip_serializing_if = "Option::is_none")]
119    pub max_request_bytes: Option<u64>,
120    #[serde(default, skip_serializing_if = "Option::is_none")]
121    pub images: Option<ImageLimits>,
122}
123
124#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
125#[serde(rename_all = "camelCase")]
126pub struct ImageLimits {
127    #[serde(default, skip_serializing_if = "Option::is_none")]
128    pub resize: Option<ImageResize>,
129    #[serde(default, skip_serializing_if = "Option::is_none")]
130    pub max_per_message: Option<u32>,
131    #[serde(default, skip_serializing_if = "Option::is_none")]
132    pub max_per_request: Option<u32>,
133}
134
135#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
136#[serde(rename_all = "camelCase")]
137pub struct ImageResize {
138    #[serde(default, skip_serializing_if = "Option::is_none")]
139    pub max_width: Option<u32>,
140    #[serde(default, skip_serializing_if = "Option::is_none")]
141    pub max_height: Option<u32>,
142    #[serde(default, skip_serializing_if = "Option::is_none")]
143    pub max_bytes: Option<u64>,
144    /// 1 to 100.
145    #[serde(default, skip_serializing_if = "Option::is_none")]
146    pub jpeg_quality: Option<u8>,
147}
148
149/// Prompt cache retention, in seconds.
150#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
151pub struct PromptCache {
152    #[serde(default, skip_serializing_if = "Option::is_none")]
153    pub short: Option<f64>,
154    #[serde(default, skip_serializing_if = "Option::is_none")]
155    pub long: Option<f64>,
156}
157
158/// US dollars per million tokens.
159#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
160#[serde(rename_all = "camelCase")]
161pub struct ModelCost {
162    #[serde(default, skip_serializing_if = "Option::is_none")]
163    pub input: Option<f64>,
164    #[serde(default, skip_serializing_if = "Option::is_none")]
165    pub output: Option<f64>,
166    #[serde(default, skip_serializing_if = "Option::is_none")]
167    pub cache_read: Option<f64>,
168    #[serde(default, skip_serializing_if = "Option::is_none")]
169    pub cache_write: Option<f64>,
170    /// Higher rates above an input size.
171    #[serde(default, skip_serializing_if = "Option::is_none")]
172    pub tiers: Option<Vec<CostTier>>,
173}
174
175#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
176#[serde(rename_all = "camelCase")]
177pub struct CostTier {
178    pub input_tokens_above: u64,
179    pub input: f64,
180    pub output: f64,
181    pub cache_read: f64,
182    pub cache_write: f64,
183}