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
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,16 @@ APP_LOG_TO_FILE=true
# Comma-separated data sources. Default: litellm
# PRICING_SYNC_SOURCES=litellm

# ═══════════════════════════════════════════════════════════════════════════════
# 18b. ARENA ELO SYNC
# ═══════════════════════════════════════════════════════════════════════════════
# Enable auto-updating model intelligence from Arena AI leaderboard ELO scores.
# Used by: src/lib/arenaEloSync.ts
# ARENA_ELO_SYNC_ENABLED=false

# Sync interval in seconds. Default: 86400 (24 hours).
# ARENA_ELO_SYNC_INTERVAL=86400

# ═══════════════════════════════════════════════════════════════════════════════
# 19. MODEL SYNC (Dev)
# ═══════════════════════════════════════════════════════════════════════════════
Expand Down
9 changes: 9 additions & 0 deletions docs/reference/ENVIRONMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,15 @@ Automatic model pricing data synchronization from external sources.

---

## Arena ELO Sync

| Variable | Default | Source File | Description |
| --------------------------- | ------------- | -------------------------- | ------------------------------------------------------------- |
| `ARENA_ELO_SYNC_ENABLED` | `false` | `src/lib/arenaEloSync.ts` | Opt-in periodic Arena AI leaderboard ELO sync. |
| `ARENA_ELO_SYNC_INTERVAL` | `86400` (24h) | `src/lib/arenaEloSync.ts` | Sync interval in seconds. |

---

## 19. Model Sync (Dev)

| Variable | Default | Source File | Description |
Expand Down
2 changes: 1 addition & 1 deletion file-size-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"src/shared/constants/providers.ts": 3121,
"src/shared/constants/sidebarVisibility.ts": 990,
"src/shared/services/cliRuntime.ts": 1073,
"src/shared/validation/schemas.ts": 2490,
"src/shared/validation/schemas.ts": 2513,
"src/sse/handlers/chat.ts": 1381,
"src/sse/services/auth.ts": 2198
},
Expand Down
165 changes: 163 additions & 2 deletions open-sse/services/autoCombo/__tests__/autoCombo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* Unit tests for Auto-Combo Engine (Phase 5)
*/

import { describe, it, expect, beforeEach } from "vitest";
import { describe, it, expect, beforeEach, vi } from "vitest";
import { calculateFactors, calculateScore, DEFAULT_WEIGHTS, validateWeights } from "../scoring";
import type { ProviderCandidate, ScoringWeights } from "../scoring";
import { getTaskFitness, getTaskTypes } from "../taskFitness";
import { getTaskFitness, getTaskFitnessWithSource, getTaskTypes, getModelsDevTierFitness, invalidateFitnessCache } from "../taskFitness";
import { SelfHealingManager } from "../selfHealing";
import { MODE_PACKS, getModePack, getModePackNames } from "../modePacks";
import { getStrategy } from "../routerStrategy";
Expand Down Expand Up @@ -410,3 +410,164 @@ describe("LKGP Strategy", () => {
expect(result.provider).toBe("openai");
});
});

