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