1use std::sync::Arc;
2
3use anyhow::Result;
4use collections::HashMap;
5use gpui::App;
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
9
10use crate::provider::{
11 self,
12 anthropic::AnthropicSettings,
13 bedrock::AmazonBedrockSettings,
14 cloud::{self, ZedDotDevSettings},
15 deepseek::DeepSeekSettings,
16 google::GoogleSettings,
17 lmstudio::LmStudioSettings,
18 mistral::MistralSettings,
19 ollama::OllamaSettings,
20 open_ai::OpenAiSettings,
21 open_ai_compatible::OpenAiCompatibleSettings,
22 open_router::OpenRouterSettings,
23 vercel::VercelSettings,
24 x_ai::XAiSettings,
25};
26
27/// Initializes the language model settings.
28pub fn init_settings(cx: &mut App) {
29 AllLanguageModelSettings::register(cx);
30}
31
32#[derive(Default)]
33pub struct AllLanguageModelSettings {
34 pub anthropic: AnthropicSettings,
35 pub bedrock: AmazonBedrockSettings,
36 pub deepseek: DeepSeekSettings,
37 pub google: GoogleSettings,
38 pub lmstudio: LmStudioSettings,
39 pub mistral: MistralSettings,
40 pub ollama: OllamaSettings,
41 pub open_router: OpenRouterSettings,
42 pub openai: OpenAiSettings,
43 pub openai_compatible: HashMap<Arc<str>, OpenAiCompatibleSettings>,
44 pub vercel: VercelSettings,
45 pub x_ai: XAiSettings,
46 pub zed_dot_dev: ZedDotDevSettings,
47}
48
49#[derive(
50 Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, SettingsUi, SettingsKey,
51)]
52#[settings_key(key = "language_models")]
53pub struct AllLanguageModelSettingsContent {
54 pub anthropic: Option<AnthropicSettingsContent>,
55 pub bedrock: Option<AmazonBedrockSettingsContent>,
56 pub deepseek: Option<DeepseekSettingsContent>,
57 pub google: Option<GoogleSettingsContent>,
58 pub lmstudio: Option<LmStudioSettingsContent>,
59 pub mistral: Option<MistralSettingsContent>,
60 pub ollama: Option<OllamaSettingsContent>,
61 pub open_router: Option<OpenRouterSettingsContent>,
62 pub openai: Option<OpenAiSettingsContent>,
63 pub openai_compatible: Option<HashMap<Arc<str>, OpenAiCompatibleSettingsContent>>,
64 pub vercel: Option<VercelSettingsContent>,
65 pub x_ai: Option<XAiSettingsContent>,
66 #[serde(rename = "zed.dev")]
67 pub zed_dot_dev: Option<ZedDotDevSettingsContent>,
68}
69
70#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
71pub struct AnthropicSettingsContent {
72 pub api_url: Option<String>,
73 pub available_models: Option<Vec<provider::anthropic::AvailableModel>>,
74}
75
76#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
77pub struct AmazonBedrockSettingsContent {
78 available_models: Option<Vec<provider::bedrock::AvailableModel>>,
79 endpoint_url: Option<String>,
80 region: Option<String>,
81 profile: Option<String>,
82 authentication_method: Option<provider::bedrock::BedrockAuthMethod>,
83}
84
85#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
86pub struct OllamaSettingsContent {
87 pub api_url: Option<String>,
88 pub available_models: Option<Vec<provider::ollama::AvailableModel>>,
89}
90
91#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
92pub struct LmStudioSettingsContent {
93 pub api_url: Option<String>,
94 pub available_models: Option<Vec<provider::lmstudio::AvailableModel>>,
95}
96
97#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
98pub struct DeepseekSettingsContent {
99 pub api_url: Option<String>,
100 pub available_models: Option<Vec<provider::deepseek::AvailableModel>>,
101}
102
103#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
104pub struct MistralSettingsContent {
105 pub api_url: Option<String>,
106 pub available_models: Option<Vec<provider::mistral::AvailableModel>>,
107}
108
109#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
110pub struct OpenAiSettingsContent {
111 pub api_url: Option<String>,
112 pub available_models: Option<Vec<provider::open_ai::AvailableModel>>,
113}
114
115#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
116pub struct OpenAiCompatibleSettingsContent {
117 pub api_url: String,
118 pub available_models: Vec<provider::open_ai_compatible::AvailableModel>,
119}
120
121#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
122pub struct VercelSettingsContent {
123 pub api_url: Option<String>,
124 pub available_models: Option<Vec<provider::vercel::AvailableModel>>,
125}
126
127#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
128pub struct GoogleSettingsContent {
129 pub api_url: Option<String>,
130 pub available_models: Option<Vec<provider::google::AvailableModel>>,
131}
132
133#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
134pub struct XAiSettingsContent {
135 pub api_url: Option<String>,
136 pub available_models: Option<Vec<provider::x_ai::AvailableModel>>,
137}
138
139#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
140pub struct ZedDotDevSettingsContent {
141 available_models: Option<Vec<cloud::AvailableModel>>,
142}
143
144#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
145pub struct OpenRouterSettingsContent {
146 pub api_url: Option<String>,
147 pub available_models: Option<Vec<provider::open_router::AvailableModel>>,
148}
149
150impl settings::Settings for AllLanguageModelSettings {
151 const PRESERVED_KEYS: Option<&'static [&'static str]> = Some(&["version"]);
152
153 type FileContent = AllLanguageModelSettingsContent;
154
155 fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
156 fn merge<T>(target: &mut T, value: Option<T>) {
157 if let Some(value) = value {
158 *target = value;
159 }
160 }
161
162 let mut settings = AllLanguageModelSettings::default();
163
164 for value in sources.defaults_and_customizations() {
165 // Anthropic
166 let anthropic = value.anthropic.clone();
167 merge(
168 &mut settings.anthropic.api_url,
169 anthropic.as_ref().and_then(|s| s.api_url.clone()),
170 );
171 merge(
172 &mut settings.anthropic.available_models,
173 anthropic.as_ref().and_then(|s| s.available_models.clone()),
174 );
175
176 // Bedrock
177 let bedrock = value.bedrock.clone();
178 merge(
179 &mut settings.bedrock.profile_name,
180 bedrock.as_ref().map(|s| s.profile.clone()),
181 );
182 merge(
183 &mut settings.bedrock.authentication_method,
184 bedrock.as_ref().map(|s| s.authentication_method.clone()),
185 );
186 merge(
187 &mut settings.bedrock.region,
188 bedrock.as_ref().map(|s| s.region.clone()),
189 );
190 merge(
191 &mut settings.bedrock.endpoint,
192 bedrock.as_ref().map(|s| s.endpoint_url.clone()),
193 );
194
195 // Ollama
196 let ollama = value.ollama.clone();
197
198 merge(
199 &mut settings.ollama.api_url,
200 value.ollama.as_ref().and_then(|s| s.api_url.clone()),
201 );
202 merge(
203 &mut settings.ollama.available_models,
204 ollama.as_ref().and_then(|s| s.available_models.clone()),
205 );
206
207 // LM Studio
208 let lmstudio = value.lmstudio.clone();
209
210 merge(
211 &mut settings.lmstudio.api_url,
212 value.lmstudio.as_ref().and_then(|s| s.api_url.clone()),
213 );
214 merge(
215 &mut settings.lmstudio.available_models,
216 lmstudio.as_ref().and_then(|s| s.available_models.clone()),
217 );
218
219 // DeepSeek
220 let deepseek = value.deepseek.clone();
221
222 merge(
223 &mut settings.deepseek.api_url,
224 value.deepseek.as_ref().and_then(|s| s.api_url.clone()),
225 );
226 merge(
227 &mut settings.deepseek.available_models,
228 deepseek.as_ref().and_then(|s| s.available_models.clone()),
229 );
230
231 // OpenAI
232 let openai = value.openai.clone();
233 merge(
234 &mut settings.openai.api_url,
235 openai.as_ref().and_then(|s| s.api_url.clone()),
236 );
237 merge(
238 &mut settings.openai.available_models,
239 openai.as_ref().and_then(|s| s.available_models.clone()),
240 );
241
242 // OpenAI Compatible
243 if let Some(openai_compatible) = value.openai_compatible.clone() {
244 for (id, openai_compatible_settings) in openai_compatible {
245 settings.openai_compatible.insert(
246 id,
247 OpenAiCompatibleSettings {
248 api_url: openai_compatible_settings.api_url,
249 available_models: openai_compatible_settings.available_models,
250 },
251 );
252 }
253 }
254
255 // Vercel
256 let vercel = value.vercel.clone();
257 merge(
258 &mut settings.vercel.api_url,
259 vercel.as_ref().and_then(|s| s.api_url.clone()),
260 );
261 merge(
262 &mut settings.vercel.available_models,
263 vercel.as_ref().and_then(|s| s.available_models.clone()),
264 );
265
266 // XAI
267 let x_ai = value.x_ai.clone();
268 merge(
269 &mut settings.x_ai.api_url,
270 x_ai.as_ref().and_then(|s| s.api_url.clone()),
271 );
272 merge(
273 &mut settings.x_ai.available_models,
274 x_ai.as_ref().and_then(|s| s.available_models.clone()),
275 );
276
277 // ZedDotDev
278 merge(
279 &mut settings.zed_dot_dev.available_models,
280 value
281 .zed_dot_dev
282 .as_ref()
283 .and_then(|s| s.available_models.clone()),
284 );
285 merge(
286 &mut settings.google.api_url,
287 value.google.as_ref().and_then(|s| s.api_url.clone()),
288 );
289 merge(
290 &mut settings.google.available_models,
291 value
292 .google
293 .as_ref()
294 .and_then(|s| s.available_models.clone()),
295 );
296
297 // Mistral
298 let mistral = value.mistral.clone();
299 merge(
300 &mut settings.mistral.api_url,
301 mistral.as_ref().and_then(|s| s.api_url.clone()),
302 );
303 merge(
304 &mut settings.mistral.available_models,
305 mistral.as_ref().and_then(|s| s.available_models.clone()),
306 );
307
308 // OpenRouter
309 let open_router = value.open_router.clone();
310 merge(
311 &mut settings.open_router.api_url,
312 open_router.as_ref().and_then(|s| s.api_url.clone()),
313 );
314 merge(
315 &mut settings.open_router.available_models,
316 open_router
317 .as_ref()
318 .and_then(|s| s.available_models.clone()),
319 );
320 }
321
322 Ok(settings)
323 }
324
325 fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
326}