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