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