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}