1use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use serde_json::Value;
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub enum WorkflowEventType {
20 Started,
26 Phase,
28 Log,
30 AgentStarted,
32 AgentEvent,
34 AgentCompleted,
36 AgentFailed,
38 Result,
40 Error,
42 Other(String),
47}
48
49impl WorkflowEventType {
50 pub fn as_str(&self) -> &str {
52 match self {
53 Self::Started => "workflow.started",
54 Self::Phase => "workflow.phase",
55 Self::Log => "workflow.log",
56 Self::AgentStarted => "workflow.agent_started",
57 Self::AgentEvent => "workflow.agent_event",
58 Self::AgentCompleted => "workflow.agent_completed",
59 Self::AgentFailed => "workflow.agent_failed",
60 Self::Result => "workflow.result",
61 Self::Error => "workflow.error",
62 Self::Other(event_type) => event_type.as_str(),
63 }
64 }
65}
66
67impl From<&str> for WorkflowEventType {
68 fn from(value: &str) -> Self {
69 match value {
70 "workflow.started" => Self::Started,
71 "workflow.phase" => Self::Phase,
72 "workflow.log" => Self::Log,
73 "workflow.agent_started" => Self::AgentStarted,
74 "workflow.agent_event" => Self::AgentEvent,
75 "workflow.agent_completed" => Self::AgentCompleted,
76 "workflow.agent_failed" => Self::AgentFailed,
77 "workflow.result" => Self::Result,
78 "workflow.error" => Self::Error,
79 value => Self::Other(value.to_string()),
80 }
81 }
82}
83
84impl From<String> for WorkflowEventType {
85 fn from(value: String) -> Self {
86 WorkflowEventType::from(value.as_str())
87 }
88}
89
90impl std::fmt::Display for WorkflowEventType {
91 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 formatter.write_str(self.as_str())
93 }
94}
95
96impl Serialize for WorkflowEventType {
97 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
98 where
99 S: Serializer,
100 {
101 serializer.serialize_str(self.as_str())
102 }
103}
104
105impl<'de> Deserialize<'de> for WorkflowEventType {
106 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
107 where
108 D: Deserializer<'de>,
109 {
110 let event_type = String::deserialize(deserializer)?;
111 Ok(Self::from(event_type))
112 }
113}
114
115#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
117#[serde(rename_all = "camelCase")]
118pub struct WorkflowEventMetadata {
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub run_id: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
128 pub step_id: Option<String>,
129 #[serde(skip_serializing_if = "Option::is_none")]
131 pub provider: Option<String>,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub session_id: Option<String>,
135 #[serde(skip_serializing_if = "Option::is_none")]
139 pub workflow_depth: Option<u32>,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub parent_step_id: Option<String>,
143}
144
145#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
151#[serde(rename_all = "camelCase")]
152pub struct WorkflowEvent {
153 #[serde(rename = "type")]
155 pub event_type: WorkflowEventType,
156 #[serde(skip_serializing_if = "Option::is_none")]
161 pub elapsed_nanos: Option<u64>,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub metadata: Option<WorkflowEventMetadata>,
165 pub data: Value,
170}
171
172impl WorkflowEvent {
173 pub fn started(start_time: String) -> Self {
175 Self {
176 event_type: WorkflowEventType::Started,
177 elapsed_nanos: None,
178 metadata: None,
179 data: serde_json::json!({ "startTime": start_time }),
180 }
181 }
182
183 pub fn log(message: String) -> Self {
185 Self {
186 event_type: WorkflowEventType::Log,
187 elapsed_nanos: None,
188 metadata: None,
189 data: serde_json::json!({ "message": message }),
190 }
191 }
192
193 pub fn phase(name: String, options: Option<Value>) -> Self {
195 let mut data = serde_json::Map::new();
196 data.insert("name".to_string(), Value::String(name));
197 if let Some(options) = options {
198 data.insert("options".to_string(), options);
199 }
200 Self {
201 event_type: WorkflowEventType::Phase,
202 elapsed_nanos: None,
203 metadata: None,
204 data: Value::Object(data),
205 }
206 }
207
208 pub fn result(
210 input_tokens: u64,
211 output_tokens: u64,
212 total_tokens: u64,
213 results: Value,
214 ) -> Self {
215 Self {
216 event_type: WorkflowEventType::Result,
217 elapsed_nanos: None,
218 metadata: None,
219 data: serde_json::json!({
220 "tokenUsage": {
221 "inputTokens": input_tokens,
222 "outputTokens": output_tokens,
223 "totalTokens": total_tokens,
224 },
225 "results": results,
226 }),
227 }
228 }
229
230 pub fn error(message: String, details: Option<String>) -> Self {
232 let mut data = serde_json::Map::new();
233 data.insert("message".to_string(), Value::String(message));
234 if let Some(details) = details {
235 data.insert("details".to_string(), Value::String(details));
236 }
237 Self {
238 event_type: WorkflowEventType::Error,
239 elapsed_nanos: None,
240 metadata: None,
241 data: Value::Object(data),
242 }
243 }
244
245 pub fn agent_started(data: Value, metadata: WorkflowEventMetadata) -> Self {
247 Self {
248 event_type: WorkflowEventType::AgentStarted,
249 elapsed_nanos: None,
250 metadata: Some(metadata),
251 data,
252 }
253 }
254
255 pub fn agent_event(data: Value, metadata: WorkflowEventMetadata) -> Self {
257 Self {
258 event_type: WorkflowEventType::AgentEvent,
259 elapsed_nanos: None,
260 metadata: Some(metadata),
261 data,
262 }
263 }
264
265 pub fn agent_completed(data: Value, metadata: WorkflowEventMetadata) -> Self {
267 Self {
268 event_type: WorkflowEventType::AgentCompleted,
269 elapsed_nanos: None,
270 metadata: Some(metadata),
271 data,
272 }
273 }
274
275 pub fn agent_failed(data: Value, metadata: WorkflowEventMetadata) -> Self {
277 Self {
278 event_type: WorkflowEventType::AgentFailed,
279 elapsed_nanos: None,
280 metadata: Some(metadata),
281 data,
282 }
283 }
284}
285
286#[async_trait::async_trait]
293pub trait WorkflowEventSink: Send + Sync {
294 async fn emit(&self, event: WorkflowEvent) -> anyhow::Result<()>;
296}