Skip to content

[qa] 划词追问浮窗多处取消 race:Esc 关不掉流 / 烧 token / 跨会话漏字 / loading 帧丢失 #161

Description

@appergb

现象 / Symptom

划词追问(QA)浮窗在 LLM 流式输出过程中,关闭 / 取消 / 重开 流程存在多个观察可见的异常:

  1. Esc 没用:流式生成中按 Esc,浮窗界面消失,但 LLM 在后端仍持续生成(也仍在烧 token / 计费)。
  2. 跨会话漏字:取消后立刻重新打开浮窗 + 按 Option 开始第二轮提问,旧会话的 LLM chunk 仍会被推到新窗口,新气泡里"幽灵地"出现上一轮的剩余答案。
  3. 过渡帧丢失:从"录音"到"思考中"的中间过渡("识别中"/"loading"那一帧)UI 没渲染——用户体验上是"录音状态突然跳到完整答案",中间"识别中"的反馈空了几百毫秒到几秒。

复现

  1. 选段长文,Cmd+Shift+; 弹浮窗
  2. 按 Option,说几句长问题让 LLM 答 30+ 秒
  3. 流式刚开始(前 1-3 个气泡 chunk 已出)→ 按 Esc 关浮窗
  4. 立刻 Cmd+Shift+; 重开浮窗 → Option 录音问新问题
  5. 观察:新会话气泡里会冒出旧 LLM 的尾段;后端日志会看到旧 LLM 流持续发完整篇

根因

问题文件:行解释
Esc 走错路由coordinator.rs:744 handle_window_hotkey_event前端 QA 浮窗的 Esc → 后端无条件cancel_session(inner)(dictation 取消),从不查 qa_state.panel_visible
SSE 流无 cancel hookpolish.rs:286 chat_completion_history_streaming流式 loop while response.chunk().await 不查 qa_state.cancelled,没 tokio::select! abort signal;仅在 loop 结束后才有一次 cancelled 检查
on_delta 无 session_id 守卫coordinator.rs:1916on_delta 闭包仅捕获 Arc<Inner>,emit 时不验当前 qa_state.session_id 是否 == 启动时的;旧会话 chunk 漏进新会话
loading kind 后端发但前端不处理coordinator.rs:1815{kind:"loading"},但 QaPanel.tsx:51 switch 5 个 case 都不匹配;types.ts:105QaStateKind 联合也没 'loading'

影响

  • token 浪费:用户取消的流式仍计费到完整长度
  • 气泡污染:新会话出现旧字
  • 过渡反馈丢失:录音→思考中那一帧用户看不到反馈,体感"中断"
  • 平台:三平台(macOS/Windows/Linux)都受影响(流式逻辑跨平台)

建议 fix

  1. Esc 路由:在 handle_window_hotkey_event Esc 分支先查 panel_visible → 是 → cancel_qa_session + close_qa_panel;否 → 现行 dictation cancel
  2. SSE 取消:注入 Arc<AtomicBool>tokio_util::sync::CancellationToken,loop 每帧检查;cancel_qa_session flip 它
  3. session_id 守卫:on_delta 闭包捕获 let captured_id = inner.qa_state.lock().session_id;,每次 emit 前比对当前 id,不等就跳过
  4. loading 帧:后端去掉 loading 帧(直接发 thinking),或前端 QaPanel.tsx switch 加 case 'loading': setStatus('thinking'); break; + types.tsQaStateKind'loading'

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions