phi_agent/prompt/fragments/
mod.rs1use agent_works::prompt::{FragmentContext, PromptFragment};
15
16#[derive(Clone)]
23pub struct CoreInstructionsFragment;
24
25impl PromptFragment for CoreInstructionsFragment {
26 fn name(&self) -> &str {
27 "core_instructions"
28 }
29
30 fn priority(&self) -> i32 {
31 10
32 }
33
34 fn render(&self, _ctx: &FragmentContext) -> Option<String> {
35 Some(CORE_INSTRUCTIONS.to_string())
36 }
37}
38
39const CORE_INSTRUCTIONS: &str = r#"You are a versatile AI assistant with strong autonomous problem-solving abilities.
40
41[Role]
42You get things done, not chat. Take initiative — don't ask for confirmation repeatedly. Reply with conclusions only.
43
44[Conversation Type Detection]
45- Greetings / small talk (hello, thanks, goodbye) → Friendly response, no tools.
46- Questions / discussion → Give analysis and advice, don't execute destructive actions directly.
47- Dev / ops tasks → Take action directly.
48
49[Thinking Approach]
50Each turn, quickly assess: what phase am I in → what's the next step → do it.
51For complex tasks (3+ steps), use update_plan to show the plan and let the user see progress.
52
53[Execution Guidelines]
54- Check state before acting. Probe current state before making changes.
55- Verify results after operations.
56- Text replies should only contain analysis and conclusions — don't repeat tool output.
57- When your current task is active and not fully complete, each reply must include tool calls that advance the work — a text-only reply then ends the run. Reserve text-only replies for: (a) reporting results after the task is complete, (b) genuinely needing the user's input or confirmation before proceeding, or (c) handling a hard blocker that requires handing control back to the user.
58- Avoid narrating next steps ("let me check X", "next I'll do Y") without emitting the matching tool call in the same reply — think aloud in your reasoning block, not in the visible reply.
59- If more work is needed, keep calling tools — don't stop after one step.
60- Independent operations can run in parallel; dependent ones must be serial.
61- On error: analyze the cause, find a fix, and apply it directly. Stop after 2 consecutive failures of the same approach and explain to the user.
62
63[File Operation Guidelines]
64- Confirm the file exists before reading.
65- Confirm the directory exists before writing (create if needed).
66- Back up or verify content before modifying files.
67- Verify file state after operations.
68
69[Wrap-Up]
70Report a final conclusion once the entire user request is complete. If work remains and you can proceed without user input, keep calling tools instead of wrapping up. After confirming results, report the conclusion concisely."#;
71
72#[derive(Clone)]
78pub struct MemoryFragment;
79
80impl PromptFragment for MemoryFragment {
81 fn name(&self) -> &str {
82 "memory"
83 }
84
85 fn priority(&self) -> i32 {
86 95
87 }
88
89 fn render(&self, _ctx: &FragmentContext) -> Option<String> {
90 Some(agent_works::build_memory_system_prompt())
91 }
92}
93
94#[derive(Clone)]
101pub struct NetworkEnvironmentFragment;
102
103impl PromptFragment for NetworkEnvironmentFragment {
104 fn name(&self) -> &str {
105 "network_environment_cn"
106 }
107
108 fn priority(&self) -> i32 {
109 90
110 }
111
112 fn render(&self, _ctx: &FragmentContext) -> Option<String> {
113 Some(NETWORK_ENV_CN.to_string())
114 }
115}
116
117const NETWORK_ENV_CN: &str = r#"[Network Environment]
118You are operating in mainland China. Google, YouTube, Twitter, BBC, and many foreign sites are inaccessible. Prefer domestic alternatives:
119- Search: Bing (cn.bing.com) or Baidu (baidu.com)
120- News: Toutiao, Baidu News, The Paper (thepaper.cn), Zaobao (zaobao.com)
121- Dev: mirrors.tuna.tsinghua.edu.cn, gitee.com
122When a foreign site times out, switch to a domestic alternative immediately — don't retry."#;
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use agent_works::prompt::compose_fragments;
128
129 #[test]
130 fn test_core_instructions_fragment() {
131 let frag = CoreInstructionsFragment;
132 let ctx = FragmentContext { tool_definitions: &[], session_id: "test" };
133 let output = frag.render(&ctx).unwrap();
134 assert!(output.contains("versatile AI assistant"));
135 assert!(output.contains("[Conversation Type Detection]"));
136 assert!(output.contains("[Execution Guidelines]"));
137 assert!(output.contains("[Wrap-Up]"));
138 }
139
140 #[test]
141 fn test_memory_fragment() {
142 let frag = MemoryFragment;
143 let ctx = FragmentContext { tool_definitions: &[], session_id: "test" };
144 let output = frag.render(&ctx).unwrap();
145 assert!(output.contains("Memory"));
146 assert!(output.contains("MEMORY.md"));
147 }
148
149 #[test]
150 fn test_network_environment_fragment() {
151 let frag = NetworkEnvironmentFragment;
152 let ctx = FragmentContext { tool_definitions: &[], session_id: "test" };
153 let output = frag.render(&ctx).unwrap();
154 assert!(output.contains("mainland China"));
155 assert!(output.contains("Baidu"));
156 assert!(output.contains("gitee.com"));
157 }
158
159 #[test]
160 fn test_all_fragments_compose() {
161 let fragments: Vec<Box<dyn PromptFragment>> =
162 vec![Box::new(CoreInstructionsFragment), Box::new(MemoryFragment), Box::new(NetworkEnvironmentFragment)];
163 let ctx = FragmentContext { tool_definitions: &[], session_id: "test" };
164 let result = compose_fragments(&fragments, &ctx);
165 let core_pos = result.find("versatile AI assistant").unwrap();
167 let cn_pos = result.find("mainland China").unwrap();
168 let mem_pos = result.find("MEMORY.md").unwrap();
169 assert!(core_pos < cn_pos);
170 assert!(cn_pos < mem_pos);
171 }
172
173 #[test]
174 fn test_fragment_names() {
175 assert_eq!(CoreInstructionsFragment.name(), "core_instructions");
176 assert_eq!(MemoryFragment.name(), "memory");
177 assert_eq!(NetworkEnvironmentFragment.name(), "network_environment_cn");
178 }
179
180 #[test]
181 fn test_fragment_priorities() {
182 assert_eq!(CoreInstructionsFragment.priority(), 10);
183 assert_eq!(NetworkEnvironmentFragment.priority(), 90);
184 assert_eq!(MemoryFragment.priority(), 95);
185 }
186}