1use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10use uuid::Uuid;
11
12use behest_core::id::RunId;
13use behest_core::message::{FinishReason, TokenUsage};
14use behest_core::tool_types::ToolCall;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub enum AgentEvent {
19 RunStarted(RunStarted),
21 ContextBuilt(ContextBuilt),
23 ModelStarted(ModelStarted),
25 TextDelta(TextDelta),
27 ToolCallStarted(ToolCallStarted),
29 ToolCallDelta(ToolCallDelta),
31 ToolCallCompleted(ToolCallCompleted),
33 ToolExecutionStarted(ToolExecutionStarted),
35 ToolExecutionFinished(ToolExecutionFinished),
37 AssistantMessageCommitted(MessageCommitted),
39 ToolMessageCommitted(MessageCommitted),
41 UsageRecorded(UsageRecorded),
43 CacheMetrics(CacheMetrics),
45 RunCompleted(RunCompleted),
47 RunFailed(RunFailed),
49 RunCancelled(RunCancelled),
51 DoomLoopDetected(DoomLoopDetected),
53 CompactionCircuitOpened(CompactionCircuitOpened),
55}
56
57impl AgentEvent {
58 #[must_use]
60 pub fn run_id(&self) -> RunId {
61 match self {
62 AgentEvent::RunStarted(e) => e.run_id,
63 AgentEvent::ContextBuilt(e) => e.run_id,
64 AgentEvent::ModelStarted(e) => e.run_id,
65 AgentEvent::TextDelta(e) => e.run_id,
66 AgentEvent::ToolCallStarted(e) => e.run_id,
67 AgentEvent::ToolCallDelta(e) => e.run_id,
68 AgentEvent::ToolCallCompleted(e) => e.run_id,
69 AgentEvent::ToolExecutionStarted(e) => e.run_id,
70 AgentEvent::ToolExecutionFinished(e) => e.run_id,
71 AgentEvent::AssistantMessageCommitted(e) | AgentEvent::ToolMessageCommitted(e) => {
72 e.run_id
73 }
74 AgentEvent::UsageRecorded(e) => e.run_id,
75 AgentEvent::CacheMetrics(e) => e.run_id,
76 AgentEvent::RunCompleted(e) => e.run_id,
77 AgentEvent::RunFailed(e) => e.run_id,
78 AgentEvent::RunCancelled(e) => e.run_id,
79 AgentEvent::DoomLoopDetected(e) => e.run_id,
80 AgentEvent::CompactionCircuitOpened(e) => e.run_id,
81 }
82 }
83
84 #[must_use]
86 pub fn is_terminal(&self) -> bool {
87 matches!(
88 self,
89 AgentEvent::RunCompleted(_) | AgentEvent::RunFailed(_) | AgentEvent::RunCancelled(_)
90 )
91 }
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct RunStarted {
97 pub run_id: RunId,
99 pub session_id: Uuid,
101 pub provider: behest_core::id::ProviderId,
103 pub model: behest_core::id::ModelName,
105 pub timestamp: DateTime<Utc>,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct ContextBuilt {
112 pub run_id: RunId,
114 pub message_count: usize,
116 pub timestamp: DateTime<Utc>,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct ModelStarted {
123 pub run_id: RunId,
125 pub provider: behest_core::id::ProviderId,
127 pub model: behest_core::id::ModelName,
129 pub iteration: usize,
131 pub timestamp: DateTime<Utc>,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct TextDelta {
138 pub run_id: RunId,
140 pub delta: String,
142 pub timestamp: DateTime<Utc>,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct ToolCallStarted {
149 pub run_id: RunId,
151 pub call_id: String,
153 pub tool_name: String,
155 pub timestamp: DateTime<Utc>,
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct ToolCallDelta {
162 pub run_id: RunId,
164 pub call_id: String,
166 pub delta: String,
168 pub timestamp: DateTime<Utc>,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct ToolCallCompleted {
175 pub run_id: RunId,
177 pub call: ToolCall,
179 pub timestamp: DateTime<Utc>,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct ToolExecutionStarted {
186 pub run_id: RunId,
188 pub call_id: String,
190 pub tool_name: String,
192 pub timestamp: DateTime<Utc>,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct ToolExecutionFinished {
199 pub run_id: RunId,
201 pub call_id: String,
203 pub tool_name: String,
205 pub result: ToolExecutionResult,
207 pub duration_ms: u64,
209 pub timestamp: DateTime<Utc>,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub enum ToolExecutionResult {
216 Success {
218 output: serde_json::Value,
220 },
221 Failure {
223 error: String,
225 },
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct MessageCommitted {
231 pub run_id: RunId,
233 pub message_id: Uuid,
235 pub timestamp: DateTime<Utc>,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct UsageRecorded {
242 pub run_id: RunId,
244 pub usage: TokenUsage,
246 pub timestamp: DateTime<Utc>,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct CacheMetrics {
255 pub run_id: RunId,
257 pub cache_creation_input_tokens: u64,
260 pub cache_read_input_tokens: u64,
263 pub cached_input_tokens: u64,
266 pub timestamp: DateTime<Utc>,
268}
269
270impl CacheMetrics {
271 #[must_use]
273 pub const fn total_cache_tokens(&self) -> u64 {
274 self.cache_creation_input_tokens + self.cache_read_input_tokens + self.cached_input_tokens
275 }
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize)]
280pub struct RunCompleted {
281 pub run_id: RunId,
283 pub finish_reason: FinishReason,
285 pub iterations: usize,
287 pub timestamp: DateTime<Utc>,
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct RunFailed {
294 pub run_id: RunId,
296 pub error: String,
298 pub timestamp: DateTime<Utc>,
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct RunCancelled {
305 pub run_id: RunId,
307 pub timestamp: DateTime<Utc>,
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize)]
313pub struct DoomLoopDetected {
314 pub run_id: RunId,
316 pub description: String,
318 pub timestamp: DateTime<Utc>,
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct CompactionCircuitOpened {
325 pub run_id: RunId,
327 pub consecutive_failures: u32,
329 pub timestamp: DateTime<Utc>,
331}