Skip to main content

harn_vm/llm_config/
presentation.rs

1//! Catalog-authored presentation metadata for model pickers.
2//!
3//! Runtime routing does not consume these records. They let hosts render
4//! recommendation presets and one- or two-dimensional model families without
5//! hardcoding provider/model names in each UI. A recommendation may also carry
6//! the reviewed measurement receipts that make it eligible as a host default.
7
8use std::collections::BTreeMap;
9
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
13pub struct PresentationConfig {
14    /// Stable recommendation id -> authored display copy and generic selector.
15    #[serde(default)]
16    pub variants: BTreeMap<String, PresentationVariantDef>,
17    /// Stable presentation-family id -> ordered dimensions and presets.
18    #[serde(default)]
19    pub families: BTreeMap<String, ModelFamilyDef>,
20}
21
22impl PresentationConfig {
23    pub fn is_empty(&self) -> bool {
24        self.variants.is_empty() && self.families.is_empty()
25    }
26}
27
28#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
29pub struct PresentationVariantDef {
30    /// Ascending display order in the resolved recommendation array.
31    pub order: u16,
32    pub label: String,
33    pub description: String,
34    pub selector: PresentationVariantSelector,
35    /// Reviewed evidence authorizing this concrete route as the automatic host
36    /// default. Absence means the variant is picker-only.
37    #[serde(default, skip_serializing_if = "Option::is_none")]
38    pub automatic_eligibility: Option<AutomaticModelEligibility>,
39}
40
41/// Catalog-owned decision that a measured route may be selected automatically.
42#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
43pub struct AutomaticModelEligibility {
44    pub schema: AutomaticModelEligibilitySchema,
45    pub decision: AutomaticModelEligibilityDecision,
46    pub receipts: Vec<ModelEligibilityMeasurement>,
47}
48
49#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
50pub enum AutomaticModelEligibilitySchema {
51    #[serde(rename = "harn.automatic_model_eligibility.v1")]
52    V1,
53}
54
55#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
56#[serde(rename_all = "snake_case")]
57pub enum AutomaticModelEligibilityDecision {
58    Eligible,
59}
60
61/// One exact, reproducible measured input to an automatic-eligibility review.
62#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
63pub struct ModelEligibilityMeasurement {
64    pub kind: ModelEligibilityMeasurementKind,
65    pub source: String,
66    pub observed_at: String,
67    pub harn_version: String,
68    pub passed: u32,
69    pub trials: u32,
70}
71
72#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
73#[serde(rename_all = "snake_case")]
74pub enum ModelEligibilityMeasurementKind {
75    MeterHoldout,
76    ToolCallFidelity,
77    ProviderHealth,
78}
79
80/// Small, deliberately closed selector vocabulary for global recommendations.
81///
82/// This keeps labels and choices in catalog data without growing a second
83/// model-query language. The resolved artifact always contains a concrete
84/// provider/model pair.
85#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
86#[serde(tag = "kind", rename_all = "snake_case")]
87pub enum PresentationVariantSelector {
88    Alias { name: String },
89    Model { model_id: String },
90    BestLocal,
91    CheapestHosted,
92    LargestVisionContext,
93    LargestContext,
94}
95
96#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
97pub struct ModelFamilyDef {
98    pub label: String,
99    pub plain_description: String,
100    /// Concrete model for families without a model/variant dimension, such as
101    /// a one-dimensional reasoning-effort family.
102    #[serde(default, skip_serializing_if = "Option::is_none")]
103    pub model_id: Option<String>,
104    pub dimensions: Vec<ModelFamilyDimensionDef>,
105    pub presets: Vec<ModelFamilyPresetDef>,
106}
107
108#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
109pub struct ModelFamilyDimensionDef {
110    pub key: String,
111    pub label: String,
112    pub plain_description: String,
113    pub kind: ModelFamilyDimensionKind,
114    pub ordered_values: Vec<ModelFamilyValueDef>,
115}
116
117#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
118#[serde(rename_all = "snake_case")]
119pub enum ModelFamilyDimensionKind {
120    /// Each value selects a concrete model id.
121    Model,
122    /// Each value is a provider reasoning-effort token.
123    ReasoningEffort,
124}
125
126#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
127pub struct ModelFamilyValueDef {
128    pub value: String,
129    pub label: String,
130    pub plain_description: String,
131    pub relative_cost_hint: u8,
132    pub relative_speed_hint: u8,
133    /// Required only for values on a `model` dimension.
134    #[serde(default, skip_serializing_if = "Option::is_none")]
135    pub model_id: Option<String>,
136}
137
138#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
139pub struct ModelFamilyPresetDef {
140    pub id: String,
141    pub label: String,
142    pub plain_blurb: String,
143    pub coordinates: BTreeMap<String, String>,
144}