use crate::agent::capabilities::ReasoningStrategy;
use crate::agent::context::AgentContext;
use crate::agent::error::AgentResult;
use crate::agent::types::AgentInput;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
#[async_trait]
pub trait Reasoner: Send + Sync {
async fn reason(&self, input: &AgentInput, ctx: &AgentContext) -> AgentResult<ReasoningResult>;
fn strategy(&self) -> ReasoningStrategy;
fn supports_multi_step(&self) -> bool {
matches!(
self.strategy(),
ReasoningStrategy::ReAct { .. }
| ReasoningStrategy::ChainOfThought
| ReasoningStrategy::TreeOfThought { .. }
)
}
fn name(&self) -> &str {
"reasoner"
}
fn description(&self) -> Option<&str> {
None
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReasoningResult {
pub thoughts: Vec<ThoughtStep>,
pub decision: Decision,
pub confidence: f32,
}
impl ReasoningResult {
pub fn respond(content: impl Into<String>) -> Self {
Self {
thoughts: vec![],
decision: Decision::Respond {
content: content.into(),
},
confidence: 1.0,
}
}
pub fn call_tool(tool_name: impl Into<String>, arguments: serde_json::Value) -> Self {
Self {
thoughts: vec![],
decision: Decision::CallTool {
tool_name: tool_name.into(),
arguments,
},
confidence: 1.0,
}
}
pub fn with_thought(mut self, step: ThoughtStep) -> Self {
self.thoughts.push(step);
self
}
pub fn with_confidence(mut self, confidence: f32) -> Self {
self.confidence = confidence.clamp(0.0, 1.0);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThoughtStep {
pub step_type: ThoughtStepType,
pub content: String,
pub step_number: usize,
pub timestamp_ms: u64,
}
impl ThoughtStep {
pub fn new(step_type: ThoughtStepType, content: impl Into<String>, step_number: usize) -> Self {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64;
Self {
step_type,
content: content.into(),
step_number,
timestamp_ms: now,
}
}
pub fn thought(content: impl Into<String>, step_number: usize) -> Self {
Self::new(ThoughtStepType::Thought, content, step_number)
}
pub fn analysis(content: impl Into<String>, step_number: usize) -> Self {
Self::new(ThoughtStepType::Analysis, content, step_number)
}
pub fn planning(content: impl Into<String>, step_number: usize) -> Self {
Self::new(ThoughtStepType::Planning, content, step_number)
}
pub fn reflection(content: impl Into<String>, step_number: usize) -> Self {
Self::new(ThoughtStepType::Reflection, content, step_number)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ThoughtStepType {
Thought,
Analysis,
Planning,
Reflection,
Evaluation,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Decision {
Respond {
content: String,
},
CallTool {
tool_name: String,
arguments: serde_json::Value,
},
CallMultipleTools {
tool_calls: Vec<ToolCall>,
},
Delegate {
agent_id: String,
task: String,
},
NeedMoreInfo {
questions: Vec<String>,
},
CannotHandle {
reason: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCall {
pub tool_name: String,
pub arguments: serde_json::Value,
}
impl ToolCall {
pub fn new(tool_name: impl Into<String>, arguments: serde_json::Value) -> Self {
Self {
tool_name: tool_name.into(),
arguments,
}
}
}