Skip to main content

harness_lock_core/
providers.rs

1//! LLM providers — a thin abstraction with a deterministic reference provider.
2
3/// A provider manifests itself to the resolver through `complete`, which returns a
4/// `ProviderResponse`. The reference provider is deterministic and offline so the
5/// whole local loop runs with no accounts or network.
6#[derive(Debug, Clone)]
7pub struct Usage {
8    pub input_tokens: u64,
9    pub output_tokens: u64,
10}
11
12#[derive(Debug, Clone)]
13pub struct ProviderResponse {
14    pub content: String,
15    pub usage: Usage,
16    pub cost_usd: f64,
17    pub latency_ms: f64,
18}
19
20/// Deterministic provider: "succeeds" with per-model probability so the resolver can
21/// discriminate candidate stacks and produce a real-looking leaderboard + lock.
22#[derive(Debug, Clone)]
23pub struct ReferenceProvider {
24    pub(crate) seed: u64,
25}
26
27impl Default for ReferenceProvider {
28    fn default() -> Self {
29        ReferenceProvider { seed: 0 }
30    }
31}
32
33impl ReferenceProvider {
34    /// Resolve a `provider:model` manifest spec to a pinned model id.
35    pub fn resolve_alias(&self, alias: &str) -> (String, String) {
36        match alias.split_once(':') {
37            Some((p, m)) if !m.is_empty() => (p.to_string(), m.to_string()),
38            _ => ("reference".to_string(), alias.to_string()),
39        }
40    }
41
42    fn quality(model: &str) -> f64 {
43        match model {
44            "qwen-1.5b" => 0.55,
45            "qwen-7b" => 0.75,
46            "qwen-32b" => 0.88,
47            _ => {
48                // deterministic pseudo-quality from the model id
49                let h = sha256_int(model);
50                0.4 + (h % 5000) as f64 / 10000.0
51            }
52        }
53    }
54
55    pub fn complete(&self, model: &str, messages: u64) -> ProviderResponse {
56        // simple deterministic rng based on seed + prompt length
57        let mut state = self.seed * 2654435761 ^ (messages as u64).wrapping_mul(40503);
58        for _ in 0..4 {
59            state = state.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
60        }
61        let r = (state >> 33) as f64 / 4294967296.0_f64;
62        let q = Self::quality(model);
63        let succeeded = r < q;
64        let content = format!(
65            "{}{}|{}",
66            if succeeded { "ANSWER_OK" } else { "ANSWER_UNCERTAIN" },
67            "",
68            model
69        );
70        let cost: f64 = 0.0001 * if model.contains("32") { 4.0 } else { 1.0 };
71        let latency = 100.0 + (r * 800.0);
72        ProviderResponse {
73            content,
74            usage: Usage {
75                input_tokens: 200,
76                output_tokens: 50,
77            },
78            cost_usd: (cost * 1_000_000.0_f64).round() / 1_000_000.0_f64,
79            latency_ms: (latency * 10.0).round() / 10.0,
80        }
81    }
82}
83
84fn sha256_int(s: &str) -> u64 {
85    use sha2::{Digest, Sha256};
86    let mut h = Sha256::new();
87    h.update(s.as_bytes());
88    let d = h.finalize();
89    let mut out = 0u64;
90    for b in &d[..8] {
91        out = (out << 8) | *b as u64;
92    }
93    out
94}