assistant: Remove `/project` (#27660)

Marshall Bowers created

This PR removes the `/project` command.

This was feature-flagged and was never released to the general public.

Release Notes:

- N/A

Change summary

Cargo.lock                                                      |   2 
crates/assistant/src/assistant.rs                               |  26 
crates/assistant_slash_commands/Cargo.toml                      |   2 
crates/assistant_slash_commands/src/assistant_slash_commands.rs |   2 
crates/assistant_slash_commands/src/project_command.rs          | 197 ---
5 files changed, 4 insertions(+), 225 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -671,12 +671,10 @@ dependencies = [
  "http_client",
  "indexed_docs",
  "language",
- "language_model",
  "pretty_assertions",
  "project",
  "prompt_store",
  "rope",
- "schemars",
  "semantic_index",
  "serde",
  "serde_json",

crates/assistant/src/assistant.rs 🔗

@@ -10,7 +10,7 @@ use std::sync::Arc;
 
 use assistant_settings::AssistantSettings;
 use assistant_slash_command::SlashCommandRegistry;
-use assistant_slash_commands::{ProjectSlashCommandFeatureFlag, SearchSlashCommandFeatureFlag};
+use assistant_slash_commands::SearchSlashCommandFeatureFlag;
 use client::Client;
 use command_palette_hooks::CommandPaletteFilter;
 use feature_flags::FeatureFlagAppExt;
@@ -108,11 +108,8 @@ pub fn init(
             let is_search_slash_command_enabled = cx
                 .update(|cx| cx.wait_for_flag::<SearchSlashCommandFeatureFlag>())?
                 .await;
-            let is_project_slash_command_enabled = cx
-                .update(|cx| cx.wait_for_flag::<ProjectSlashCommandFeatureFlag>())?
-                .await;
 
-            if !is_search_slash_command_enabled && !is_project_slash_command_enabled {
+            if !is_search_slash_command_enabled {
                 return Ok(());
             }
 
@@ -137,7 +134,7 @@ pub fn init(
     assistant_panel::init(cx);
     context_server::init(cx);
 
-    register_slash_commands(Some(prompt_builder.clone()), cx);
+    register_slash_commands(cx);
     inline_assistant::init(
         fs.clone(),
         prompt_builder.clone(),
@@ -213,7 +210,7 @@ fn update_active_language_model_from_settings(cx: &mut App) {
     });
 }
 
-fn register_slash_commands(prompt_builder: Option<Arc<PromptBuilder>>, cx: &mut App) {
+fn register_slash_commands(cx: &mut App) {
     let slash_command_registry = SlashCommandRegistry::global(cx);
 
     slash_command_registry.register_command(assistant_slash_commands::FileSlashCommand, true);
@@ -231,21 +228,6 @@ fn register_slash_commands(prompt_builder: Option<Arc<PromptBuilder>>, cx: &mut
         .register_command(assistant_slash_commands::DiagnosticsSlashCommand, true);
     slash_command_registry.register_command(assistant_slash_commands::FetchSlashCommand, true);
 
-    if let Some(prompt_builder) = prompt_builder {
-        cx.observe_flag::<assistant_slash_commands::ProjectSlashCommandFeatureFlag, _>({
-            let slash_command_registry = slash_command_registry.clone();
-            move |is_enabled, _cx| {
-                if is_enabled {
-                    slash_command_registry.register_command(
-                        assistant_slash_commands::ProjectSlashCommand::new(prompt_builder.clone()),
-                        true,
-                    );
-                }
-            }
-        })
-        .detach();
-    }
-
     cx.observe_flag::<assistant_slash_commands::StreamingExampleSlashCommandFeatureFlag, _>({
         let slash_command_registry = slash_command_registry.clone();
         move |is_enabled, _cx| {

crates/assistant_slash_commands/Cargo.toml 🔗

@@ -29,11 +29,9 @@ html_to_markdown.workspace = true
 http_client.workspace = true
 indexed_docs.workspace = true
 language.workspace = true
-language_model.workspace = true
 project.workspace = true
 prompt_store.workspace = true
 rope.workspace = true
-schemars.workspace = true
 semantic_index.workspace = true
 serde.workspace = true
 serde_json.workspace = true

crates/assistant_slash_commands/src/assistant_slash_commands.rs 🔗

@@ -7,7 +7,6 @@ mod docs_command;
 mod fetch_command;
 mod file_command;
 mod now_command;
-mod project_command;
 mod prompt_command;
 mod search_command;
 mod selection_command;
@@ -29,7 +28,6 @@ pub use crate::docs_command::*;
 pub use crate::fetch_command::*;
 pub use crate::file_command::*;
 pub use crate::now_command::*;
-pub use crate::project_command::*;
 pub use crate::prompt_command::*;
 pub use crate::search_command::*;
 pub use crate::selection_command::*;

crates/assistant_slash_commands/src/project_command.rs 🔗

@@ -1,197 +0,0 @@
-use std::{
-    fmt::Write as _,
-    ops::DerefMut,
-    sync::{atomic::AtomicBool, Arc},
-};
-
-use anyhow::{anyhow, Result};
-use assistant_slash_command::{
-    ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection,
-    SlashCommandResult,
-};
-use feature_flags::FeatureFlag;
-use gpui::{App, Task, WeakEntity};
-use language::{Anchor, CodeLabel, LspAdapterDelegate};
-use language_model::{LanguageModelRegistry, LanguageModelTool};
-use prompt_store::PromptBuilder;
-use schemars::JsonSchema;
-use semantic_index::SemanticDb;
-use serde::Deserialize;
-use ui::prelude::*;
-use workspace::Workspace;
-
-use super::{create_label_for_command, search_command::add_search_result_section};
-
-pub struct ProjectSlashCommandFeatureFlag;
-
-impl FeatureFlag for ProjectSlashCommandFeatureFlag {
-    const NAME: &'static str = "project-slash-command";
-}
-
-pub struct ProjectSlashCommand {
-    prompt_builder: Arc<PromptBuilder>,
-}
-
-impl ProjectSlashCommand {
-    pub fn new(prompt_builder: Arc<PromptBuilder>) -> Self {
-        Self { prompt_builder }
-    }
-}
-
-impl SlashCommand for ProjectSlashCommand {
-    fn name(&self) -> String {
-        "project".into()
-    }
-
-    fn label(&self, cx: &App) -> CodeLabel {
-        create_label_for_command("project", &[], cx)
-    }
-
-    fn description(&self) -> String {
-        "Generate a semantic search based on context".into()
-    }
-
-    fn icon(&self) -> IconName {
-        IconName::Folder
-    }
-
-    fn menu_text(&self) -> String {
-        self.description()
-    }
-
-    fn requires_argument(&self) -> bool {
-        false
-    }
-
-    fn complete_argument(
-        self: Arc<Self>,
-        _arguments: &[String],
-        _cancel: Arc<AtomicBool>,
-        _workspace: Option<WeakEntity<Workspace>>,
-        _window: &mut Window,
-        _cx: &mut App,
-    ) -> Task<Result<Vec<ArgumentCompletion>>> {
-        Task::ready(Ok(Vec::new()))
-    }
-
-    fn run(
-        self: Arc<Self>,
-        _arguments: &[String],
-        _context_slash_command_output_sections: &[SlashCommandOutputSection<Anchor>],
-        context_buffer: language::BufferSnapshot,
-        workspace: WeakEntity<Workspace>,
-        _delegate: Option<Arc<dyn LspAdapterDelegate>>,
-        window: &mut Window,
-        cx: &mut App,
-    ) -> Task<SlashCommandResult> {
-        let model_registry = LanguageModelRegistry::read_global(cx);
-        let current_model = model_registry.active_model();
-        let prompt_builder = self.prompt_builder.clone();
-
-        let Some(workspace) = workspace.upgrade() else {
-            return Task::ready(Err(anyhow::anyhow!("workspace was dropped")));
-        };
-        let project = workspace.read(cx).project().clone();
-        let fs = project.read(cx).fs().clone();
-        let Some(project_index) =
-            cx.update_global(|index: &mut SemanticDb, cx| index.project_index(project, cx))
-        else {
-            return Task::ready(Err(anyhow::anyhow!("no project indexer")));
-        };
-
-        window.spawn(cx, async move |cx| {
-            let current_model = current_model.ok_or_else(|| anyhow!("no model selected"))?;
-
-            let prompt =
-                prompt_builder.generate_project_slash_command_prompt(context_buffer.text())?;
-
-            let search_queries = current_model
-                .use_tool::<SearchQueries>(
-                    language_model::LanguageModelRequest {
-                        messages: vec![language_model::LanguageModelRequestMessage {
-                            role: language_model::Role::User,
-                            content: vec![language_model::MessageContent::Text(prompt)],
-                            cache: false,
-                        }],
-                        tools: vec![],
-                        stop: vec![],
-                        temperature: None,
-                    },
-                    cx.deref_mut(),
-                )
-                .await?
-                .search_queries;
-
-            let results = project_index
-                .read_with(cx, |project_index, cx| {
-                    project_index.search(search_queries.clone(), 25, cx)
-                })?
-                .await?;
-
-            let results = SemanticDb::load_results(results, &fs, &cx).await?;
-
-            cx.background_spawn(async move {
-                let mut output = "Project context:\n".to_string();
-                let mut sections = Vec::new();
-
-                for (ix, query) in search_queries.into_iter().enumerate() {
-                    let start_ix = output.len();
-                    writeln!(&mut output, "Results for {query}:").unwrap();
-                    let mut has_results = false;
-                    for result in &results {
-                        if result.query_index == ix {
-                            add_search_result_section(result, &mut output, &mut sections);
-                            has_results = true;
-                        }
-                    }
-                    if has_results {
-                        sections.push(SlashCommandOutputSection {
-                            range: start_ix..output.len(),
-                            icon: IconName::MagnifyingGlass,
-                            label: query.into(),
-                            metadata: None,
-                        });
-                        output.push('\n');
-                    } else {
-                        output.truncate(start_ix);
-                    }
-                }
-
-                sections.push(SlashCommandOutputSection {
-                    range: 0..output.len(),
-                    icon: IconName::Book,
-                    label: "Project context".into(),
-                    metadata: None,
-                });
-
-                Ok(SlashCommandOutput {
-                    text: output,
-                    sections,
-                    run_commands_in_text: true,
-                }
-                .to_event_stream())
-            })
-            .await
-        })
-    }
-}
-
-#[derive(JsonSchema, Deserialize)]
-struct SearchQueries {
-    /// An array of semantic search queries.
-    ///
-    /// These queries will be used to search the user's codebase.
-    /// The function can only accept 4 queries, otherwise it will error.
-    /// As such, it's important that you limit the length of the search_queries array to 5 queries or less.
-    search_queries: Vec<String>,
-}
-
-impl LanguageModelTool for SearchQueries {
-    fn name() -> String {
-        "search_queries".to_string()
-    }
-
-    fn description() -> String {
-        "Generate semantic search queries based on context".to_string()
-    }
-}