swiftide_agents/
system_prompt.rs1use derive_builder::Builder;
13use swiftide_core::prompt::Prompt;
14
15#[derive(Clone, Debug, Builder)]
16#[builder(setter(into, strip_option))]
17pub struct SystemPrompt {
18    #[builder(default)]
20    role: Option<String>,
21
22    #[builder(default, setter(custom))]
24    guidelines: Vec<String>,
25    #[builder(default, setter(custom))]
27    constraints: Vec<String>,
28
29    #[builder(default = default_prompt_template())]
31    template: Prompt,
32}
33
34impl SystemPrompt {
35    pub fn builder() -> SystemPromptBuilder {
36        SystemPromptBuilder::default()
37    }
38}
39
40impl Default for SystemPrompt {
41    fn default() -> Self {
42        SystemPrompt {
43            role: None,
44            guidelines: Vec::new(),
45            constraints: Vec::new(),
46            template: default_prompt_template(),
47        }
48    }
49}
50
51impl SystemPromptBuilder {
52    pub fn guidelines<T: IntoIterator<Item = S>, S: AsRef<str>>(
53        &mut self,
54        guidelines: T,
55    ) -> &mut Self {
56        self.guidelines = Some(
57            guidelines
58                .into_iter()
59                .map(|s| s.as_ref().to_string())
60                .collect(),
61        );
62        self
63    }
64
65    pub fn constraints<T: IntoIterator<Item = S>, S: AsRef<str>>(
66        &mut self,
67        constraints: T,
68    ) -> &mut Self {
69        self.constraints = Some(
70            constraints
71                .into_iter()
72                .map(|s| s.as_ref().to_string())
73                .collect(),
74        );
75        self
76    }
77}
78
79fn default_prompt_template() -> Prompt {
80    include_str!("system_prompt_template.md").into()
81}
82
83#[allow(clippy::from_over_into)]
84impl Into<Prompt> for SystemPrompt {
85    fn into(self) -> Prompt {
86        let SystemPrompt {
87            role,
88            guidelines,
89            constraints,
90            template,
91        } = self;
92
93        template
94            .with_context_value("role", role)
95            .with_context_value("guidelines", guidelines)
96            .with_context_value("constraints", constraints)
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[tokio::test]
105    async fn test_customization() {
106        let prompt = SystemPrompt::builder()
107            .role("role")
108            .guidelines(["guideline"])
109            .constraints(vec!["constraint".to_string()])
110            .build()
111            .unwrap();
112
113        let prompt: Prompt = prompt.into();
114
115        let rendered = prompt.render().unwrap();
116
117        insta::assert_snapshot!(rendered);
118    }
119}