重构:斜杠命令通过 handle_message 处理,Channel 不再管理 Session
架构优化: - Feishu 渠道的 handle_and_publish 简化为只发布消息到 bus - Session 创建/复用由 SessionManager 在 handle_message 内部处理 - 斜杠命令检测移到 handle_message,execute_slash_command 直接调用 - CLI 和 Feishu 统一通过消息总线处理斜杠命令
This commit is contained in:
parent
e787203e94
commit
e61b78eaff
@ -12,9 +12,7 @@ use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
use crate::bus::{MessageBus, MediaItem, OutboundMessage};
|
||||
use crate::channels::base::{Channel, ChannelError};
|
||||
use crate::channels::slash_command::parse_slash_command;
|
||||
use crate::config::FeishuChannelConfig;
|
||||
use crate::session::{SessionCommand, SessionEvent};
|
||||
|
||||
const FEISHU_API_BASE: &str = "https://open.feishu.cn/open-apis";
|
||||
const FEISHU_WS_BASE: &str = "https://open.feishu.cn";
|
||||
@ -2003,94 +2001,8 @@ impl Channel for FeishuChannel {
|
||||
bus: &Arc<MessageBus>,
|
||||
msg: &crate::bus::InboundMessage,
|
||||
) -> Result<(), ChannelError> {
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
if !self.is_allowed(&msg.sender_id) {
|
||||
tracing::warn!(
|
||||
channel = %self.name(),
|
||||
sender = %msg.sender_id,
|
||||
"Access denied"
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Check for slash command
|
||||
if let Some((cmd_name, cmd_args)) = parse_slash_command(&msg.content) {
|
||||
tracing::info!(cmd = %cmd_name, "Feishu slash command detected");
|
||||
|
||||
// For slash commands, we need to ensure a session exists first
|
||||
// Get or create session via control plane
|
||||
let (reply_tx, mut reply_rx) = mpsc::channel(1);
|
||||
bus.publish_control(crate::bus::ControlMessage {
|
||||
op: SessionCommand::CreateDialog {
|
||||
channel: msg.channel.clone(),
|
||||
chat_id: msg.chat_id.clone(),
|
||||
title: None,
|
||||
},
|
||||
reply_tx,
|
||||
}).await?;
|
||||
|
||||
// Wait for session creation
|
||||
let session_id = match reply_rx.recv().await {
|
||||
Some(Ok(SessionEvent::DialogCreated { session_id, .. })) => Some(session_id),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Now execute the slash command with the session
|
||||
let (cmd_reply_tx, mut cmd_reply_rx) = mpsc::channel(1);
|
||||
bus.publish_control(crate::bus::ControlMessage {
|
||||
op: SessionCommand::ExecuteSlashCommand {
|
||||
command: cmd_name.to_string(),
|
||||
args: if cmd_args.is_empty() { None } else { Some(cmd_args.to_string()) },
|
||||
channel: msg.channel.clone(),
|
||||
chat_id: msg.chat_id.clone(),
|
||||
current_session_id: session_id,
|
||||
},
|
||||
reply_tx: cmd_reply_tx,
|
||||
}).await?;
|
||||
|
||||
// Handle response
|
||||
if let Some(result) = reply_rx.recv().await {
|
||||
match result {
|
||||
Ok(SessionEvent::SlashCommandExecuted { message, .. }) => {
|
||||
let outbound = crate::bus::OutboundMessage {
|
||||
channel: msg.channel.clone(),
|
||||
chat_id: msg.chat_id.clone(),
|
||||
content: message,
|
||||
reply_to: None,
|
||||
media: vec![],
|
||||
metadata: msg.forwarded_metadata.clone(),
|
||||
};
|
||||
bus.publish_outbound(outbound).await?;
|
||||
}
|
||||
Ok(SessionEvent::Error { message, .. }) => {
|
||||
let outbound = crate::bus::OutboundMessage {
|
||||
channel: msg.channel.clone(),
|
||||
chat_id: msg.chat_id.clone(),
|
||||
content: message,
|
||||
reply_to: None,
|
||||
media: vec![],
|
||||
metadata: msg.forwarded_metadata.clone(),
|
||||
};
|
||||
bus.publish_outbound(outbound).await?;
|
||||
}
|
||||
Err(e) => {
|
||||
let outbound = crate::bus::OutboundMessage {
|
||||
channel: msg.channel.clone(),
|
||||
chat_id: msg.chat_id.clone(),
|
||||
content: format!("Error: {}", e),
|
||||
reply_to: None,
|
||||
media: vec![],
|
||||
metadata: msg.forwarded_metadata.clone(),
|
||||
};
|
||||
bus.publish_outbound(outbound).await?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// All messages (including slash commands) go through the normal inbound flow
|
||||
// SessionManager handles session creation/reuse internally
|
||||
bus.publish_inbound(msg.clone()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ use tokio::sync::{Mutex, mpsc};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::bus::ChatMessage;
|
||||
use crate::channels::slash_command::parse_slash_command;
|
||||
use crate::config::LLMProviderConfig;
|
||||
use crate::agent::{AgentLoop, AgentError, ContextCompressor};
|
||||
use crate::agent::system_prompt::build_system_prompt;
|
||||
@ -517,6 +518,29 @@ impl SessionManager {
|
||||
let unified_id = UnifiedSessionId::new(channel, chat_id, dialog_id);
|
||||
let session = self.get_or_create_session(&unified_id).await?;
|
||||
|
||||
// Check for slash command
|
||||
if let Some((cmd_name, cmd_args)) = parse_slash_command(content) {
|
||||
let (new_session_id, response) = self.execute_slash_command(
|
||||
cmd_name,
|
||||
if cmd_args.is_empty() { None } else { Some(cmd_args) },
|
||||
channel,
|
||||
chat_id,
|
||||
Some(&unified_id),
|
||||
).await?;
|
||||
|
||||
// If a new session was created (e.g., /new, /delete), update the session binding
|
||||
if let Some(new_id) = new_session_id {
|
||||
// Update the session in the map with the new ID
|
||||
let mut inner = self.inner.lock().await;
|
||||
if let Some(old_session) = inner.sessions.remove(&unified_id.to_string()) {
|
||||
inner.sessions.insert(new_id.to_string(), old_session);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
// Normal message handling through LLM
|
||||
let response: String = {
|
||||
let mut session_guard = session.lock().await;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user