Skip to main content

honcho_ai/types/
dream.rs

1//! Dream API types — background memory consolidation scheduling.
2
3use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7/// Types of dreams that can be triggered.
8#[non_exhaustive]
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum DreamType {
11    /// Omni dream — consolidate all observations.
12    #[serde(rename = "omni")]
13    Omni,
14    /// Unknown dream type — forward-compatibility catch-all for unrecognised variants.
15    #[serde(other, rename = "unknown")]
16    Unknown,
17}
18
19/// Request to schedule a dream task.
20///
21/// Maps `ScheduleDreamRequest` from the `OpenAPI` spec.
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, bon::Builder)]
23#[non_exhaustive]
24#[builder(derive(Debug), on(String, into))]
25#[builder(finish_fn = build)]
26pub struct ScheduleDreamRequest {
27    /// Observer peer name.
28    pub observer: String,
29    /// Type of dream to schedule.
30    #[builder(default = DreamType::Omni)]
31    pub dream_type: DreamType,
32    /// Observed peer name (defaults to observer if not specified).
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub observed: Option<String>,
35    /// Session ID to scope the dream to.
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub session_id: Option<String>,
38}
39
40/// Status for a specific session within the processing queue.
41///
42/// Maps `SessionQueueStatus` from the `OpenAPI` spec.
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44#[non_exhaustive]
45pub struct SessionQueueStatus {
46    /// Session ID if filtered by session.
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub session_id: Option<String>,
49    /// Total work units.
50    pub total_work_units: u64,
51    /// Completed work units (since last periodic cleanup).
52    pub completed_work_units: u64,
53    /// Work units currently being processed.
54    pub in_progress_work_units: u64,
55    /// Work units waiting to be processed.
56    pub pending_work_units: u64,
57}
58
59/// Aggregated processing queue status.
60///
61/// Tracks user-facing task types only: representation, summary, and dream.
62/// Internal infrastructure tasks (reconciler, webhook, deletion) are excluded.
63///
64/// Maps `QueueStatus` from the `OpenAPI` spec.
65#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66#[non_exhaustive]
67pub struct QueueStatus {
68    /// Total work units.
69    pub total_work_units: u64,
70    /// Completed work units (since last periodic cleanup).
71    pub completed_work_units: u64,
72    /// Work units currently being processed.
73    pub in_progress_work_units: u64,
74    /// Work units waiting to be processed.
75    pub pending_work_units: u64,
76    /// Per-session status when not filtered by session.
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub sessions: Option<HashMap<String, SessionQueueStatus>>,
79}
80
81#[cfg(test)]
82#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic, missing_docs)]
83mod tests {
84    use std::collections::HashSet;
85
86    use serde_json::json;
87
88    use super::*;
89
90    #[test]
91    fn dream_type_unknown_catches_future_variants() {
92        // Any unrecognised wire string must deserialise to Unknown, not Err.
93        let got: DreamType = serde_json::from_value(json!("some_future_dream")).unwrap();
94        assert_eq!(got, DreamType::Unknown);
95    }
96
97    #[test]
98    fn dream_type_omni_roundtrips_exact_wire_string() {
99        // Must still produce "omni" — unchanged from the previous rename_all = "lowercase" encoding.
100        assert_eq!(serde_json::to_string(&DreamType::Omni).unwrap(), "\"omni\"");
101        let got: DreamType = serde_json::from_value(json!("omni")).unwrap();
102        assert_eq!(got, DreamType::Omni);
103    }
104
105    #[test]
106    fn dream_type_is_hashable() {
107        // Validates the new Hash derive; duplicate insertion must be deduplicated.
108        let mut set = HashSet::new();
109        set.insert(DreamType::Omni);
110        set.insert(DreamType::Unknown);
111        set.insert(DreamType::Omni); // duplicate — should not grow the set
112        assert_eq!(set.len(), 2);
113    }
114}