Skip to content

[Bug] 编辑(撤回)排队中的消息丢失对话引用,并把 userselect 原始尾块内联进正文(重发后引用提示条也不再显示) #871

Open

Description

@jzcangshu

提交前确认 · Pre-submission checklist

  • 我已搜索过现有 issue,确认这不是重复 / I searched existing issues and confirmed this isn't a duplicate.
  • 我已阅读 CONTRIBUTING.md / I've read CONTRIBUTING.md.

问题类别 · Category

对话 / Agent 交互 · Agent chat

涉及的 Agent 框架 · Agent framework

ZCode Agent(自研)

严重程度 · Severity

影响体验 · Major (功能可用但体验受损 / works but degraded)

复现频率 · Reproducibility

必现 · Always

问题描述 · Description

编辑(撤回)一条带「对话引用」的排队消息时,引用 chip 不会恢复,输入框里反而多出一串 # userselect: 原始 JSON 尾块;这条消息再次发出后,气泡也不再显示正常情况下应有的引用内容提示条。尾块长这样:

# userselect:
```userselect
[{"text":"被引用的文字","path":"..."}]
```

根因定位(源码 + 安装版 bundle 双重核对,v3.14.4 渲染 bundle styles-Qlp0Bew7.js 与仓库 HEAD 一致):

对话引用没有协议级独立字段。发送时 composer 把四类外部上下文(对话引用 / 代码评论 / 网页元素 / PPTX 元素)按固定顺序序列化成正文尾块,这是模型可见的传输契约(packages/ui/src/v4/composer/composerPromptContexts.ts 的 serializeComposerPromptContexts;引用格式见 packages/ui/src/lib/conversationSelectionReference.ts 的 buildPromptWithConversationSelections)。因此消息入队时,ConversationInputIntent.text 存的就是含尾块的完整序列化 prompt。

而队列项「编辑」是撤回语义(deleteQueueItem ACK 后恢复到 composer),恢复链路把 item.text 原样 setText 回输入框,整条链路没有调用 parseComposerPromptContexts 把尾块拆回上下文状态:

  • SessionPane.handleEditQueueItem → resolveQueuedComposerRestore(SessionPane.tsx:453,text: v4QueuedCommandText(item.kind, item.text) 原样取用)
  • → ConversationComposer.applyComposerRestoreRequestToComposer(ConversationComposer.tsx:304,inputApi.setText(request.text))

于是引用 chip 状态不恢复(引用 UI 消失),# userselect: JSON 尾块成为输入框可见正文。

重发后提示条消失的机制:气泡侧 UserInputRowView 依赖尾锚定正则识别并隐藏尾块、渲染引用提示条:

/(?:\n\n)?# userselect:\n```userselect\n([\s\S]*?)\n```\s*$/

撤回后的文本经编辑(光标通常在末尾,新输入落在块之后)后块不再位于末尾,解析失败 → 裸块按正文渲染、提示条不出现。

影响面:同一根因也影响代码评论 / 网页元素 / PPTX 元素三类尾块——撤回编辑都会把它们原样内联为正文,不只对话引用。

复现步骤 · Steps to reproduce

  1. 让 agent 处于忙碌状态(turn 进行中),使后续发送的消息进入队列。
  2. 选中此前某条消息的一段文字 → 点「添加到会话中」,输入框出现引用 chip。
  3. 输入文字并发送 → 消息连引用一起进入队列(队列行只显示截断文本,引用此时不可见)。
  4. 点该队列项的「编辑」(铅笔)按钮,把消息撤回到输入框。
  5. 观察输入框:引用 chip 消失,正文末尾出现 # userselect: + userselect [...] 原始 JSON 块。
  6. 把修改文字打在末尾后再次发送 → 消息气泡显示裸 JSON 块作为正文,且没有引用内容提示条。

期望表现 · Expected behavior

撤回编辑后引用 chip 应恢复原样,输入框正文不含任何序列化尾块;再次发送后气泡正常显示引用内容提示条。

实际表现 · Actual behavior

撤回后引用 chip 丢失,# userselect: JSON 块成为可见正文;重发后气泡不显示引用提示条(当编辑文字落在块之后时,裸块会永久显示在气泡正文里)。

ZCode 版本 · ZCode version

v3.14.4(Desktop)

设备 / 系统 / 浏览器 · Device / OS / Browser

Windows 11 x64(10.0.22631)

截图 / 录屏 / 日志 · Screenshots / Recordings / Logs

纯文本即可稳定复现。修复建议:

  • 方案 A(最小修复,纯反解析):resolveQueuedComposerRestore 对 item.text 执行 parseComposerPromptContexts,text 恢复为 visibleContent,解析出的四类上下文随 ComposerRestoreRequest 传回 composer 一并恢复。代码评论 / 网页元素 / PPTX 元素可完整还原;对话引用尾块只含 {text, path}(发送契约有意剥离内部元数据),而 ConversationSelectionReferenceChip 本就支持展示型引用,可降级渲染(无来源行、不支持单条删除)。
  • 方案 B(完全保真):入队成功时 renderer 按 queueItemId 快照完整引用状态(队列本身即非持久态,生命周期一致),撤回时优先用快照恢复完整 chip;快照缺失(renderer 重载)时回退方案 A。

临时规避:撤回后手动删除输入框中的 userselect 尾块,再重新选中原消息文字点「添加到会话中」。

Activity

  1. github-actions commented on Sep 29, 2026

    @github-actions

    👋 感谢你的反馈,我们已经收到。

    • 维护者看到后会尽快回复你。
    • 状态保持为 status: 待评估,你可以随时补充信息。
    • 信息不全时我们会打上 needs: 更多信息 标签并 @ 你。

    👋 Thanks — we've received your issue.

    • A maintainer will get back to you as soon as we can.
    • Status stays at status: 待评估 (Triage); feel free to add context.
    • If we need more details, we'll add needs: 更多信息 and ping you.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions