systemprompt_cloud/profile_authoring/
local_builder.rs1use std::path::Path;
7
8use systemprompt_identifiers::{Email, TenantId};
9use systemprompt_loader::ExtensionLoader;
10use systemprompt_manifest::profile::{
11 ProfileResult, SecretsConfig, SecretsSource, SecretsValidationMode,
12};
13use systemprompt_manifest::services::SystemAdminConfig;
14use systemprompt_manifest::{
15 CloudConfig, CloudValidationMode, ExtensionsConfig, HostingProvider, PathsConfig, Profile,
16 ProfileDatabaseConfig, ProfileType, RateLimitsConfig, ServerConfig, SiteConfig,
17};
18
19use super::{generate_display_name, local_runtime_config, security_config, webhook_governance};
20use crate::constants::profile as consts;
21use crate::paths::ProjectContext;
22
23#[derive(Debug)]
24pub struct LocalProfileBuilder {
25 name: String,
26 tenant_id: Option<TenantId>,
27 secrets_path: String,
28 services_path: String,
29}
30
31impl LocalProfileBuilder {
32 pub fn new(
33 name: impl Into<String>,
34 secrets_path: impl AsRef<Path>,
35 services_path: impl AsRef<Path>,
36 ) -> Self {
37 Self {
38 name: name.into(),
39 tenant_id: None,
40 secrets_path: secrets_path.as_ref().to_string_lossy().to_string(),
41 services_path: services_path.as_ref().to_string_lossy().to_string(),
42 }
43 }
44
45 #[must_use]
46 pub fn with_tenant_id(mut self, tenant_id: TenantId) -> Self {
47 self.tenant_id = Some(tenant_id);
48 self
49 }
50
51 pub fn build(self) -> ProfileResult<Profile> {
52 let ctx = ProjectContext::discover();
53 let root = ctx.root();
54 let system_path = root.to_string_lossy().to_string();
55 let display_name = generate_display_name(&self.name);
56 let local_url = format!("http://localhost:{}", consts::DEFAULT_PORT);
57
58 let mut profile = Profile {
59 storage: systemprompt_manifest::profile::StorageConfig::default(),
60 observability: systemprompt_manifest::profile::ObservabilityConfig::default(),
61 config_planes: systemprompt_manifest::profile::ConfigPlanesConfig::default(),
62 licence: systemprompt_manifest::profile::LicenceConfig::default(),
63 notifications: systemprompt_manifest::profile::NotificationsProfile::default(),
64 name: self.name,
65 display_name,
66 target: ProfileType::Local,
67 site: SiteConfig {
68 name: "systemprompt.io".to_owned(),
69 github_link: None,
70 },
71 database: ProfileDatabaseConfig {
72 db_type: consts::DEFAULT_DB_TYPE.to_owned(),
73 external_db_access: false,
74 migrate_on_boot: true,
75 pool: None,
76 },
77 security: security_config(Vec::new(), true),
78 server: local_server_config(local_url),
79 paths: PathsConfig {
80 root: None,
81 system: system_path,
82 services: self.services_path,
83 bin: ExtensionLoader::resolve_bin_directory(root, None)
84 .to_string_lossy()
85 .to_string(),
86 storage: Some(ctx.storage_dir().to_string_lossy().to_string()),
87 geoip_database: None,
88 data: None,
89 web_path: None,
90 shipped_files: None,
91 },
92 rate_limits: RateLimitsConfig {
93 disabled: true,
94 ..Default::default()
95 },
96 runtime: local_runtime_config(),
97 cloud: Some(CloudConfig {
98 tenant_id: self.tenant_id,
99 provider: HostingProvider::DockerLocal,
100 validation: CloudValidationMode::Warn,
101 deploy: None,
102 operator: None,
103 }),
104 secrets: Some(SecretsConfig {
105 secrets_path: Some(self.secrets_path),
106 validation: SecretsValidationMode::Warn,
107 source: SecretsSource::File,
108 vault: None,
109 external: None,
110 refresh_secs: None,
111 }),
112 extensions: ExtensionsConfig::default(),
113 governance: Some(webhook_governance()),
114 services: systemprompt_manifest::profile::ServicesProfileConfig::default(),
115 judge: systemprompt_manifest::profile::JudgeProfile::default(),
116 retention: systemprompt_manifest::profile::RetentionConfig::default(),
117 system_admin: SystemAdminConfig {
118 username: "admin".to_owned(),
119 email: Some(Email::local_admin()),
120 },
121 };
122 profile.derive_fields()?;
123 Ok(profile)
124 }
125}
126
127fn local_server_config(local_url: String) -> ServerConfig {
128 let mut server = ServerConfig::new(consts::LOCAL_HOST, consts::DEFAULT_PORT, local_url);
129 server.extra_cors_origins = vec!["http://localhost:5173".to_owned()];
130 server.role = systemprompt_manifest::profile::NodeRole::All;
131 server.trusted_proxies =
132 crate::trusted_proxies::default_trusted_proxies(HostingProvider::DockerLocal);
133 server
134}