1use crate::types::ids::{MessageId, RunId, ThreadId, ToolCallId};
2use crate::types::message::{Message, Role};
3use crate::{AgentState, JsonValue};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
10pub enum EventType {
11 TextMessageStart,
13 TextMessageContent,
15 TextMessageEnd,
17 TextMessageChunk,
19 ThinkingTextMessageStart,
21 ThinkingTextMessageContent,
23 ThinkingTextMessageEnd,
25 ToolCallStart,
27 ToolCallArgs,
29 ToolCallEnd,
31 ToolCallChunk,
33 ToolCallResult,
35 ThinkingStart,
37 ThinkingEnd,
39 StateSnapshot,
41 StateDelta,
43 MessagesSnapshot,
45 Raw,
47 Custom,
49 RunStarted,
51 RunFinished,
53 RunError,
55 StepStarted,
57 StepFinished,
59}
60
61#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
64pub struct BaseEvent {
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub timestamp: Option<f64>,
67 #[serde(rename = "rawEvent", skip_serializing_if = "Option::is_none")]
68 pub raw_event: Option<JsonValue>,
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74pub struct TextMessageStartEvent {
75 #[serde(flatten)]
76 pub base: BaseEvent,
77 #[serde(rename = "messageId")]
78 pub message_id: MessageId,
79 pub role: Role, }
81
82#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85pub struct TextMessageContentEvent {
86 #[serde(flatten)]
87 pub base: BaseEvent,
88 #[serde(rename = "messageId")]
89 pub message_id: MessageId,
90 pub delta: String,
91}
92
93#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
96pub struct TextMessageEndEvent {
97 #[serde(flatten)]
98 pub base: BaseEvent,
99 #[serde(rename = "messageId")]
100 pub message_id: MessageId,
101}
102
103#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
107pub struct TextMessageChunkEvent {
108 #[serde(flatten)]
109 pub base: BaseEvent,
110 #[serde(rename = "messageId", skip_serializing_if = "Option::is_none")]
111 pub message_id: Option<MessageId>,
112 pub role: Role,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub delta: Option<String>,
115}
116
117#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
120pub struct ThinkingTextMessageStartEvent {
121 #[serde(flatten)]
122 pub base: BaseEvent,
123}
124
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
128pub struct ThinkingTextMessageContentEvent {
129 #[serde(flatten)]
130 pub base: BaseEvent,
131 pub delta: String,
132}
133
134#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
137pub struct ThinkingTextMessageEndEvent {
138 #[serde(flatten)]
139 pub base: BaseEvent,
140}
141
142#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145pub struct ToolCallStartEvent {
146 #[serde(flatten)]
147 pub base: BaseEvent,
148 #[serde(rename = "toolCallId")]
149 pub tool_call_id: ToolCallId,
150 #[serde(rename = "toolCallName")]
151 pub tool_call_name: String,
152 #[serde(rename = "parentMessageId", skip_serializing_if = "Option::is_none")]
153 pub parent_message_id: Option<MessageId>,
154}
155
156#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
159pub struct ToolCallArgsEvent {
160 #[serde(flatten)]
161 pub base: BaseEvent,
162 #[serde(rename = "toolCallId")]
163 pub tool_call_id: ToolCallId,
164 pub delta: String,
165}
166
167#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
170pub struct ToolCallEndEvent {
171 #[serde(flatten)]
172 pub base: BaseEvent,
173 #[serde(rename = "toolCallId")]
174 pub tool_call_id: ToolCallId,
175}
176
177#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
180pub struct ToolCallResultEvent {
181 #[serde(flatten)]
182 pub base: BaseEvent,
183 #[serde(rename = "messageId")]
184 pub message_id: MessageId,
185 #[serde(rename = "toolCallId")]
186 pub tool_call_id: ToolCallId,
187 pub content: String,
188 #[serde(default = "Role::tool")]
189 pub role: Role, }
191
192#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
196pub struct ToolCallChunkEvent {
197 #[serde(flatten)]
198 pub base: BaseEvent,
199 #[serde(rename = "toolCallId", skip_serializing_if = "Option::is_none")]
200 pub tool_call_id: Option<ToolCallId>,
201 #[serde(rename = "toolCallName", skip_serializing_if = "Option::is_none")]
202 pub tool_call_name: Option<String>,
203 #[serde(rename = "parentMessageId", skip_serializing_if = "Option::is_none")]
204 pub parent_message_id: Option<MessageId>,
205 #[serde(skip_serializing_if = "Option::is_none")]
206 pub delta: Option<String>,
207}
208
209#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
212pub struct ThinkingStartEvent {
213 #[serde(flatten)]
214 pub base: BaseEvent,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub title: Option<String>,
217}
218
219#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
222pub struct ThinkingEndEvent {
223 #[serde(flatten)]
224 pub base: BaseEvent,
225}
226
227#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
230#[serde(bound(deserialize = ""))]
231pub struct StateSnapshotEvent<StateT: AgentState = JsonValue> {
232 #[serde(flatten)]
233 pub base: BaseEvent,
234 pub snapshot: StateT,
235}
236
237#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
240pub struct StateDeltaEvent {
241 #[serde(flatten)]
242 pub base: BaseEvent,
243 pub delta: Vec<JsonValue>,
244}
245
246#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
249pub struct MessagesSnapshotEvent {
250 #[serde(flatten)]
251 pub base: BaseEvent,
252 pub messages: Vec<Message>,
253}
254
255#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
258pub struct RawEvent {
259 #[serde(flatten)]
260 pub base: BaseEvent,
261 pub event: JsonValue,
262 #[serde(skip_serializing_if = "Option::is_none")]
263 pub source: Option<String>,
264}
265
266#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
269pub struct CustomEvent {
270 #[serde(flatten)]
271 pub base: BaseEvent,
272 pub name: String,
273 pub value: JsonValue,
274}
275
276#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
279pub struct RunStartedEvent {
280 #[serde(flatten)]
281 pub base: BaseEvent,
282 #[serde(rename = "threadId")]
283 pub thread_id: ThreadId,
284 #[serde(rename = "runId")]
285 pub run_id: RunId,
286}
287
288#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
291pub struct RunFinishedEvent {
292 #[serde(flatten)]
293 pub base: BaseEvent,
294 #[serde(rename = "threadId")]
295 pub thread_id: ThreadId,
296 #[serde(rename = "runId")]
297 pub run_id: RunId,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub result: Option<JsonValue>,
300}
301
302#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
305pub struct RunErrorEvent {
306 #[serde(flatten)]
307 pub base: BaseEvent,
308 pub message: String,
309 #[serde(skip_serializing_if = "Option::is_none")]
310 pub code: Option<String>,
311}
312
313#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
316pub struct StepStartedEvent {
317 #[serde(flatten)]
318 pub base: BaseEvent,
319 #[serde(rename = "stepName")]
320 pub step_name: String,
321}
322
323#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
326pub struct StepFinishedEvent {
327 #[serde(flatten)]
328 pub base: BaseEvent,
329 #[serde(rename = "stepName")]
330 pub step_name: String,
331}
332
333#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
337#[serde(
338 tag = "type",
339 rename_all = "SCREAMING_SNAKE_CASE",
340 bound(deserialize = "")
341)]
342pub enum Event<StateT: AgentState = JsonValue> {
343 TextMessageStart(TextMessageStartEvent),
346
347 TextMessageContent(TextMessageContentEvent),
350
351 TextMessageEnd(TextMessageEndEvent),
354
355 TextMessageChunk(TextMessageChunkEvent),
358
359 ThinkingTextMessageStart(ThinkingTextMessageStartEvent),
362
363 ThinkingTextMessageContent(ThinkingTextMessageContentEvent),
366
367 ThinkingTextMessageEnd(ThinkingTextMessageEndEvent),
369
370 ToolCallStart(ToolCallStartEvent),
373
374 ToolCallArgs(ToolCallArgsEvent),
377
378 ToolCallEnd(ToolCallEndEvent),
381
382 ToolCallChunk(ToolCallChunkEvent),
385
386 ToolCallResult(ToolCallResultEvent),
389
390 ThinkingStart(ThinkingStartEvent),
393
394 ThinkingEnd(ThinkingEndEvent),
396
397 StateSnapshot(StateSnapshotEvent<StateT>),
400
401 StateDelta(StateDeltaEvent),
404
405 MessagesSnapshot(MessagesSnapshotEvent),
408
409 Raw(RawEvent),
412
413 Custom(CustomEvent),
416
417 RunStarted(RunStartedEvent),
420
421 RunFinished(RunFinishedEvent),
424
425 RunError(RunErrorEvent),
428
429 StepStarted(StepStartedEvent),
432
433 StepFinished(StepFinishedEvent),
436}
437
438impl Event {
439 pub fn event_type(&self) -> EventType {
441 match self {
442 Event::TextMessageStart(_) => EventType::TextMessageStart,
443 Event::TextMessageContent(_) => EventType::TextMessageContent,
444 Event::TextMessageEnd(_) => EventType::TextMessageEnd,
445 Event::TextMessageChunk(_) => EventType::TextMessageChunk,
446 Event::ThinkingTextMessageStart(_) => EventType::ThinkingTextMessageStart,
447 Event::ThinkingTextMessageContent(_) => EventType::ThinkingTextMessageContent,
448 Event::ThinkingTextMessageEnd(_) => EventType::ThinkingTextMessageEnd,
449 Event::ToolCallStart(_) => EventType::ToolCallStart,
450 Event::ToolCallArgs(_) => EventType::ToolCallArgs,
451 Event::ToolCallEnd(_) => EventType::ToolCallEnd,
452 Event::ToolCallChunk(_) => EventType::ToolCallChunk,
453 Event::ToolCallResult(_) => EventType::ToolCallResult,
454 Event::ThinkingStart(_) => EventType::ThinkingStart,
455 Event::ThinkingEnd(_) => EventType::ThinkingEnd,
456 Event::StateSnapshot(_) => EventType::StateSnapshot,
457 Event::StateDelta(_) => EventType::StateDelta,
458 Event::MessagesSnapshot(_) => EventType::MessagesSnapshot,
459 Event::Raw(_) => EventType::Raw,
460 Event::Custom(_) => EventType::Custom,
461 Event::RunStarted(_) => EventType::RunStarted,
462 Event::RunFinished(_) => EventType::RunFinished,
463 Event::RunError(_) => EventType::RunError,
464 Event::StepStarted(_) => EventType::StepStarted,
465 Event::StepFinished(_) => EventType::StepFinished,
466 }
467 }
468
469 pub fn timestamp(&self) -> Option<f64> {
471 match self {
472 Event::TextMessageStart(e) => e.base.timestamp,
473 Event::TextMessageContent(e) => e.base.timestamp,
474 Event::TextMessageEnd(e) => e.base.timestamp,
475 Event::TextMessageChunk(e) => e.base.timestamp,
476 Event::ThinkingTextMessageStart(e) => e.base.timestamp,
477 Event::ThinkingTextMessageContent(e) => e.base.timestamp,
478 Event::ThinkingTextMessageEnd(e) => e.base.timestamp,
479 Event::ToolCallStart(e) => e.base.timestamp,
480 Event::ToolCallArgs(e) => e.base.timestamp,
481 Event::ToolCallEnd(e) => e.base.timestamp,
482 Event::ToolCallChunk(e) => e.base.timestamp,
483 Event::ToolCallResult(e) => e.base.timestamp,
484 Event::ThinkingStart(e) => e.base.timestamp,
485 Event::ThinkingEnd(e) => e.base.timestamp,
486 Event::StateSnapshot(e) => e.base.timestamp,
487 Event::StateDelta(e) => e.base.timestamp,
488 Event::MessagesSnapshot(e) => e.base.timestamp,
489 Event::Raw(e) => e.base.timestamp,
490 Event::Custom(e) => e.base.timestamp,
491 Event::RunStarted(e) => e.base.timestamp,
492 Event::RunFinished(e) => e.base.timestamp,
493 Event::RunError(e) => e.base.timestamp,
494 Event::StepStarted(e) => e.base.timestamp,
495 Event::StepFinished(e) => e.base.timestamp,
496 }
497 }
498}
499
500#[derive(Debug, thiserror::Error)]
503pub enum EventValidationError {
504 #[error("Delta must not be an empty string")]
505 EmptyDelta,
506 #[error("Invalid event format: {0}")]
507 InvalidFormat(String),
508}
509
510impl TextMessageContentEvent {
512 pub fn validate(&self) -> Result<(), EventValidationError> {
513 if self.delta.is_empty() {
514 return Err(EventValidationError::EmptyDelta);
515 }
516 Ok(())
517 }
518}
519
520impl TextMessageStartEvent {
522 pub fn new(message_id: impl Into<MessageId>) -> Self {
523 Self {
524 base: BaseEvent {
525 timestamp: None,
526 raw_event: None,
527 },
528 message_id: message_id.into(),
529 role: Role::Assistant,
530 }
531 }
532
533 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
534 self.base.timestamp = Some(timestamp);
535 self
536 }
537
538 pub fn with_raw_event(mut self, raw_event: JsonValue) -> Self {
539 self.base.raw_event = Some(raw_event);
540 self
541 }
542}
543
544impl TextMessageContentEvent {
545 pub fn new(
546 message_id: impl Into<MessageId>,
547 delta: String,
548 ) -> Result<Self, EventValidationError> {
549 let event = Self {
550 base: BaseEvent {
551 timestamp: None,
552 raw_event: None,
553 },
554 message_id: message_id.into(),
555 delta,
556 };
557 event.validate()?;
558 Ok(event)
559 }
560
561 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
562 self.base.timestamp = Some(timestamp);
563 self
564 }
565}