Skip to content

v0.8.7 对话列表底部留白过大;agent 运行中上滑视口跳动(#333) #403

Description

@zhudatou630

现象

@agegr/pi-web@0.8.707f873c)相对 v0.8.6 有两个回归。

都来自:

具体是:

  1. 消息列表底部留白过大(agent 空闲也有)
  2. agent 运行中稍一上滑,视口来回跳动

复现

留白

  1. 打开有消息的会话(agent 不必在跑)
  2. 滚到列表底部
  3. 看最后一条消息和输入区之间

结果: 中间有一大块空白,高度大约等于整条底部栏(常见 150–250px)。

跳动

  1. 发送会持续流式输出 / 工具调用的 prompt
  2. agent 还在跑时,稍微向上滚一点
  3. 观察视口

结果: 反复被拉向底部,再被拽回最新用户消息附近。

更容易出现在:

  • 内容还不长
  • 只上滑了一小段(仍靠近尾部)

滑到离底部很远时,相对稳定。


根因

#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")

为什么会来回抢

短距离上滑时,这几件事会叠在一起:

  1. 目标冲突
    一套钉底,一套钉最新用户消息。只上滑一点时,两者经常同时成立。

  2. 程序滚动压制用户滚动
    程序滚动会设置:

    ignoreProgrammaticScrollUntil = now + 700ms

    这 700ms 内,用户滚动的意图处理会被跳过。

  3. near-bottom 被写回
    scrollUserMsgToTop() 会主动写:

    isNearBottomRef.current = ...

    用户正在上滑,仍可能被标成 near-bottom。
    下一帧 live-follow 又把人拽回去。

  4. 动画和布局互相打断

    • anchor 用 smooth
    • live-follow 用 auto
    • spacer 改变 scrollHeight,触发 ResizeObserver 重测
    • 流式过程中布局反复失效

所以不是“上滑没检测到”,而是:

检测到了,仍被两套程序滚动来回抢。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions