refactor(channel): accept SendMessage struct in Channel::send()

Refactor the Channel trait to accept a SendMessage struct instead of
separate message and recipient string parameters. This enables passing
additional metadata like email subjects.

Changes:
- Add SendMessage struct with content, recipient, and optional subject
- Update Channel::send() signature to accept &SendMessage
- Update all 12 channel implementations
- Update call sites in channels/mod.rs and gateway/mod.rs

Subject field usage:
- Email: uses subject for email subject line
- DingTalk: uses subject as markdown message title
- All others: ignore subject (no native platform support)
This commit is contained in:
Kieran 2026-02-17 14:37:03 +00:00 committed by Chummy
parent b8ed42edbb
commit dbebd48dfe
14 changed files with 153 additions and 73 deletions

View file

@ -1,4 +1,4 @@
use super::traits::{Channel, ChannelMessage};
use super::traits::{Channel, ChannelMessage, SendMessage};
use async_trait::async_trait;
use futures_util::{SinkExt, StreamExt};
use std::collections::HashMap;
@ -84,20 +84,22 @@ impl Channel for DingTalkChannel {
"dingtalk"
}
async fn send(&self, message: &str, recipient: &str) -> anyhow::Result<()> {
async fn send(&self, message: &SendMessage) -> anyhow::Result<()> {
let webhooks = self.session_webhooks.read().await;
let webhook_url = webhooks.get(recipient).ok_or_else(|| {
let webhook_url = webhooks.get(&message.recipient).ok_or_else(|| {
anyhow::anyhow!(
"No session webhook found for chat {recipient}. \
The user must send a message first to establish a session."
"No session webhook found for chat {}. \
The user must send a message first to establish a session.",
message.recipient
)
})?;
let title = message.subject.as_deref().unwrap_or("ZeroClaw");
let body = serde_json::json!({
"msgtype": "markdown",
"markdown": {
"title": "ZeroClaw",
"text": message,
"title": title,
"text": message.content,
}
});