1mod active_thread;
2mod agent_configuration;
3mod agent_diff;
4mod agent_model_selector;
5mod agent_panel;
6mod buffer_codegen;
7mod context_picker;
8mod context_server_configuration;
9mod context_strip;
10mod debug;
11mod inline_assistant;
12mod inline_prompt_editor;
13mod message_editor;
14mod profile_selector;
15mod slash_command_settings;
16mod terminal_codegen;
17mod terminal_inline_assistant;
18mod thread_history;
19mod tool_compatibility;
20mod ui;
21
22use std::sync::Arc;
23
24use agent::{Thread, ThreadId};
25use agent_settings::{AgentProfileId, AgentSettings, LanguageModelSelection};
26use assistant_slash_command::SlashCommandRegistry;
27use client::Client;
28use feature_flags::FeatureFlagAppExt as _;
29use fs::Fs;
30use gpui::{App, Entity, actions, impl_actions};
31use language::LanguageRegistry;
32use language_model::{
33 ConfiguredModel, LanguageModel, LanguageModelId, LanguageModelProviderId, LanguageModelRegistry,
34};
35use prompt_store::PromptBuilder;
36use schemars::JsonSchema;
37use serde::Deserialize;
38use settings::{Settings as _, SettingsStore};
39
40pub use crate::active_thread::ActiveThread;
41use crate::agent_configuration::{ConfigureContextServerModal, ManageProfilesModal};
42pub use crate::agent_panel::{AgentPanel, ConcreteAssistantPanelDelegate};
43pub use crate::inline_assistant::InlineAssistant;
44use crate::slash_command_settings::SlashCommandSettings;
45pub use agent_diff::{AgentDiffPane, AgentDiffToolbar};
46pub use ui::preview::{all_agent_previews, get_agent_preview};
47
48actions!(
49 agent,
50 [
51 NewTextThread,
52 ToggleContextPicker,
53 ToggleNavigationMenu,
54 ToggleOptionsMenu,
55 DeleteRecentlyOpenThread,
56 ToggleProfileSelector,
57 RemoveAllContext,
58 ExpandMessageEditor,
59 OpenHistory,
60 AddContextServer,
61 RemoveSelectedThread,
62 Chat,
63 ChatWithFollow,
64 CycleNextInlineAssist,
65 CyclePreviousInlineAssist,
66 FocusUp,
67 FocusDown,
68 FocusLeft,
69 FocusRight,
70 RemoveFocusedContext,
71 AcceptSuggestedContext,
72 OpenActiveThreadAsMarkdown,
73 OpenAgentDiff,
74 Keep,
75 Reject,
76 RejectAll,
77 KeepAll,
78 Follow,
79 ResetTrialUpsell,
80 ResetTrialEndUpsell,
81 ContinueThread,
82 ContinueWithBurnMode,
83 ToggleBurnMode,
84 ]
85);
86
87#[derive(Default, Clone, PartialEq, Deserialize, JsonSchema)]
88pub struct NewThread {
89 #[serde(default)]
90 from_thread_id: Option<ThreadId>,
91}
92
93#[derive(PartialEq, Clone, Default, Debug, Deserialize, JsonSchema)]
94pub struct ManageProfiles {
95 #[serde(default)]
96 pub customize_tools: Option<AgentProfileId>,
97}
98
99impl ManageProfiles {
100 pub fn customize_tools(profile_id: AgentProfileId) -> Self {
101 Self {
102 customize_tools: Some(profile_id),
103 }
104 }
105}
106
107impl_actions!(agent, [NewThread, ManageProfiles]);
108
109#[derive(Clone)]
110pub(crate) enum ModelUsageContext {
111 Thread(Entity<Thread>),
112 InlineAssistant,
113}
114
115impl ModelUsageContext {
116 pub fn configured_model(&self, cx: &App) -> Option<ConfiguredModel> {
117 match self {
118 Self::Thread(thread) => thread.read(cx).configured_model(),
119 Self::InlineAssistant => {
120 LanguageModelRegistry::read_global(cx).inline_assistant_model()
121 }
122 }
123 }
124
125 pub fn language_model(&self, cx: &App) -> Option<Arc<dyn LanguageModel>> {
126 self.configured_model(cx)
127 .map(|configured_model| configured_model.model)
128 }
129}
130
131/// Initializes the `agent` crate.
132pub fn init(
133 fs: Arc<dyn Fs>,
134 client: Arc<Client>,
135 prompt_builder: Arc<PromptBuilder>,
136 language_registry: Arc<LanguageRegistry>,
137 is_eval: bool,
138 cx: &mut App,
139) {
140 AgentSettings::register(cx);
141 SlashCommandSettings::register(cx);
142
143 assistant_context_editor::init(client.clone(), cx);
144 rules_library::init(cx);
145 if !is_eval {
146 // Initializing the language model from the user settings messes with the eval, so we only initialize them when
147 // we're not running inside of the eval.
148 init_language_model_settings(cx);
149 }
150 assistant_slash_command::init(cx);
151 agent::init(cx);
152 agent_panel::init(cx);
153 context_server_configuration::init(language_registry.clone(), fs.clone(), cx);
154
155 register_slash_commands(cx);
156 inline_assistant::init(
157 fs.clone(),
158 prompt_builder.clone(),
159 client.telemetry().clone(),
160 cx,
161 );
162 terminal_inline_assistant::init(
163 fs.clone(),
164 prompt_builder.clone(),
165 client.telemetry().clone(),
166 cx,
167 );
168 indexed_docs::init(cx);
169 cx.observe_new(move |workspace, window, cx| {
170 ConfigureContextServerModal::register(workspace, language_registry.clone(), window, cx)
171 })
172 .detach();
173 cx.observe_new(ManageProfilesModal::register).detach();
174}
175
176fn init_language_model_settings(cx: &mut App) {
177 update_active_language_model_from_settings(cx);
178
179 cx.observe_global::<SettingsStore>(update_active_language_model_from_settings)
180 .detach();
181 cx.subscribe(
182 &LanguageModelRegistry::global(cx),
183 |_, event: &language_model::Event, cx| match event {
184 language_model::Event::ProviderStateChanged
185 | language_model::Event::AddedProvider(_)
186 | language_model::Event::RemovedProvider(_) => {
187 update_active_language_model_from_settings(cx);
188 }
189 _ => {}
190 },
191 )
192 .detach();
193}
194
195fn update_active_language_model_from_settings(cx: &mut App) {
196 let settings = AgentSettings::get_global(cx);
197
198 fn to_selected_model(selection: &LanguageModelSelection) -> language_model::SelectedModel {
199 language_model::SelectedModel {
200 provider: LanguageModelProviderId::from(selection.provider.0.clone()),
201 model: LanguageModelId::from(selection.model.clone()),
202 }
203 }
204
205 let default = to_selected_model(&settings.default_model);
206 let inline_assistant = settings
207 .inline_assistant_model
208 .as_ref()
209 .map(to_selected_model);
210 let commit_message = settings
211 .commit_message_model
212 .as_ref()
213 .map(to_selected_model);
214 let thread_summary = settings
215 .thread_summary_model
216 .as_ref()
217 .map(to_selected_model);
218 let inline_alternatives = settings
219 .inline_alternatives
220 .iter()
221 .map(to_selected_model)
222 .collect::<Vec<_>>();
223
224 LanguageModelRegistry::global(cx).update(cx, |registry, cx| {
225 registry.select_default_model(Some(&default), cx);
226 registry.select_inline_assistant_model(inline_assistant.as_ref(), cx);
227 registry.select_commit_message_model(commit_message.as_ref(), cx);
228 registry.select_thread_summary_model(thread_summary.as_ref(), cx);
229 registry.select_inline_alternative_models(inline_alternatives, cx);
230 });
231}
232
233fn register_slash_commands(cx: &mut App) {
234 let slash_command_registry = SlashCommandRegistry::global(cx);
235
236 slash_command_registry.register_command(assistant_slash_commands::FileSlashCommand, true);
237 slash_command_registry.register_command(assistant_slash_commands::DeltaSlashCommand, true);
238 slash_command_registry.register_command(assistant_slash_commands::OutlineSlashCommand, true);
239 slash_command_registry.register_command(assistant_slash_commands::TabSlashCommand, true);
240 slash_command_registry
241 .register_command(assistant_slash_commands::CargoWorkspaceSlashCommand, true);
242 slash_command_registry.register_command(assistant_slash_commands::PromptSlashCommand, true);
243 slash_command_registry.register_command(assistant_slash_commands::SelectionCommand, true);
244 slash_command_registry.register_command(assistant_slash_commands::DefaultSlashCommand, false);
245 slash_command_registry.register_command(assistant_slash_commands::NowSlashCommand, false);
246 slash_command_registry
247 .register_command(assistant_slash_commands::DiagnosticsSlashCommand, true);
248 slash_command_registry.register_command(assistant_slash_commands::FetchSlashCommand, true);
249
250 cx.observe_flag::<assistant_slash_commands::StreamingExampleSlashCommandFeatureFlag, _>({
251 let slash_command_registry = slash_command_registry.clone();
252 move |is_enabled, _cx| {
253 if is_enabled {
254 slash_command_registry.register_command(
255 assistant_slash_commands::StreamingExampleSlashCommand,
256 false,
257 );
258 }
259 }
260 })
261 .detach();
262
263 update_slash_commands_from_settings(cx);
264 cx.observe_global::<SettingsStore>(update_slash_commands_from_settings)
265 .detach();
266}
267
268fn update_slash_commands_from_settings(cx: &mut App) {
269 let slash_command_registry = SlashCommandRegistry::global(cx);
270 let settings = SlashCommandSettings::get_global(cx);
271
272 if settings.docs.enabled {
273 slash_command_registry.register_command(assistant_slash_commands::DocsSlashCommand, true);
274 } else {
275 slash_command_registry.unregister_command(assistant_slash_commands::DocsSlashCommand);
276 }
277
278 if settings.cargo_workspace.enabled {
279 slash_command_registry
280 .register_command(assistant_slash_commands::CargoWorkspaceSlashCommand, true);
281 } else {
282 slash_command_registry
283 .unregister_command(assistant_slash_commands::CargoWorkspaceSlashCommand);
284 }
285}