mod agent_profile; use std::sync::Arc; use ::open_ai::Model as OpenAiModel;use anthropic::Model as AnthropicModel;use anyhow::{Result, bail};use collections::IndexMap;use deepseek::Model as DeepseekModel;use gpui::{App, Pixels, SharedString};use language_model::LanguageModel;use lmstudio::Model as LmStudioModel;use mistral::Model as MistralModel;use ollama::Model as OllamaModel;use schemars::{JsonSchema, schema::Schema};use serde::{Deserialize, Serialize};use settings::{Settings, SettingsSources}; pub use crate::agent_profile::*; pub fn init(cx: &mut App) { AgentSettings::register(cx);} #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum AgentDockPosition { Left, #[default] Right, Bottom,} #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum DefaultView { #[default] Thread, TextThread,} #[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")]#[schemars(deny_unknown_fields)]pub enum AgentProviderContentV1 { #[serde(rename = "zed.dev")] ZedDotDev { default_model: Option<String> }, #[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>, }, #[serde(rename = "mistral")] Mistral { default_model: Option<MistralModel>, api_url: Option<String>, },} #[derive(Default, Clone, Debug)]pub struct AgentSettings { pub enabled: bool, pub button: bool, pub dock: AgentDockPosition, 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 default_profile: AgentProfileId, pub default_view: DefaultView, pub profiles: IndexMap<AgentProfileId, AgentProfile>, pub always_allow_tool_actions: bool, pub notify_when_agent_waiting: NotifyWhenAgentWaiting, pub play_sound_when_agent_done: bool, pub stream_edits: bool, pub single_file_review: bool, pub model_parameters: Vec<LanguageModelParameters>, pub preferred_completion_mode: CompletionMode, pub enable_feedback: bool,} impl AgentSettings { pub fn temperature_for_model(model: &Arc<dyn LanguageModel>, cx: &App) -> Option<f32> { let settings = Self::get_global(cx); settings .model_parameters .iter() .rfind(|setting| setting.matches(model)) .and_then(|m| m.temperature) } pub fn set_inline_assistant_model(&mut self, provider: String, model: String) { self.inline_assistant_model = Some(LanguageModelSelection { provider: provider.into(), model, }); } pub fn set_commit_message_model(&mut self, provider: String, model: String) { self.commit_message_model = Some(LanguageModelSelection { provider: provider.into(), model, }); } pub fn set_thread_summary_model(&mut self, provider: String, model: String) { self.thread_summary_model = Some(LanguageModelSelection { provider: provider.into(), model, }); }} #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]pub struct LanguageModelParameters { pub provider: Option<LanguageModelProviderSetting>, pub model: Option<SharedString>, pub temperature: Option<f32>,} impl LanguageModelParameters { pub fn matches(&self, model: &Arc<dyn LanguageModel>) -> bool { if let Some(provider) = &self.provider { if provider.0 != model.provider_id().0 { return false; } } if let Some(setting_model) = &self.model { if *setting_model != model.id().0 { return false; } } true }} /// Agent panel settings#[derive(Clone, Serialize, Deserialize, Debug, Default)]pub struct AgentSettingsContent { #[serde(flatten)] pub inner: Option<AgentSettingsContentInner>,} #[derive(Clone, Serialize, Deserialize, Debug)]#[serde(untagged)]pub enum AgentSettingsContentInner { Versioned(Box<VersionedAgentSettingsContent>), Legacy(LegacyAgentSettingsContent),} impl AgentSettingsContentInner { fn for_v2(content: AgentSettingsContentV2) -> Self { AgentSettingsContentInner::Versioned(Box::new(VersionedAgentSettingsContent::V2(content))) }} impl JsonSchema for AgentSettingsContent { fn schema_name() -> String { VersionedAgentSettingsContent::schema_name() } fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> Schema { VersionedAgentSettingsContent::json_schema(r#gen) } fn is_referenceable() -> bool { VersionedAgentSettingsContent::is_referenceable() }} impl AgentSettingsContent { pub fn is_version_outdated(&self) -> bool { match &self.inner { Some(AgentSettingsContentInner::Versioned(settings)) => match **settings { VersionedAgentSettingsContent::V1(_) => true, VersionedAgentSettingsContent::V2(_) => false, }, Some(AgentSettingsContentInner::Legacy(_)) => true, None => false, } } fn upgrade(&self) -> AgentSettingsContentV2 { match &self.inner { Some(AgentSettingsContentInner::Versioned(settings)) => match **settings { VersionedAgentSettingsContent::V1(ref settings) => AgentSettingsContentV2 { 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 { AgentProviderContentV1::ZedDotDev { default_model } => default_model .map(|model| LanguageModelSelection { provider: "zed.dev".into(), model, }), AgentProviderContentV1::OpenAi { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "openai".into(), model: model.id().to_string(), }), AgentProviderContentV1::Anthropic { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "anthropic".into(), model: model.id().to_string(), }) } AgentProviderContentV1::Ollama { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "ollama".into(), model: model.id().to_string(), }), AgentProviderContentV1::LmStudio { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "lmstudio".into(), model: model.id().to_string(), }), AgentProviderContentV1::DeepSeek { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "deepseek".into(), model: model.id().to_string(), }), AgentProviderContentV1::Mistral { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "mistral".into(), model: model.id().to_string(), }), }), inline_assistant_model: None, commit_message_model: None, thread_summary_model: None, inline_alternatives: None, default_profile: None, default_view: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, stream_edits: None, single_file_review: None, model_parameters: Vec::new(), preferred_completion_mode: None, enable_feedback: None, play_sound_when_agent_done: None, }, VersionedAgentSettingsContent::V2(ref settings) => settings.clone(), }, Some(AgentSettingsContentInner::Legacy(settings)) => AgentSettingsContentV2 { enabled: None, button: settings.button, dock: settings.dock, default_width: settings.default_width, default_height: settings.default_height, default_model: Some(LanguageModelSelection { provider: "openai".into(), 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, default_profile: None, default_view: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, stream_edits: None, single_file_review: None, model_parameters: Vec::new(), preferred_completion_mode: None, enable_feedback: None, play_sound_when_agent_done: None, }, None => AgentSettingsContentV2::default(), } } pub fn set_dock(&mut self, dock: AgentDockPosition) { match &mut self.inner { Some(AgentSettingsContentInner::Versioned(settings)) => match **settings { VersionedAgentSettingsContent::V1(ref mut settings) => { settings.dock = Some(dock); } VersionedAgentSettingsContent::V2(ref mut settings) => { settings.dock = Some(dock); } }, Some(AgentSettingsContentInner::Legacy(settings)) => { settings.dock = Some(dock); } None => { self.inner = Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 { dock: Some(dock), ..Default::default() })) } } } 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 &mut self.inner { Some(AgentSettingsContentInner::Versioned(settings)) => match **settings { VersionedAgentSettingsContent::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(AgentProviderContentV1::Anthropic { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AgentProviderContentV1::Anthropic { default_model: AnthropicModel::from_id(&model).ok(), api_url, }); } "ollama" => { let api_url = match &settings.provider { Some(AgentProviderContentV1::Ollama { api_url, .. }) => api_url.clone(), _ => None, }; settings.provider = Some(AgentProviderContentV1::Ollama { default_model: Some(ollama::Model::new( &model, None, None, Some(language_model.supports_tools()), Some(language_model.supports_images()), None, )), api_url, }); } "lmstudio" => { let api_url = match &settings.provider { Some(AgentProviderContentV1::LmStudio { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AgentProviderContentV1::LmStudio { default_model: Some(lmstudio::Model::new(&model, None, None, false)), api_url, }); } "openai" => { let (api_url, available_models) = match &settings.provider { Some(AgentProviderContentV1::OpenAi { api_url, available_models, .. }) => (api_url.clone(), available_models.clone()), _ => (None, None), }; settings.provider = Some(AgentProviderContentV1::OpenAi { default_model: OpenAiModel::from_id(&model).ok(), api_url, available_models, }); } "deepseek" => { let api_url = match &settings.provider { Some(AgentProviderContentV1::DeepSeek { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AgentProviderContentV1::DeepSeek { default_model: DeepseekModel::from_id(&model).ok(), api_url, }); } _ => {} }, VersionedAgentSettingsContent::V2(ref mut settings) => { settings.default_model = Some(LanguageModelSelection { provider: provider.into(), model, }); } }, Some(AgentSettingsContentInner::Legacy(settings)) => { if let Ok(model) = OpenAiModel::from_id(&language_model.id().0) { settings.default_open_ai_model = Some(model); } } None => { self.inner = Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 { default_model: Some(LanguageModelSelection { provider: provider.into(), model, }), ..Default::default() })); } } } pub fn set_inline_assistant_model(&mut self, provider: String, model: String) { self.v2_setting(|setting| { setting.inline_assistant_model = Some(LanguageModelSelection { provider: provider.into(), model, }); Ok(()) }) .ok(); } pub fn set_commit_message_model(&mut self, provider: String, model: String) { self.v2_setting(|setting| { setting.commit_message_model = Some(LanguageModelSelection { provider: provider.into(), model, }); Ok(()) }) .ok(); } pub fn v2_setting( &mut self, f: impl FnOnce(&mut AgentSettingsContentV2) -> anyhow::Result<()>, ) -> anyhow::Result<()> { match self.inner.get_or_insert_with(|| { AgentSettingsContentInner::for_v2(AgentSettingsContentV2 { ..Default::default() }) }) { AgentSettingsContentInner::Versioned(boxed) => { if let VersionedAgentSettingsContent::V2(ref mut settings) = **boxed { f(settings) } else { Ok(()) } } _ => Ok(()), } } pub fn set_thread_summary_model(&mut self, provider: String, model: String) { self.v2_setting(|setting| { setting.thread_summary_model = Some(LanguageModelSelection { provider: provider.into(), model, }); Ok(()) }) .ok(); } pub fn set_always_allow_tool_actions(&mut self, allow: bool) { self.v2_setting(|setting| {Lines 1–500 of 1121. 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 collections::IndexMap; use deepseek::Model as DeepseekModel; use gpui::{App, Pixels, SharedString}; use language_model::LanguageModel; use lmstudio::Model as LmStudioModel; use mistral::Model as MistralModel; use ollama::Model as OllamaModel; use schemars::{JsonSchema, schema::Schema}; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsSources}; pub use crate::agent_profile::*; pub fn init(cx: &mut App) { AgentSettings::register(cx); } #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum AgentDockPosition { Left, #[default] Right, Bottom, } #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum DefaultView { #[default] Thread, TextThread, } #[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")] #[schemars(deny_unknown_fields)] pub enum AgentProviderContentV1 { #[serde(rename = "zed.dev")] ZedDotDev { default_model: Option<String> }, #[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>, }, #[serde(rename = "mistral")] Mistral { default_model: Option<MistralModel>, api_url: Option<String>, }, } #[derive(Default, Clone, Debug)] pub struct AgentSettings { pub enabled: bool, pub button: bool, pub dock: AgentDockPosition, 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 default_profile: AgentProfileId, pub default_view: DefaultView, pub profiles: IndexMap<AgentProfileId, AgentProfile>, pub always_allow_tool_actions: bool, pub notify_when_agent_waiting: NotifyWhenAgentWaiting, pub play_sound_when_agent_done: bool, pub stream_edits: bool, pub single_file_review: bool, pub model_parameters: Vec<LanguageModelParameters>, pub preferred_completion_mode: CompletionMode, pub enable_feedback: bool, } impl AgentSettings { pub fn temperature_for_model(model: &Arc<dyn LanguageModel>, cx: &App) -> Option<f32> { let settings = Self::get_global(cx); settings .model_parameters .iter() .rfind(|setting| setting.matches(model)) .and_then(|m| m.temperature) } pub fn set_inline_assistant_model(&mut self, provider: String, model: String) { self.inline_assistant_model = Some(LanguageModelSelection { provider: provider.into(), model, }); } pub fn set_commit_message_model(&mut self, provider: String, model: String) { self.commit_message_model = Some(LanguageModelSelection { provider: provider.into(), model, }); } pub fn set_thread_summary_model(&mut self, provider: String, model: String) { self.thread_summary_model = Some(LanguageModelSelection { provider: provider.into(), model, }); } } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)] pub struct LanguageModelParameters { pub provider: Option<LanguageModelProviderSetting>, pub model: Option<SharedString>, pub temperature: Option<f32>, } impl LanguageModelParameters { pub fn matches(&self, model: &Arc<dyn LanguageModel>) -> bool { if let Some(provider) = &self.provider { if provider.0 != model.provider_id().0 { return false; } } if let Some(setting_model) = &self.model { if *setting_model != model.id().0 { return false; } } true } } /// Agent panel settings #[derive(Clone, Serialize, Deserialize, Debug, Default)] pub struct AgentSettingsContent { #[serde(flatten)] pub inner: Option<AgentSettingsContentInner>, } #[derive(Clone, Serialize, Deserialize, Debug)] #[serde(untagged)] pub enum AgentSettingsContentInner { Versioned(Box<VersionedAgentSettingsContent>), Legacy(LegacyAgentSettingsContent), } impl AgentSettingsContentInner { fn for_v2(content: AgentSettingsContentV2) -> Self { AgentSettingsContentInner::Versioned(Box::new(VersionedAgentSettingsContent::V2(content))) } } impl JsonSchema for AgentSettingsContent { fn schema_name() -> String { VersionedAgentSettingsContent::schema_name() } fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> Schema { VersionedAgentSettingsContent::json_schema(r#gen) } fn is_referenceable() -> bool { VersionedAgentSettingsContent::is_referenceable() } } impl AgentSettingsContent { pub fn is_version_outdated(&self) -> bool { match &self.inner { Some(AgentSettingsContentInner::Versioned(settings)) => match **settings { VersionedAgentSettingsContent::V1(_) => true, VersionedAgentSettingsContent::V2(_) => false, }, Some(AgentSettingsContentInner::Legacy(_)) => true, None => false, } } fn upgrade(&self) -> AgentSettingsContentV2 { match &self.inner { Some(AgentSettingsContentInner::Versioned(settings)) => match **settings { VersionedAgentSettingsContent::V1(ref settings) => AgentSettingsContentV2 { 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 { AgentProviderContentV1::ZedDotDev { default_model } => default_model .map(|model| LanguageModelSelection { provider: "zed.dev".into(), model, }), AgentProviderContentV1::OpenAi { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "openai".into(), model: model.id().to_string(), }), AgentProviderContentV1::Anthropic { default_model, .. } => { default_model.map(|model| LanguageModelSelection { provider: "anthropic".into(), model: model.id().to_string(), }) } AgentProviderContentV1::Ollama { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "ollama".into(), model: model.id().to_string(), }), AgentProviderContentV1::LmStudio { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "lmstudio".into(), model: model.id().to_string(), }), AgentProviderContentV1::DeepSeek { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "deepseek".into(), model: model.id().to_string(), }), AgentProviderContentV1::Mistral { default_model, .. } => default_model .map(|model| LanguageModelSelection { provider: "mistral".into(), model: model.id().to_string(), }), }), inline_assistant_model: None, commit_message_model: None, thread_summary_model: None, inline_alternatives: None, default_profile: None, default_view: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, stream_edits: None, single_file_review: None, model_parameters: Vec::new(), preferred_completion_mode: None, enable_feedback: None, play_sound_when_agent_done: None, }, VersionedAgentSettingsContent::V2(ref settings) => settings.clone(), }, Some(AgentSettingsContentInner::Legacy(settings)) => AgentSettingsContentV2 { enabled: None, button: settings.button, dock: settings.dock, default_width: settings.default_width, default_height: settings.default_height, default_model: Some(LanguageModelSelection { provider: "openai".into(), 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, default_profile: None, default_view: None, profiles: None, always_allow_tool_actions: None, notify_when_agent_waiting: None, stream_edits: None, single_file_review: None, model_parameters: Vec::new(), preferred_completion_mode: None, enable_feedback: None, play_sound_when_agent_done: None, }, None => AgentSettingsContentV2::default(), } } pub fn set_dock(&mut self, dock: AgentDockPosition) { match &mut self.inner { Some(AgentSettingsContentInner::Versioned(settings)) => match **settings { VersionedAgentSettingsContent::V1(ref mut settings) => { settings.dock = Some(dock); } VersionedAgentSettingsContent::V2(ref mut settings) => { settings.dock = Some(dock); } }, Some(AgentSettingsContentInner::Legacy(settings)) => { settings.dock = Some(dock); } None => { self.inner = Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 { dock: Some(dock), ..Default::default() })) } } } 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 &mut self.inner { Some(AgentSettingsContentInner::Versioned(settings)) => match **settings { VersionedAgentSettingsContent::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(AgentProviderContentV1::Anthropic { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AgentProviderContentV1::Anthropic { default_model: AnthropicModel::from_id(&model).ok(), api_url, }); } "ollama" => { let api_url = match &settings.provider { Some(AgentProviderContentV1::Ollama { api_url, .. }) => api_url.clone(), _ => None, }; settings.provider = Some(AgentProviderContentV1::Ollama { default_model: Some(ollama::Model::new( &model, None, None, Some(language_model.supports_tools()), Some(language_model.supports_images()), None, )), api_url, }); } "lmstudio" => { let api_url = match &settings.provider { Some(AgentProviderContentV1::LmStudio { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AgentProviderContentV1::LmStudio { default_model: Some(lmstudio::Model::new(&model, None, None, false)), api_url, }); } "openai" => { let (api_url, available_models) = match &settings.provider { Some(AgentProviderContentV1::OpenAi { api_url, available_models, .. }) => (api_url.clone(), available_models.clone()), _ => (None, None), }; settings.provider = Some(AgentProviderContentV1::OpenAi { default_model: OpenAiModel::from_id(&model).ok(), api_url, available_models, }); } "deepseek" => { let api_url = match &settings.provider { Some(AgentProviderContentV1::DeepSeek { api_url, .. }) => { api_url.clone() } _ => None, }; settings.provider = Some(AgentProviderContentV1::DeepSeek { default_model: DeepseekModel::from_id(&model).ok(), api_url, }); } _ => {} }, VersionedAgentSettingsContent::V2(ref mut settings) => { settings.default_model = Some(LanguageModelSelection { provider: provider.into(), model, }); } }, Some(AgentSettingsContentInner::Legacy(settings)) => { if let Ok(model) = OpenAiModel::from_id(&language_model.id().0) { settings.default_open_ai_model = Some(model); } } None => { self.inner = Some(AgentSettingsContentInner::for_v2(AgentSettingsContentV2 { default_model: Some(LanguageModelSelection { provider: provider.into(), model, }), ..Default::default() })); } } } pub fn set_inline_assistant_model(&mut self, provider: String, model: String) { self.v2_setting(|setting| { setting.inline_assistant_model = Some(LanguageModelSelection { provider: provider.into(), model, }); Ok(()) }) .ok(); } pub fn set_commit_message_model(&mut self, provider: String, model: String) { self.v2_setting(|setting| { setting.commit_message_model = Some(LanguageModelSelection { provider: provider.into(), model, }); Ok(()) }) .ok(); } pub fn v2_setting( &mut self, f: impl FnOnce(&mut AgentSettingsContentV2) -> anyhow::Result<()>, ) -> anyhow::Result<()> { match self.inner.get_or_insert_with(|| { AgentSettingsContentInner::for_v2(AgentSettingsContentV2 { ..Default::default() }) }) { AgentSettingsContentInner::Versioned(boxed) => { if let VersionedAgentSettingsContent::V2(ref mut settings) = **boxed { f(settings) } else { Ok(()) } } _ => Ok(()), } } pub fn set_thread_summary_model(&mut self, provider: String, model: String) { self.v2_setting(|setting| { setting.thread_summary_model = Some(LanguageModelSelection { provider: provider.into(), model, }); Ok(()) }) .ok(); } pub fn set_always_allow_tool_actions(&mut self, allow: bool) { self.v2_setting(|setting| {