后端: - 新增 ListChannels 命令,列出所有可用通道 (WebSocket/CLI) - 新增 ListSessionsByChannel 命令,支持按通道筛选会话 - 新增 ListTopics 命令,列出 Session 的所有 Topics - 添加 Channel 和 TopicSummary 数据结构 - 更新 WebSocket 协议,支持 channel_list 和 topic_list 消息 前端: - 新增 ChannelSelector 组件用于通道选择 - 新增 SessionSelector 组件用于会话选择 - 更新 TopicList 组件支持话题展示 - 更新 useChat hook 和协议类型定义 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
89 lines
2.7 KiB
Rust
89 lines
2.7 KiB
Rust
use crate::command::context::CommandContext;
|
|
use crate::command::handler::{CommandHandler, CommandMetadata};
|
|
use crate::command::response::{CommandError, CommandResponse, MessageKind};
|
|
use crate::command::Command;
|
|
use crate::protocol::SessionSummary;
|
|
use crate::storage::SessionStore;
|
|
use async_trait::async_trait;
|
|
use std::sync::Arc;
|
|
|
|
/// 按通道列出会话命令处理器
|
|
pub struct ListSessionsByChannelCommandHandler {
|
|
store: Arc<SessionStore>,
|
|
}
|
|
|
|
impl ListSessionsByChannelCommandHandler {
|
|
pub fn new(store: Arc<SessionStore>) -> Self {
|
|
Self { store }
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl CommandHandler for ListSessionsByChannelCommandHandler {
|
|
fn can_handle(&self, cmd: &Command) -> bool {
|
|
matches!(cmd, Command::ListSessionsByChannel { .. })
|
|
}
|
|
|
|
fn metadata(&self) -> Option<CommandMetadata> {
|
|
Some(CommandMetadata {
|
|
name: "list_by_channel",
|
|
description: "列出指定通道的所有会话",
|
|
usage: "/list_by_channel <channel_name>",
|
|
})
|
|
}
|
|
|
|
async fn handle(
|
|
&self,
|
|
cmd: Command,
|
|
ctx: CommandContext,
|
|
) -> Result<CommandResponse, CommandError> {
|
|
match cmd {
|
|
Command::ListSessionsByChannel {
|
|
channel_name,
|
|
include_archived,
|
|
} => handle_list_sessions_by_channel(self, channel_name, include_archived, ctx).await,
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn handle_list_sessions_by_channel(
|
|
handler: &ListSessionsByChannelCommandHandler,
|
|
channel_name: String,
|
|
include_archived: bool,
|
|
ctx: CommandContext,
|
|
) -> Result<CommandResponse, CommandError> {
|
|
let sessions = handler
|
|
.store
|
|
.list_sessions(&channel_name, include_archived)
|
|
.map_err(|e| CommandError::new("LIST_SESSIONS_ERROR", e.to_string()))?;
|
|
|
|
let summaries: Vec<SessionSummary> = sessions
|
|
.into_iter()
|
|
.map(|s| SessionSummary {
|
|
session_id: s.id,
|
|
title: s.title,
|
|
channel_name: s.channel_name,
|
|
chat_id: s.chat_id,
|
|
message_count: s.message_count,
|
|
last_active_at: s.last_active_at,
|
|
archived_at: s.archived_at,
|
|
})
|
|
.collect();
|
|
|
|
let sessions_json = serde_json::to_string(&summaries)
|
|
.map_err(|e| CommandError::new("SERIALIZE_ERROR", e.to_string()))?;
|
|
|
|
let message = format!(
|
|
"Found {} session(s) in channel '{}'",
|
|
summaries.len(),
|
|
channel_name
|
|
);
|
|
|
|
Ok(CommandResponse::success(ctx.request_id)
|
|
.with_message(MessageKind::Notification, &message)
|
|
.with_metadata("sessions", &sessions_json)
|
|
.with_metadata("channel_name", &channel_name)
|
|
.with_metadata("count", &summaries.len().to_string()))
|
|
}
|