You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It is not capturing everything I'm saying. I want everything I say transcribed into the message as
I speak it, in the thread right away. Currently the transcribed text disappears after I submit and
reappears once the LLM has processed it. I want to see what I said (dictation), then the converted
transcription, and a status on the message in the thread saying it is being transcribed.
Where the text actually goes today
The live transcript lives in the composer, never in the thread, and it is destroyed at
end-of-turn:
Speaking → streamed partials land in voice.interim, rendered in the textarea
(InstanceDetail.tsx:786, value={voice.interim || input} — accent, italic, readOnly).
End-of-turn → use-voice.ts:312 does setInterim("Transcribing…"). The words you just spoke
are overwritten by that literal string. This is the disappearance in the report — it is not a
race or a dropped update, it is an assignment.
Final transcript returns → onSend → doSend → only now is a user message appended
(InstanceDetail.tsx:405).
So there is a window — the whole upload-and-transcribe round trip — where the user's words exist
nowhere on screen. In hands-free that window is exactly when the user is not looking at the
composer and expects to see what was heard.
What is being asked for
Move the utterance into the thread, as a real message with a lifecycle, instead of a transient
composer value:
State
Shows
dictating
live partials, updating as spoken, in a pending user bubble
transcribing
the same bubble, with a "transcribing" status on it
sent
replaced in place by the final transcript
failed
stays, with the failure and the audio retained so nothing is silently lost
doSend already appends optimistically, so the pattern exists — it just starts too late. The bubble
should be created when speech starts, not when transcription ends.
The capture-loss half, and why the fix above is also the diagnostic
Evidence from the Coder Lead thread (all voice turns, all with audioKey):
"Coder Lead" — a bare fragment, alone as a whole turn.
"What do they need to do for this model?" → the agent replied "I don't have context on what
'this model' refers to." The referent is missing, consistent with words being cut.
Candidate causes, all plausible and not currently distinguishable from the outside:
the VAD ends the turn mid-sentence (silenceMs / sensitivity) and the tail is never recorded;
the final Whisper transcript replaces the streamed partials, so anything the partials caught
but the final pass dropped is lost with no trace;
isTooShortToTranscribe discards a clip that did contain speech.
Right now a lost tail is invisible: the partials are gone (overwritten by "Transcribing…") and
only the final text is ever recorded. Keeping the dictation in the thread makes the loss
observable — if the bubble showed "…verify the application is built on the platform for the MCP"
during dictation and the final message reads "…for this model", the discrepancy is on screen and
reportable instead of a vague feeling that words go missing.
Worth logging both strings (partial-at-end-of-turn vs final) when they diverge materially, at least
behind a debug flag, so the cause can be identified rather than guessed.
Notes
Voice transcription lost when agent message arrives mid-dictation #175 (turn lost when an agent message arrives mid-dictation) is fixed and recovers text into the
composer via onRecoveredText. That is the same instinct as this ticket — do not throw away what
the user said — applied one step earlier.
The audio is already persisted per turn (audioKey, replay on double-tap), so a failed or
suspect transcription always has the original to fall back on.
Verification
Speaking in hands-free shows a pending user bubble in the thread that updates as words arrive.
The bubble is never blanked; it carries a transcribing status until the final text replaces it.
A failed transcription leaves the bubble with its partials and the recording, not an empty gap.
Where the final transcript materially differs from the last partial, the divergence is recorded.
The report
Where the text actually goes today
The live transcript lives in the composer, never in the thread, and it is destroyed at
end-of-turn:
voice.interim, rendered in the textarea(
InstanceDetail.tsx:786,value={voice.interim || input}— accent, italic,readOnly).use-voice.ts:312doessetInterim("Transcribing…"). The words you just spokeare overwritten by that literal string. This is the disappearance in the report — it is not a
race or a dropped update, it is an assignment.
onSend→doSend→ only now is a user message appended(
InstanceDetail.tsx:405).So there is a window — the whole upload-and-transcribe round trip — where the user's words exist
nowhere on screen. In hands-free that window is exactly when the user is not looking at the
composer and expects to see what was heard.
What is being asked for
Move the utterance into the thread, as a real message with a lifecycle, instead of a transient
composer value:
dictatingtranscribingsentfaileddoSendalready appends optimistically, so the pattern exists — it just starts too late. The bubbleshould be created when speech starts, not when transcription ends.
The capture-loss half, and why the fix above is also the diagnostic
Evidence from the Coder Lead thread (all voice turns, all with
audioKey):"Coder Lead"— a bare fragment, alone as a whole turn."What do they need to do for this model?"→ the agent replied "I don't have context on what'this model' refers to." The referent is missing, consistent with words being cut.
Candidate causes, all plausible and not currently distinguishable from the outside:
silenceMs/ sensitivity) and the tail is never recorded;but the final pass dropped is lost with no trace;
isTooShortToTranscribediscards a clip that did contain speech.Right now a lost tail is invisible: the partials are gone (overwritten by
"Transcribing…") andonly the final text is ever recorded. Keeping the dictation in the thread makes the loss
observable — if the bubble showed "…verify the application is built on the platform for the MCP"
during dictation and the final message reads "…for this model", the discrepancy is on screen and
reportable instead of a vague feeling that words go missing.
Worth logging both strings (partial-at-end-of-turn vs final) when they diverge materially, at least
behind a debug flag, so the cause can be identified rather than guessed.
Notes
composer via
onRecoveredText. That is the same instinct as this ticket — do not throw away whatthe user said — applied one step earlier.
audioKey, replay on double-tap), so a failed orsuspect transcription always has the original to fall back on.
Verification