coro_core/trajectory/
entry.rs

1//! Trajectory entry structures
2
3use crate::llm::LlmMessage;
4use crate::tools::{ToolCall, ToolResult};
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use uuid::Uuid;
9
10/// A single entry in the execution trajectory
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct TrajectoryEntry {
13    /// Unique identifier for this entry
14    pub id: String,
15
16    /// Timestamp when this entry was created
17    pub timestamp: DateTime<Utc>,
18
19    /// Type of entry
20    pub entry_type: EntryType,
21
22    /// Step number in the execution
23    pub step: usize,
24
25    /// Optional metadata
26    pub metadata: Option<HashMap<String, serde_json::Value>>,
27}
28
29/// Type of trajectory entry
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(tag = "type", rename_all = "snake_case")]
32pub enum EntryType {
33    /// Task started
34    TaskStart {
35        task: String,
36        agent_config: serde_json::Value,
37    },
38
39    /// LLM request sent
40    LlmRequest {
41        messages: Vec<LlmMessage>,
42        model: String,
43        provider: String,
44    },
45
46    /// LLM response received
47    LlmResponse {
48        message: LlmMessage,
49        usage: Option<crate::llm::Usage>,
50        finish_reason: Option<String>,
51    },
52
53    /// Tool call initiated
54    ToolCall { call: ToolCall },
55
56    /// Tool result received
57    ToolResult { result: ToolResult },
58
59    /// Agent step completed
60    StepComplete { step_summary: String, success: bool },
61
62    /// Task completed
63    TaskComplete {
64        success: bool,
65        final_result: String,
66        total_steps: usize,
67        duration_ms: u64,
68    },
69
70    /// Error occurred
71    Error {
72        error: String,
73        context: Option<String>,
74    },
75
76    /// Custom log entry
77    Log {
78        level: LogLevel,
79        message: String,
80        context: Option<HashMap<String, serde_json::Value>>,
81    },
82}
83
84/// Log level for trajectory entries
85#[derive(Debug, Clone, Serialize, Deserialize)]
86#[serde(rename_all = "lowercase")]
87pub enum LogLevel {
88    Debug,
89    Info,
90    Warn,
91    Error,
92}
93
94impl TrajectoryEntry {
95    /// Create a new trajectory entry
96    pub fn new(entry_type: EntryType, step: usize) -> Self {
97        Self {
98            id: Uuid::new_v4().to_string(),
99            timestamp: Utc::now(),
100            entry_type,
101            step,
102            metadata: None,
103        }
104    }
105
106    /// Add metadata to the entry
107    pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
108        self.metadata = Some(metadata);
109        self
110    }
111
112    /// Create a task start entry
113    pub fn task_start(task: String, agent_config: serde_json::Value) -> Self {
114        Self::new(EntryType::TaskStart { task, agent_config }, 0)
115    }
116
117    /// Create an LLM request entry
118    pub fn llm_request(
119        messages: Vec<LlmMessage>,
120        model: String,
121        provider: String,
122        step: usize,
123    ) -> Self {
124        Self::new(
125            EntryType::LlmRequest {
126                messages,
127                model,
128                provider,
129            },
130            step,
131        )
132    }
133
134    /// Create an LLM response entry
135    pub fn llm_response(
136        message: LlmMessage,
137        usage: Option<crate::llm::Usage>,
138        finish_reason: Option<String>,
139        step: usize,
140    ) -> Self {
141        Self::new(
142            EntryType::LlmResponse {
143                message,
144                usage,
145                finish_reason,
146            },
147            step,
148        )
149    }
150
151    /// Create a tool call entry
152    pub fn tool_call(call: ToolCall, step: usize) -> Self {
153        Self::new(EntryType::ToolCall { call }, step)
154    }
155
156    /// Create a tool result entry
157    pub fn tool_result(result: ToolResult, step: usize) -> Self {
158        Self::new(EntryType::ToolResult { result }, step)
159    }
160
161    /// Create a step complete entry
162    pub fn step_complete(step_summary: String, success: bool, step: usize) -> Self {
163        Self::new(
164            EntryType::StepComplete {
165                step_summary,
166                success,
167            },
168            step,
169        )
170    }
171
172    /// Create a task complete entry
173    pub fn task_complete(
174        success: bool,
175        final_result: String,
176        total_steps: usize,
177        duration_ms: u64,
178    ) -> Self {
179        Self::new(
180            EntryType::TaskComplete {
181                success,
182                final_result,
183                total_steps,
184                duration_ms,
185            },
186            total_steps,
187        )
188    }
189
190    /// Create an error entry
191    pub fn error(error: String, context: Option<String>, step: usize) -> Self {
192        Self::new(EntryType::Error { error, context }, step)
193    }
194
195    /// Create a log entry
196    pub fn log(level: LogLevel, message: String, step: usize) -> Self {
197        Self::new(
198            EntryType::Log {
199                level,
200                message,
201                context: None,
202            },
203            step,
204        )
205    }
206
207    /// Create a log entry with context
208    pub fn log_with_context(
209        level: LogLevel,
210        message: String,
211        context: HashMap<String, serde_json::Value>,
212        step: usize,
213    ) -> Self {
214        Self::new(
215            EntryType::Log {
216                level,
217                message,
218                context: Some(context),
219            },
220            step,
221        )
222    }
223}