Skip to main content

ag_ui/event/
mod.rs

1//! The AG-UI event stream.
2//!
3//! An agent run is a sequence of these events. [`Event`] is the closed union of
4//! all of them, tagged on the wire by a `type` field holding a
5//! SCREAMING_SNAKE_CASE name:
6//!
7//! ```
8//! # use ag_ui::{Event, EventType};
9//! let event = Event::text_message_content("msg-1", "Hello");
10//! assert_eq!(event.event_type(), EventType::TextMessageContent);
11//! assert_eq!(
12//!     serde_json::to_string(&event).unwrap(),
13//!     r#"{"type":"TEXT_MESSAGE_CONTENT","messageId":"msg-1","delta":"Hello"}"#
14//! );
15//! ```
16//!
17//! Every event also carries the optional [`BaseEvent`] fields — a timestamp,
18//! the provider event it was translated from, and [`metadata`](crate::metadata)
19//! — flattened into the same JSON object. Most events additionally accept an
20//! optional `subagentRunId` saying which subagent produced them; see
21//! [`subagent`].
22
23// The THINKING_* events are deprecated but still part of the protocol, so this
24// module has to name them constantly — in the union, in `event_type()`, in the
25// factories. Downstream users still get the warnings; we just do not warn at
26// ourselves for implementing the spec as written.
27#![allow(deprecated)]
28
29pub mod activity;
30pub mod factories;
31pub mod lifecycle;
32pub mod reasoning;
33pub mod special;
34pub mod state;
35pub mod subagent;
36pub mod text;
37pub mod tool;
38
39use std::fmt;
40use std::str::FromStr;
41
42use serde::{Deserialize, Serialize};
43use serde_json::Value;
44
45use crate::JsonObject;
46use crate::error::{Error, Result};
47use crate::ids::SubagentRunId;
48
49pub use activity::{ActivityDeltaEvent, ActivitySnapshotEvent};
50pub use lifecycle::{
51    RunErrorEvent, RunFinishedEvent, RunStartedEvent, StepFinishedEvent, StepStartedEvent,
52};
53pub use reasoning::{
54    ReasoningEncryptedValueEvent, ReasoningEncryptedValueSubtype, ReasoningEndEvent,
55    ReasoningMessageChunkEvent, ReasoningMessageContentEvent, ReasoningMessageEndEvent,
56    ReasoningMessageStartEvent, ReasoningRole, ReasoningStartEvent, ThinkingEndEvent,
57    ThinkingStartEvent, ThinkingTextMessageContentEvent, ThinkingTextMessageEndEvent,
58    ThinkingTextMessageStartEvent,
59};
60pub use special::{CustomEvent, RawEvent};
61pub use state::{MessagesSnapshotEvent, StateDeltaEvent, StateSnapshotEvent};
62pub use subagent::{
63    SubagentErrorEvent, SubagentFinishedEvent, SubagentOutcome, SubagentStartedEvent,
64};
65pub use text::{
66    TextMessageChunkEvent, TextMessageContentEvent, TextMessageEndEvent, TextMessageRole,
67    TextMessageStartEvent,
68};
69pub use tool::{
70    ToolCallArgsEvent, ToolCallChunkEvent, ToolCallEndEvent, ToolCallResultEvent,
71    ToolCallStartEvent, ToolResultRole,
72};
73
74/// The fields every event may carry, flattened into the event's own JSON
75/// object rather than nested under a key.
76#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
77#[serde(rename_all = "camelCase")]
78#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
79#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
80pub struct BaseEvent {
81    /// When the event was produced, in milliseconds since the Unix epoch.
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub timestamp: Option<i64>,
84    /// The provider event this was translated from, for debugging.
85    #[serde(default, skip_serializing_if = "Option::is_none")]
86    pub raw_event: Option<Value>,
87    /// Extra information, open by key. Absent or an object — a JSON `null` in
88    /// place of the object is rejected. See [`crate::metadata`] for the
89    /// reserved key and how consumers merge it into messages.
90    #[serde(
91        default,
92        deserialize_with = "crate::serde_util::reject_null",
93        skip_serializing_if = "Option::is_none"
94    )]
95    #[cfg_attr(
96        feature = "schemars",
97        schemars(with = "Option<std::collections::BTreeMap<String, serde_json::Value>>")
98    )]
99    #[cfg_attr(feature = "utoipa", schema(value_type = Option<Object>))]
100    pub metadata: Option<JsonObject>,
101}
102
103impl BaseEvent {
104    /// An empty base — no timestamp, no raw event, no metadata.
105    pub fn new() -> Self {
106        Self::default()
107    }
108
109    /// Whether every field is absent, in which case the base contributes
110    /// nothing to the serialized event.
111    pub const fn is_empty(&self) -> bool {
112        self.timestamp.is_none() && self.raw_event.is_none() && self.metadata.is_none()
113    }
114}
115
116macro_rules! define_events {
117    ($(
118        $(#[$meta:meta])*
119        $variant:ident($payload:ty) => $tag:literal,
120    )*) => {
121        /// One event in an AG-UI stream.
122        ///
123        /// Serializes as the payload's fields plus a `type` discriminator, so
124        /// there is no nesting on the wire.
125        ///
126        /// # Exhaustive on purpose
127        ///
128        /// This enum is deliberately *not* `#[non_exhaustive]`, unlike every
129        /// error type in this workspace. A new protocol event **should** be a
130        /// compile error where you match on events: that is what a typed SDK
131        /// buys you over `serde_json::Value`, and the alternative — a `_` arm
132        /// in every consumer — is exactly how the previous Rust SDK came to be
133        /// missing eight event types without anyone noticing.
134        ///
135        /// The consequence is that adding an event is a major version of this
136        /// crate. That is the intended price; see `docs/DESIGN.md`.
137        #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
138        #[serde(tag = "type")]
139        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
140        #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
141        pub enum Event {
142            $(
143                $(#[$meta])*
144                #[serde(rename = $tag)]
145                $variant($payload),
146            )*
147        }
148
149        /// The `type` discriminator of an [`Event`], on its own.
150        ///
151        /// Useful for routing and filtering without matching the payload.
152        /// Exhaustive for the same reason [`Event`] is, and
153        /// [`EventType::ALL`] is the list, in upstream order.
154        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
155        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
156        #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
157        pub enum EventType {
158            $(
159                $(#[$meta])*
160                #[serde(rename = $tag)]
161                $variant,
162            )*
163        }
164
165        impl EventType {
166            /// Every event type the protocol defines, in upstream order.
167            pub const ALL: &'static [EventType] = &[$(EventType::$variant),*];
168
169            /// The wire string for this type.
170            pub const fn as_str(&self) -> &'static str {
171                match self {
172                    $(Self::$variant => $tag,)*
173                }
174            }
175        }
176
177        impl FromStr for EventType {
178            type Err = Error;
179
180            fn from_str(s: &str) -> Result<Self> {
181                match s {
182                    $($tag => Ok(Self::$variant),)*
183                    other => Err(Error::UnknownEventType(other.to_owned())),
184                }
185            }
186        }
187
188        impl Event {
189            /// The discriminator for this event.
190            pub const fn event_type(&self) -> EventType {
191                match self {
192                    $(Self::$variant(_) => EventType::$variant,)*
193                }
194            }
195
196            /// The timestamp and raw-event fields, whatever the variant.
197            pub const fn base(&self) -> &BaseEvent {
198                match self {
199                    $(Self::$variant(payload) => &payload.base,)*
200                }
201            }
202
203            /// Mutable access to the timestamp and raw-event fields.
204            pub const fn base_mut(&mut self) -> &mut BaseEvent {
205                match self {
206                    $(Self::$variant(payload) => &mut payload.base,)*
207                }
208            }
209        }
210
211        $(
212            impl From<$payload> for Event {
213                fn from(payload: $payload) -> Self {
214                    Self::$variant(payload)
215                }
216            }
217        )*
218    };
219}
220
221define_events! {
222    /// Opens a text message. See [`TextMessageStartEvent`].
223    TextMessageStart(TextMessageStartEvent) => "TEXT_MESSAGE_START",
224    /// Appends to a text message. See [`TextMessageContentEvent`].
225    TextMessageContent(TextMessageContentEvent) => "TEXT_MESSAGE_CONTENT",
226    /// Closes a text message. See [`TextMessageEndEvent`].
227    TextMessageEnd(TextMessageEndEvent) => "TEXT_MESSAGE_END",
228    /// A whole text update in one event. See [`TextMessageChunkEvent`].
229    TextMessageChunk(TextMessageChunkEvent) => "TEXT_MESSAGE_CHUNK",
230    /// Opens a tool call. See [`ToolCallStartEvent`].
231    ToolCallStart(ToolCallStartEvent) => "TOOL_CALL_START",
232    /// Appends tool-call arguments. See [`ToolCallArgsEvent`].
233    ToolCallArgs(ToolCallArgsEvent) => "TOOL_CALL_ARGS",
234    /// Closes a tool call. See [`ToolCallEndEvent`].
235    ToolCallEnd(ToolCallEndEvent) => "TOOL_CALL_END",
236    /// A whole tool call in one event. See [`ToolCallChunkEvent`].
237    ToolCallChunk(ToolCallChunkEvent) => "TOOL_CALL_CHUNK",
238    /// A tool call's result. See [`ToolCallResultEvent`].
239    ToolCallResult(ToolCallResultEvent) => "TOOL_CALL_RESULT",
240    /// Opens a thinking block. See [`ThinkingStartEvent`].
241    #[cfg_attr(not(feature = "utoipa"), deprecated(note = "use Event::ReasoningStart"))]
242    ThinkingStart(ThinkingStartEvent) => "THINKING_START",
243    /// Closes a thinking block. See [`ThinkingEndEvent`].
244    #[cfg_attr(not(feature = "utoipa"), deprecated(note = "use Event::ReasoningEnd"))]
245    ThinkingEnd(ThinkingEndEvent) => "THINKING_END",
246    /// Opens a thinking message. See [`ThinkingTextMessageStartEvent`].
247    #[cfg_attr(not(feature = "utoipa"), deprecated(note = "use Event::ReasoningMessageStart"))]
248    ThinkingTextMessageStart(ThinkingTextMessageStartEvent) => "THINKING_TEXT_MESSAGE_START",
249    /// Appends thinking text. See [`ThinkingTextMessageContentEvent`].
250    #[cfg_attr(not(feature = "utoipa"), deprecated(note = "use Event::ReasoningMessageContent"))]
251    ThinkingTextMessageContent(ThinkingTextMessageContentEvent) => "THINKING_TEXT_MESSAGE_CONTENT",
252    /// Closes a thinking message. See [`ThinkingTextMessageEndEvent`].
253    #[cfg_attr(not(feature = "utoipa"), deprecated(note = "use Event::ReasoningMessageEnd"))]
254    ThinkingTextMessageEnd(ThinkingTextMessageEndEvent) => "THINKING_TEXT_MESSAGE_END",
255    /// Replaces the shared state. See [`StateSnapshotEvent`].
256    StateSnapshot(StateSnapshotEvent) => "STATE_SNAPSHOT",
257    /// Patches the shared state. See [`StateDeltaEvent`].
258    StateDelta(StateDeltaEvent) => "STATE_DELTA",
259    /// Replaces the message history. See [`MessagesSnapshotEvent`].
260    MessagesSnapshot(MessagesSnapshotEvent) => "MESSAGES_SNAPSHOT",
261    /// Publishes an activity. See [`ActivitySnapshotEvent`].
262    ActivitySnapshot(ActivitySnapshotEvent) => "ACTIVITY_SNAPSHOT",
263    /// Patches an activity. See [`ActivityDeltaEvent`].
264    ActivityDelta(ActivityDeltaEvent) => "ACTIVITY_DELTA",
265    /// Forwards a provider event. See [`RawEvent`].
266    Raw(RawEvent) => "RAW",
267    /// An application-defined event. See [`CustomEvent`].
268    Custom(CustomEvent) => "CUSTOM",
269    /// Starts a run. See [`RunStartedEvent`].
270    RunStarted(RunStartedEvent) => "RUN_STARTED",
271    /// Finishes or pauses a run. See [`RunFinishedEvent`].
272    RunFinished(RunFinishedEvent) => "RUN_FINISHED",
273    /// Fails a run. See [`RunErrorEvent`].
274    RunError(RunErrorEvent) => "RUN_ERROR",
275    /// Starts a step. See [`StepStartedEvent`].
276    StepStarted(StepStartedEvent) => "STEP_STARTED",
277    /// Finishes a step. See [`StepFinishedEvent`].
278    StepFinished(StepFinishedEvent) => "STEP_FINISHED",
279    /// Opens a reasoning block. See [`ReasoningStartEvent`].
280    ReasoningStart(ReasoningStartEvent) => "REASONING_START",
281    /// Opens a reasoning message. See [`ReasoningMessageStartEvent`].
282    ReasoningMessageStart(ReasoningMessageStartEvent) => "REASONING_MESSAGE_START",
283    /// Appends reasoning text. See [`ReasoningMessageContentEvent`].
284    ReasoningMessageContent(ReasoningMessageContentEvent) => "REASONING_MESSAGE_CONTENT",
285    /// Closes a reasoning message. See [`ReasoningMessageEndEvent`].
286    ReasoningMessageEnd(ReasoningMessageEndEvent) => "REASONING_MESSAGE_END",
287    /// A whole reasoning update in one event. See [`ReasoningMessageChunkEvent`].
288    ReasoningMessageChunk(ReasoningMessageChunkEvent) => "REASONING_MESSAGE_CHUNK",
289    /// Closes a reasoning block. See [`ReasoningEndEvent`].
290    ReasoningEnd(ReasoningEndEvent) => "REASONING_END",
291    /// Carries an encrypted reasoning blob. See [`ReasoningEncryptedValueEvent`].
292    ReasoningEncryptedValue(ReasoningEncryptedValueEvent) => "REASONING_ENCRYPTED_VALUE",
293    /// Announces a subagent invocation. See [`SubagentStartedEvent`].
294    SubagentStarted(SubagentStartedEvent) => "SUBAGENT_STARTED",
295    /// Closes a subagent invocation. See [`SubagentFinishedEvent`].
296    SubagentFinished(SubagentFinishedEvent) => "SUBAGENT_FINISHED",
297    /// Fails a subagent invocation. See [`SubagentErrorEvent`].
298    SubagentError(SubagentErrorEvent) => "SUBAGENT_ERROR",
299}
300
301impl fmt::Display for EventType {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        f.write_str(self.as_str())
304    }
305}
306
307impl Event {
308    /// Stamps the event with a millisecond Unix timestamp.
309    #[must_use]
310    pub fn with_timestamp(mut self, timestamp: i64) -> Self {
311        self.base_mut().timestamp = Some(timestamp);
312        self
313    }
314
315    /// Attaches the provider event this was translated from.
316    #[must_use]
317    pub fn with_raw_event(mut self, raw_event: impl Into<Value>) -> Self {
318        self.base_mut().raw_event = Some(raw_event.into());
319        self
320    }
321
322    /// Attaches metadata, replacing any the event already carried. See
323    /// [`crate::metadata`].
324    #[must_use]
325    pub fn with_metadata(mut self, metadata: JsonObject) -> Self {
326        self.base_mut().metadata = Some(metadata);
327        self
328    }
329
330    /// The event's metadata, if it carries any.
331    pub const fn metadata(&self) -> Option<&JsonObject> {
332        self.base().metadata.as_ref()
333    }
334
335    /// Whether this event's type is deprecated in favour of a `REASONING_*`
336    /// one.
337    pub const fn is_deprecated(&self) -> bool {
338        matches!(
339            self.event_type(),
340            EventType::ThinkingStart
341                | EventType::ThinkingEnd
342                | EventType::ThinkingTextMessageStart
343                | EventType::ThinkingTextMessageContent
344                | EventType::ThinkingTextMessageEnd
345        )
346    }
347
348    // ---- subagent attribution ------------------------------------------
349
350    /// The `subagentRunId` slot of the 24 event types that carry attribution.
351    ///
352    /// Hand-written and exhaustive: a new variant has to be placed on one
353    /// side or the other here, which is the point.
354    fn attribution(&self) -> Option<&Option<SubagentRunId>> {
355        match self {
356            Self::TextMessageStart(e) => Some(&e.subagent_run_id),
357            Self::TextMessageContent(e) => Some(&e.subagent_run_id),
358            Self::TextMessageEnd(e) => Some(&e.subagent_run_id),
359            Self::TextMessageChunk(e) => Some(&e.subagent_run_id),
360            Self::ToolCallStart(e) => Some(&e.subagent_run_id),
361            Self::ToolCallArgs(e) => Some(&e.subagent_run_id),
362            Self::ToolCallEnd(e) => Some(&e.subagent_run_id),
363            Self::ToolCallChunk(e) => Some(&e.subagent_run_id),
364            Self::ToolCallResult(e) => Some(&e.subagent_run_id),
365            Self::StateSnapshot(e) => Some(&e.subagent_run_id),
366            Self::StateDelta(e) => Some(&e.subagent_run_id),
367            Self::ActivitySnapshot(e) => Some(&e.subagent_run_id),
368            Self::ActivityDelta(e) => Some(&e.subagent_run_id),
369            Self::Raw(e) => Some(&e.subagent_run_id),
370            Self::Custom(e) => Some(&e.subagent_run_id),
371            Self::StepStarted(e) => Some(&e.subagent_run_id),
372            Self::StepFinished(e) => Some(&e.subagent_run_id),
373            Self::ReasoningStart(e) => Some(&e.subagent_run_id),
374            Self::ReasoningMessageStart(e) => Some(&e.subagent_run_id),
375            Self::ReasoningMessageContent(e) => Some(&e.subagent_run_id),
376            Self::ReasoningMessageEnd(e) => Some(&e.subagent_run_id),
377            Self::ReasoningMessageChunk(e) => Some(&e.subagent_run_id),
378            Self::ReasoningEnd(e) => Some(&e.subagent_run_id),
379            Self::ReasoningEncryptedValue(e) => Some(&e.subagent_run_id),
380            Self::RunStarted(_)
381            | Self::RunFinished(_)
382            | Self::RunError(_)
383            | Self::MessagesSnapshot(_)
384            | Self::ThinkingStart(_)
385            | Self::ThinkingEnd(_)
386            | Self::ThinkingTextMessageStart(_)
387            | Self::ThinkingTextMessageContent(_)
388            | Self::ThinkingTextMessageEnd(_)
389            | Self::SubagentStarted(_)
390            | Self::SubagentFinished(_)
391            | Self::SubagentError(_) => None,
392        }
393    }
394
395    fn attribution_mut(&mut self) -> Option<&mut Option<SubagentRunId>> {
396        match self {
397            Self::TextMessageStart(e) => Some(&mut e.subagent_run_id),
398            Self::TextMessageContent(e) => Some(&mut e.subagent_run_id),
399            Self::TextMessageEnd(e) => Some(&mut e.subagent_run_id),
400            Self::TextMessageChunk(e) => Some(&mut e.subagent_run_id),
401            Self::ToolCallStart(e) => Some(&mut e.subagent_run_id),
402            Self::ToolCallArgs(e) => Some(&mut e.subagent_run_id),
403            Self::ToolCallEnd(e) => Some(&mut e.subagent_run_id),
404            Self::ToolCallChunk(e) => Some(&mut e.subagent_run_id),
405            Self::ToolCallResult(e) => Some(&mut e.subagent_run_id),
406            Self::StateSnapshot(e) => Some(&mut e.subagent_run_id),
407            Self::StateDelta(e) => Some(&mut e.subagent_run_id),
408            Self::ActivitySnapshot(e) => Some(&mut e.subagent_run_id),
409            Self::ActivityDelta(e) => Some(&mut e.subagent_run_id),
410            Self::Raw(e) => Some(&mut e.subagent_run_id),
411            Self::Custom(e) => Some(&mut e.subagent_run_id),
412            Self::StepStarted(e) => Some(&mut e.subagent_run_id),
413            Self::StepFinished(e) => Some(&mut e.subagent_run_id),
414            Self::ReasoningStart(e) => Some(&mut e.subagent_run_id),
415            Self::ReasoningMessageStart(e) => Some(&mut e.subagent_run_id),
416            Self::ReasoningMessageContent(e) => Some(&mut e.subagent_run_id),
417            Self::ReasoningMessageEnd(e) => Some(&mut e.subagent_run_id),
418            Self::ReasoningMessageChunk(e) => Some(&mut e.subagent_run_id),
419            Self::ReasoningEnd(e) => Some(&mut e.subagent_run_id),
420            Self::ReasoningEncryptedValue(e) => Some(&mut e.subagent_run_id),
421            Self::RunStarted(_)
422            | Self::RunFinished(_)
423            | Self::RunError(_)
424            | Self::MessagesSnapshot(_)
425            | Self::ThinkingStart(_)
426            | Self::ThinkingEnd(_)
427            | Self::ThinkingTextMessageStart(_)
428            | Self::ThinkingTextMessageContent(_)
429            | Self::ThinkingTextMessageEnd(_)
430            | Self::SubagentStarted(_)
431            | Self::SubagentFinished(_)
432            | Self::SubagentError(_) => None,
433        }
434    }
435
436    /// The subagent this event belongs to.
437    ///
438    /// `None` means the parent agent — or an event type that carries no
439    /// attribution at all; [`EventType::is_attributable`] tells the two
440    /// apart. For the three `SUBAGENT_*` lifecycle events this is the
441    /// subagent they announce, which is required rather than optional.
442    pub fn subagent_run_id(&self) -> Option<&SubagentRunId> {
443        match self {
444            Self::SubagentStarted(e) => Some(&e.subagent_run_id),
445            Self::SubagentFinished(e) => Some(&e.subagent_run_id),
446            Self::SubagentError(e) => Some(&e.subagent_run_id),
447            _ => self.attribution().and_then(Option::as_ref),
448        }
449    }
450
451    /// Attributes the event to `id`.
452    ///
453    /// Returns `false`, leaving the event untouched, for the nine event types
454    /// the protocol defines without the field: `RUN_*`, `MESSAGES_SNAPSHOT`
455    /// and the deprecated `THINKING_*` family. On a `SUBAGENT_*` event it sets
456    /// the subject.
457    pub fn set_subagent_run_id(&mut self, id: impl Into<SubagentRunId>) -> bool {
458        let id = id.into();
459        match self {
460            Self::SubagentStarted(e) => e.subagent_run_id = id,
461            Self::SubagentFinished(e) => e.subagent_run_id = id,
462            Self::SubagentError(e) => e.subagent_run_id = id,
463            _ => match self.attribution_mut() {
464                Some(slot) => *slot = Some(id),
465                None => return false,
466            },
467        }
468        true
469    }
470
471    /// Removes attribution from an attributable event and returns it.
472    ///
473    /// The `SUBAGENT_*` events carry their id as a required subject, so this
474    /// leaves them alone and returns `None`, as it does for the event types
475    /// that never carry the field.
476    pub fn clear_subagent_run_id(&mut self) -> Option<SubagentRunId> {
477        self.attribution_mut().and_then(Option::take)
478    }
479
480    /// Builder form of [`set_subagent_run_id`](Self::set_subagent_run_id); a
481    /// no-op on the event types that cannot carry attribution.
482    #[must_use]
483    pub fn with_subagent_run_id(mut self, id: impl Into<SubagentRunId>) -> Self {
484        self.set_subagent_run_id(id);
485        self
486    }
487}
488
489impl EventType {
490    /// Whether this event type carries the optional `subagentRunId`
491    /// attribution — 24 of the 36 do.
492    ///
493    /// The three `SUBAGENT_*` lifecycle events return `false`: they carry the
494    /// field as their required subject, not as a tag. The run lifecycle,
495    /// `MESSAGES_SNAPSHOT` (whose messages carry their own) and the deprecated
496    /// `THINKING_*` family have no such field.
497    pub const fn is_attributable(self) -> bool {
498        !matches!(
499            self,
500            Self::RunStarted
501                | Self::RunFinished
502                | Self::RunError
503                | Self::MessagesSnapshot
504                | Self::ThinkingStart
505                | Self::ThinkingEnd
506                | Self::ThinkingTextMessageStart
507                | Self::ThinkingTextMessageContent
508                | Self::ThinkingTextMessageEnd
509                | Self::SubagentStarted
510                | Self::SubagentFinished
511                | Self::SubagentError
512        )
513    }
514}