agent.rs

  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 generating git commit messages. Defaults to default_model when not specified.
 40    pub commit_message_model: Option<LanguageModelSelection>,
 41    /// Model to use for generating thread summaries. Defaults to default_model when not specified.
 42    pub thread_summary_model: Option<LanguageModelSelection>,
 43    /// Additional models with which to generate alternatives when performing inline assists.
 44    pub inline_alternatives: Option<Vec<LanguageModelSelection>>,
 45    /// The default profile to use in the Agent.
 46    ///
 47    /// Default: write
 48    pub default_profile: Option<Arc<str>>,
 49    /// Which view type to show by default in the agent panel.
 50    ///
 51    /// Default: "thread"
 52    pub default_view: Option<DefaultAgentView>,
 53    /// The available agent profiles.
 54    pub profiles: Option<IndexMap<Arc<str>, AgentProfileContent>>,
 55    /// Whenever a tool action would normally wait for your confirmation
 56    /// that you allow it, always choose to allow it.
 57    ///
 58    /// This setting has no effect on external agents that support permission modes, such as Claude Code.
 59    ///
 60    /// Set `agent_servers.claude.default_mode` to `bypassPermissions`, to disable all permission requests when using Claude Code.
 61    ///
 62    /// Default: false
 63    pub always_allow_tool_actions: Option<bool>,
 64    /// Where to show a popup notification when the agent is waiting for user input.
 65    ///
 66    /// Default: "primary_screen"
 67    pub notify_when_agent_waiting: Option<NotifyWhenAgentWaiting>,
 68    /// Whether to play a sound when the agent has either completed its response, or needs user input.
 69    ///
 70    /// Default: false
 71    pub play_sound_when_agent_done: Option<bool>,
 72    /// Whether to display agent edits in single-file editors in addition to the review multibuffer pane.
 73    ///
 74    /// Default: true
 75    pub single_file_review: Option<bool>,
 76    /// Additional parameters for language model requests. When making a request
 77    /// to a model, parameters will be taken from the last entry in this list
 78    /// that matches the model's provider and name. In each entry, both provider
 79    /// and model are optional, so that you can specify parameters for either
 80    /// one.
 81    ///
 82    /// Default: []
 83    #[serde(default)]
 84    pub model_parameters: Vec<LanguageModelParameters>,
 85    /// What completion mode to enable for new threads
 86    ///
 87    /// Default: normal
 88    pub preferred_completion_mode: Option<CompletionMode>,
 89    /// Whether to show thumb buttons for feedback in the agent panel.
 90    ///
 91    /// Default: true
 92    pub enable_feedback: Option<bool>,
 93    /// Whether to have edit cards in the agent panel expanded, showing a preview of the full diff.
 94    ///
 95    /// Default: true
 96    pub expand_edit_card: Option<bool>,
 97    /// Whether to have terminal cards in the agent panel expanded, showing the whole command output.
 98    ///
 99    /// Default: true
