1use std::collections::BTreeMap;
9
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
13pub struct PresentationConfig {
14 #[serde(default)]
16 pub variants: BTreeMap<String, PresentationVariantDef>,
17 #[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 pub order: u16,
32 pub label: String,
33 pub description: String,
34 pub selector: PresentationVariantSelector,
35 #[serde(default, skip_serializing_if = "Option::is_none")]
38 pub automatic_eligibility: Option<AutomaticModelEligibility>,
39}
40
41#[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#[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#[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 #[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 Model,
122 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 #[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}