现象
@agegr/pi-web@0.8.7(07f873c)相对 v0.8.6 有两个回归。
都来自:
具体是:
- 消息列表底部留白过大(agent 空闲也有)
- agent 运行中稍一上滑,视口来回跳动
复现
留白
- 打开有消息的会话(agent 不必在跑)
- 滚到列表底部
- 看最后一条消息和输入区之间
结果: 中间有一大块空白,高度大约等于整条底部栏(常见 150–250px)。
跳动
- 发送会持续流式输出 / 工具调用的 prompt
- agent 还在跑时,稍微向上滚一点
- 观察视口
结果: 反复被拉向底部,再被拽回最新用户消息附近。
更容易出现在:
滑到离底部很远时,相对稳定。
根因
#333 用三套机制,替换了 v0.8.6 的条件占位。
对比
|
v0.8.6 |
v0.8.7 |
| 尾部占位 |
仅 agentRunning |
始终存在 |
| 占位高度 |
≈ 视口 |
≈ 整个 composer |
| 其它 |
无 |
prompt-anchor + 流式 live-follow |
相关文件
components/ChatWindow.tsx
hooks/useAgentSession.ts
1. 留白
消息列表里无条件渲染了 composer 等高 spacer:
<div aria-hidden="true" style={{ height: bottomComposerHeight }} />
bottomComposerRef 包的是整块底部,不只是输入框:
- extension widgets
ChatInput
- status bar
所以 bottomComposerHeight 往往有 150–250px。
它一直在文档流里。用户贴底时,最后一条消息下面就会空出整条 composer 的高度。
agent 运行时,还可能和 promptAnchorSpacerHeight 叠在一起,空白更大。
2. 跳动
agent 运行时,下面三套逻辑可能同时改滚动位置:
Live-follow(钉底)
- 触发:流式
message_update
- 条件:距底 ≤ 150px(
SCROLL_BOTTOM_THRESHOLD)
- 动作:
scrollToBottom("auto")
Prompt-anchor(钉最新用户消息)
- 触发:
agentRunning && promptAnchorActive
- 动作:
- 动态 spacer,把最新用户消息钉到顶部约 16px
- spacer 从
0 变为正值时,调用 scrollUserMsgToTop()
- 使用
behavior: "smooth"
Composer 高度跟随
- 触发:composer 高度变化
- 条件:距底 ≤
|Δh| + 1
- 动作:再次
scrollToBottom("auto")
为什么会来回抢
短距离上滑时,这几件事会叠在一起:
-
目标冲突
一套钉底,一套钉最新用户消息。只上滑一点时,两者经常同时成立。
-
程序滚动压制用户滚动
程序滚动会设置:
ignoreProgrammaticScrollUntil = now + 700ms
这 700ms 内,用户滚动的意图处理会被跳过。
-
near-bottom 被写回
scrollUserMsgToTop() 会主动写:
isNearBottomRef.current = ...
用户正在上滑,仍可能被标成 near-bottom。
下一帧 live-follow 又把人拽回去。
-
动画和布局互相打断
- anchor 用 smooth
- live-follow 用 auto
- spacer 改变
scrollHeight,触发 ResizeObserver 重测
- 流式过程中布局反复失效
所以不是“上滑没检测到”,而是:
检测到了,仍被两套程序滚动来回抢。
现象
@agegr/pi-web@0.8.7(07f873c)相对v0.8.6有两个回归。都来自:
3a37c04具体是:
复现
留白
结果: 中间有一大块空白,高度大约等于整条底部栏(常见 150–250px)。
跳动
结果: 反复被拉向底部,再被拽回最新用户消息附近。
更容易出现在:
滑到离底部很远时,相对稳定。
根因
#333 用三套机制,替换了 v0.8.6 的条件占位。
对比
agentRunning相关文件
components/ChatWindow.tsxhooks/useAgentSession.ts1. 留白
消息列表里无条件渲染了 composer 等高 spacer:
bottomComposerRef包的是整块底部,不只是输入框:ChatInput所以
bottomComposerHeight往往有 150–250px。它一直在文档流里。用户贴底时,最后一条消息下面就会空出整条 composer 的高度。
agent 运行时,还可能和
promptAnchorSpacerHeight叠在一起,空白更大。2. 跳动
agent 运行时,下面三套逻辑可能同时改滚动位置:
Live-follow(钉底)
message_updateSCROLL_BOTTOM_THRESHOLD)scrollToBottom("auto")Prompt-anchor(钉最新用户消息)
agentRunning && promptAnchorActive0变为正值时,调用scrollUserMsgToTop()behavior: "smooth"Composer 高度跟随
|Δh| + 1scrollToBottom("auto")为什么会来回抢
短距离上滑时,这几件事会叠在一起:
目标冲突
一套钉底,一套钉最新用户消息。只上滑一点时,两者经常同时成立。
程序滚动压制用户滚动
程序滚动会设置:
这 700ms 内,用户滚动的意图处理会被跳过。
near-bottom 被写回
scrollUserMsgToTop()会主动写:用户正在上滑,仍可能被标成 near-bottom。
下一帧 live-follow 又把人拽回去。
动画和布局互相打断
scrollHeight,触发 ResizeObserver 重测所以不是“上滑没检测到”,而是: