use serde::{Deserialize, Serialize};
use crate::knowledge::KnowledgeBase;
use crate::schedule::Capability;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Workflow {
#[serde(flatten)]
pub base: KnowledgeBase,
#[serde(default)]
pub steps: Vec<Step>,
#[serde(default)]
pub variables: Vec<Variable>,
#[serde(default)]
pub source_sessions: Vec<String>,
#[serde(default)]
pub trigger: String,
#[serde(default)]
pub tools: Vec<String>,
#[serde(default)]
pub published_version: u32,
#[serde(default)]
pub permission: Permission,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub schedule: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub notify: Option<NotifyConfig>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub requires: Vec<Capability>,
}
impl std::ops::Deref for Workflow {
type Target = KnowledgeBase;
fn deref(&self) -> &KnowledgeBase {
&self.base
}
}
impl std::ops::DerefMut for Workflow {
fn deref_mut(&mut self) -> &mut KnowledgeBase {
&mut self.base
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Step {
pub order: u32,
pub description: String,
#[serde(default)]
pub command: Option<String>,
#[serde(default)]
pub tool: Option<String>,
#[serde(default)]
pub needs_approval: bool,
#[serde(default)]
pub on_failure: FailureAction,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub breakpoint: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub retry: Option<RetryConfig>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timeout_secs: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetryConfig {
pub max_retries: u32,
#[serde(default)]
pub backoff_secs: Option<u64>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum FailureAction {
Skip,
#[default]
Abort,
Retry,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Variable {
pub name: String,
#[serde(rename = "type", default)]
pub var_type: VarType,
#[serde(default)]
pub required: bool,
#[serde(default)]
pub default_value: Option<String>,
#[serde(default)]
pub description: String,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum VarType {
#[default]
String,
Path,
Url,
Number,
Bool,
Array,
}
impl std::fmt::Display for VarType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VarType::String => write!(f, "string"),
VarType::Path => write!(f, "path"),
VarType::Url => write!(f, "url"),
VarType::Number => write!(f, "number"),
VarType::Bool => write!(f, "bool"),
VarType::Array => write!(f, "array"),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum NotifyLevel {
#[default]
Silent,
Normal,
Alert,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NotifyConfig {
#[serde(default)]
pub on_success: NotifyLevel,
#[serde(default = "default_alert")]
pub on_failure: NotifyLevel,
#[serde(default = "default_normal")]
pub on_anomaly: NotifyLevel,
}
fn default_alert() -> NotifyLevel {
NotifyLevel::Alert
}
fn default_normal() -> NotifyLevel {
NotifyLevel::Normal
}
impl Default for NotifyConfig {
fn default() -> Self {
Self {
on_success: NotifyLevel::Silent,
on_failure: NotifyLevel::Alert,
on_anomaly: NotifyLevel::Normal,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Permission {
#[default]
Read,
Write,
#[serde(rename = "execute_only")]
ExecuteOnly,
}