autoagents_core/agent/
runnable.rs

1use super::base::{AgentDeriveT, BaseAgent};
2use super::error::RunnableAgentError;
3use crate::error::Error;
4use crate::memory::MemoryProvider;
5use crate::protocol::{Event, TaskResult};
6use crate::runtime::Task;
7use crate::tool::ToolCallResult;
8use async_trait::async_trait;
9use serde_json::Value;
10use std::fmt::Debug;
11use std::sync::Arc;
12use tokio::sync::{mpsc, RwLock};
13use tokio::task::JoinHandle;
14use uuid::Uuid;
15
16/// State tracking for agent execution
17#[derive(Debug, Default, Clone)]
18pub struct AgentState {
19    /// Tool calls made during execution
20    pub tool_calls: Vec<ToolCallResult>,
21    /// Tasks that have been executed
22    pub task_history: Vec<Task>,
23}
24
25impl AgentState {
26    pub fn new() -> Self {
27        Self::default()
28    }
29
30    pub fn record_tool_call(&mut self, tool_call: ToolCallResult) {
31        self.tool_calls.push(tool_call);
32    }
33
34    pub fn record_task(&mut self, task: Task) {
35        self.task_history.push(task);
36    }
37}
38
39/// Trait for agents that can be executed within the system
40#[async_trait]
41pub trait RunnableAgent: Send + Sync + 'static + Debug {
42    fn name(&self) -> &'static str;
43    fn description(&self) -> &'static str;
44    fn id(&self) -> Uuid;
45
46    async fn run(self: Arc<Self>, task: Task, tx_event: mpsc::Sender<Event>) -> Result<(), Error>;
47
48    fn memory(&self) -> Option<Arc<RwLock<Box<dyn MemoryProvider>>>>;
49
50    fn spawn_task(
51        self: Arc<Self>,
52        task: Task,
53        tx_event: mpsc::Sender<Event>,
54    ) -> JoinHandle<Result<(), Error>> {
55        tokio::spawn(async move { self.run(task, tx_event).await })
56    }
57}
58
59/// Wrapper that makes BaseAgent<T> implement RunnableAgent
60#[derive(Debug)]
61pub struct RunnableAgentImpl<T: AgentDeriveT> {
62    agent: BaseAgent<T>,
63    state: Arc<RwLock<AgentState>>,
64}
65
66impl<T: AgentDeriveT> RunnableAgentImpl<T> {
67    pub fn new(agent: BaseAgent<T>) -> Self {
68        Self {
69            agent,
70            state: Arc::new(RwLock::new(AgentState::new())),
71        }
72    }
73
74    #[allow(dead_code)]
75    pub fn state(&self) -> Arc<RwLock<AgentState>> {
76        self.state.clone()
77    }
78}
79
80#[async_trait]
81impl<T> RunnableAgent for RunnableAgentImpl<T>
82where
83    T: AgentDeriveT,
84{
85    fn name(&self) -> &'static str {
86        self.agent.name()
87    }
88
89    fn description(&self) -> &'static str {
90        self.agent.description()
91    }
92
93    fn id(&self) -> Uuid {
94        self.agent.id
95    }
96
97    fn memory(&self) -> Option<Arc<RwLock<Box<dyn MemoryProvider>>>> {
98        self.agent.memory()
99    }
100
101    async fn run(self: Arc<Self>, task: Task, tx_event: mpsc::Sender<Event>) -> Result<(), Error> {
102        // Execute the agent's logic using the executor
103        match self
104            .agent
105            .inner()
106            .execute(
107                self.agent.llm(),
108                self.agent.memory(),
109                self.agent.tools(),
110                &self.agent.agent_config(),
111                task.clone(),
112                self.state.clone(),
113                tx_event.clone(),
114            )
115            .await
116        {
117            Ok(output) => {
118                // Convert output to Value
119                let value: Value = output.into();
120
121                // Send completion event
122                let _ = tx_event
123                    .send(Event::TaskComplete {
124                        sub_id: task.submission_id,
125                        result: TaskResult::Value(value),
126                    })
127                    .await
128                    .map_err(RunnableAgentError::event_send_error)?;
129
130                Ok(())
131            }
132            Err(e) => {
133                // Send error event
134                let error_msg = e.to_string();
135                let _ = tx_event
136                    .send(Event::TaskComplete {
137                        sub_id: task.submission_id,
138                        result: TaskResult::Failure(error_msg.clone()),
139                    })
140                    .await;
141
142                Err(RunnableAgentError::ExecutorError(error_msg).into())
143            }
144        }
145    }
146}
147
148/// Extension trait for converting BaseAgent to RunnableAgent
149pub trait IntoRunnable<T: AgentDeriveT> {
150    fn into_runnable(self) -> Arc<dyn RunnableAgent>;
151}
152
153impl<T: AgentDeriveT> IntoRunnable<T> for BaseAgent<T> {
154    fn into_runnable(self) -> Arc<dyn RunnableAgent> {
155        Arc::new(RunnableAgentImpl::new(self))
156    }
157}