mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-13 03:52:00 +00:00
fix(tui): restore voice push-to-talk parity (#20897)
* fix(tui): restore classic CLI voice push-to-talk parity
(cherry picked from commit 93b9ae301b)
* fix(tui): harden voice push-to-talk stop flow
Address review feedback from PR #16189 by stopping the active recorder before background transcription, documenting single-shot voice capture, and covering the TUI gateway flags with regression tests.
* fix(tui): preserve silent voice strike tracking
Keep single-shot voice recording's no-speech counter alive across starts so the TUI can still emit the three-strikes auto-disable event, and bind the auto-restart state at module scope for type checking.
* fix(tui): clean up voice stop failure path
Address follow-up review by naming the TUI flow as single-shot push-to-talk and cancelling the recorder when forced stop cannot produce a WAV.
* fix(tui): report busy voice capture starts
Return explicit start state from the voice wrapper so the TUI gateway does not report recording while forced-stop transcription is still cleaning up.
* fix(tui): handle busy voice record responses
Apply the gateway busy status immediately in the TUI and route forced-stop voice events to the session that sent the stop request.
* fix(tui): clear voice recording on null response
Treat a null voice.record RPC result as a failed optimistic start so the REC badge cannot stick after gateway-side errors.
* fix(tui): count silent manual voice stops
Preserve single-shot voice no-speech strikes through forced stop transcription so empty push-to-talk captures still trigger the three-strikes guard.
---------
Co-authored-by: Montbra <montbra@gmail.com>
This commit is contained in:
parent
5ccab51fa8
commit
04cf4788cc
7 changed files with 527 additions and 57 deletions
|
|
@ -204,6 +204,7 @@ def test_voice_record_start_handles_non_dict_voice_cfg(monkeypatch):
|
|||
assert resp["result"]["status"] == "recording"
|
||||
assert captured["silence_threshold"] == 200
|
||||
assert captured["silence_duration"] == 3.0
|
||||
assert captured["auto_restart"] is False
|
||||
|
||||
# Round-12 Copilot review regression on #19835: ``bool`` is a subclass
|
||||
# of ``int``, so the naive ``isinstance(threshold, (int, float))``
|
||||
|
|
@ -232,6 +233,80 @@ def test_voice_record_start_handles_non_dict_voice_cfg(monkeypatch):
|
|||
assert (
|
||||
captured["silence_duration"] == 3.0
|
||||
), f"bool silence_duration leaked through for {bad_bool_cfg!r}"
|
||||
assert captured["auto_restart"] is False
|
||||
|
||||
|
||||
def test_voice_record_stop_forces_transcription(monkeypatch):
|
||||
captured: dict = {}
|
||||
|
||||
def fake_stop_continuous(**kwargs):
|
||||
captured.update(kwargs)
|
||||
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"hermes_cli.voice",
|
||||
types.SimpleNamespace(
|
||||
start_continuous=lambda **_kwargs: None,
|
||||
stop_continuous=fake_stop_continuous,
|
||||
),
|
||||
)
|
||||
|
||||
resp = server.dispatch(
|
||||
{
|
||||
"id": "voice-record-stop",
|
||||
"method": "voice.record",
|
||||
"params": {"action": "stop"},
|
||||
}
|
||||
)
|
||||
|
||||
assert resp["result"]["status"] == "stopped"
|
||||
assert captured["force_transcribe"] is True
|
||||
|
||||
|
||||
def test_voice_record_stop_updates_event_session_id(monkeypatch):
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"hermes_cli.voice",
|
||||
types.SimpleNamespace(
|
||||
start_continuous=lambda **_kwargs: True,
|
||||
stop_continuous=lambda **_kwargs: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(server, "_voice_event_sid", "old-session")
|
||||
|
||||
resp = server.dispatch(
|
||||
{
|
||||
"id": "voice-record-stop-session",
|
||||
"method": "voice.record",
|
||||
"params": {"action": "stop", "session_id": "new-session"},
|
||||
}
|
||||
)
|
||||
|
||||
assert resp["result"]["status"] == "stopped"
|
||||
assert server._voice_event_sid == "new-session"
|
||||
|
||||
|
||||
def test_voice_record_start_reports_busy_when_stop_is_in_progress(monkeypatch):
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"hermes_cli.voice",
|
||||
types.SimpleNamespace(
|
||||
start_continuous=lambda **_kwargs: False,
|
||||
stop_continuous=lambda **_kwargs: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setenv("HERMES_VOICE", "1")
|
||||
monkeypatch.setattr(server, "_load_cfg", lambda: {"voice": {}})
|
||||
|
||||
resp = server.dispatch(
|
||||
{
|
||||
"id": "voice-record-busy",
|
||||
"method": "voice.record",
|
||||
"params": {"action": "start"},
|
||||
}
|
||||
)
|
||||
|
||||
assert resp["result"]["status"] == "busy"
|
||||
|
||||
|
||||
def test_voice_toggle_tts_branch_also_carries_record_key(monkeypatch):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue