use opi_ai::message::ToolDef;
const BASE_INSTRUCTIONS: &str = "\
You are opi, an expert coding agent. You help users with software engineering \
tasks including reading, writing, and editing code, running commands, and \
searching codebases. Be concise and precise. Explain your reasoning when \
making changes.";
pub struct SystemPromptBuilder {
tools: Vec<ToolDef>,
user_system: Option<String>,
context_files: Option<String>,
}
impl SystemPromptBuilder {
pub fn new() -> Self {
Self {
tools: Vec::new(),
user_system: None,
context_files: None,
}
}
pub fn tools(mut self, tools: Vec<ToolDef>) -> Self {
self.tools = tools;
self
}
pub fn user_system(mut self, content: impl Into<String>) -> Self {
let s = content.into();
self.user_system = if s.is_empty() { None } else { Some(s) };
self
}
pub fn context_files(mut self, content: impl Into<String>) -> Self {
let s = content.into();
self.context_files = if s.is_empty() { None } else { Some(s) };
self
}
pub fn tool_definitions(&self) -> &[ToolDef] {
&self.tools
}
pub fn build(self) -> String {
let mut parts = Vec::new();
parts.push(BASE_INSTRUCTIONS.to_owned());
if !self.tools.is_empty() {
let mut tool_section = String::from("Available tools:\n");
for tool in &self.tools {
tool_section.push_str(&format!("- {}: {}\n", tool.name, tool.description));
}
parts.push(tool_section);
}
if let Some(user) = self.user_system {
parts.push(format!("User instructions:\n{}", user));
}
if let Some(context) = self.context_files {
parts.push(format!("Project context:\n{}", context));
}
parts.join("\n\n")
}
}
impl Default for SystemPromptBuilder {
fn default() -> Self {
Self::new()
}
}