1use serde::{Deserialize, Deserializer, Serialize};
4
5use crate::event::BaseEvent;
6use crate::ids::{MessageId, SubagentRunId};
7
8fn null_role_is_the_default<'de, D>(deserializer: D) -> Result<TextMessageRole, D::Error>
19where
20 D: Deserializer<'de>,
21{
22 Ok(Option::<TextMessageRole>::deserialize(deserializer)?.unwrap_or_default())
23}
24
25#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
30#[serde(rename_all = "lowercase")]
31#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
32#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
33pub enum TextMessageRole {
34 Developer,
36 System,
38 #[default]
40 Assistant,
41 User,
43}
44
45impl TextMessageRole {
46 pub const fn as_str(&self) -> &'static str {
48 match self {
49 Self::Developer => "developer",
50 Self::System => "system",
51 Self::Assistant => "assistant",
52 Self::User => "user",
53 }
54 }
55}
56
57#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
62#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
63pub struct TextMessageStartEvent {
64 #[serde(flatten)]
66 pub base: BaseEvent,
67 pub message_id: MessageId,
69 #[serde(default, deserialize_with = "null_role_is_the_default")]
72 pub role: TextMessageRole,
73 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub name: Option<String>,
76 #[serde(
79 default,
80 deserialize_with = "crate::serde_util::reject_null",
81 skip_serializing_if = "Option::is_none"
82 )]
83 pub subagent_run_id: Option<SubagentRunId>,
84}
85
86impl TextMessageStartEvent {
87 pub fn new(message_id: impl Into<MessageId>, role: TextMessageRole) -> Self {
89 Self {
90 base: BaseEvent::default(),
91 message_id: message_id.into(),
92 role,
93 name: None,
94 subagent_run_id: None,
95 }
96 }
97}
98
99#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
101#[serde(rename_all = "camelCase")]
102#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
103#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
104pub struct TextMessageContentEvent {
105 #[serde(flatten)]
107 pub base: BaseEvent,
108 pub message_id: MessageId,
110 pub delta: String,
112 #[serde(
115 default,
116 deserialize_with = "crate::serde_util::reject_null",
117 skip_serializing_if = "Option::is_none"
118 )]
119 pub subagent_run_id: Option<SubagentRunId>,
120}
121
122impl TextMessageContentEvent {
123 pub fn new(message_id: impl Into<MessageId>, delta: impl Into<String>) -> Self {
125 Self {
126 base: BaseEvent::default(),
127 message_id: message_id.into(),
128 delta: delta.into(),
129 subagent_run_id: None,
130 }
131 }
132}
133
134#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
136#[serde(rename_all = "camelCase")]
137#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
138#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
139pub struct TextMessageEndEvent {
140 #[serde(flatten)]
142 pub base: BaseEvent,
143 pub message_id: MessageId,
145 #[serde(
148 default,
149 deserialize_with = "crate::serde_util::reject_null",
150 skip_serializing_if = "Option::is_none"
151 )]
152 pub subagent_run_id: Option<SubagentRunId>,
153}
154
155impl TextMessageEndEvent {
156 pub fn new(message_id: impl Into<MessageId>) -> Self {
158 Self {
159 base: BaseEvent::default(),
160 message_id: message_id.into(),
161 subagent_run_id: None,
162 }
163 }
164}
165
166#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
171#[serde(rename_all = "camelCase")]
172#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
173#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
174pub struct TextMessageChunkEvent {
175 #[serde(flatten)]
177 pub base: BaseEvent,
178 #[serde(default, skip_serializing_if = "Option::is_none")]
180 pub message_id: Option<MessageId>,
181 #[serde(default, skip_serializing_if = "Option::is_none")]
183 pub role: Option<TextMessageRole>,
184 #[serde(default, skip_serializing_if = "Option::is_none")]
186 pub delta: Option<String>,
187 #[serde(default, skip_serializing_if = "Option::is_none")]
189 pub name: Option<String>,
190 #[serde(
196 default,
197 deserialize_with = "crate::serde_util::reject_null",
198 skip_serializing_if = "Option::is_none"
199 )]
200 pub subagent_run_id: Option<SubagentRunId>,
201}
202
203impl TextMessageChunkEvent {
204 pub fn new(message_id: Option<MessageId>, delta: Option<String>) -> Self {
206 Self {
207 base: BaseEvent::default(),
208 message_id,
209 role: None,
210 delta,
211 name: None,
212 subagent_run_id: None,
213 }
214 }
215}