strands_agents/event_loop/
mod.rs

1//! Event loop types for agent execution.
2//!
3//! This module defines the event types that are emitted during agent execution,
4//! providing a structured way to observe different events in the event loop and
5//! agent lifecycle.
6
7mod recover_max_tokens;
8
9pub use recover_max_tokens::recover_message_on_max_tokens_reached;
10
11use std::any::Any;
12use std::collections::HashMap;
13
14use crate::agent::AgentResult;
15use crate::hooks::Interrupt;
16use crate::telemetry::EventLoopMetrics;
17use crate::types::citations::Citation;
18use crate::types::content::Message;
19use crate::types::streaming::{ContentBlockDelta, Metrics, StopReason, StreamEvent, Usage};
20use crate::types::tools::{ToolResult as ToolResultType, ToolUse};
21
22/// Base trait for typed events.
23pub trait TypedEventBase: Send + Sync + std::fmt::Debug {
24    /// Whether this event should trigger the callback_handler.
25    fn is_callback_event(&self) -> bool {
26        true
27    }
28
29    /// Convert to a raw dictionary for emitting purposes.
30    fn as_dict(&self) -> HashMap<String, serde_json::Value>;
31
32    /// Prepare the event for emission by adding invocation state.
33    fn prepare(&mut self, _invocation_state: &HashMap<String, serde_json::Value>) {}
34
35    /// Returns the event as Any for downcasting.
36    fn as_any(&self) -> &dyn Any;
37}
38
39/// Event emitted at the very beginning of agent execution.
40#[derive(Debug, Clone, Default)]
41pub struct InitEventLoopEvent {
42    pub state: HashMap<String, serde_json::Value>,
43}
44
45impl InitEventLoopEvent {
46    pub fn new() -> Self {
47        Self {
48            state: HashMap::new(),
49        }
50    }
51}
52
53impl TypedEventBase for InitEventLoopEvent {
54    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
55        let mut map = HashMap::new();
56        map.insert("init_event_loop".to_string(), serde_json::Value::Bool(true));
57        map.extend(self.state.clone());
58        map
59    }
60
61    fn prepare(&mut self, invocation_state: &HashMap<String, serde_json::Value>) {
62        self.state.extend(invocation_state.clone());
63    }
64
65    fn as_any(&self) -> &dyn Any {
66        self
67    }
68}
69
70/// Event emitted at the start of each event loop cycle (deprecated, use StartEventLoopEvent).
71#[derive(Debug, Clone, Default)]
72pub struct StartEvent;
73
74impl TypedEventBase for StartEvent {
75    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
76        let mut map = HashMap::new();
77        map.insert("start".to_string(), serde_json::Value::Bool(true));
78        map
79    }
80
81    fn as_any(&self) -> &dyn Any {
82        self
83    }
84}
85
86/// Event emitted when the event loop cycle begins processing.
87#[derive(Debug, Clone, Default)]
88pub struct StartEventLoopEvent;
89
90impl TypedEventBase for StartEventLoopEvent {
91    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
92        let mut map = HashMap::new();
93        map.insert("start_event_loop".to_string(), serde_json::Value::Bool(true));
94        map
95    }
96
97    fn as_any(&self) -> &dyn Any {
98        self
99    }
100}
101
102/// Event emitted during model response streaming for each raw chunk.
103#[derive(Debug, Clone)]
104pub struct ModelStreamChunkEvent {
105    pub chunk: StreamEvent,
106}
107
108impl ModelStreamChunkEvent {
109    pub fn new(chunk: StreamEvent) -> Self {
110        Self { chunk }
111    }
112}
113
114impl TypedEventBase for ModelStreamChunkEvent {
115    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
116        let mut map = HashMap::new();
117        map.insert(
118            "event".to_string(),
119            serde_json::to_value(&self.chunk).unwrap_or_default(),
120        );
121        map
122    }
123
124    fn as_any(&self) -> &dyn Any {
125        self
126    }
127}
128
129/// Event emitted during model response streaming.
130#[derive(Debug, Clone, Default)]
131pub struct ModelStreamEvent {
132    pub delta_data: HashMap<String, serde_json::Value>,
133}
134
135impl ModelStreamEvent {
136    pub fn new(delta_data: HashMap<String, serde_json::Value>) -> Self {
137        Self { delta_data }
138    }
139}
140
141impl TypedEventBase for ModelStreamEvent {
142    fn is_callback_event(&self) -> bool {
143        !self.delta_data.is_empty()
144    }
145
146    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
147        self.delta_data.clone()
148    }
149
150    fn prepare(&mut self, invocation_state: &HashMap<String, serde_json::Value>) {
151        if self.delta_data.contains_key("delta") {
152            self.delta_data.extend(invocation_state.clone());
153        }
154    }
155
156    fn as_any(&self) -> &dyn Any {
157        self
158    }
159}
160
161/// Event emitted during tool use input streaming.
162#[derive(Debug, Clone)]
163pub struct ToolUseStreamEvent {
164    pub delta: ContentBlockDelta,
165    pub current_tool_use: HashMap<String, serde_json::Value>,
166}
167
168impl ToolUseStreamEvent {
169    pub fn new(delta: ContentBlockDelta, current_tool_use: HashMap<String, serde_json::Value>) -> Self {
170        Self { delta, current_tool_use }
171    }
172}
173
174impl TypedEventBase for ToolUseStreamEvent {
175    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
176        let mut map = HashMap::new();
177        map.insert("type".to_string(), serde_json::Value::String("tool_use_stream".to_string()));
178        map.insert("delta".to_string(), serde_json::to_value(&self.delta).unwrap_or_default());
179        map.insert("current_tool_use".to_string(), serde_json::to_value(&self.current_tool_use).unwrap_or_default());
180        map
181    }
182
183    fn as_any(&self) -> &dyn Any {
184        self
185    }
186}
187
188/// Event emitted during text content streaming.
189#[derive(Debug, Clone)]
190pub struct TextStreamEvent {
191    pub delta: ContentBlockDelta,
192    pub text: String,
193}
194
195impl TextStreamEvent {
196    pub fn new(delta: ContentBlockDelta, text: impl Into<String>) -> Self {
197        Self { delta, text: text.into() }
198    }
199}
200
201impl TypedEventBase for TextStreamEvent {
202    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
203        let mut map = HashMap::new();
204        map.insert("data".to_string(), serde_json::Value::String(self.text.clone()));
205        map.insert("delta".to_string(), serde_json::to_value(&self.delta).unwrap_or_default());
206        map
207    }
208
209    fn as_any(&self) -> &dyn Any {
210        self
211    }
212}
213
214/// Event emitted during citation streaming.
215#[derive(Debug, Clone)]
216pub struct CitationStreamEvent {
217    pub delta: ContentBlockDelta,
218    pub citation: Citation,
219}
220
221impl CitationStreamEvent {
222    pub fn new(delta: ContentBlockDelta, citation: Citation) -> Self {
223        Self { delta, citation }
224    }
225}
226
227impl TypedEventBase for CitationStreamEvent {
228    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
229        let mut map = HashMap::new();
230        map.insert("citation".to_string(), serde_json::to_value(&self.citation).unwrap_or_default());
231        map.insert("delta".to_string(), serde_json::to_value(&self.delta).unwrap_or_default());
232        map
233    }
234
235    fn as_any(&self) -> &dyn Any {
236        self
237    }
238}
239
240/// Event emitted during reasoning text streaming.
241#[derive(Debug, Clone)]
242pub struct ReasoningTextStreamEvent {
243    pub delta: ContentBlockDelta,
244    pub reasoning_text: Option<String>,
245}
246
247impl ReasoningTextStreamEvent {
248    pub fn new(delta: ContentBlockDelta, reasoning_text: Option<String>) -> Self {
249        Self { delta, reasoning_text }
250    }
251}
252
253impl TypedEventBase for ReasoningTextStreamEvent {
254    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
255        let mut map = HashMap::new();
256        map.insert("reasoningText".to_string(), serde_json::to_value(&self.reasoning_text).unwrap_or_default());
257        map.insert("delta".to_string(), serde_json::to_value(&self.delta).unwrap_or_default());
258        map.insert("reasoning".to_string(), serde_json::Value::Bool(true));
259        map
260    }
261
262    fn as_any(&self) -> &dyn Any {
263        self
264    }
265}
266
267/// Event emitted during redacted content streaming.
268#[derive(Debug, Clone)]
269pub struct ReasoningRedactedContentStreamEvent {
270    pub delta: ContentBlockDelta,
271    pub redacted_content: Option<Vec<u8>>,
272}
273
274impl ReasoningRedactedContentStreamEvent {
275    pub fn new(delta: ContentBlockDelta, redacted_content: Option<Vec<u8>>) -> Self {
276        Self { delta, redacted_content }
277    }
278}
279
280impl TypedEventBase for ReasoningRedactedContentStreamEvent {
281    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
282        let mut map = HashMap::new();
283        map.insert("reasoningRedactedContent".to_string(), serde_json::to_value(&self.redacted_content).unwrap_or_default());
284        map.insert("delta".to_string(), serde_json::to_value(&self.delta).unwrap_or_default());
285        map.insert("reasoning".to_string(), serde_json::Value::Bool(true));
286        map
287    }
288
289    fn as_any(&self) -> &dyn Any {
290        self
291    }
292}
293
294/// Event emitted during reasoning signature streaming.
295#[derive(Debug, Clone)]
296pub struct ReasoningSignatureStreamEvent {
297    pub delta: ContentBlockDelta,
298    pub reasoning_signature: Option<String>,
299}
300
301impl ReasoningSignatureStreamEvent {
302    pub fn new(delta: ContentBlockDelta, reasoning_signature: Option<String>) -> Self {
303        Self { delta, reasoning_signature }
304    }
305}
306
307impl TypedEventBase for ReasoningSignatureStreamEvent {
308    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
309        let mut map = HashMap::new();
310        map.insert("reasoning_signature".to_string(), serde_json::to_value(&self.reasoning_signature).unwrap_or_default());
311        map.insert("delta".to_string(), serde_json::to_value(&self.delta).unwrap_or_default());
312        map.insert("reasoning".to_string(), serde_json::Value::Bool(true));
313        map
314    }
315
316    fn as_any(&self) -> &dyn Any {
317        self
318    }
319}
320
321/// Event emitted when model stops generating.
322#[derive(Debug, Clone)]
323pub struct ModelStopReasonEvent {
324    pub stop_reason: StopReason,
325    pub message: Message,
326    pub usage: Usage,
327    pub metrics: Metrics,
328}
329
330impl ModelStopReasonEvent {
331    pub fn new(stop_reason: StopReason, message: Message, usage: Usage, metrics: Metrics) -> Self {
332        Self { stop_reason, message, usage, metrics }
333    }
334}
335
336impl TypedEventBase for ModelStopReasonEvent {
337    fn is_callback_event(&self) -> bool {
338        false
339    }
340
341    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
342        let mut map = HashMap::new();
343        map.insert(
344            "stop".to_string(),
345            serde_json::json!([
346                self.stop_reason,
347                self.message,
348                self.usage,
349                self.metrics
350            ]),
351        );
352        map
353    }
354
355    fn as_any(&self) -> &dyn Any {
356        self
357    }
358}
359
360/// Event emitted when the agent execution completes normally.
361#[derive(Debug, Clone)]
362pub struct EventLoopStopEvent {
363    pub stop_reason: StopReason,
364    pub message: Message,
365    pub metrics: EventLoopMetrics,
366    pub request_state: serde_json::Value,
367    pub interrupts: Option<Vec<Interrupt>>,
368    pub structured_output: Option<serde_json::Value>,
369}
370
371impl EventLoopStopEvent {
372    pub fn new(
373        stop_reason: StopReason,
374        message: Message,
375        metrics: EventLoopMetrics,
376        request_state: serde_json::Value,
377    ) -> Self {
378        Self {
379            stop_reason,
380            message,
381            metrics,
382            request_state,
383            interrupts: None,
384            structured_output: None,
385        }
386    }
387
388    pub fn with_interrupts(mut self, interrupts: Vec<Interrupt>) -> Self {
389        self.interrupts = Some(interrupts);
390        self
391    }
392
393    pub fn with_structured_output(mut self, output: serde_json::Value) -> Self {
394        self.structured_output = Some(output);
395        self
396    }
397
398    fn interrupts_to_json(&self) -> serde_json::Value {
399        match &self.interrupts {
400            Some(interrupts) => serde_json::Value::Array(
401                interrupts
402                    .iter()
403                    .map(|i| {
404                        serde_json::json!({
405                            "id": i.id,
406                            "name": i.name,
407                            "reason": i.reason
408                        })
409                    })
410                    .collect(),
411            ),
412            None => serde_json::Value::Null,
413        }
414    }
415}
416
417impl TypedEventBase for EventLoopStopEvent {
418    fn is_callback_event(&self) -> bool {
419        false
420    }
421
422    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
423        let mut map = HashMap::new();
424        map.insert(
425            "stop".to_string(),
426            serde_json::json!([
427                self.stop_reason,
428                self.message,
429                self.metrics.get_summary(),
430                self.request_state,
431                self.interrupts_to_json(),
432                self.structured_output
433            ]),
434        );
435        map
436    }
437
438    fn as_any(&self) -> &dyn Any {
439        self
440    }
441}
442
443/// Event emitted when structured output is detected and processed.
444#[derive(Debug, Clone)]
445pub struct StructuredOutputEvent {
446    pub structured_output: serde_json::Value,
447}
448
449impl StructuredOutputEvent {
450    pub fn new(structured_output: serde_json::Value) -> Self {
451        Self { structured_output }
452    }
453}
454
455impl TypedEventBase for StructuredOutputEvent {
456    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
457        let mut map = HashMap::new();
458        map.insert("structured_output".to_string(), self.structured_output.clone());
459        map
460    }
461
462    fn as_any(&self) -> &dyn Any {
463        self
464    }
465}
466
467/// Event emitted when the event loop is throttled due to rate limiting.
468#[derive(Debug, Clone)]
469pub struct EventLoopThrottleEvent {
470    pub delay: u32,
471    pub state: HashMap<String, serde_json::Value>,
472}
473
474impl EventLoopThrottleEvent {
475    pub fn new(delay: u32) -> Self {
476        Self {
477            delay,
478            state: HashMap::new(),
479        }
480    }
481}
482
483impl TypedEventBase for EventLoopThrottleEvent {
484    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
485        let mut map = HashMap::new();
486        map.insert("event_loop_throttled_delay".to_string(), serde_json::Value::Number(self.delay.into()));
487        map.extend(self.state.clone());
488        map
489    }
490
491    fn prepare(&mut self, invocation_state: &HashMap<String, serde_json::Value>) {
492        self.state.extend(invocation_state.clone());
493    }
494
495    fn as_any(&self) -> &dyn Any {
496        self
497    }
498}
499
500/// Event emitted when a tool execution completes.
501#[derive(Debug, Clone)]
502pub struct ToolResultEvent {
503    pub tool_result: ToolResultType,
504}
505
506impl ToolResultEvent {
507    pub fn new(tool_result: ToolResultType) -> Self {
508        Self { tool_result }
509    }
510
511    pub fn tool_use_id(&self) -> &str {
512        &self.tool_result.tool_use_id
513    }
514}
515
516impl TypedEventBase for ToolResultEvent {
517    fn is_callback_event(&self) -> bool {
518        false
519    }
520
521    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
522        let mut map = HashMap::new();
523        map.insert("type".to_string(), serde_json::Value::String("tool_result".to_string()));
524        map.insert("tool_result".to_string(), serde_json::to_value(&self.tool_result).unwrap_or_default());
525        map
526    }
527
528    fn as_any(&self) -> &dyn Any {
529        self
530    }
531}
532
533/// Event emitted when a tool yields sub-events during execution.
534#[derive(Debug, Clone)]
535pub struct ToolStreamEvent {
536    pub tool_use: ToolUse,
537    pub tool_stream_data: serde_json::Value,
538}
539
540impl ToolStreamEvent {
541    pub fn new(tool_use: ToolUse, tool_stream_data: serde_json::Value) -> Self {
542        Self { tool_use, tool_stream_data }
543    }
544
545    pub fn tool_use_id(&self) -> &str {
546        &self.tool_use.tool_use_id
547    }
548}
549
550impl TypedEventBase for ToolStreamEvent {
551    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
552        let mut map = HashMap::new();
553        map.insert("type".to_string(), serde_json::Value::String("tool_stream".to_string()));
554        map.insert(
555            "tool_stream_event".to_string(),
556            serde_json::json!({
557                "tool_use": self.tool_use,
558                "data": self.tool_stream_data
559            }),
560        );
561        map
562    }
563
564    fn as_any(&self) -> &dyn Any {
565        self
566    }
567}
568
569/// Event emitted when a tool call is cancelled.
570#[derive(Debug, Clone)]
571pub struct ToolCancelEvent {
572    pub tool_use: ToolUse,
573    pub message: String,
574}
575
576impl ToolCancelEvent {
577    pub fn new(tool_use: ToolUse, message: impl Into<String>) -> Self {
578        Self { tool_use, message: message.into() }
579    }
580
581    pub fn tool_use_id(&self) -> &str {
582        &self.tool_use.tool_use_id
583    }
584}
585
586impl TypedEventBase for ToolCancelEvent {
587    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
588        let mut map = HashMap::new();
589        map.insert(
590            "tool_cancel_event".to_string(),
591            serde_json::json!({
592                "tool_use": self.tool_use,
593                "message": self.message
594            }),
595        );
596        map
597    }
598
599    fn as_any(&self) -> &dyn Any {
600        self
601    }
602}
603
604/// Event emitted when a tool is interrupted.
605#[derive(Debug, Clone)]
606pub struct ToolInterruptEvent {
607    pub tool_use: ToolUse,
608    pub interrupts: Vec<Interrupt>,
609}
610
611impl ToolInterruptEvent {
612    pub fn new(tool_use: ToolUse, interrupts: Vec<Interrupt>) -> Self {
613        Self { tool_use, interrupts }
614    }
615
616    pub fn tool_use_id(&self) -> &str {
617        &self.tool_use.tool_use_id
618    }
619}
620
621impl TypedEventBase for ToolInterruptEvent {
622    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
623        let mut map = HashMap::new();
624        map.insert(
625            "tool_interrupt_event".to_string(),
626            serde_json::json!({
627                "tool_use": self.tool_use,
628                "interrupts": self.interrupts.iter().map(|i| {
629                    serde_json::json!({
630                        "id": i.id,
631                        "name": i.name,
632                        "reason": i.reason
633                    })
634                }).collect::<Vec<_>>()
635            }),
636        );
637        map
638    }
639
640    fn as_any(&self) -> &dyn Any {
641        self
642    }
643}
644
645/// Event emitted when the model invocation has completed.
646#[derive(Debug, Clone)]
647pub struct ModelMessageEvent {
648    pub message: Message,
649}
650
651impl ModelMessageEvent {
652    pub fn new(message: Message) -> Self {
653        Self { message }
654    }
655}
656
657impl TypedEventBase for ModelMessageEvent {
658    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
659        let mut map = HashMap::new();
660        map.insert("message".to_string(), serde_json::to_value(&self.message).unwrap_or_default());
661        map
662    }
663
664    fn as_any(&self) -> &dyn Any {
665        self
666    }
667}
668
669/// Event emitted when tool results are formatted as a message.
670#[derive(Debug, Clone)]
671pub struct ToolResultMessageEvent {
672    pub message: Message,
673}
674
675impl ToolResultMessageEvent {
676    pub fn new(message: Message) -> Self {
677        Self { message }
678    }
679}
680
681impl TypedEventBase for ToolResultMessageEvent {
682    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
683        let mut map = HashMap::new();
684        map.insert("message".to_string(), serde_json::to_value(&self.message).unwrap_or_default());
685        map
686    }
687
688    fn as_any(&self) -> &dyn Any {
689        self
690    }
691}
692
693/// Event emitted when the agent execution is forcibly stopped.
694#[derive(Debug, Clone)]
695pub struct ForceStopEvent {
696    pub reason: String,
697}
698
699impl ForceStopEvent {
700    pub fn new(reason: impl Into<String>) -> Self {
701        Self { reason: reason.into() }
702    }
703
704    pub fn from_error(err: &dyn std::error::Error) -> Self {
705        Self { reason: err.to_string() }
706    }
707}
708
709impl TypedEventBase for ForceStopEvent {
710    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
711        let mut map = HashMap::new();
712        map.insert("force_stop".to_string(), serde_json::Value::Bool(true));
713        map.insert("force_stop_reason".to_string(), serde_json::Value::String(self.reason.clone()));
714        map
715    }
716
717    fn as_any(&self) -> &dyn Any {
718        self
719    }
720}
721
722/// Event emitted when agent execution completes with a result.
723#[derive(Debug, Clone)]
724pub struct AgentResultEvent {
725    pub result: AgentResult,
726}
727
728impl AgentResultEvent {
729    pub fn new(result: AgentResult) -> Self {
730        Self { result }
731    }
732}
733
734impl TypedEventBase for AgentResultEvent {
735    fn as_dict(&self) -> HashMap<String, serde_json::Value> {
736        let mut map = HashMap::new();
737        map.insert("result".to_string(), serde_json::to_value(&self.result).unwrap_or_default());
738        map
739    }
740
741    fn as_any(&self) -> &dyn Any {
742        self
743    }
744}
745
746/// Unified typed event enum for backward compatibility.
747#[derive(Debug, Clone)]
748pub enum TypedEvent {
749    InitEventLoop(InitEventLoopEvent),
750    Start(StartEvent),
751    StartEventLoop(StartEventLoopEvent),
752    ModelStreamChunk(ModelStreamChunkEvent),
753    ModelStream(ModelStreamEvent),
754    ToolUseStream(ToolUseStreamEvent),
755    TextStream(TextStreamEvent),
756    CitationStream(CitationStreamEvent),
757    ReasoningTextStream(ReasoningTextStreamEvent),
758    ReasoningRedactedContentStream(ReasoningRedactedContentStreamEvent),
759    ReasoningSignatureStream(ReasoningSignatureStreamEvent),
760    ModelStopReason(ModelStopReasonEvent),
761    EventLoopStop(EventLoopStopEvent),
762    StructuredOutput(StructuredOutputEvent),
763    EventLoopThrottle(EventLoopThrottleEvent),
764    ToolResult(ToolResultEvent),
765    ToolStream(ToolStreamEvent),
766    ToolCancel(ToolCancelEvent),
767    ToolInterrupt(ToolInterruptEvent),
768    ModelMessage(ModelMessageEvent),
769    ToolResultMessage(ToolResultMessageEvent),
770    ForceStop(ForceStopEvent),
771    AgentResult(AgentResultEvent),
772}
773
774impl TypedEvent {
775    pub fn is_result(&self) -> bool {
776        matches!(self, Self::AgentResult(_) | Self::EventLoopStop(_))
777    }
778
779    pub fn as_result(&self) -> Option<&AgentResult> {
780        match self {
781            Self::AgentResult(e) => Some(&e.result),
782            _ => None,
783        }
784    }
785
786    pub fn as_model_message(&self) -> Option<&Message> {
787        match self {
788            Self::ModelMessage(e) => Some(&e.message),
789            _ => None,
790        }
791    }
792
793    pub fn as_text(&self) -> Option<String> {
794        match self {
795            Self::TextStream(e) => Some(e.text.clone()),
796            Self::ModelMessage(e) => Some(e.message.text_content()),
797            Self::AgentResult(e) => Some(e.result.text()),
798            _ => None,
799        }
800    }
801
802    pub fn as_text_delta(&self) -> Option<&str> {
803        match self {
804            Self::TextStream(e) => Some(&e.text),
805            Self::ModelStreamChunk(e) => e.chunk.as_text_delta(),
806            _ => None,
807        }
808    }
809
810    pub fn is_callback_event(&self) -> bool {
811        match self {
812            Self::InitEventLoop(e) => e.is_callback_event(),
813            Self::Start(e) => e.is_callback_event(),
814            Self::StartEventLoop(e) => e.is_callback_event(),
815            Self::ModelStreamChunk(e) => e.is_callback_event(),
816            Self::ModelStream(e) => e.is_callback_event(),
817            Self::ToolUseStream(e) => e.is_callback_event(),
818            Self::TextStream(e) => e.is_callback_event(),
819            Self::CitationStream(e) => e.is_callback_event(),
820            Self::ReasoningTextStream(e) => e.is_callback_event(),
821            Self::ReasoningRedactedContentStream(e) => e.is_callback_event(),
822            Self::ReasoningSignatureStream(e) => e.is_callback_event(),
823            Self::ModelStopReason(e) => e.is_callback_event(),
824            Self::EventLoopStop(e) => e.is_callback_event(),
825            Self::StructuredOutput(e) => e.is_callback_event(),
826            Self::EventLoopThrottle(e) => e.is_callback_event(),
827            Self::ToolResult(e) => e.is_callback_event(),
828            Self::ToolStream(e) => e.is_callback_event(),
829            Self::ToolCancel(e) => e.is_callback_event(),
830            Self::ToolInterrupt(e) => e.is_callback_event(),
831            Self::ModelMessage(e) => e.is_callback_event(),
832            Self::ToolResultMessage(e) => e.is_callback_event(),
833            Self::ForceStop(e) => e.is_callback_event(),
834            Self::AgentResult(e) => e.is_callback_event(),
835        }
836    }
837
838    pub fn as_dict(&self) -> HashMap<String, serde_json::Value> {
839        match self {
840            Self::InitEventLoop(e) => e.as_dict(),
841            Self::Start(e) => e.as_dict(),
842            Self::StartEventLoop(e) => e.as_dict(),
843            Self::ModelStreamChunk(e) => e.as_dict(),
844            Self::ModelStream(e) => e.as_dict(),
845            Self::ToolUseStream(e) => e.as_dict(),
846            Self::TextStream(e) => e.as_dict(),
847            Self::CitationStream(e) => e.as_dict(),
848            Self::ReasoningTextStream(e) => e.as_dict(),
849            Self::ReasoningRedactedContentStream(e) => e.as_dict(),
850            Self::ReasoningSignatureStream(e) => e.as_dict(),
851            Self::ModelStopReason(e) => e.as_dict(),
852            Self::EventLoopStop(e) => e.as_dict(),
853            Self::StructuredOutput(e) => e.as_dict(),
854            Self::EventLoopThrottle(e) => e.as_dict(),
855            Self::ToolResult(e) => e.as_dict(),
856            Self::ToolStream(e) => e.as_dict(),
857            Self::ToolCancel(e) => e.as_dict(),
858            Self::ToolInterrupt(e) => e.as_dict(),
859            Self::ModelMessage(e) => e.as_dict(),
860            Self::ToolResultMessage(e) => e.as_dict(),
861            Self::ForceStop(e) => e.as_dict(),
862            Self::AgentResult(e) => e.as_dict(),
863        }
864    }
865}
866
867impl TypedEvent {
868    pub fn init_event_loop() -> Self {
869        Self::InitEventLoop(InitEventLoopEvent::new())
870    }
871
872    pub fn start() -> Self {
873        Self::Start(StartEvent)
874    }
875
876    pub fn start_event_loop() -> Self {
877        Self::StartEventLoop(StartEventLoopEvent)
878    }
879
880    pub fn text_stream(delta: ContentBlockDelta, text: impl Into<String>) -> Self {
881        Self::TextStream(TextStreamEvent::new(delta, text))
882    }
883
884    pub fn model_message(message: Message) -> Self {
885        Self::ModelMessage(ModelMessageEvent::new(message))
886    }
887
888    pub fn tool_result(tool_result: ToolResultType) -> Self {
889        Self::ToolResult(ToolResultEvent::new(tool_result))
890    }
891
892    pub fn agent_result(result: AgentResult) -> Self {
893        Self::AgentResult(AgentResultEvent::new(result))
894    }
895
896    pub fn force_stop(reason: impl Into<String>) -> Self {
897        Self::ForceStop(ForceStopEvent::new(reason))
898    }
899
900    pub fn throttle(delay: u32) -> Self {
901        Self::EventLoopThrottle(EventLoopThrottleEvent::new(delay))
902    }
903}
904
905#[cfg(test)]
906mod tests {
907    use super::*;
908
909    #[test]
910    fn test_init_event_loop_event() {
911        let event = InitEventLoopEvent::new();
912        let dict = event.as_dict();
913        assert_eq!(dict.get("init_event_loop"), Some(&serde_json::Value::Bool(true)));
914    }
915
916    #[test]
917    fn test_start_event() {
918        let event = StartEvent;
919        let dict = event.as_dict();
920        assert_eq!(dict.get("start"), Some(&serde_json::Value::Bool(true)));
921    }
922
923    #[test]
924    fn test_force_stop_event() {
925        let event = ForceStopEvent::new("Test reason");
926        let dict = event.as_dict();
927        assert_eq!(dict.get("force_stop"), Some(&serde_json::Value::Bool(true)));
928        assert_eq!(dict.get("force_stop_reason"), Some(&serde_json::Value::String("Test reason".to_string())));
929    }
930
931    #[test]
932    fn test_typed_event_enum() {
933        let event = TypedEvent::start();
934        assert!(!event.is_result());
935
936        let event = TypedEvent::force_stop("error");
937        let dict = event.as_dict();
938        assert!(dict.contains_key("force_stop"));
939    }
940}