1pub mod config;
7pub mod credentials;
8pub mod provider;
9mod runtime;
10pub mod thinking;
11pub mod values;
12
13pub use provider::{ResolveError, ResolvedModel, RuntimeFactories as ProviderRegistry};
14pub use runtime::{ModelIdentity, ModelSelection, Runtime, RuntimeSnapshot};
15pub use values::ValueSource;
16
17#[derive(Clone)]
19pub struct ProviderDeclaration {
20 pub id: String,
21 pub models: Vec<rpi_ai::Model>,
22 pub api_key_env: Option<String>,
23 pub requires_auth: bool,
24}
25
26#[derive(Clone, Default, serde::Deserialize)]
28#[serde(rename_all = "camelCase")]
29pub struct RuntimeSettings {
30 pub default_provider: Option<String>,
31 pub default_model: Option<String>,
32 pub default_thinking_level: Option<String>,
33 pub theme: Option<String>,
35 pub http_idle_timeout_ms: Option<i64>,
36}
37
38#[derive(Default)]
40pub struct ModelRequest<'a> {
41 pub provider: Option<&'a str>,
42 pub api: Option<rpi_ai::Api>,
44 pub model: Option<&'a str>,
45 pub thinking: Option<rpi_ai::ThinkingLevel>,
46 pub api_key: Option<&'a str>,
47 pub base_url: Option<&'a str>,
48}
49
50#[derive(Clone, Default)]
53pub struct RuntimeConfig {
54 pub models: config::ModelsConfig,
55 pub credentials: config::AuthStore,
56 pub settings: RuntimeSettings,
57}
58
59impl RuntimeConfig {
60 pub fn auth_states(
62 &self,
63 providers: &ProviderRegistry,
64 values: &dyn ValueSource,
65 ) -> std::collections::BTreeMap<String, credentials::AuthState> {
66 let mut ids: std::collections::BTreeSet<String> = provider::builtin_catalog()
67 .into_iter()
68 .map(|model| model.provider)
69 .collect();
70 ids.extend(self.models.providers.keys().cloned());
71 ids.extend(self.credentials.keys().cloned());
72 ids.extend(
73 providers
74 .manifests
75 .iter()
76 .map(|manifest| manifest.id.clone()),
77 );
78 ids.into_iter()
79 .map(|id| {
80 let state = self.auth_status(&id, providers, values);
81 (id, state)
82 })
83 .collect()
84 }
85 pub fn auth_status(
87 &self,
88 provider: &str,
89 providers: &ProviderRegistry,
90 values: &dyn ValueSource,
91 ) -> credentials::AuthState {
92 credentials::state(
93 provider,
94 self.models.providers.get(provider),
95 &self.credentials,
96 providers
97 .manifests
98 .iter()
99 .find(|manifest| manifest.id == provider),
100 values,
101 || {
102 provider::provider_has_auth_headers(
103 provider,
104 &self.models,
105 &providers.manifests,
106 values,
107 )
108 },
109 )
110 }
111 pub fn resolve(
114 &self,
115 request: &ModelRequest<'_>,
116 providers: &ProviderRegistry,
117 values: &dyn ValueSource,
118 ) -> Result<ResolvedModel, ResolveError> {
119 provider::resolve_with_factories(request, self, providers, values)
120 }
121
122 pub fn catalog(
125 &self,
126 providers: &ProviderRegistry,
127 values: &dyn ValueSource,
128 ) -> (Vec<rpi_ai::Model>, Vec<String>) {
129 provider::catalog_with_diagnostics(self.models.clone(), &providers.manifests, values)
130 }
131}
132
133#[cfg(test)]
134mod test_host;