use crate::llm_codegen::{GeneratedCode, LlmError};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VerificationResult {
pub compiles: bool,
pub tests_pass: bool,
pub compile_errors: Vec<String>,
pub test_failures: Vec<String>,
pub clippy_warnings: usize,
pub success: bool,
}
impl VerificationResult {
pub fn success() -> Self {
Self {
compiles: true,
tests_pass: true,
compile_errors: Vec::new(),
test_failures: Vec::new(),
clippy_warnings: 0,
success: true,
}
}
pub fn compile_failure(errors: Vec<String>) -> Self {
Self {
compiles: false,
tests_pass: false,
compile_errors: errors,
test_failures: Vec::new(),
clippy_warnings: 0,
success: false,
}
}
pub fn test_failure(failures: Vec<String>) -> Self {
Self {
compiles: true,
tests_pass: false,
compile_errors: Vec::new(),
test_failures: failures,
clippy_warnings: 0,
success: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IterationContext {
pub iteration: usize,
pub max_iterations: usize,
pub previous_code: Option<String>,
pub previous_errors: Vec<String>,
pub feedback: Vec<String>,
}
impl IterationContext {
pub fn new(max_iterations: usize) -> Self {
Self {
iteration: 1,
max_iterations,
previous_code: None,
previous_errors: Vec::new(),
feedback: Vec::new(),
}
}
pub fn can_retry(&self) -> bool {
self.iteration <= self.max_iterations
}
pub fn record_failure(&mut self, code: &str, errors: Vec<String>) {
self.previous_code = Some(code.to_string());
self.previous_errors = errors.clone();
for error in &errors {
self.feedback.push(format!("Iteration {}: {}", self.iteration, error));
}
self.iteration += 1;
}
pub fn get_feedback(&self) -> String {
let mut feedback = String::new();
feedback.push_str("## Previous Errors\n\n");
for error in &self.previous_errors {
feedback.push_str("- ");
feedback.push_str(error);
feedback.push('\n');
}
if let Some(ref code) = self.previous_code {
feedback.push_str("\n## Previous Code\n```rust\n");
feedback.push_str(code);
feedback.push_str("\n```\n");
}
feedback.push_str("\n## Instructions\n");
feedback.push_str("Please fix the errors above and generate corrected Rust code.\n");
feedback
}
}
#[derive(Debug)]
pub struct CodeVerifier {
_temp_dir: Option<std::path::PathBuf>,
}
impl CodeVerifier {
pub fn new() -> Self {
Self { _temp_dir: None }
}
pub fn verify(&self, code: &GeneratedCode) -> Result<VerificationResult, LlmError> {
if code.code.trim().is_empty() {
return Ok(VerificationResult::compile_failure(vec!["Empty code".to_string()]));
}
let open = code.code.matches('{').count();
let close = code.code.matches('}').count();
if open != close {
return Ok(VerificationResult::compile_failure(vec![format!(
"Unbalanced braces: {} open, {} close",
open, close
)]));
}
Ok(VerificationResult::success())
}
pub fn compile(&self, code: &str) -> Result<(), Vec<String>> {
if code.trim().is_empty() {
return Err(vec!["Empty code".to_string()]);
}
let open_braces = code.matches('{').count();
let close_braces = code.matches('}').count();
if open_braces != close_braces {
return Err(vec![format!(
"Unbalanced braces: {} open, {} close",
open_braces, close_braces
)]);
}
Ok(())
}
pub fn lint(&self, code: &str) -> Result<usize, LlmError> {
let mut warnings = 0;
if code.contains("unwrap()") {
warnings += 1;
}
if code.contains("expect(") {
warnings += 1;
}
if code.contains("panic!") {
warnings += 1;
}
Ok(warnings)
}
pub fn run_tests(&self, code: &str) -> Result<(), Vec<String>> {
if code.contains("#[test]") {
Ok(())
} else {
Ok(())
}
}
fn _create_temp_project(&self, _code: &str) -> Result<std::path::PathBuf, LlmError> {
Err(LlmError::ApiError("Temporary project creation not implemented".to_string()))
}
}
impl Default for CodeVerifier {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct VerificationLoop {
max_iterations: usize,
}
impl VerificationLoop {
pub fn new(max_iterations: usize) -> Self {
Self { max_iterations }
}
pub fn max_iterations(&self) -> usize {
self.max_iterations
}
pub fn is_success(&self, result: &VerificationResult) -> bool {
result.success && result.compiles && result.tests_pass
}
pub fn format_feedback(&self, result: &VerificationResult) -> String {
let mut feedback = String::new();
if !result.compile_errors.is_empty() {
feedback.push_str("## Compilation Errors\n\n");
for error in &result.compile_errors {
feedback.push_str("- ");
feedback.push_str(error);
feedback.push('\n');
}
}
if !result.test_failures.is_empty() {
feedback.push_str("\n## Test Failures\n\n");
for failure in &result.test_failures {
feedback.push_str("- ");
feedback.push_str(failure);
feedback.push('\n');
}
}
if result.clippy_warnings > 0 {
feedback.push_str(&format!("\n## Clippy Warnings: {}\n", result.clippy_warnings));
}
feedback
}
}
impl Default for VerificationLoop {
fn default() -> Self {
Self::new(3)
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CompilationMetrics {
total_attempts: u64,
first_try_successes: u64,
total_iterations: u64,
iteration_counts: std::collections::HashMap<usize, u64>,
}
impl CompilationMetrics {
pub const TARGET_RATE: f64 = 0.85;
pub fn new() -> Self {
Self {
total_attempts: 0,
first_try_successes: 0,
total_iterations: 0,
iteration_counts: std::collections::HashMap::new(),
}
}
pub fn record_attempt(&mut self, success: bool, iterations: usize) {
self.total_attempts += 1;
self.total_iterations += iterations as u64;
if success && iterations == 1 {
self.first_try_successes += 1;
}
*self.iteration_counts.entry(iterations).or_insert(0) += 1;
}
pub fn total_attempts(&self) -> u64 {
self.total_attempts
}
pub fn first_try_successes(&self) -> u64 {
self.first_try_successes
}
pub fn first_try_rate(&self) -> f64 {
if self.total_attempts == 0 {
return 0.0;
}
self.first_try_successes as f64 / self.total_attempts as f64
}
pub fn meets_target(&self, target: f64) -> bool {
self.first_try_rate() >= target
}
pub fn average_iterations(&self) -> f64 {
if self.total_attempts == 0 {
return 0.0;
}
self.total_iterations as f64 / self.total_attempts as f64
}
pub fn iteration_histogram(&self) -> &std::collections::HashMap<usize, u64> {
&self.iteration_counts
}
pub fn reset(&mut self) {
self.total_attempts = 0;
self.first_try_successes = 0;
self.total_iterations = 0;
self.iteration_counts.clear();
}
}