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