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 requested feature is not supported by this channel.
56    #[error("not supported: {0}")]
57    NotSupported(String),
58    /// The channel has been closed (user disconnected, etc.).
59    #[error("channel closed")]
60    Closed,
61}
62
63/// Abstract channel for multi-endpoint agent interaction.
64///
65/// Each channel implementation handles the transport-specific details
66/// of receiving user input and delivering agent output. The agent loop
67/// is decoupled from any specific transport.
68///
69/// ## Implementing a Channel
70///
71/// ```rust,ignore
72/// use bob_core::channel::{Channel, ChannelMessage, ChannelOutput, ChannelError};
73///
74/// struct MyTelegramChannel { /* ... */ }
75///
76/// #[async_trait::async_trait]
77/// impl Channel for MyTelegramChannel {
78///     async fn recv(&mut self) -> Option<ChannelMessage> {
79///         // Poll Telegram API for new messages...
80///     }
81///
82///     async fn send(&self, output: ChannelOutput) -> Result<(), ChannelError> {
83///         // Send via Telegram Bot API...
84///         Ok(())
85///     }
86/// }
87/// ```
88#[async_trait::async_trait]
89pub trait Channel: Send {
90    /// Receive the next user input message.
91    ///
92    /// Returns `None` when the channel is closed (e.g. user disconnected,
93    /// stdin EOF, or graceful shutdown).
94    async fn recv(&mut self) -> Option<ChannelMessage>;
95
96    /// Send an agent response back to the user.
97    async fn send(&self, output: ChannelOutput) -> Result<(), ChannelError>;
98}