mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-29 18:46:59 +00:00
fix(tools): keep command TTS deadline through exit
This commit is contained in:
parent
1b97e3efc5
commit
4e8a66dace
3 changed files with 36 additions and 9 deletions
|
|
@ -396,6 +396,32 @@ class TestRunCommandTts:
|
|||
assert read_sizes["stdout"][0] == 65536
|
||||
assert read_sizes["stderr"][0] == 65536
|
||||
|
||||
def test_closed_pipes_still_running_honors_idle_timeout(self):
|
||||
class ClosedStream:
|
||||
def read(self, size: int) -> str:
|
||||
return ""
|
||||
|
||||
class FakeProcess:
|
||||
def __init__(self):
|
||||
self.pid = 12345
|
||||
self.returncode = None
|
||||
self.stdout = ClosedStream()
|
||||
self.stderr = ClosedStream()
|
||||
|
||||
def wait(self, timeout=None):
|
||||
if timeout is None:
|
||||
self.returncode = 0
|
||||
return self.returncode
|
||||
raise subprocess.TimeoutExpired("fake tts", timeout)
|
||||
|
||||
process = FakeProcess()
|
||||
with (
|
||||
patch("tools.tts_tool.subprocess.Popen", return_value=process),
|
||||
patch("tools.tts_tool._terminate_command_tts_process_tree"),
|
||||
):
|
||||
with pytest.raises(subprocess.TimeoutExpired):
|
||||
_run_command_tts("fake tts", timeout=0.25)
|
||||
|
||||
def test_stderr_progress_extends_beyond_timeout(self, tmp_path):
|
||||
script = tmp_path / "progress_then_exit.py"
|
||||
script.write_text(
|
||||
|
|
|
|||
|
|
@ -1026,17 +1026,13 @@ def _run_command_tts(command: str, timeout: float) -> subprocess.CompletedProces
|
|||
|
||||
def read_stream(name: str, stream: Any) -> None:
|
||||
encoding = getattr(stream, "encoding", None) or "utf-8"
|
||||
read1 = getattr(getattr(stream, "buffer", None), "read1", None)
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
fd = stream.fileno()
|
||||
except (AttributeError, OSError):
|
||||
fd = None
|
||||
|
||||
if fd is None:
|
||||
if read1 is None:
|
||||
chunk = stream.read(65536)
|
||||
else:
|
||||
data = os.read(fd, 65536)
|
||||
data = read1(65536)
|
||||
chunk = data.decode(encoding, errors="replace")
|
||||
if not chunk:
|
||||
break
|
||||
|
|
@ -1076,6 +1072,12 @@ def _run_command_tts(command: str, timeout: float) -> subprocess.CompletedProces
|
|||
chunks[name].append(chunk)
|
||||
deadline = time.monotonic() + timeout
|
||||
|
||||
if not timed_out:
|
||||
try:
|
||||
proc.wait(timeout=max(0.0, deadline - time.monotonic()))
|
||||
except subprocess.TimeoutExpired:
|
||||
timed_out = True
|
||||
|
||||
if timed_out:
|
||||
_terminate_command_tts_process_tree(proc)
|
||||
for reader in readers:
|
||||
|
|
@ -1101,7 +1103,6 @@ def _run_command_tts(command: str, timeout: float) -> subprocess.CompletedProces
|
|||
|
||||
stdout = "".join(chunks["stdout"])
|
||||
stderr = "".join(chunks["stderr"])
|
||||
proc.wait()
|
||||
|
||||
if proc.returncode:
|
||||
raise subprocess.CalledProcessError(
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ Use `{{` and `}}` for literal braces.
|
|||
|
||||
| Key | Default | Meaning |
|
||||
|--------------------|---------|------------------------------------------------------------------------------------------------------------|
|
||||
| `timeout` | `120` | Seconds; the process tree is killed on expiry (Unix `killpg`, Windows `taskkill /T`). |
|
||||
| `timeout` | `120` | Idle seconds; stdout or stderr output resets the deadline. The process tree is killed after inactivity (Unix `killpg`, Windows `taskkill /T`). |
|
||||
| `output_format` | `mp3` | One of `mp3` / `wav` / `ogg` / `flac`. Auto-inferred from the output extension if Hermes picks a path. |
|
||||
| `voice_compatible` | `false` | When `true`, Hermes converts MP3/WAV output to Opus/OGG via ffmpeg so Telegram renders a voice bubble. |
|
||||
| `max_text_length` | `5000` | Input is truncated to this length before rendering the command. |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue