Skip to main content

bob_core/
channel.rs

1//! # Channel Abstraction
2//!
3//! Multi-endpoint channel interface for the Bob Agent Framework.
4//!
5//! A **channel** is the boundary between the outside world (user) and the
6//! agent loop. Its only responsibility is receiving user input and delivering
7//! agent output — no agent logic lives here.
8//!
9//! ## Architecture
10//!
11//! ```text
12//! ┌─────────┐       ┌────────────┐       ┌───────────┐
13//! │  User   │ ───→  │  Channel   │ ───→  │ AgentLoop │
14//! │         │ ←───  │ (trait)    │ ←───  │           │
15//! └─────────┘       └────────────┘       └───────────┘
16//! ```
17//!
18//! Concrete implementations live in adapter or binary crates:
19//!
20//! | Channel      | Scenario                              |
21//! |-------------|---------------------------------------|
22//! | CLI          | One-shot `run --prompt "..."`          |
23//! | REPL         | Interactive terminal                   |
24//! | Telegram Bot | Long-polling with ACL                  |
25//! | Discord Bot  | Gateway-based with channel filtering  |
26
27use serde::{Deserialize, Serialize};
28
29/// Incoming message from a channel to the agent.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct ChannelMessage {
32    /// Raw user text (may be a slash command or natural language).
33    pub text: String,
34    /// Session identifier for conversation continuity.
35    pub session_id: String,
36    /// Optional sender identifier (username, user-id, etc.).
37    pub sender: Option<String>,
38}
39
40/// Outgoing agent response delivered back through the channel.
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct ChannelOutput {
43    /// Response text.
44    pub text: String,
45    /// Whether this output represents an error condition.
46    pub is_error: bool,
47}
48
49/// Errors that can occur during channel I/O.
50#[derive(Debug, thiserror::Error)]
51pub enum ChannelError {
52    /// Sending a message to the user failed.
53    #[error("send failed: {0}")]
54    SendFailed(String),
55    /// The channel has been closed (user disconnected, etc.).
56    #[error("channel closed")]
57    Closed,
58}
59
60/// Abstract channel for multi-endpoint agent interaction.
61///
62/// Each channel implementation handles the transport-specific details
63/// of receiving user input and delivering agent output. The agent loop
64/// is decoupled from any specific transport.
65///
66/// ## Implementing a Channel
67///
68/// ```rust,ignore
69/// use bob_core::channel::{Channel, ChannelMessage, ChannelOutput, ChannelError};
70///
71/// struct MyTelegramChannel { /* ... */ }
72///
73/// #[async_trait::async_trait]
74/// impl Channel for MyTelegramChannel {
75///     async fn recv(&mut self) -> Option<ChannelMessage> {
76///         // Poll Telegram API for new messages...
77///     }
78///
79///     async fn send(&self, output: ChannelOutput) -> Result<(), ChannelError> {
80///         // Send via Telegram Bot API...
81///         Ok(())
82///     }
83/// }
84/// ```
85#[async_trait::async_trait]
86pub trait Channel: Send {
87    /// Receive the next user input message.
88    ///
89    /// Returns `None` when the channel is closed (e.g. user disconnected,
90    /// stdin EOF, or graceful shutdown).
91    async fn recv(&mut self) -> Option<ChannelMessage>;
92
93    /// Send an agent response back to the user.
94    async fn send(&self, output: ChannelOutput) -> Result<(), ChannelError>;
95}