1use std::time::Duration;
2
3use anyhow::Result;
4use gpui::AppContext;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use settings::{Settings, SettingsSources};
8
9use crate::provider::{
10 anthropic::AnthropicSettings,
11 cloud::{self, ZedDotDevSettings},
12 copilot_chat::CopilotChatSettings,
13 google::GoogleSettings,
14 ollama::OllamaSettings,
15 open_ai::OpenAiSettings,
16};
17
18/// Initializes the language model settings.
19pub fn init(cx: &mut AppContext) {
20 AllLanguageModelSettings::register(cx);
21}
22
23#[derive(Default)]
24pub struct AllLanguageModelSettings {
25 pub anthropic: AnthropicSettings,
26 pub ollama: OllamaSettings,
27 pub openai: OpenAiSettings,
28 pub zed_dot_dev: ZedDotDevSettings,
29 pub google: GoogleSettings,
30 pub copilot_chat: CopilotChatSettings,
31}
32
33#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
34pub struct AllLanguageModelSettingsContent {
35 pub anthropic: Option<AnthropicSettingsContent>,
36 pub ollama: Option<OllamaSettingsContent>,
37 pub openai: Option<OpenAiSettingsContent>,
38 #[serde(rename = "zed.dev")]
39 pub zed_dot_dev: Option<ZedDotDevSettingsContent>,
40 pub google: Option<GoogleSettingsContent>,
41 pub copilot_chat: Option<CopilotChatSettingsContent>,
42}
43
44#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
45pub struct AnthropicSettingsContent {
46 pub api_url: Option<String>,
47 pub low_speed_timeout_in_seconds: Option<u64>,
48 pub available_models: Option<Vec<anthropic::Model>>,
49}
50
51#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
52pub struct OllamaSettingsContent {
53 pub api_url: Option<String>,
54 pub low_speed_timeout_in_seconds: Option<u64>,
55}
56
57#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
58pub struct OpenAiSettingsContent {
59 pub api_url: Option<String>,
60 pub low_speed_timeout_in_seconds: Option<u64>,
61 pub available_models: Option<Vec<open_ai::Model>>,
62}
63
64#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
65pub struct GoogleSettingsContent {
66 pub api_url: Option<String>,
67 pub low_speed_timeout_in_seconds: Option<u64>,
68 pub available_models: Option<Vec<google_ai::Model>>,
69}
70
71#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
72pub struct ZedDotDevSettingsContent {
73 available_models: Option<Vec<cloud::AvailableModel>>,
74}
75
76#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
77pub struct CopilotChatSettingsContent {
78 low_speed_timeout_in_seconds: Option<u64>,
79}
80
81impl settings::Settings for AllLanguageModelSettings {
82 const KEY: Option<&'static str> = Some("language_models");
83
84 type FileContent = AllLanguageModelSettingsContent;
85
86 fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
87 fn merge<T>(target: &mut T, value: Option<T>) {
88 if let Some(value) = value {
89 *target = value;
90 }
91 }
92
93 let mut settings = AllLanguageModelSettings::default();
94
95 for value in sources.defaults_and_customizations() {
96 merge(
97 &mut settings.anthropic.api_url,
98 value.anthropic.as_ref().and_then(|s| s.api_url.clone()),
99 );
100 if let Some(low_speed_timeout_in_seconds) = value
101 .anthropic
102 .as_ref()
103 .and_then(|s| s.low_speed_timeout_in_seconds)
104 {
105 settings.anthropic.low_speed_timeout =
106 Some(Duration::from_secs(low_speed_timeout_in_seconds));
107 }
108 merge(
109 &mut settings.anthropic.available_models,
110 value
111 .anthropic
112 .as_ref()
113 .and_then(|s| s.available_models.clone()),
114 );
115
116 merge(
117 &mut settings.ollama.api_url,
118 value.ollama.as_ref().and_then(|s| s.api_url.clone()),
119 );
120 if let Some(low_speed_timeout_in_seconds) = value
121 .ollama
122 .as_ref()
123 .and_then(|s| s.low_speed_timeout_in_seconds)
124 {
125 settings.ollama.low_speed_timeout =
126 Some(Duration::from_secs(low_speed_timeout_in_seconds));
127 }
128
129 merge(
130 &mut settings.openai.api_url,
131 value.openai.as_ref().and_then(|s| s.api_url.clone()),
132 );
133 if let Some(low_speed_timeout_in_seconds) = value
134 .openai
135 .as_ref()
136 .and_then(|s| s.low_speed_timeout_in_seconds)
137 {
138 settings.openai.low_speed_timeout =
139 Some(Duration::from_secs(low_speed_timeout_in_seconds));
140 }
141 merge(
142 &mut settings.openai.available_models,
143 value
144 .openai
145 .as_ref()
146 .and_then(|s| s.available_models.clone()),
147 );
148
149 merge(
150 &mut settings.zed_dot_dev.available_models,
151 value
152 .zed_dot_dev
153 .as_ref()
154 .and_then(|s| s.available_models.clone()),
155 );
156
157 merge(
158 &mut settings.google.api_url,
159 value.google.as_ref().and_then(|s| s.api_url.clone()),
160 );
161 if let Some(low_speed_timeout_in_seconds) = value
162 .google
163 .as_ref()
164 .and_then(|s| s.low_speed_timeout_in_seconds)
165 {
166 settings.google.low_speed_timeout =
167 Some(Duration::from_secs(low_speed_timeout_in_seconds));
168 }
169 merge(
170 &mut settings.google.available_models,
171 value
172 .google
173 .as_ref()
174 .and_then(|s| s.available_models.clone()),
175 );
176
177 if let Some(low_speed_timeout) = value
178 .copilot_chat
179 .as_ref()
180 .and_then(|s| s.low_speed_timeout_in_seconds)
181 {
182 settings.copilot_chat.low_speed_timeout =
183 Some(Duration::from_secs(low_speed_timeout));
184 }
185 }
186
187 Ok(settings)
188 }
189}