紧凑模式:只要还能「加载更早」,所有已关闭轮次都不折叠(含刚结束的那个)—— 建议折叠门禁从会话级 hasMore 改为逐轮次 turn/start / Compact mode: no closed Turn folds while older history is still loadable, including the one that just finished — gate folding on the Turn's own turn/start instead of session-wide hasMore #7229
BrokenReflection
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
compact-fold-per-turn.patch
摘要
「紧凑」显示模式下,只要会话还能点「加载更早」,所有已关闭轮次都会保持展开、折叠控件也不出现 —— 包括刚从尾部结束的那个轮次。根因是折叠门禁用了会话级的
hasMore,而它真正要防的风险只存在于「自身起始边界尚未加载」的那一个轮次。建议把判据改为逐轮次,并附上基于当前 master 的补丁。现象
对话显示使用默认的「紧凑」时,若会话打开后仍可点「加载更早」(更早历史尚未加载完),推理行、上下文注入、工具行与较早的 Assistant 内容会一直保持展开,轮次过程控件也不出现 —— 对每一个轮次都是如此,包括刚结束的那个。只有把「加载更早」点到底、历史全部加载完之后,所有合格的已关闭轮次才会一起收起。
复现
PAGE_MESSAGES = 50,packages/api/session-controller/src/client/sessions/session.ts),所以大多数真实会话都符合条件。turn/end:过程行保持展开,折叠控件不出现。为什么确实需要某种限制
当某个轮次自己的
turn/start不在已加载窗口内时,processStartSeq会回退到「已加载的最早证据」(packages/client/ui-chat/src/client/conversation-nodes/turn-process.ts):此时折叠并不安全:翻入更早的一页会扩大这个范围、并移动控件锚点(
controlAnchorSeq),于是刚进入窗口的行会落进已收起的组里 —— 而那正是读者翻上去要看的内容。建议
把折叠门禁从会话级
hasMore改为按轮次自身的起始边界判定:membersLoaded由轮次自身的边界派生(packages/client/ui-chat/src/client/conversation-nodes/turn-process-presentation.ts):TurnLocation.start恰好在该轮次的turn/start事件位于已加载窗口之外时为undefined(packages/client/ui-conversation/src/client/contract/conversation.ts)。由于已加载窗口是一个连续的[head, tail]区间,起始落在窗口内的轮次,其全部过程成员必然都已加载 —— 折叠它不可能隐藏尚未翻入的行。改动后的行为:
补丁(基于当前 master)
附件
compact-fold-per-turn.patch由git format-patch生成,基线是当前的master:ddefc45fbc(2026-09-17,Merge pull request #4469 … release-dsh-0.1.6-alpha.2),即版本0.1.6-alpha.2的 master 顶端c8aad2f88d(2026-09-20)git am compact-fold-per-turn.patch(保留提交信息)或git apply compact-fold-per-turn.patch;若 master 已有前进,可git apply --3waypnpm vitest run packages/client/ui-chat证据
TurnLocation.start:packages/client/ui-chat/tests/chat-view.client.spec.tsx、packages/client/ui-chat/tests/chat-snapshot-fixture.client.ts。packages/client/ui-chat测试套件 358/358 通过。希望了解
hasMore)是有意为之,还是这里本就该用逐轮次的turn/start边界?Summary
With the default
Compactconversation display, as long as a Session can still load older history (theLoad earlierbutton is visible), every closed Turn stays expanded and the folding control never appears — including the Turn that just finished at the tail. The fold gate reads the session-widehasMore, while the risk it guards against only exists for the one Turn whose own start boundary is not loaded yet. The proposal below gates on the Turn itself, with a patch based on the currentmaster.What happens today
With the default
Compactdisplay, while older history is still loadable, reasoning rows, Context injection, Tool rows and earlier Assistant material stay expanded and no Turn-process control appears — for every Turn, including the one that just finished. Only afterLoad earlierhas been clicked until history is exhausted does every eligible closed Turn collapse at once.Reproduction
PAGE_MESSAGES = 50,packages/api/session-controller/src/client/sessions/session.ts), so most real Sessions qualify.turn/end: the process rows stay expanded and no folding control appears.Load earlieruntil the button disappears: every eligible closed Turn collapses immediately.Why some restriction is needed
When a Turn's own
turn/startis outside the loaded window,processStartSeqfalls back to the earliest loaded evidence (packages/client/ui-chat/src/client/conversation-nodes/turn-process.ts):Folding such a Turn is unsafe: paging an older page in widens that range and moves the control's anchor (
controlAnchorSeq), so rows that just landed in the window would be hidden inside an already collapsed group — exactly the rows the reader paged up to read.Proposal
Gate the fold on the Turn's own start boundary instead of the session-wide
hasMore:membersLoadedis derived from the Turn's own boundary (packages/client/ui-chat/src/client/conversation-nodes/turn-process-presentation.ts):TurnLocation.startisundefinedexactly when that Turn'sturn/startevent is outside the loaded window (packages/client/ui-conversation/src/client/contract/conversation.ts). Since the loaded window is one contiguous[head, tail]range, a Turn whose start is inside it has all of its process members already loaded — folding it can never hide rows that are still to be paged in.Resulting behavior:
Patch (based on the current master)
The attached
compact-fold-per-turn.patchis produced bygit format-patchand targets the currentmaster:ddefc45fbc(2026-09-17,Merge pull request #4469 … release-dsh-0.1.6-alpha.2), the tip ofmasterat version0.1.6-alpha.2c8aad2f88d(2026-09-20)git am compact-fold-per-turn.patch(keeps the commit message) orgit apply compact-fold-per-turn.patch; usegit apply --3wayifmasterhas movedpnpm vitest run packages/client/ui-chatEvidence
Load earlierstill owns the head), and the fixture modelsTurnLocation.start:packages/client/ui-chat/tests/chat-view.client.spec.tsx,packages/client/ui-chat/tests/chat-snapshot-fixture.client.ts.packages/client/ui-chatsuite: 358/358 passing.compact-fold-per-turn.patch
What I would like to know
hasMore) intended, or is the per-Turnturn/startboundary the rule you would want here?All reactions