mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(tui): break TTS→STT feedback loop + colorize REC badge
TTS feedback loop (hermes_cli/voice.py)
The VAD loop kept the microphone live while speak_text played the
agent's reply over the speakers, so the reply itself was picked up,
transcribed, and submitted — the agent then replied to its own echo
("Ha, looks like we're in a loop").
Ported cli.py:_voice_tts_done synchronisation:
- _tts_playing: threading.Event (initially set = "not playing").
- speak_text cancels the active recorder before opening the speakers,
clears _tts_playing, and on exit waits 300 ms before re-starting the
recorder — long enough for the OS audio device to settle so afplay
and sounddevice don't race for it.
- _continuous_on_silence now waits on _tts_playing (up to 60 s) before
re-arming the mic with another 300 ms gap, mirroring
cli.py:10619-10621. If the user flips voice off during the wait the
loop exits cleanly instead of fighting for the device.
Without both halves the loop races: if the silence callback fires
before TTS starts it re-arms immediately; if TTS is already playing
the pause-and-resume path catches it.
Red REC badge (ui-tui appChrome + useMainApp)
Classic CLI (cli.py:_get_voice_status_fragments) renders "● REC" in
red and "◉ STT" in amber. TUI was showing a dim "REC" with no dot,
making it hard to spot at a glance. voiceLabel now emits the same
glyphs and appChrome colours them via t.color.error / t.color.warn,
falling back to dim for the idle label.
This commit is contained in:
parent
42ff785771
commit
98418afd5d
3 changed files with 91 additions and 2 deletions
|
|
@ -716,7 +716,9 @@ export function useMainApp(gw: GatewayClient) {
|
|||
statusColor: statusColorOf(ui.status, ui.theme.color),
|
||||
stickyPrompt,
|
||||
turnStartedAt: ui.sid ? turnStartedAt : null,
|
||||
voiceLabel: voiceRecording ? 'REC' : voiceProcessing ? 'STT' : `voice ${voiceEnabled ? 'on' : 'off'}`
|
||||
// CLI parity: the classic prompt_toolkit status bar shows a red dot
|
||||
// on REC (cli.py:_get_voice_status_fragments line 2344).
|
||||
voiceLabel: voiceRecording ? '● REC' : voiceProcessing ? '◉ STT' : `voice ${voiceEnabled ? 'on' : 'off'}`
|
||||
}),
|
||||
[
|
||||
cwd,
|
||||
|
|
|
|||
|
|
@ -215,7 +215,20 @@ export function StatusRule({
|
|||
</Text>
|
||||
) : null}
|
||||
<SpawnHud t={t} />
|
||||
{voiceLabel ? <Text color={t.color.dim}> │ {voiceLabel}</Text> : null}
|
||||
{voiceLabel ? (
|
||||
<Text
|
||||
color={
|
||||
voiceLabel.startsWith('●')
|
||||
? t.color.error
|
||||
: voiceLabel.startsWith('◉')
|
||||
? t.color.warn
|
||||
: t.color.dim
|
||||
}
|
||||
>
|
||||
{' │ '}
|
||||
{voiceLabel}
|
||||
</Text>
|
||||
) : null}
|
||||
{bgCount > 0 ? <Text color={t.color.dim}> │ {bgCount} bg</Text> : null}
|
||||
{showCost && typeof usage.cost_usd === 'number' ? (
|
||||
<Text color={t.color.dim}> │ ${usage.cost_usd.toFixed(4)}</Text>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue