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