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