Skip to main content

el_runtime/
defaults.rs

1//! Default, pure-Rust port implementations (no-op / identity) so a session can
2//! be built without any external adapter.
3
4use crate::ports::{GrammarMasker, InferenceEngine, PromptCompressor};
5use el_core::{Result, Token};
6
7/// Identity compressor — passes the prompt through unchanged.
8pub struct IdentityCompressor;
9
10impl PromptCompressor for IdentityCompressor {
11    fn compress(&self, tokens: &[Token]) -> Vec<Token> {
12        tokens.to_vec()
13    }
14}
15
16/// Allow-all grammar — every token legal (used when no schema is registered).
17pub struct AllowAllMasker;
18
19impl GrammarMasker for AllowAllMasker {
20    fn mask(&self, _recent: &[Token], vocab: usize) -> Vec<bool> {
21        vec![true; vocab]
22    }
23}
24
25/// A trivial engine that emits EOS immediately after prefill. Lets you exercise
26/// the full session lifecycle without the Candle adapter (ADR-002 is the real
27/// engine). Not for production inference.
28pub struct NullEngine {
29    pub eos: Token,
30    pub vocab: usize,
31}
32
33impl NullEngine {
34    pub fn new(eos: Token, vocab: usize) -> Self {
35        Self { eos, vocab }
36    }
37}
38
39impl InferenceEngine for NullEngine {
40    fn prefill(&mut self, tokens: &[Token]) -> Result<u32> {
41        Ok(tokens.len() as u32)
42    }
43
44    fn next_logits(&mut self, _committed: &[Token]) -> Vec<i32> {
45        let mut v = vec![0i32; self.vocab];
46        if let Some(slot) = v.get_mut(self.eos as usize) {
47            *slot = 1;
48        }
49        v
50    }
51
52    fn eos_token(&self) -> Token {
53        self.eos
54    }
55
56    /// Stateless: `next_logits` ignores `committed`, so there is nothing to undo.
57    fn rollback(&mut self, _keep_committed: u32) -> Result<()> {
58        Ok(())
59    }
60
61    /// Stateless: no conversation cache to discard.
62    fn reset_cache(&mut self) -> Result<()> {
63        Ok(())
64    }
65}