1pub mod fragments;
17
18use agent_works::prompt::{FragmentContext, PromptFragment, compose_fragments};
19
20use fragments::{CoreInstructionsFragment, MemoryFragment, NetworkEnvironmentFragment};
21
22pub fn build_system_prompt() -> String {
29 build_system_prompt_with_fragments(&[], &[], false)
30}
31
32pub fn build_system_prompt_cn() -> String {
37 build_system_prompt_with_fragments(&[], &[], true)
38}
39
40pub fn build_system_prompt_with_fragments(
50 extra_fragments: &[Box<dyn PromptFragment>],
51 tool_definitions: &[serde_json::Value],
52 include_cn: bool,
53) -> String {
54 let ctx = FragmentContext {
55 tool_definitions,
56 session_id: "", };
58
59 let mut fragments: Vec<Box<dyn PromptFragment>> = vec![Box::new(CoreInstructionsFragment)];
60
61 if include_cn {
62 fragments.push(Box::new(NetworkEnvironmentFragment));
63 }
64
65 fragments.push(Box::new(MemoryFragment));
67
68 fragments.extend(extra_fragments.iter().map(|f| dyn_clone::clone_box(f.as_ref())));
70
71 let body = compose_fragments(&fragments, &ctx);
72
73 body.replacen("\n\n## Memory", "\n---\n\n## Memory", 1)
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_build_system_prompt() {
85 let prompt = build_system_prompt();
86 assert!(prompt.contains("versatile AI assistant"));
87 assert!(prompt.contains("[Conversation Type Detection]"));
88 assert!(prompt.contains("[Execution Guidelines]"));
89 assert!(prompt.contains("[Wrap-Up]"));
90 assert!(prompt.contains("\n---\n"));
92 }
93
94 #[test]
95 fn test_build_system_prompt_cn() {
96 let prompt = build_system_prompt_cn();
97 assert!(prompt.contains("versatile AI assistant"));
99 assert!(prompt.contains("[Network Environment]"));
100 assert!(prompt.contains("mainland China"));
101 assert!(prompt.contains("Baidu"));
102 assert!(prompt.contains("gitee.com"));
103 }
104
105 #[test]
106 fn test_build_system_prompt_with_custom_fragments() {
107 #[derive(Clone)]
108 struct CustomFragment;
109 impl PromptFragment for CustomFragment {
110 fn name(&self) -> &str {
111 "custom"
112 }
113 fn priority(&self) -> i32 {
114 200
115 }
116 fn render(&self, _ctx: &FragmentContext) -> Option<String> {
117 Some("[Custom Section]".to_string())
118 }
119 }
120
121 let extra: Vec<Box<dyn PromptFragment>> = vec![Box::new(CustomFragment)];
122 let prompt = build_system_prompt_with_fragments(&extra, &[], false);
123 assert!(prompt.contains("[Custom Section]"));
124 assert!(prompt.contains("versatile AI assistant"));
125 }
126
127 #[test]
128 fn test_backward_compat_output_matches_original() {
129 let prompt = build_system_prompt();
132 let original_sections = [
133 "You are a versatile AI assistant",
134 "[Role]",
135 "[Conversation Type Detection]",
136 "[Thinking Approach]",
137 "[Execution Guidelines]",
138 "[File Operation Guidelines]",
139 "[Wrap-Up]",
140 "## Memory",
141 "MEMORY.md",
142 ];
143 for section in &original_sections {
144 assert!(prompt.contains(section), "Missing section: {}", section);
145 }
146 }
147}