aether_core/events/
turn_event.rs1use llm::{ContentBlock, LlmCallPurpose, LlmError, ModelIdentity, StopReason, TokenUsage};
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
7#[serde(tag = "status", rename_all = "snake_case")]
8pub enum TurnOutcome {
9 Completed,
10 Cancelled,
11 Failed { error: String },
12}
13
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
16#[serde(tag = "status", rename_all = "snake_case")]
17pub enum LlmCallOutcome {
18 Completed {
19 stop_reason: Option<StopReason>,
20 usage: Option<TokenUsage>,
21 },
22 Failed {
23 error: String,
24 will_retry: bool,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 http_status: Option<u16>,
27 #[serde(default, skip_serializing_if = "Option::is_none")]
28 provider_request_id: Option<String>,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 provider_error_code: Option<String>,
31 },
32 Cancelled,
33}
34
35impl LlmCallOutcome {
36 pub fn failed(error: impl Into<String>, will_retry: bool) -> Self {
37 Self::Failed {
38 error: error.into(),
39 will_retry,
40 http_status: None,
41 provider_request_id: None,
42 provider_error_code: None,
43 }
44 }
45
46 pub fn from_llm_error(error: &LlmError, will_retry: bool) -> Self {
47 let Some(provider) = error.provider() else {
48 return Self::failed(error.to_string(), will_retry);
49 };
50 Self::Failed {
51 error: provider.to_string(),
52 will_retry,
53 http_status: provider.http_status,
54 provider_request_id: provider.request_id.clone(),
55 provider_error_code: provider.code.clone(),
56 }
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct RetryInfo {
63 pub attempt: u32,
64 pub max_attempts: u32,
65 pub delay_ms: u64,
66}
67
68#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
77#[serde(tag = "type", rename_all = "snake_case")]
78pub enum TurnEvent {
79 Started {
82 #[serde(default, skip_serializing_if = "Vec::is_empty")]
83 content: Vec<ContentBlock>,
84 },
85 RetryScheduled { purpose: LlmCallPurpose, attempt: u32, max_attempts: u32, delay_ms: u64 },
87 LlmCallStarted {
89 purpose: LlmCallPurpose,
90 model: ModelIdentity,
91 display_name: String,
92 attempt: u32,
94 max_attempts: u32,
95 },
96 LlmCallEnded { purpose: LlmCallPurpose, outcome: LlmCallOutcome },
98 AutoContinue { attempt: u32, max_attempts: u32 },
101 Ended { outcome: TurnOutcome },
103}
104
105impl TurnEvent {
106 pub fn retry_info(&self) -> Option<RetryInfo> {
107 match self {
108 Self::RetryScheduled { attempt, max_attempts, delay_ms, .. } => {
109 Some(RetryInfo { attempt: *attempt, max_attempts: *max_attempts, delay_ms: *delay_ms })
110 }
111 _ => None,
112 }
113 }
114}