Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/quality/file-size-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"_comment": "Catraca de tamanho (check-file-size.mjs). frozen so pode encolher; arquivos novos <= cap. --update ratcheta.",
"_rebaseline_v3.8.25": "Drift consciente do ciclo v3.8.24->v3.8.25 (features #3799-#3806: free-provider-rankings, plugins menu, proxy IP-family selector). 3 arquivos cresceram por feature legitima, nao por regressao de qualidade: ProxyRegistryManager.tsx 1072->1089, sidebarVisibility.ts 990->1006, schemas.ts 2519->2522. Encolher fica como debt para um refactor dedicado.",
"_rebaseline_2026_06_15_3860_compression_ui": "PR #3860 own growth: sidebarVisibility.ts 1006->1100 (+94 = Compression Hub menu entries: Hub + per-engine Lite/Aggressive/Ultra pages + combos editor) and chatCore.ts 5812->5815 (+3 = compression UI config wiring). Cohesive feature growth, not a quality regression.",
"_rebaseline_2026_06_15_3871_empty_pool": "PR #3871 own growth: combo.ts 5203->5204 (+1 = guard expandAutoComboCandidatePool against an empty candidatePool array — Array.isArray(pool) && pool.length > 0 so [] falls through to active-connection expansion instead of early-returning). One-line correctness fix; not extractable.",
"cap": 800,
"frozen": {
"open-sse/config/providerRegistry.ts": 4703,
Expand Down Expand Up @@ -30,7 +31,7 @@
"open-sse/services/batchProcessor.ts": 828,
"open-sse/services/browserBackedChat.ts": 850,
"open-sse/services/claudeCodeCompatible.ts": 1202,
"open-sse/services/combo.ts": 5203,
"open-sse/services/combo.ts": 5204,
"open-sse/services/rateLimitManager.ts": 1017,
"open-sse/services/tokenRefresh.ts": 1997,
"open-sse/services/usage.ts": 3408,
Expand Down
3 changes: 2 additions & 1 deletion open-sse/services/combo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2994,7 +2994,8 @@ export async function expandAutoComboCandidatePool(
(combo?.config as Record<string, unknown> | undefined) ||
{};

if (Array.isArray(localAutoConfig?.candidatePool)) return eligibleTargets;
if (Array.isArray(localAutoConfig?.candidatePool) && localAutoConfig.candidatePool.length > 0)
return eligibleTargets;
Comment on lines +2997 to +2998

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While this change correctly prevents an early return when candidatePool is an empty array, accessing localAutoConfig.candidatePool.length directly might trigger TypeScript compiler errors (e.g., Object is of type 'unknown' or Property 'length' does not exist on type 'unknown') because localAutoConfig is typed as Record<string, unknown>.

Extracting candidatePool to a local variable allows TypeScript's Array.isArray type guard to correctly narrow its type to any[], ensuring type-safe access to .length.

Additionally, please note that there is a similar check on line 3264:

const candidatePool = Array.isArray(autoConfigSource.candidatePool)
  ? autoConfigSource.candidatePool
  : [...new Set(eligibleTargets.map((target) => target.provider))];

If autoConfigSource.candidatePool is an empty array [], it will bypass the fallback and pass [] to selectAutoProvider, which will fail to select any candidates. You should also update line 3264 to check for length > 0 so it correctly falls back to the active connections' providers.

Suggested change
if (Array.isArray(localAutoConfig?.candidatePool) && localAutoConfig.candidatePool.length > 0)
return eligibleTargets;
const candidatePool = localAutoConfig?.candidatePool;
if (Array.isArray(candidatePool) && candidatePool.length > 0)
return eligibleTargets;


try {
const allConnections = await getProviderConnections({ isActive: true });
Expand Down
23 changes: 23 additions & 0 deletions tests/unit/combo-auto-candidate-expansion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,29 @@ test("expandAutoComboCandidatePool is a no-op when an explicit candidatePool exi
assert.equal(result[0].modelStr, "openai/gpt-4o");
});

test("expandAutoComboCandidatePool falls through to active connections when candidatePool is an empty array", async () => {
await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "OpenAI",
apiKey: "sk-test-openai",
defaultModel: "gpt-4o-mini",
});

const expanded = await combo.expandAutoComboCandidatePool([], {
config: { auto: { candidatePool: [] } },
});

// An empty candidatePool should NOT trigger early return — the function
// should fall through and expand from active connections instead.
assert.ok(
expanded.length > 0,
"expected expansion from active connections despite empty candidatePool"
);
const openaiTargets = expanded.filter((t) => t.provider === "openai");
assert.ok(openaiTargets.length > 0, "expected openai targets to be expanded");
});

test("expandAutoComboCandidatePool does not duplicate an already-present modelStr", async () => {
await providersDb.createProviderConnection({
provider: "openai",
Expand Down