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