Repository navigation
refactor(combo): god-file split part 3 — auto strategy (QG v2 Fase 9 T5 D8) - #4186
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the combo service by extracting auto-strategy scoring, intent extraction, request-tag routing, and candidate registry logic from open-sse/services/combo.ts into a new dedicated module open-sse/services/combo/autoStrategy.ts. While the logic was moved byte-identically, the reviewer identified a critical race condition in the _activeExecutionCandidates registry map. Because the executionKey is static and shared across concurrent requests for the same combo, concurrent executions can overwrite each other's candidates and prematurely clear them during unregistration.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // Populated by buildAutoCandidates registrations; cleaned up after each execution. | ||
| // This allows chatCore.ts to mark a candidate's quotaSoftPenalty flag so that | ||
| // subsequent scoring iterations (auto-combo fallback) deprioritize it. | ||
| const _activeExecutionCandidates = new Map<string, Map<string, { quotaSoftPenalty?: boolean }>>(); |
There was a problem hiding this comment.
Há uma condição de corrida (race condition) crítica no uso do _activeExecutionCandidates.
O _activeExecutionCandidates é um Map global no nível do módulo indexado por executionKey. No entanto, a executionKey (gerada via buildExecutionKey(path, step.id)) é estática e compartilhada entre todas as requisições concorrentes que executam o mesmo combo.
Isso causa os seguintes problemas em ambientes de produção com requisições concorrentes:
- Requisições concorrentes para o mesmo combo sobrescrevem os candidatos uns dos outros no
Map. - Quando qualquer requisição termina, ela chama
_unregisterExecutionCandidates, o que remove aexecutionKeyestática doMapglobal, limpando prematuramente os candidatos de outras requisições concorrentes que ainda estão em execução.
Para corrigir isso, o registro deveria utilizar um identificador único por execução/requisição (como um UUID ou o ID da requisição) combinado com a chave, em vez de depender apenas da executionKey estática.
…d) (#4183) Integrated into release/v3.8.29 — register Kimi K2.7 Code (kimi-k2.7-code + -highspeed). New KIMI_K27_MODELS in providers/shared.ts (262144 ctx, vision+reasoning, temperature/top_p stripped = fixed sampling), wired into kimi-coding, kimi-coding-apikey, moonshot and kimi. Validated: 6/6 unit tests (all 4 providers advertise it + context + reasoning + param stripping) + file-size; PR CI CLEAN. OAuth coding endpoint validated live on the test VPS.
…4180) Integrated into release/v3.8.29 — default includeThoughts for modern Gemini (2.5+) in the openai->gemini translator, so the model's reasoning is marked thought:true and routed to reasoning_content instead of leaking into visible content (#4170). Thanks @dhaern! On review we regenerated the gemini golden snapshots (basic-chat/with-system) and committed the new modern-gemini-default-thinking snapshot. 61/61 translator + golden tests pass; eslint clean. Respects explicit client thinking config (only applies when none is set) and excludes gemini-1.x / non-thinking 2.0.
…#4184) Integrated into release/v3.8.29 — correct contextLength for theoldllm models. Adds an entry-level defaultContextLength (200000) + per-model overrides (GPT-5.4 400K, Gemini 3 Flash/Pro 1M, Claude/DeepSeek 200K) so the models report their real context windows instead of null. Thanks @herjarsa! On review we added a regression test (the resolved window was null before this fix), satisfying the PR Test Policy gate. 4/4 tests + eslint + prettier clean.
…iscovery (#3931 bug 3, #3737) (#4185) Integrated into release/v3.8.29 — add moonshotai/kimi-k2.7-code to the kmca (kimi-coding-apikey) catalog (KIMI_CODING_SHARED.models), requested in discussion #3737. On resync: the PR's qwen-web PROVIDER_MODELS_CONFIG addition (issue #3931 bug #3) was already shipped by #4172 — dropped the duplicate, kept release's entry (which has the Array.isArray guard); kept #4183's KIMI_K27_MODELS spread + added the moonshotai-prefixed entry (union). Also reconciled the file-size baseline for openai-to-gemini.ts (#4180 merged without its +20 bump). Validated: 13/13 tests (kmca catalog + qwen-web parse + kimi registration) + file-size green.
Integrated into release/v3.8.29. Opt-in Qdrant scalar int8 quantization (F4.4 Q1); default 'none' keeps the create body byte-identical. Validated: vitest 9/9, file-size OK, lint clean.
…4190) Integrated into release/v3.8.29. Opt-in sqlite-vec int8 storage quantization (F4.4 Q2) via MEMORY_VEC_QUANTIZATION=int8; signature-gated so flipping mode triggers a reindex; default unchanged. Validated: node test 3/3 (incl. real int8 recall = exact float32 NN), file-size OK, lint clean.
…nd-trip (#4181) (#4191) Follow-up to #4091/#4153: the generic capture re-attach in createPreparedRequestLogger().body() was only regression-tested on the native-Claude OAuth cloak. Add a dedicated test driving the real cloakAntigravityToolPayload (_ide suffix scheme) through the JSON.parse(JSON.stringify()) capture round-trip, asserting the reverse map survives, stays non-enumerable, and that all-native traffic yields no spurious map. Proven RED with the #4153 re-attach removed. No production change. Closes #4181
…v2 Fase 9 T5 C2-C3-C5) (#4188) Integrated into release/v3.8.29. chatCore god-file split Fase 2 part A (QG v2 Fase 9 T5 C2-C3-C5): 3 byte-identical leaf modules (passthroughHelpers/responseHeaders/telemetryHelpers) under open-sse/handlers/chatCore/; chatCore.ts re-exports the 5 previously-public symbols so existing importers resolve. Validated: lint clean, file-size OK (chatCore 5445→5265), 108/109 symbol-importer tests (the 1 fail = known executor-200ms timing flake under load; 65/65 clean on isolated re-run).
Passthrough / per-model-quota providers (antigravity, gemini, github, compatible) multiplex independent upstream models behind one provider connection. A quota 429 for one model was setting providerExhausted=true and skipping every other same-provider combo target — including models that are not quota-limited. Guard the providerExhausted decision in handleComboChat and handleRoundRobinCombo with !hasPerModelQuota(provider, model) so a per-model quota stays model-scoped (Model Lockout) instead of poisoning the whole provider for the request. Reconciled onto the post-split combo.ts (cheaper-inference#4186) for release/v3.8.29. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Integrated into release/v3.8.29 — reconciled onto post-split combo.ts (#4186); RED->GREEN validated. Thanks @Svetznaniy33.
…T5 D8) (cheaper-inference#4186) Integrated into release/v3.8.29. combo god-file split part 3 (QG v2 Fase 9 T5 D8, reduced): auto-strategy scoring/intent/tag-routing/candidate-pool/quota-soft registry extracted byte-identically to open-sse/services/combo/autoStrategy.ts (434 LOC, <cap); buildAutoCandidates kept in combo.ts to avoid a combo⇄autoStrategy cycle; 4 public symbols re-exported. Validated: lint clean, file-size OK (combo.ts 3819→3432), check:cycles OK, autoStrategy has no combo-barrel import, 16/16 re-export tests.
…#4194) Integrated into release/v3.8.29 — reconciled onto post-split combo.ts (cheaper-inference#4186); RED->GREEN validated. Thanks @Svetznaniy33.
O que
Parte 3 do split do god-file
open-sse/services/combo.ts(Quality Gate v2 / Fase 9 T5), seguindo #4162 (D1-D3) e #4175 (D4-D6). Extrai o bloco de auto-strategy para o novoopen-sse/services/combo/autoStrategy.ts— move byte-idêntico, zero mudança de comportamento.combo.ts3819 → 3431 LOC (−388);autoStrategy.ts434 LOC (< cap 800).Movido para
combo/autoStrategy.ts_activeExecutionCandidates+setCandidateQuotaSoftPenalty/_registerExecutionCandidates/_unregisterExecutionCandidates, mantidos juntos = coesão de estado) +QUOTA_SOFT_DEPRIORITIZE_FACTOR.toTextContent/extractPromptForIntent/mapIntentToTaskType/toStringArray/getIntentConfig.applyRequestTagRouting,scoreAutoTargets,expandAutoComboCandidatePool,deriveComboSessionKey.Mantido deliberadamente no
combo.ts(D8-reduzido)buildAutoCandidates+ seus 2 helpers privados (calculateTargetContextAffinity,getBootstrapLatencyMs) + 3 consts (DEFAULT_MODEL_P95_MS/MIN_HISTORY_SAMPLES/OUTPUT_TOKEN_RATIO). Motivo:buildAutoCandidatesé o único consumidor das helpers reset-window (resolveResetWindowConfig/fetchResetAwareQuotaWithCache/calculateResetWindowAffinity) que ficam nocombo.ts. Mantê-lo aqui evita um ciclocombo ↔ autoStrategy(e sobrevive à futura extração quota-window do D7).autoStrategy.tsnão importa nada do barrelcombo.ts.Contrato preservado
chatCore.tsfazawait import("../services/combo")e lêQUOTA_SOFT_DEPRIORITIZE_FACTOR+setCandidateQuotaSoftPenalty— ambos re-exportados docombo.ts.scoreAutoTargets/expandAutoComboCandidatePoolmantêm o re-export público.Validação
typecheck:corerc=0 (0 erros TS)combo-auto-candidate-expansion+combo-quota-soft-penalty+auto-combo-context-advertising(22) +chatcore-imports-cleanly(1, contrato do dynamic-import)check:cyclesrc=0 ·check:file-sizerc=0 (baselinecombo.ts→ 3432)Refactor puro — testes existentes são a guarda de regressão.
🤖 Generated with Claude Code