Skip to main content

ag_ui/event/
factories.rs

1//! Ergonomic constructors for every event type.
2//!
3//! These mirror the `create*Event` helpers in the TypeScript SDK: each takes
4//! the fields the schema requires and leaves the optional ones unset. Anything
5//! optional is set afterwards, either on the payload struct or through
6//! [`Event::with_timestamp`] and [`Event::with_raw_event`].
7//!
8//! ```
9//! # use ag_ui::{Event, RunOutcome, Interrupt};
10//! let paused = Event::run_finished_interrupt(
11//!     "thread-1",
12//!     "run-1",
13//!     vec![Interrupt::new("i-1", "tool_approval")],
14//! )
15//! .with_timestamp(1_700_000_000_000);
16//! ```
17
18use serde_json::Value;
19
20use crate::JsonObject;
21use crate::event::Event;
22use crate::event::activity::{ActivityDeltaEvent, ActivitySnapshotEvent};
23use crate::event::lifecycle::{
24    RunErrorEvent, RunFinishedEvent, RunStartedEvent, StepFinishedEvent, StepStartedEvent,
25};
26use crate::event::reasoning::{
27    ReasoningEncryptedValueEvent, ReasoningEncryptedValueSubtype, ReasoningEndEvent,
28    ReasoningMessageChunkEvent, ReasoningMessageContentEvent, ReasoningMessageEndEvent,
29    ReasoningMessageStartEvent, ReasoningStartEvent, ThinkingEndEvent, ThinkingStartEvent,
30    ThinkingTextMessageContentEvent, ThinkingTextMessageEndEvent, ThinkingTextMessageStartEvent,
31};
32use crate::event::special::{CustomEvent, RawEvent};
33use crate::event::state::{MessagesSnapshotEvent, StateDeltaEvent, StateSnapshotEvent};
34use crate::event::subagent::{
35    SubagentErrorEvent, SubagentFinishedEvent, SubagentOutcome, SubagentStartedEvent,
36};
37use crate::event::text::{
38    TextMessageChunkEvent, TextMessageContentEvent, TextMessageEndEvent, TextMessageRole,
39    TextMessageStartEvent,
40};
41use crate::event::tool::{
42    ToolCallArgsEvent, ToolCallChunkEvent, ToolCallEndEvent, ToolCallResultEvent,
43    ToolCallStartEvent,
44};
45use crate::ids::{MessageId, RunId, StepName, SubagentRunId, ThreadId, ToolCallId};
46use crate::message::Message;
47use crate::outcome::{Interrupt, RunOutcome};
48use crate::patch::PatchOperation;
49
50impl Event {
51    /// `TEXT_MESSAGE_START` — opens a text message.
52    pub fn text_message_start(message_id: impl Into<MessageId>, role: TextMessageRole) -> Self {
53        TextMessageStartEvent::new(message_id, role).into()
54    }
55
56    /// `TEXT_MESSAGE_CONTENT` — appends text to an open message.
57    pub fn text_message_content(
58        message_id: impl Into<MessageId>,
59        delta: impl Into<String>,
60    ) -> Self {
61        TextMessageContentEvent::new(message_id, delta).into()
62    }
63
64    /// `TEXT_MESSAGE_END` — closes a text message.
65    pub fn text_message_end(message_id: impl Into<MessageId>) -> Self {
66        TextMessageEndEvent::new(message_id).into()
67    }
68
69    /// `TEXT_MESSAGE_CHUNK` — a whole text update in one event.
70    pub fn text_message_chunk(message_id: Option<MessageId>, delta: Option<String>) -> Self {
71        TextMessageChunkEvent::new(message_id, delta).into()
72    }
73
74    /// `TOOL_CALL_START` — opens a tool call.
75    pub fn tool_call_start(
76        tool_call_id: impl Into<ToolCallId>,
77        tool_call_name: impl Into<String>,
78    ) -> Self {
79        ToolCallStartEvent::new(tool_call_id, tool_call_name).into()
80    }
81
82    /// `TOOL_CALL_ARGS` — appends argument JSON to an open call.
83    pub fn tool_call_args(tool_call_id: impl Into<ToolCallId>, delta: impl Into<String>) -> Self {
84        ToolCallArgsEvent::new(tool_call_id, delta).into()
85    }
86
87    /// `TOOL_CALL_END` — closes a tool call.
88    pub fn tool_call_end(tool_call_id: impl Into<ToolCallId>) -> Self {
89        ToolCallEndEvent::new(tool_call_id).into()
90    }
91
92    /// `TOOL_CALL_CHUNK` — a whole tool call in one event.
93    pub fn tool_call_chunk(
94        tool_call_id: Option<ToolCallId>,
95        tool_call_name: Option<String>,
96        delta: Option<String>,
97    ) -> Self {
98        ToolCallChunkEvent::new(tool_call_id, tool_call_name, delta).into()
99    }
100
101    /// `TOOL_CALL_RESULT` — reports what a tool returned.
102    pub fn tool_call_result(
103        message_id: impl Into<MessageId>,
104        tool_call_id: impl Into<ToolCallId>,
105        content: impl Into<String>,
106    ) -> Self {
107        ToolCallResultEvent::new(message_id, tool_call_id, content).into()
108    }
109
110    /// `THINKING_START` — opens a thinking block.
111    #[deprecated(note = "use Event::reasoning_start")]
112    pub fn thinking_start(title: Option<String>) -> Self {
113        ThinkingStartEvent::new(title).into()
114    }
115
116    /// `THINKING_END` — closes a thinking block.
117    #[deprecated(note = "use Event::reasoning_end")]
118    pub fn thinking_end() -> Self {
119        ThinkingEndEvent::default().into()
120    }
121
122    /// `THINKING_TEXT_MESSAGE_START` — opens a thinking message.
123    #[deprecated(note = "use Event::reasoning_message_start")]
124    pub fn thinking_text_message_start() -> Self {
125        ThinkingTextMessageStartEvent::default().into()
126    }
127
128    /// `THINKING_TEXT_MESSAGE_CONTENT` — appends thinking text.
129    #[deprecated(note = "use Event::reasoning_message_content")]
130    pub fn thinking_text_message_content(delta: impl Into<String>) -> Self {
131        ThinkingTextMessageContentEvent::new(delta).into()
132    }
133
134    /// `THINKING_TEXT_MESSAGE_END` — closes a thinking message.
135    #[deprecated(note = "use Event::reasoning_message_end")]
136    pub fn thinking_text_message_end() -> Self {
137        ThinkingTextMessageEndEvent::default().into()
138    }
139
140    /// `STATE_SNAPSHOT` — replaces the shared state.
141    pub fn state_snapshot(snapshot: impl Into<Value>) -> Self {
142        StateSnapshotEvent::new(snapshot).into()
143    }
144
145    /// `STATE_DELTA` — patches the shared state.
146    pub fn state_delta(delta: impl Into<Vec<PatchOperation>>) -> Self {
147        StateDeltaEvent::new(delta).into()
148    }
149
150    /// `MESSAGES_SNAPSHOT` — replaces the message history.
151    pub fn messages_snapshot(messages: impl Into<Vec<Message>>) -> Self {
152        MessagesSnapshotEvent::new(messages).into()
153    }
154
155    /// `ACTIVITY_SNAPSHOT` — publishes an activity payload.
156    pub fn activity_snapshot(
157        message_id: impl Into<MessageId>,
158        activity_type: impl Into<String>,
159        content: JsonObject,
160    ) -> Self {
161        ActivitySnapshotEvent::new(message_id, activity_type, content).into()
162    }
163
164    /// `ACTIVITY_DELTA` — patches an activity payload.
165    pub fn activity_delta(
166        message_id: impl Into<MessageId>,
167        activity_type: impl Into<String>,
168        patch: impl Into<Vec<PatchOperation>>,
169    ) -> Self {
170        ActivityDeltaEvent::new(message_id, activity_type, patch).into()
171    }
172
173    /// `RAW` — forwards a provider event verbatim.
174    pub fn raw(event: impl Into<Value>) -> Self {
175        RawEvent::new(event).into()
176    }
177
178    /// `CUSTOM` — an application-defined event.
179    pub fn custom(name: impl Into<String>, value: impl Into<Value>) -> Self {
180        CustomEvent::new(name, value).into()
181    }
182
183    /// `RUN_STARTED` — starts a run.
184    pub fn run_started(thread_id: impl Into<ThreadId>, run_id: impl Into<RunId>) -> Self {
185        RunStartedEvent::new(thread_id, run_id).into()
186    }
187
188    /// `RUN_FINISHED` without an outcome — the legacy shape, which consumers
189    /// read as success.
190    pub fn run_finished(thread_id: impl Into<ThreadId>, run_id: impl Into<RunId>) -> Self {
191        RunFinishedEvent::new(thread_id, run_id).into()
192    }
193
194    /// `RUN_FINISHED` with an explicit success outcome.
195    pub fn run_finished_success(thread_id: impl Into<ThreadId>, run_id: impl Into<RunId>) -> Self {
196        RunFinishedEvent::new(thread_id, run_id)
197            .with_outcome(RunOutcome::Success)
198            .into()
199    }
200
201    /// `RUN_FINISHED` with an interrupt outcome — the run is paused until the
202    /// client answers.
203    pub fn run_finished_interrupt(
204        thread_id: impl Into<ThreadId>,
205        run_id: impl Into<RunId>,
206        interrupts: impl Into<Vec<Interrupt>>,
207    ) -> Self {
208        RunFinishedEvent::new(thread_id, run_id)
209            .with_outcome(RunOutcome::interrupt(interrupts))
210            .into()
211    }
212
213    /// `RUN_ERROR` — fails the run.
214    pub fn run_error(message: impl Into<String>) -> Self {
215        RunErrorEvent::new(message).into()
216    }
217
218    /// `STEP_STARTED` — opens a named step.
219    pub fn step_started(step_name: impl Into<StepName>) -> Self {
220        StepStartedEvent::new(step_name).into()
221    }
222
223    /// `STEP_FINISHED` — closes a named step.
224    pub fn step_finished(step_name: impl Into<StepName>) -> Self {
225        StepFinishedEvent::new(step_name).into()
226    }
227
228    /// `REASONING_START` — opens a reasoning block.
229    pub fn reasoning_start(message_id: impl Into<MessageId>) -> Self {
230        ReasoningStartEvent::new(message_id).into()
231    }
232
233    /// `REASONING_MESSAGE_START` — opens a reasoning message.
234    pub fn reasoning_message_start(message_id: impl Into<MessageId>) -> Self {
235        ReasoningMessageStartEvent::new(message_id).into()
236    }
237
238    /// `REASONING_MESSAGE_CONTENT` — appends reasoning text.
239    pub fn reasoning_message_content(
240        message_id: impl Into<MessageId>,
241        delta: impl Into<String>,
242    ) -> Self {
243        ReasoningMessageContentEvent::new(message_id, delta).into()
244    }
245
246    /// `REASONING_MESSAGE_END` — closes a reasoning message.
247    pub fn reasoning_message_end(message_id: impl Into<MessageId>) -> Self {
248        ReasoningMessageEndEvent::new(message_id).into()
249    }
250
251    /// `REASONING_MESSAGE_CHUNK` — a whole reasoning update in one event.
252    pub fn reasoning_message_chunk(message_id: Option<MessageId>, delta: Option<String>) -> Self {
253        ReasoningMessageChunkEvent::new(message_id, delta).into()
254    }
255
256    /// `REASONING_END` — closes a reasoning block.
257    pub fn reasoning_end(message_id: impl Into<MessageId>) -> Self {
258        ReasoningEndEvent::new(message_id).into()
259    }
260
261    /// `REASONING_ENCRYPTED_VALUE` — carries an opaque reasoning blob.
262    pub fn reasoning_encrypted_value(
263        subtype: ReasoningEncryptedValueSubtype,
264        entity_id: impl Into<String>,
265        encrypted_value: impl Into<String>,
266    ) -> Self {
267        ReasoningEncryptedValueEvent::new(subtype, entity_id, encrypted_value).into()
268    }
269
270    /// `SUBAGENT_STARTED` — announces a subagent invocation.
271    pub fn subagent_started(
272        subagent_run_id: impl Into<SubagentRunId>,
273        name: impl Into<String>,
274    ) -> Self {
275        SubagentStartedEvent::new(subagent_run_id, name).into()
276    }
277
278    /// `SUBAGENT_FINISHED` without an outcome — the legacy shape, which
279    /// consumers read as success.
280    pub fn subagent_finished(subagent_run_id: impl Into<SubagentRunId>) -> Self {
281        SubagentFinishedEvent::new(subagent_run_id).into()
282    }
283
284    /// `SUBAGENT_FINISHED` with an explicit success outcome.
285    pub fn subagent_finished_success(subagent_run_id: impl Into<SubagentRunId>) -> Self {
286        SubagentFinishedEvent::new(subagent_run_id)
287            .with_outcome(SubagentOutcome::Success)
288            .into()
289    }
290
291    /// `SUBAGENT_FINISHED` with a suspended outcome — the subagent is waiting
292    /// on the named interrupts.
293    pub fn subagent_finished_suspended(
294        subagent_run_id: impl Into<SubagentRunId>,
295        interrupt_ids: impl Into<Vec<String>>,
296    ) -> Self {
297        SubagentFinishedEvent::new(subagent_run_id)
298            .with_outcome(SubagentOutcome::suspended(interrupt_ids))
299            .into()
300    }
301
302    /// `SUBAGENT_ERROR` — fails a subagent invocation.
303    pub fn subagent_error(
304        subagent_run_id: impl Into<SubagentRunId>,
305        message: impl Into<String>,
306    ) -> Self {
307        SubagentErrorEvent::new(subagent_run_id, message).into()
308    }
309}