Skip to content

fix(sse): route claude discovery aliases for catalog-only providers - #9777

Merged
diegosouzapw merged 1 commit into
cheaper-inference:release/v3.8.50from
Michael-Rocco-Goldmann:fix/cc-alias-provider-prefix
Aug 11, 2026
Merged

diegosouzapw merged 1 commit into
cheaper-inference:release/v3.8.50from
Michael-Rocco-Goldmann:fix/cc-alias-provider-prefix

Conversation

@Michael-Rocco-Goldmann

Copy link
Copy Markdown
Contributor

Bug

Claude Code discovery aliases are advertised for providers the request path then refuses to route, so every such request silently goes to the Claude provider instead.

Reproduced live against an Azure AI Foundry connection:

POST /v1/messages  {"model":"claude/azure-ai/DeepSeek-V4-Flash"}
-> ROUTING: Provider: claude, Model: azure-ai/DeepSeek-V4-Flash
-> 404 (routed to the Claude provider, not Azure)

POST /v1/messages  {"model":"azure-ai/DeepSeek-V4-Flash"}   # direct id
-> 200 OK

No CC_DISCOVERY log line was emitted, confirming stripped === false.

Root cause

The two sides of the alias disagree:

side predicate
Catalog (ccAliasPredicate.ts) alias gate only - consults no provider registry
Request (stripCcDiscoveryAlias) gate plus isKnownProviderPrefix

isKnownProviderPrefix was built from getRegistryEntry() (the open-sse REGISTRY) plus operator-defined custom nodes. Enterprise-cloud providers such as azure-ai / azure-openai live only in the provider catalog (src/shared/constants/providers/apikey/enterprise-cloud.ts) and have no open-sse registry entry - "azure-ai" appears nowhere under open-sse/config/.

So the catalog advertised the mirror id, the request path declined to strip it, and the unstripped id fell through to normal resolution - which splits on the first / and parses claude as the provider.

This is exactly the hazard called out in src/lib/ccDiscoveryAliasResolve.ts: "they must match or an alias could be listed yet rejected."

Fix

Extract the predicate as isRoutableProviderPrefix() and widen it to the provider catalog (getProviderById + getProviderByAlias) alongside the existing registry lookup, so the request path recognises exactly what the catalog can advertise.

Widening the request side (rather than narrowing the catalog) is the correct direction: these models genuinely route - the direct ids return 200.

Tests

New tests/unit/cc-discovery-alias-routable-prefix.test.ts:

  • azure-ai, azure-openai routable (the regression)
  • azure alias resolves
  • openai / anthropic stay routable
  • unknown prefix and empty string stay non-routable

TDD verified - the azure and alias assertions failed against the pre-fix predicate (false !== true), then passed after the widening.

new suite                    4 pass / 0 fail
existing cc-discovery suites 70 pass / 0 fail   (6 files)
typecheck:core               clean
eslint (changed files)       exit 0

WARNING - base-red inherited: #9737

…oviders

The /v1/models catalog mirrors `claude/<provider>/<model>` ids purely from the
alias gate -- ccAliasPredicate.ts consults no provider registry. The request
path additionally required the prefix to be an open-sse REGISTRY entry or an
operator-defined custom node.

Enterprise-cloud providers such as azure-ai / azure-openai live only in the
provider catalog (src/shared/constants/providers/apikey/enterprise-cloud.ts).
They route fine directly -- `azure-ai/Phi-4` returns 200 -- but have no
open-sse registry entry, so the two sides disagreed: the catalog advertised
`claude/azure-ai/<model>` while stripCcDiscoveryAlias refused to strip it.

The unstripped id then fell through to normal resolution, which splits on the
first / and parsed `claude` as the provider. Every Claude Code request for an
Azure model was routed to the Claude provider instead:

  ROUTING: Provider: claude, Model: azure-ai/DeepSeek-V4-Flash

Extract the predicate as `isRoutableProviderPrefix()` and widen it to the
provider catalog (id + alias) alongside the open-sse registry, so the request
path recognises exactly what the catalog can advertise.

Regression guard: tests/unit/cc-discovery-alias-routable-prefix.test.ts pins
azure-ai/azure-openai/azure as routable, keeps openai/anthropic routable, and
keeps an unknown prefix non-routable. Verified failing before the widening.
@diegosouzapw

Copy link
Copy Markdown
Collaborator

Thanks for the PR. Please address the mandatory items (tests and/or merge blockers) in this branch, then rerun checks before /merge-prs.

2 similar comments
@diegosouzapw

Copy link
Copy Markdown
Collaborator

Thanks for the PR. Please address the mandatory items (tests and/or merge blockers) in this branch, then rerun checks before /merge-prs.

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Thanks for the PR. Please address the mandatory items (tests and/or merge blockers) in this branch, then rerun checks before /merge-prs.

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Obrigado pelo PR. Mantive a revisão de fix-in-place e não foi possível concluir o ajuste completo aqui:

  • Para os PRs em fork: não consigo aplicar push de correção diretamente na sua branch.
    Por favor, faça um rebase/sync com release/v3.8.50, resolva conflitos se houver, e rode os checks dessa branch.
    Se preferir, posso aplicar a correção na próxima rodada assim que você mandar o branch atualizado ou confirmar que o PR está limpo pra esse merge.

@diegosouzapw
diegosouzapw merged commit 4a4cc87 into cheaper-inference:release/v3.8.50 Aug 11, 2026
3 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…oviders (cheaper-inference#9777)

The /v1/models catalog mirrors `claude/<provider>/<model>` ids purely from the
alias gate -- ccAliasPredicate.ts consults no provider registry. The request
path additionally required the prefix to be an open-sse REGISTRY entry or an
operator-defined custom node.

Enterprise-cloud providers such as azure-ai / azure-openai live only in the
provider catalog (src/shared/constants/providers/apikey/enterprise-cloud.ts).
They route fine directly -- `azure-ai/Phi-4` returns 200 -- but have no
open-sse registry entry, so the two sides disagreed: the catalog advertised
`claude/azure-ai/<model>` while stripCcDiscoveryAlias refused to strip it.

The unstripped id then fell through to normal resolution, which splits on the
first / and parsed `claude` as the provider. Every Claude Code request for an
Azure model was routed to the Claude provider instead:

  ROUTING: Provider: claude, Model: azure-ai/DeepSeek-V4-Flash

Extract the predicate as `isRoutableProviderPrefix()` and widen it to the
provider catalog (id + alias) alongside the open-sse registry, so the request
path recognises exactly what the catalog can advertise.

Regression guard: tests/unit/cc-discovery-alias-routable-prefix.test.ts pins
azure-ai/azure-openai/azure as routable, keeps openai/anthropic routable, and
keeps an unknown prefix non-routable. Verified failing before the widening.
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.

2 participants