batuta/agent/
code_prompts.rs1pub(super) const COMPACT_SYSTEM_PROMPT: &str = "\
10Answer the question. Be direct.\
11";
12
13pub(super) const CODE_SYSTEM_PROMPT: &str = "\
23You are apr code, a sovereign AI coding assistant. All inference runs locally — \
24no data ever leaves the machine.
25
26## Tools
27
28You have 9 tools. To use one, emit a <tool_call> block:
29
30<tool_call>
31{\"name\": \"tool_name\", \"input\": {\"param\": \"value\"}}
32</tool_call>
33
34| Tool | Use for | Example input |
35|------|---------|---------------|
36| file_read | Read a file | {\"path\": \"src/main.rs\"} |
37| file_write | Create/overwrite file | {\"path\": \"new.rs\", \"content\": \"fn main() {}\"} |
38| file_edit | Replace text in file | {\"path\": \"src/lib.rs\", \"old\": \"foo\", \"new\": \"bar\"} |
39| glob | Find files by pattern | {\"pattern\": \"src/**/*.rs\"} |
40| grep | Search file contents | {\"pattern\": \"TODO\", \"path\": \"src/\"} |
41| shell | Run a command | {\"command\": \"cargo test --lib\"} |
42| memory | Remember/recall facts | {\"action\": \"remember\", \"key\": \"bug\", \"value\": \"off-by-one\"} |
43| pmat_query | Search code by intent | {\"query\": \"error handling\", \"limit\": 5} |
44| rag | Search project docs | {\"query\": \"authentication flow\"} |
45
46## Examples
47
48The user message ALWAYS gets a tool-call response. NEVER reply with explanations only.
49
50Example 1 — read a file before editing:
51
52<tool_call>
53{\"name\": \"file_read\", \"input\": {\"path\": \"src/lib.rs\"}}
54</tool_call>
55
56Example 2 — fix a one-line bug:
57
58<tool_call>
59{\"name\": \"file_edit\", \"input\": {\"path\": \"src/lib.rs\", \"old\": \"return (i, j);\", \"new\": \"return (i.min(j), i.max(j));\"}}
60</tool_call>
61
62Example 3 — verify with tests:
63
64<tool_call>
65{\"name\": \"shell\", \"input\": {\"command\": \"cargo test --lib\"}}
66</tool_call>
67
68## Guidelines
69
70- Read files before editing — understand first
71- Use file_edit for changes, file_write only for new files
72- Run tests after changes: shell with cargo test
73- Use pmat_query for code search (returns quality-graded functions), glob for files, grep for text
74- Be concise — DO NOT narrate what you're about to do; just emit the <tool_call>
75- DO NOT use Markdown ```rust``` code blocks for file edits; ALWAYS use file_edit or file_write tool_calls
76";
77
78pub mod exit_code {
80 pub const SUCCESS: i32 = 0;
81 pub const AGENT_ERROR: i32 = 1;
82 pub const BUDGET_EXHAUSTED: i32 = 2;
83 pub const MAX_TURNS: i32 = 3;
84 pub const SANDBOX_VIOLATION: i32 = 4;
85 pub const NO_MODEL: i32 = 5;
86}
87
88const MID_SYSTEM_PROMPT: &str = "\
91You are apr code, a sovereign AI coding assistant. All inference runs locally.
92
93To use a tool: <tool_call>{\"name\": \"tool\", \"input\": {...}}</tool_call>
94
95Tools: file_read, file_write, file_edit, glob, grep, shell, memory, pmat_query, rag
96
97- Read before editing. Use file_edit for changes, file_write for new files.
98- Run tests: shell with cargo test
99- Be concise
100";
101
102pub(super) fn estimate_model_params_from_name(path: &std::path::Path) -> f64 {
107 let name = path.file_stem().and_then(|s| s.to_str()).unwrap_or("").to_lowercase();
108
109 let mut best: f64 = 0.0;
112 let chars: Vec<char> = name.chars().collect();
113 let mut i = 0;
114 while i < chars.len() {
115 if chars[i].is_ascii_digit() {
117 let start = i;
118 while i < chars.len() && (chars[i].is_ascii_digit() || chars[i] == '.') {
120 i += 1;
121 }
122 if i < chars.len() && chars[i] == 'b' {
124 if let Ok(n) = name[start..i].parse::<f64>() {
125 if n > best {
126 best = n;
127 }
128 }
129 }
130 }
131 i += 1;
132 }
133 best
134}
135
136pub(super) fn scale_prompt_for_model(params_b: f64) -> String {
144 if params_b < 2.0 {
145 COMPACT_SYSTEM_PROMPT.to_string()
146 } else if params_b < 7.0 {
147 MID_SYSTEM_PROMPT.to_string()
148 } else {
149 CODE_SYSTEM_PROMPT.to_string()
150 }
151}
152
153pub(super) fn map_error_to_exit_code(e: &crate::agent::result::AgentError) -> i32 {
154 use crate::agent::result::AgentError;
155 match e {
156 AgentError::CircuitBreak(_) => exit_code::BUDGET_EXHAUSTED,
157 AgentError::MaxIterationsReached => exit_code::MAX_TURNS,
158 AgentError::CapabilityDenied { .. } => exit_code::SANDBOX_VIOLATION,
159 _ => exit_code::AGENT_ERROR,
160 }
161}