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