fix: message ordering and duplicate messages
Backend: - Composite ORDER BY (created_at DESC, iteration ASC, id ASC) to fix non-deterministic ordering when multiple messages share same second - Composite key cursor pagination to avoid missing messages at boundary Android: - Fix message duplication: guard loadMoreHistory from firing before initial scroll completes (isAtTop race → fetchOlderMessages → cacheMessagesFromApi with different IDs → Room duplicates) - Add distinctBy(id) at all message assignment points in ViewModel - cacheMessagesFromApi: skip insert if same ID or same content exists - Add relative timestamp display on message bubbles Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -604,7 +604,7 @@ async def list_agent_sessions(
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""获取 Agent 的会话列表,按最近活跃时间排序。"""
|
||||
from sqlalchemy import func as sa_func, desc
|
||||
from sqlalchemy import func as sa_func, desc, or_
|
||||
|
||||
# 验证 agent 存在或有权限
|
||||
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
||||
@@ -666,6 +666,8 @@ async def get_session_messages(
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""获取会话的消息历史(分页),从旧到新排序。"""
|
||||
from sqlalchemy import or_
|
||||
|
||||
# limit 限制
|
||||
limit = min(max(limit, 1), 200)
|
||||
|
||||
@@ -674,16 +676,22 @@ async def get_session_messages(
|
||||
ChatMessage.session_id == session_id,
|
||||
)
|
||||
|
||||
# 游标分页:before_id 之前的老消息
|
||||
# 游标分页:before_id 之前的老消息(使用复合键避免 created_at 相同导致遗漏)
|
||||
if before_id:
|
||||
cursor_msg = db.query(ChatMessage).filter(ChatMessage.id == before_id).first()
|
||||
if cursor_msg and cursor_msg.created_at:
|
||||
base_q = base_q.filter(ChatMessage.created_at < cursor_msg.created_at)
|
||||
base_q = base_q.filter(
|
||||
or_(
|
||||
ChatMessage.created_at < cursor_msg.created_at,
|
||||
(ChatMessage.created_at == cursor_msg.created_at) & (ChatMessage.id < cursor_msg.id),
|
||||
)
|
||||
)
|
||||
|
||||
# 取 N+1 条,判断 has_more(按时间降序取最新 N 条,再反转)
|
||||
# 二级排序 iteration + id 避免同一秒内多条消息顺序不确定
|
||||
batch = (
|
||||
base_q
|
||||
.order_by(ChatMessage.created_at.desc())
|
||||
.order_by(ChatMessage.created_at.desc(), ChatMessage.iteration.asc(), ChatMessage.id.asc())
|
||||
.limit(limit + 1)
|
||||
.all()
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user