Follow-up to #281, which fixed the visibility of a turn in flight. This is about keeping the
dictation after the turn ends.
The ask
Tap a voice message and see what was captured live (the dictation), instead of only the final
transcript. Then the two can be compared.
Today the comparison is impossible, not just hidden
AgentMessage (agent-types.ts:1) carries:
role · content · channel · userId · toolCalls · toolResults · audioKey · createdAt
There is no field for the live transcript, and nothing client-side ever sends it — the partials
live in browser state and are overwritten by "Transcribing…" at end-of-turn. So for every voice
turn already in the thread, the dictation is gone. Asked "is anything missing from what I
said?", the honest answer is that the platform cannot tell.
Only two artefacts survive: the final transcript (the message) and the audio (audioKey → R2).
Proposal
1. Persist the dictation next to the transcript. One nullable field on the message — the last
partial at end-of-turn — sent alongside audioKey on the same request that already carries it. No
new transport, no new round trip.
2. Tap to switch the bubble between transcript and dictation. Double-tap already replays the
audio, so the gesture vocabulary becomes: read what was sent · read what was heard · hear what was
said. Only show the toggle where a dictation was actually stored, so old turns do not sprout a dead
affordance.
3. Flag divergence. Where the final transcript differs materially from the last partial, mark
it — that is the signal the user has been describing as "it is not capturing everything I say", and
right now it is invisible on both sides. A count of dropped words is enough; the detail is one tap
away.
Retrospective check, for turns already past
The audio is still there, so the question can be answered for existing messages by re-transcribing
voice-audio/:turnId and diffing against the stored content. Worth doing once as a diagnostic
over a real thread — if the recordings contain words the messages do not, that localises the loss
to transcription rather than to capture, and the reverse localises it to the VAD cutting the turn.
That is the measurement neither #281 nor this ticket can substitute for; both make the loss
visible going forward, but only re-transcription says what already went missing.
Cost and scope
- One nullable text column's worth of data per voice turn, bounded by the same size limits as the
message content.
- Should respect the same retention as the audio — a dictation outliving its recording is odd, and
clearing the chat already deletes the R2 blobs.
- No change to what is sent to the model. The dictation is a user-facing artefact, not context —
feeding both versions to the LLM would be strictly worse.
Verification
- A voice turn stores both strings; a typed turn stores neither.
- Tapping toggles; double-tap still replays; a turn with no stored dictation shows no toggle.
- A deliberately clipped utterance shows a divergence flag.
- Clearing the chat removes dictation, transcript and audio together.
Follow-up to #281, which fixed the visibility of a turn in flight. This is about keeping the
dictation after the turn ends.
The ask
Tap a voice message and see what was captured live (the dictation), instead of only the final
transcript. Then the two can be compared.
Today the comparison is impossible, not just hidden
AgentMessage(agent-types.ts:1) carries:There is no field for the live transcript, and nothing client-side ever sends it — the partials
live in browser state and are overwritten by
"Transcribing…"at end-of-turn. So for every voiceturn already in the thread, the dictation is gone. Asked "is anything missing from what I
said?", the honest answer is that the platform cannot tell.
Only two artefacts survive: the final transcript (the message) and the audio (
audioKey→ R2).Proposal
1. Persist the dictation next to the transcript. One nullable field on the message — the last
partial at end-of-turn — sent alongside
audioKeyon the same request that already carries it. Nonew transport, no new round trip.
2. Tap to switch the bubble between transcript and dictation. Double-tap already replays the
audio, so the gesture vocabulary becomes: read what was sent · read what was heard · hear what was
said. Only show the toggle where a dictation was actually stored, so old turns do not sprout a dead
affordance.
3. Flag divergence. Where the final transcript differs materially from the last partial, mark
it — that is the signal the user has been describing as "it is not capturing everything I say", and
right now it is invisible on both sides. A count of dropped words is enough; the detail is one tap
away.
Retrospective check, for turns already past
The audio is still there, so the question can be answered for existing messages by re-transcribing
voice-audio/:turnIdand diffing against the stored content. Worth doing once as a diagnosticover a real thread — if the recordings contain words the messages do not, that localises the loss
to transcription rather than to capture, and the reverse localises it to the VAD cutting the turn.
That is the measurement neither #281 nor this ticket can substitute for; both make the loss
visible going forward, but only re-transcription says what already went missing.
Cost and scope
message content.
clearing the chat already deletes the R2 blobs.
feeding both versions to the LLM would be strictly worse.
Verification