Skip to main content

ferrum_interfaces/
engine.rs

1//! Inference engine interfaces — split per modality.
2//!
3//! Phase 5a step 2 splits the historical mega-trait (which mixed LLM
4//! generation, embedding, transcription, and TTS in one) into a base
5//! lifecycle trait and four modality-specific supertraits. Each
6//! engine impl now implements exactly the trait its modality needs;
7//! no more inert "unsupported" stubs.
8
9use async_trait::async_trait;
10use ferrum_types::{
11    EngineConfig, ExecutionResourceAuthority, ExecutorAdmissionSnapshot, InferenceRequest,
12    InferenceResponse, Result, StreamChunk,
13};
14use futures::Stream;
15use std::pin::Pin;
16
17/// Lifecycle / status methods shared by every engine kind.
18///
19/// LLM engines, embedders, transcribers, and TTS services all expose
20/// the same minimal status/metrics surface to the server / CLI. The
21/// modality-specific traits below extend this base.
22#[async_trait]
23pub trait InferenceEngine: Send + Sync {
24    /// Get current engine status.
25    async fn status(&self) -> ferrum_types::EngineStatus;
26
27    /// Shutdown engine gracefully.
28    async fn shutdown(&self) -> Result<()>;
29
30    /// Get engine configuration.
31    fn config(&self) -> &EngineConfig;
32
33    /// Get engine metrics.
34    fn metrics(&self) -> ferrum_types::EngineMetrics;
35
36    /// Health check.
37    async fn health_check(&self) -> ferrum_types::HealthStatus;
38
39    /// Optional cache metrics emitted by concrete LLM engines.
40    ///
41    /// The default keeps non-LLM and stub engines source-compatible. Real
42    /// engines can expose prefix/session cache counters without forcing those
43    /// fields into every modality's core metrics type.
44    fn cache_metrics_snapshot(&self) -> Option<serde_json::Value> {
45        None
46    }
47
48    /// Optional compact provider-attribution witness from the active model
49    /// executor. The default keeps non-vNext engines source-compatible.
50    fn execution_attribution_snapshot(&self) -> Option<serde_json::Value> {
51        None
52    }
53
54    /// Runtime-authoritative admission state. Startup sizing estimates are
55    /// intentionally not accepted through this method.
56    fn admission_snapshot(&self) -> Result<Option<ExecutorAdmissionSnapshot>> {
57        Ok(None)
58    }
59
60    /// Optional LoRA runtime metrics emitted by concrete LLM engines.
61    fn lora_metrics_snapshot(&self) -> Option<serde_json::Value> {
62        None
63    }
64}
65
66/// LLM text-generation engine.
67///
68/// Implemented by `ContinuousBatchEngine` (the production path) and
69/// `DefaultInferenceEngine` (legacy reference path). Backs
70/// `/v1/chat/completions` and `/v1/completions`.
71#[async_trait]
72pub trait LlmInferenceEngine: InferenceEngine {
73    /// Authoritative owner of request-lifetime state and capacity. This is a
74    /// cheap capability query; it must not construct a metrics snapshot.
75    /// Plan-runtime engines supply native prefix observations even when their
76    /// selected plan cannot retain checkpoints.
77    fn execution_resource_authority(&self) -> ExecutionResourceAuthority {
78        ExecutionResourceAuthority::LegacyEngine
79    }
80
81    /// Effective per-request capacity in tokens, including input and output.
82    /// Implementations must report the limit used by request admission, not
83    /// the model weights' nominal context window. None means unreported.
84    fn context_capacity(&self) -> Option<usize> {
85        None
86    }
87
88    /// Execute single inference request.
89    async fn infer(&self, request: InferenceRequest) -> Result<InferenceResponse>;
90
91    /// Execute streaming inference request.
92    async fn infer_stream(
93        &self,
94        request: InferenceRequest,
95    ) -> Result<Pin<Box<dyn Stream<Item = Result<StreamChunk>> + Send>>>;
96}
97
98/// Embedding engine (CLIP, BERT, etc.).
99///
100/// Backs `/v1/embeddings`. Distinct from LLM engines — no token
101/// generation, no scheduling, no KV cache.
102#[async_trait]
103pub trait EmbedEngine: InferenceEngine {
104    /// Embed raw text string → float vector (engine handles tokenization).
105    async fn embed_text(&self, text: &str) -> Result<Vec<f32>>;
106
107    /// Embed image (file path or base64) → float vector.
108    async fn embed_image(&self, image: &str) -> Result<Vec<f32>>;
109
110    /// Get embedding dimension.
111    fn embedding_dim(&self) -> usize;
112}
113
114/// Speech-to-text (Whisper) engine.
115///
116/// Backs `/v1/audio/transcriptions`.
117#[async_trait]
118pub trait TranscribeEngine: InferenceEngine {
119    /// Transcribe audio file → text.
120    async fn transcribe_file(&self, path: &str, language: Option<&str>) -> Result<String>;
121
122    /// Transcribe audio bytes (WAV / etc.) → text.
123    async fn transcribe_bytes(&self, data: &[u8], language: Option<&str>) -> Result<String>;
124}
125
126/// Text-to-speech (Qwen3-TTS, etc.) engine.
127///
128/// Backs `/v1/audio/speech`.
129#[async_trait]
130pub trait TtsEngine: InferenceEngine {
131    /// Synthesize speech → PCM audio chunks (streaming).
132    /// Returns Vec of PCM f32 samples per chunk.
133    async fn synthesize_speech(
134        &self,
135        text: &str,
136        language: Option<&str>,
137        chunk_frames: usize,
138    ) -> Result<Vec<Vec<f32>>>;
139
140    /// Get TTS sample rate.
141    fn tts_sample_rate(&self) -> u32;
142}
143
144/// Advanced engine capabilities — opt-in addition to LLM engines that
145/// support batching / speculation / runtime reconfig / diagnostics.
146#[async_trait]
147pub trait AdvancedInferenceEngine: LlmInferenceEngine {
148    /// Execute batch inference.
149    async fn infer_batch(
150        &self,
151        requests: Vec<InferenceRequest>,
152    ) -> Result<Vec<Result<InferenceResponse>>>;
153
154    /// Execute speculative inference.
155    async fn infer_speculative(
156        &self,
157        request: InferenceRequest,
158        speculation_config: ferrum_types::SpeculationConfig,
159    ) -> Result<InferenceResponse>;
160
161    /// Warm up engine with sample requests.
162    async fn warmup(
163        &mut self,
164        warmup_requests: Vec<InferenceRequest>,
165    ) -> Result<ferrum_types::WarmupResult>;
166
167    /// Configure engine at runtime.
168    async fn reconfigure(&mut self, config: EngineConfig) -> Result<()>;
169
170    /// Get detailed diagnostics.
171    async fn diagnostics(&self) -> ferrum_types::DiagnosticsReport;
172
173    /// Export engine state for debugging.
174    async fn export_state(&self) -> Result<ferrum_types::EngineState>;
175
176    /// Import engine state for debugging/testing.
177    async fn import_state(&mut self, state: ferrum_types::EngineState) -> Result<()>;
178}
179
180/// Speculation configuration for speculative decoding.
181pub type SpeculationConfig = ferrum_types::SpeculationConfig;
182
183/// Hardware constraints alias.
184pub type HardwareConstraints = ferrum_types::HardwareConstraints;
185
186/// Request characteristics alias.
187pub type RequestCharacteristics = ferrum_types::RequestCharacteristics;
188
189/// Latency requirements alias.
190pub type LatencyRequirements = ferrum_types::LatencyRequirements;