1use crate::state::AgentState;
13use crate::types::{Message, MessageId, Role, RunId, ThreadId, ToolCallId};
14use crate::JsonValue;
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
34#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
35pub enum EventType {
36 TextMessageStart,
38 TextMessageContent,
40 TextMessageEnd,
42 TextMessageChunk,
44 ThinkingTextMessageStart,
46 ThinkingTextMessageContent,
48 ThinkingTextMessageEnd,
50 ToolCallStart,
52 ToolCallArgs,
54 ToolCallEnd,
56 ToolCallChunk,
58 ToolCallResult,
60 ThinkingStart,
62 ThinkingEnd,
64 StateSnapshot,
66 StateDelta,
68 MessagesSnapshot,
70 ActivitySnapshot,
72 ActivityDelta,
74 Raw,
76 Custom,
78 RunStarted,
80 RunFinished,
82 RunError,
84 StepStarted,
86 StepFinished,
88}
89
90impl EventType {
91 pub fn as_str(&self) -> &'static str {
93 match self {
94 EventType::TextMessageStart => "TEXT_MESSAGE_START",
95 EventType::TextMessageContent => "TEXT_MESSAGE_CONTENT",
96 EventType::TextMessageEnd => "TEXT_MESSAGE_END",
97 EventType::TextMessageChunk => "TEXT_MESSAGE_CHUNK",
98 EventType::ThinkingTextMessageStart => "THINKING_TEXT_MESSAGE_START",
99 EventType::ThinkingTextMessageContent => "THINKING_TEXT_MESSAGE_CONTENT",
100 EventType::ThinkingTextMessageEnd => "THINKING_TEXT_MESSAGE_END",
101 EventType::ToolCallStart => "TOOL_CALL_START",
102 EventType::ToolCallArgs => "TOOL_CALL_ARGS",
103 EventType::ToolCallEnd => "TOOL_CALL_END",
104 EventType::ToolCallChunk => "TOOL_CALL_CHUNK",
105 EventType::ToolCallResult => "TOOL_CALL_RESULT",
106 EventType::ThinkingStart => "THINKING_START",
107 EventType::ThinkingEnd => "THINKING_END",
108 EventType::StateSnapshot => "STATE_SNAPSHOT",
109 EventType::StateDelta => "STATE_DELTA",
110 EventType::MessagesSnapshot => "MESSAGES_SNAPSHOT",
111 EventType::ActivitySnapshot => "ACTIVITY_SNAPSHOT",
112 EventType::ActivityDelta => "ACTIVITY_DELTA",
113 EventType::Raw => "RAW",
114 EventType::Custom => "CUSTOM",
115 EventType::RunStarted => "RUN_STARTED",
116 EventType::RunFinished => "RUN_FINISHED",
117 EventType::RunError => "RUN_ERROR",
118 EventType::StepStarted => "STEP_STARTED",
119 EventType::StepFinished => "STEP_FINISHED",
120 }
121 }
122}
123
124impl std::fmt::Display for EventType {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 write!(f, "{}", self.as_str())
127 }
128}
129
130#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
151pub struct BaseEvent {
152 #[serde(skip_serializing_if = "Option::is_none")]
154 pub timestamp: Option<f64>,
155 #[serde(rename = "rawEvent", skip_serializing_if = "Option::is_none")]
157 pub raw_event: Option<JsonValue>,
158}
159
160impl BaseEvent {
161 pub fn new() -> Self {
163 Self::default()
164 }
165
166 pub fn with_current_timestamp() -> Self {
168 Self {
169 timestamp: Some(
170 std::time::SystemTime::now()
171 .duration_since(std::time::UNIX_EPOCH)
172 .map(|d| d.as_millis() as f64)
173 .unwrap_or(0.0),
174 ),
175 raw_event: None,
176 }
177 }
178
179 pub fn timestamp(mut self, timestamp: f64) -> Self {
181 self.timestamp = Some(timestamp);
182 self
183 }
184
185 pub fn raw_event(mut self, raw_event: JsonValue) -> Self {
187 self.raw_event = Some(raw_event);
188 self
189 }
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
196pub enum EventValidationError {
197 #[error("Delta must not be an empty string")]
199 EmptyDelta,
200 #[error("Invalid event format: {0}")]
202 InvalidFormat(String),
203 #[error("Missing required field: {0}")]
205 MissingField(String),
206 #[error("Event type mismatch: expected {expected}, got {actual}")]
208 TypeMismatch {
209 expected: String,
211 actual: String,
213 },
214}
215
216#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
235pub struct TextMessageStartEvent {
236 #[serde(flatten)]
238 pub base: BaseEvent,
239 #[serde(rename = "messageId")]
241 pub message_id: MessageId,
242 pub role: Role,
244}
245
246impl TextMessageStartEvent {
247 pub fn new(message_id: impl Into<MessageId>) -> Self {
249 Self {
250 base: BaseEvent::default(),
251 message_id: message_id.into(),
252 role: Role::Assistant,
253 }
254 }
255
256 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
258 self.base.timestamp = Some(timestamp);
259 self
260 }
261
262 pub fn with_raw_event(mut self, raw_event: JsonValue) -> Self {
264 self.base.raw_event = Some(raw_event);
265 self
266 }
267}
268
269#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
279pub struct TextMessageContentEvent {
280 #[serde(flatten)]
282 pub base: BaseEvent,
283 #[serde(rename = "messageId")]
285 pub message_id: MessageId,
286 pub delta: String,
288}
289
290impl TextMessageContentEvent {
291 pub fn new(
295 message_id: impl Into<MessageId>,
296 delta: impl Into<String>,
297 ) -> Result<Self, EventValidationError> {
298 let delta = delta.into();
299 if delta.is_empty() {
300 return Err(EventValidationError::EmptyDelta);
301 }
302 Ok(Self {
303 base: BaseEvent::default(),
304 message_id: message_id.into(),
305 delta,
306 })
307 }
308
309 pub fn new_unchecked(message_id: impl Into<MessageId>, delta: impl Into<String>) -> Self {
313 Self {
314 base: BaseEvent::default(),
315 message_id: message_id.into(),
316 delta: delta.into(),
317 }
318 }
319
320 pub fn validate(&self) -> Result<(), EventValidationError> {
322 if self.delta.is_empty() {
323 return Err(EventValidationError::EmptyDelta);
324 }
325 Ok(())
326 }
327
328 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
330 self.base.timestamp = Some(timestamp);
331 self
332 }
333}
334
335#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
339pub struct TextMessageEndEvent {
340 #[serde(flatten)]
342 pub base: BaseEvent,
343 #[serde(rename = "messageId")]
345 pub message_id: MessageId,
346}
347
348impl TextMessageEndEvent {
349 pub fn new(message_id: impl Into<MessageId>) -> Self {
351 Self {
352 base: BaseEvent::default(),
353 message_id: message_id.into(),
354 }
355 }
356
357 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
359 self.base.timestamp = Some(timestamp);
360 self
361 }
362}
363
364#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
369pub struct TextMessageChunkEvent {
370 #[serde(flatten)]
372 pub base: BaseEvent,
373 #[serde(rename = "messageId", skip_serializing_if = "Option::is_none")]
375 pub message_id: Option<MessageId>,
376 pub role: Role,
378 #[serde(skip_serializing_if = "Option::is_none")]
380 pub delta: Option<String>,
381}
382
383impl TextMessageChunkEvent {
384 pub fn new(role: Role) -> Self {
386 Self {
387 base: BaseEvent::default(),
388 message_id: None,
389 role,
390 delta: None,
391 }
392 }
393
394 pub fn with_message_id(mut self, message_id: impl Into<MessageId>) -> Self {
396 self.message_id = Some(message_id.into());
397 self
398 }
399
400 pub fn with_delta(mut self, delta: impl Into<String>) -> Self {
402 self.delta = Some(delta.into());
403 self
404 }
405
406 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
408 self.base.timestamp = Some(timestamp);
409 self
410 }
411}
412
413#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
423pub struct ThinkingTextMessageStartEvent {
424 #[serde(flatten)]
426 pub base: BaseEvent,
427}
428
429impl ThinkingTextMessageStartEvent {
430 pub fn new() -> Self {
432 Self {
433 base: BaseEvent::default(),
434 }
435 }
436
437 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
439 self.base.timestamp = Some(timestamp);
440 self
441 }
442}
443
444impl Default for ThinkingTextMessageStartEvent {
445 fn default() -> Self {
446 Self::new()
447 }
448}
449
450#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
456pub struct ThinkingTextMessageContentEvent {
457 #[serde(flatten)]
459 pub base: BaseEvent,
460 pub delta: String,
462}
463
464impl ThinkingTextMessageContentEvent {
465 pub fn new(delta: impl Into<String>) -> Self {
467 Self {
468 base: BaseEvent::default(),
469 delta: delta.into(),
470 }
471 }
472
473 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
475 self.base.timestamp = Some(timestamp);
476 self
477 }
478}
479
480#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
484pub struct ThinkingTextMessageEndEvent {
485 #[serde(flatten)]
487 pub base: BaseEvent,
488}
489
490impl ThinkingTextMessageEndEvent {
491 pub fn new() -> Self {
493 Self {
494 base: BaseEvent::default(),
495 }
496 }
497
498 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
500 self.base.timestamp = Some(timestamp);
501 self
502 }
503}
504
505impl Default for ThinkingTextMessageEndEvent {
506 fn default() -> Self {
507 Self::new()
508 }
509}
510
511#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
520pub struct ToolCallStartEvent {
521 #[serde(flatten)]
523 pub base: BaseEvent,
524 #[serde(rename = "toolCallId")]
526 pub tool_call_id: ToolCallId,
527 #[serde(rename = "toolCallName")]
529 pub tool_call_name: String,
530 #[serde(rename = "parentMessageId", skip_serializing_if = "Option::is_none")]
532 pub parent_message_id: Option<MessageId>,
533}
534
535impl ToolCallStartEvent {
536 pub fn new(tool_call_id: impl Into<ToolCallId>, tool_call_name: impl Into<String>) -> Self {
538 Self {
539 base: BaseEvent::default(),
540 tool_call_id: tool_call_id.into(),
541 tool_call_name: tool_call_name.into(),
542 parent_message_id: None,
543 }
544 }
545
546 pub fn with_parent_message_id(mut self, message_id: impl Into<MessageId>) -> Self {
548 self.parent_message_id = Some(message_id.into());
549 self
550 }
551
552 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
554 self.base.timestamp = Some(timestamp);
555 self
556 }
557}
558
559#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
564pub struct ToolCallArgsEvent {
565 #[serde(flatten)]
567 pub base: BaseEvent,
568 #[serde(rename = "toolCallId")]
570 pub tool_call_id: ToolCallId,
571 pub delta: String,
573}
574
575impl ToolCallArgsEvent {
576 pub fn new(tool_call_id: impl Into<ToolCallId>, delta: impl Into<String>) -> Self {
578 Self {
579 base: BaseEvent::default(),
580 tool_call_id: tool_call_id.into(),
581 delta: delta.into(),
582 }
583 }
584
585 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
587 self.base.timestamp = Some(timestamp);
588 self
589 }
590}
591
592#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
596pub struct ToolCallEndEvent {
597 #[serde(flatten)]
599 pub base: BaseEvent,
600 #[serde(rename = "toolCallId")]
602 pub tool_call_id: ToolCallId,
603}
604
605impl ToolCallEndEvent {
606 pub fn new(tool_call_id: impl Into<ToolCallId>) -> Self {
608 Self {
609 base: BaseEvent::default(),
610 tool_call_id: tool_call_id.into(),
611 }
612 }
613
614 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
616 self.base.timestamp = Some(timestamp);
617 self
618 }
619}
620
621#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
626pub struct ToolCallChunkEvent {
627 #[serde(flatten)]
629 pub base: BaseEvent,
630 #[serde(rename = "toolCallId", skip_serializing_if = "Option::is_none")]
632 pub tool_call_id: Option<ToolCallId>,
633 #[serde(rename = "toolCallName", skip_serializing_if = "Option::is_none")]
635 pub tool_call_name: Option<String>,
636 #[serde(rename = "parentMessageId", skip_serializing_if = "Option::is_none")]
638 pub parent_message_id: Option<MessageId>,
639 #[serde(skip_serializing_if = "Option::is_none")]
641 pub delta: Option<String>,
642}
643
644impl ToolCallChunkEvent {
645 pub fn new() -> Self {
647 Self {
648 base: BaseEvent::default(),
649 tool_call_id: None,
650 tool_call_name: None,
651 parent_message_id: None,
652 delta: None,
653 }
654 }
655
656 pub fn with_tool_call_id(mut self, tool_call_id: impl Into<ToolCallId>) -> Self {
658 self.tool_call_id = Some(tool_call_id.into());
659 self
660 }
661
662 pub fn with_tool_call_name(mut self, name: impl Into<String>) -> Self {
664 self.tool_call_name = Some(name.into());
665 self
666 }
667
668 pub fn with_parent_message_id(mut self, message_id: impl Into<MessageId>) -> Self {
670 self.parent_message_id = Some(message_id.into());
671 self
672 }
673
674 pub fn with_delta(mut self, delta: impl Into<String>) -> Self {
676 self.delta = Some(delta.into());
677 self
678 }
679
680 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
682 self.base.timestamp = Some(timestamp);
683 self
684 }
685}
686
687impl Default for ToolCallChunkEvent {
688 fn default() -> Self {
689 Self::new()
690 }
691}
692
693#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
697pub struct ToolCallResultEvent {
698 #[serde(flatten)]
700 pub base: BaseEvent,
701 #[serde(rename = "messageId")]
703 pub message_id: MessageId,
704 #[serde(rename = "toolCallId")]
706 pub tool_call_id: ToolCallId,
707 pub content: String,
709 #[serde(default = "Role::tool")]
711 pub role: Role,
712}
713
714impl ToolCallResultEvent {
715 pub fn new(
717 message_id: impl Into<MessageId>,
718 tool_call_id: impl Into<ToolCallId>,
719 content: impl Into<String>,
720 ) -> Self {
721 Self {
722 base: BaseEvent::default(),
723 message_id: message_id.into(),
724 tool_call_id: tool_call_id.into(),
725 content: content.into(),
726 role: Role::Tool,
727 }
728 }
729
730 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
732 self.base.timestamp = Some(timestamp);
733 self
734 }
735}
736
737#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
746pub struct RunStartedEvent {
747 #[serde(flatten)]
749 pub base: BaseEvent,
750 #[serde(rename = "threadId")]
752 pub thread_id: ThreadId,
753 #[serde(rename = "runId")]
755 pub run_id: RunId,
756}
757
758impl RunStartedEvent {
759 pub fn new(thread_id: impl Into<ThreadId>, run_id: impl Into<RunId>) -> Self {
761 Self {
762 base: BaseEvent::default(),
763 thread_id: thread_id.into(),
764 run_id: run_id.into(),
765 }
766 }
767
768 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
770 self.base.timestamp = Some(timestamp);
771 self
772 }
773}
774
775#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
780#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
781pub enum RunFinishedOutcome {
782 Success,
784 Interrupt,
786}
787
788impl Default for RunFinishedOutcome {
789 fn default() -> Self {
790 Self::Success
791 }
792}
793
794#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
814pub struct InterruptInfo {
815 #[serde(skip_serializing_if = "Option::is_none")]
817 pub id: Option<String>,
818 #[serde(skip_serializing_if = "Option::is_none")]
821 pub reason: Option<String>,
822 #[serde(skip_serializing_if = "Option::is_none")]
825 pub payload: Option<JsonValue>,
826}
827
828impl InterruptInfo {
829 pub fn new() -> Self {
831 Self::default()
832 }
833
834 pub fn with_id(mut self, id: impl Into<String>) -> Self {
836 self.id = Some(id.into());
837 self
838 }
839
840 pub fn with_reason(mut self, reason: impl Into<String>) -> Self {
842 self.reason = Some(reason.into());
843 self
844 }
845
846 pub fn with_payload(mut self, payload: JsonValue) -> Self {
848 self.payload = Some(payload);
849 self
850 }
851}
852
853#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
881pub struct RunFinishedEvent {
882 #[serde(flatten)]
884 pub base: BaseEvent,
885 #[serde(rename = "threadId")]
887 pub thread_id: ThreadId,
888 #[serde(rename = "runId")]
890 pub run_id: RunId,
891 #[serde(skip_serializing_if = "Option::is_none")]
894 pub outcome: Option<RunFinishedOutcome>,
895 #[serde(skip_serializing_if = "Option::is_none")]
898 pub result: Option<JsonValue>,
899 #[serde(skip_serializing_if = "Option::is_none")]
902 pub interrupt: Option<InterruptInfo>,
903}
904
905impl RunFinishedEvent {
906 pub fn new(thread_id: impl Into<ThreadId>, run_id: impl Into<RunId>) -> Self {
908 Self {
909 base: BaseEvent::default(),
910 thread_id: thread_id.into(),
911 run_id: run_id.into(),
912 outcome: None,
913 result: None,
914 interrupt: None,
915 }
916 }
917
918 pub fn with_outcome(mut self, outcome: RunFinishedOutcome) -> Self {
920 self.outcome = Some(outcome);
921 self
922 }
923
924 pub fn with_result(mut self, result: JsonValue) -> Self {
926 self.result = Some(result);
927 self
928 }
929
930 pub fn with_interrupt(mut self, interrupt: InterruptInfo) -> Self {
932 self.outcome = Some(RunFinishedOutcome::Interrupt);
933 self.interrupt = Some(interrupt);
934 self
935 }
936
937 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
939 self.base.timestamp = Some(timestamp);
940 self
941 }
942
943 pub fn effective_outcome(&self) -> RunFinishedOutcome {
949 self.outcome.unwrap_or_else(|| {
950 if self.interrupt.is_some() {
951 RunFinishedOutcome::Interrupt
952 } else {
953 RunFinishedOutcome::Success
954 }
955 })
956 }
957}
958
959#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
963pub struct RunErrorEvent {
964 #[serde(flatten)]
966 pub base: BaseEvent,
967 pub message: String,
969 #[serde(skip_serializing_if = "Option::is_none")]
971 pub code: Option<String>,
972}
973
974impl RunErrorEvent {
975 pub fn new(message: impl Into<String>) -> Self {
977 Self {
978 base: BaseEvent::default(),
979 message: message.into(),
980 code: None,
981 }
982 }
983
984 pub fn with_code(mut self, code: impl Into<String>) -> Self {
986 self.code = Some(code.into());
987 self
988 }
989
990 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
992 self.base.timestamp = Some(timestamp);
993 self
994 }
995}
996
997#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1006pub struct StepStartedEvent {
1007 #[serde(flatten)]
1009 pub base: BaseEvent,
1010 #[serde(rename = "stepName")]
1012 pub step_name: String,
1013}
1014
1015impl StepStartedEvent {
1016 pub fn new(step_name: impl Into<String>) -> Self {
1018 Self {
1019 base: BaseEvent::default(),
1020 step_name: step_name.into(),
1021 }
1022 }
1023
1024 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1026 self.base.timestamp = Some(timestamp);
1027 self
1028 }
1029}
1030
1031#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1035pub struct StepFinishedEvent {
1036 #[serde(flatten)]
1038 pub base: BaseEvent,
1039 #[serde(rename = "stepName")]
1041 pub step_name: String,
1042}
1043
1044impl StepFinishedEvent {
1045 pub fn new(step_name: impl Into<String>) -> Self {
1047 Self {
1048 base: BaseEvent::default(),
1049 step_name: step_name.into(),
1050 }
1051 }
1052
1053 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1055 self.base.timestamp = Some(timestamp);
1056 self
1057 }
1058}
1059
1060#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1073#[serde(bound(deserialize = ""))]
1074pub struct StateSnapshotEvent<StateT: AgentState = JsonValue> {
1075 #[serde(flatten)]
1077 pub base: BaseEvent,
1078 pub snapshot: StateT,
1080}
1081
1082impl<StateT: AgentState> StateSnapshotEvent<StateT> {
1083 pub fn new(snapshot: StateT) -> Self {
1085 Self {
1086 base: BaseEvent::default(),
1087 snapshot,
1088 }
1089 }
1090
1091 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1093 self.base.timestamp = Some(timestamp);
1094 self
1095 }
1096}
1097
1098impl<StateT: AgentState + Default> Default for StateSnapshotEvent<StateT> {
1099 fn default() -> Self {
1100 Self {
1101 base: BaseEvent::default(),
1102 snapshot: StateT::default(),
1103 }
1104 }
1105}
1106
1107#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1112pub struct StateDeltaEvent {
1113 #[serde(flatten)]
1115 pub base: BaseEvent,
1116 pub delta: Vec<JsonValue>,
1118}
1119
1120impl StateDeltaEvent {
1121 pub fn new(delta: Vec<JsonValue>) -> Self {
1123 Self {
1124 base: BaseEvent::default(),
1125 delta,
1126 }
1127 }
1128
1129 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1131 self.base.timestamp = Some(timestamp);
1132 self
1133 }
1134}
1135
1136impl Default for StateDeltaEvent {
1137 fn default() -> Self {
1138 Self {
1139 base: BaseEvent::default(),
1140 delta: Vec::new(),
1141 }
1142 }
1143}
1144
1145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1149pub struct MessagesSnapshotEvent {
1150 #[serde(flatten)]
1152 pub base: BaseEvent,
1153 pub messages: Vec<Message>,
1155}
1156
1157impl MessagesSnapshotEvent {
1158 pub fn new(messages: Vec<Message>) -> Self {
1160 Self {
1161 base: BaseEvent::default(),
1162 messages,
1163 }
1164 }
1165
1166 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1168 self.base.timestamp = Some(timestamp);
1169 self
1170 }
1171}
1172
1173impl Default for MessagesSnapshotEvent {
1174 fn default() -> Self {
1175 Self {
1176 base: BaseEvent::default(),
1177 messages: Vec::new(),
1178 }
1179 }
1180}
1181
1182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1205pub struct ActivitySnapshotEvent {
1206 #[serde(flatten)]
1208 pub base: BaseEvent,
1209 #[serde(rename = "messageId")]
1211 pub message_id: MessageId,
1212 #[serde(rename = "activityType")]
1214 pub activity_type: String,
1215 pub content: JsonValue,
1217 #[serde(skip_serializing_if = "Option::is_none")]
1219 pub replace: Option<bool>,
1220}
1221
1222impl ActivitySnapshotEvent {
1223 pub fn new(
1225 message_id: impl Into<MessageId>,
1226 activity_type: impl Into<String>,
1227 content: JsonValue,
1228 ) -> Self {
1229 Self {
1230 base: BaseEvent::default(),
1231 message_id: message_id.into(),
1232 activity_type: activity_type.into(),
1233 content,
1234 replace: None,
1235 }
1236 }
1237
1238 pub fn with_replace(mut self, replace: bool) -> Self {
1240 self.replace = Some(replace);
1241 self
1242 }
1243
1244 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1246 self.base.timestamp = Some(timestamp);
1247 self
1248 }
1249}
1250
1251#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1270pub struct ActivityDeltaEvent {
1271 #[serde(flatten)]
1273 pub base: BaseEvent,
1274 #[serde(rename = "messageId")]
1276 pub message_id: MessageId,
1277 #[serde(rename = "activityType")]
1279 pub activity_type: String,
1280 pub patch: Vec<JsonValue>,
1282}
1283
1284impl ActivityDeltaEvent {
1285 pub fn new(
1287 message_id: impl Into<MessageId>,
1288 activity_type: impl Into<String>,
1289 patch: Vec<JsonValue>,
1290 ) -> Self {
1291 Self {
1292 base: BaseEvent::default(),
1293 message_id: message_id.into(),
1294 activity_type: activity_type.into(),
1295 patch,
1296 }
1297 }
1298
1299 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1301 self.base.timestamp = Some(timestamp);
1302 self
1303 }
1304}
1305
1306#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1316pub struct ThinkingStartEvent {
1317 #[serde(flatten)]
1319 pub base: BaseEvent,
1320 #[serde(skip_serializing_if = "Option::is_none")]
1322 pub title: Option<String>,
1323}
1324
1325impl ThinkingStartEvent {
1326 pub fn new() -> Self {
1328 Self {
1329 base: BaseEvent::default(),
1330 title: None,
1331 }
1332 }
1333
1334 pub fn with_title(mut self, title: impl Into<String>) -> Self {
1336 self.title = Some(title.into());
1337 self
1338 }
1339
1340 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1342 self.base.timestamp = Some(timestamp);
1343 self
1344 }
1345}
1346
1347impl Default for ThinkingStartEvent {
1348 fn default() -> Self {
1349 Self::new()
1350 }
1351}
1352
1353#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1357pub struct ThinkingEndEvent {
1358 #[serde(flatten)]
1360 pub base: BaseEvent,
1361}
1362
1363impl ThinkingEndEvent {
1364 pub fn new() -> Self {
1366 Self {
1367 base: BaseEvent::default(),
1368 }
1369 }
1370
1371 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1373 self.base.timestamp = Some(timestamp);
1374 self
1375 }
1376}
1377
1378impl Default for ThinkingEndEvent {
1379 fn default() -> Self {
1380 Self::new()
1381 }
1382}
1383
1384#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1393pub struct RawEvent {
1394 #[serde(flatten)]
1396 pub base: BaseEvent,
1397 pub event: JsonValue,
1399 #[serde(skip_serializing_if = "Option::is_none")]
1401 pub source: Option<String>,
1402}
1403
1404impl RawEvent {
1405 pub fn new(event: JsonValue) -> Self {
1407 Self {
1408 base: BaseEvent::default(),
1409 event,
1410 source: None,
1411 }
1412 }
1413
1414 pub fn with_source(mut self, source: impl Into<String>) -> Self {
1416 self.source = Some(source.into());
1417 self
1418 }
1419
1420 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1422 self.base.timestamp = Some(timestamp);
1423 self
1424 }
1425}
1426
1427#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1431pub struct CustomEvent {
1432 #[serde(flatten)]
1434 pub base: BaseEvent,
1435 pub name: String,
1437 pub value: JsonValue,
1439}
1440
1441impl CustomEvent {
1442 pub fn new(name: impl Into<String>, value: JsonValue) -> Self {
1444 Self {
1445 base: BaseEvent::default(),
1446 name: name.into(),
1447 value,
1448 }
1449 }
1450
1451 pub fn with_timestamp(mut self, timestamp: f64) -> Self {
1453 self.base.timestamp = Some(timestamp);
1454 self
1455 }
1456}
1457
1458#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1478#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE", bound(deserialize = ""))]
1479pub enum Event<StateT: AgentState = JsonValue> {
1480 TextMessageStart(TextMessageStartEvent),
1482 TextMessageContent(TextMessageContentEvent),
1484 TextMessageEnd(TextMessageEndEvent),
1486 TextMessageChunk(TextMessageChunkEvent),
1488 ThinkingTextMessageStart(ThinkingTextMessageStartEvent),
1490 ThinkingTextMessageContent(ThinkingTextMessageContentEvent),
1492 ThinkingTextMessageEnd(ThinkingTextMessageEndEvent),
1494 ToolCallStart(ToolCallStartEvent),
1496 ToolCallArgs(ToolCallArgsEvent),
1498 ToolCallEnd(ToolCallEndEvent),
1500 ToolCallChunk(ToolCallChunkEvent),
1502 ToolCallResult(ToolCallResultEvent),
1504 ThinkingStart(ThinkingStartEvent),
1506 ThinkingEnd(ThinkingEndEvent),
1508 StateSnapshot(StateSnapshotEvent<StateT>),
1510 StateDelta(StateDeltaEvent),
1512 MessagesSnapshot(MessagesSnapshotEvent),
1514 ActivitySnapshot(ActivitySnapshotEvent),
1516 ActivityDelta(ActivityDeltaEvent),
1518 Raw(RawEvent),
1520 Custom(CustomEvent),
1522 RunStarted(RunStartedEvent),
1524 RunFinished(RunFinishedEvent),
1526 RunError(RunErrorEvent),
1528 StepStarted(StepStartedEvent),
1530 StepFinished(StepFinishedEvent),
1532}
1533
1534impl<StateT: AgentState> Event<StateT> {
1535 pub fn event_type(&self) -> EventType {
1537 match self {
1538 Event::TextMessageStart(_) => EventType::TextMessageStart,
1539 Event::TextMessageContent(_) => EventType::TextMessageContent,
1540 Event::TextMessageEnd(_) => EventType::TextMessageEnd,
1541 Event::TextMessageChunk(_) => EventType::TextMessageChunk,
1542 Event::ThinkingTextMessageStart(_) => EventType::ThinkingTextMessageStart,
1543 Event::ThinkingTextMessageContent(_) => EventType::ThinkingTextMessageContent,
1544 Event::ThinkingTextMessageEnd(_) => EventType::ThinkingTextMessageEnd,
1545 Event::ToolCallStart(_) => EventType::ToolCallStart,
1546 Event::ToolCallArgs(_) => EventType::ToolCallArgs,
1547 Event::ToolCallEnd(_) => EventType::ToolCallEnd,
1548 Event::ToolCallChunk(_) => EventType::ToolCallChunk,
1549 Event::ToolCallResult(_) => EventType::ToolCallResult,
1550 Event::ThinkingStart(_) => EventType::ThinkingStart,
1551 Event::ThinkingEnd(_) => EventType::ThinkingEnd,
1552 Event::StateSnapshot(_) => EventType::StateSnapshot,
1553 Event::StateDelta(_) => EventType::StateDelta,
1554 Event::MessagesSnapshot(_) => EventType::MessagesSnapshot,
1555 Event::ActivitySnapshot(_) => EventType::ActivitySnapshot,
1556 Event::ActivityDelta(_) => EventType::ActivityDelta,
1557 Event::Raw(_) => EventType::Raw,
1558 Event::Custom(_) => EventType::Custom,
1559 Event::RunStarted(_) => EventType::RunStarted,
1560 Event::RunFinished(_) => EventType::RunFinished,
1561 Event::RunError(_) => EventType::RunError,
1562 Event::StepStarted(_) => EventType::StepStarted,
1563 Event::StepFinished(_) => EventType::StepFinished,
1564 }
1565 }
1566
1567 pub fn timestamp(&self) -> Option<f64> {
1569 match self {
1570 Event::TextMessageStart(e) => e.base.timestamp,
1571 Event::TextMessageContent(e) => e.base.timestamp,
1572 Event::TextMessageEnd(e) => e.base.timestamp,
1573 Event::TextMessageChunk(e) => e.base.timestamp,
1574 Event::ThinkingTextMessageStart(e) => e.base.timestamp,
1575 Event::ThinkingTextMessageContent(e) => e.base.timestamp,
1576 Event::ThinkingTextMessageEnd(e) => e.base.timestamp,
1577 Event::ToolCallStart(e) => e.base.timestamp,
1578 Event::ToolCallArgs(e) => e.base.timestamp,
1579 Event::ToolCallEnd(e) => e.base.timestamp,
1580 Event::ToolCallChunk(e) => e.base.timestamp,
1581 Event::ToolCallResult(e) => e.base.timestamp,
1582 Event::ThinkingStart(e) => e.base.timestamp,
1583 Event::ThinkingEnd(e) => e.base.timestamp,
1584 Event::StateSnapshot(e) => e.base.timestamp,
1585 Event::StateDelta(e) => e.base.timestamp,
1586 Event::MessagesSnapshot(e) => e.base.timestamp,
1587 Event::ActivitySnapshot(e) => e.base.timestamp,
1588 Event::ActivityDelta(e) => e.base.timestamp,
1589 Event::Raw(e) => e.base.timestamp,
1590 Event::Custom(e) => e.base.timestamp,
1591 Event::RunStarted(e) => e.base.timestamp,
1592 Event::RunFinished(e) => e.base.timestamp,
1593 Event::RunError(e) => e.base.timestamp,
1594 Event::StepStarted(e) => e.base.timestamp,
1595 Event::StepFinished(e) => e.base.timestamp,
1596 }
1597 }
1598}
1599
1600#[cfg(test)]
1601mod tests {
1602 use super::*;
1603
1604 #[test]
1605 fn test_event_type_serialization() {
1606 let event_type = EventType::TextMessageStart;
1607 let json = serde_json::to_string(&event_type).unwrap();
1608 assert_eq!(json, "\"TEXT_MESSAGE_START\"");
1609
1610 let event_type = EventType::ToolCallArgs;
1611 let json = serde_json::to_string(&event_type).unwrap();
1612 assert_eq!(json, "\"TOOL_CALL_ARGS\"");
1613
1614 let event_type = EventType::StateSnapshot;
1615 let json = serde_json::to_string(&event_type).unwrap();
1616 assert_eq!(json, "\"STATE_SNAPSHOT\"");
1617 }
1618
1619 #[test]
1620 fn test_event_type_deserialization() {
1621 let event_type: EventType = serde_json::from_str("\"RUN_STARTED\"").unwrap();
1622 assert_eq!(event_type, EventType::RunStarted);
1623
1624 let event_type: EventType = serde_json::from_str("\"THINKING_TEXT_MESSAGE_CONTENT\"").unwrap();
1625 assert_eq!(event_type, EventType::ThinkingTextMessageContent);
1626 }
1627
1628 #[test]
1629 fn test_event_type_as_str() {
1630 assert_eq!(EventType::TextMessageStart.as_str(), "TEXT_MESSAGE_START");
1631 assert_eq!(EventType::RunFinished.as_str(), "RUN_FINISHED");
1632 assert_eq!(EventType::Custom.as_str(), "CUSTOM");
1633 }
1634
1635 #[test]
1636 fn test_event_type_display() {
1637 assert_eq!(format!("{}", EventType::TextMessageStart), "TEXT_MESSAGE_START");
1638 assert_eq!(format!("{}", EventType::StateDelta), "STATE_DELTA");
1639 }
1640
1641 #[test]
1642 fn test_base_event_serialization() {
1643 let event = BaseEvent {
1644 timestamp: Some(1706123456789.0),
1645 raw_event: None,
1646 };
1647 let json = serde_json::to_string(&event).unwrap();
1648 assert!(json.contains("\"timestamp\":1706123456789.0"));
1649 assert!(!json.contains("rawEvent")); }
1651
1652 #[test]
1653 fn test_base_event_with_raw_event() {
1654 let event = BaseEvent {
1655 timestamp: None,
1656 raw_event: Some(serde_json::json!({"provider": "openai"})),
1657 };
1658 let json = serde_json::to_string(&event).unwrap();
1659 assert!(json.contains("\"rawEvent\""));
1660 assert!(json.contains("\"provider\":\"openai\""));
1661 }
1662
1663 #[test]
1664 fn test_base_event_builder() {
1665 let event = BaseEvent::new()
1666 .timestamp(1234567890.0)
1667 .raw_event(serde_json::json!({"test": true}));
1668
1669 assert_eq!(event.timestamp, Some(1234567890.0));
1670 assert!(event.raw_event.is_some());
1671 }
1672
1673 #[test]
1674 fn test_event_validation_error_display() {
1675 let error = EventValidationError::EmptyDelta;
1676 assert_eq!(error.to_string(), "Delta must not be an empty string");
1677
1678 let error = EventValidationError::InvalidFormat("bad json".to_string());
1679 assert_eq!(error.to_string(), "Invalid event format: bad json");
1680
1681 let error = EventValidationError::MissingField("message_id".to_string());
1682 assert_eq!(error.to_string(), "Missing required field: message_id");
1683
1684 let error = EventValidationError::TypeMismatch {
1685 expected: "TEXT_MESSAGE_START".to_string(),
1686 actual: "RUN_STARTED".to_string(),
1687 };
1688 assert_eq!(
1689 error.to_string(),
1690 "Event type mismatch: expected TEXT_MESSAGE_START, got RUN_STARTED"
1691 );
1692 }
1693
1694 #[test]
1695 fn test_event_validation_error_is_std_error() {
1696 fn requires_error<E: std::error::Error>(_: E) {}
1697 requires_error(EventValidationError::EmptyDelta);
1698 }
1699
1700 #[test]
1701 fn test_all_event_types_roundtrip() {
1702 let all_types = [
1703 EventType::TextMessageStart,
1704 EventType::TextMessageContent,
1705 EventType::TextMessageEnd,
1706 EventType::TextMessageChunk,
1707 EventType::ThinkingTextMessageStart,
1708 EventType::ThinkingTextMessageContent,
1709 EventType::ThinkingTextMessageEnd,
1710 EventType::ToolCallStart,
1711 EventType::ToolCallArgs,
1712 EventType::ToolCallEnd,
1713 EventType::ToolCallChunk,
1714 EventType::ToolCallResult,
1715 EventType::ThinkingStart,
1716 EventType::ThinkingEnd,
1717 EventType::StateSnapshot,
1718 EventType::StateDelta,
1719 EventType::MessagesSnapshot,
1720 EventType::ActivitySnapshot,
1721 EventType::ActivityDelta,
1722 EventType::Raw,
1723 EventType::Custom,
1724 EventType::RunStarted,
1725 EventType::RunFinished,
1726 EventType::RunError,
1727 EventType::StepStarted,
1728 EventType::StepFinished,
1729 ];
1730
1731 for event_type in all_types {
1732 let json = serde_json::to_string(&event_type).unwrap();
1733 let parsed: EventType = serde_json::from_str(&json).unwrap();
1734 assert_eq!(event_type, parsed);
1735 }
1736 }
1737
1738 #[test]
1743 fn test_text_message_start_event() {
1744 use crate::types::{MessageId, Role};
1745
1746 let event = TextMessageStartEvent::new(MessageId::random());
1747 assert_eq!(event.role, Role::Assistant);
1748
1749 let json = serde_json::to_string(&event).unwrap();
1750 assert!(json.contains("\"messageId\""));
1751 assert!(json.contains("\"role\":\"assistant\""));
1752 }
1753
1754 #[test]
1755 fn test_text_message_start_event_with_timestamp() {
1756 use crate::types::MessageId;
1757
1758 let event = TextMessageStartEvent::new(MessageId::random()).with_timestamp(1234567890.0);
1759 assert_eq!(event.base.timestamp, Some(1234567890.0));
1760 }
1761
1762 #[test]
1763 fn test_text_message_content_event_validation() {
1764 use crate::types::MessageId;
1765
1766 let result = TextMessageContentEvent::new(MessageId::random(), "Hello");
1768 assert!(result.is_ok());
1769
1770 let result = TextMessageContentEvent::new(MessageId::random(), "");
1772 assert!(matches!(result, Err(EventValidationError::EmptyDelta)));
1773 }
1774
1775 #[test]
1776 fn test_text_message_content_event_validate_method() {
1777 use crate::types::MessageId;
1778
1779 let event = TextMessageContentEvent::new_unchecked(MessageId::random(), "");
1780 assert!(matches!(event.validate(), Err(EventValidationError::EmptyDelta)));
1781
1782 let event = TextMessageContentEvent::new_unchecked(MessageId::random(), "Hello");
1783 assert!(event.validate().is_ok());
1784 }
1785
1786 #[test]
1787 fn test_text_message_content_event_serialization() {
1788 use crate::types::MessageId;
1789
1790 let event = TextMessageContentEvent::new(MessageId::random(), "Hello, world!").unwrap();
1791 let json = serde_json::to_string(&event).unwrap();
1792
1793 assert!(json.contains("\"messageId\""));
1794 assert!(json.contains("\"delta\":\"Hello, world!\""));
1795 }
1796
1797 #[test]
1798 fn test_text_message_end_event() {
1799 use crate::types::MessageId;
1800
1801 let msg_id = MessageId::random();
1802 let event = TextMessageEndEvent::new(msg_id.clone());
1803
1804 let json = serde_json::to_string(&event).unwrap();
1805 assert!(json.contains("\"messageId\""));
1806 }
1807
1808 #[test]
1809 fn test_text_message_chunk_event() {
1810 use crate::types::{MessageId, Role};
1811
1812 let event = TextMessageChunkEvent::new(Role::Assistant)
1813 .with_message_id(MessageId::random())
1814 .with_delta("chunk content");
1815
1816 assert!(event.message_id.is_some());
1817 assert_eq!(event.delta, Some("chunk content".to_string()));
1818
1819 let json = serde_json::to_string(&event).unwrap();
1820 assert!(json.contains("\"messageId\""));
1821 assert!(json.contains("\"delta\":\"chunk content\""));
1822 }
1823
1824 #[test]
1825 fn test_text_message_chunk_event_skips_none() {
1826 use crate::types::Role;
1827
1828 let event = TextMessageChunkEvent::new(Role::Assistant);
1829 let json = serde_json::to_string(&event).unwrap();
1830
1831 assert!(!json.contains("\"messageId\""));
1833 assert!(!json.contains("\"delta\""));
1834 assert!(json.contains("\"role\":\"assistant\""));
1835 }
1836
1837 #[test]
1842 fn test_thinking_text_message_start_event() {
1843 let event = ThinkingTextMessageStartEvent::new();
1844 let json = serde_json::to_string(&event).unwrap();
1845
1846 assert_eq!(json, "{}");
1848 }
1849
1850 #[test]
1851 fn test_thinking_text_message_start_event_with_timestamp() {
1852 let event = ThinkingTextMessageStartEvent::new().with_timestamp(1234567890.0);
1853 let json = serde_json::to_string(&event).unwrap();
1854
1855 assert!(json.contains("\"timestamp\":1234567890.0"));
1856 }
1857
1858 #[test]
1859 fn test_thinking_text_message_content_event() {
1860 let event = ThinkingTextMessageContentEvent::new("Let me think about this...");
1861
1862 assert_eq!(event.delta, "Let me think about this...");
1863
1864 let json = serde_json::to_string(&event).unwrap();
1865 assert!(json.contains("\"delta\":\"Let me think about this...\""));
1866 }
1867
1868 #[test]
1869 fn test_thinking_text_message_content_event_allows_empty() {
1870 let event = ThinkingTextMessageContentEvent::new("");
1872 assert_eq!(event.delta, "");
1873 }
1874
1875 #[test]
1876 fn test_thinking_text_message_end_event() {
1877 let event = ThinkingTextMessageEndEvent::new();
1878 let json = serde_json::to_string(&event).unwrap();
1879
1880 assert_eq!(json, "{}");
1882 }
1883
1884 #[test]
1885 fn test_thinking_text_message_events_default() {
1886 let start = ThinkingTextMessageStartEvent::default();
1887 let end = ThinkingTextMessageEndEvent::default();
1888
1889 assert!(start.base.timestamp.is_none());
1890 assert!(end.base.timestamp.is_none());
1891 }
1892
1893 #[test]
1898 fn test_tool_call_start_event() {
1899 use crate::types::ToolCallId;
1900
1901 let event = ToolCallStartEvent::new(ToolCallId::random(), "get_weather");
1902
1903 assert_eq!(event.tool_call_name, "get_weather");
1904 assert!(event.parent_message_id.is_none());
1905
1906 let json = serde_json::to_string(&event).unwrap();
1907 assert!(json.contains("\"toolCallId\""));
1908 assert!(json.contains("\"toolCallName\":\"get_weather\""));
1909 assert!(!json.contains("parentMessageId")); }
1911
1912 #[test]
1913 fn test_tool_call_start_event_with_parent() {
1914 use crate::types::{MessageId, ToolCallId};
1915
1916 let event = ToolCallStartEvent::new(ToolCallId::random(), "get_weather")
1917 .with_parent_message_id(MessageId::random());
1918
1919 assert!(event.parent_message_id.is_some());
1920
1921 let json = serde_json::to_string(&event).unwrap();
1922 assert!(json.contains("\"parentMessageId\""));
1923 }
1924
1925 #[test]
1926 fn test_tool_call_args_event() {
1927 use crate::types::ToolCallId;
1928
1929 let event = ToolCallArgsEvent::new(ToolCallId::random(), r#"{"location":"#);
1930
1931 assert_eq!(event.delta, r#"{"location":"#);
1932
1933 let json = serde_json::to_string(&event).unwrap();
1934 assert!(json.contains("\"toolCallId\""));
1935 assert!(json.contains("\"delta\""));
1936 }
1937
1938 #[test]
1939 fn test_tool_call_end_event() {
1940 use crate::types::ToolCallId;
1941
1942 let event = ToolCallEndEvent::new(ToolCallId::random());
1943
1944 let json = serde_json::to_string(&event).unwrap();
1945 assert!(json.contains("\"toolCallId\""));
1946 }
1947
1948 #[test]
1949 fn test_tool_call_chunk_event() {
1950 use crate::types::ToolCallId;
1951
1952 let event = ToolCallChunkEvent::new()
1953 .with_tool_call_id(ToolCallId::random())
1954 .with_tool_call_name("search")
1955 .with_delta(r#"{"query": "rust"}"#);
1956
1957 assert!(event.tool_call_id.is_some());
1958 assert_eq!(event.tool_call_name, Some("search".to_string()));
1959 assert!(event.delta.is_some());
1960
1961 let json = serde_json::to_string(&event).unwrap();
1962 assert!(json.contains("\"toolCallId\""));
1963 assert!(json.contains("\"toolCallName\":\"search\""));
1964 assert!(json.contains("\"delta\""));
1965 }
1966
1967 #[test]
1968 fn test_tool_call_chunk_event_skips_none() {
1969 let event = ToolCallChunkEvent::new();
1970 let json = serde_json::to_string(&event).unwrap();
1971
1972 assert_eq!(json, "{}");
1974 }
1975
1976 #[test]
1977 fn test_tool_call_result_event() {
1978 use crate::types::{MessageId, Role, ToolCallId};
1979
1980 let event = ToolCallResultEvent::new(
1981 MessageId::random(),
1982 ToolCallId::random(),
1983 r#"{"weather": "sunny", "temp": 72}"#,
1984 );
1985
1986 assert_eq!(event.role, Role::Tool);
1987 assert!(event.content.contains("sunny"));
1988
1989 let json = serde_json::to_string(&event).unwrap();
1990 assert!(json.contains("\"messageId\""));
1991 assert!(json.contains("\"toolCallId\""));
1992 assert!(json.contains("\"content\""));
1993 assert!(json.contains("\"role\":\"tool\""));
1994 }
1995
1996 #[test]
1997 fn test_tool_call_result_event_deserialize_default_role() {
1998 let json = r#"{"messageId":"550e8400-e29b-41d4-a716-446655440000","toolCallId":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","content":"result"}"#;
2000 let event: ToolCallResultEvent = serde_json::from_str(json).unwrap();
2001
2002 assert_eq!(event.role, Role::Tool);
2003 }
2004
2005 #[test]
2010 fn test_run_started_event() {
2011 use crate::types::{RunId, ThreadId};
2012
2013 let event = RunStartedEvent::new(ThreadId::random(), RunId::random());
2014
2015 let json = serde_json::to_string(&event).unwrap();
2016 assert!(json.contains("\"threadId\""));
2017 assert!(json.contains("\"runId\""));
2018 }
2019
2020 #[test]
2021 fn test_run_finished_event() {
2022 use crate::types::{RunId, ThreadId};
2023
2024 let event = RunFinishedEvent::new(ThreadId::random(), RunId::random());
2025
2026 assert!(event.result.is_none());
2027
2028 let json = serde_json::to_string(&event).unwrap();
2029 assert!(json.contains("\"threadId\""));
2030 assert!(json.contains("\"runId\""));
2031 assert!(!json.contains("\"result\"")); }
2033
2034 #[test]
2035 fn test_run_finished_event_with_result() {
2036 use crate::types::{RunId, ThreadId};
2037
2038 let event = RunFinishedEvent::new(ThreadId::random(), RunId::random())
2039 .with_result(serde_json::json!({"success": true}));
2040
2041 assert!(event.result.is_some());
2042
2043 let json = serde_json::to_string(&event).unwrap();
2044 assert!(json.contains("\"result\""));
2045 assert!(json.contains("\"success\":true"));
2046 }
2047
2048 #[test]
2049 fn test_run_error_event() {
2050 let event = RunErrorEvent::new("Connection timeout");
2051
2052 assert_eq!(event.message, "Connection timeout");
2053 assert!(event.code.is_none());
2054
2055 let json = serde_json::to_string(&event).unwrap();
2056 assert!(json.contains("\"message\":\"Connection timeout\""));
2057 assert!(!json.contains("\"code\"")); }
2059
2060 #[test]
2061 fn test_run_error_event_with_code() {
2062 let event = RunErrorEvent::new("Rate limit exceeded").with_code("RATE_LIMITED");
2063
2064 assert_eq!(event.code, Some("RATE_LIMITED".to_string()));
2065
2066 let json = serde_json::to_string(&event).unwrap();
2067 assert!(json.contains("\"code\":\"RATE_LIMITED\""));
2068 }
2069
2070 #[test]
2075 fn test_run_finished_outcome_serialization() {
2076 let success = RunFinishedOutcome::Success;
2078 let interrupt = RunFinishedOutcome::Interrupt;
2079
2080 let success_json = serde_json::to_string(&success).unwrap();
2081 let interrupt_json = serde_json::to_string(&interrupt).unwrap();
2082
2083 assert_eq!(success_json, "\"SUCCESS\"");
2084 assert_eq!(interrupt_json, "\"INTERRUPT\"");
2085
2086 let deserialized: RunFinishedOutcome = serde_json::from_str("\"SUCCESS\"").unwrap();
2088 assert_eq!(deserialized, RunFinishedOutcome::Success);
2089
2090 let deserialized: RunFinishedOutcome = serde_json::from_str("\"INTERRUPT\"").unwrap();
2091 assert_eq!(deserialized, RunFinishedOutcome::Interrupt);
2092 }
2093
2094 #[test]
2095 fn test_run_finished_outcome_default() {
2096 let outcome = RunFinishedOutcome::default();
2097 assert_eq!(outcome, RunFinishedOutcome::Success);
2098 }
2099
2100 #[test]
2101 fn test_interrupt_info_empty() {
2102 let info = InterruptInfo::new();
2103
2104 assert!(info.id.is_none());
2105 assert!(info.reason.is_none());
2106 assert!(info.payload.is_none());
2107
2108 let json = serde_json::to_string(&info).unwrap();
2110 assert_eq!(json, "{}");
2111 }
2112
2113 #[test]
2114 fn test_interrupt_info_with_all_fields() {
2115 let info = InterruptInfo::new()
2116 .with_id("approval-001")
2117 .with_reason("human_approval")
2118 .with_payload(serde_json::json!({"action": "delete", "rows": 42}));
2119
2120 assert_eq!(info.id, Some("approval-001".to_string()));
2121 assert_eq!(info.reason, Some("human_approval".to_string()));
2122 assert!(info.payload.is_some());
2123
2124 let json = serde_json::to_string(&info).unwrap();
2125 assert!(json.contains("\"id\":\"approval-001\""));
2126 assert!(json.contains("\"reason\":\"human_approval\""));
2127 assert!(json.contains("\"action\":\"delete\""));
2128 }
2129
2130 #[test]
2131 fn test_run_finished_event_with_interrupt() {
2132 use crate::types::{RunId, ThreadId};
2133
2134 let event = RunFinishedEvent::new(ThreadId::random(), RunId::random())
2135 .with_interrupt(
2136 InterruptInfo::new()
2137 .with_reason("human_approval")
2138 .with_payload(serde_json::json!({"proposal": "send email"}))
2139 );
2140
2141 assert_eq!(event.outcome, Some(RunFinishedOutcome::Interrupt));
2143 assert!(event.interrupt.is_some());
2144 assert!(event.result.is_none());
2145
2146 let json = serde_json::to_string(&event).unwrap();
2147 assert!(json.contains("\"outcome\":\"INTERRUPT\""));
2148 assert!(json.contains("\"interrupt\""));
2149 assert!(json.contains("\"reason\":\"human_approval\""));
2150 }
2151
2152 #[test]
2153 fn test_run_finished_event_backward_compatibility() {
2154 use crate::types::{RunId, ThreadId};
2155
2156 let event = RunFinishedEvent::new(ThreadId::random(), RunId::random())
2158 .with_result(serde_json::json!({"done": true}));
2159
2160 assert!(event.outcome.is_none());
2162 assert!(event.interrupt.is_none());
2163
2164 assert_eq!(event.effective_outcome(), RunFinishedOutcome::Success);
2166
2167 let json = serde_json::to_string(&event).unwrap();
2168 assert!(!json.contains("\"outcome\"")); }
2170
2171 #[test]
2172 fn test_run_finished_event_effective_outcome() {
2173 use crate::types::{RunId, ThreadId};
2174
2175 let event1 = RunFinishedEvent::new(ThreadId::random(), RunId::random());
2177 assert_eq!(event1.effective_outcome(), RunFinishedOutcome::Success);
2178
2179 let mut event2 = RunFinishedEvent::new(ThreadId::random(), RunId::random());
2181 event2.interrupt = Some(InterruptInfo::new());
2182 assert_eq!(event2.effective_outcome(), RunFinishedOutcome::Interrupt);
2183
2184 let event3 = RunFinishedEvent::new(ThreadId::random(), RunId::random())
2186 .with_outcome(RunFinishedOutcome::Interrupt);
2187 assert_eq!(event3.effective_outcome(), RunFinishedOutcome::Interrupt);
2188 }
2189
2190 #[test]
2195 fn test_step_started_event() {
2196 let event = StepStartedEvent::new("process_input");
2197
2198 assert_eq!(event.step_name, "process_input");
2199
2200 let json = serde_json::to_string(&event).unwrap();
2201 assert!(json.contains("\"stepName\":\"process_input\""));
2202 }
2203
2204 #[test]
2205 fn test_step_finished_event() {
2206 let event = StepFinishedEvent::new("generate_response");
2207
2208 assert_eq!(event.step_name, "generate_response");
2209
2210 let json = serde_json::to_string(&event).unwrap();
2211 assert!(json.contains("\"stepName\":\"generate_response\""));
2212 }
2213
2214 #[test]
2215 fn test_step_events_with_timestamp() {
2216 let start = StepStartedEvent::new("step1").with_timestamp(1234567890.0);
2217 let end = StepFinishedEvent::new("step1").with_timestamp(1234567891.0);
2218
2219 assert_eq!(start.base.timestamp, Some(1234567890.0));
2220 assert_eq!(end.base.timestamp, Some(1234567891.0));
2221 }
2222
2223 #[test]
2228 fn test_state_snapshot_event() {
2229 let event = StateSnapshotEvent::new(serde_json::json!({"count": 42}));
2230
2231 let json = serde_json::to_string(&event).unwrap();
2232 assert!(json.contains("\"snapshot\""));
2233 assert!(json.contains("\"count\":42"));
2234 }
2235
2236 #[test]
2237 fn test_state_snapshot_event_default() {
2238 let event: StateSnapshotEvent<()> = StateSnapshotEvent::default();
2239 assert!(event.base.timestamp.is_none());
2240 }
2241
2242 #[test]
2243 fn test_state_delta_event() {
2244 let patches = vec![
2245 serde_json::json!({"op": "replace", "path": "/count", "value": 43}),
2246 serde_json::json!({"op": "add", "path": "/new_field", "value": "hello"}),
2247 ];
2248 let event = StateDeltaEvent::new(patches);
2249
2250 assert_eq!(event.delta.len(), 2);
2251
2252 let json = serde_json::to_string(&event).unwrap();
2253 assert!(json.contains("\"delta\""));
2254 assert!(json.contains("\"op\":\"replace\""));
2255 }
2256
2257 #[test]
2258 fn test_state_delta_event_default() {
2259 let event = StateDeltaEvent::default();
2260 assert!(event.delta.is_empty());
2261 }
2262
2263 #[test]
2264 fn test_messages_snapshot_event() {
2265 use crate::types::{Message, MessageId};
2266
2267 let messages = vec![
2268 Message::User {
2269 id: MessageId::random(),
2270 content: "Hello".to_string(),
2271 name: None,
2272 },
2273 Message::Assistant {
2274 id: MessageId::random(),
2275 content: Some("Hi there!".to_string()),
2276 name: None,
2277 tool_calls: None,
2278 },
2279 ];
2280 let event = MessagesSnapshotEvent::new(messages);
2281
2282 assert_eq!(event.messages.len(), 2);
2283
2284 let json = serde_json::to_string(&event).unwrap();
2285 assert!(json.contains("\"messages\""));
2286 }
2287
2288 #[test]
2289 fn test_messages_snapshot_event_default() {
2290 let event = MessagesSnapshotEvent::default();
2291 assert!(event.messages.is_empty());
2292 }
2293
2294 #[test]
2299 fn test_thinking_start_event() {
2300 let event = ThinkingStartEvent::new();
2301
2302 assert!(event.title.is_none());
2303
2304 let json = serde_json::to_string(&event).unwrap();
2305 assert!(!json.contains("\"title\"")); }
2307
2308 #[test]
2309 fn test_thinking_start_event_with_title() {
2310 let event = ThinkingStartEvent::new().with_title("Analyzing query");
2311
2312 assert_eq!(event.title, Some("Analyzing query".to_string()));
2313
2314 let json = serde_json::to_string(&event).unwrap();
2315 assert!(json.contains("\"title\":\"Analyzing query\""));
2316 }
2317
2318 #[test]
2319 fn test_thinking_end_event() {
2320 let event = ThinkingEndEvent::new();
2321
2322 let json = serde_json::to_string(&event).unwrap();
2323 assert_eq!(json, "{}");
2324 }
2325
2326 #[test]
2327 fn test_thinking_step_events_default() {
2328 let start = ThinkingStartEvent::default();
2329 let end = ThinkingEndEvent::default();
2330
2331 assert!(start.title.is_none());
2332 assert!(end.base.timestamp.is_none());
2333 }
2334
2335 #[test]
2340 fn test_raw_event() {
2341 let event = RawEvent::new(serde_json::json!({"provider_data": "openai"}));
2342
2343 assert!(event.source.is_none());
2344
2345 let json = serde_json::to_string(&event).unwrap();
2346 assert!(json.contains("\"event\""));
2347 assert!(json.contains("\"provider_data\":\"openai\""));
2348 assert!(!json.contains("\"source\"")); }
2350
2351 #[test]
2352 fn test_raw_event_with_source() {
2353 let event = RawEvent::new(serde_json::json!({})).with_source("anthropic");
2354
2355 assert_eq!(event.source, Some("anthropic".to_string()));
2356
2357 let json = serde_json::to_string(&event).unwrap();
2358 assert!(json.contains("\"source\":\"anthropic\""));
2359 }
2360
2361 #[test]
2362 fn test_custom_event() {
2363 let event = CustomEvent::new("user_action", serde_json::json!({"clicked": "button"}));
2364
2365 assert_eq!(event.name, "user_action");
2366
2367 let json = serde_json::to_string(&event).unwrap();
2368 assert!(json.contains("\"name\":\"user_action\""));
2369 assert!(json.contains("\"value\""));
2370 assert!(json.contains("\"clicked\":\"button\""));
2371 }
2372
2373 #[test]
2378 fn test_event_enum_serialization() {
2379 use crate::types::MessageId;
2380
2381 let event: Event = Event::TextMessageStart(TextMessageStartEvent::new(
2382 MessageId::random(),
2383 ));
2384
2385 let json = serde_json::to_string(&event).unwrap();
2386 assert!(json.contains("\"type\":\"TEXT_MESSAGE_START\""));
2387 assert!(json.contains("\"messageId\""));
2388 assert!(json.contains("\"role\":\"assistant\""));
2389 }
2390
2391 #[test]
2392 fn test_event_enum_deserialization() {
2393 let json = r#"{"type":"RUN_ERROR","message":"Test error"}"#;
2394 let event: Event = serde_json::from_str(json).unwrap();
2395
2396 match event {
2397 Event::RunError(e) => assert_eq!(e.message, "Test error"),
2398 _ => panic!("Expected RunError variant"),
2399 }
2400 }
2401
2402 #[test]
2403 fn test_event_type_method() {
2404 use crate::types::MessageId;
2405
2406 let event: Event = Event::TextMessageEnd(TextMessageEndEvent::new(MessageId::random()));
2407 assert_eq!(event.event_type(), EventType::TextMessageEnd);
2408
2409 let event: Event = Event::RunStarted(RunStartedEvent::new(
2410 crate::types::ThreadId::random(),
2411 crate::types::RunId::random(),
2412 ));
2413 assert_eq!(event.event_type(), EventType::RunStarted);
2414
2415 let event: Event = Event::Custom(CustomEvent::new("test", serde_json::json!({})));
2416 assert_eq!(event.event_type(), EventType::Custom);
2417 }
2418
2419 #[test]
2420 fn test_event_timestamp_method() {
2421 use crate::types::MessageId;
2422
2423 let event: Event = Event::TextMessageStart(
2424 TextMessageStartEvent::new(MessageId::random())
2425 .with_timestamp(1234567890.0),
2426 );
2427 assert_eq!(event.timestamp(), Some(1234567890.0));
2428
2429 let event: Event = Event::ThinkingEnd(ThinkingEndEvent::new());
2430 assert_eq!(event.timestamp(), None);
2431 }
2432
2433 #[test]
2434 fn test_event_all_variants_serialize() {
2435 use crate::types::{Message, MessageId, RunId, ThreadId, ToolCallId};
2436
2437 let events: Vec<Event> = vec![
2439 Event::TextMessageStart(TextMessageStartEvent::new(MessageId::random())),
2440 Event::TextMessageContent(TextMessageContentEvent::new_unchecked(MessageId::random(), "Hello")),
2441 Event::TextMessageEnd(TextMessageEndEvent::new(MessageId::random())),
2442 Event::TextMessageChunk(TextMessageChunkEvent::new(Role::Assistant).with_delta("Hi")),
2443 Event::ThinkingTextMessageStart(ThinkingTextMessageStartEvent::new()),
2444 Event::ThinkingTextMessageContent(ThinkingTextMessageContentEvent::new("thinking...")),
2445 Event::ThinkingTextMessageEnd(ThinkingTextMessageEndEvent::new()),
2446 Event::ToolCallStart(ToolCallStartEvent::new(ToolCallId::random(), "test_tool")),
2447 Event::ToolCallArgs(ToolCallArgsEvent::new(ToolCallId::random(), "{}")),
2448 Event::ToolCallEnd(ToolCallEndEvent::new(ToolCallId::random())),
2449 Event::ToolCallChunk(ToolCallChunkEvent::new()),
2450 Event::ToolCallResult(ToolCallResultEvent::new(MessageId::random(), ToolCallId::random(), "result")),
2451 Event::ThinkingStart(ThinkingStartEvent::new()),
2452 Event::ThinkingEnd(ThinkingEndEvent::new()),
2453 Event::StateSnapshot(StateSnapshotEvent::new(serde_json::json!({}))),
2454 Event::StateDelta(StateDeltaEvent::new(vec![])),
2455 Event::MessagesSnapshot(MessagesSnapshotEvent::new(vec![Message::Assistant {
2456 id: MessageId::random(),
2457 content: Some("Hi".to_string()),
2458 name: None,
2459 tool_calls: None,
2460 }])),
2461 Event::ActivitySnapshot(ActivitySnapshotEvent::new(MessageId::random(), "PLAN", serde_json::json!({"steps": []}))),
2462 Event::ActivityDelta(ActivityDeltaEvent::new(MessageId::random(), "PLAN", vec![serde_json::json!({"op": "add", "path": "/steps/-", "value": "test"})])),
2463 Event::Raw(RawEvent::new(serde_json::json!({}))),
2464 Event::Custom(CustomEvent::new("test", serde_json::json!({}))),
2465 Event::RunStarted(RunStartedEvent::new(ThreadId::random(), RunId::random())),
2466 Event::RunFinished(RunFinishedEvent::new(ThreadId::random(), RunId::random())),
2467 Event::RunError(RunErrorEvent::new("error")),
2468 Event::StepStarted(StepStartedEvent::new("step")),
2469 Event::StepFinished(StepFinishedEvent::new("step")),
2470 ];
2471
2472 for event in events {
2473 let json = serde_json::to_string(&event).unwrap();
2474 assert!(json.contains("\"type\":"));
2475
2476 let deserialized: Event = serde_json::from_str(&json).unwrap();
2478 assert_eq!(event.event_type(), deserialized.event_type());
2479 }
2480 }
2481}