Skip to main content

systemprompt_extension/
context.rs

1//! Runtime context handed to extensions during router resolution.
2//!
3//! Beyond config, database and storage, the context carries the
4//! cross-replica seams core owns: [`ExtensionContext::instances`] answers
5//! whether a replica is alive, [`ExtensionContext::leases`] hands out
6//! expiring single-owner claims, and [`ExtensionContext::advisory_locks`]
7//! takes session-scoped locks on the session pool. A context without a
8//! database refuses all three through [`UnavailableCoordination`].
9//!
10//! [`ExtensionContext::secret`] reads an operator-provisioned custom secret
11//! from the platform secrets document, so an extension never reads its
12//! credentials from the process environment; [`ExtensionContext::instance_id`]
13//! is the node identity in place of `HOSTNAME`.
14//!
15//! Copyright (c) systemprompt.io — Business Source License 1.1.
16//! See <https://systemprompt.io> for licensing details.
17
18use std::sync::Arc;
19use systemprompt_identifiers::InstanceId;
20use systemprompt_provider_contracts::{ConfigPlaneError, ConfigPlaneResult, ConfigPlaneSet};
21use systemprompt_traits::{
22    ConfigProvider, DatabaseHandle, DynAdvisoryLocks, DynInstanceRegistry, DynLeaseRepository,
23    ExtensionSecret, FileStorage, UnavailableCoordination,
24};
25
26pub trait ExtensionContext: Send + Sync {
27    fn system_owner_id(&self) -> systemprompt_identifiers::UserId;
28
29    fn config(&self) -> Arc<dyn ConfigProvider>;
30
31    fn database(&self) -> Arc<dyn DatabaseHandle>;
32
33    fn file_storage(&self) -> Arc<dyn FileStorage>;
34
35    fn instance_id(&self) -> InstanceId;
36
37    fn instances(&self) -> DynInstanceRegistry {
38        Arc::new(UnavailableCoordination)
39    }
40
41    fn leases(&self) -> DynLeaseRepository {
42        Arc::new(UnavailableCoordination)
43    }
44
45    fn advisory_locks(&self) -> DynAdvisoryLocks {
46        Arc::new(UnavailableCoordination)
47    }
48
49    fn secret(&self, _name: &str) -> Option<ExtensionSecret> {
50        None
51    }
52
53    fn get_extension(&self, id: &str) -> Option<Arc<dyn crate::Extension>>;
54
55    fn has_extension(&self, id: &str) -> bool {
56        self.get_extension(id).is_some()
57    }
58
59    fn config_planes(&self) -> ConfigPlaneResult<ConfigPlaneSet> {
60        Err(ConfigPlaneError::PlanesUnavailable)
61    }
62}
63
64pub type DynExtensionContext = Arc<dyn ExtensionContext>;