mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(web): 修复切换会话时消息乱序问题 (#150)
* feat(web): add built-in Nerd Font for terminal icon support 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 #121 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: use CDN for Nerd Font instead of bundled file 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> * fix(web): prevent message ordering issues when switching sessions 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 #148 via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> --------- Co-authored-by: tfq <tfq@gmail.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: HAPI <noreply@hapi.run>
This commit is contained in:
co-authored by
HAPI
tfq
Claude Opus 4.5
parent
2735421e3f
commit
2f6bbcd400
@@ -48,11 +48,24 @@ export function reduceChatBlocks(
|
||||
let hasReadyEvent = rootResult.hasReadyEvent
|
||||
|
||||
// Only create permission-only tool cards when there is no tool call/result in the transcript.
|
||||
// Also skip if the permission is older than the oldest message in the current view,
|
||||
// to avoid mixing old tool cards with newer messages when paginating.
|
||||
const oldestMessageTime = normalized.length > 0
|
||||
? Math.min(...normalized.map(m => m.createdAt))
|
||||
: null
|
||||
|
||||
for (const [id, entry] of permissionsById) {
|
||||
if (toolIdsInMessages.has(id)) continue
|
||||
if (rootResult.toolBlocksById.has(id)) continue
|
||||
|
||||
const createdAt = entry.permission.createdAt ?? Date.now()
|
||||
|
||||
// Skip permissions that are older than the oldest message in the current view.
|
||||
// These will be shown when the user loads older messages.
|
||||
if (oldestMessageTime !== null && createdAt < oldestMessageTime) {
|
||||
continue
|
||||
}
|
||||
|
||||
const block = ensureToolBlock(rootResult.blocks, rootResult.toolBlocksById, id, {
|
||||
createdAt,
|
||||
localId: null,
|
||||
|
||||
@@ -141,12 +141,22 @@ export function SessionChat(props: {
|
||||
voice.toggleMic()
|
||||
}, [voice])
|
||||
|
||||
// Track session id to clear caches when it changes
|
||||
const prevSessionIdRef = useRef<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
normalizedCacheRef.current.clear()
|
||||
blocksByIdRef.current.clear()
|
||||
}, [props.session.id])
|
||||
|
||||
const normalizedMessages: NormalizedMessage[] = useMemo(() => {
|
||||
// Clear caches immediately when session changes (before useEffect runs)
|
||||
if (prevSessionIdRef.current !== null && prevSessionIdRef.current !== props.session.id) {
|
||||
normalizedCacheRef.current.clear()
|
||||
blocksByIdRef.current.clear()
|
||||
}
|
||||
prevSessionIdRef.current = props.session.id
|
||||
|
||||
const cache = normalizedCacheRef.current
|
||||
const normalized: NormalizedMessage[] = []
|
||||
const seen = new Set<string>()
|
||||
|
||||
@@ -23,9 +23,11 @@ function isOptimisticMessage(msg: DecryptedMessage): boolean {
|
||||
function compareMessages(a: DecryptedMessage, b: DecryptedMessage): number {
|
||||
const aSeq = typeof a.seq === 'number' ? a.seq : null
|
||||
const bSeq = typeof b.seq === 'number' ? b.seq : null
|
||||
|
||||
if (aSeq !== null && bSeq !== null && aSeq !== bSeq) {
|
||||
return aSeq - bSeq
|
||||
}
|
||||
|
||||
if (a.createdAt !== b.createdAt) {
|
||||
return a.createdAt - b.createdAt
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user