extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use serde::Deserialize;
#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum Strictness {
Lenient,
Balanced,
Strict,
}
#[derive(Deserialize, Debug, Clone)]
pub struct JsonSchemaSubset {
pub required: Option<Vec<String>>,
#[serde(rename = "type")]
pub schema_type: Option<String>,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum RuleConfig {
Regex { pattern: String },
Exact { value: String },
JsonSchema(JsonSchemaSubset),
}
#[derive(Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(rename_all = "snake_case")]
pub enum CountMode {
#[default]
All,
ErrorsOnly,
}
#[derive(Deserialize, Debug, Clone)]
pub struct TrajectoryGateDefaults {
#[serde(default = "default_max_repeats")]
pub max_repeats: usize,
#[serde(default)]
pub count_mode: CountMode,
}
#[derive(Deserialize, Debug, Clone)]
pub struct MicroloopDefaults {
pub trajectory_gate: TrajectoryGateDefaults,
}
#[derive(Deserialize, Debug, Clone)]
pub struct ErrorDetectionCfg {
pub json_path: Option<String>,
pub status_field: Option<String>,
pub status_not_in: Option<Vec<u16>>,
pub regex: Option<String>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct ToolTrajectoryGate {
pub max_repeats: Option<usize>,
pub count_mode: Option<CountMode>,
#[serde(default)]
pub volatile_fields: Vec<String>,
pub error_detection: Option<ErrorDetectionCfg>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct ToolConfig {
pub name: String,
pub trajectory_gate: ToolTrajectoryGate,
}
#[derive(Deserialize, Debug, Clone)]
pub struct MicroloopConfig {
#[serde(default = "default_strictness")]
pub strictness: Strictness,
#[serde(default = "default_max_repeats")]
pub max_repeats: usize,
#[serde(default)]
pub ignore_args: bool,
pub history_window: Option<usize>,
#[serde(default)]
pub rules: Vec<RuleConfig>,
pub defaults: Option<MicroloopDefaults>,
#[serde(default)]
pub tools: Vec<ToolConfig>,
}
impl MicroloopConfig {
pub fn from_yaml(yaml_str: &str) -> Result<Self, alloc::string::String> {
serde_yaml::from_str(yaml_str).map_err(|e| alloc::format!("YAML parsing error: {}", e))
}
}
fn default_strictness() -> Strictness {
Strictness::Balanced
}
fn default_max_repeats() -> usize {
3
}