PicoBot/src/channels/base.rs
xiaoski 2dada36bc6 feat: introduce multimodal content handling with media support
- Added ContentBlock enum for multimodal content representation (text, image).
- Enhanced ChatMessage struct to include media references.
- Updated InboundMessage and OutboundMessage to use MediaItem for media handling.
- Implemented media download and upload functionality in FeishuChannel.
- Modified message processing in the gateway to handle media items.
- Improved logging for message processing and media handling in debug mode.
- Refactored message serialization for LLM providers to support content blocks.
2026-04-07 23:09:31 +08:00

80 lines
2.3 KiB
Rust

use async_trait::async_trait;
use std::sync::Arc;
use crate::bus::{BusError, InboundMessage, MessageBus, OutboundMessage};
#[derive(Debug)]
pub enum ChannelError {
ConfigError(String),
ConnectionError(String),
SendError(String),
BusError(String),
Other(String),
}
impl std::fmt::Display for ChannelError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ChannelError::ConfigError(s) => write!(f, "Config error: {}", s),
ChannelError::ConnectionError(s) => write!(f, "Connection error: {}", s),
ChannelError::SendError(s) => write!(f, "Send error: {}", s),
ChannelError::BusError(s) => write!(f, "Bus error: {}", s),
ChannelError::Other(s) => write!(f, "Error: {}", s),
}
}
}
impl std::error::Error for ChannelError {}
impl From<BusError> for ChannelError {
fn from(e: BusError) -> Self {
ChannelError::BusError(e.to_string())
}
}
#[async_trait]
pub trait Channel: Send + Sync + 'static {
fn name(&self) -> &str;
fn is_running(&self) -> bool;
/// Start the channel with a reference to the MessageBus
async fn start(&self, bus: Arc<MessageBus>) -> Result<(), ChannelError>;
/// Stop the channel
async fn stop(&self) -> Result<(), ChannelError>;
/// Send a message to the channel (called by OutboundDispatcher)
async fn send(&self, msg: OutboundMessage) -> Result<(), ChannelError>;
/// Send a streaming delta (optional, for channels that support it)
async fn send_delta(&self, chat_id: &str, delta: &str) -> Result<(), ChannelError> {
let _ = chat_id;
let _ = delta;
Ok(())
}
/// Check if a sender is allowed to use this channel
fn is_allowed(&self, _sender_id: &str) -> bool {
true
}
/// Handle an inbound message: check permissions and publish to bus
async fn handle_and_publish(
&self,
bus: &Arc<MessageBus>,
msg: &InboundMessage,
) -> Result<(), ChannelError> {
if !self.is_allowed(&msg.sender_id) {
tracing::warn!(
channel = %self.name(),
sender = %msg.sender_id,
"Access denied"
);
return Ok(());
}
bus.publish_inbound(msg.clone()).await?;
Ok(())
}
}