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