# Agents.md ## 业务自滚动吸顶原则 - 自动滚动的吸顶判断,应以“最后一条 AI 消息是否仍处于打字机动画中”为核心依据。 - 不要仅依赖 `isGenerating` 之类的请求状态来决定是否吸顶;请求结束不等于内容展示结束。 - 当自动滚动推进到最后一条 AI 消息顶部阈值时,应进入吸顶控制状态,避免打字机动画继续把内容顶出视口。 - 吸顶状态应是阶段性的、可退出的;同一轮滚动中避免反复触发或抖动。 - 用户发生手动滚动、触摸、鼠标滚轮或其他明确交互后,应重置吸顶状态,恢复默认滚动行为。 - PC 和 Mobile 的滚动策略应保持一致,差异只应来自平台滚动容器本身,而不是业务规则分叉。 - 调试阶段可以保留必要日志,用于判断吸顶是否触发、是否已停止自动滚动、当前滚动位置以及最后一条 AI 消息的打字状态。 ## 会话切换与消息状态原则 - 切换会话后,新会话应自动滚动到消息列表底部,保证用户直接看到最新上下文。 - 历史消息和实时生成消息应复用同一套消息状态判断,避免同一种业务状态在不同来源下表现不一致。 - AI 消息内容为空、被中断、请求取消,或只残留未完成的思考/查询 `scope` 时,应明确展示“请求已取消”。 - “请求已取消”的展示不应影响正常生成中的消息,也不应打断仍在流式追加的代码或文本内容。 ## Scope 动画与布局原则 - `scopeContent` 的进入、退出、淡入、淡出应交给 Vue `Transition`/`TransitionGroup` 管理,避免在业务逻辑中手写动画状态。 - `scopeContent` 退场只需要 fade,不需要 translate;退场过程中不应重置光点坐标,视觉位置应保持连续。 - `scope` 达到最大宽度前,标题、正文行和行列表应优先使用 ellipsis 隐藏换行内容;只有达到最大宽度后才允许自然换行。 - `scope-content-line` 与 `scope-line-list` 应遵循同一套宽度与换行规则,避免局部换行导致动画抖动。 - 当 `scope` 准备淡出时,不应通过临时 `position: absolute` 改变布局位置;布局稳定性应由外层高度锁定或过渡结构承担。 ## 打字机与 Markdown 渲染原则 - 文本打字机应由父级统一维护“当前可见行”和“当前正在打字的行”,避免多段文本同时竞争动画节奏。 - 一条 AI 回复中,后段内容可以先进入数据队列,但 UI 上应按顺序释放可见文本,保证阅读节奏自然。 - 请求流关闭不等于打字机结束;最后一个消息到达后,未完成的打字动画应继续执行直到文本全部展示完毕。 - 打字机每 tick 应推进稳定数量的字符,避免速度忽快忽慢;当前约定以每 tick 2 个字作为基础节奏。 - Markdown 内容在打字机过程中应尽量每 tick 实时 parse,使展示结构即时更新,减少纯文本与 Markdown 成品之间切换造成的抖动。 - `markdown-content.block-markdown` 不应自行设置 `min-height`;高度稳定应由外层消息容器或业务记录容器维护。 ## 消息高度稳定原则 - 最后一条 AI 消息处于打字机动画时,应在 `message-row.ai.is-last` 上维护最小高度,而不是让内部 Markdown 节点自行锁高。 - 该最小高度在打字机过程中只增不减,用来抵消 Markdown 重排、scope 淡出和文本接续造成的高度回缩。 - 当最后一条 AI 消息仍在视口内时,应保持最小高度;只有当 `business-record-body` 的底边已经接触滚动容器底部时,才允许释放高度锁。 - 高度锁应服务于滚动与动画稳定,不应成为永久布局样式。 ## 流式分段与节奏原则 - 流式解析应识别 `\n` 这样的自然边界,并在边界到达时立即 enqueue,避免 scope 结束后的正文被延迟到后续大段内容一起出现。 - `scope` 内容、普通正文、Markdown 标题和 followup JSON 等不同片段应保持清晰边界,便于动画、取消态和最终态分别处理。 - 流暂停输出 message 时,前端打字机仍应以自己的节奏继续推进;网络节奏不应直接决定文字动画是否流畅。 ## 调试入口原则 - 用于测试输入和 `playMockStreamMessage` 的按钮可以保留在 PC 端调试入口中,并应放在 `actions-right` 内、发送按钮左侧。 - 调试按钮不应影响 Mobile 端正式输入区,也不应改变用户发送消息的主流程。