mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-08 00:02:20 +03:00
fix(compression): apply compression combo assignments to routing combos (#7779)
* fix(api): enumerate tiered auto combo endpoints in /api/combos/auto The backend already supports auto/<category>[:<tier>] routing via suffixComposition.ts + virtualFactory.ts, but GET /api/combos/auto only exposed 6 flat variants. This adds a second loop enumerating the 10 curated AUTO_SUFFIX_VARIANTS (auto/coding:free, auto/coding:cheap, auto/coding:pro, auto/reasoning, auto/vision, etc.). Fixes #7619 * fix(combos): enumerate template and family auto variants in GET /api/combos/auto The endpoint was missing 27 auto variants that /v1/models already advertises, causing 404s when clients tried to use them: - 20 template variants (auto/best-coding, auto/pro-*, auto/claude-*, auto/best-free, etc.) - 7 family variants (auto/glm, auto/minimax, auto/mimo, auto/zai, auto/gemma, auto/llama, auto/gemini) Fixes #7619 Refs #6453 * fix(combos): swap Phase B/C ordering to match catalog.ts Template variants (Phase C) now enumerate before suffix variants (Phase B) so that overlapping ids like auto/reasoning and auto/vision use template resolution (variant-based) rather than suffix resolution (category-based), matching the behavior in catalog.ts. * fix(combos): fix comment labels and redundant as const * fix(compression): apply compression combo assignments to routing combos Routing combos (e.g. codex, free-only, or-free) use provider-prefixed model strings like codex/gpt-5.5 and go through handleSingleModelChat, which passes comboName: null, isCombo: false. The compression combo assignment lookup in chatCore.ts was gated behind if (isCombo && comboName), so routing combos never had their compression combos applied. Fix: - Add routingComboId parameter threaded through handleSingleModelChat → executeChatWithBreaker → handleChatCore - In handleChat(), resolve the routing combo UUID from the model string's provider prefix via getComboByName - In chatCore.ts, change the gate to (isCombo && comboName) || routingComboId and add routingComboId to the lookup key array Fixes #7771 * fix(autoCombo): guarantee positive maxOutputTokens fallback in computeAdvertisedLimits GET /api/combos/auto now enumerates auto/<family> variants (auto/llama, auto/glm, etc). computeAdvertisedLimits() already guaranteed a positive contextLength for any non-empty candidate pool via getTokenLimit()'s fallback chain, but had no equivalent fallback for maxOutputTokens — candidates whose registry entry and models.dev sync data both lack that field (common for no-auth/free-tier providers matching a family filter, e.g. llama-* on groq/bazaarlink/etc) left maxOutputTokens null, which tests/unit/auto-combo-context-advertising.test.ts catches as a contract violation of the endpoint (opencode disables smart auto-compaction when a limit is falsy — the same bug class this module's docstring already describes for contextLength). Fall back to a conservative generic default (4096) when no candidate in the pool resolves a known maxOutputTokens, mirroring the existing contextLength guarantee. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix(autoCombo): align advertised max_output_tokens fallback with the catalog convention (8192) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(quality): file-size baseline for chatHelpers routingComboId thread (876->877) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Erick Kinnee <erick@ekinnee.dev> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
@@ -280,7 +280,8 @@
|
||||
"_rebaseline_2026_06_28_5275_correlation_id_extract": "Extraction of the safe CorrelationId subset of #5275 (hartmark) — request correlation id stored in call_logs (migration 109) and returned via the X-Correlation-Id response header, WITHOUT the combo/resilience or build/lazy-loading changes (those stay in #5275). Own growth: callLogs.ts 975->985 (correlation_id column on CallLogSummaryRow + read/map), usageHistory.ts 983->988 (correlationId metadata normalize), chat.ts 1575->1632 (withCorrelationId response wiring + combo-failure log carrying correlationId), chatHelpers.ts new 811 (withCorrelationId helper + reqId threading; was 791<cap pre-feature). Cohesive request/logging chokepoint wiring; structural shrink of chat.ts tracked in #3501.",
|
||||
"_rebaseline_2026_07_09_6678_routing_strategy_9router": "#6678 (SeaXen) — 9router-parity Routing Strategy settings card + per-provider/combo sticky-round-robin override. Own growth: ProviderDetailPageClient.tsx 784->786 (single ProviderAccountRoutingCard mount + import), auth.ts 2448->2458 (providerStrategies override resolution: fallbackStrategy/stickyRoundRobinLimit per-provider cascade in getProviderCredentials). Both additive, zero unrelated refactor; new UI/logic lives in new files (ProviderAccountRoutingCard.tsx, RoutingStrategyCard.tsx, rrState.ts::resolveComboStickyRoundRobinLimit). chat.ts value below reflects the current release tip (grown by other concurrent PRs, e.g. #6640), not this PR own change.",
|
||||
"src/sse/handlers/chat.ts": 1797,
|
||||
"src/sse/handlers/chatHelpers.ts": 876,
|
||||
"_rebaseline_2026_07_20_7779_routingcombo_thread": "PR #7779 own growth: chatHelpers.ts 876->877 (+1, thread routingComboId into executeChatWithBreaker for compression-combo assignment). Frozen so it can only shrink.",
|
||||
"src/sse/handlers/chatHelpers.ts": 877,
|
||||
"src/sse/services/auth.ts": 2462,
|
||||
"open-sse/executors/default.ts": 890,
|
||||
"open-sse/translator/request/openai-responses.ts": 902,
|
||||
|
||||
@@ -389,6 +389,7 @@ export async function handleChatCore({
|
||||
comboName,
|
||||
comboStrategy = null,
|
||||
isCombo = false,
|
||||
routingComboId = null,
|
||||
comboStepId = null,
|
||||
comboExecutionKey = null,
|
||||
cachedSettings = null,
|
||||
@@ -1146,11 +1147,11 @@ export async function handleChatCore({
|
||||
compressionComboApplied = true;
|
||||
return true;
|
||||
};
|
||||
if (isCombo && comboName) {
|
||||
if ((isCombo && comboName) || routingComboId) {
|
||||
try {
|
||||
const { getComboByName } = await import("../../src/lib/localDb");
|
||||
let comboConfig = await getComboByName(comboName);
|
||||
if (!comboConfig && comboName.startsWith("combo/")) {
|
||||
if (!comboConfig && comboName?.startsWith("combo/")) {
|
||||
comboConfig = await getComboByName(comboName.substring(6));
|
||||
}
|
||||
const comboRuntimeConfig =
|
||||
@@ -1185,7 +1186,8 @@ export async function handleChatCore({
|
||||
const routingComboIds = [
|
||||
comboConfig?.id,
|
||||
comboName,
|
||||
comboName.startsWith("combo/") ? comboName.substring(6) : null,
|
||||
routingComboId,
|
||||
comboName?.startsWith("combo/") ? comboName.substring(6) : null,
|
||||
].filter((id): id is string => typeof id === "string" && id.length > 0);
|
||||
if (routingComboIds.length > 0) {
|
||||
const { getCompressionComboForRoutingCombo } =
|
||||
|
||||
@@ -233,7 +233,19 @@ function getNoAuthCandidates(
|
||||
*
|
||||
* Unknown candidates resolve through getTokenLimit()'s fallback chain, so a
|
||||
* non-empty pool always yields a positive contextLength.
|
||||
*
|
||||
* maxOutputTokens has no such guaranteed fallback in getResolvedModelCapabilities()
|
||||
* — registry entries and models.dev sync data are both optional per model, so a
|
||||
* candidate pool whose members all lack that specific field (e.g. #6453's
|
||||
* provider-family combos, `auto/llama` and friends, over no-auth/free-tier
|
||||
* registry entries that were never annotated with maxOutputTokens) would
|
||||
* otherwise advertise `null`, which mirrors the `context: 0` bug this module's
|
||||
* docstring describes for contextLength (opencode disables smart auto-compaction
|
||||
* entirely when a limit is falsy). Fall back to a conservative generic default so
|
||||
* a non-empty pool always yields a positive maxOutputTokens too.
|
||||
*/
|
||||
const DEFAULT_ADVERTISED_MAX_OUTPUT_TOKENS = 8192;
|
||||
|
||||
export function computeAdvertisedLimits(candidates: Array<{ provider: string; model: string }>): {
|
||||
contextLength: number | null;
|
||||
maxOutputTokens: number | null;
|
||||
@@ -257,6 +269,9 @@ export function computeAdvertisedLimits(candidates: Array<{ provider: string; mo
|
||||
maxOutputTokens = maxOutputTokens === null ? output : Math.max(maxOutputTokens, output);
|
||||
}
|
||||
}
|
||||
if (maxOutputTokens === null) {
|
||||
maxOutputTokens = DEFAULT_ADVERTISED_MAX_OUTPUT_TOKENS;
|
||||
}
|
||||
return { contextLength, maxOutputTokens };
|
||||
}
|
||||
|
||||
|
||||
@@ -888,6 +888,20 @@ export async function handleChat(
|
||||
telemetry.endPhase();
|
||||
|
||||
// Single model request
|
||||
// Try to resolve routing combo from model prefix for compression combo lookup
|
||||
let routingComboId: string | null = null;
|
||||
if (!combo) {
|
||||
const providerPrefix = resolvedModelStr.split("/")[0];
|
||||
if (providerPrefix) {
|
||||
try {
|
||||
const { getComboByName } = await import("@/lib/localDb");
|
||||
const routingCombo = await getComboByName(providerPrefix);
|
||||
if (routingCombo?.id) {
|
||||
routingComboId = routingCombo.id;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
const response = await handleSingleModelChat(
|
||||
body,
|
||||
resolvedModelStr,
|
||||
@@ -902,6 +916,7 @@ export async function handleChat(
|
||||
forceLiveComboTest: isComboLiveTest,
|
||||
forcedConnectionId: requestedConnectionId,
|
||||
correlationId: reqId,
|
||||
routingComboId,
|
||||
reasoningDecision,
|
||||
reasoningIntent,
|
||||
reasoningRequestTags: requestRoutingTags.tags,
|
||||
@@ -953,6 +968,7 @@ async function handleSingleModelChat(
|
||||
cachedSettings?: any;
|
||||
providerId?: string | null;
|
||||
correlationId?: string | null;
|
||||
routingComboId?: string | null;
|
||||
modelPinned?: boolean;
|
||||
reasoningDecision?: ReasoningRuleDecision | null;
|
||||
reasoningIntent?: ExtractedReasoningIntent | null;
|
||||
@@ -1380,6 +1396,7 @@ async function handleSingleModelChat(
|
||||
skipUpstreamRetry: runtimeOptions.skipUpstreamRetry ?? false,
|
||||
correlationId: runtimeOptions?.correlationId ?? null,
|
||||
modelPinned: runtimeOptions?.modelPinned ?? false,
|
||||
routingComboId: runtimeOptions?.routingComboId ?? null,
|
||||
});
|
||||
if (telemetry) telemetry.endPhase();
|
||||
|
||||
|
||||
@@ -395,6 +395,7 @@ export async function executeChatWithBreaker({
|
||||
trafficType = "production",
|
||||
correlationId = null,
|
||||
modelPinned = false,
|
||||
routingComboId = null,
|
||||
}: ExecuteChatWithBreakerOptions): Promise<{ result: any; tlsFingerprintUsed: boolean }> {
|
||||
let tlsFingerprintUsed = false;
|
||||
const normalizedTrafficType: TrafficType =
|
||||
@@ -432,6 +433,7 @@ export async function executeChatWithBreaker({
|
||||
trafficType: normalizedTrafficType,
|
||||
correlationId,
|
||||
modelPinned,
|
||||
routingComboId,
|
||||
onCredentialsRefreshed: async (newCreds: any) => {
|
||||
await updateProviderCredentials(credentials.connectionId, {
|
||||
accessToken: newCreds.accessToken,
|
||||
|
||||
Reference in New Issue
Block a user