Skip to main content

ferrin_core/telemetry/
events.rs

1//! Telemetry event payloads.
2
3use std::collections::BTreeMap;
4use std::sync::Arc;
5use std::time::Duration;
6
7use ferrin_message::Message;
8use ferrin_spec::FinishReason;
9use ferrin_spec::JsonValue;
10use ferrin_spec::ModelId;
11use ferrin_spec::ProviderId;
12use ferrin_spec::ResponseMetadata;
13use ferrin_spec::ToolCallId;
14use ferrin_spec::ToolName;
15use ferrin_spec::Usage;
16use ferrin_spec::Warning;
17use ferrin_spec::language_model::CallOptionsRecord;
18use serde::Deserialize;
19use serde::Serialize;
20
21use crate::error::Error;
22use crate::generate_text::StepContent;
23use crate::generate_text::StepPerformance;
24use crate::generate_text::StepResult;
25use crate::generate_text::ToolErrorInfo;
26
27/// Provider and model ids of the model handling a call.
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
29pub struct ModelIdentity {
30    /// Provider id.
31    pub provider: ProviderId,
32    /// Model id.
33    pub model_id: ModelId,
34}
35
36impl ModelIdentity {
37    /// Creates an identity.
38    #[must_use]
39    pub fn new(provider: impl Into<ProviderId>, model_id: impl Into<ModelId>) -> Self {
40        Self {
41            provider: provider.into(),
42            model_id: model_id.into(),
43        }
44    }
45}
46
47/// Inputs recorded when `record_inputs` is enabled.
48#[derive(Debug, Clone, PartialEq)]
49pub struct RecordedInputs {
50    /// System instructions.
51    pub system: Option<String>,
52    /// The initial messages.
53    pub messages: Arc<[Message]>,
54}
55
56/// A call started.
57#[derive(Debug, Clone)]
58pub struct StartEvent {
59    /// Call id.
60    pub call_id: String,
61    /// Function id from the telemetry options.
62    pub function_id: Option<String>,
63    /// The model.
64    pub model: ModelIdentity,
65    /// Inputs (only when `record_inputs`).
66    pub inputs: Option<RecordedInputs>,
67    /// Metadata from the telemetry options.
68    pub metadata: BTreeMap<String, JsonValue>,
69}
70
71/// A step started.
72#[derive(Debug, Clone)]
73pub struct StepStartEvent {
74    /// Call id.
75    pub call_id: String,
76    /// Zero-based step index.
77    pub step_number: u32,
78    /// The model of this step.
79    pub model: ModelIdentity,
80    /// Messages sent to the model (only when `record_inputs`).
81    pub messages: Option<Arc<[Message]>>,
82}
83
84/// A model call is about to be made.
85#[derive(Debug, Clone)]
86pub struct ModelCallStartEvent {
87    /// Call id.
88    pub call_id: String,
89    /// Zero-based step index.
90    pub step_number: u32,
91    /// The model.
92    pub model: ModelIdentity,
93    /// Serializable snapshot of the call options (only when `record_inputs`).
94    pub call_options: Option<CallOptionsRecord>,
95}
96
97/// A model call finished and its tool calls were parsed.
98#[derive(Debug, Clone)]
99pub struct ModelCallEndEvent {
100    /// Call id.
101    pub call_id: String,
102    /// Zero-based step index.
103    pub step_number: u32,
104    /// The model.
105    pub model: ModelIdentity,
106    /// Parsed content (only when `record_outputs`).
107    pub content: Option<Vec<StepContent>>,
108    /// Finish reason.
109    pub finish_reason: FinishReason,
110    /// Usage.
111    pub usage: Usage,
112    /// Response metadata.
113    pub response: ResponseMetadata,
114    /// Timing.
115    pub performance: StepPerformance,
116    /// Warnings.
117    pub warnings: Vec<Warning>,
118}
119
120/// A tool execution is about to start.
121#[derive(Debug, Clone)]
122pub struct ToolExecutionStartEvent {
123    /// Call id.
124    pub call_id: String,
125    /// Tool call id.
126    pub tool_call_id: ToolCallId,
127    /// Tool name.
128    pub tool_name: ToolName,
129    /// Input (only when `record_inputs`).
130    pub input: Option<JsonValue>,
131}
132
133/// A tool execution finished.
134#[derive(Debug, Clone)]
135pub struct ToolExecutionEndEvent {
136    /// Call id.
137    pub call_id: String,
138    /// Tool call id.
139    pub tool_call_id: ToolCallId,
140    /// Tool name.
141    pub tool_name: ToolName,
142    /// Output on success (only when `record_outputs`).
143    pub output: Option<ToolOutcome>,
144    /// Error on failure.
145    pub error: Option<ToolErrorInfo>,
146    /// Execution time.
147    pub duration: Duration,
148}
149
150/// The successful outcome of a tool execution.
151#[derive(Debug, Clone, PartialEq)]
152pub struct ToolOutcome {
153    /// The final output value.
154    pub output: JsonValue,
155}
156
157/// A step finished.
158#[derive(Debug, Clone)]
159pub struct StepEndEvent {
160    /// Call id.
161    pub call_id: String,
162    /// The step.
163    pub step: Arc<StepResult>,
164}
165
166/// A call finished.
167#[derive(Debug, Clone)]
168pub struct EndEvent {
169    /// Call id.
170    pub call_id: String,
171    /// All steps.
172    pub steps: Arc<[StepResult]>,
173    /// Usage summed over all steps.
174    pub total_usage: Usage,
175    /// Structured output as JSON (only when `record_outputs` and configured).
176    pub output_recorded: Option<JsonValue>,
177}
178
179/// A streaming call was aborted by cancellation.
180#[derive(Debug, Clone)]
181pub struct AbortEvent {
182    /// Call id.
183    pub call_id: String,
184    /// Steps completed before the abort.
185    pub steps_completed: u32,
186}
187
188/// Where an error occurred.
189#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
190#[serde(rename_all = "kebab-case")]
191#[non_exhaustive]
192pub enum ErrorPhase {
193    /// Prompt standardization or conversion.
194    Prompt,
195    /// The model call.
196    ModelCall,
197    /// Tool execution.
198    ToolExecution,
199    /// Structured output parsing.
200    Output,
201    /// The stream pipeline.
202    Stream,
203}
204
205/// An error occurred.
206#[derive(Debug)]
207pub struct ErrorEvent<'a> {
208    /// Call id.
209    pub call_id: &'a str,
210    /// The error.
211    pub error: &'a Error,
212    /// Where it occurred.
213    pub phase: ErrorPhase,
214}
215
216/// An embedding call started.
217#[derive(Debug, Clone)]
218pub struct EmbedStartEvent {
219    /// Call id.
220    pub call_id: String,
221    /// The model.
222    pub model: ModelIdentity,
223    /// Number of values.
224    pub value_count: usize,
225    /// The values (only when `record_inputs`).
226    pub values: Option<Vec<String>>,
227}
228
229/// An embedding call finished.
230#[derive(Debug, Clone)]
231pub struct EmbedEndEvent {
232    /// Call id.
233    pub call_id: String,
234    /// Number of embeddings.
235    pub embedding_count: usize,
236    /// Tokens used, if reported.
237    pub tokens: Option<u64>,
238    /// Wall time.
239    pub duration: Duration,
240}
241
242/// A rerank call started.
243#[derive(Debug, Clone)]
244pub struct RerankStartEvent {
245    /// Call id.
246    pub call_id: String,
247    /// The model.
248    pub model: ModelIdentity,
249    /// Number of documents.
250    pub document_count: usize,
251    /// The query (only when `record_inputs`).
252    pub query: Option<String>,
253}
254
255/// A rerank call finished.
256#[derive(Debug, Clone)]
257pub struct RerankEndEvent {
258    /// Call id.
259    pub call_id: String,
260    /// Number of ranked documents.
261    pub ranked_count: usize,
262    /// Wall time.
263    pub duration: Duration,
264}