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 providers.refreshes_oauth(provider),
102 || {
103 provider::provider_has_auth_headers(
104 provider,
105 &self.models,
106 &providers.manifests,
107 values,
108 )
109 },
110 )
111 }
112 pub fn resolve(
115 &self,
116 request: &ModelRequest<'_>,
117 providers: &ProviderRegistry,
118 values: &dyn ValueSource,
119 ) -> Result<ResolvedModel, ResolveError> {
120 provider::resolve_with_factories(request, self, providers, values)
121 }
122
123 pub fn catalog(
126 &self,
127 providers: &ProviderRegistry,
128 values: &dyn ValueSource,
129 ) -> (Vec<rpi_ai::Model>, Vec<String>) {
130 provider::catalog_with_diagnostics(self.models.clone(), &providers.manifests, values)
131 }
132}
133
134#[cfg(test)]
135mod test_host;