Skip to main content

rskit_ai/
stream.rs

1//! Streaming response event vocabulary.
2
3use serde::{Deserialize, Serialize};
4
5use crate::role::Role;
6use crate::usage::Usage;
7
8/// Canonical finish reason for GenAI responses.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11#[non_exhaustive]
12pub enum FinishReason {
13    /// Natural stop.
14    Stop,
15    /// Length/token limit reached.
16    Length,
17    /// Model stopped to request tool use.
18    ToolUse,
19    /// Provider content filter stopped generation.
20    ContentFilter,
21    /// Error stopped generation.
22    Error,
23    /// Cancellation stopped generation.
24    Cancelled,
25}
26
27/// Incremental event emitted during an AI stream.
28pub trait StreamEvent: Send + Sync + std::fmt::Debug {
29    /// Stable event type emitted on the wire.
30    fn event_type(&self) -> &'static str;
31}
32
33/// Shared stream event reference used across async boundaries.
34pub type StreamEventRef = std::sync::Arc<dyn StreamEvent>;
35
36/// Signals the start of a new message.
37#[derive(Debug, Clone, PartialEq)]
38pub struct MessageStart {
39    /// Message role.
40    pub role: Role,
41    /// Model identifier.
42    pub model: String,
43    /// Provider request identifier, when available.
44    pub request_id: Option<String>,
45}
46
47impl StreamEvent for MessageStart {
48    fn event_type(&self) -> &'static str {
49        "message.start"
50    }
51}
52
53/// Incremental text delta.
54#[derive(Debug, Clone, PartialEq)]
55pub struct TextDelta {
56    /// Text delta.
57    pub text: String,
58}
59
60impl StreamEvent for TextDelta {
61    fn event_type(&self) -> &'static str {
62        "text.delta"
63    }
64}
65
66/// Incremental reasoning delta.
67#[derive(Debug, Clone, PartialEq)]
68pub struct ReasoningDelta {
69    /// Reasoning text delta.
70    pub text: String,
71}
72
73impl StreamEvent for ReasoningDelta {
74    fn event_type(&self) -> &'static str {
75        "reasoning.delta"
76    }
77}
78
79/// Tool-use block has started.
80#[derive(Debug, Clone, PartialEq)]
81pub struct ToolUseStart {
82    /// Tool-use identifier.
83    pub id: String,
84    /// Tool name.
85    pub name: String,
86}
87
88impl StreamEvent for ToolUseStart {
89    fn event_type(&self) -> &'static str {
90        "tool_use.start"
91    }
92}
93
94/// Incremental tool-use input delta.
95#[derive(Debug, Clone, PartialEq)]
96pub struct ToolUseDelta {
97    /// Tool-use identifier.
98    pub id: String,
99    /// Incremental JSON argument fragment.
100    pub input_delta: String,
101}
102
103impl StreamEvent for ToolUseDelta {
104    fn event_type(&self) -> &'static str {
105        "tool_use.delta"
106    }
107}
108
109/// Tool-use block has stopped.
110#[derive(Debug, Clone, PartialEq)]
111pub struct ToolUseStop {
112    /// Tool-use identifier.
113    pub id: String,
114}
115
116impl StreamEvent for ToolUseStop {
117    fn event_type(&self) -> &'static str {
118        "tool_use.stop"
119    }
120}
121
122/// Message has stopped.
123#[derive(Debug, Clone, PartialEq)]
124pub struct MessageStop {
125    /// Finish reason.
126    pub finish_reason: FinishReason,
127}
128
129impl StreamEvent for MessageStop {
130    fn event_type(&self) -> &'static str {
131        "message.stop"
132    }
133}
134
135/// Token usage delta/update.
136#[derive(Debug, Clone, PartialEq)]
137pub struct UsageDelta {
138    /// Usage counters.
139    pub usage: Usage,
140}
141
142impl StreamEvent for UsageDelta {
143    fn event_type(&self) -> &'static str {
144        "usage.delta"
145    }
146}
147
148/// Terminal stream error.
149#[derive(Debug, Clone, PartialEq)]
150pub struct ErrorEvent {
151    /// Error message.
152    pub message: String,
153    /// Stable error code, when available.
154    pub code: Option<String>,
155}
156
157impl StreamEvent for ErrorEvent {
158    fn event_type(&self) -> &'static str {
159        "error"
160    }
161}