1use crate::system::SystemInfo;
2use handlebars::Handlebars;
3use rust_embed::RustEmbed;
4use serde_json::json;
5
6#[derive(RustEmbed)]
8#[folder = "static/prompts/"]
9struct PromptAssets;
10
11pub struct PromptBuilder {
13 system_info: SystemInfo,
14 handlebars: Handlebars<'static>,
15}
16
17impl PromptBuilder {
18 pub fn new(system_info: SystemInfo) -> Self {
20 Self {
21 system_info,
22 handlebars: Handlebars::new(),
23 }
24 }
25
26 fn load_prompt(name: &str) -> String {
28 PromptAssets::get(name)
29 .and_then(|file| {
30 std::str::from_utf8(file.data.as_ref())
31 .ok()
32 .map(|s| s.to_string())
33 })
34 .unwrap_or_else(|| {
35 eprintln!("Warning: Failed to load prompt file: {}", name);
36 tracing::warn!("Failed to load prompt file: {}", name);
37 String::new()
38 })
39 }
40
41 fn build_common_prompt(&self) -> String {
43 let template = Self::load_prompt("common.md");
44
45 let data = json!({
46 "os": self.system_info.os.as_str(),
47 "shell": self.system_info.shell.as_str(),
48 "current_dir": self.system_info.current_dir.display().to_string(),
49 "username": self.system_info.username.as_deref().unwrap_or("unknown"),
50 "hostname": self.system_info.hostname.as_deref().unwrap_or("unknown"),
51 });
52
53 self.handlebars
54 .render_template(&template, &data)
55 .unwrap_or(template)
56 }
57
58 pub fn build_ask(&self) -> String {
60 let common_prompt = self.build_common_prompt();
61 let ask_template = Self::load_prompt("ask.md");
62
63 let prompt = format!("{}\n\n---\n\n{}", common_prompt, ask_template);
64 prompt
65 }
66
67 pub fn build_suggest(&self) -> String {
69 let common_prompt = self.build_common_prompt();
70 let suggest_template = Self::load_prompt("suggest.md");
71
72 let data = json!({
73 "os": self.system_info.os.as_str(),
74 "shell": self.system_info.shell.as_str(),
75 });
76
77 let suggest_prompt = self
78 .handlebars
79 .render_template(&suggest_template, &data)
80 .unwrap_or(suggest_template);
81
82 let prompt = format!("{}\n\n---\n\n{}", common_prompt, suggest_prompt);
83 prompt
84 }
85
86 pub fn build_mode_select(&self) -> String {
88 let common_prompt = self.build_common_prompt();
89 let mode_select_template = Self::load_prompt("mode_select.md");
90
91 let prompt = format!("{}\n\n---\n\n{}", common_prompt, mode_select_template);
92 prompt
93 }
94}