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 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}