Config Extension
Add configuration namespaces and validation to your extension.
On this page
Extensions add configuration via config_prefix(), config_schema(), and validate_config().
Configuration Prefix
fn config_prefix(&self) -> Option<&str> {
Some("my_extension")
}
Configuration is loaded from profile.yaml:
extensions:
my_extension:
enabled: true
max_items: 100
api_url: "https://api.example.com"
Configuration Schema
Define JSON Schema for your configuration:
fn config_schema(&self) -> Option<JsonValue> {
Some(json!({
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": true
},
"max_items": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"default": 100
},
"api_url": {
"type": "string",
"format": "uri"
}
},
"required": ["api_url"]
}))
}
Custom Validation
fn validate_config(&self, config: &JsonValue) -> Result<(), ConfigError> {
// Check max_items limit
if let Some(max) = config.get("max_items").and_then(|v| v.as_i64()) {
if max > 10000 {
return Err(ConfigError::InvalidValue {
key: "max_items".into(),
message: "Value cannot exceed 10000".into(),
});
}
}
// Check API URL is reachable
if let Some(url) = config.get("api_url").and_then(|v| v.as_str()) {
if !url.starts_with("https://") {
return Err(ConfigError::InvalidValue {
key: "api_url".into(),
message: "API URL must use HTTPS".into(),
});
}
}
Ok(())
}
ConfigError
pub enum ConfigError {
NotFound(String),
InvalidValue { key: String, message: String },
ParseError(String),
SchemaValidation(String),
}
Typed Configuration
Use the type-state pattern for validated configuration:
use serde::Deserialize;
use std::path::PathBuf;
// Raw config from YAML
#[derive(Debug, Deserialize)]
pub struct MyConfigRaw {
pub data_path: String,
pub api_url: String,
pub max_items: Option<u32>,
}
// Validated config with parsed types
#[derive(Debug, Clone)]
pub struct MyConfigValidated {
pub data_path: PathBuf,
pub api_url: url::Url,
pub max_items: u32,
}
impl MyConfigValidated {
pub fn validate(raw: MyConfigRaw, base_path: &Path) -> Result<Self, ConfigError> {
let data_path = base_path.join(&raw.data_path);
if !data_path.exists() {
return Err(ConfigError::InvalidValue {
key: "data_path".into(),
message: format!("Path does not exist: {}", data_path.display()),
});
}
let api_url = url::Url::parse(&raw.api_url)
.map_err(|e| ConfigError::InvalidValue {
key: "api_url".into(),
message: e.to_string(),
})?;
Ok(Self {
data_path,
api_url,
max_items: raw.max_items.unwrap_or(100),
})
}
}
Typed Extension
use systemprompt::extension::prelude::ConfigExtensionTyped;
impl ConfigExtensionTyped for MyExtension {
fn config_prefix(&self) -> &'static str {
"my_extension"
}
fn validate_config(&self, config: &JsonValue) -> Result<(), ConfigError> {
// Custom validation
Ok(())
}
fn config_schema(&self) -> Option<JsonValue> {
Some(json!({ /* schema */ }))
}
}