agent_settings.rs

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