use anyhow::Result;
use tokio::sync::mpsc;
use crate::cancel::CancellationToken;
use crate::event::AgentEvent;
pub struct SessionManager {
cancel_token: Option<CancellationToken>,
event_tx: mpsc::Sender<AgentEvent>,
ask_rx: Option<mpsc::Receiver<String>>,
pending_input_rx: Option<mpsc::Receiver<String>>,
}
impl SessionManager {
pub fn new(event_tx: mpsc::Sender<AgentEvent>) -> Self {
Self {
cancel_token: None,
event_tx,
ask_rx: None,
pending_input_rx: None,
}
}
pub fn with_channels(
event_tx: mpsc::Sender<AgentEvent>,
ask_rx: Option<mpsc::Receiver<String>>,
) -> Self {
Self {
cancel_token: None,
event_tx,
ask_rx,
pending_input_rx: None,
}
}
pub fn with_pending_input(
event_tx: mpsc::Sender<AgentEvent>,
pending_input_rx: Option<mpsc::Receiver<String>>,
) -> Self {
Self {
cancel_token: None,
event_tx,
ask_rx: None,
pending_input_rx,
}
}
pub fn with_all_channels(
event_tx: mpsc::Sender<AgentEvent>,
ask_rx: Option<mpsc::Receiver<String>>,
pending_input_rx: Option<mpsc::Receiver<String>>,
) -> Self {
Self {
cancel_token: None,
event_tx,
ask_rx,
pending_input_rx,
}
}
pub fn emit(&self, event: AgentEvent) -> Result<()> {
self.event_tx
.try_send(event)
.map_err(|e| anyhow::anyhow!("Failed to emit event: {}", e))?;
Ok(())
}
pub fn is_cancelled(&self) -> bool {
self.cancel_token
.as_ref()
.map(|t| t.is_cancelled())
.unwrap_or(false)
}
pub fn set_cancel_token(&mut self, token: CancellationToken) {
self.cancel_token = Some(token);
}
pub fn cancel_token(&self) -> Option<&CancellationToken> {
self.cancel_token.as_ref()
}
pub fn set_ask_channel(&mut self, rx: mpsc::Receiver<String>) {
self.ask_rx = Some(rx);
}
pub fn has_ask_channel(&self) -> bool {
self.ask_rx.is_some()
}
pub fn ask_rx(&mut self) -> Option<&mut mpsc::Receiver<String>> {
self.ask_rx.as_mut()
}
pub fn set_pending_input_channel(&mut self, rx: mpsc::Receiver<String>) {
self.pending_input_rx = Some(rx);
}
pub fn pending_input_rx(&mut self) -> Option<&mut mpsc::Receiver<String>> {
self.pending_input_rx.as_mut()
}
pub fn drain_pending_inputs(&mut self) -> Vec<String> {
let mut inputs = Vec::new();
if let Some(rx) = &mut self.pending_input_rx {
while let Ok(msg) = rx.try_recv() {
inputs.push(msg);
}
}
inputs
}
pub fn event_sender(&self) -> mpsc::Sender<AgentEvent> {
self.event_tx.clone()
}
pub fn clear(&mut self) {
self.cancel_token = None;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_session_new_creates_empty_session() {
let (tx, _rx) = mpsc::channel(100);
let session = SessionManager::new(tx);
assert!(session.cancel_token.is_none());
assert!(session.ask_rx.is_none());
assert!(!session.is_cancelled());
}
#[test]
fn test_session_emit_sends_event() {
let (tx, mut rx) = mpsc::channel(100);
let session = SessionManager::new(tx);
let event = AgentEvent::session_started();
session.emit(event).unwrap();
let received = rx.try_recv();
assert!(received.is_ok(), "should receive emitted event");
}
#[test]
fn test_session_set_cancel_token() {
let (tx, _rx) = mpsc::channel(100);
let mut session = SessionManager::new(tx);
let token = CancellationToken::new();
session.set_cancel_token(token.clone());
assert!(session.cancel_token().is_some());
assert!(!session.is_cancelled());
token.cancel();
assert!(session.is_cancelled());
}
#[test]
fn test_session_set_ask_channel() {
let (tx, _rx) = mpsc::channel(100);
let (ask_tx, ask_rx) = mpsc::channel(10);
let mut session = SessionManager::new(tx);
session.set_ask_channel(ask_rx);
assert!(session.ask_rx().is_some());
ask_tx.try_send("test response".to_string()).unwrap();
let response = session.ask_rx().unwrap().try_recv();
assert!(response.is_ok(), "should receive ask response");
}
#[test]
fn test_session_event_sender_can_clone() {
let (tx, _rx) = mpsc::channel(100);
let session = SessionManager::new(tx);
let sender = session.event_sender();
sender.try_send(AgentEvent::session_started()).unwrap();
}
#[test]
fn test_session_clear_reset_cancellation() {
let (tx, _rx) = mpsc::channel(100);
let mut session = SessionManager::new(tx);
let token = CancellationToken::new();
session.set_cancel_token(token);
session.clear();
assert!(session.cancel_token().is_none());
assert!(!session.is_cancelled());
}
}