doum_cli/llm/
prompt.rs

1use crate::system::SystemInfo;
2use handlebars::Handlebars;
3use rust_embed::RustEmbed;
4use serde_json::json;
5
6/// Embed prompt assets
7#[derive(RustEmbed)]
8#[folder = "static/prompts/"]
9struct PromptAssets;
10
11/// Prompt builder structure
12pub struct PromptBuilder {
13    system_info: SystemInfo,
14    handlebars: Handlebars<'static>,
15}
16
17impl PromptBuilder {
18    /// Create new PromptBuilder
19    pub fn new(system_info: SystemInfo) -> Self {
20        Self {
21            system_info,
22            handlebars: Handlebars::new(),
23        }
24    }
25
26    /// Load prompt file content
27    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    /// Create common prompt section
42    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    /// Create Ask mode message array
59    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    /// Create Suggest mode message array
68    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    /// Create Mode Select message array
87    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}