systemprompt_models/services/gateway/config/
mod.rs1mod runtime;
13mod validate;
14
15use serde::{Deserialize, Serialize};
16use systemprompt_identifiers::ProviderId;
17
18use crate::services::gateway::override_rule::SystemPromptRule;
19use crate::services::gateway::route::GatewayRoute;
20
21pub use runtime::GatewayConfig;
22
23pub(crate) const DEFAULT_ROUTE_PATTERN: &str = "*";
24
25#[derive(
30 Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, schemars::JsonSchema,
31)]
32#[serde(rename_all = "lowercase")]
33pub enum QuotaFaultMode {
34 #[default]
35 Open,
36 Closed,
37}
38
39impl QuotaFaultMode {
40 #[must_use]
41 pub const fn is_closed(self) -> bool {
42 matches!(self, Self::Closed)
43 }
44
45 #[must_use]
46 pub const fn as_str(self) -> &'static str {
47 match self {
48 Self::Open => "open",
49 Self::Closed => "closed",
50 }
51 }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
55#[serde(deny_unknown_fields)]
56pub struct GatewayConfigSpec {
57 #[serde(default)]
58 pub enabled: bool,
59 #[serde(default)]
60 pub routes: Vec<GatewayRoute>,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub default_provider: Option<ProviderId>,
63 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub default_model: Option<String>,
65 #[serde(default)]
66 pub allow_unlisted_models: bool,
67 #[serde(default)]
68 pub quota_fault_mode: QuotaFaultMode,
69 #[serde(default = "default_auth_scheme")]
70 pub auth_scheme: String,
71 #[serde(default = "default_inference_path_prefix")]
72 pub inference_path_prefix: String,
73 #[serde(default, skip_serializing_if = "Vec::is_empty")]
74 pub system_prompt_overrides: Vec<SystemPromptRule>,
75 #[serde(default, skip_serializing_if = "Option::is_none")]
76 pub bridge_releases: Option<BridgeReleasesSpec>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
86#[serde(deny_unknown_fields)]
87pub struct BridgeReleasesSpec {
88 pub repo: String,
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 pub token_secret: Option<String>,
91 #[serde(default = "default_tag_prefix")]
92 pub tag_prefix: String,
93 #[serde(default, skip_serializing_if = "Option::is_none")]
94 pub pinned_version: Option<String>,
95 #[serde(default)]
96 pub assets: std::collections::BTreeMap<String, String>,
97 #[serde(default, skip_serializing_if = "Option::is_none")]
98 pub api_base: Option<String>,
99}
100
101impl BridgeReleasesSpec {
102 #[must_use]
103 pub fn api_base(&self) -> &str {
104 self.api_base.as_deref().unwrap_or("https://api.github.com")
105 }
106}
107
108fn default_tag_prefix() -> String {
109 "bridge-v".to_owned()
110}
111
112impl Default for GatewayConfigSpec {
113 fn default() -> Self {
114 Self {
115 enabled: false,
116 routes: Vec::new(),
117 default_provider: None,
118 default_model: None,
119 allow_unlisted_models: false,
120 quota_fault_mode: QuotaFaultMode::default(),
121 auth_scheme: default_auth_scheme(),
122 inference_path_prefix: default_inference_path_prefix(),
123 system_prompt_overrides: Vec::new(),
124 bridge_releases: None,
125 }
126 }
127}
128
129pub(crate) fn default_auth_scheme() -> String {
130 "bearer".to_owned()
131}
132
133pub(crate) fn default_inference_path_prefix() -> String {
134 "/v1".to_owned()
135}
136
137impl GatewayConfigSpec {
138 #[must_use]
139 pub fn resolve(self) -> GatewayConfig {
140 let Self {
141 enabled,
142 routes,
143 default_provider,
144 default_model,
145 allow_unlisted_models,
146 quota_fault_mode,
147 auth_scheme,
148 inference_path_prefix,
149 system_prompt_overrides,
150 bridge_releases,
151 } = self;
152
153 GatewayConfig {
154 enabled,
155 routes,
156 default_provider,
157 default_model,
158 allow_unlisted_models,
159 quota_fault_mode,
160 auth_scheme,
161 inference_path_prefix,
162 system_prompt_overrides,
163 bridge_releases,
164 }
165 }
166}