Skip to content

fix(web): 修复消息排序问题 - 后端返回过滤后的权限#156

Closed
0x7551 wants to merge 7 commits intotiann:mainfrom
0x7551:fix/message-ordering-148
Closed

fix(web): 修复消息排序问题 - 后端返回过滤后的权限#156
0x7551 wants to merge 7 commits intotiann:mainfrom
0x7551:fix/message-ordering-148

Conversation

@0x7551
Copy link
Copy Markdown
Contributor

@0x7551 0x7551 commented Feb 3, 2026

问题描述

1. 消息排序问题

切换会话或加载分页消息时,旧的工具卡片会混入当前消息中,导致显示顺序混乱。

根本原因agentState 包含整个 session 历史中的所有权限请求,而 props.messages 是分页的(最多 400 条)。

2. 滚动位置问题

加载历史消息后,页面滚动位置跳到最顶部,而不是保持在加载前的位置。

根本原因

  • assistant-ui 库的 autoScroll 在内容变化时会自动滚动到底部
  • messagesVersion 变化时,新消息还没有渲染到 DOM,导致滚动位置计算错误

#150 的关系

此 PR 是 #150 的改进版本:

此 PR 会移除 #150 中的前端过滤逻辑。

解决方案

消息排序修复

后端在返回消息时,同时返回该时间范围内的权限(completedRequests),确保权限和消息的生命周期同步。

后端改动

  • hub/src/sync/messageService.ts:添加 filterPermissionsByTimeRange() 函数
  • GET /sessions/:id/messages 响应新增 permissions 字段

前端改动

  • 存储 API 返回的权限数据
  • 对于待处理权限(requests):使用实时 SSE 数据,确保新权限立即显示
  • 对于已完成权限(completedRequests):使用 API 过滤后的数据,避免显示旧的工具卡片
  • 移除 reducer.ts 中的 oldestMessageTime 过滤逻辑

滚动位置修复

HappyThread.tsx 中:

  1. 禁用 autoScroll:加载历史消息前临时禁用 autoScroll,防止 assistant-ui 干扰
  2. 等待 DOM 更新:使用 requestAnimationFrame 循环检查,等待新消息渲染到 DOM 后再恢复滚动位置
  3. 恢复 autoScroll:滚动位置恢复后,延迟 50ms 重新启用 autoScroll

测试场景

  • 切换不同的 session,确认消息顺序正确
  • 新的权限请求能实时显示
  • 点击 "Load older" 加载更多历史消息,滚动位置正确保持
  • 滚动位置在加载历史消息后正确恢复

关闭的 Issue

Closes #148

tfq and others added 3 commits January 30, 2026 22:24
Add MesloLGLDZ Nerd Font as a built-in web font to ensure Powerlevel10k
and other Nerd Font-dependent prompts render correctly in the web terminal,
even on devices without local Nerd Fonts installed (e.g., mobile phones).

Changes:
- Add MesloLGLDZNerdFontMono-Regular.woff2 to web/public/fonts/
- Load font via FontFace API with BASE_URL support for subpath deployments
- Merge font loading and terminal creation in same useEffect to ensure
  font is ready before terminal renders

Fixes tiann#121

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Load MesloLGLDZ Nerd Font from jsDelivr CDN instead of bundling the 1.2MB
font file. This reduces the bundle size significantly while still ensuring
Nerd Font icons display correctly on all devices.

CDN URL: https://cdn.jsdelivr.net/gh/mshaugh/nerdfont-webfonts@v3.3.0/build/fonts/MesloLGLDZNerdFontMono-Regular.woff2

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@0x7551 0x7551 marked this pull request as ready for review February 6, 2026 02:31
@tiann
Copy link
Copy Markdown
Owner

tiann commented Feb 8, 2026

请把两个修复分开 PR

tfq and others added 4 commits February 9, 2026 14:53
When switching between sessions or loading paginated messages, old tool
blocks from agentState.requests were being mixed with current messages,
causing display order issues.

Root cause: reduceChatBlocks creates tool blocks for all permissions in
agentState, including those older than the current message page. These
old blocks (with earlier createdAt) would appear mixed with newer messages.

Fix:
1. In reducer.ts: Skip creating permission-only tool blocks if their
   createdAt is older than the oldest message in the current view
2. In SessionChat.tsx: Clear caches synchronously in useMemo when session
   changes, since useEffect runs after render

Closes tiann#148

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
Root cause: agentState contains all historical permissions while
messages are paginated (max 400). This caused old tool cards to
appear mixed with current messages when switching sessions.

Solution: Backend now returns permissions filtered by the time range
of returned messages, ensuring permissions and messages stay in sync.

- Add filterPermissionsByTimeRange() in messageService.ts
- Return permissions field in GET /sessions/:id/messages response
- Store and use filtered permissions in frontend message-window-store
- Remove frontend time filtering workaround from reducer.ts

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
Pending requests (requests) should use real-time SSE data from
agentState, not the filtered API response. This ensures new
permission requests appear immediately without needing to
switch sessions.

Only completed requests (completedRequests) use the filtered
API data to avoid showing old tool cards.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
Remove the frontend permission filtering logic (oldestMessageTime check)
since we now use backend filtering via the permissions field in the API
response. This is the intended approach as described in the PR.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
@0x7551 0x7551 force-pushed the fix/message-ordering-148 branch from 3e05183 to f3d3f16 Compare February 9, 2026 06:54
@0x7551
Copy link
Copy Markdown
Contributor Author

0x7551 commented Feb 9, 2026

已按要求拆分PR:

当前PR (#156): 只包含消息排序问题的修复

  • 防止切换会话时的消息排序问题
  • 在API响应中按消息时间范围过滤权限
  • 使用实时 agentState 处理待处理的权限请求
  • 移除前端权限过滤逻辑

新PR (#167): 滚动位置恢复问题的修复

  • 防止 autoScroll 干扰历史加载时的滚动位置
  • 等待 DOM 更新完成后再恢复滚动位置

两个PR现在是独立的,可以分别审查和合并。

@0x7551 0x7551 closed this Feb 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: 多次切换 session 后消息顺序错乱

2 participants