use std::sync::Arc;
use super::{Skill, SkillPrompter};
pub struct LazySkillPrompter {
title: String,
instruction_template: String,
item_prefix: String,
}
impl Default for LazySkillPrompter {
fn default() -> Self {
Self {
title: "## Available Skills".to_string(),
instruction_template:
"> Use `read_file` with the file path to read the full skill instructions."
.to_string(),
item_prefix: "- **".to_string(),
}
}
}
impl LazySkillPrompter {
pub fn new() -> Self {
Self::default()
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = title.into();
self
}
pub fn instruction(mut self, instruction: impl Into<String>) -> Self {
self.instruction_template = instruction.into();
self
}
pub fn item_prefix(mut self, prefix: impl Into<String>) -> Self {
self.item_prefix = prefix.into();
self
}
}
impl SkillPrompter for LazySkillPrompter {
fn build_prompt(&self, skills: &[Arc<dyn Skill>], _detail_tool_name: &str) -> String {
if skills.is_empty() {
return String::new();
}
let mut prompt = String::new();
prompt.push_str(&self.title);
prompt.push('\n');
for skill in skills {
let file_hint = if let Some(path) = skill.source_path() {
format!(" → `{}`", path.display())
} else {
String::new()
};
prompt.push_str(&format!(
"{}{}**{}**: {}{}\n",
self.item_prefix,
"", skill.name(),
skill.brief_description(),
file_hint,
));
}
prompt.push('\n');
prompt.push_str(&self.instruction_template);
prompt
}
}
pub struct FullDetailPrompter;
impl SkillPrompter for FullDetailPrompter {
fn build_prompt(&self, skills: &[Arc<dyn Skill>], _detail_tool_name: &str) -> String {
tracing::debug!("skill prompt generated");
if skills.is_empty() {
return String::new();
}
let mut prompt = String::from("## Available Skills\n\n");
for skill in skills {
prompt.push_str(&format!("### {}\n\n", skill.name()));
prompt.push_str(&skill.brief_description());
prompt.push_str("\n\n");
prompt.push_str(&skill.detailed_description());
prompt.push_str("\n\n---\n\n");
}
prompt
}
}