use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use tokio::sync::mpsc;
#[derive(Clone, Debug)]
pub enum ThoughtFragment {
Context(String),
Hypothesis(String),
Action(String),
Result(String),
Process(String),
Insight(String),
Question(String),
}
#[derive(Clone)]
pub struct Thought {
pub fragment: ThoughtFragment,
pub timestamp: Instant,
pub correlation_id: String,
}
#[derive(Clone)]
pub struct ThoughtStreamer {
thoughts: Arc<Mutex<Vec<Thought>>>,
max_thoughts: usize,
output_mode: OutputMode,
tx: Option<tokio::sync::mpsc::UnboundedSender<Thought>>,
rx: Option<Arc<Mutex<Option<tokio::sync::mpsc::UnboundedReceiver<Thought>>>>>,
}
#[derive(Clone)]
pub enum OutputMode {
Verbose,
Selective,
Minimal,
Streaming,
}
impl Default for OutputMode {
fn default() -> Self {
OutputMode::Selective
}
}
impl Default for ThoughtStreamer {
fn default() -> Self {
let (tx, rx) = mpsc::unbounded_channel();
Self {
thoughts: Arc::new(Mutex::new(Vec::new())),
max_thoughts: 100,
output_mode: OutputMode::default(),
tx: Some(tx),
rx: Some(Arc::new(Mutex::new(Some(rx)))),
}
}
}
impl ThoughtStreamer {
pub fn new() -> Self {
Self::default()
}
pub fn with_output_mode(mode: OutputMode) -> Self {
let (tx, rx) = mpsc::unbounded_channel();
Self {
thoughts: Arc::new(Mutex::new(Vec::new())),
max_thoughts: 100,
output_mode: mode,
tx: Some(tx),
rx: Some(Arc::new(Mutex::new(Some(rx)))),
}
}
pub fn emit(&self, fragment: ThoughtFragment) {
let thought = Thought {
fragment: fragment.clone(),
timestamp: Instant::now(),
correlation_id: uuid::Uuid::new_v4().to_string(),
};
if let Ok(mut thoughts) = self.thoughts.lock() {
thoughts.push(thought.clone());
if thoughts.len() > self.max_thoughts {
thoughts.remove(0);
}
}
match &self.output_mode {
OutputMode::Verbose => {
self.display_thought(&thought);
},
OutputMode::Selective => {
match &thought.fragment {
ThoughtFragment::Action(_) |
ThoughtFragment::Result(_) |
ThoughtFragment::Insight(_) => {
self.display_thought(&thought);
},
_ => {
}
}
},
OutputMode::Minimal => {
if matches!(&thought.fragment, ThoughtFragment::Result(_)) {
self.display_thought(&thought);
}
},
OutputMode::Streaming => {
self.display_thought_streaming(&thought);
}
}
if let Some(tx) = &self.tx {
let _ = tx.send(thought);
}
}
fn display_thought_streaming(&self, thought: &Thought) {
match &thought.fragment {
ThoughtFragment::Context(msg) => println!("⏳ [{}] Context: {}", self.format_duration(thought.timestamp.elapsed()), msg),
ThoughtFragment::Hypothesis(msg) => println!("🔍 [{}] Considering: {}", self.format_duration(thought.timestamp.elapsed()), msg),
ThoughtFragment::Action(msg) => println!("⚙️ [{}] Executing: {}", self.format_duration(thought.timestamp.elapsed()), msg),
ThoughtFragment::Result(msg) => println!("✅ [{}] Completed: {}", self.format_duration(thought.timestamp.elapsed()), msg),
ThoughtFragment::Process(msg) => println!("🔄 [{}] Processing: {}", self.format_duration(thought.timestamp.elapsed()), msg),
ThoughtFragment::Insight(msg) => println!("💡 [{}] Insight: {}", self.format_duration(thought.timestamp.elapsed()), msg),
ThoughtFragment::Question(msg) => println!("❓ [{}] Question: {}", self.format_duration(thought.timestamp.elapsed()), msg),
}
}
fn display_thought(&self, thought: &Thought) {
match &thought.fragment {
ThoughtFragment::Context(msg) => println!("📚 Context: {}", msg),
ThoughtFragment::Hypothesis(msg) => println!("🧠 Hypothesis: {}", msg),
ThoughtFragment::Action(msg) => println!("⚙️ Action: {}", msg),
ThoughtFragment::Result(msg) => println!("✅ Result: {}", msg),
ThoughtFragment::Process(msg) => println!("🔄 Process: {}", msg),
ThoughtFragment::Insight(msg) => println!("💡 Insight: {}", msg),
ThoughtFragment::Question(msg) => println!("❓ Question: {}", msg),
}
}
fn format_duration(&self, duration: Duration) -> String {
if duration.as_millis() < 1000 {
format!("{}ms", duration.as_millis())
} else {
format!("{:.1}s", duration.as_secs_f64())
}
}
pub fn get_recent_thoughts(&self, count: usize) -> Vec<Thought> {
if let Ok(thoughts) = self.thoughts.lock() {
thoughts.iter()
.rev()
.take(count)
.cloned()
.collect()
} else {
Vec::new()
}
}
pub fn get_thoughts_by_type(&self, fragment_type: &str) -> Vec<Thought> {
if let Ok(thoughts) = self.thoughts.lock() {
thoughts.iter()
.filter(|thought| {
matches!(
(&thought.fragment, fragment_type),
(ThoughtFragment::Context(_), "context") |
(ThoughtFragment::Hypothesis(_), "hypothesis") |
(ThoughtFragment::Action(_), "action") |
(ThoughtFragment::Result(_), "result") |
(ThoughtFragment::Process(_), "process") |
(ThoughtFragment::Insight(_), "insight") |
(ThoughtFragment::Question(_), "question")
)
})
.cloned()
.collect()
} else {
Vec::new()
}
}
pub fn clear_thoughts(&self) {
if let Ok(mut thoughts) = self.thoughts.lock() {
thoughts.clear();
}
}
pub fn thought_count(&self) -> usize {
if let Ok(thoughts) = self.thoughts.lock() {
thoughts.len()
} else {
0
}
}
pub fn summary(&self) -> String {
let thoughts = self.get_recent_thoughts(10);
let action_count = thoughts.iter()
.filter(|t| matches!(t.fragment, ThoughtFragment::Action(_)))
.count();
let result_count = thoughts.iter()
.filter(|t| matches!(t.fragment, ThoughtFragment::Result(_)))
.count();
format!("Recent thinking: {} actions, {} results", action_count, result_count)
}
}