Skip to main content

kernel/capabilities/
chunk.rs

1//! The streamed output vocabulary: one `CapabilityChunk` per thing a runtime
2//! emits — text, separated thinking, timestamped segments, audio, embedding
3//! vectors, free-text status, and a terminal `Done` carrying generation stats.
4
5use serde::{Deserialize, Serialize};
6
7use super::tools::ToolCall;
8
9/// A chunk of a raw binary audio payload plus the sample rate it was produced
10/// at (captured from the sidecar's ready handshake).
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct AudioFrame {
13    pub data: Vec<u8>,
14    pub sample_rate: i64,
15}
16
17impl AudioFrame {
18    /// An audio frame carrying `data` at `sample_rate` hertz.
19    pub fn new(data: Vec<u8>, sample_rate: i64) -> Self {
20        Self { data, sample_rate }
21    }
22}
23
24/// Metrics reported when a generation finishes. Every field is optional — a
25/// runtime fills in what it can measure.
26#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct GenerationStats {
29    #[serde(skip_serializing_if = "Option::is_none", default)]
30    pub prompt_tokens: Option<i64>,
31    #[serde(skip_serializing_if = "Option::is_none", default)]
32    pub completion_tokens: Option<i64>,
33    #[serde(skip_serializing_if = "Option::is_none", default)]
34    pub duration_ms: Option<i64>,
35    #[serde(skip_serializing_if = "Option::is_none", default)]
36    pub ttft_ms: Option<i64>,
37    #[serde(skip_serializing_if = "Option::is_none", default)]
38    pub load_ms: Option<i64>,
39    #[serde(skip_serializing_if = "Option::is_none", default)]
40    pub finish_reason: Option<String>,
41    #[serde(default)]
42    pub token_counts_estimated: bool,
43}
44
45/// One item in a capability stream (chat, vision, speech, transcription,
46/// embeddings).
47#[derive(Debug, Clone, PartialEq)]
48pub enum CapabilityChunk {
49    /// Visible generated text.
50    Text(String),
51    /// Reasoning the runtime separated from the visible answer.
52    Thinking(String),
53    /// A transcription segment with its millisecond time span.
54    Segment {
55        text: String,
56        start_ms: i64,
57        end_ms: i64,
58    },
59    /// A raw audio payload at the handshake sample rate.
60    Audio(AudioFrame),
61    /// An embedding vector.
62    Vector(Vec<f64>),
63    /// A tool call the model emitted.
64    ToolCall(ToolCall),
65    /// A free-text status notice.
66    Status(String),
67    /// The terminal marker, carrying stats when the runtime reported any.
68    Done(Option<GenerationStats>),
69}