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    /// 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                        "copilot_chat",
272                        "deepseek",
273                        "google",
274                        "lmstudio",
275                        "mistral",
276                        "ollama",
277                        "openai",
278                        "openrouter",
279                        "vercel",
280                        "x_ai",
281                        "zed.dev"
282                    ]
283                },
284                {
285                    "type": "string",
286                }
287            ]
288        })
289    }
290}
291
292impl From<String> for LanguageModelProviderSetting {
293    fn from(provider: String) -> Self {
294        Self(provider)
295    }
296}
297
298impl From<&str> for LanguageModelProviderSetting {
299    fn from(provider: &str) -> Self {
300        Self(provider.to_string())
301    }
302}
303
304#[with_fallible_options]
305#[derive(Default, PartialEq, Deserialize, Serialize, Clone, JsonSchema, MergeFrom, Debug)]
306pub struct AllAgentServersSettings {
307    pub gemini: Option<BuiltinAgentServerSettings>,
308    pub claude: Option<BuiltinAgentServerSettings>,
309    pub codex: Option<BuiltinAgentServerSettings>,
310
311    /// Custom agent servers configured by the user
312    #[serde(flatten)]
313    pub custom: HashMap<SharedString, CustomAgentServerSettings>,
314}
315
316#[with_fallible_options]
317#[derive(Default, Deserialize, Serialize, Clone, JsonSchema, MergeFrom, Debug, PartialEq)]
318pub struct BuiltinAgentServerSettings {
319    /// Absolute path to a binary to be used when launching this agent.
320    ///
321    /// This can be used to run a specific binary without automatic downloads or searching `$PATH`.
322    #[serde(rename = "command")]
323    pub path: Option<PathBuf>,
324    /// If a binary is specified in `command`, it will be passed these arguments.
325    pub args: Option<Vec<String>>,
326    /// If a binary is specified in `command`, it will be passed these environment variables.
327    pub env: Option<HashMap<String, String>>,
328    /// Whether to skip searching `$PATH` for an agent server binary when
329    /// launching this agent.
330    ///
331    /// This has no effect if a `command` is specified. Otherwise, when this is
332    /// `false`, Zed will search `$PATH` for an agent server binary and, if one
333    /// is found, use it for threads with this agent. If no agent binary is
334    /// found on `$PATH`, Zed will automatically install and use its own binary.
335    /// When this is `true`, Zed will not search `$PATH`, and will always use
336    /// its own binary.
337    ///
338    /// Default: true
339    pub ignore_system_version: Option<bool>,
340    /// The default mode to use for this agent.
341    ///
342    /// Note: Not only all agents support modes.
343    ///
344    /// Default: None
345    pub default_mode: Option<String>,
346    /// The default model to use for this agent.
347    ///
348    /// This should be the model ID as reported by the agent.
349    ///
350    /// Default: None
351    pub default_model: Option<String>,
352}
353
354#[with_fallible_options]
355#[derive(Deserialize, Serialize, Clone, JsonSchema, MergeFrom, Debug, PartialEq)]
356#[serde(tag = "type", rename_all = "snake_case")]
357pub enum CustomAgentServerSettings {
358    Custom {
359        #[serde(rename = "command")]
360        path: PathBuf,
361        #[serde(default)]
362        args: Vec<String>,
363        env: Option<HashMap<String, String>>,
364        /// The default mode to use for this agent.
365        ///
366        /// Note: Not only all agents support modes.
367        ///
368        /// Default: None
369        default_mode: Option<String>,
370        /// The default model to use for this agent.
371        ///
372        /// This should be the model ID as reported by the agent.
373        ///
374        /// Default: None
375        default_model: Option<String>,
376    },
377    Extension {
378        /// The default mode to use for this agent.
379        ///
380        /// Note: Not only all agents support modes.
381        ///
382        /// Default: None
383        default_mode: Option<String>,
384        /// The default model to use for this agent.
385        ///
386        /// This should be the model ID as reported by the agent.
387        ///
388        /// Default: None
389        default_model: Option<String>,
390    },
391}