collet 0.1.0

Relentless agentic coding orchestrator with zero-drop agent loops
Documentation
//! Persistence operations for knowledge snapshot serialization.

use crate::agent::swarm::knowledge::SharedKnowledge;
use crate::agent::swarm::knowledge::types::{
    BlackboardKind, KnowledgeSnapshot, SnapshotAnnouncement, SnapshotBlackboard, SnapshotFact,
    SnapshotFileRead,
};

impl SharedKnowledge {
    /// Create a serializable snapshot of the knowledge base.
    pub async fn snapshot(&self) -> KnowledgeSnapshot {
        let inner = self.inner.read().await;

        let facts = inner
            .facts
            .values()
            .map(|f| SnapshotFact {
                agent_id: f.agent_id.clone(),
                topic: f.topic.clone(),
                content: f.content.clone(),
            })
            .collect();

        let files_read = inner
            .files_read
            .values()
            .map(|f| SnapshotFileRead {
                agent_id: f.agent_id.clone(),
                path: f.path.clone(),
                summary: f.summary.clone(),
                line_count: f.line_count,
            })
            .collect();

        let announcements = inner
            .announcements
            .iter()
            .map(|a| SnapshotAnnouncement {
                agent_id: a.agent_id.clone(),
                message: a.message.clone(),
            })
            .collect();

        let blackboard = inner
            .blackboard
            .values()
            .map(|b| SnapshotBlackboard {
                key: b.key.clone(),
                value: b.value.clone(),
                author: b.author.clone(),
                kind: format!("{:?}", b.kind),
                votes_for: b.votes_for.clone(),
                votes_against: b.votes_against.clone(),
            })
            .collect();

        KnowledgeSnapshot {
            facts,
            files_read,
            announcements,
            blackboard,
        }
    }

    /// Restore knowledge base from a snapshot (re-indexes everything).
    pub async fn restore(&self, snapshot: KnowledgeSnapshot) {
        for fact in snapshot.facts {
            self.post_fact(&fact.agent_id, &fact.topic, &fact.content)
                .await;
        }
        for file in snapshot.files_read {
            self.record_file_read(&file.agent_id, &file.path, &file.summary, file.line_count)
                .await;
        }
        for ann in snapshot.announcements {
            self.announce(&ann.agent_id, &ann.message).await;
        }
        for bb in snapshot.blackboard {
            let kind = match bb.kind.as_str() {
                "Proposal" => BlackboardKind::Proposal,
                "Decision" => BlackboardKind::Decision,
                "Status" => BlackboardKind::Status,
                "Claim" => BlackboardKind::Claim,
                _ => BlackboardKind::Status,
            };
            self.post_to_blackboard(&bb.key, &bb.value, &bb.author, kind)
                .await;
            // Restore votes
            let mut inner = self.inner.write().await;
            if let Some(entry) = inner.blackboard.get_mut(&bb.key) {
                entry.votes_for = bb.votes_for;
                entry.votes_against = bb.votes_against;
            }
        }
    }

    /// Save snapshot to a JSON file.
    pub async fn save_to_file(&self, path: &std::path::Path) -> std::io::Result<()> {
        let snapshot = self.snapshot().await;
        let json = serde_json::to_string_pretty(&snapshot).map_err(std::io::Error::other)?;
        tokio::fs::write(path, json).await
    }

    /// Load snapshot from a JSON file and restore.
    pub async fn load_from_file(&self, path: &std::path::Path) -> std::io::Result<()> {
        let json = tokio::fs::read_to_string(path).await?;
        let snapshot: KnowledgeSnapshot =
            serde_json::from_str(&json).map_err(std::io::Error::other)?;
        self.restore(snapshot).await;
        Ok(())
    }
}