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    /// Milliseconds the backend spent on the prompt.
40    #[serde(skip_serializing_if = "Option::is_none", default)]
41    pub prompt_ms: Option<i64>,
42    /// Milliseconds the backend spent generating, the prompt excluded.
43    #[serde(skip_serializing_if = "Option::is_none", default)]
44    pub eval_ms: Option<i64>,
45    #[serde(skip_serializing_if = "Option::is_none", default)]
46    pub finish_reason: Option<String>,
47    #[serde(default)]
48    pub token_counts_estimated: bool,
49}
50
51/// One item in a capability stream (chat, vision, speech, transcription,
52/// embeddings).
53#[derive(Debug, Clone, PartialEq)]
54pub enum CapabilityChunk {
55    /// Visible generated text.
56    Text(String),
57    /// Reasoning the runtime separated from the visible answer.
58    Thinking(String),
59    /// A transcription segment with its millisecond time span.
60    Segment {
61        text: String,
62        start_ms: i64,
63        end_ms: i64,
64    },
65    /// A raw audio payload at the handshake sample rate.
66    Audio(AudioFrame),
67    /// An embedding vector.
68    Vector(Vec<f64>),
69    /// A tool call the model emitted.
70    ToolCall(ToolCall),
71    /// A free-text status notice.
72    Status(String),
73    /// The terminal marker, carrying stats when the runtime reported any.
74    Done(Option<GenerationStats>),
75}