use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::types::RoutingTier;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PluginConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub agents: Option<AgentsConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub features: Option<FeaturesConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mcp_servers: Option<McpServersConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub permissions: Option<PermissionsConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub magic_keywords: Option<MagicKeywordsConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub routing: Option<RoutingConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AgentsConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub uira: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub architect: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub librarian: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub explore: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frontend_engineer: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub document_writer: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub multimodal_looker: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub critic: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub analyst: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub orchestrator_sisyphus: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sisyphus_junior: Option<AgentModelConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub planner: Option<AgentModelConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AgentModelConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FeaturesConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub parallel_execution: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lsp_tools: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ast_tools: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub continuation_enforcement: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub auto_context_injection: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct McpServersConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub exa: Option<ExaConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context7: Option<Context7Config>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ExaConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub api_key: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Context7Config {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PermissionsConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_bash: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_edit: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_write: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_background_tasks: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MagicKeywordsConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub ultrawork: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub search: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub analyze: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ultrathink: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RoutingConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_tier: Option<RoutingTier>,
#[serde(skip_serializing_if = "Option::is_none")]
pub escalation_enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_escalations: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tier_models: Option<TierModelsConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub agent_overrides: Option<HashMap<String, AgentTierOverride>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub escalation_keywords: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub simplification_keywords: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TierModelsConfig {
#[serde(rename = "LOW", skip_serializing_if = "Option::is_none")]
pub low: Option<String>,
#[serde(rename = "MEDIUM", skip_serializing_if = "Option::is_none")]
pub medium: Option<String>,
#[serde(rename = "HIGH", skip_serializing_if = "Option::is_none")]
pub high: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentTierOverride {
pub tier: RoutingTier,
pub reason: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_plugin_config_default() {
let config = PluginConfig::default();
assert!(config.agents.is_none());
assert!(config.features.is_none());
}
#[test]
fn test_plugin_config_serialize() {
let config = PluginConfig {
features: Some(FeaturesConfig {
parallel_execution: Some(true),
..Default::default()
}),
..Default::default()
};
let json = serde_json::to_string(&config).unwrap();
assert!(json.contains("parallel_execution"));
}
}