Introduce a new /workflow
command (#15854)
This subsumes the previous built-in prompt. Release Notes: - N/A
This commit is contained in:
parent
889a14a2c2
commit
411934bb61
6 changed files with 85 additions and 50 deletions
1
assets/icons/route.svg
Normal file
1
assets/icons/route.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-route"><circle cx="6" cy="19" r="3"/><path d="M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15"/><circle cx="18" cy="5" r="3"/></svg>
|
After Width: | Height: | Size: 340 B |
|
@ -31,7 +31,7 @@ use settings::{update_settings_file, Settings, SettingsStore};
|
||||||
use slash_command::{
|
use slash_command::{
|
||||||
active_command, default_command, diagnostics_command, docs_command, fetch_command,
|
active_command, default_command, diagnostics_command, docs_command, fetch_command,
|
||||||
file_command, now_command, project_command, prompt_command, search_command, symbols_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;
|
use std::sync::Arc;
|
||||||
pub(crate) use streaming_diff::*;
|
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(now_command::NowSlashCommand, true);
|
||||||
slash_command_registry.register_command(diagnostics_command::DiagnosticsSlashCommand, true);
|
slash_command_registry.register_command(diagnostics_command::DiagnosticsSlashCommand, true);
|
||||||
slash_command_registry.register_command(docs_command::DocsSlashCommand, 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);
|
slash_command_registry.register_command(fetch_command::FetchSlashCommand, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1201,6 +1201,12 @@ impl PromptStore {
|
||||||
let mut txn = db_env.write_txn()?;
|
let mut txn = db_env.write_txn()?;
|
||||||
let metadata = db_env.create_database(&mut txn, Some("metadata.v2"))?;
|
let metadata = db_env.create_database(&mut txn, Some("metadata.v2"))?;
|
||||||
let bodies = db_env.create_database(&mut txn, Some("bodies.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()?;
|
txn.commit()?;
|
||||||
|
|
||||||
Self::upgrade_dbs(&db_env, metadata, bodies).log_err();
|
Self::upgrade_dbs(&db_env, metadata, bodies).log_err();
|
||||||
|
@ -1209,17 +1215,13 @@ impl PromptStore {
|
||||||
let metadata_cache = MetadataCache::from_db(metadata, &txn)?;
|
let metadata_cache = MetadataCache::from_db(metadata, &txn)?;
|
||||||
txn.commit()?;
|
txn.commit()?;
|
||||||
|
|
||||||
let store = PromptStore {
|
Ok(PromptStore {
|
||||||
executor,
|
executor,
|
||||||
env: db_env,
|
env: db_env,
|
||||||
metadata_cache: RwLock::new(metadata_cache),
|
metadata_cache: RwLock::new(metadata_cache),
|
||||||
metadata,
|
metadata,
|
||||||
bodies,
|
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<SharedString>,
|
|
||||||
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(
|
fn save_metadata(
|
||||||
&self,
|
&self,
|
||||||
id: PromptId,
|
id: PromptId,
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub mod search_command;
|
||||||
pub mod symbols_command;
|
pub mod symbols_command;
|
||||||
pub mod tabs_command;
|
pub mod tabs_command;
|
||||||
pub mod term_command;
|
pub mod term_command;
|
||||||
|
pub mod workflow_command;
|
||||||
|
|
||||||
pub(crate) struct SlashCommandCompletionProvider {
|
pub(crate) struct SlashCommandCompletionProvider {
|
||||||
cancel_flag: Mutex<Arc<AtomicBool>>,
|
cancel_flag: Mutex<Arc<AtomicBool>>,
|
||||||
|
|
71
crates/assistant/src/slash_command/workflow_command.rs
Normal file
71
crates/assistant/src/slash_command/workflow_command.rs
Normal file
|
@ -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<Self>,
|
||||||
|
_query: String,
|
||||||
|
_cancel: Arc<AtomicBool>,
|
||||||
|
_workspace: Option<WeakView<Workspace>>,
|
||||||
|
_cx: &mut AppContext,
|
||||||
|
) -> Task<Result<Vec<ArgumentCompletion>>> {
|
||||||
|
Task::ready(Ok(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
self: Arc<Self>,
|
||||||
|
_argument: Option<&str>,
|
||||||
|
_workspace: WeakView<Workspace>,
|
||||||
|
_delegate: Option<Arc<dyn LspAdapterDelegate>>,
|
||||||
|
_cx: &mut WindowContext,
|
||||||
|
) -> Task<Result<SlashCommandOutput>> {
|
||||||
|
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,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
|
@ -223,6 +223,7 @@ pub enum IconName {
|
||||||
Rerun,
|
Rerun,
|
||||||
Return,
|
Return,
|
||||||
Reveal,
|
Reveal,
|
||||||
|
Route,
|
||||||
RotateCcw,
|
RotateCcw,
|
||||||
RotateCw,
|
RotateCw,
|
||||||
Save,
|
Save,
|
||||||
|
@ -385,6 +386,7 @@ impl IconName {
|
||||||
IconName::Reveal => "icons/reveal.svg",
|
IconName::Reveal => "icons/reveal.svg",
|
||||||
IconName::RotateCcw => "icons/rotate_ccw.svg",
|
IconName::RotateCcw => "icons/rotate_ccw.svg",
|
||||||
IconName::RotateCw => "icons/rotate_cw.svg",
|
IconName::RotateCw => "icons/rotate_cw.svg",
|
||||||
|
IconName::Route => "icons/route.svg",
|
||||||
IconName::Save => "icons/save.svg",
|
IconName::Save => "icons/save.svg",
|
||||||
IconName::Screen => "icons/desktop.svg",
|
IconName::Screen => "icons/desktop.svg",
|
||||||
IconName::SearchSelection => "icons/search_selection.svg",
|
IconName::SearchSelection => "icons/search_selection.svg",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue