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