diff --git a/assets/icons/route.svg b/assets/icons/route.svg
new file mode 100644
index 00000000000000..7d2a5621ff425a
--- /dev/null
+++ b/assets/icons/route.svg
@@ -0,0 +1 @@
+
diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs
index 4c6941d756dc57..47266cf03137e8 100644
--- a/crates/assistant/src/assistant.rs
+++ b/crates/assistant/src/assistant.rs
@@ -31,7 +31,7 @@ use settings::{update_settings_file, Settings, SettingsStore};
use slash_command::{
active_command, default_command, diagnostics_command, docs_command, fetch_command,
file_command, now_command, project_command, prompt_command, search_command, symbols_command,
- tabs_command, term_command,
+ tabs_command, term_command, workflow_command,
};
use std::sync::Arc;
pub(crate) use streaming_diff::*;
@@ -260,6 +260,7 @@ fn register_slash_commands(cx: &mut AppContext) {
slash_command_registry.register_command(now_command::NowSlashCommand, true);
slash_command_registry.register_command(diagnostics_command::DiagnosticsSlashCommand, true);
slash_command_registry.register_command(docs_command::DocsSlashCommand, true);
+ slash_command_registry.register_command(workflow_command::WorkflowSlashCommand, true);
slash_command_registry.register_command(fetch_command::FetchSlashCommand, false);
}
diff --git a/crates/assistant/src/prompt_library.rs b/crates/assistant/src/prompt_library.rs
index f83d16a571c053..23f76177f70200 100644
--- a/crates/assistant/src/prompt_library.rs
+++ b/crates/assistant/src/prompt_library.rs
@@ -1201,6 +1201,12 @@ impl PromptStore {
let mut txn = db_env.write_txn()?;
let metadata = db_env.create_database(&mut txn, Some("metadata.v2"))?;
let bodies = db_env.create_database(&mut txn, Some("bodies.v2"))?;
+
+ // Remove edit workflow prompt, as we decided to opt into it using
+ // a slash command instead.
+ metadata.delete(&mut txn, &PromptId::EditWorkflow).ok();
+ bodies.delete(&mut txn, &PromptId::EditWorkflow).ok();
+
txn.commit()?;
Self::upgrade_dbs(&db_env, metadata, bodies).log_err();
@@ -1209,17 +1215,13 @@ impl PromptStore {
let metadata_cache = MetadataCache::from_db(metadata, &txn)?;
txn.commit()?;
- let store = PromptStore {
+ Ok(PromptStore {
executor,
env: db_env,
metadata_cache: RwLock::new(metadata_cache),
metadata,
bodies,
- };
-
- store.save_built_in_prompts().log_err();
-
- Ok(store)
+ })
}
})
}
@@ -1425,49 +1427,6 @@ impl PromptStore {
})
}
- fn save_built_in_prompts(&self) -> Result<()> {
- self.save_built_in_prompt(
- PromptId::EditWorkflow,
- "Built-in: Editing Workflow",
- "prompts/edit_workflow.md",
- )?;
- Ok(())
- }
-
- /// Write a built-in prompt to the database, preserving the value of the default field
- /// if a prompt with this id already exists. This method blocks.
- fn save_built_in_prompt(
- &self,
- id: PromptId,
- title: impl Into,
- body_path: &str,
- ) -> Result<()> {
- let mut metadata_cache = self.metadata_cache.write();
- let existing_metadata = metadata_cache.metadata_by_id.get(&id).cloned();
-
- let prompt_metadata = PromptMetadata {
- id,
- title: Some(title.into()),
- default: existing_metadata.map_or(true, |m| m.default),
- saved_at: Utc::now(),
- };
-
- metadata_cache.insert(prompt_metadata.clone());
-
- let db_connection = self.env.clone();
- let bodies = self.bodies;
- let metadata_db = self.metadata;
-
- let mut txn = db_connection.write_txn()?;
- metadata_db.put(&mut txn, &id, &prompt_metadata)?;
-
- let body = String::from_utf8(Assets.load(body_path)?.unwrap().to_vec())?;
- bodies.put(&mut txn, &id, &body)?;
-
- txn.commit()?;
- Ok(())
- }
-
fn save_metadata(
&self,
id: PromptId,
diff --git a/crates/assistant/src/slash_command.rs b/crates/assistant/src/slash_command.rs
index c64820cbd8f6e9..516fe2fa5ebc3c 100644
--- a/crates/assistant/src/slash_command.rs
+++ b/crates/assistant/src/slash_command.rs
@@ -30,6 +30,7 @@ pub mod search_command;
pub mod symbols_command;
pub mod tabs_command;
pub mod term_command;
+pub mod workflow_command;
pub(crate) struct SlashCommandCompletionProvider {
cancel_flag: Mutex>,
diff --git a/crates/assistant/src/slash_command/workflow_command.rs b/crates/assistant/src/slash_command/workflow_command.rs
new file mode 100644
index 00000000000000..f55275f0114905
--- /dev/null
+++ b/crates/assistant/src/slash_command/workflow_command.rs
@@ -0,0 +1,71 @@
+use std::sync::atomic::AtomicBool;
+use std::sync::Arc;
+
+use anyhow::{Context as _, Result};
+use assets::Assets;
+use assistant_slash_command::{
+ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection,
+};
+use gpui::{AppContext, AssetSource, Task, WeakView};
+use language::LspAdapterDelegate;
+use text::LineEnding;
+use ui::prelude::*;
+use workspace::Workspace;
+
+pub(crate) struct WorkflowSlashCommand;
+
+impl SlashCommand for WorkflowSlashCommand {
+ fn name(&self) -> String {
+ "workflow".into()
+ }
+
+ fn description(&self) -> String {
+ "insert a prompt that opts into the edit workflow".into()
+ }
+
+ fn menu_text(&self) -> String {
+ "Insert Workflow Prompt".into()
+ }
+
+ fn requires_argument(&self) -> bool {
+ false
+ }
+
+ fn complete_argument(
+ self: Arc,
+ _query: String,
+ _cancel: Arc,
+ _workspace: Option>,
+ _cx: &mut AppContext,
+ ) -> Task>> {
+ Task::ready(Ok(Vec::new()))
+ }
+
+ fn run(
+ self: Arc,
+ _argument: Option<&str>,
+ _workspace: WeakView,
+ _delegate: Option>,
+ _cx: &mut WindowContext,
+ ) -> Task> {
+ let mut text = match Assets
+ .load("prompts/edit_workflow.md")
+ .and_then(|prompt| prompt.context("prompts/edit_workflow.md not found"))
+ {
+ Ok(prompt) => String::from_utf8_lossy(&prompt).into_owned(),
+ Err(error) => return Task::ready(Err(error)),
+ };
+ LineEnding::normalize(&mut text);
+ let range = 0..text.len();
+
+ Task::ready(Ok(SlashCommandOutput {
+ text,
+ sections: vec![SlashCommandOutputSection {
+ range,
+ icon: IconName::Route,
+ label: "Workflow".into(),
+ }],
+ run_commands_in_text: false,
+ }))
+ }
+}
diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs
index fdcdeafa01bad6..4ef5e0574e1bac 100644
--- a/crates/ui/src/components/icon.rs
+++ b/crates/ui/src/components/icon.rs
@@ -223,6 +223,7 @@ pub enum IconName {
Rerun,
Return,
Reveal,
+ Route,
RotateCcw,
RotateCw,
Save,
@@ -385,6 +386,7 @@ impl IconName {
IconName::Reveal => "icons/reveal.svg",
IconName::RotateCcw => "icons/rotate_ccw.svg",
IconName::RotateCw => "icons/rotate_cw.svg",
+ IconName::Route => "icons/route.svg",
IconName::Save => "icons/save.svg",
IconName::Screen => "icons/desktop.svg",
IconName::SearchSelection => "icons/search_selection.svg",