use crate::types::AgenticConfig;
use schemars::Schema;
use schemars::generate::SchemaSettings;
pub fn schema() -> Schema {
SchemaSettings::default()
.into_generator()
.into_root_schema_for::<AgenticConfig>()
}
pub fn schema_json_pretty() -> anyhow::Result<String> {
Ok(serde_json::to_string_pretty(&schema())?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_schema_is_valid_json() {
let json = schema_json_pretty().unwrap();
let _: serde_json::Value = serde_json::from_str(&json).unwrap();
}
#[test]
fn test_schema_has_required_properties() {
let schema = schema();
let json = serde_json::to_value(&schema).unwrap();
assert!(json.get("$defs").is_some() || json.get("definitions").is_some());
let orchestrator_properties = &json["$defs"]["OrchestratorConfig"]["properties"];
assert!(orchestrator_properties.get("commands").is_some());
let command_properties = &json["$defs"]["OrchestratorCommandsConfig"]["properties"];
assert!(command_properties.get("allow").is_some());
assert!(command_properties.get("deny").is_some());
let subagents_properties = &json["$defs"]["SubagentsConfig"]["properties"];
assert!(subagents_properties.get("runtime_timeout_secs").is_some());
let cli_tools_properties = &json["$defs"]["CliToolsConfig"]["properties"];
assert!(
cli_tools_properties
.get("just_execute_timeout_secs")
.is_some()
);
assert!(
cli_tools_properties
.get("just_search_timeout_secs")
.is_some()
);
let services_properties = &json["$defs"]["ServicesConfig"]["properties"];
assert!(services_properties.get("linear").is_some());
assert!(services_properties.get("github").is_some());
let review_properties = &json["$defs"]["ReviewConfig"]["properties"];
assert!(review_properties.get("run_timeout_secs").is_some());
let thoughts_properties = &json["$defs"]["ThoughtsConfig"]["properties"];
assert!(
thoughts_properties
.get("add_reference_timeout_secs")
.is_some()
);
}
#[test]
fn test_schema_excludes_secrets() {
let json = schema_json_pretty().unwrap();
assert!(!json.contains("\"api_key\""));
}
#[test]
fn test_default_config_validates_against_schema() {
let schema = schema();
let config = AgenticConfig::default();
let config_json = serde_json::to_value(&config).unwrap();
let validator = jsonschema::validator_for(&serde_json::to_value(&schema).unwrap()).unwrap();
let result = validator.validate(&config_json);
assert!(
result.is_ok(),
"Default config should validate against schema: {:?}",
result.err()
);
}
#[test]
fn test_partial_config_validates_against_schema() {
let schema = schema();
let config_json = serde_json::json!({
"subagents": {
"locator_model": "claude-haiku-4-5"
}
});
let validator = jsonschema::validator_for(&serde_json::to_value(&schema).unwrap()).unwrap();
let result = validator.validate(&config_json);
assert!(
result.is_ok(),
"Partial config should validate against schema: {:?}",
result.err()
);
}
}