1use collections::{HashMap, IndexMap};
2use gpui::SharedString;
3use schemars::{JsonSchema, json_schema};
4use serde::{Deserialize, Serialize};
5use settings_macros::{MergeFrom, with_fallible_options};
6use std::{borrow::Cow, path::PathBuf, sync::Arc};
7
8use crate::{DockPosition, DockSide};
9
10#[with_fallible_options]
11#[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, Default)]
12pub struct AgentSettingsContent {
13 /// Whether the Agent is enabled.
14 ///
15 /// Default: true
16 pub enabled: Option<bool>,
17 /// Whether to show the agent panel button in the status bar.
18 ///
19 /// Default: true
20 pub button: Option<bool>,
21 /// Where to dock the agent panel.
22 ///
23 /// Default: right
24 pub dock: Option<DockPosition>,
25 /// Where to dock the utility pane (the thread view pane).
26 ///
27 /// Default: left
28 pub agents_panel_dock: Option<DockSide>,
29 /// Default width in pixels when the agent panel is docked to the left or right.
30 ///
31 /// Default: 640
32 #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
33 pub default_width: Option<f32>,
34 /// Default height in pixels when the agent panel is docked to the bottom.
35 ///
36 /// Default: 320
37 #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
38 pub default_height: Option<f32>,
39 /// The default model to use when creating new chats and for other features when a specific model is not specified.
40 pub default_model: Option<LanguageModelSelection>,
41 /// Favorite models to show at the top of the model selector.
42 #[serde(default)]
43 pub favorite_models: Vec<LanguageModelSelection>,
44 /// Model to use for the inline assistant. Defaults to default_model when not specified.
45 pub inline_assistant_model: Option<LanguageModelSelection>,
46 /// Model to use for the inline assistant when streaming tools are enabled.
47 ///
48 /// Default: true
49 pub inline_assistant_use_streaming_tools: Option<bool>,
50 /// Model to use for generating git commit messages.
51 ///
52 /// Default: true
53 pub commit_message_model: Option<LanguageModelSelection>,
54 /// Model to use for generating thread summaries. Defaults to default_model when not specified.
55 pub thread_summary_model: Option<LanguageModelSelection>,
56 /// Additional models with which to generate alternatives when performing inline assists.
57 pub inline_alternatives: Option<Vec<LanguageModelSelection>>,
58 /// The default profile to use in the Agent.
59 ///
60 /// Default: write
61 pub default_profile: Option<Arc<str>>,
62 /// Which view type to show by default in the agent panel.
63 ///
64 /// Default: "thread"
65 pub default_view: Option<DefaultAgentView>,
66 /// The available agent profiles.
67 pub profiles: Option<IndexMap<Arc<str>, AgentProfileContent>>,
68 /// Whenever a tool action would normally wait for your confirmation
69 /// that you allow it, always choose to allow it.
70 ///
71 /// This setting has no effect on external agents that support permission modes, such as Claude Code.
72 ///
73 /// Set `agent_servers.claude.default_mode` to `bypassPermissions`, to disable all permission requests when using Claude Code.
74 ///
75 /// Default: false
76 pub always_allow_tool_actions: Option<bool>,
77 /// Where to show a popup notification when the agent is waiting for user input.
78 ///
79 /// Default: "primary_screen"
80 pub notify_when_agent_waiting: Option<NotifyWhenAgentWaiting>,
81 /// Whether to play a sound when the agent has either completed its response, or needs user input.
82 ///
83 /// Default: false
84 pub play_sound_when_agent_done: Option<bool>,
85 /// Whether to display agent edits in single-file editors in addition to the review multibuffer pane.
86 ///
87 /// Default: true
88 pub single_file_review: Option<bool>,
89 /// Additional parameters for language model requests. When making a request
90 /// to a model, parameters will be taken from the last entry in this list
91 /// that matches the model's provider and name. In each entry, both provider
92 /// and model are optional, so that you can specify parameters for either
93 /// one.
94 ///
95 /// Default: []
96 #[serde(default)]
97 pub model_parameters: Vec<LanguageModelParameters>,
98 /// What completion mode to enable for new threads
99 ///
100 /// Default: normal
101 pub preferred_completion_mode: Option<CompletionMode>,
102 /// Whether to show thumb buttons for feedback in the agent panel.
103 ///
104 /// Default: true
105 pub enable_feedback: Option<bool>,
106 /// Whether to have edit cards in the agent panel expanded, showing a preview of the full diff.
107 ///
108 /// Default: true
109 pub expand_edit_card: Option<bool>,
110 /// Whether to have terminal cards in the agent panel expanded, showing the whole command output.
111 ///
112 /// Default: true
113 pub expand_terminal_card: Option<bool>,
114 /// Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages in the agent panel.
115 ///
116 /// Default: false
117 pub use_modifier_to_send: Option<bool>,
118 /// Minimum number of lines of height the agent message editor should have.
119 ///
120 /// Default: 4
121 pub message_editor_min_lines: Option<usize>,
122}
123
124impl AgentSettingsContent {
125 pub fn set_dock(&mut self, dock: DockPosition) {
126 self.dock = Some(dock);
127 }
128
129 pub fn set_model(&mut self, language_model: LanguageModelSelection) {
130 // let model = language_model.id().0.to_string();
131 // let provider = language_model.provider_id().0.to_string();
132 // self.default_model = Some(LanguageModelSelection {
133 // provider: provider.into(),
134 // model,
135 // });
136 self.default_model = Some(language_model)
137 }
138
139 pub fn set_inline_assistant_model(&mut self, provider: String, model: String) {
140 self.inline_assistant_model = Some(LanguageModelSelection {
141 provider: provider.into(),
142 model,
143 });
144 }
145 pub fn set_inline_assistant_use_streaming_tools(&mut self, use_tools: bool) {
146 self.inline_assistant_use_streaming_tools = Some(use_tools);
147 }
148
149 pub fn set_commit_message_model(&mut self, provider: String, model: String) {
150 self.commit_message_model = Some(LanguageModelSelection {
151 provider: provider.into(),
152 model,
153 });
154 }
155
156 pub fn set_thread_summary_model(&mut self, provider: String, model: String) {
157 self.thread_summary_model = Some(LanguageModelSelection {
158 provider: provider.into(),
159 model,
160 });
161 }
162
163 pub fn set_always_allow_tool_actions(&mut self, allow: bool) {
164 self.always_allow_tool_actions = Some(allow);
165 }
166
167 pub fn set_play_sound_when_agent_done(&mut self, allow: bool) {
168 self.play_sound_when_agent_done = Some(allow);
169 }
170
171 pub fn set_single_file_review(&mut self, allow: bool) {
172 self.single_file_review = Some(allow);
173 }
174
175 pub fn set_use_modifier_to_send(&mut self, always_use: bool) {
176 self.use_modifier_to_send = Some(always_use);
177 }
178
179 pub fn set_profile(&mut self, profile_id: Arc<str>) {
180 self.default_profile = Some(profile_id);
181 }
182
183 pub fn add_favorite_model(&mut self, model: LanguageModelSelection) {
184 if !self.favorite_models.contains(&model) {
185 self.favorite_models.push(model);
186 }
187 }
188
189 pub fn remove_favorite_model(&mut self, model: &LanguageModelSelection) {
190 self.favorite_models.retain(|m| m != model);
191 }
192}
193
194#[with_fallible_options]
195#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
196pub struct AgentProfileContent {
197 pub name: Arc<str>,
198 #[serde(default)]
199 pub tools: IndexMap<Arc<str>, bool>,
200 /// Whether all context servers are enabled by default.
201 pub enable_all_context_servers: Option<bool>,
202 #[serde(default)]
203 pub context_servers: IndexMap<Arc<str>, ContextServerPresetContent>,
204 /// The default language model selected when using this profile.
205 pub default_model: Option<LanguageModelSelection>,
206}
207
208#[with_fallible_options]
209#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
210pub struct ContextServerPresetContent {
211 pub tools: IndexMap<Arc<str>, bool>,
212}
213
214#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
215#[serde(rename_all = "snake_case")]
216pub enum DefaultAgentView {
217 #[default]
218 Thread,
219 TextThread,
220}
221
222#[derive(
223 Copy,
224 Clone,
225 Default,
226 Debug,
227 Serialize,
228 Deserialize,
229 JsonSchema,
230 MergeFrom,
231 PartialEq,
232 strum::VariantArray,
233 strum::VariantNames,
234)]
235#[serde(rename_all = "snake_case")]
236pub enum NotifyWhenAgentWaiting {
237 #[default]
238 PrimaryScreen,
239 AllScreens,
240 Never,
241}
242
243#[with_fallible_options]
244#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
245pub struct LanguageModelSelection {
246 pub provider: LanguageModelProviderSetting,
247 pub model: String,
248}
249
250#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Default)]
251#[serde(rename_all = "snake_case")]
252pub enum CompletionMode {
253 #[default]
254 Normal,
255 #[serde(alias = "max")]
256 Burn,
257}
258
259#[with_fallible_options]
260#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
261pub struct LanguageModelParameters {
262 pub provider: Option<LanguageModelProviderSetting>,
263 pub model: Option<SharedString>,
264 #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
265 pub temperature: Option<f32>,
266}
267
268#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, MergeFrom)]
269pub struct LanguageModelProviderSetting(pub String);
270
271impl JsonSchema for LanguageModelProviderSetting {
272 fn schema_name() -> Cow<'static, str> {
273 "LanguageModelProviderSetting".into()
274 }
275
276 fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
277 // list the builtin providers as a subset so that we still auto complete them in the settings
278 json_schema!({
279 "anyOf": [
280 {
281 "type": "string",
282 "enum": [
283 "amazon-bedrock",
284 "anthropic",
285 "copilot_chat",
286 "deepseek",
287 "google",
288 "lmstudio",
289 "mistral",
290 "ollama",
291 "openai",
292 "openrouter",
293 "vercel",
294 "x_ai",
295 "zed.dev"
296 ]
297 },
298 {
299 "type": "string",
300 }
301 ]
302 })
303 }
304}
305
306impl From<String> for LanguageModelProviderSetting {
307 fn from(provider: String) -> Self {
308 Self(provider)
309 }
310}
311
312impl From<&str> for LanguageModelProviderSetting {
313 fn from(provider: &str) -> Self {
314 Self(provider.to_string())
315 }
316}
317
318#[with_fallible_options]
319#[derive(Default, PartialEq, Deserialize, Serialize, Clone, JsonSchema, MergeFrom, Debug)]
320pub struct AllAgentServersSettings {
321 pub gemini: Option<BuiltinAgentServerSettings>,
322 pub claude: Option<BuiltinAgentServerSettings>,
323 pub codex: Option<BuiltinAgentServerSettings>,
324
325 /// Custom agent servers configured by the user
326 #[serde(flatten)]
327 pub custom: HashMap<SharedString, CustomAgentServerSettings>,
328}
329
330#[with_fallible_options]
331#[derive(Default, Deserialize, Serialize, Clone, JsonSchema, MergeFrom, Debug, PartialEq)]
332pub struct BuiltinAgentServerSettings {
333 /// Absolute path to a binary to be used when launching this agent.
334 ///
335 /// This can be used to run a specific binary without automatic downloads or searching `$PATH`.
336 #[serde(rename = "command")]
337 pub path: Option<PathBuf>,
338 /// If a binary is specified in `command`, it will be passed these arguments.
339 pub args: Option<Vec<String>>,
340 /// If a binary is specified in `command`, it will be passed these environment variables.
341 pub env: Option<HashMap<String, String>>,
342 /// Whether to skip searching `$PATH` for an agent server binary when
343 /// launching this agent.
344 ///
345 /// This has no effect if a `command` is specified. Otherwise, when this is
346 /// `false`, Zed will search `$PATH` for an agent server binary and, if one
347 /// is found, use it for threads with this agent. If no agent binary is
348 /// found on `$PATH`, Zed will automatically install and use its own binary.
349 /// When this is `true`, Zed will not search `$PATH`, and will always use
350 /// its own binary.
351 ///
352 /// Default: true
353 pub ignore_system_version: Option<bool>,
354 /// The default mode to use for this agent.
355 ///
356 /// Note: Not only all agents support modes.
357 ///
358 /// Default: None
359 pub default_mode: Option<String>,
360 /// The default model to use for this agent.
361 ///
362 /// This should be the model ID as reported by the agent.
363 ///
364 /// Default: None
365 pub default_model: Option<String>,
366 /// The favorite models for this agent.
367 ///
368 /// These are the model IDs as reported by the agent.
369 ///
370 /// Default: []
371 #[serde(default)]
372 pub favorite_models: Vec<String>,
373 /// Default values for session config options.
374 ///
375 /// This is a map from config option ID to value ID.
376 ///
377 /// Default: {}
378 #[serde(default)]
379 pub default_config_options: HashMap<String, String>,
380 /// Favorited values for session config options.
381 ///
382 /// This is a map from config option ID to a list of favorited value IDs.
383 ///
384 /// Default: {}
385 #[serde(default)]
386 pub favorite_config_option_values: HashMap<String, Vec<String>>,
387}
388
389#[with_fallible_options]
390#[derive(Deserialize, Serialize, Clone, JsonSchema, MergeFrom, Debug, PartialEq)]
391#[serde(tag = "type", rename_all = "snake_case")]
392pub enum CustomAgentServerSettings {
393 Custom {
394 #[serde(rename = "command")]
395 path: PathBuf,
396 #[serde(default)]
397 args: Vec<String>,
398 env: Option<HashMap<String, String>>,
399 /// The default mode to use for this agent.
400 ///
401 /// Note: Not only all agents support modes.
402 ///
403 /// Default: None
404 default_mode: Option<String>,
405 /// The default model to use for this agent.
406 ///
407 /// This should be the model ID as reported by the agent.
408 ///
409 /// Default: None
410 default_model: Option<String>,
411 /// The favorite models for this agent.
412 ///
413 /// These are the model IDs as reported by the agent.
414 ///
415 /// Default: []
416 #[serde(default)]
417 favorite_models: Vec<String>,
418 /// Default values for session config options.
419 ///
420 /// This is a map from config option ID to value ID.
421 ///
422 /// Default: {}
423 #[serde(default)]
424 default_config_options: HashMap<String, String>,
425 /// Favorited values for session config options.
426 ///
427 /// This is a map from config option ID to a list of favorited value IDs.
428 ///
429 /// Default: {}
430 #[serde(default)]
431 favorite_config_option_values: HashMap<String, Vec<String>>,
432 },
433 Extension {
434 /// The default mode to use for this agent.
435 ///
436 /// Note: Not only all agents support modes.
437 ///
438 /// Default: None
439 default_mode: Option<String>,
440 /// The default model to use for this agent.
441 ///
442 /// This should be the model ID as reported by the agent.
443 ///
444 /// Default: None
445 default_model: Option<String>,
446 /// The favorite models for this agent.
447 ///
448 /// These are the model IDs as reported by the agent.
449 ///
450 /// Default: []
451 #[serde(default)]
452 favorite_models: Vec<String>,
453 /// Default values for session config options.
454 ///
455 /// This is a map from config option ID to value ID.
456 ///
457 /// Default: {}
458 #[serde(default)]
459 default_config_options: HashMap<String, String>,
460 /// Favorited values for session config options.
461 ///
462 /// This is a map from config option ID to a list of favorited value IDs.
463 ///
464 /// Default: {}
465 #[serde(default)]
466 favorite_config_option_values: HashMap<String, Vec<String>>,
467 },
468}