oven_cli/agents/
implementer.rs1use anyhow::{Context, Result};
2use askama::Template;
3
4use super::AgentContext;
5
6#[derive(Template)]
7#[template(path = "implementer.txt")]
8struct ImplementerPrompt<'a> {
9 ctx: &'a AgentContext,
10}
11
12pub fn build_prompt(ctx: &AgentContext) -> Result<String> {
13 let tmpl = ImplementerPrompt { ctx };
14 tmpl.render().context("rendering implementer template")
15}
16
17#[cfg(test)]
18mod tests {
19 use super::*;
20
21 fn sample_context() -> AgentContext {
22 AgentContext {
23 issue_number: 42,
24 issue_title: "Add retry logic".to_string(),
25 issue_body: "Implement retry for API calls".to_string(),
26 branch: "oven/issue-42-abcd1234".to_string(),
27 pr_number: Some(99),
28 test_command: Some("cargo test".to_string()),
29 lint_command: Some("cargo clippy".to_string()),
30 review_findings: None,
31 cycle: 1,
32 target_repo: None,
33 issue_source: "github".to_string(),
34 }
35 }
36
37 #[test]
38 fn prompt_includes_issue_details() {
39 let prompt = build_prompt(&sample_context()).unwrap();
40 assert!(prompt.contains("<issue_number>42</issue_number>"));
41 assert!(prompt.contains("<issue_title>Add retry logic</issue_title>"));
42 assert!(prompt.contains("Implement retry for API calls"));
43 assert!(prompt.contains("oven/issue-42-abcd1234"));
44 assert!(prompt.contains("PR: #99"));
45 }
46
47 #[test]
48 fn prompt_includes_scope_discipline() {
49 let prompt = build_prompt(&sample_context()).unwrap();
50 assert!(prompt.contains("Scope Discipline"));
51 assert!(prompt.contains("MUST NOT modify code outside the issue"));
52 }
53
54 #[test]
55 fn prompt_includes_verification_checklist() {
56 let prompt = build_prompt(&sample_context()).unwrap();
57 assert!(prompt.contains("Verification Checklist"));
58 assert!(prompt.contains("git diff main --stat"));
59 }
60
61 #[test]
62 fn prompt_includes_test_and_lint_commands() {
63 let prompt = build_prompt(&sample_context()).unwrap();
64 assert!(prompt.contains("cargo test"));
65 assert!(prompt.contains("cargo clippy"));
66 }
67
68 #[test]
69 fn prompt_without_test_command() {
70 let mut ctx = sample_context();
71 ctx.test_command = None;
72 let prompt = build_prompt(&ctx).unwrap();
73 assert!(!prompt.contains("cargo test"));
74 }
75
76 #[test]
77 fn prompt_includes_when_stuck_guidance() {
78 let prompt = build_prompt(&sample_context()).unwrap();
79 assert!(prompt.contains("When Stuck"));
80 assert!(prompt.contains("switch to a different strategy"));
81 }
82
83 #[test]
84 fn prompt_includes_commit_workflow() {
85 let prompt = build_prompt(&sample_context()).unwrap();
86 assert!(prompt.contains("Commit Workflow"));
87 assert!(prompt.contains("atomic conventional commits"));
88 }
89}