github / github/copilot-cli

Voice (PTT): typing during the finalize window drops the dictated transcript

未关闭
#3,896 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
area:input-keyboard
主要语言
Shell
星标
11.2k
派生
1.9k
平均合并
14 小时 16 分钟
30 天内合并 PR
6

描述

### Summary

When using **push-to-talk (PTT) voice dictation** (hold the trigger key, speak, release), if I start typing before the final transcript lands, my **entire dictation is lost**. The grey "preview" text disappears and is replaced by whatever I type.

### Steps to reproduce

1. Place the cursor in the prompt input.
2. Hold the voice push-to-talk trigger, speak a sentence (the live transcription appears as **grey/dim preview text**), then release the key.
3. Immediately — before the text turns solid/committed (white) — type any character.

### Expected

The pending dictation should be committed first (the grey preview becomes real text), and my typed character should be appended after it. I should not lose what I dictated.

### Actual

The grey preview text is cleared and the finalized transcript is **dropped entirely**. Only the character I typed remains. The whole dictation is lost.

### Root cause (from inspecting the bundled `app.js`, v1.0.63)

The voice reactor hook (`ycr`) drives a small state machine: `idle → recording → finalizing → idle`.

- During recording, streaming partial transcripts are shown via the input controller's `setPreview(...)` — this is the **grey/dim preview** text.
- Releasing the PTT key calls `finishSession({ commit: true })` and moves to the `finalizing` state, while the speech engine **asynchronously** drains audio and returns the final transcript.
- The keyboard handler only intercepts/commits a keystroke when `mode === "dictation" && state === "recording"`:

```js
if (Fe && Fe.mode === "dictation" && x.current === "recording" && (he.length > 0 || ...))
return fe(), true; // commit + swallow the key
```

In **PTT mode**, and during the **`finalizing`** window, this guard is false, so the keystroke is **not** intercepted — it falls through into the input box and mutates the buffer.
- When `finishSession` resolves, the result handler (`ae`) clears the preview and, **for PTT specifically**, performs a strict snapshot check against the recording anchor:

```js
if (he.mode === "ptt") {
if (Ge.text !== he.anchor.before + he.anchor.after || Ge.cursorPosition !== he.anchor.pos) {
// logs: "ptt: snapshot diverged after release; dropped transcript"
return; // <-- DROPS the transcript
}
Ge.insertInput(...);
} else {
// dictation (toggle) mode: on divergence it still inserts at the current cursor (does NOT drop)
}
```

Because the user typed during the `finalizing` window, the input no longer matches the anchor, so the PTT branch hits the divergence guard and **drops the transcript**. Dictation (toggle) mode does **not** drop on divergence — it recovers by inserting at the current cursor. This asymmetry is the bug: PTT loses the dictation, toggle mode does not.

### Suggested fixes (either would resolve it)

1. **Queue keystrokes during `finalizing`**: while a session is finalizing, hold incoming keystrokes until the transcript is inserted (mirrors how dictation-while-recording already swallows the first keystroke to commit), then apply them. This commits the grey preview before the typed text.
2. **Make PTT recover like dictation**: on snapshot divergence, insert the committed transcript at the current cursor position instead of dropping it. This is the smaller change and preserves the dictation in every case.

### Environment

- GitHub Copilot CLI `v1.0.63`
- Platform: Linux
- Voice mode: push-to-talk (hold-to-talk)

贡献指南

打开贡献指南

调研方向

Start by reproducing the PTT sequence in the CLI, then inspect the bundled app.js v1.0.63 around the voice reactor hook ycr, finishSession, the keyboard handler, and result handler ae. Verify that typing during finalizing preserves the pending transcript and appends the typed character, rather than triggering the snapshot-divergence drop.

由索引模型根据 Issue 内容生成。

评估

技术栈
javascript
领域
audio-video-rtc, cli
Issue 类型
缺陷
难度
3/5
预计耗时
1-2 天
活跃度
冷清
描述清晰度
描述清楚
新手友好度
55/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。