Skip to content

fix(tts): fail loud on unknown provider + CI guard preventing #797 regression#9

Merged
lmsanch merged 1 commit into
mainfrom
fix/tts-fail-loud-on-unknown-provider
Apr 23, 2026
Merged

fix(tts): fail loud on unknown provider + CI guard preventing #797 regression#9
lmsanch merged 1 commit into
mainfrom
fix/tts-fail-loud-on-unknown-provider

Conversation

@lmsanch

@lmsanch lmsanch commented Apr 23, 2026

Copy link
Copy Markdown
Owner

Summary

Permanence layer for the Fish Audio regression (lmsanch/toryx-private#797 / hermes-agent#8). Closes the mechanism by which the regression could happen again, not just the specific reverted commit.

Changes

tools/tts_tool.py — split the old catch-all else: into two paths:

  • elif provider == "edge": — the original Edge TTS + NeuTTS fallback logic (unchanged behavior when edge is explicitly configured)
  • else:loud failure: returns {"success": false, "error": "TTS provider 'X' is not implemented. Known providers: edge, elevenlabs, ..."}. Logs at ERROR level.

Before: any typo in tts.provider ("Fish" instead of "fish", or "fish" after a buggy revert) silently routed to Edge. You got audio back in a generic voice and no error surfaced. That's how NousResearch#797 went unnoticed for a day.

After: the same typo surfaces immediately with an explicit error listing the known providers.

tests/tools/test_tts_providers.py — new CI guard (4 tests):

  1. Every documented provider in REQUIRED_PROVIDERS has a _generate_* function in tts_tool.py
  2. Every documented provider has a provider == "..." dispatch branch
  3. The unknown-provider else must contain a loud-failure marker ("not implemented" or "Known providers")
  4. _generate_fish_audio specifically exists and has a dispatch branch (canary for the exact feat: add email gateway platform (IMAP/SMTP) NousResearch/hermes-agent#797 regression)

If anyone deletes Fish (or any provider), CI fails with a message pointing at NousResearch#797 and explaining the pattern. They must also remove it from REQUIRED_PROVIDERS with a deliberate human-reviewed commit to merge.

Test results (from the hermes-agent venv, locally)

✅ test_every_required_provider_has_a_dispatch_branch
✅ test_every_required_provider_has_a_generator_function
✅ test_fish_audio_specifically_present
✅ test_unknown_provider_fails_loud

What this does NOT do

  • Does not change behavior when provider is a known value — all existing Edge/Fish/OpenAI/etc. flows unchanged
  • Does not add a new provider
  • Does not prevent someone from merging a PR that removes a provider AND the test entry in the same commit — but that's now a visible, deliberate action (and a human reviewer has to approve it), not a silent side effect of a revert

Related

  • lmsanch/toryx-private#797 — Fish Audio regression (reopening for this permanence track)
  • hermes-agent#8 — the cherry-pick that restored Fish Audio (this PR adds the guard)

…earch#797 regression

Addresses the permanence gap revealed by toryx-private#797: commit
19098b0 reverted the Fish Audio implementation (_generate_fish_audio +
elif provider == 'fish' branch), and the broken state went unnoticed for
nearly a day because the dispatcher's final else: silently fell back to
Edge TTS. Ray's responses were generated in a generic Microsoft voice
instead of his cloned Fish voice, but no error ever surfaced.

This PR closes the mechanism:

1. text_to_speech_tool dispatch: unknown provider now returns a loud
   JSON error listing the known providers, rather than silently routing
   to Edge. The 'edge' default is preserved via an explicit
   elif provider == 'edge' branch.

2. tests/tools/test_tts_providers.py: new CI test that parses
   tts_tool.py and asserts every documented provider has a generator
   function AND a dispatch branch. Fish Audio has a dedicated canary
   test. Deleting Fish (or any other provider) will now fail CI.

Together these make the NousResearch#797-class regression impossible to re-ship
without an explicit, visible deletion from REQUIRED_PROVIDERS — which
a human reviewer has to approve.

Related: closes lmsanch/toryx-private#797 (reopened)
@lmsanch lmsanch merged commit 76bb951 into main Apr 23, 2026
@lmsanch lmsanch deleted the fix/tts-fail-loud-on-unknown-provider branch April 23, 2026 12:04
lmsanch added a commit that referenced this pull request May 23, 2026
…earch#797 regression (#9)

Addresses the permanence gap revealed by toryx-private#797: commit
19098b0 reverted the Fish Audio implementation (_generate_fish_audio +
elif provider == 'fish' branch), and the broken state went unnoticed for
nearly a day because the dispatcher's final else: silently fell back to
Edge TTS. Ray's responses were generated in a generic Microsoft voice
instead of his cloned Fish voice, but no error ever surfaced.

This PR closes the mechanism:

1. text_to_speech_tool dispatch: unknown provider now returns a loud
   JSON error listing the known providers, rather than silently routing
   to Edge. The 'edge' default is preserved via an explicit
   elif provider == 'edge' branch.

2. tests/tools/test_tts_providers.py: new CI test that parses
   tts_tool.py and asserts every documented provider has a generator
   function AND a dispatch branch. Fish Audio has a dedicated canary
   test. Deleting Fish (or any other provider) will now fail CI.

Together these make the NousResearch#797-class regression impossible to re-ship
without an explicit, visible deletion from REQUIRED_PROVIDERS — which
a human reviewer has to approve.

Related: closes lmsanch/toryx-private#797 (reopened)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant