aether_core/events/message_event.rs
1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4/// Whether a streamed text or thought chunk is the final one for its message.
5///
6/// `Partial` chunks stream as they arrive; a single `Complete` event carries the
7/// full accumulated text and is emitted when the turn wraps up (which may be after
8/// the originating LLM call's
9/// [`TurnEvent::LlmCallEnded`](crate::events::TurnEvent::LlmCallEnded)).
10///
11/// This stands in for the raw `is_complete: bool` on event constructors so that
12/// call sites read as `StreamState::Complete` instead of an opaque `true` literal.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum StreamState {
15 /// More chunks may follow for this message.
16 Partial,
17 /// This is the final chunk for the message.
18 Complete,
19}
20
21impl StreamState {
22 pub fn is_complete(self) -> bool {
23 matches!(self, Self::Complete)
24 }
25}
26
27/// Streaming message content from the agent.
28///
29/// Chunks stream with `is_complete: false`; a final event with `is_complete: true`
30/// carries the full accumulated text. The completion event is emitted when the
31/// turn wraps up, which may be after the originating LLM call's
32/// [`TurnEvent::LlmCallEnded`](crate::events::TurnEvent::LlmCallEnded).
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
34#[serde(tag = "type", rename_all = "snake_case")]
35pub enum MessageEvent {
36 /// Assistant response text.
37 Text { message_id: String, chunk: String, is_complete: bool },
38 /// Assistant reasoning summary text.
39 Thought { message_id: String, chunk: String, is_complete: bool },
40}