car-reason 0.6.0

Code reasoning engine for Common Agent Runtime — adaptive, graph-driven, learning
Documentation
//! Core types for the reasoning engine.

use serde::{Deserialize, Serialize};

/// Classification of what kind of code problem this is.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ProblemClass {
    BugFix,
    Refactor,
    Architecture,
    NewFeature,
    Performance,
    TestWriting,
    Explanation,
    Unknown,
}

impl ProblemClass {
    /// Keywords that identify this problem class (for skill triggers).
    pub fn keywords(&self) -> Vec<String> {
        match self {
            ProblemClass::BugFix => vec!["bug", "fix", "broken", "error", "crash", "wrong", "failing"],
            ProblemClass::Refactor => vec!["refactor", "clean", "simplify", "restructure", "rename"],
            ProblemClass::Architecture => vec!["architecture", "design", "pattern", "structure", "approach"],
            ProblemClass::NewFeature => vec!["add", "implement", "create", "feature", "new", "build"],
            ProblemClass::Performance => vec!["slow", "fast", "optimize", "performance", "memory", "latency"],
            ProblemClass::TestWriting => vec!["test", "coverage", "assert", "mock", "spec"],
            ProblemClass::Explanation => vec!["explain", "why", "how", "what", "understand"],
            ProblemClass::Unknown => vec![],
        }.into_iter().map(String::from).collect()
    }

    /// Parse from a classification model's output.
    pub fn from_label(s: &str) -> Self {
        let lower = s.to_lowercase();
        if lower.contains("bug") || lower.contains("fix") { ProblemClass::BugFix }
        else if lower.contains("refactor") { ProblemClass::Refactor }
        else if lower.contains("architect") { ProblemClass::Architecture }
        else if lower.contains("feature") || lower.contains("implement") { ProblemClass::NewFeature }
        else if lower.contains("perf") || lower.contains("optim") { ProblemClass::Performance }
        else if lower.contains("test") { ProblemClass::TestWriting }
        else if lower.contains("explain") { ProblemClass::Explanation }
        else { ProblemClass::Unknown }
    }
}

impl std::fmt::Display for ProblemClass {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ProblemClass::BugFix => write!(f, "bug_fix"),
            ProblemClass::Refactor => write!(f, "refactor"),
            ProblemClass::Architecture => write!(f, "architecture"),
            ProblemClass::NewFeature => write!(f, "new_feature"),
            ProblemClass::Performance => write!(f, "performance"),
            ProblemClass::TestWriting => write!(f, "test_writing"),
            ProblemClass::Explanation => write!(f, "explanation"),
            ProblemClass::Unknown => write!(f, "unknown"),
        }
    }
}

/// A discrete reasoning step.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ActionKind {
    /// Determine problem class.
    Classify,
    /// Find relevant code/files in the codebase.
    Locate,
    /// Pull similar past fixes from graph memory.
    RetrievePatterns,
    /// Root cause analysis.
    Diagnose,
    /// Produce a code suggestion.
    GenerateFix,
    /// Static/formal verification of the suggestion.
    VerifyFix,
    /// Human-readable explanation.
    Explain,
}

impl ActionKind {
    /// Skill name in the memgine graph.
    pub fn skill_name(&self) -> String {
        format!("reason:{self}")
    }

    /// Temperature for this action (lower = more deterministic).
    pub fn temperature(&self) -> f64 {
        match self {
            ActionKind::Classify => 0.0,
            ActionKind::Locate => 0.1,
            ActionKind::RetrievePatterns => 0.0,
            ActionKind::Diagnose => 0.4,
            ActionKind::GenerateFix => 0.3,
            ActionKind::VerifyFix => 0.0,
            ActionKind::Explain => 0.5,
        }
    }

    /// Max tokens for this action.
    pub fn max_tokens(&self) -> usize {
        match self {
            ActionKind::Classify => 50,
            ActionKind::Locate => 512,
            ActionKind::RetrievePatterns => 256,
            ActionKind::Diagnose => 1024,
            ActionKind::GenerateFix => 2048,
            ActionKind::VerifyFix => 256,
            ActionKind::Explain => 1024,
        }
    }
}

impl std::fmt::Display for ActionKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ActionKind::Classify => write!(f, "classify"),
            ActionKind::Locate => write!(f, "locate"),
            ActionKind::RetrievePatterns => write!(f, "retrieve_patterns"),
            ActionKind::Diagnose => write!(f, "diagnose"),
            ActionKind::GenerateFix => write!(f, "generate_fix"),
            ActionKind::VerifyFix => write!(f, "verify_fix"),
            ActionKind::Explain => write!(f, "explain"),
        }
    }
}

/// Configuration for a reasoning action, stored as the skill's `code` field in the graph.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionConfig {
    pub kind: ActionKind,
    /// Which problem classes this action applies to.
    pub applicable_to: Vec<ProblemClass>,
    /// Prerequisite actions that must complete before this one.
    pub prerequisites: Vec<ActionKind>,
    /// Prompt template with placeholders: {problem}, {context}, {patterns}, {diagnosis}, {code}
    pub prompt_template: String,
    /// Execution priority (lower = earlier). Graph can override via activation scores.
    pub priority: u32,
}

/// The result of executing a single reasoning action.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionOutcome {
    pub action: ActionKind,
    pub model_used: String,
    pub trace_id: String,
    pub latency_ms: u64,
    pub output: String,
    pub confidence: f64,
    pub success: bool,
}

/// A code suggestion with confidence and verification status.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodeSuggestion {
    pub file_path: Option<String>,
    pub original: Option<String>,
    pub suggested: String,
    pub confidence: f64,
    pub verification: VerificationStatus,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum VerificationStatus {
    NotVerified,
    Passed,
    Failed,
    PartiallyVerified,
}

/// The complete output of a reasoning session.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReasoningResult {
    pub session_id: String,
    pub problem_class: ProblemClass,
    pub diagnosis: String,
    pub suggestions: Vec<CodeSuggestion>,
    pub explanation: String,
    pub actions_taken: Vec<ActionOutcome>,
    pub overall_confidence: f64,
    pub total_latency_ms: u64,
}