fix(model-normalize): pass DeepSeek V-series IDs through instead of folding to deepseek-chat#15119
Closed
0xbyt4 wants to merge 1 commit into
Closed
fix(model-normalize): pass DeepSeek V-series IDs through instead of folding to deepseek-chat#151190xbyt4 wants to merge 1 commit into
0xbyt4 wants to merge 1 commit into
Conversation
…olding to deepseek-chat
`_normalize_for_deepseek` was mapping every non-reasoner input into
`deepseek-chat` on the assumption that DeepSeek's API accepts only two
model IDs. That assumption no longer holds — `deepseek-v4-pro` and
`deepseek-v4-flash` are first-class IDs accepted by the direct API,
and on aggregators `deepseek-chat` routes explicitly to V3 (DeepInfra
backend returns `deepseek-chat-v3`). So a user picking V4 Pro through
the model picker was being silently downgraded to V3.
Verified 2026-04-24 against Nous portal's OpenAI-compat surface:
- `deepseek/deepseek-v4-flash` → provider: DeepSeek,
model: deepseek-v4-flash-20260423
- `deepseek/deepseek-chat` → provider: DeepInfra,
model: deepseek/deepseek-chat-v3
Fix:
- Add `deepseek-v4-pro` and `deepseek-v4-flash` to
`_DEEPSEEK_CANONICAL_MODELS` so exact matches pass through.
- Add `_DEEPSEEK_V_SERIES_RE` (`^deepseek-v\d+(...)?$`) so future
V-series IDs (`deepseek-v5-*`, dated variants) keep passing through
without another code change.
- Update docstring + module header to reflect the new rule.
Tests:
- New `TestDeepseekVSeriesPassThrough` — 8 parametrized cases covering
bare, vendor-prefixed, case-variant, dated, and future V-series IDs
plus end-to-end `normalize_model_for_provider(..., "deepseek")`.
- New `TestDeepseekCanonicalAndReasonerMapping` — regression coverage
for canonical pass-through, reasoner-keyword folding, and
fall-back-to-chat behaviour.
- 77/77 pass.
Reported on Discord (Ufonik, Don Piedro): `/model > Deepseek >
deepseek-v4-pro` surfaced
`Normalized 'deepseek-v4-pro' to 'deepseek-chat'`. Picker listing
showed the v4 names, so validation also rejected the post-normalize
`deepseek-chat` as "not in provider listing" — the contradiction
users saw. Normalizer now respects the picker's choice.
Collaborator
Contributor
2 tasks
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
_normalize_for_deepseekwas folding every non-reasoner DeepSeek input intodeepseek-chaton the assumption that DeepSeek's API accepts only two model IDs. That's no longer true —deepseek-v4-proanddeepseek-v4-flashare first-class IDs accepted by the direct API, and on aggregatorsdeepseek-chatroutes explicitly to V3. So a user picking V4 Pro through the model picker was silently downgraded to V3.Reported by @UFOnik and @Don-Piedro on Discord (
/model > Deepseek > deepseek-v4-prosurfacedNormalized 'deepseek-v4-pro' to 'deepseek-chat', and the picker listing then rejected the post-normalizedeepseek-chatas "not in provider listing" because live/v1/modelsreturns v4 names, not canonical ones — that's the contradictory message users saw).Empirical verification (2026-04-24)
End-to-end simulation against an OpenAI-compat endpoint (Nous portal's surface,
/v1/chat/completions) with identical user inputdeepseek-v4-flashandprovider=deepseek:deepseek-v4-flashdeepseek-v4-flashdeepseek-chatdeepseek-v4-flashdeepseek/deepseek-chatdeepseek/deepseek-v4-flashdeepseek/deepseek-chat-v3deepseek/deepseek-v4-flash-20260423V-series names are real model IDs, not aliases of
deepseek-chat. Aggregator routing even flips —deepseek-chatlands on a cheaper Novita/DeepInfra backend,deepseek-v4-flashgoes direct to DeepSeek.Fix
deepseek-v4-pro/deepseek-v4-flashto_DEEPSEEK_CANONICAL_MODELS(exact-match pass-through)._DEEPSEEK_V_SERIES_RE(^deepseek-v\d+(...)?$) so future V-series IDs (deepseek-v5-*, dated variants likedeepseek-v4-flash-20260423) pass through without another code change.Tests
TestDeepseekVSeriesPassThrough— 8 parametrized + 2 end-to-end cases (bare, vendor-prefixed, case-variant, dated, future V-series).TestDeepseekCanonicalAndReasonerMapping— regressions for canonical pass-through, reasoner-keyword folding, chat fallback.tests/hermes_cli/test_model_normalize.py.