Reported
"In hands-free mode, when it has just started and says Listening, it is not transcribing or showing
any text/dictation. Only after I spoke for a while."
The composer reads a variable that stopped carrying speech
packages/sdk/src/voice/use-voice.ts:151:
// `interim` is now ONLY the composer's transient NOTICE line (mic errors, the wrong-language
// …
const [interim, setInterim] = useState("");
#281 promoted the live utterance to a first-class Dictation object (voice.dictation — text +
dictating/transcribing/failed status, words never blanked by a status change) and repurposed
interim as the notice line. The console was not updated with it. InstanceDetail.tsx:946:
value={voice.interim || input}
and :953 still styles the box for live speech when it is set:
${voice.interim ? "border-accent text-accent italic" : voice.micOn ? "border-green" : "border-line"}
So the accent-italic "you are speaking" treatment now fires only on a mic error, and the input can
never display speech — because speech no longer goes there.
What the user sees
In hands-free the top box shows its placeholder ("Listening…", :951) and stays empty for the whole
utterance. The words are being captured correctly and rendered correctly — as the voice.dictation
bubble at :1162, which is the last child of the message thread, i.e. below the fold, at the
opposite end of the screen from the input the user is watching.
Nothing is lost and nothing is broken in the voice pipeline. The live transcript is simply drawn
somewhere the reporter was not looking, while the place they were looking asserts "Listening…" and
shows nothing.
Two surfaces, one of them dead
This is the part worth fixing rather than papering over: there are currently two live-transcript
surfaces in the chat tab, and one of them has been disconnected since #281 without being removed. A
reader of InstanceDetail.tsx cannot tell which is authoritative, and the styling actively implies
the dead one is.
Fix
Stop binding the composer to voice.interim. voice.dictation is the single live-speech surface and
should stay that way.
interim still needs a home — it is the only thing that surfaces mic errors and the wrong-language
warning today, so it cannot simply be dropped. A small banner near the controls, not the input's
value (which also makes the input readOnly while a notice shows, :952).
Open, not proven
The dead binding fully explains "the box never shows my words". It does not necessarily explain
"only after I spoke for a while" — that half may additionally be the Web Speech gate's start-up
latency, since the gate is constructed and start()ed per turn (use-voice.ts:275-343) and cannot
emit onInterim until the engine boots. Worth measuring once the binding is fixed and the words are
somewhere visible; it may disappear entirely as a reporting artefact.
Related: #281 (the dictation object), #319 (the stored live capture), #365 (the layout change that
supersedes this).
Reported
The composer reads a variable that stopped carrying speech
packages/sdk/src/voice/use-voice.ts:151:#281 promoted the live utterance to a first-class
Dictationobject (voice.dictation— text +dictating/transcribing/failedstatus, words never blanked by a status change) and repurposedinterimas the notice line. The console was not updated with it.InstanceDetail.tsx:946:and
:953still styles the box for live speech when it is set:So the accent-italic "you are speaking" treatment now fires only on a mic error, and the input can
never display speech — because speech no longer goes there.
What the user sees
In hands-free the top box shows its placeholder (
"Listening…",:951) and stays empty for the wholeutterance. The words are being captured correctly and rendered correctly — as the
voice.dictationbubble at
:1162, which is the last child of the message thread, i.e. below the fold, at theopposite end of the screen from the input the user is watching.
Nothing is lost and nothing is broken in the voice pipeline. The live transcript is simply drawn
somewhere the reporter was not looking, while the place they were looking asserts "Listening…" and
shows nothing.
Two surfaces, one of them dead
This is the part worth fixing rather than papering over: there are currently two live-transcript
surfaces in the chat tab, and one of them has been disconnected since #281 without being removed. A
reader of
InstanceDetail.tsxcannot tell which is authoritative, and the styling actively impliesthe dead one is.
Fix
Stop binding the composer to
voice.interim.voice.dictationis the single live-speech surface andshould stay that way.
interimstill needs a home — it is the only thing that surfaces mic errors and the wrong-languagewarning today, so it cannot simply be dropped. A small banner near the controls, not the input's
value(which also makes the inputreadOnlywhile a notice shows,:952).Open, not proven
The dead binding fully explains "the box never shows my words". It does not necessarily explain
"only after I spoke for a while" — that half may additionally be the Web Speech gate's start-up
latency, since the gate is constructed and
start()ed per turn (use-voice.ts:275-343) and cannotemit
onInterimuntil the engine boots. Worth measuring once the binding is fixed and the words aresomewhere visible; it may disappear entirely as a reporting artefact.
Related: #281 (the dictation object), #319 (the stored live capture), #365 (the layout change that
supersedes this).