ai-agents-reasoning 1.0.0-rc.15

Reasoning and reflection capabilities for AI Agents framework
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ReasoningMode {
    #[default]
    None,
    #[serde(alias = "cot")]
    CoT,
    React,
    PlanAndExecute,
    Auto,
}

impl ReasoningMode {
    pub fn requires_llm_judge(&self) -> bool {
        matches!(self, ReasoningMode::Auto)
    }

    pub fn uses_planning(&self) -> bool {
        matches!(self, ReasoningMode::PlanAndExecute)
    }

    pub fn uses_iteration(&self) -> bool {
        matches!(self, ReasoningMode::React | ReasoningMode::PlanAndExecute)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ReflectionMode {
    #[default]
    #[serde(alias = "false")]
    Disabled,
    #[serde(alias = "true")]
    Enabled,
    Auto,
}

impl ReflectionMode {
    pub fn is_enabled(&self) -> bool {
        matches!(self, ReflectionMode::Enabled)
    }

    pub fn is_auto(&self) -> bool {
        matches!(self, ReflectionMode::Auto)
    }

    pub fn requires_evaluation(&self) -> bool {
        !matches!(self, ReflectionMode::Disabled)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ReasoningOutput {
    #[default]
    Hidden,
    Visible,
    Tagged,
}

impl ReasoningOutput {
    pub fn should_include_thinking(&self) -> bool {
        !matches!(self, ReasoningOutput::Hidden)
    }

    pub fn uses_tags(&self) -> bool {
        matches!(self, ReasoningOutput::Tagged)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_reasoning_mode_default() {
        let mode: ReasoningMode = Default::default();
        assert_eq!(mode, ReasoningMode::None);
    }

    #[test]
    fn test_reasoning_mode_serde() {
        let mode: ReasoningMode = serde_json::from_str(r#""cot""#).unwrap();
        assert_eq!(mode, ReasoningMode::CoT);

        let mode: ReasoningMode = serde_json::from_str(r#""plan_and_execute""#).unwrap();
        assert_eq!(mode, ReasoningMode::PlanAndExecute);

        let mode: ReasoningMode = serde_json::from_str(r#""auto""#).unwrap();
        assert_eq!(mode, ReasoningMode::Auto);
    }

    #[test]
    fn test_reasoning_mode_requires_llm_judge() {
        assert!(!ReasoningMode::None.requires_llm_judge());
        assert!(!ReasoningMode::CoT.requires_llm_judge());
        assert!(ReasoningMode::Auto.requires_llm_judge());
    }

    #[test]
    fn test_reasoning_mode_uses_planning() {
        assert!(!ReasoningMode::None.uses_planning());
        assert!(!ReasoningMode::CoT.uses_planning());
        assert!(ReasoningMode::PlanAndExecute.uses_planning());
    }

    #[test]
    fn test_reflection_mode_default() {
        let mode: ReflectionMode = Default::default();
        assert_eq!(mode, ReflectionMode::Disabled);
    }

    #[test]
    fn test_reflection_mode_serde_aliases() {
        let mode: ReflectionMode = serde_json::from_str(r#""true""#).unwrap();
        assert_eq!(mode, ReflectionMode::Enabled);

        let mode: ReflectionMode = serde_json::from_str(r#""false""#).unwrap();
        assert_eq!(mode, ReflectionMode::Disabled);

        let mode: ReflectionMode = serde_json::from_str(r#""enabled""#).unwrap();
        assert_eq!(mode, ReflectionMode::Enabled);
    }

    #[test]
    fn test_reflection_mode_methods() {
        assert!(!ReflectionMode::Disabled.is_enabled());
        assert!(ReflectionMode::Enabled.is_enabled());
        assert!(!ReflectionMode::Auto.is_enabled());

        assert!(ReflectionMode::Auto.is_auto());
        assert!(!ReflectionMode::Enabled.is_auto());

        assert!(!ReflectionMode::Disabled.requires_evaluation());
        assert!(ReflectionMode::Enabled.requires_evaluation());
        assert!(ReflectionMode::Auto.requires_evaluation());
    }

    #[test]
    fn test_reasoning_output_default() {
        let output: ReasoningOutput = Default::default();
        assert_eq!(output, ReasoningOutput::Hidden);
    }

    #[test]
    fn test_reasoning_output_methods() {
        assert!(!ReasoningOutput::Hidden.should_include_thinking());
        assert!(ReasoningOutput::Visible.should_include_thinking());
        assert!(ReasoningOutput::Tagged.should_include_thinking());

        assert!(!ReasoningOutput::Hidden.uses_tags());
        assert!(!ReasoningOutput::Visible.uses_tags());
        assert!(ReasoningOutput::Tagged.uses_tags());
    }
}