systemprompt_config/services/
provider_catalog.rs1use std::collections::HashMap;
14
15use systemprompt_identifiers::{ModelId, ProviderId, SecretName};
16use systemprompt_models::profile::{
17 ApiSurface, ProviderEntry, ProviderModel, ProviderRegistry, WireProtocol,
18};
19use systemprompt_models::services::ai::{ModelCapabilities, ModelLimits, ModelPricing};
20
21use crate::error::{ConfigError, ConfigResult};
22
23#[derive(Debug, Clone)]
24pub struct ProviderSpec {
25 pub name: ProviderId,
26 pub wire: WireProtocol,
27 pub surface: ApiSurface,
28 pub endpoint: String,
29 pub api_key_secret: SecretName,
30 pub extra_headers: HashMap<String, String>,
31}
32
33#[derive(Debug, Clone)]
34pub struct ModelSpec {
35 pub provider: ProviderId,
36 pub id: ModelId,
37 pub aliases: Vec<ModelId>,
38 pub upstream_model: Option<String>,
39}
40
41#[derive(Debug, Clone, Copy)]
42pub struct ProviderCatalogService;
43
44impl ProviderCatalogService {
45 pub fn upsert_provider(registry: &mut ProviderRegistry, spec: ProviderSpec) {
46 let models = registry
47 .find_provider(spec.name.as_str())
48 .map(|p| p.models.clone())
49 .unwrap_or_default();
50 registry
51 .providers
52 .retain(|p| p.name.as_str() != spec.name.as_str());
53 registry.providers.push(ProviderEntry {
54 name: spec.name,
55 wire: spec.wire,
56 surface: spec.surface,
57 endpoint: spec.endpoint,
58 api_key_secret: spec.api_key_secret,
59 extra_headers: spec.extra_headers,
60 models,
61 });
62 }
63
64 pub fn remove_provider(registry: &mut ProviderRegistry, name: &ProviderId) -> ConfigResult<()> {
65 let before = registry.providers.len();
66 registry
67 .providers
68 .retain(|p| p.name.as_str() != name.as_str());
69 if registry.providers.len() == before {
70 return Err(ConfigError::ProviderNotFound {
71 name: name.to_string(),
72 });
73 }
74 Ok(())
75 }
76
77 pub fn upsert_model(registry: &mut ProviderRegistry, spec: ModelSpec) -> ConfigResult<()> {
78 let provider = registry
79 .providers
80 .iter_mut()
81 .find(|p| p.name.as_str() == spec.provider.as_str())
82 .ok_or_else(|| ConfigError::ProviderNotFound {
83 name: spec.provider.to_string(),
84 })?;
85 provider
86 .models
87 .retain(|m| m.id.as_str() != spec.id.as_str());
88 provider.models.push(ProviderModel {
89 id: spec.id,
90 aliases: spec.aliases,
91 upstream_model: spec.upstream_model,
92 pricing: ModelPricing::default(),
93 capabilities: ModelCapabilities::default(),
94 limits: ModelLimits::default(),
95 });
96 Ok(())
97 }
98
99 pub fn remove_model(
100 registry: &mut ProviderRegistry,
101 provider_name: &ProviderId,
102 id: &ModelId,
103 ) -> ConfigResult<()> {
104 let provider = registry
105 .providers
106 .iter_mut()
107 .find(|p| p.name.as_str() == provider_name.as_str())
108 .ok_or_else(|| ConfigError::ProviderNotFound {
109 name: provider_name.to_string(),
110 })?;
111 let before = provider.models.len();
112 provider.models.retain(|m| m.id.as_str() != id.as_str());
113 if provider.models.len() == before {
114 return Err(ConfigError::ModelNotFound {
115 id: id.to_string(),
116 provider: provider_name.to_string(),
117 });
118 }
119 Ok(())
120 }
121}