fix: 会话回答完成瞬间气泡闪烁(视图身份跨完成时刻保持稳定) - #271
Merged
Merged
Conversation
Collaborator
Author
|
WeiBeiSelfCheck ✅ passed |
taekchef
force-pushed
the
codex/fix-agent-streaming-flicker
branch
2 times, most recently
from
August 20, 2026 16:35
306d87d to
3ec6b75
Compare
The chat pane and floating panel switched between two different view types for generating vs completed messages. When a reply finished, the conditional flip tore down the whole bubble subtree — WKWebView destroyed and cold-started, native fallback text flashing in between, bubble height collapsing to the loading seed and expanding again. Render one row type per surface (AgentMessageBubble / FloatingSelectionMessageRow) so the view identity — and the mounted markdown WKWebView — survives the generating → completed flip, and the keepsMarkdownSurfaceMounted seamless-handoff path (14941e7) becomes reachable again. Only the generating row observes the live AgentStreamingState; completed rows observe a shared inert state that never publishes. @ObservedObject subscribes regardless of body reads, so pointing finished rows at the live state would re-broadcast every token to every mounted bubble — the churn e058c61 set out to remove. Keep the streaming WebView fully visible through the finalized-snapshot handoff instead of hiding it (opacity 0.01) behind the native fallback while awaiting the authoritative measurement. The native overlay is now reserved for cold-mounted rows whose WebView has no content yet, so the completion moment no longer flashes unstyled text.
taekchef
force-pushed
the
codex/fix-agent-streaming-flicker
branch
from
August 20, 2026 16:36
3ec6b75 to
6e45d74
Compare
taekchef
marked this pull request as ready for review
August 20, 2026 17:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
会话回答完成的瞬间气泡闪烁:排版好的内容闪断成无 KaTeX/表格/代码高亮的原生兜底文本,气泡高度塌缩回 44pt 加载高度再弹开,随后新 WebView 冷启动完毕二次跳变。含公式/代码/表格的长回答最明显,纯文本短回答不易察觉。
根因
chat 窗格(agentMessageRow)与浮层面板各自用两个不同类型的视图分支渲染生成中/已完成消息(e058c61 引入)。SwiftUI 条件分支翻转时整棵子树销毁重建:
completionState翻转瞬间被 dismantle;finalizedRendererReady之前显示原生兜底层(无富渲染样式);14941e7建立的「同一 Markdown 表面跨越流式→完成」契约(keepsMarkdownSurfaceMounted + finishStreamingMarkdown)因外层 remount 无法生效。改动(仅 Sources/WeiBei/Views/NotesAgentView.swift)
AgentMessageBubble/FloatingSelectionMessageRow),liveStreamingText/liveActivityText只在.generating时传值,完成后传nil。AgentStreamingState;完成的行改观察共享的inertAgentStreamingState(永不发布)。@ObservedObject 装上即订阅、与 body 是否读取无关,因此不能简单让完成行继续观察全局 live state——那会把 e058c61 消除的「每个 token 广播给所有历史气泡」请回来。AgentBubble.streaming参数(体内从未读取)与floatingText(for:)。共享核心文件占用
无(仅 NotesAgentView.swift,不在共享核心面)。
验证
swift build✅swift run WeiBeiSelfCheck✅webview.markdown_create/webview.markdown_destroyperf 事件——同一条消息从生成到完成不得出现旧实例 destroy + 新实例 create。已知残留 / 未做
final snapshot 等待期原生兜底轻闪:已修复(第二轮,验收反馈后)。交接期 WebView 保持可见,原生兜底只留给冷挂载的历史消息;最终快照高度与流式末帧不同时最多有一次高度微调。editor.tsstreaming 插件throttleMs: 0导致的流式过程中格式跳变(未闭合 fence/表格中间态)不在本 PR 范围。