100    pub expand_terminal_card: Option<bool>,
101    /// Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages in the agent panel.
102    ///
103    /// Default: false
104    pub use_modifier_to_send: Option<bool>,
105    /// Minimum number of lines of height the agent message editor should have.
106    ///
107    /// Default: 4
108    pub message_editor_min_lines: Option<usize>,
109}
110
111impl AgentSettingsContent {
112    pub fn set_dock(&mut self, dock: DockPosition) {
113        self.dock = Some(dock);
114    }
115
116    pub fn set_model(&mut self, language_model: LanguageModelSelection) {
117        // let model = language_model.id().0.to_string();
118        // let provider = language_model.provider_id().0.to_string();
119        // self.default_model = Some(LanguageModelSelection {
120        //     provider: provider.into(),
121        //     model,
122        // });
123        self.default_model = Some(language_model)
124    }
125
126    pub fn set_inline_assistant_model(&mut self, provider: String, model: String) {
127        self.inline_assistant_model = Some(LanguageModelSelection {
128            provider: provider.into(),
129            model,
130        });
131    }
132
133    pub fn set_commit_message_model(&mut self, provider: String, model: String) {
134        self.commit_message_model = Some(LanguageModelSelection {
135            provider: provider.into(),
136            model,
137        });
138    }
139
140    pub fn set_thread_summary_model(&mut self, provider: String, model: String) {
141        self.thread_summary_model = Some(LanguageModelSelection {
142            provider: provider.into(),
143            model,
144        });
145    }
146
147    pub fn set_always_allow_tool_actions(&mut self, allow: bool) {
148        self.always_allow_tool_actions = Some(allow);
149    }
150
151    pub fn set_play_sound_when_agent_done(&mut self, allow: bool) {
152        self.play_sound_when_agent_done = Some(allow);
153    }
154
155    pub fn set_single_file_review(&mut self, allow: bool) {
156        self.single_file_review = Some(allow);
157    }
158
159    pub fn set_use_modifier_to_send(&mut self, always_use: bool) {
160        self.use_modifier_to_send = Some(always_use);
161    }
162
163    pub fn set_profile(&mut self, profile_id: Arc<str>) {
164        self.default_profile = Some(profile_id);
165    }
166}
167
168#[with_fallible_options]
169#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
170pub struct AgentProfileContent {
171    pub name: Arc<str>,
172    #[serde(default)]
173    pub tools: IndexMap<Arc<str>, bool>,
174    /// Whether all context servers are enabled by default.
175    pub enable_all_context_servers: Option<bool>,
176    #[serde(default)]
177    pub context_servers: IndexMap<Arc<str>, ContextServerPresetContent>,
178    /// The default language model selected when using this profile.
179    pub default_model: Option<LanguageModelSelection>,
180}
181
182#[with_fallible_options]
183#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
184pub struct ContextServerPresetContent {
185    pub tools: IndexMap<Arc<str>, bool>,
186}
187
188#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
189#[serde(rename_all = "snake_case")]
190pub enum DefaultAgentView {
191    #[default]
192    Thread,
193    TextThread,
194}
195
196#[derive(
197    Copy,
198    Clone,
199    Default,
200    Debug,
201    Serialize,
202    Deserialize,
203    JsonSchema,
204    MergeFrom,
205    PartialEq,
206    strum::VariantArray,
207    strum::VariantNames,
208)]
209#[serde(rename_all = "snake_case")]
210pub enum NotifyWhenAgentWaiting {
211    #[default]
212    PrimaryScreen,
213    AllScreens,
214    Never,
215}
216
217#[with_fallible_options]
218#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
219pub struct LanguageModelSelection {
220    pub provider: LanguageModelProviderSetting,
221    pub model: String,
222}
223
224#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Default)]
225#[serde(rename_all = "snake_case")]
226pub enum CompletionMode {
227    #[default]
228    Normal,
229    #[serde(alias = "max")]
230    Burn,
231}
232
233#[with_fallible_options]
234#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
235pub struct LanguageModelParameters {
236    pub provider: Option<LanguageModelProviderSetting>,
237    pub model: Option<SharedString>,
238    #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
239    pub temperature: Option<f32>,
240}
241
242#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, MergeFrom)]
243pub struct LanguageModelProviderSetting(pub String);
244
245impl JsonSchema for LanguageModelProviderSetting {
246    fn schema_name() -> Cow<'static, str> {
247        "LanguageModelProviderSetting".into()
248    }
249
250    fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
251        // list the builtin providers as a subset so that we still auto complete them in the settings
252        json_schema!({
253            "anyOf": [
254                {
255                    "type": "string",
256                    "enum": [
257                        "amazon-bedrock",
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#[with_fallible_options]
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#[with_fallible_options]
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    /// The default model to use for this agent.
334    ///
335    /// This should be the model ID as reported by the agent.
336    ///
337    /// Default: None
338    pub default_model: Option<String>,
339}
340
341#[with_fallible_options]
342#[derive(Deserialize, Serialize, Clone, JsonSchema, MergeFrom, Debug, PartialEq)]
343#[serde(tag = "type", rename_all = "snake_case")]
344pub enum CustomAgentServerSettings {
345    Custom {
346        #[serde(rename = "command")]
347        path: PathBuf,
348        #[serde(default)]
349        args: Vec<String>,
350        env: Option<HashMap<String, String>>,
351        /// The default mode to use for this agent.
352        ///
353        /// Note: Not only all agents support modes.
354        ///
355        /// Default: None
356        default_mode: Option<String>,
357        /// The default model to use for this agent.
358        ///
359        /// This should be the model ID as reported by the agent.
360        ///
361        /// Default: None
362        default_model: Option<String>,
363    },
364    Extension {
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}