use mofa_kernel::agent::{
AgentCapabilities, AgentContext, AgentError, AgentOutput, AgentResult, AgentState, AgentStats,
InterruptResult, MoFAAgent,
};
use async_trait::async_trait;
pub struct BaseAgent {
pub id: String,
pub name: String,
pub description: Option<String>,
pub version: Option<String>,
pub capabilities: AgentCapabilities,
pub state: AgentState,
stats: AgentStats,
}
impl BaseAgent {
pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
Self {
id: id.into(),
name: name.into(),
description: None,
version: None,
capabilities: AgentCapabilities::default(),
state: AgentState::Created,
stats: AgentStats::default(),
}
}
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn with_version(mut self, version: impl Into<String>) -> Self {
self.version = Some(version.into());
self
}
pub fn with_capabilities(mut self, capabilities: AgentCapabilities) -> Self {
self.capabilities = capabilities;
self
}
pub fn transition_to(&mut self, new_state: AgentState) -> AgentResult<()> {
if self.state.can_transition_to(&new_state) {
self.state = new_state;
Ok(())
} else {
Err(AgentError::invalid_state_transition(
&self.state,
&new_state,
))
}
}
pub fn record_success(&mut self, duration_ms: u64, tokens: u64, tool_calls: u64) {
self.stats.total_executions += 1;
self.stats.successful_executions += 1;
self.stats.total_tokens_used += tokens;
self.stats.total_tool_calls += tool_calls;
let n = self.stats.total_executions as f64;
self.stats.avg_execution_time_ms =
(self.stats.avg_execution_time_ms * (n - 1.0) + duration_ms as f64) / n;
}
pub fn record_failure(&mut self) {
self.stats.total_executions += 1;
self.stats.failed_executions += 1;
}
pub fn stats(&self) -> &AgentStats {
&self.stats
}
pub fn id(&self) -> &str {
&self.id
}
pub fn name(&self) -> &str {
&self.name
}
pub fn capabilities(&self) -> &AgentCapabilities {
&self.capabilities
}
pub fn state(&self) -> AgentState {
self.state.clone()
}
pub async fn initialize(&mut self, _ctx: &AgentContext) -> AgentResult<()> {
self.transition_to(AgentState::Initializing)?;
self.transition_to(AgentState::Ready)?;
Ok(())
}
pub async fn interrupt(&mut self) -> AgentResult<InterruptResult> {
Ok(InterruptResult::Acknowledged)
}
pub async fn shutdown(&mut self) -> AgentResult<()> {
self.transition_to(AgentState::ShuttingDown)?;
self.transition_to(AgentState::Shutdown)?;
Ok(())
}
}
#[async_trait]
impl MoFAAgent for BaseAgent {
fn id(&self) -> &str {
&self.id
}
fn name(&self) -> &str {
&self.name
}
fn capabilities(&self) -> &AgentCapabilities {
&self.capabilities
}
async fn initialize(
&mut self,
_ctx: &mofa_kernel::agent::context::AgentContext,
) -> AgentResult<()> {
self.transition_to(AgentState::Initializing)?;
self.transition_to(AgentState::Ready)?;
Ok(())
}
async fn execute(
&mut self,
_input: mofa_kernel::agent::AgentInput,
_ctx: &mofa_kernel::agent::context::AgentContext,
) -> AgentResult<AgentOutput> {
Ok(AgentOutput::text("BaseAgent execute"))
}
async fn shutdown(&mut self) -> AgentResult<()> {
self.transition_to(AgentState::ShuttingDown)?;
self.transition_to(AgentState::Shutdown)?;
Ok(())
}
fn state(&self) -> AgentState {
self.state.clone()
}
}