describe("Task Fitness Resolution Chain", () => {
it("getTaskFitness should return static table score for known models", () => {
const score = getTaskFitness("claude-sonnet", "coding");
expect(score).toBe(0.95);
});

it("getTaskFitness should return 0.5 for unknown models with no wildcard match", () => {
const score = getTaskFitness("unknown-model-xyz", "coding");
expect(score).toBe(0.5);
});

it("getTaskFitness should apply wildcard boosts for model name patterns", () => {
const score = getTaskFitness("deepseek-coder-v2", "coding");
expect(score).toBeGreaterThan(0.5);
});

it("getTaskFitness should apply thinking wildcard for planning tasks", () => {
const score = getTaskFitness("some-thinking-model", "planning");
expect(score).toBeGreaterThan(0.5);
});

it("getTaskFitnessWithSource should return source='fitness_table' for known static models", () => {
const result = getTaskFitnessWithSource("claude-sonnet", "coding");
expect(result).toEqual({ score: 0.95, source: "fitness_table" });
});

it("getTaskFitnessWithSource should return source='wildcard_boost' for wildcard-matched models", () => {
const result = getTaskFitnessWithSource("fast-model", "coding");
expect(result).toEqual({ score: expect.any(Number), source: "wildcard_boost" });
});

it("getTaskTypes should return task types without 'default'", () => {
const types = getTaskTypes();
expect(types).toContain("coding");
expect(types).toContain("review");
expect(types).toContain("planning");
expect(types).not.toContain("default");
});

it("unknown models should return 0.5 (default) when no DB or static entry exists", () => {
const score = getTaskFitness("completely-unknown-model-xyz-999", "coding");
expect(score).toBe(0.5);
});

it("wildcard boosts still work for models containing 'coder'", () => {
const score = getTaskFitness("my-coder-pro", "coding");
// Base 0.5 + coder boost 0.15 + code boost 0.1 = 0.75
// "coder" contains "code", so both wildcard patterns match
expect(score).toBe(0.75);
});

it("wildcard boosts still work for models containing 'thinking'", () => {
const score = getTaskFitness("my-thinking-model", "planning");
// Base 0.5 + thinking boost 0.1 = 0.6
expect(score).toBe(0.6);
});

it("wildcard boosts still work for models containing 'thinking' for analysis tasks", () => {
const score = getTaskFitness("my-thinking-model", "analysis");
// Base 0.5 + thinking boost 0.1 = 0.6
expect(score).toBe(0.6);
});

it("wildcard boosts for 'code' pattern apply to coding tasks", () => {
const score = getTaskFitness("my-code-generator", "coding");
// Base 0.5 + code boost 0.1 = 0.6
expect(score).toBe(0.6);
});

it("wildcard boosts for 'fast' pattern apply to coding tasks", () => {
const score = getTaskFitness("my-fast-model", "coding");
// Base 0.5 + fast boost 0.05 = 0.55
expect(score).toBe(0.55);
});

it("getTaskFitnessWithSource returns 'wildcard_boost' for pattern-matched unknown models", () => {
const result = getTaskFitnessWithSource("my-coder-pro", "coding");
expect(result.source).toBe("wildcard_boost");
expect(result.score).toBeGreaterThan(0.5);
});

it("getTaskFitnessWithSource returns 'fitness_table' for statically known models", () => {
const result = getTaskFitnessWithSource("claude-sonnet", "review");
expect(result.source).toBe("fitness_table");
expect(result.score).toBe(0.92);
});

it("getTaskFitnessWithSource returns 'wildcard_boost' with 0.5 for unknown models with no pattern", () => {
const result = getTaskFitnessWithSource("totally-random-xyz", "coding");
expect(result.source).toBe("wildcard_boost");
expect(result.score).toBe(0.5);
});
});

describe("Task Fitness DB Resolution Chain", () => {
// These tests verify that when DB is available, the resolution chain
// (user_override → arena_elo → models_dev_tier → static → wildcard)
// works correctly. Since the DB module is loaded lazily via require(),
// these tests cover the cases where DB is NOT available (graceful fallback).

it("falls back to static FITNESS_TABLE when DB is not initialized", () => {
// In the test environment, DB is typically not initialized,
// so getTaskFitness should fall through to the static table
const score = getTaskFitness("claude-sonnet", "coding");
// Static table has claude-sonnet → 0.95 for coding
expect(score).toBe(0.95);
});

it("falls back to static FITNESS_TABLE for review task type", () => {
const score = getTaskFitness("claude-opus", "review");
// Static table has claude-opus → 0.95 for review
expect(score).toBe(0.95);
});

it("falls back to wildcard boosts when no static entry exists and DB unavailable", () => {
// "coder-unknown" has no static entry but matches "coder" wildcard
const score = getTaskFitness("coder-unknown", "coding");
expect(score).toBeGreaterThan(0.5);
expect(score).toBeLessThanOrEqual(1.0);
});

it("getModelsDevTierFitness returns null when DB is not initialized", () => {
// Without a running DB, this should return null gracefully
const score = getModelsDevTierFitness("claude-sonnet", "coding");
// Either null (no capabilities data) or a number from DB if DB happens to be up
if (score !== null) {
expect(score).toBeGreaterThanOrEqual(0);
expect(score).toBeLessThanOrEqual(1);
}
});

it("invalidateFitnessCache does not throw", () => {
expect(() => invalidateFitnessCache()).not.toThrow();
});

it("resolution chain: static table takes priority over wildcard for known models", () => {
// "claude-sonnet" is in the static table with coding=0.95
// It does NOT match "coder" wildcard because the static table is checked first
const score = getTaskFitness("claude-sonnet", "coding");
expect(score).toBe(0.95); // From static table, NOT wildcard
});

it("getTaskFitnessWithSource identifies fitness_table as source for known models", () => {
const result = getTaskFitnessWithSource("gpt-4o", "coding");
expect(result.source).toBe("fitness_table");
expect(result.score).toBe(0.9);
});

it("case insensitivity: model names are lowercased before lookup", () => {
const upperScore = getTaskFitness("CLAUDE-SONNET", "coding");
const lowerScore = getTaskFitness("claude-sonnet", "coding");
expect(upperScore).toBe(lowerScore);
});

it("case insensitivity: task types are lowercased before lookup", () => {
const upperScore = getTaskFitness("claude-sonnet", "CODING");
const lowerScore = getTaskFitness("claude-sonnet", "coding");
expect(upperScore).toBe(lowerScore);
});
});
Loading