Skip to main content

vtcode_core/diagnostics/
recovery.rs

1use std::sync::Arc;
2
3use anyhow::Result;
4use async_trait::async_trait;
5
6/// Recovery action executed when a degradation is detected.
7#[async_trait]
8pub trait RecoveryAction: Send + Sync {
9    async fn execute(&self) -> Result<()>;
10    fn name(&self) -> &'static str;
11}
12
13/// Composite set of recovery actions.
14#[derive(Default, Clone)]
15pub struct RecoveryPlaybook {
16    actions: Vec<Arc<dyn RecoveryAction>>,
17}
18
19impl RecoveryPlaybook {
20    pub fn new(actions: Vec<Arc<dyn RecoveryAction>>) -> Self {
21        Self { actions }
22    }
23
24    pub fn with_action(mut self, action: Arc<dyn RecoveryAction>) -> Self {
25        self.actions.push(action);
26        self
27    }
28
29    pub async fn execute_all(&self) -> Result<Vec<String>> {
30        let mut results = Vec::new();
31        for action in &self.actions {
32            action.execute().await?;
33            results.push(action.name().to_string());
34        }
35        Ok(results)
36    }
37}
38
39/// Simple recovery action that records a label (for testing/demo).
40pub struct LabeledAction {
41    label: &'static str,
42}
43
44impl LabeledAction {
45    pub fn new(label: &'static str) -> Self {
46        Self { label }
47    }
48}
49
50#[async_trait]
51impl RecoveryAction for LabeledAction {
52    async fn execute(&self) -> Result<()> {
53        Ok(())
54    }
55
56    fn name(&self) -> &'static str {
57        self.label
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[tokio::test]
66    async fn executes_all_actions() {
67        let playbook =
68            RecoveryPlaybook::default().with_action(Arc::new(LabeledAction::new("reset")));
69        let executed = playbook.execute_all().await.expect("playbook should run");
70        assert_eq!(executed, vec!["reset".to_string()]);
71    }
72}