heartbit_core/config/
provider.rs1use serde::Deserialize;
2use std::time::Duration;
3
4#[derive(Debug, Default, Deserialize)]
9pub struct ProviderConfig {
10 #[serde(default)]
12 pub name: String,
13 #[serde(default)]
15 pub model: String,
16 #[serde(default)]
19 pub base_url: Option<String>,
20 #[serde(default)]
23 pub api_key: Option<String>,
24 pub retry: Option<RetryProviderConfig>,
26 #[serde(default)]
29 pub prompt_caching: bool,
30 pub cascade: Option<CascadeConfig>,
33 #[serde(default)]
36 pub circuit: ProviderCircuitConfig,
37}
38
39#[derive(Debug, Clone, Deserialize)]
45pub struct CascadeConfig {
46 #[serde(default)]
48 pub enabled: bool,
49 #[serde(default)]
52 pub tiers: Vec<CascadeTierConfig>,
53 #[serde(default)]
55 pub gate: CascadeGateConfig,
56}
57
58#[derive(Debug, Clone, Deserialize)]
60pub struct CascadeTierConfig {
61 pub model: String,
63}
64
65#[derive(Debug, Clone, Deserialize)]
67#[serde(tag = "type", rename_all = "snake_case")]
68pub enum CascadeGateConfig {
69 Heuristic {
71 #[serde(default = "default_min_output_tokens")]
73 min_output_tokens: u32,
74 #[serde(default = "super::default_true")]
76 accept_tool_calls: bool,
77 #[serde(default = "super::default_true")]
79 escalate_on_max_tokens: bool,
80 },
81}
82
83impl Default for CascadeGateConfig {
84 fn default() -> Self {
85 Self::Heuristic {
86 min_output_tokens: default_min_output_tokens(),
87 accept_tool_calls: true,
88 escalate_on_max_tokens: true,
89 }
90 }
91}
92
93fn default_min_output_tokens() -> u32 {
94 5
95}
96
97#[derive(Debug, Clone, Default, serde::Serialize, Deserialize)]
103#[serde(deny_unknown_fields)]
104pub struct ProviderCircuitConfig {
105 #[serde(default, skip_serializing_if = "Option::is_none")]
107 pub failure_threshold: Option<u32>,
108 #[serde(default, skip_serializing_if = "Option::is_none")]
110 pub initial_open_duration_seconds: Option<u32>,
111 #[serde(default, skip_serializing_if = "Option::is_none")]
113 pub max_open_duration_seconds: Option<u32>,
114 #[serde(default, skip_serializing_if = "Option::is_none")]
116 pub backoff_multiplier: Option<f64>,
117}
118
119impl From<&ProviderCircuitConfig> for crate::llm::circuit::CircuitConfig {
120 fn from(c: &ProviderCircuitConfig) -> Self {
121 let default = crate::llm::circuit::CircuitConfig::default();
122 Self {
123 failure_threshold: c.failure_threshold.unwrap_or(default.failure_threshold),
124 initial_open_duration: c
125 .initial_open_duration_seconds
126 .map(|s| std::time::Duration::from_secs(u64::from(s)))
127 .unwrap_or(default.initial_open_duration),
128 max_open_duration: c
129 .max_open_duration_seconds
130 .map(|s| std::time::Duration::from_secs(u64::from(s)))
131 .unwrap_or(default.max_open_duration),
132 backoff_multiplier: c.backoff_multiplier.unwrap_or(default.backoff_multiplier),
133 }
134 }
135}
136
137#[derive(Debug, Deserialize)]
139pub struct RetryProviderConfig {
140 #[serde(default = "default_max_retries")]
142 pub max_retries: u32,
143 #[serde(default = "default_base_delay_ms")]
145 pub base_delay_ms: u64,
146 #[serde(default = "default_max_delay_ms")]
148 pub max_delay_ms: u64,
149}
150
151fn default_max_retries() -> u32 {
152 3
153}
154
155fn default_base_delay_ms() -> u64 {
156 500
157}
158
159fn default_max_delay_ms() -> u64 {
160 30_000
161}
162
163impl From<&RetryProviderConfig> for crate::llm::retry::RetryConfig {
164 fn from(r: &RetryProviderConfig) -> Self {
165 Self {
166 max_retries: r.max_retries,
167 base_delay: Duration::from_millis(r.base_delay_ms),
168 max_delay: Duration::from_millis(r.max_delay_ms),
169 }
170 }
171}