Skip to main content

ag_ui/event/
special.rs

1//! Escape hatches: `RAW` and `CUSTOM`.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::event::BaseEvent;
7use crate::ids::SubagentRunId;
8
9/// Forwards a provider event verbatim, for debugging and for consumers that
10/// understand the upstream format.
11#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
12#[serde(rename_all = "camelCase")]
13#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
14#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
15pub struct RawEvent {
16    /// Timestamp and raw provider event.
17    #[serde(flatten)]
18    pub base: BaseEvent,
19    /// The upstream event, untouched.
20    pub event: Value,
21    /// Which system produced it, for example `"openai"`.
22    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub source: Option<String>,
24    /// The subagent that produced this event; absent means the parent agent.
25    /// A JSON `null` is rejected — see [`crate::event::subagent`].
26    #[serde(
27        default,
28        deserialize_with = "crate::serde_util::reject_null",
29        skip_serializing_if = "Option::is_none"
30    )]
31    pub subagent_run_id: Option<SubagentRunId>,
32}
33
34impl RawEvent {
35    /// Forwards `event` as-is.
36    pub fn new(event: impl Into<Value>) -> Self {
37        Self {
38            base: BaseEvent::default(),
39            event: event.into(),
40            source: None,
41            subagent_run_id: None,
42        }
43    }
44}
45
46/// An application-defined event, outside the protocol's vocabulary.
47///
48/// Use this for anything a specific client and agent agree on; the protocol
49/// only guarantees the envelope.
50#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
53#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
54pub struct CustomEvent {
55    /// Timestamp and raw provider event.
56    #[serde(flatten)]
57    pub base: BaseEvent,
58    /// The event name both sides agreed on.
59    pub name: String,
60    /// The payload.
61    pub value: Value,
62    /// The subagent that produced this event; absent means the parent agent.
63    /// A JSON `null` is rejected — see [`crate::event::subagent`].
64    #[serde(
65        default,
66        deserialize_with = "crate::serde_util::reject_null",
67        skip_serializing_if = "Option::is_none"
68    )]
69    pub subagent_run_id: Option<SubagentRunId>,
70}
71
72impl CustomEvent {
73    /// Emits a named custom event.
74    pub fn new(name: impl Into<String>, value: impl Into<Value>) -> Self {
75        Self {
76            base: BaseEvent::default(),
77            name: name.into(),
78            value: value.into(),
79            subagent_run_id: None,
80        }
81    }
82}