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,
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 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
103#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
104#[serde(rename_all = "snake_case")]
105pub enum CompletionMode {
106 #[default]
107 Normal,
108 #[serde(alias = "max")]
109 Burn,
110}
111
112impl From<CompletionMode> for cloud_llm_client::CompletionMode {
113 fn from(value: CompletionMode) -> Self {
114 match value {
115 CompletionMode::Normal => cloud_llm_client::CompletionMode::Normal,
116 CompletionMode::Burn => cloud_llm_client::CompletionMode::Max,
117 }
118 }
119}
120
121impl From<settings::CompletionMode> for CompletionMode {
122 fn from(value: settings::CompletionMode) -> Self {
123 match value {
124 settings::CompletionMode::Normal => CompletionMode::Normal,
125 settings::CompletionMode::Burn => CompletionMode::Burn,
126 }
127 }
128}
129
130#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
131pub struct AgentProfileId(pub Arc<str>);
132
133impl AgentProfileId {
134 pub fn as_str(&self) -> &str {
135 &self.0
136 }
137}
138
139impl std::fmt::Display for AgentProfileId {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 write!(f, "{}", self.0)
142 }
143}
144
145impl Default for AgentProfileId {
146 fn default() -> Self {
147 Self("write".into())
148 }
149}
150
151impl Settings for AgentSettings {
152 fn from_settings(content: &settings::SettingsContent) -> Self {
153 let agent = content.agent.clone().unwrap();
154 Self {
155 enabled: agent.enabled.unwrap(),
156 button: agent.button.unwrap(),
157 dock: agent.dock.unwrap(),
158 default_width: px(agent.default_width.unwrap()),
159 default_height: px(agent.default_height.unwrap()),
160 default_model: Some(agent.default_model.unwrap()),
161 inline_assistant_model: agent.inline_assistant_model,
162 commit_message_model: agent.commit_message_model,
163 thread_summary_model: agent.thread_summary_model,
164 inline_alternatives: agent.inline_alternatives.unwrap_or_default(),
165 default_profile: AgentProfileId(agent.default_profile.unwrap()),
166 default_view: agent.default_view.unwrap(),
167 profiles: agent
168 .profiles
169 .unwrap()
170 .into_iter()
171 .map(|(key, val)| (AgentProfileId(key), val.into()))
172 .collect(),
173 always_allow_tool_actions: agent.always_allow_tool_actions.unwrap(),
174 notify_when_agent_waiting: agent.notify_when_agent_waiting.unwrap(),
175 play_sound_when_agent_done: agent.play_sound_when_agent_done.unwrap(),
176 single_file_review: agent.single_file_review.unwrap(),
177 model_parameters: agent.model_parameters,
178 preferred_completion_mode: agent.preferred_completion_mode.unwrap().into(),
179 enable_feedback: agent.enable_feedback.unwrap(),
180 expand_edit_card: agent.expand_edit_card.unwrap(),
181 expand_terminal_card: agent.expand_terminal_card.unwrap(),
182 use_modifier_to_send: agent.use_modifier_to_send.unwrap(),
183 message_editor_min_lines: agent.message_editor_min_lines.unwrap(),
184 }
185 }
186}