systemprompt_runtime/context/
mod.rs1use std::sync::{Arc, OnceLock};
11
12use tokio::task::JoinHandle;
13
14use systemprompt_agent::repository::A2ARepositories;
15use systemprompt_ai::repository::AiRepositories;
16use systemprompt_analytics::repository::AnalyticsRepositories;
17use systemprompt_analytics::{AnalyticsService, FingerprintRepository, GeoIpReader};
18use systemprompt_content::repository::ContentRepositories;
19use systemprompt_database::{DbPool, ServiceRepository};
20use systemprompt_evaluation::repository::experiments::EvaluationRepositories;
21use systemprompt_extension::ExtensionRegistry;
22use systemprompt_files::FileRepository;
23use systemprompt_marketplace::MarketplaceFilter;
24use systemprompt_marketplace::managed::ManagedRepository;
25use systemprompt_mcp::repository::McpSessionRepository;
26use systemprompt_mcp::services::registry::RegistryService;
27use systemprompt_models::services::SystemAdmin;
28use systemprompt_models::{AppPaths, Config, ContentConfigRaw, ContentRouting, RouteClassifier};
29use systemprompt_oauth::repository::OAuthRepositories;
30use systemprompt_security::authz::SharedAuthzHook;
31use systemprompt_traits::FileStorage;
32use systemprompt_users::{UserRepository, UserService};
33
34mod context_loaders;
35mod debug_impls;
36mod shutdown;
37
38pub use shutdown::ShutdownRequest;
39
40use crate::builder::AppContextBuilder;
41use crate::error::RuntimeResult;
42use crate::registry::ModuleApiRegistry;
43
44#[derive(Clone)]
49pub struct DataPlane {
50 pub database: DbPool,
51 pub analytics_service: Arc<AnalyticsService>,
52 pub fingerprint_repo: Option<Arc<FingerprintRepository>>,
53 pub user_service: Option<Arc<UserService>>,
54 pub a2a_repositories: Arc<A2ARepositories>,
55 pub content_repositories: Arc<ContentRepositories>,
56 pub oauth_repositories: Arc<OAuthRepositories>,
57 pub user_repository: Arc<UserRepository>,
58 pub service_repository: Arc<ServiceRepository>,
59 pub ai_repositories: Arc<AiRepositories>,
60 pub analytics_repositories: Arc<AnalyticsRepositories>,
61 pub file_repository: Arc<FileRepository>,
62 pub mcp_session_repository: Arc<McpSessionRepository>,
63 pub managed_repository: Arc<ManagedRepository>,
64 pub evaluation_repositories: Arc<EvaluationRepositories>,
65}
66
67#[derive(Clone)]
68pub struct ConfigPlane {
69 pub config: Arc<Config>,
70 pub app_paths: Arc<AppPaths>,
71 pub content_config: Option<Arc<ContentConfigRaw>>,
72 pub route_classifier: Arc<RouteClassifier>,
73}
74
75#[derive(Clone)]
76pub struct Plugins {
77 pub extension_registry: Arc<ExtensionRegistry>,
78 pub api_registry: Arc<ModuleApiRegistry>,
79 pub mcp_registry: RegistryService,
80 pub marketplace_filter: Arc<dyn MarketplaceFilter>,
81}
82
83#[derive(Clone)]
84pub struct Subsystems {
85 pub system_admin: Arc<SystemAdmin>,
86 pub authz_hook: SharedAuthzHook,
87 pub event_bridge: Arc<OnceLock<JoinHandle<()>>>,
88 pub geoip_reader: Option<GeoIpReader>,
89 pub file_storage: Arc<dyn FileStorage>,
90 pub shutdown: ShutdownRequest,
91}
92
93#[derive(Clone)]
105pub struct AppContext {
106 pub(crate) data: DataPlane,
107 pub(crate) cfg: ConfigPlane,
108 pub(crate) plugins: Plugins,
109 pub(crate) subsystems: Subsystems,
110}
111
112impl AppContext {
113 pub async fn new() -> RuntimeResult<Self> {
114 Self::builder().build().await
115 }
116
117 #[must_use]
118 pub fn builder() -> AppContextBuilder {
119 AppContextBuilder::new()
120 }
121
122 #[must_use]
123 pub const fn from_parts(
124 data: DataPlane,
125 cfg: ConfigPlane,
126 plugins: Plugins,
127 subsystems: Subsystems,
128 ) -> Self {
129 Self {
130 data,
131 cfg,
132 plugins,
133 subsystems,
134 }
135 }
136
137 pub fn load_geoip_database(
138 config: &Config,
139 show_warnings: bool,
140 ) -> Result<Option<GeoIpReader>, crate::error::RuntimeError> {
141 context_loaders::load_geoip_database(config, show_warnings)
142 }
143
144 pub fn load_content_config(
145 config: &Config,
146 app_paths: &AppPaths,
147 ) -> Option<Arc<ContentConfigRaw>> {
148 context_loaders::load_content_config(config, app_paths)
149 }
150
151 pub fn config(&self) -> &Config {
152 &self.cfg.config
153 }
154
155 pub fn content_config(&self) -> Option<&ContentConfigRaw> {
156 self.cfg.content_config.as_ref().map(AsRef::as_ref)
157 }
158
159 pub fn content_routing(&self) -> Option<Arc<dyn ContentRouting>> {
160 let concrete = Arc::clone(self.cfg.content_config.as_ref()?);
161 let routing: Arc<dyn ContentRouting> = concrete;
162 Some(routing)
163 }
164
165 pub const fn db_pool(&self) -> &DbPool {
166 &self.data.database
167 }
168
169 pub fn api_registry(&self) -> &ModuleApiRegistry {
170 &self.plugins.api_registry
171 }
172
173 pub fn extension_registry(&self) -> &ExtensionRegistry {
174 &self.plugins.extension_registry
175 }
176
177 pub fn server_address(&self) -> String {
178 format!("{}:{}", self.cfg.config.host, self.cfg.config.port)
179 }
180
181 pub const fn geoip_reader(&self) -> Option<&GeoIpReader> {
182 self.subsystems.geoip_reader.as_ref()
183 }
184
185 pub const fn file_storage(&self) -> &Arc<dyn FileStorage> {
186 &self.subsystems.file_storage
187 }
188
189 pub const fn analytics_service(&self) -> &Arc<AnalyticsService> {
190 &self.data.analytics_service
191 }
192
193 #[must_use]
194 pub fn session_usage(&self) -> systemprompt_traits::DynSessionUsageCounters {
195 Arc::new(self.data.analytics_service.session_repo().clone())
196 }
197
198 pub fn context_materializer(&self) -> systemprompt_traits::DynContextMaterializer {
199 Arc::new(systemprompt_agent::services::ContextProviderService::new(
200 self.data.a2a_repositories.contexts.clone(),
201 ))
202 }
203
204 pub const fn a2a_repositories(&self) -> &Arc<A2ARepositories> {
205 &self.data.a2a_repositories
206 }
207
208 pub const fn content_repositories(&self) -> &Arc<ContentRepositories> {
209 &self.data.content_repositories
210 }
211
212 pub const fn oauth_repositories(&self) -> &Arc<OAuthRepositories> {
213 &self.data.oauth_repositories
214 }
215
216 pub const fn user_repository(&self) -> &Arc<UserRepository> {
217 &self.data.user_repository
218 }
219
220 pub const fn service_repository(&self) -> &Arc<ServiceRepository> {
221 &self.data.service_repository
222 }
223
224 pub const fn ai_repositories(&self) -> &Arc<AiRepositories> {
225 &self.data.ai_repositories
226 }
227
228 pub const fn analytics_repositories(&self) -> &Arc<AnalyticsRepositories> {
229 &self.data.analytics_repositories
230 }
231
232 pub const fn file_repository(&self) -> &Arc<FileRepository> {
233 &self.data.file_repository
234 }
235
236 pub const fn mcp_session_repository(&self) -> &Arc<McpSessionRepository> {
237 &self.data.mcp_session_repository
238 }
239
240 pub const fn managed_repository(&self) -> &Arc<ManagedRepository> {
241 &self.data.managed_repository
242 }
243
244 pub const fn evaluation_repositories(&self) -> &Arc<EvaluationRepositories> {
245 &self.data.evaluation_repositories
246 }
247
248 pub const fn route_classifier(&self) -> &Arc<RouteClassifier> {
249 &self.cfg.route_classifier
250 }
251
252 pub fn app_paths(&self) -> &AppPaths {
253 &self.cfg.app_paths
254 }
255
256 pub const fn app_paths_arc(&self) -> &Arc<AppPaths> {
257 &self.cfg.app_paths
258 }
259
260 pub fn marketplace_filter(&self) -> &Arc<dyn MarketplaceFilter> {
261 &self.plugins.marketplace_filter
262 }
263
264 pub const fn event_bridge(&self) -> &Arc<OnceLock<JoinHandle<()>>> {
265 &self.subsystems.event_bridge
266 }
267
268 pub fn system_admin(&self) -> &SystemAdmin {
269 &self.subsystems.system_admin
270 }
271
272 pub const fn mcp_registry(&self) -> &RegistryService {
273 &self.plugins.mcp_registry
274 }
275
276 pub const fn authz_hook(&self) -> &SharedAuthzHook {
277 &self.subsystems.authz_hook
278 }
279
280 pub const fn shutdown_request(&self) -> &ShutdownRequest {
281 &self.subsystems.shutdown
282 }
283
284 pub fn request_restart(&self, reason: &str) {
285 self.subsystems.shutdown.request(reason);
286 }
287}