Skip to main content

systemprompt_models/services/
mod.rs

1//! `services` module — see crate-level docs for context.
2
3pub mod agent_config;
4pub mod ai;
5pub mod artifacts;
6pub mod external_agent;
7pub mod frontmatter;
8pub mod hooks;
9mod includable;
10pub mod marketplace;
11pub mod mcp;
12pub mod plugin;
13pub mod runtime;
14pub mod scheduler;
15pub mod settings;
16pub mod skills;
17pub mod slack;
18pub mod system_admin;
19pub mod teams;
20mod validation;
21
22pub use includable::IncludableString;
23
24pub use agent_config::{
25    AGENT_CONFIG_FILENAME, AgentCardConfig, AgentConfig, AgentMetadataConfig, AgentProviderInfo,
26    AgentSkillConfig, AgentSummary, CapabilitiesConfig, DEFAULT_AGENT_SYSTEM_PROMPT_FILE,
27    DiskAgentConfig, OAuthConfig,
28};
29pub use ai::{
30    AiConfig, AiProviderConfig, HistoryConfig, McpConfig, ModelCapabilities, ModelDefinition,
31    ModelLimits, ModelPricing, ResilienceSettings, SamplingConfig,
32};
33pub use artifacts::{ARTIFACT_CONFIG_FILENAME, DEFAULT_ARTIFACT_CONTENT_FILE, DiskArtifactConfig};
34pub use external_agent::{ExternalAgentConfig, ExternalAgentKind};
35pub use frontmatter::{Frontmatter, split_frontmatter, strip_frontmatter};
36pub use hooks::{
37    DiskHookConfig, HOOK_CONFIG_FILENAME, HookAction, HookCategory, HookEvent, HookEventsConfig,
38    HookMatcher, HookType,
39};
40pub use marketplace::{
41    MarketplaceAccess, MarketplaceConfig, MarketplaceConfigFile, MarketplaceVisibility,
42};
43pub use mcp::McpServerSummary;
44pub use plugin::{
45    ComponentFilter, ComponentSource, PluginAuthor, PluginComponentRef, PluginConfig,
46    PluginConfigFile, PluginScript, PluginSummary, PluginVariableDef,
47};
48pub use runtime::{RuntimeStatus, ServiceType};
49pub use scheduler::*;
50pub use settings::*;
51pub use skills::{
52    DEFAULT_SKILL_CONTENT_FILE, DiskSkillConfig, SKILL_CONFIG_FILENAME, SkillConfig, SkillDetail,
53    SkillSummary, SkillsConfig,
54};
55pub use slack::{SlackAppConfig, SlackAuthzConfig};
56pub use system_admin::{SystemAdmin, SystemAdminConfig};
57pub use systemprompt_provider_contracts::{BrandingConfig, WebConfig};
58pub use teams::{TeamsAppConfig, TeamsAuthzConfig};
59
60use crate::errors::ConfigValidationError;
61use crate::mcp::Deployment;
62use serde::{Deserialize, Serialize};
63use std::collections::HashMap;
64use systemprompt_identifiers::{ExternalAgentId, MarketplaceId};
65
66/// The single canonical shape of a services config file.
67///
68/// A root config file and an include file deserialize into the same struct.
69/// `settings` is meaningful only at the root; the loader rejects an include
70/// that sets it (`ConfigLoadError::IncludeMustNotSetGlobalSettings`) rather
71/// than silently ignoring the value.
72#[derive(Debug, Clone, Default, Serialize, Deserialize)]
73#[serde(deny_unknown_fields)]
74pub struct ServicesConfig {
75    #[serde(default)]
76    pub includes: Vec<String>,
77    #[serde(default)]
78    pub settings: Settings,
79    #[serde(default)]
80    pub agents: HashMap<String, AgentConfig>,
81    #[serde(default)]
82    pub mcp_servers: HashMap<String, Deployment>,
83    #[serde(default)]
84    pub scheduler: Option<SchedulerConfig>,
85    #[serde(default)]
86    pub ai: AiConfig,
87    #[serde(default)]
88    pub web: Option<WebConfig>,
89    #[serde(default)]
90    pub plugins: HashMap<String, PluginConfig>,
91    #[serde(default)]
92    pub marketplaces: HashMap<MarketplaceId, MarketplaceConfig>,
93    #[serde(default)]
94    pub skills: SkillsConfig,
95    #[serde(default)]
96    pub external_agents: HashMap<ExternalAgentId, ExternalAgentConfig>,
97    #[serde(default)]
98    pub slack_apps: HashMap<String, SlackAppConfig>,
99    #[serde(default)]
100    pub teams_apps: HashMap<String, TeamsAppConfig>,
101}
102
103impl ServicesConfig {
104    pub fn validate(&self) -> Result<(), ConfigValidationError> {
105        self.validate_ports()?;
106        self.validate_single_default_agent()?;
107
108        for (name, agent) in &self.agents {
109            agent.validate(name)?;
110        }
111
112        for (name, mcp) in &self.mcp_servers {
113            mcp.validate(name)?;
114        }
115
116        for (name, plugin) in &self.plugins {
117            plugin.validate(name)?;
118            self.validate_plugin_bindings(name, plugin)?;
119        }
120
121        for (id, marketplace) in &self.marketplaces {
122            marketplace.validate(id.as_str())?;
123            self.validate_marketplace_bindings(id.as_str(), marketplace)?;
124        }
125
126        self.validate_default_marketplace_selector()?;
127
128        for (name, app) in &self.slack_apps {
129            app.validate(name)?;
130        }
131
132        for (name, app) in &self.teams_apps {
133            app.validate(name)?;
134        }
135
136        Ok(())
137    }
138}