mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
fix(tts): find_voices={} browses voices instead of falling to speech
An empty find_voices object is the model's way to browse the library with the
defaults, but a truthiness check sent it down the speech path ('Text is
required', or audio instead of a search). Check for presence, in the handler and
the display formatter (Greptile P1 on #144633).
This commit is contained in:
1 parent
f9d17adfe9
commit
ff29484938
3 files changed
+11
-4
No files matched your search
+1
-1
@@ -1266,7 +1266,7 @@ _CUTE_LINES = {
|
||||
"image_generate": lambda a, r: _cute_row("🎨", "create", _cute_trunc(a.get("prompt", ""))),
|
||||
"text_to_speech": lambda a, r: (
|
||||
_cute_row("🗣️ ", "voices", _cute_trunc((a.get("find_voices") or {}).get("query") or "browse"))
|
||||
if isinstance(a.get("find_voices"), dict) and a["find_voices"]
|
||||
if isinstance(a.get("find_voices"), dict)
|
||||
else _cute_row("🔊", "speak", _cute_trunc(a.get("text", "")))),
|
||||
"vision_analyze": lambda a, r: _cute_row("👁️ ", "vision", _cute_trunc(a.get("question", ""))),
|
||||
"send_message": lambda a, r: _cute_row("📨", "send", f"{a.get('target', '?')}: \"{_cute_trunc(a.get('message', ''))}\""),
|
||||
|
||||
@@ -70,6 +70,10 @@ def test_voice_id_reaches_elevenlabs_and_is_ignored_elsewhere(tmp_path):
|
||||
"use case": "characters"},
|
||||
"preview_url": "https://example.test/bram.mp3"}],
|
||||
"has_more": True, "next_page_token": "tok-2"}, "tok-2"),
|
||||
({}, "/v1/shared-voices", # an empty object browses the library with the defaults
|
||||
{"sort": "usage_character_count_1y", "page": 0, "page_size": 20},
|
||||
{"voices": [{"voice_id": "lib2", "name": "Bram", "gender": "male", "accent": "scottish"}],
|
||||
"has_more": False}, None),
|
||||
])
|
||||
def test_find_voices_pages_both_sources(find, path, expected_params, body, next_page):
|
||||
calls = []
|
||||
@@ -81,7 +85,10 @@ def test_find_voices_pages_both_sources(find, path, expected_params, body, next_
|
||||
with patch("tools.tts_tool._load_tts_config", return_value=_EL_CONFIG), \
|
||||
patch("tools.tts_tool._resolve_provider_key", return_value="el-test-key"), \
|
||||
patch("tools.tts_elevenlabs_voices.httpx.get", side_effect=fake_get):
|
||||
result = json.loads(tts_tool.text_to_speech_tool("", find_voices=find))
|
||||
from tools.registry import registry # through the registered handler, as the model calls it
|
||||
entry = registry.get_entry("text_to_speech")
|
||||
assert entry is not None
|
||||
result = json.loads(entry.handler({"find_voices": find}))
|
||||
bad_page = json.loads(tts_tool.text_to_speech_tool("", find_voices={"page": "tok-2"}))
|
||||
url, params, headers = calls[0]
|
||||
assert url == "https://api.elevenlabs.io" + path and headers["xi-api-key"] == "el-test-key"
|
||||
@@ -90,7 +97,7 @@ def test_find_voices_pages_both_sources(find, path, expected_params, body, next_
|
||||
assert result["success"] and result["next_page"] == next_page
|
||||
assert row["gender"] == "male" and row["accent"] == "scottish"
|
||||
assert result["configured_voice_id"] == "configuredVoice001"
|
||||
if path == "/v1/shared-voices":
|
||||
if "total_count" in body:
|
||||
assert result["total"] == 812 and len(row["description"]) == 240 and row["credit_rate"] == 2
|
||||
assert not bad_page["success"] and len(calls) == 1 # a cursor token is not a library page
|
||||
|
||||
|
||||
+1
-1
@@ -509,7 +509,7 @@ def text_to_speech_tool(
|
||||
sequentially, then packed against the platform's upload limit: a failed combine keeps the
|
||||
separate valid files and no over-limit artifact is ever returned. ``find_voices`` (ElevenLabs
|
||||
only) searches voices instead of speaking."""
|
||||
if find_voices:
|
||||
if find_voices is not None: # {} = browse with the defaults
|
||||
return _find_voices(find_voices)
|
||||
if not text or not text.strip():
|
||||
return tool_error("Text is required", success=False)
|
||||
|
||||
Reference in new issue
Block a user