nano_agent/context/
system_prompt_generator.rs1use 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 pub fn new() -> Self {
14 Self {
15 background: None,
16 steps: None,
17 output_instructions: None,
18 context_provider: vec![],
19 }
20 }
21
22 pub fn with_background(mut self, background: Vec<String>) -> Self {
24 self.background = Some(background);
25 self
26 }
27
28 pub fn with_steps(mut self, steps: Vec<String>) -> Self {
30 self.steps = Some(steps);
31 self
32 }
33
34 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 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}