opi_coding_agent/
prompt.rs1use opi_ai::message::ToolDef;
10
11const BASE_INSTRUCTIONS: &str = "\
12You are opi, an expert coding agent. You help users with software engineering \
13tasks including reading, writing, and editing code, running commands, and \
14searching codebases. Be concise and precise. Explain your reasoning when \
15making changes.";
16
17pub struct SystemPromptBuilder {
19 tools: Vec<ToolDef>,
20 user_system: Option<String>,
21 context_files: Option<String>,
22}
23
24impl SystemPromptBuilder {
25 pub fn new() -> Self {
26 Self {
27 tools: Vec::new(),
28 user_system: None,
29 context_files: None,
30 }
31 }
32
33 pub fn tools(mut self, tools: Vec<ToolDef>) -> Self {
35 self.tools = tools;
36 self
37 }
38
39 pub fn user_system(mut self, content: impl Into<String>) -> Self {
41 let s = content.into();
42 self.user_system = if s.is_empty() { None } else { Some(s) };
43 self
44 }
45
46 pub fn context_files(mut self, content: impl Into<String>) -> Self {
48 let s = content.into();
49 self.context_files = if s.is_empty() { None } else { Some(s) };
50 self
51 }
52
53 pub fn tool_definitions(&self) -> &[ToolDef] {
55 &self.tools
56 }
57
58 pub fn build(self) -> String {
60 let mut parts = Vec::new();
61
62 parts.push(BASE_INSTRUCTIONS.to_owned());
64
65 if !self.tools.is_empty() {
67 let mut tool_section = String::from("Available tools:\n");
68 for tool in &self.tools {
69 tool_section.push_str(&format!("- {}: {}\n", tool.name, tool.description));
70 }
71 parts.push(tool_section);
72 }
73
74 if let Some(user) = self.user_system {
76 parts.push(format!("User instructions:\n{}", user));
77 }
78
79 if let Some(context) = self.context_files {
81 parts.push(format!("Project context:\n{}", context));
82 }
83
84 parts.join("\n\n")
85 }
86}
87
88impl Default for SystemPromptBuilder {
89 fn default() -> Self {
90 Self::new()
91 }
92}