Skip to main content

apollo/channels/
traits.rs

1//! Core Channel trait — messaging interface.
2//! Inspired by ZeroClaw's channel abstraction + NanoClaw's group isolation.
3
4use async_trait::async_trait;
5use serde::{Deserialize, Serialize};
6use tokio::sync::mpsc;
7
8/// Incoming message from a channel.
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct IncomingMessage {
11    pub id: String,
12    pub sender_id: String,
13    pub sender_name: Option<String>,
14    pub chat_id: String,
15    pub text: String,
16    pub is_group: bool,
17    pub reply_to: Option<String>,
18    pub timestamp: chrono::DateTime<chrono::Utc>,
19}
20
21/// Outgoing message to a channel.
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct OutgoingMessage {
24    pub chat_id: String,
25    pub text: String,
26    pub reply_to: Option<String>,
27}
28
29/// The core Channel trait.
30/// Implement for each messaging platform (Telegram, Discord, CLI, WebSocket, etc.)
31#[async_trait]
32pub trait Channel: Send + Sync {
33    /// Channel name (e.g., "telegram", "discord", "cli")
34    fn name(&self) -> &str;
35
36    /// Start receiving messages. Returns a receiver for incoming messages.
37    async fn start(&mut self) -> anyhow::Result<mpsc::Receiver<IncomingMessage>>;
38
39    /// Send a message through this channel. Returns an optional message ID for tracking/editing.
40    async fn send(&self, message: OutgoingMessage) -> anyhow::Result<Option<String>>;
41
42    /// Send a typing indicator (or equivalent) to the user.
43    async fn send_typing(&self, _chat_id: &str) -> anyhow::Result<()> {
44        Ok(())
45    }
46
47    /// Edit a previously sent message if the channel supports it.
48    async fn edit(&self, _chat_id: &str, _message_id: &str, _new_text: &str) -> anyhow::Result<()> {
49        Ok(())
50    }
51
52    /// Whether this channel supports live draft updates (send → update → finalize).
53    fn supports_draft_updates(&self) -> bool {
54        false
55    }
56
57    /// Send an initial draft placeholder (e.g. "⏳"). Returns message ID for edits.
58    async fn send_draft(&self, _chat_id: &str, _text: &str) -> anyhow::Result<Option<String>> {
59        Ok(None)
60    }
61
62    /// Edit the draft with a live progress update (tool start/end). Rate-limited by impl.
63    async fn update_draft_progress(
64        &self,
65        _chat_id: &str,
66        _message_id: &str,
67        _text: &str,
68    ) -> anyhow::Result<()> {
69        Ok(())
70    }
71
72    /// Finalize the draft with the full formatted response, replacing any progress text.
73    async fn finalize_draft(
74        &self,
75        _chat_id: &str,
76        _message_id: &str,
77        _text: &str,
78    ) -> anyhow::Result<()> {
79        Ok(())
80    }
81
82    /// Stop the channel gracefully.
83    async fn stop(&mut self) -> anyhow::Result<()>;
84}