mod agent_profile; use std::sync::Arc; use ::open_ai::Model as OpenAiModel;use anthropic::Model as AnthropicModel;use anyhow::{Result, bail};use deepseek::Model as DeepseekModel;use feature_flags::{Assistant2FeatureFlag, FeatureFlagAppExt};use gpui::{App, Pixels};use indexmap::IndexMap;use language_model::{CloudModel, LanguageModel};use lmstudio::Model as LmStudioModel;use ollama::Model as OllamaModel;use schemars::{JsonSchema, schema::Schema};use serde::{Deserialize, Serialize};use settings::{Settings, SettingsSources}; pub use crate::agent_profile::*; #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum AssistantDockPosition { Left, #[default] Right, Bottom,} #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]#[serde(rename_all = "snake_case")]pub enum NotifyWhenAgentWaiting { #[default] PrimaryScreen, AllScreens, Never,} #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]#[serde(tag = "name", rename_all = "snake_case")]pub enum AssistantProviderContentV1 { #[serde(rename = "zed.dev")] ZedDotDev { default_model: Option<CloudModel> }, #[serde(rename = "openai")] OpenAi { default_model: Option<OpenAiModel>, api_url: Option<String>, available_models: Option<Vec<OpenAiModel>>, }, #[serde(rename = "anthropic")] Anthropic { default_model: Option<AnthropicModel>, api_url: Option<String>, }, #[serde(rename = "ollama")] Ollama { default_model: Option<OllamaModel>, api_url: Option<String>, }, #[serde(rename = "lmstudio")] LmStudio { default_model: Option<LmStudioModel>, api_url: Option<String>, }, #[serde(rename = "deepseek")] DeepSeek { default_model: Option<DeepseekModel>, api_url: Option<String>, },} #[derive(Clone, Debug, Default)]pub struct AssistantSettings { pub enabled: bool, pub button: bool, pub dock: AssistantDockPosition, pub default_width: Pixels, pub default_height: Pixels, pub default_model: LanguageModelSelection, pub inline_assistant_model: Option<LanguageModelSelection>, pub commit_message_model: Option<LanguageModelSelection>, pub thread_summary_model: Option<LanguageModelSelection>, pub inline_alternatives: Vec<LanguageModelSelection>, pub using_outdated_settings_version: bool, pub enable_experimental_live_diffs: bool, pub default_profile: AgentProfileId, pub profiles: IndexMap<AgentProfileId, AgentProfile>, pub always_allow_tool_actions: bool, pub notify_when_agent_waiting: NotifyWhenAgentWaiting,} impl AssistantSettings { pub fn are_live_diffs_enabled(&self, cx: &App) -> bool { if cx.has_flag::<Assistant2FeatureFlag>() { return false; } cx.is_staff() || self.enable_experimental_live_diffs } pub fn set_inline_assistant_model(&mut self, provider: String, model: String) { self.inline_assistant_model = Some(LanguageModelSelection { provider, model }); } pub fn set_commit_message_model(&mut self, provider: String, model: String) { self.commit_message_model = Some(LanguageModelSelection { provider, model }); } pub fn set_thread_summary_model(&mut self, provider: String, model: String) { self.thread_summary_model = Some(LanguageModelSelection { provider, model }); }} /// Assistant panel settings#[derive(Clone, Serialize, Deserialize, Debug)]#[serde(untagged)]pub enum AssistantSettingsContent { Versioned(Box<VersionedAssistantSettingsContent>), Legacy(LegacyAssistantSettingsContent),} impl JsonSchema for AssistantSettingsContent { fn schema_name() -> String { VersionedAssistantSettingsContent::schema_name() } fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> Schema { VersionedAssistantSettingsContent::json_schema(r#gen) } fn is_referenceable() -> bool { VersionedAssistantSettingsContent::is_referenceable() }} impl Default for AssistantSettingsContent { fn default() -> Self { Self::Versioned(Box::new(VersionedAssistantSettingsContent::default())) }} impl AssistantSettingsContent { pub fn is_version_outdated(&self) -> bool { match self { AssistantSettingsContent::Versioned(settings) => match **settings { VersionedAssistantSettingsContent::V1(_) => true, VersionedAssistantSettingsContent::V2(_) => false, }, AssistantSettingsContent::Legacy(_) => true, } } fn upgrade(&self) -> AssistantSettingsContentV2 { match self { AssistantSettingsContent::Versioned(settings) => match **settings { VersionedAssistantSettingsContent::V1(ref settings) => AssistantSettingsContentV2 { enabled: settings.enabled, button: settings.button, dock: settings.dock, default_width: settings.default_width, default_height: settings.default_width, default_model: settings .provider .clone() .and_then(|provider| match provider { AssistantProviderContentV1::ZedDotDev { default_model } => { default_model.map(|model| LanguageModelSelection { provider: "zed.dev".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::OpenAi { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "openai".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::Anthropic { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "anthropic".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::Ollama { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "ollama".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::LmStudio { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "lmstudio".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::DeepSeek { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "deepseek".to_string(), model: model.id().to_string(), }) } }), inline_assistant_model: None, commit_message_model: None, thread_summary_model: None, inline_alternatives: None, enable_experimental_live_diffs: None, default_profile: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, }, VersionedAssistantSettingsContent::V2(ref settings) => settings.clone(), }, AssistantSettingsContent::Legacy(settings) => AssistantSettingsContentV2 { enabled: None, button: settings.button, dock: settings.dock, default_width: settings.default_width, default_height: settings.default_height, default_model: Some(LanguageModelSelection { provider: "openai".to_string(), model: settings .default_open_ai_model .clone() .unwrap_or_default() .id() .to_string(), }), inline_assistant_model: None, commit_message_model: None, thread_summary_model: None, inline_alternatives: None, enable_experimental_live_diffs: None, default_profile: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, }, } } pub fn set_dock(&mut self, dock: AssistantDockPosition) { match self { AssistantSettingsContent::Versioned(settings) => match **settings { VersionedAssistantSettingsContent::V1(ref mut settings) => { settings.dock = Some(dock); } VersionedAssistantSettingsContent::V2(ref mut settings) => { settings.dock = Some(dock); } }, AssistantSettingsContent::Legacy(settings) => { settings.dock = Some(dock); } } } pub fn set_model(&mut self, language_model: Arc<dyn LanguageModel>) { let model = language_model.id().0.to_string(); let provider = language_model.provider_id().0.to_string(); match self { AssistantSettingsContent::Versioned(settings) => match **settings { VersionedAssistantSettingsContent::V1(ref mut settings) => { match provider.as_ref() { "zed.dev" => { log::warn!("attempted to set zed.dev model on outdated settings"); } "anthropic" => { let api_url = match &settings.provider { Some(AssistantProviderContentV1::Anthropic { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AssistantProviderContentV1::Anthropic { default_model: AnthropicModel::from_id(&model).ok(), api_url, }); } "ollama" => { let api_url = match &settings.provider { Some(AssistantProviderContentV1::Ollama { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AssistantProviderContentV1::Ollama { default_model: Some(ollama::Model::new(&model, None, None)), api_url, }); } "lmstudio" => { let api_url = match &settings.provider { Some(AssistantProviderContentV1::LmStudio { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AssistantProviderContentV1::LmStudio { default_model: Some(lmstudio::Model::new(&model, None, None)), api_url, }); } "openai" => { let (api_url, available_models) = match &settings.provider { Some(AssistantProviderContentV1::OpenAi { api_url, available_models, .. }) => (api_url.clone(), available_models.clone()), _ => (None, None), }; settings.provider = Some(AssistantProviderContentV1::OpenAi { default_model: OpenAiModel::from_id(&model).ok(), api_url, available_models, }); } "deepseek" => { let api_url = match &settings.provider { Some(AssistantProviderContentV1::DeepSeek { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AssistantProviderContentV1::DeepSeek { default_model: DeepseekModel::from_id(&model).ok(), api_url, }); } _ => {} } } VersionedAssistantSettingsContent::V2(ref mut settings) => { settings.default_model = Some(LanguageModelSelection { provider, model }); } }, AssistantSettingsContent::Legacy(settings) => { if let Ok(model) = OpenAiModel::from_id(&language_model.id().0) { settings.default_open_ai_model = Some(model); } } } } pub fn set_inline_assistant_model(&mut self, provider: String, model: String) { if let AssistantSettingsContent::Versioned(boxed) = self { if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.inline_assistant_model = Some(LanguageModelSelection { provider, model }); } } } pub fn set_commit_message_model(&mut self, provider: String, model: String) { if let AssistantSettingsContent::Versioned(boxed) = self { if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.commit_message_model = Some(LanguageModelSelection { provider, model }); } } } pub fn set_thread_summary_model(&mut self, provider: String, model: String) { if let AssistantSettingsContent::Versioned(boxed) = self { if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.thread_summary_model = Some(LanguageModelSelection { provider, model }); } } } pub fn set_always_allow_tool_actions(&mut self, allow: bool) { let AssistantSettingsContent::Versioned(boxed) = self else { return; }; if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.always_allow_tool_actions = Some(allow); } } pub fn set_profile(&mut self, profile_id: AgentProfileId) { let AssistantSettingsContent::Versioned(boxed) = self else { return; }; if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.default_profile = Some(profile_id); } } pub fn create_profile( &mut self, profile_id: AgentProfileId, profile: AgentProfile, ) -> Result<()> { let AssistantSettingsContent::Versioned(boxed) = self else { return Ok(()); }; if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { let profiles = settings.profiles.get_or_insert_default(); if profiles.contains_key(&profile_id) { bail!("profile with ID '{profile_id}' already exists"); } profiles.insert( profile_id, AgentProfileContent { name: profile.name.into(), tools: profile.tools, enable_all_context_servers: Some(profile.enable_all_context_servers), context_servers: profile .context_servers .into_iter() .map(|(server_id, preset)| { ( server_id, ContextServerPresetContent { tools: preset.tools, }, ) }) .collect(), }, ); } Ok(()) }} #[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]#[serde(tag = "version")]pub enum VersionedAssistantSettingsContent { #[serde(rename = "1")] V1(AssistantSettingsContentV1), #[serde(rename = "2")] V2(AssistantSettingsContentV2),} impl Default for VersionedAssistantSettingsContent { fn default() -> Self { Self::V2(AssistantSettingsContentV2 { enabled: None, button: None, dock: None, default_width: None, default_height: None, default_model: None, inline_assistant_model: None, commit_message_model: None, thread_summary_model: None, inline_alternatives: None, enable_experimental_live_diffs: None, default_profile: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, }) }} #[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]pub struct AssistantSettingsContentV2 { /// Whether the Assistant is enabled. /// /// Default: true enabled: Option<bool>, /// Whether to show the assistant panel button in the status bar. /// /// Default: true button: Option<bool>, /// Where to dock the assistant. /// /// Default: right dock: Option<AssistantDockPosition>, /// Default width in pixels when the assistant is docked to the left or right. /// /// Default: 640 default_width: Option<f32>, /// Default height in pixels when the assistant is docked to the bottom. /// /// Default: 320 default_height: Option<f32>, /// The default model to use when creating new chats and for other features when a specific model is not specified. default_model: Option<LanguageModelSelection>, /// Model to use for the inline assistant. Defaults to default_model when not specified. inline_assistant_model: Option<LanguageModelSelection>, /// Model to use for generating git commit messages. Defaults to default_model when not specified. commit_message_model: Option<LanguageModelSelection>, /// Model to use for generating thread summaries. Defaults to default_model when not specified. thread_summary_model: Option<LanguageModelSelection>, /// Additional models with which to generate alternatives when performing inline assists. inline_alternatives: Option<Vec<LanguageModelSelection>>, /// Enable experimental live diffs in the assistant panel. /// /// Default: false enable_experimental_live_diffs: Option<bool>, /// The default profile to use in the Agent.Lines 1–500 of 795. Load more
mod agent_profile; use std::sync::Arc; use ::open_ai::Model as OpenAiModel; use anthropic::Model as AnthropicModel; use anyhow::{Result, bail}; use deepseek::Model as DeepseekModel; use feature_flags::{Assistant2FeatureFlag, FeatureFlagAppExt}; use gpui::{App, Pixels}; use indexmap::IndexMap; use language_model::{CloudModel, LanguageModel}; use lmstudio::Model as LmStudioModel; use ollama::Model as OllamaModel; use schemars::{JsonSchema, schema::Schema}; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsSources}; pub use crate::agent_profile::*; #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum AssistantDockPosition { Left, #[default] Right, Bottom, } #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum NotifyWhenAgentWaiting { #[default] PrimaryScreen, AllScreens, Never, } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)] #[serde(tag = "name", rename_all = "snake_case")] pub enum AssistantProviderContentV1 { #[serde(rename = "zed.dev")] ZedDotDev { default_model: Option<CloudModel> }, #[serde(rename = "openai")] OpenAi { default_model: Option<OpenAiModel>, api_url: Option<String>, available_models: Option<Vec<OpenAiModel>>, }, #[serde(rename = "anthropic")] Anthropic { default_model: Option<AnthropicModel>, api_url: Option<String>, }, #[serde(rename = "ollama")] Ollama { default_model: Option<OllamaModel>, api_url: Option<String>, }, #[serde(rename = "lmstudio")] LmStudio { default_model: Option<LmStudioModel>, api_url: Option<String>, }, #[serde(rename = "deepseek")] DeepSeek { default_model: Option<DeepseekModel>, api_url: Option<String>, }, } #[derive(Clone, Debug, Default)] pub struct AssistantSettings { pub enabled: bool, pub button: bool, pub dock: AssistantDockPosition, pub default_width: Pixels, pub default_height: Pixels, pub default_model: LanguageModelSelection, pub inline_assistant_model: Option<LanguageModelSelection>, pub commit_message_model: Option<LanguageModelSelection>, pub thread_summary_model: Option<LanguageModelSelection>, pub inline_alternatives: Vec<LanguageModelSelection>, pub using_outdated_settings_version: bool, pub enable_experimental_live_diffs: bool, pub default_profile: AgentProfileId, pub profiles: IndexMap<AgentProfileId, AgentProfile>, pub always_allow_tool_actions: bool, pub notify_when_agent_waiting: NotifyWhenAgentWaiting, } impl AssistantSettings { pub fn are_live_diffs_enabled(&self, cx: &App) -> bool { if cx.has_flag::<Assistant2FeatureFlag>() { return false; } cx.is_staff() || self.enable_experimental_live_diffs } pub fn set_inline_assistant_model(&mut self, provider: String, model: String) { self.inline_assistant_model = Some(LanguageModelSelection { provider, model }); } pub fn set_commit_message_model(&mut self, provider: String, model: String) { self.commit_message_model = Some(LanguageModelSelection { provider, model }); } pub fn set_thread_summary_model(&mut self, provider: String, model: String) { self.thread_summary_model = Some(LanguageModelSelection { provider, model }); } } /// Assistant panel settings #[derive(Clone, Serialize, Deserialize, Debug)] #[serde(untagged)] pub enum AssistantSettingsContent { Versioned(Box<VersionedAssistantSettingsContent>), Legacy(LegacyAssistantSettingsContent), } impl JsonSchema for AssistantSettingsContent { fn schema_name() -> String { VersionedAssistantSettingsContent::schema_name() } fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> Schema { VersionedAssistantSettingsContent::json_schema(r#gen) } fn is_referenceable() -> bool { VersionedAssistantSettingsContent::is_referenceable() } } impl Default for AssistantSettingsContent { fn default() -> Self { Self::Versioned(Box::new(VersionedAssistantSettingsContent::default())) } } impl AssistantSettingsContent { pub fn is_version_outdated(&self) -> bool { match self { AssistantSettingsContent::Versioned(settings) => match **settings { VersionedAssistantSettingsContent::V1(_) => true, VersionedAssistantSettingsContent::V2(_) => false, }, AssistantSettingsContent::Legacy(_) => true, } } fn upgrade(&self) -> AssistantSettingsContentV2 { match self { AssistantSettingsContent::Versioned(settings) => match **settings { VersionedAssistantSettingsContent::V1(ref settings) => AssistantSettingsContentV2 { enabled: settings.enabled, button: settings.button, dock: settings.dock, default_width: settings.default_width, default_height: settings.default_width, default_model: settings .provider .clone() .and_then(|provider| match provider { AssistantProviderContentV1::ZedDotDev { default_model } => { default_model.map(|model| LanguageModelSelection { provider: "zed.dev".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::OpenAi { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "openai".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::Anthropic { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "anthropic".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::Ollama { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "ollama".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::LmStudio { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "lmstudio".to_string(), model: model.id().to_string(), }) } AssistantProviderContentV1::DeepSeek { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "deepseek".to_string(), model: model.id().to_string(), }) } }), inline_assistant_model: None, commit_message_model: None, thread_summary_model: None, inline_alternatives: None, enable_experimental_live_diffs: None, default_profile: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, }, VersionedAssistantSettingsContent::V2(ref settings) => settings.clone(), }, AssistantSettingsContent::Legacy(settings) => AssistantSettingsContentV2 { enabled: None, button: settings.button, dock: settings.dock, default_width: settings.default_width, default_height: settings.default_height, default_model: Some(LanguageModelSelection { provider: "openai".to_string(), model: settings .default_open_ai_model .clone() .unwrap_or_default() .id() .to_string(), }), inline_assistant_model: None, commit_message_model: None, thread_summary_model: None, inline_alternatives: None, enable_experimental_live_diffs: None, default_profile: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, }, } } pub fn set_dock(&mut self, dock: AssistantDockPosition) { match self { AssistantSettingsContent::Versioned(settings) => match **settings { VersionedAssistantSettingsContent::V1(ref mut settings) => { settings.dock = Some(dock); } VersionedAssistantSettingsContent::V2(ref mut settings) => { settings.dock = Some(dock); } }, AssistantSettingsContent::Legacy(settings) => { settings.dock = Some(dock); } } } pub fn set_model(&mut self, language_model: Arc<dyn LanguageModel>) { let model = language_model.id().0.to_string(); let provider = language_model.provider_id().0.to_string(); match self { AssistantSettingsContent::Versioned(settings) => match **settings { VersionedAssistantSettingsContent::V1(ref mut settings) => { match provider.as_ref() { "zed.dev" => { log::warn!("attempted to set zed.dev model on outdated settings"); } "anthropic" => { let api_url = match &settings.provider { Some(AssistantProviderContentV1::Anthropic { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AssistantProviderContentV1::Anthropic { default_model: AnthropicModel::from_id(&model).ok(), api_url, }); } "ollama" => { let api_url = match &settings.provider { Some(AssistantProviderContentV1::Ollama { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AssistantProviderContentV1::Ollama { default_model: Some(ollama::Model::new(&model, None, None)), api_url, }); } "lmstudio" => { let api_url = match &settings.provider { Some(AssistantProviderContentV1::LmStudio { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AssistantProviderContentV1::LmStudio { default_model: Some(lmstudio::Model::new(&model, None, None)), api_url, }); } "openai" => { let (api_url, available_models) = match &settings.provider { Some(AssistantProviderContentV1::OpenAi { api_url, available_models, .. }) => (api_url.clone(), available_models.clone()), _ => (None, None), }; settings.provider = Some(AssistantProviderContentV1::OpenAi { default_model: OpenAiModel::from_id(&model).ok(), api_url, available_models, }); } "deepseek" => { let api_url = match &settings.provider { Some(AssistantProviderContentV1::DeepSeek { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AssistantProviderContentV1::DeepSeek { default_model: DeepseekModel::from_id(&model).ok(), api_url, }); } _ => {} } } VersionedAssistantSettingsContent::V2(ref mut settings) => { settings.default_model = Some(LanguageModelSelection { provider, model }); } }, AssistantSettingsContent::Legacy(settings) => { if let Ok(model) = OpenAiModel::from_id(&language_model.id().0) { settings.default_open_ai_model = Some(model); } } } } pub fn set_inline_assistant_model(&mut self, provider: String, model: String) { if let AssistantSettingsContent::Versioned(boxed) = self { if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.inline_assistant_model = Some(LanguageModelSelection { provider, model }); } } } pub fn set_commit_message_model(&mut self, provider: String, model: String) { if let AssistantSettingsContent::Versioned(boxed) = self { if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.commit_message_model = Some(LanguageModelSelection { provider, model }); } } } pub fn set_thread_summary_model(&mut self, provider: String, model: String) { if let AssistantSettingsContent::Versioned(boxed) = self { if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.thread_summary_model = Some(LanguageModelSelection { provider, model }); } } } pub fn set_always_allow_tool_actions(&mut self, allow: bool) { let AssistantSettingsContent::Versioned(boxed) = self else { return; }; if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.always_allow_tool_actions = Some(allow); } } pub fn set_profile(&mut self, profile_id: AgentProfileId) { let AssistantSettingsContent::Versioned(boxed) = self else { return; }; if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { settings.default_profile = Some(profile_id); } } pub fn create_profile( &mut self, profile_id: AgentProfileId, profile: AgentProfile, ) -> Result<()> { let AssistantSettingsContent::Versioned(boxed) = self else { return Ok(()); }; if let VersionedAssistantSettingsContent::V2(ref mut settings) = **boxed { let profiles = settings.profiles.get_or_insert_default(); if profiles.contains_key(&profile_id) { bail!("profile with ID '{profile_id}' already exists"); } profiles.insert( profile_id, AgentProfileContent { name: profile.name.into(), tools: profile.tools, enable_all_context_servers: Some(profile.enable_all_context_servers), context_servers: profile .context_servers .into_iter() .map(|(server_id, preset)| { ( server_id, ContextServerPresetContent { tools: preset.tools, }, ) }) .collect(), }, ); } Ok(()) } } #[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] #[serde(tag = "version")] pub enum VersionedAssistantSettingsContent { #[serde(rename = "1")] V1(AssistantSettingsContentV1), #[serde(rename = "2")] V2(AssistantSettingsContentV2), } impl Default for VersionedAssistantSettingsContent { fn default() -> Self { Self::V2(AssistantSettingsContentV2 { enabled: None, button: None, dock: None, default_width: None, default_height: None, default_model: None, inline_assistant_model: None, commit_message_model: None, thread_summary_model: None, inline_alternatives: None, enable_experimental_live_diffs: None, default_profile: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, }) } } #[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] pub struct AssistantSettingsContentV2 { /// Whether the Assistant is enabled. /// /// Default: true enabled: Option<bool>, /// Whether to show the assistant panel button in the status bar. /// /// Default: true button: Option<bool>, /// Where to dock the assistant. /// /// Default: right dock: Option<AssistantDockPosition>, /// Default width in pixels when the assistant is docked to the left or right. /// /// Default: 640 default_width: Option<f32>, /// Default height in pixels when the assistant is docked to the bottom. /// /// Default: 320 default_height: Option<f32>, /// The default model to use when creating new chats and for other features when a specific model is not specified. default_model: Option<LanguageModelSelection>, /// Model to use for the inline assistant. Defaults to default_model when not specified. inline_assistant_model: Option<LanguageModelSelection>, /// Model to use for generating git commit messages. Defaults to default_model when not specified. commit_message_model: Option<LanguageModelSelection>, /// Model to use for generating thread summaries. Defaults to default_model when not specified. thread_summary_model: Option<LanguageModelSelection>, /// Additional models with which to generate alternatives when performing inline assists. inline_alternatives: Option<Vec<LanguageModelSelection>>, /// Enable experimental live diffs in the assistant panel. /// /// Default: false enable_experimental_live_diffs: Option<bool>, /// The default profile to use in the Agent.