Skip to content

0.10.0 版本中,/retry(以及 /undo)只回滚了 UI 显示层:模型上下文与持久化会话仍保留被撤销的消息 #6788

Description

@w1w218

描述

/retry 的语义是「撤销上一次失败的交换,并重新发送上一条用户消息」。但实际行为是:

  • 界面显示:被撤销的消息从 transcript 消失(看起来只有一条);
  • 发给模型的上下文:被撤销的消息仍然存在,且每次重试都会再累积一条——AI 的思维链里会出现"用户连续发了 N 条重复的 xxx";
  • 持久化会话:磁盘上的会话记录也没有同步,退出后重新加载会话,被撤销的消息全部回归。

也就是说,/retry 只改了 UI 镜像,没有改变模型真正看到的上下文,也没有改变落盘的会话。

复现步骤

  1. 新开会话,发送一条消息;
  2. 手动连续执行 /retry 若干次(例如 10 次);
  3. 观察 TUI transcript:由于撤销,界面只显示一条消息;
  4. 观察模型侧的思维链/上下文:出现了多条重复的用户消息("用户连续发了 10 条重复的 xxx");
  5. 退出 TUI 并重新加载该会话:被撤销的消息全部重新出现。

预期行为

/retry 撤销后,以下三处应保持一致,都回到「重发前」的状态:

  • TUI 显示层;
  • 下一次模型请求的上下文;
  • 持久化的会话记录。

实际行为

只有 TUI 显示层被撤销;模型上下文和持久化记录都保留(甚至累积)了被撤销的消息。

根因

模型请求的消息源是 engine 内部的 session.messages(AppendLog),而不是 TUI 的 app.api_messages。而 /retry、/undo 的撤销逻辑(undo_conversation)只做了:

  • app.history 的 pop;
  • app.api_messages(TUI 镜像)的 pop。

它既不通知 engine 截断 session.messages,也不触发会话持久化(journal)的同步。engine 侧也没有任何「消息回滚」的 op 能力。因此在消息源从 TUI 镜像迁移到 engine 内部记录之后,undo/retry 命令没有跟着迁移,形成了"只撤 UI、不撤上下文和磁盘"的缺陷。

修复尝试

  1. engine 增加消息截断/回滚能力(session.messages.truncate_to + revision 失效),/undo、/retry 撤销后通知 engine 截断到撤销点;
  2. 撤销后同步持久化(journal 对齐 + 落盘),避免重进会话时撤销内容复活。

修改后,三者行为都保持了一致。再也不会出现 "用户连续发了很多次 xxx, 非常着急" 的思维链了

环境

  • 分支:0.10.0
  • 相关代码:crates/tui/src/commands/groups/debug/undo.rs(undo_conversation / retry)、crates/tui/src/core/session.rs(session.messages,AppendLog)

Activity

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

    bugSomething isn't working

    Projects

    • Status
      Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions