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