agent_settings.rs

  1mod agent_profile;
  2
  3use std::sync::Arc;
  4
  5use agent_client_protocol::ModelId;
  6use collections::{HashSet, IndexMap};
  7use gpui::{App, Pixels, px};
  8use language_model::LanguageModel;
  9use project::DisableAiSettings;
 10use schemars::JsonSchema;
 11use serde::{Deserialize, Serialize};
 12use settings::{
 13    DefaultAgentView, DockPosition, DockSide, LanguageModelParameters, LanguageModelSelection,
 14    NotifyWhenAgentWaiting, RegisterSetting, Settings,
 15};
 16
 17pub use crate::agent_profile::*;
 18
 19pub const SUMMARIZE_THREAD_PROMPT: &str = include_str!("prompts/summarize_thread_prompt.txt");
 20pub const SUMMARIZE_THREAD_DETAILED_PROMPT: &str =
 21    include_str!("prompts/summarize_thread_detailed_prompt.txt");
 22
 23#[derive(Clone, Debug, RegisterSetting)]
 24pub struct AgentSettings {
 25    pub enabled: bool,
 26    pub button: bool,
 27    pub dock: DockPosition,
 28    pub agents_panel_dock: DockSide,
 29    pub default_width: Pixels,
 30    pub default_height: Pixels,
 31    pub default_model: Option<LanguageModelSelection>,
 32    pub inline_assistant_model: Option<LanguageModelSelection>,
 33    pub inline_assistant_use_streaming_tools: bool,
 34    pub commit_message_model: Option<LanguageModelSelection>,
 35    pub thread_summary_model: Option<LanguageModelSelection>,
 36    pub inline_alternatives: Vec<LanguageModelSelection>,
 37    pub favorite_models: Vec<LanguageModelSelection>,
 38    pub default_profile: AgentProfileId,
 39    pub default_view: DefaultAgentView,
 40    pub profiles: IndexMap<AgentProfileId, AgentProfileSettings>,
 41    pub always_allow_tool_actions: bool,
 42    pub notify_when_agent_waiting: NotifyWhenAgentWaiting,
 43    pub play_sound_when_agent_done: bool,
 44    pub single_file_review: bool,
 45    pub model_parameters: Vec<LanguageModelParameters>,
 46    pub preferred_completion_mode: CompletionMode,
 47    pub enable_feedback: bool,
 48    pub expand_edit_card: bool,
 49    pub expand_terminal_card: bool,
 50    pub use_modifier_to_send: bool,
 51    pub message_editor_min_lines: usize,
 52}
 53
 54impl AgentSettings {
 55    pub fn enabled(&self, cx: &App) -> bool {
 56        self.enabled && !DisableAiSettings::get_global(cx).disable_ai
 57    }
 58
 59    pub fn temperature_for_model(model: &Arc<dyn LanguageModel>, cx: &App) -> Option<f32> {
 60        let settings = Self::get_global(cx);
 61        for setting in settings.model_parameters.iter().rev() {
 62            if let Some(provider) = &setting.provider
 63                && provider.0 != model.provider_id().0
 64            {
 65                continue;
 66            }
 67            if let Some(setting_model) = &setting.model
 68                && *setting_model != model.id().0
 69            {
 70                continue;
 71            }
 72            return setting.temperature;
 73        }
 74        return None;
 75    }
 76
 77    pub fn set_inline_assistant_model(&mut self, provider: String, model: String) {
 78        self.inline_assistant_model = Some(LanguageModelSelection {
 79            provider: provider.into(),
 80            model,
 81        });
 82    }
 83
 84    pub fn set_commit_message_model(&mut self, provider: String, model: String) {
 85        self.commit_message_model = Some(LanguageModelSelection {
 86            provider: provider.into(),
 87            model,
 88        });
 89    }
 90
 91    pub fn set_thread_summary_model(&mut self, provider: String, model: String) {
 92        self.thread_summary_model = Some(LanguageModelSelection {
 93            provider: provider.into(),
 94            model,
 95        });
 96    }
 97
 98    pub fn set_message_editor_max_lines(&self) -> usize {
 99        self.message_editor_min_lines * 2
100    }
101
102    pub fn favorite_model_ids(&self) -> HashSet<ModelId> {
103        self.favorite_models
104            .iter()
105            .map(|sel| ModelId::new(format!("{}/{}", sel.provider.0, sel.model)))
106            .collect()
107    }
108}
109
110#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
111#[serde(rename_all = "snake_case")]
112pub enum CompletionMode {
113    #[default]
114    Normal,
115    #[serde(alias = "max")]
116    Burn,
117}
118
119impl From<CompletionMode> for cloud_llm_client::CompletionMode {
120    fn from(value: CompletionMode) -> Self {
121        match value {
122            CompletionMode::Normal => cloud_llm_client::CompletionMode::Normal,
123            CompletionMode::Burn => cloud_llm_client::CompletionMode::Max,
124        }
125    }
126}
127
128impl From<settings::CompletionMode> for CompletionMode {
129    fn from(value: settings::CompletionMode) -> Self {
130        match value {
131            settings::CompletionMode::Normal => CompletionMode::Normal,
132            settings::CompletionMode::Burn => CompletionMode::Burn,
133        }
134    }
135}
136
137#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
138pub struct AgentProfileId(pub Arc<str>);
139
140impl AgentProfileId {
141    pub fn as_str(&self) -> &str {
142        &self.0
143    }
144}
145
146impl std::fmt::Display for AgentProfileId {
147    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148        write!(f, "{}", self.0)
149    }
150}
151
152impl Default for AgentProfileId {
153    fn default() -> Self {
154        Self("write".into())
155    }
156}
157
158impl Settings for AgentSettings {
159    fn from_settings(content: &settings::SettingsContent) -> Self {
160        let agent = content.agent.clone().unwrap();
161        Self {
162            enabled: agent.enabled.unwrap(),
163            button: agent.button.unwrap(),
164            dock: agent.dock.unwrap(),
165            agents_panel_dock: agent.agents_panel_dock.unwrap(),
166            default_width: px(agent.default_width.unwrap()),
167            default_height: px(agent.default_height.unwrap()),
168            default_model: Some(agent.default_model.unwrap()),
169            inline_assistant_model: agent.inline_assistant_model,
170            inline_assistant_use_streaming_tools: agent
171                .inline_assistant_use_streaming_tools
172                .unwrap_or(true),
173            commit_message_model: agent.commit_message_model,
174            thread_summary_model: agent.thread_summary_model,
175            inline_alternatives: agent.inline_alternatives.unwrap_or_default(),
176            favorite_models: agent.favorite_models,
177            default_profile: AgentProfileId(agent.default_profile.unwrap()),
178            default_view: agent.default_view.unwrap(),
179            profiles: agent
180                .profiles
181                .unwrap()
182                .into_iter()
183                .map(|(key, val)| (AgentProfileId(key), val.into()))
184                .collect(),
185            always_allow_tool_actions: agent.always_allow_tool_actions.unwrap(),
186            notify_when_agent_waiting: agent.notify_when_agent_waiting.unwrap(),
187            play_sound_when_agent_done: agent.play_sound_when_agent_done.unwrap(),
188            single_file_review: agent.single_file_review.unwrap(),
189            model_parameters: agent.model_parameters,
190            preferred_completion_mode: agent.preferred_completion_mode.unwrap().into(),
191            enable_feedback: agent.enable_feedback.unwrap(),
192            expand_edit_card: agent.expand_edit_card.unwrap(),
193            expand_terminal_card: agent.expand_terminal_card.unwrap(),
194            use_modifier_to_send: agent.use_modifier_to_send.unwrap(),
195            message_editor_min_lines: agent.message_editor_min_lines.unwrap(),
196        }
197    }
198}