trae_agent_rs_core/output/
mod.rs1use crate::tools::{ToolCall, ToolResult};
7use async_trait::async_trait;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10
11pub struct NullOutput;
15
16#[async_trait]
17impl AgentOutput for NullOutput {
18 async fn emit_event(
19 &self,
20 _event: AgentEvent,
21 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
22 Ok(())
23 }
24}
25
26pub mod events {
28 pub use super::NullOutput;
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
33pub enum ToolExecutionStatus {
34 Executing,
36 Success,
38 Error,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct ToolExecutionInfo {
45 pub execution_id: String,
47 pub tool_name: String,
49 pub parameters: HashMap<String, serde_json::Value>,
51 pub status: ToolExecutionStatus,
53 pub result: Option<ToolResult>,
55 pub timestamp: chrono::DateTime<chrono::Utc>,
57 pub metadata: HashMap<String, serde_json::Value>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct AgentStepInfo {
64 pub step_number: usize,
66 pub task: String,
68 pub thinking: Option<String>,
70 pub tool_executions: Vec<ToolExecutionInfo>,
72 pub completed: bool,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize, Default)]
78pub struct TokenUsage {
79 pub input_tokens: u32,
81 pub output_tokens: u32,
83 pub total_tokens: u32,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct AgentExecutionContext {
90 pub agent_id: String,
92 pub task: String,
94 pub project_path: String,
96 pub max_steps: usize,
98 pub current_step: usize,
100 pub execution_time: std::time::Duration,
102 pub token_usage: TokenUsage,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
108pub enum AgentEvent {
109 ExecutionStarted { context: AgentExecutionContext },
111 ExecutionCompleted {
113 context: AgentExecutionContext,
114 success: bool,
115 summary: String,
116 },
117 StepStarted { step_info: AgentStepInfo },
119 StepCompleted { step_info: AgentStepInfo },
121 ToolExecutionStarted { tool_info: ToolExecutionInfo },
123 ToolExecutionUpdated { tool_info: ToolExecutionInfo },
125 ToolExecutionCompleted { tool_info: ToolExecutionInfo },
127 AgentThinking {
129 step_number: usize,
130 thinking: String,
131 },
132 TokenUsageUpdated { token_usage: TokenUsage },
134 StatusUpdate {
136 status: String,
137 metadata: HashMap<String, serde_json::Value>,
138 },
139 Message {
141 level: MessageLevel,
142 content: String,
143 metadata: HashMap<String, serde_json::Value>,
144 },
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
149pub enum MessageLevel {
150 Debug,
151 Info,
152 Normal,
153 Warning,
154 Error,
155}
156
157#[async_trait]
159pub trait AgentOutput: Send + Sync {
160 async fn emit_event(
162 &self,
163 event: AgentEvent,
164 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
165
166 async fn emit_message(
168 &self,
169 level: MessageLevel,
170 content: &str,
171 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
172 self.emit_event(AgentEvent::Message {
173 level,
174 content: content.to_string(),
175 metadata: HashMap::new(),
176 })
177 .await
178 }
179
180 async fn debug(&self, content: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
182 self.emit_message(MessageLevel::Debug, content).await
183 }
184
185 async fn emit_token_update(
187 &self,
188 token_usage: TokenUsage,
189 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
190 self.emit_event(AgentEvent::TokenUsageUpdated { token_usage })
191 .await
192 }
193
194 async fn info(&self, content: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
196 self.emit_message(MessageLevel::Info, content).await
197 }
198
199 async fn warning(&self, content: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
201 self.emit_message(MessageLevel::Warning, content).await
202 }
203
204 async fn error(&self, content: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
206 self.emit_message(MessageLevel::Error, content).await
207 }
208
209 async fn normal(&self, content: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
211 self.emit_message(MessageLevel::Normal, content).await
212 }
213
214 async fn emit_status_update(
216 &self,
217 status: &str,
218 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
219 self.emit_event(AgentEvent::StatusUpdate {
220 status: status.to_string(),
221 metadata: HashMap::new(),
222 })
223 .await
224 }
225
226 fn supports_realtime_updates(&self) -> bool {
228 false
229 }
230
231 async fn flush(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
233 Ok(())
234 }
235}
236
237pub trait ToolExecutionInfoBuilder {
239 fn create_tool_execution_info(
240 tool_call: &ToolCall,
241 status: ToolExecutionStatus,
242 result: Option<&ToolResult>,
243 ) -> ToolExecutionInfo;
244}
245
246impl ToolExecutionInfoBuilder for ToolExecutionInfo {
247 fn create_tool_execution_info(
248 tool_call: &ToolCall,
249 status: ToolExecutionStatus,
250 result: Option<&ToolResult>,
251 ) -> ToolExecutionInfo {
252 let parameters = if let serde_json::Value::Object(map) = &tool_call.parameters {
253 map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
254 } else {
255 let mut map = HashMap::new();
256 map.insert("raw_parameters".to_string(), tool_call.parameters.clone());
257 map
258 };
259
260 ToolExecutionInfo {
261 execution_id: tool_call.id.clone(),
262 tool_name: tool_call.name.clone(),
263 parameters,
264 status,
265 result: result.cloned(),
266 timestamp: chrono::Utc::now(),
267 metadata: HashMap::new(),
268 }
269 }
270}