Skip to content

feat(api): report engine capabilities instead of declaring them twice - #1023

Open
Lvigentini wants to merge 1 commit into
jamiepine:mainfrom
Lvigentini:feat/engine-capabilities
Open

feat(api): report engine capabilities instead of declaring them twice#1023
Lvigentini wants to merge 1 commit into
jamiepine:mainfrom
Lvigentini:feat/engine-capabilities

Conversation

@Lvigentini

@Lvigentini Lvigentini commented Aug 9, 2026

Copy link
Copy Markdown

ModelConfig.supports_instruct is set deliberately on four configs and read nowhere. The desktop app gates its instruct field on its own hard-coded set instead:

// app/src/components/Generation/EngineModelSelector.tsx
const INSTRUCT_ENGINES = new Set(['qwen_custom_voice']);

Two places declaring the same fact. They drift the first time an engine is added — a new engine that honours instruct needs a frontend edit before the field appears, even though the registry already says it works.

Changes

engine_supports_instruct(), alongside the existing engine_needs_trim() and engine_retries_runaway(), so the flag is read where it is declared. Plus engine_languages() and engine_model_sizes() derived the same way.

GET /engines exposes the lot, so clients gate on capability rather than matching engine names:

{"engines": [
  {"engine": "qwen", "display_name": "Qwen TTS", "supports_instruct": false,
   "languages": ["zh","en","ja","ko","de","fr","ru","pt","es","it"],
   "model_sizes": ["1.7B","0.6B"], "has_model_sizes": true},
  {"engine": "qwen_custom_voice", "supports_instruct": true, ...}
]}

An engine whose variants disagree reports False. A request names an engine and the model size can change under it, so the conservative answer is the only one true for every variant.

No more silent drop. Base Qwen3-TTS accepts instruct and ignores it — backends/__init__.py:249 has said so all along:

supports_instruct=False,  # Base model drops instruct silently

The app hides the field there, so desktop users are fine. API and MCP callers get no such cue and watch their delivery instructions vanish with nothing logged anywhere — which reads as the model refusing to follow them rather than never receiving them. POST /generate and POST /generate/stream now log a warning naming the engines that do honour it.

Scope

No behaviour change to generation, and no change to which engines support what — only to whether that is discoverable. The frontend still uses its local set; swapping it to read /engines is a follow-up, and deliberately not bundled here so this stays backend-only and reviewable on its own.

Worth noting this does not fix #579. That reporter is putting delivery cues inline in the text on base Qwen, which has no instruct field at all — a different problem.

Tests

17, in backend/tests/test_engine_capabilities.py: the flag checked against the registry rather than restating it, the mixed-variant rule, derived languages and sizes, the endpoint checked against the helpers so the two can't diverge, and the warning including its negative cases — absent, empty, whitespace-only, and a capable engine.

Branched off main, independent of my other open PRs.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added an endpoint for viewing text-to-speech engine capabilities, including supported languages, model sizes, and instruction support.
    • Added consolidated capability information for each available engine.
  • Bug Fixes

    • Added warnings when delivery instructions are provided to engines that do not support them.
    • Improved handling of unsupported or unknown engines without reporting false capabilities.

`ModelConfig.supports_instruct` has been carried since the field was added and
read nowhere -- the flag existed, was set deliberately on four configs, and
nothing consulted it. The desktop app gates its instruct field on its own
hard-coded `INSTRUCT_ENGINES` set instead. Two places declaring the same fact,
which drift the first time an engine is added: a new engine that honours
`instruct` needs a frontend edit before the field appears, even though the
registry already says so.

Adds `engine_supports_instruct()` alongside the existing `engine_needs_trim()`
and `engine_retries_runaway()`, so the flag is finally read where it is
declared, plus `engine_languages()` and `engine_model_sizes()` derived the same
way. `GET /engines` exposes all of it, so clients can gate on capability rather
than matching engine names.

An engine whose variants disagree reports False. A request names an engine and
the model size can change under it, so the conservative answer is the only one
true for every variant.

Also stops the silent drop. Base Qwen3-TTS accepts `instruct` and ignores it --
the config comment has said so all along. The app hides the field there, but
API and MCP callers get no such cue and watch their delivery instructions
vanish with nothing logged anywhere, which reads as the model refusing to
follow them. `POST /generate` and `POST /generate/stream` now log a warning
naming the engines that do honour it.

No behaviour change to generation itself, and no change to which engines
support what -- only to whether that is discoverable.

17 tests: the flag against the registry, the mixed-variant rule, derived
languages and sizes, the endpoint against the helpers, and the warning
including its negative cases (absent, empty, whitespace, capable engine).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f72227dc-137e-4150-98e3-49e5f1c8e212

📥 Commits

Reviewing files that changed from the base of the PR and between 51f49de and 5c2be92.

📒 Files selected for processing (5)
  • backend/backends/__init__.py
  • backend/models.py
  • backend/routes/generations.py
  • backend/routes/models.py
  • backend/tests/test_engine_capabilities.py

📝 Walkthrough

Walkthrough

The backend derives TTS engine capabilities from the registry, exposes them through GET /engines, and warns when delivery instructions target engines without instruct support. Tests cover capability aggregation, endpoint output, mixed variants, and warning behavior.

Changes

TTS capabilities and instruction handling

Layer / File(s) Summary
Registry capability contract
backend/backends/__init__.py, backend/models.py
Adds registry helpers for instruct support, languages, model sizes, and consolidated engine capabilities. Adds response models for capability entries and lists.
Engine capability endpoint
backend/routes/models.py
Adds GET /engines, which returns registry-derived capability data using EngineCapabilitiesListResponse.
Instruction warnings and validation
backend/routes/generations.py, backend/tests/test_engine_capabilities.py
Adds warnings for ignored delivery instructions in standard and streaming generation. Tests cover capability reporting, endpoint consistency, mixed variants, and warning conditions.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: jamiepine

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR documents capabilities and warnings but does not fix the ineffective Qwen3-TTS-1.7B delivery instructions reported in issue #579. Implement or explicitly defer the issue's required behavior fix in a separate tracked issue, and link this PR only if it provides a necessary part of that fix.
Out of Scope Changes check ⚠️ Warning The capability API, registry helpers, and warning logic are not required to resolve the behavior described in issue #579. Remove unrelated capability-reporting changes or link them to a separate issue that defines this scope.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: reporting engine capabilities instead of duplicating declarations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

Qwen3-TTS-1.7B Natural-language delivery instructions Not effective

1 participant