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, 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}
374
375#[with_fallible_options]
376#[derive(Deserialize, Serialize, Clone, JsonSchema, MergeFrom, Debug, PartialEq)]
377#[serde(tag = "type", rename_all = "snake_case")]
378pub enum CustomAgentServerSettings {
379    Custom {
380        #[serde(rename = "command")]
381        path: PathBuf,
382        #[serde(default)]
383        args: Vec<String>,
384        env: Option<HashMap<String, String>>,
385        /// The default mode to use for this agent.
386        ///
387        /// Note: Not only all agents support modes.
388        ///
389        /// Default: None
390        default_mode: Option<String>,
391        /// The default model to use for this agent.
392        ///
393        /// This should be the model ID as reported by the agent.
394        ///
395        /// Default: None
396        default_model: Option<String>,
397        /// The favorite models for this agent.
398        ///
399        /// These are the model IDs as reported by the agent.
400        ///
401        /// Default: []
402        #[serde(default)]
403        favorite_models: Vec<String>,
404    },
405    Extension {
406        /// The default mode to use for this agent.
407        ///
408        /// Note: Not only all agents support modes.
409        ///
410        /// Default: None
411        default_mode: Option<String>,
412        /// The default model to use for this agent.
413        ///
414        /// This should be the model ID as reported by the agent.
415        ///
416        /// Default: None
417        default_model: Option<String>,
418        /// The favorite models for this agent.
419        ///
420        /// These are the model IDs as reported by the agent.
421        ///
422        /// Default: []
423        #[serde(default)]
424        favorite_models: Vec<String>,
425    },
426}