agent.rs

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