Skip to main content

nano_agent/context/
system_prompt_generator.rs

1use crate::context::ContextProvider;
2
3#[derive(Default)]
4pub struct SystemPromptGenerator {
5    background: Option<Vec<String>>,
6    steps: Option<Vec<String>>,
7    output_instructions: Option<Vec<String>>,
8    context_provider: Vec<Box<dyn ContextProvider + Send>>,
9}
10
11impl SystemPromptGenerator {
12    /// Create a new system prompt generator.
13    pub fn new() -> Self {
14        Self {
15            background: None,
16            steps: None,
17            output_instructions: None,
18            context_provider: vec![],
19        }
20    }
21
22    /// Set the background for the system prompt.
23    pub fn with_background(mut self, background: Vec<String>) -> Self {
24        self.background = Some(background);
25        self
26    }
27
28    /// Set the steps for the system prompt.
29    pub fn with_steps(mut self, steps: Vec<String>) -> Self {
30        self.steps = Some(steps);
31        self
32    }
33
34    /// Set the output instructions for the system prompt.
35    pub fn with_output_instructions(mut self, output_instructions: Vec<String>) -> Self {
36        self.output_instructions = Some(output_instructions);
37        self
38    }
39
40    pub(crate) fn get_context_providers_mut(
41        &mut self,
42    ) -> &mut Vec<Box<dyn ContextProvider + Send>> {
43        &mut self.context_provider
44    }
45
46    /// Generate the system prompt.
47    pub fn generate(&self) -> String {
48        let mut parts: Vec<String> = Vec::new();
49
50        let sections = [
51            ("IDENTITY and PURPOSE", self.background.as_ref()),
52            ("INTERNAL ASSISTANT STEPS", self.steps.as_ref()),
53            ("OUTPUT INSTRUCTIONS", self.output_instructions.as_ref()),
54        ];
55
56        for (title, content) in sections {
57            if let Some(items) = content {
58                if !items.is_empty() {
59                    parts.push(format!("# {title}"));
60                    for item in items {
61                        parts.push(format!("- {item}"));
62                    }
63                    parts.push(String::new());
64                }
65            }
66        }
67
68        if !self.context_provider.is_empty() {
69            parts.push("# EXTRA INFORMATION AND CONTEXT".to_string());
70            for provider in &self.context_provider {
71                let info = provider.get_info();
72                if !info.is_empty() {
73                    parts.push(format!("## {}", provider.title()));
74                    parts.push(info);
75                    parts.push(String::new());
76                }
77            }
78        }
79
80        parts.join("\n").trim().to_string()
81    }
82}