新增: 消息分页懒加载与事件总线空转优化
后端基础设施两项改进: 一、历史消息分页懒加载(治长对话渲染卡顿) - 消息仓库新增分页查询方法(从尾部取最近 N 条,支持游标) - 切换对话时后端保留全量消息供模型上下文用,但只返回最近 50 条给前端渲染,附带是否有更多历史和游标位置 - 新增加载更多消息的接口,前端滚顶时按游标分页拉取 二、事件总线空转优化(消除无消费者时的序列化开销) - 发布事件前先检查订阅者数量,无订阅者直接跳过序列化 - 当前隧道订阅方未接入,20 余个发射点双写不再空转浪费 同时核验确认对话上下文透明化三项均已落地(目标可见/ 项目增强预览/完整上下文面板),关闭对应待办。
This commit is contained in:
@@ -128,6 +128,57 @@ impl AiMessageRepo {
|
||||
.map_err(storage_err)?
|
||||
}
|
||||
|
||||
/// 按对话加载最近 N 条消息(分页懒加载,治长对话渲染卡顿)。
|
||||
///
|
||||
/// 从尾部取最近 `limit` 条(ORDER BY seq DESC LIMIT),返回时反转为 ASC 顺序(与
|
||||
/// list_by_conversation 一致的 seq 升序)。`before_seq` 可选:指定后只取 seq < before_seq
|
||||
/// 的消息(滚顶加载更多时的游标,取下一页更早的历史)。
|
||||
///
|
||||
/// 典型用法:
|
||||
/// - 首次切入对话:list_recent(conv_id, 50, None) → 最近 50 条
|
||||
/// - 滚顶加载更多:list_recent(conv_id, 50, Some(最早已加载消息的 seq)) → 再加载 50 条更早的
|
||||
pub async fn list_recent(
|
||||
&self,
|
||||
conversation_id: &str,
|
||||
limit: usize,
|
||||
before_seq: Option<i64>,
|
||||
) -> Result<Vec<AiMessageRecord>> {
|
||||
let conn = self.conn.clone();
|
||||
let conv_id = conversation_id.to_owned();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let guard = conn.blocking_lock();
|
||||
// before_seq 有无分两个 SQL(参数化 LIMIT 必须用固定占位,Rust 侧 clamp 防 0)
|
||||
let limit = limit.max(1) as i64;
|
||||
let sql = if before_seq.is_some() {
|
||||
"SELECT id, conversation_id, seq, role, content, parts, tool_call_id,
|
||||
tool_calls, model, status, reasoning_content, timestamp, created_at
|
||||
FROM ai_messages WHERE conversation_id = ?1 AND seq < ?2 ORDER BY seq DESC LIMIT ?3"
|
||||
} else {
|
||||
"SELECT id, conversation_id, seq, role, content, parts, tool_call_id,
|
||||
tool_calls, model, status, reasoning_content, timestamp, created_at
|
||||
FROM ai_messages WHERE conversation_id = ?1 ORDER BY seq DESC LIMIT ?2"
|
||||
};
|
||||
let mut stmt = guard.prepare(sql).map_err(storage_err)?;
|
||||
let rows = match before_seq {
|
||||
Some(seq) => stmt
|
||||
.query_map(params![conv_id, seq, limit], ai_message_from_row)
|
||||
.map_err(storage_err)?,
|
||||
None => stmt
|
||||
.query_map(params![conv_id, limit], ai_message_from_row)
|
||||
.map_err(storage_err)?,
|
||||
};
|
||||
let mut results: Vec<AiMessageRecord> = Vec::new();
|
||||
for r in rows {
|
||||
results.push(r.map_err(storage_err)?);
|
||||
}
|
||||
// DESC → 反转为 ASC(与 list_by_conversation 一致顺序)
|
||||
results.reverse();
|
||||
Ok(results)
|
||||
})
|
||||
.await
|
||||
.map_err(storage_err)?
|
||||
}
|
||||
|
||||
/// 删除对话内 seq ∈ [min_seq, max_seq) 的消息(左闭右开)。
|
||||
///
|
||||
/// compress 压缩 / 编辑重生成 dirty 范围重写用:delete_range → insert_batch 原子覆盖。
|
||||
|
||||
Reference in New Issue
Block a user