Repository navigation
fix(routing): connection defaultModel only replaces a placeholder bare model - #16550
Merged
diegosouzapw merged 2 commits intoOct 16, 2026
Conversation
…e model A concrete bare model name such as claude-haiku-4-5 was swapped for the selected connection's defaultModel by resolveBareModelToConnectionDefault, so a Claude request could be served by a Gemini default with no error. The defaultModel now only replaces auto or an empty model. BARE_MODEL_DEFAULT_OVERRIDE_LEGACY=true restores the old behaviour and logs one warning per pair through the level-gated MODEL logger.
With the connection defaultModel limited to placeholders, a concrete bare model such as gpt-4o is no longer replaced by the default. Two route tests used that replacement only as their scenario: - hidden-model-dispatch: the default path now keeps gpt-4o (200, and still 200 after gpt-4o-mini is hidden); the original swap and 404 assertions run with BARE_MODEL_DEFAULT_OVERRIDE_LEGACY=true, so the hidden-model gate on that swap stays covered. - suffix-effort-propagation: the default path keeps the bare alias target and its max effort; the replacement without the suffix runs with the legacy override on. The override is read on every call and restored in a finally block.
Contributor
Author
|
CI on
No failing job traces to this change. The 13 failing unit tests (ten files), the same on both sides
All are under |
6 tasks done
diegosouzapw
merged commit Oct 16, 2026
54afdc3
into
cheaper-inference:release/v3.8.52
31 of 51 checks passed
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.
Follow-up to #4825, the PR that added
resolveBareModelToConnectionDefault. No open issue or PRcovers this; see Notes.
Problem
resolveBareModelToConnectionDefault(open-sse/services/model.ts) exists so that a bare request(no
/, such as an alias that resolved toauto) reaches the upstream with the connection'sdefaultModelinstead of the placeholder. One2d5747872it replaces any bare name: as soon asthe selected connection has a
defaultModel, the model the client asked for is dropped and the bodyis rewritten to
${provider}/${defaultModel}(src/sse/handlers/chat.ts, theeffectiveModel/requestBodypair right after credential selection). Nothing fails: the request is answered with200 by another model.
The base's own tests pin that behaviour:
tests/unit/hidden-model-dispatch.test.ts(from fix(routing): enforce individual hidden-model policy before dispatch #16110): agpt-4orequest on an OpenAIconnection with
defaultModel: "gpt-4o-mini"dispatchesgpt-4o-mini, and returns 404 oncegpt-4o-miniis hidden, whilegpt-4oitself is visible.tests/unit/suffix-effort-propagation.test.ts(from fix(providers): stop treating Anthropic max_tokens as the context window #14260): the aliasbare-effort-alias→agnes/agnes-3.0-flash-max, on a connection withdefaultModel: "agnes-default-replacement",sends
agnes-default-replacementupstream, and themaxeffort the alias carried goes with it.So a concrete bare catalog name (
claude-haiku-4-5), or a bare alias that already resolved to aconcrete id, is served by whatever the connection default is, across model families included
(
claude-haiku-4-5with agemini-2.5-flashdefault, in the helper test). The embeddings path(
src/lib/embeddings/service.ts) calls the same helper.Fix
defaultModelnow replaces the resolved model only when that model is aplaceholder:
null, empty, orauto. That is the case fix(sse): resolve bare model names to connection defaultModel before upstream calls #4825 was written for, and it isunchanged.
equal to the default is returned as-is.
/-qualified names were already left untouched and still are. A connection without a usabledefaultModelstill returns the resolved model.BARE_MODEL_DEFAULT_OVERRIDE_LEGACY=truerestores the previous replacement. It is read on everycall (
1,true,yes,on, case-insensitive, the same reader asOMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELSin the same file) and logs onewarning per (model, default) pair through the
MODELlogger. Documented in.env.exampleanddocs/reference/ENVIRONMENT.md, with a fragment inchangelog.d/fixes/.open-sse/services/model.tsgoes 852 → 884 lines by thecheck:file-sizecount(
split("\n").length), and its merge with the release tip9ecddd15a1measures 893 (#16493 adds9 lines elsewhere in the file). The cap for files outside
file-size-baseline.jsonis 1200, andnone of the four touched
.tsfiles is in the baseline. The three test files measure 92, 295 and591 against a
testCapof 1200. The merge with9ecddd15a1is clean (git merge-tree): #16493(
model.ts) and #16510 (.env.example,ENVIRONMENT.md) touch other hunks of the same files.Tests
Run on GitHub Actions (ubuntu-latest, Node 24 from
.nvmrc), the three files below together,twice: once with the branch (57 tests, 57 pass), and once with
.env.exampleandopen-sse/services/model.tsrestored toe2d5747872while the test files stay (57 tests, 53 pass,4 fail).
tests/unit/)e2d5747872resolve-bare-model-to-connection-default-474claude-haiku-4-5with agemini-2.5-flashdefault;gpt-4owithgpt-4o-mini)resolve-bare-model-to-connection-default-474haiku→claude-haiku-4-5-20251001overgemini-2.5-flash)hidden-model-dispatchgpt-4odispatched, 200; still 200 andgpt-4oaftergpt-4o-miniis hidden)suffix-effort-propagationagnes-3.0-flashsent,reasoning_effort: "max")resolve-bare-model-to-connection-default-474auto→gpt-4o-mini)resolve-bare-model-to-connection-default-474resolve-bare-model-to-connection-default-474resolve-bare-model-to-connection-default-474BARE_MODEL_DEFAULT_OVERRIDE_LEGACY=truerestores the old replacementhidden-model-dispatchgpt-4o-minidispatched, then 404 once hidden)suffix-effort-propagationagnes-default-replacementsent, noreasoning_effort)The last six pass on both sides on purpose. The first three of them pin the placeholder behaviour
#4825 added; the three override cases pass on the base because the base replaces whatever the
variable says. The remaining 47 cases in the three files pass on both sides.
The three tests that set the override save the previous value, set
true, and restore (or delete)it in a
finally, with the exercised call inside thetry.Notes
tests/unit/hidden-model-dispatch.test.ts. Its case "a connection default cannot replace avisible request with a hidden model" used the replacement of a concrete
gpt-4oas its scenario,so with this fix the gate on that swap would no longer be exercised. The second commit keeps the
original assertions under
BARE_MODEL_DEFAULT_OVERRIDE_LEGACY=trueand adds the default-pathcase.
tests/unit/suffix-effort-propagation.test.ts(fix(providers): stop treating Anthropic max_tokens as the context window #14260) gets the same treatment: theoriginal "replacement drops the suffix" assertions run under the override, and the default path
asserts the alias target and its effort.
OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS. The per-pair warning set lives forthe process.
src/sse/handlers/chat.tsandsrc/lib/embeddings/service.tskeeptheir original wording; the helper's own docblock carries the new rule.
auto), as the rest of the helper is.so no UI copy changes.
resolveBareModelToConnectionDefault,defaultModel,bare modelandconnection default: none covers this. fix(sse): resolve bare model names to connection defaultModel before upstream calls #4825 is the mergedPR that added the helper. Of the 100 most recently updated open PRs, one touches
open-sse/services/model.ts, perf(sse): bound parseModel and canonical-provider caches #16341; its hunks there are the imports,ResolvedModelTarget,shouldTreatAsExactModelIdandparseModel, none of them the helper.changelog.d/fixes/bare-model-default-only-placeholder.md.