Skip to main content

swink_agent/
messaging.rs

1use std::sync::{Arc, Mutex};
2
3use crate::error::AgentError;
4use crate::registry::{AgentRef, AgentRegistry};
5use crate::types::AgentMessage;
6
7/// A per-agent inbox for receiving messages.
8///
9/// Wraps a `Vec<AgentMessage>` behind an `Arc<Mutex<_>>` so it can be shared
10/// between the agent owner and any senders.
11#[derive(Clone)]
12pub struct AgentMailbox {
13    inbox: Arc<Mutex<Vec<AgentMessage>>>,
14}
15
16impl AgentMailbox {
17    /// Create an empty mailbox.
18    #[must_use]
19    pub fn new() -> Self {
20        Self {
21            inbox: Arc::new(Mutex::new(Vec::new())),
22        }
23    }
24
25    /// Push a message into the mailbox.
26    pub fn send(&self, message: AgentMessage) {
27        self.inbox
28            .lock()
29            .unwrap_or_else(std::sync::PoisonError::into_inner)
30            .push(message);
31    }
32
33    /// Take all pending messages, leaving the mailbox empty.
34    pub fn drain(&self) -> Vec<AgentMessage> {
35        std::mem::take(
36            &mut *self
37                .inbox
38                .lock()
39                .unwrap_or_else(std::sync::PoisonError::into_inner),
40        )
41    }
42
43    /// Whether the mailbox has pending messages.
44    #[must_use]
45    pub fn has_messages(&self) -> bool {
46        !self
47            .inbox
48            .lock()
49            .unwrap_or_else(std::sync::PoisonError::into_inner)
50            .is_empty()
51    }
52
53    /// Number of pending messages.
54    #[must_use]
55    pub fn len(&self) -> usize {
56        self.inbox
57            .lock()
58            .unwrap_or_else(std::sync::PoisonError::into_inner)
59            .len()
60    }
61
62    /// Whether the mailbox is empty.
63    #[must_use]
64    pub fn is_empty(&self) -> bool {
65        !self.has_messages()
66    }
67}
68
69impl Default for AgentMailbox {
70    fn default() -> Self {
71        Self::new()
72    }
73}
74
75/// Send a message to a named agent via its steering queue.
76///
77/// Looks up the agent by name in the registry, acquires the lock, and calls
78/// `steer(message)` to inject the message into the agent's steering queue.
79///
80/// # Errors
81///
82/// Returns [`AgentError::Plugin`] if the agent is not found in the registry.
83pub async fn send_to(
84    registry: &AgentRegistry,
85    agent_name: &str,
86    message: AgentMessage,
87) -> Result<(), AgentError> {
88    let agent_ref: AgentRef = registry.get(agent_name).ok_or_else(|| {
89        AgentError::plugin(
90            "messaging",
91            std::io::Error::other(format!("agent not found: {agent_name}")),
92        )
93    })?;
94    agent_ref.lock().await.steer(message);
95    Ok(())
96}