feat: 添加话题管理功能,支持按 chat_id 隔离话题

This commit is contained in:
oudecheng 2026-05-15 16:41:00 +08:00
parent e709773464
commit 2cc3b1ce9c
3 changed files with 34 additions and 12 deletions

View File

@ -32,6 +32,7 @@ use super::session_message_service::SessionMessageService;
/// Session 按 channel 隔离,每个 channel 一个 Session
/// History 按 chat_id 隔离,由 Session 统一管理
/// Topic 按 chat_id 隔离,存储在 SessionHistory 中
pub struct Session {
pub id: Uuid,
pub channel_name: String,
@ -42,7 +43,6 @@ pub struct Session {
compressor: ContextCompressor,
history: SessionHistory,
store: Arc<SessionStore>,
current_topic_id: Option<String>,
}
pub struct BusToolCallEmitter {
@ -153,7 +153,6 @@ impl Session {
chat_history_ttl_hours,
),
store,
current_topic_id: None,
})
}
@ -161,14 +160,18 @@ impl Session {
self.history.persistent_session_id(chat_id)
}
/// 设置当前话题 ID
pub fn set_current_topic(&mut self, topic_id: Option<String>) {
self.current_topic_id = topic_id;
/// 设置当前话题 ID指定 chat
pub fn set_current_topic(&mut self, chat_id: &str, topic_id: Option<String>) {
if let Some(topic_id) = topic_id {
self.history.set_chat_topic(chat_id, topic_id);
} else {
self.history.clear_chat_topic(chat_id);
}
}
/// 获取当前话题 ID
pub fn current_topic(&self) -> Option<&str> {
self.current_topic_id.as_deref()
/// 获取当前话题 ID(指定 chat
pub fn current_topic(&self, chat_id: &str) -> Option<&str> {
self.history.chat_topic(chat_id)
}
/// 切换话题 - 清除当前历史并加载新话题的历史
@ -183,7 +186,7 @@ impl Session {
.map_err(|e| AgentError::Other(format!("load topic messages error: {}", e)))?;
self.history.set_history(chat_id, messages);
self.current_topic_id = Some(topic_id.to_string());
self.history.set_chat_topic(chat_id, topic_id.to_string());
tracing::info!(
topic_id = %topic_id,
@ -243,15 +246,16 @@ impl Session {
message: ChatMessage,
) -> Result<(), AgentError> {
let session_id = self.persistent_session_id(chat_id);
let topic_id = self.history.chat_topic(chat_id).map(|s| s.to_string());
self.store
.append_message_with_topic(&session_id, self.current_topic_id.as_deref(), &message)
.append_message_with_topic(&session_id, topic_id.as_deref(), &message)
.map_err(|err| {
AgentError::Other(format!("append message persistence error: {}", err))
})?;
self.add_message(chat_id, message);
// 更新 topic 的最后活跃时间
if let Some(topic_id) = &self.current_topic_id {
if let Some(ref topic_id) = topic_id {
if let Err(e) = self.store.touch_topic(topic_id) {
tracing::warn!(error = %e, topic_id = %topic_id, "Failed to touch topic");
}
@ -337,7 +341,7 @@ impl Session {
pub(crate) fn reload_chat_history(&mut self, chat_id: &str) -> Result<(), AgentError> {
// 如果当前有 topic加载该 topic 的消息
if let Some(topic_id) = &self.current_topic_id {
if let Some(topic_id) = self.history.chat_topic(chat_id) {
let messages = self
.store
.load_messages_for_topic(topic_id)

View File

@ -25,6 +25,7 @@ fn current_timestamp() -> i64 {
pub(crate) struct SessionHistory {
channel_name: String,
chat_histories: HashMap<String, Vec<ChatMessage>>,
chat_topic_ids: HashMap<String, String>, // 每个 chat 的当前 topic
compression_in_flight: HashSet<String>,
conversations: Arc<dyn ConversationRepository>,
skill_events: Arc<dyn SkillEventRepository>,
@ -41,6 +42,7 @@ impl SessionHistory {
Self {
channel_name: channel_name.into(),
chat_histories: HashMap::new(),
chat_topic_ids: HashMap::new(),
compression_in_flight: HashSet::new(),
conversations,
skill_events,
@ -117,6 +119,21 @@ impl SessionHistory {
self.chat_histories.insert(chat_id.to_string(), history);
}
/// 设置指定 chat 的当前 topic
pub(crate) fn set_chat_topic(&mut self, chat_id: &str, topic_id: String) {
self.chat_topic_ids.insert(chat_id.to_string(), topic_id);
}
/// 获取指定 chat 的当前 topic
pub(crate) fn chat_topic(&self, chat_id: &str) -> Option<&str> {
self.chat_topic_ids.get(chat_id).map(|s| s.as_str())
}
/// 清除指定 chat 的 topic
pub(crate) fn clear_chat_topic(&mut self, chat_id: &str) {
self.chat_topic_ids.remove(chat_id);
}
pub(crate) fn add_message(&mut self, chat_id: &str, message: ChatMessage) {
self.get_or_create_history(chat_id).push(message);
}

View File

@ -44,6 +44,7 @@ impl SessionMessageService {
}
let session = self.lifecycle.active_session(channel_name).await?;
let outbound_messages = AgentExecutionService::new(self.show_tool_results)
.prepare_and_execute_message(MessageExecutionRequest {
session,