Repository navigation
fix(auto-combo): short-circuit expandAutoComboCandidatePool when models[] is non-empty (closes #8597) - #8598
Merged
diegosouzapw merged 1 commit intoJul 27, 2026
Conversation
mikeiagents
force-pushed
the
fix/auto-combo-explicit-models-guard
branch
2 times, most recently
from
July 25, 2026 18:29
c816ca4 to
4649d93
Compare
…ls[] is non-empty When an auto-combo has models[] populated by the operator but config.auto.candidatePool is empty (the default for combos created via the dashboard), expandAutoComboCandidatePool silently expands the candidate pool to every model of every active provider connection. This overrides the explicit list in models[] and lets unintended models (e.g. gemini-3.1-flash-lite) win the auto-strategy scoring contest. In omniroute@3.8.48 (npm) only one guard exists before the expansion loop (GUARD A: if (config.auto.candidatePool populated) return eligibleTargets). The upstream release branch release/v3.8.49 added a second guard (combo-ref check, PR cheaper-inference#7301) but it does not cover the common pattern where models[] holds explicit kind:"model" entries. Both gaps share the same root mechanism and the same fix. The new guard short-circuits whenever models[] is a non-empty array, covering both kind:"model" entries (the dashboard default) and kind:"combo-ref" entries (which cheaper-inference#7301 already handles). With this guard in place, the existing combo-ref check becomes redundant; it is left in place for the minimal-scope surgical fix, and can be removed in a follow-up cleanup. Validation (in isolated Docker, 3 providers + 4 controlled combos): - 3 explicit models, empty candidatePool: pool 60 -> 6 - 1 combo-ref + 2 explicit, empty candidatePool: pool 64 -> 10 - 3 explicit models, populated candidatePool (GUARD A path): 6 -> 6 - empty models[] virtual auto: 57 -> 57 (expansion preserved) Closes cheaper-inference#8597
mikeiagents
force-pushed
the
fix/auto-combo-explicit-models-guard
branch
from
July 25, 2026 18:32
4649d93 to
a366b8f
Compare
diegosouzapw
merged commit Jul 27, 2026
39e7772
into
cheaper-inference:release/v3.8.49
3 checks passed
Merged
HouMinXi
pushed a commit
to HouMinXi/OmniRoute
that referenced
this pull request
Aug 2, 2026
…ls[] is non-empty (cheaper-inference#8598) When an auto-combo has models[] populated by the operator but config.auto.candidatePool is empty (the default for combos created via the dashboard), expandAutoComboCandidatePool silently expands the candidate pool to every model of every active provider connection. This overrides the explicit list in models[] and lets unintended models (e.g. gemini-3.1-flash-lite) win the auto-strategy scoring contest. In omniroute@3.8.48 (npm) only one guard exists before the expansion loop (GUARD A: if (config.auto.candidatePool populated) return eligibleTargets). The upstream release branch release/v3.8.49 added a second guard (combo-ref check, PR cheaper-inference#7301) but it does not cover the common pattern where models[] holds explicit kind:"model" entries. Both gaps share the same root mechanism and the same fix. The new guard short-circuits whenever models[] is a non-empty array, covering both kind:"model" entries (the dashboard default) and kind:"combo-ref" entries (which cheaper-inference#7301 already handles). With this guard in place, the existing combo-ref check becomes redundant; it is left in place for the minimal-scope surgical fix, and can be removed in a follow-up cleanup. Validation (in isolated Docker, 3 providers + 4 controlled combos): - 3 explicit models, empty candidatePool: pool 60 -> 6 - 1 combo-ref + 2 explicit, empty candidatePool: pool 64 -> 10 - 3 explicit models, populated candidatePool (GUARD A path): 6 -> 6 - empty models[] virtual auto: 57 -> 57 (expansion preserved) Closes cheaper-inference#8597 Co-authored-by: Michael de Souza Marcos <michael.smarcos@hotmail.com>
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…ls[] is non-empty (cheaper-inference#8598) When an auto-combo has models[] populated by the operator but config.auto.candidatePool is empty (the default for combos created via the dashboard), expandAutoComboCandidatePool silently expands the candidate pool to every model of every active provider connection. This overrides the explicit list in models[] and lets unintended models (e.g. gemini-3.1-flash-lite) win the auto-strategy scoring contest. In omniroute@3.8.48 (npm) only one guard exists before the expansion loop (GUARD A: if (config.auto.candidatePool populated) return eligibleTargets). The upstream release branch release/v3.8.49 added a second guard (combo-ref check, PR cheaper-inference#7301) but it does not cover the common pattern where models[] holds explicit kind:"model" entries. Both gaps share the same root mechanism and the same fix. The new guard short-circuits whenever models[] is a non-empty array, covering both kind:"model" entries (the dashboard default) and kind:"combo-ref" entries (which cheaper-inference#7301 already handles). With this guard in place, the existing combo-ref check becomes redundant; it is left in place for the minimal-scope surgical fix, and can be removed in a follow-up cleanup. Validation (in isolated Docker, 3 providers + 4 controlled combos): - 3 explicit models, empty candidatePool: pool 60 -> 6 - 1 combo-ref + 2 explicit, empty candidatePool: pool 64 -> 10 - 3 explicit models, populated candidatePool (GUARD A path): 6 -> 6 - empty models[] virtual auto: 57 -> 57 (expansion preserved) Closes cheaper-inference#8597 Co-authored-by: Michael de Souza Marcos <michael.smarcos@hotmail.com>
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
Closes #8597
expandAutoComboCandidatePoolinopen-sse/services/combo/autoStrategy.tssilently expands the candidate pool of an auto-combo to every model of
every active provider connection whenever the operator has populated
models[]but leftconfig.auto.candidatePoolempty (the default forcombos built through the dashboard). This overrides the operator's
populated
models[]and lets unintended models (in the wild,gemini/gemini-3.1-flash-lite,opencode/opencode-minimax-m3-free,etc.) win the auto-strategy scoring contest.
In
omniroute@3.8.48from npm only one guard exists before theexpansion loop (GUARD A on line 414:
if (config.auto.candidatePool populated) return eligibleTargets). The upstream release branchrelease/v3.8.49has a partial second guard added by#7301 for
combo-refentries, but it does not cover the common pattern wherethe operator populates with explicit
kind: "model"entries (the defaultfor combos built through the dashboard multi-model editor). Both gaps
share the same root mechanism and the same fix.
What this PR does
Adds a single new guard between GUARD A and the expansion loop:
The new guard short-circuits whenever
models[]is a non-empty array,covering both
kind: "model"entries (the dashboard default) andkind: "combo-ref"entries (which #7301 already handles). With thisguard in place, the existing combo-ref check becomes redundant; it is
left in place for the minimal-scope surgical fix and can be removed
in a follow-up cleanup.
Behaviour preservation matrix
models[]candidatePoolcombo-ref+ 2 explicit[](virtualauto)The 6 / 10 target count (rather than 3 / 5 set by the operator) is
buildAutoCandidatesdoing its job — each target becomes ~2 candidates(primary + fallback). The same
poolSize=6shows up for β pre-patch,confirming 6 is the desired count for a 3-populated-target combo.
Validation (end-to-end, isolated environment)
node --import tsx/esm --test tests/unit/combo-auto-candidate-expansion.test.ts→ 6/6 pass (5 pre-existing + 1 new test for the explicit-models guard)npx eslint open-sse/services/combo/autoStrategy.ts tests/unit/combo-auto-candidate-expansion.test.ts→ exit 0 (clean)autovirtual 0→57autovirtual 0→57operator-populated combos while preserving the intentional expansion
for virtual
auto/*combos (which need the full catalog).Test changes
tests/unit/combo-auto-candidate-expansion.test.tshas one testrenamed/extended in scope to cover the explicit-models case. The new
test is the
expandAutoComboCandidatePool is a no-op when the operator has populated models[] (no candidatePool)case. All 5 pre-existingtests pass unmodified.
Related
auto/*path — beingfixed separately by PR #8586)
Test plan for reviewers
Notes
fix/auto-combo-explicit-models-guardbased onrelease/v3.8.49perCONTRIBUTING.md(PR base is the activerelease branch, not
main).CONTRIBUTING.md.intentionally left in place rather than deleted in this PR, even
though it becomes dead code — splitting the cleanup into a separate
PR keeps the diff focused and reviewable. Happy to follow up with
the deletion + test simplification in a sibling PR if preferred.
return eligibleTargetswith no side effects; reverting this PR is a one-commit revert.
3.8.xnpm release,operators can continue using the manual
candidatePoolmitigationdescribed in fix(backend): auto-combo candidate pool silently expands to entire provider catalog when models[] is populated but candidatePool is empty #8597.