Spaces:
Sleeping
Sleeping
File size: 7,890 Bytes
ed57015 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | /**
* Routing simulation β exercises the real routeRequest() against an in-memory
* DB seeded with synthetic traffic, so you can SEE how each strategy distributes
* requests and how the bandit adapts when a model starts failing.
*
* cd server && npm run build && node dist/scripts/routing-sim.js
*/
process.env.ENCRYPTION_KEY = '0'.repeat(64);
process.env.DEV_MODE = 'true';
import { initDb, getDb } from '../db/index.js';
import { encrypt } from '../lib/crypto.js';
import {
routeRequest, refreshStatsCache, setRoutingStrategy, getRoutingScores,
} from '../services/router.js';
import type { RoutingStrategy } from '../services/scoring.js';
interface Profile {
platform: string; modelId: string; name: string;
intelligenceRank: number; sizeLabel: string; budget: string;
// synthetic history
successes: number; failures: number; outTokens: number; latencyMs: number; ttfbMs: number;
}
// Deliberately no model that wins on every axis β so each strategy's weight
// vector picks a DIFFERENT winner (that's the whole point of the redesign).
const PROFILES: Profile[] = [
// Frontier intelligence, good-not-great reliability, genuinely slow β wins SMARTEST.
{ platform: 'google', modelId: 'gemini-x', name: 'Frontier-Smart', intelligenceRank: 1, sizeLabel: 'Frontier', budget: '~50M', successes: 22, failures: 4, outTokens: 200, latencyMs: 5000, ttfbMs: 2500 },
// Small/dumb but blazing fast and reliable β wins FASTEST.
{ platform: 'groq', modelId: 'llama-fast', name: 'Speed-King', intelligenceRank: 9, sizeLabel: 'Small', budget: '~50M', successes: 27, failures: 3, outTokens: 1100, latencyMs: 700, ttfbMs: 110 },
// Middling intel/speed but rock-solid reliability β wins RELIABLE.
{ platform: 'openrouter', modelId: 'rock', name: 'Rock-Solid', intelligenceRank: 5, sizeLabel: 'Medium', budget: '~50M', successes: 40, failures: 1, outTokens: 250, latencyMs: 2000, ttfbMs: 1500 },
// Large/smart but flaky β high intelligence dragged down by failures.
{ platform: 'cerebras', modelId: 'smart-flaky', name: 'Smart-Flaky', intelligenceRank: 3, sizeLabel: 'Large', budget: '~50M', successes: 18, failures: 14, outTokens: 500, latencyMs: 1500, ttfbMs: 600 },
];
function seed() {
const db = getDb();
db.exec('DELETE FROM fallback_config; DELETE FROM api_keys; DELETE FROM models; DELETE FROM requests;');
const insModel = db.prepare(`
INSERT INTO models (platform, model_id, display_name, intelligence_rank, speed_rank, size_label, rpm_limit, rpd_limit, tpm_limit, tpd_limit, monthly_token_budget, enabled)
VALUES (?, ?, ?, ?, 1, ?, 100000, 1000000, 100000000, 1000000000, ?, 1)
`);
const insFb = db.prepare('INSERT INTO fallback_config (model_db_id, priority, enabled) VALUES (?, ?, 1)');
const insHist = db.prepare(`
INSERT INTO requests (platform, model_id, key_id, status, input_tokens, output_tokens, latency_ms, error, ttfb_ms)
VALUES (?, ?, 1, ?, 0, ?, ?, ?, ?)
`);
PROFILES.forEach((p, i) => {
insModel.run(p.platform, p.modelId, p.name, p.intelligenceRank, p.sizeLabel, p.budget);
const id = (db.prepare('SELECT id FROM models WHERE platform=? AND model_id=?').get(p.platform, p.modelId) as { id: number }).id;
insFb.run(id, i + 1);
const { encrypted, iv, authTag } = encrypt(`key-${p.platform}`);
db.prepare(`INSERT INTO api_keys (platform, label, encrypted_key, iv, auth_tag, status, enabled) VALUES (?, 'sim', ?, ?, ?, 'healthy', 1)`)
.run(p.platform, encrypted, iv, authTag);
for (let s = 0; s < p.successes; s++) insHist.run(p.platform, p.modelId, 'success', p.outTokens, p.latencyMs, null, p.ttfbMs);
for (let f = 0; f < p.failures; f++) insHist.run(p.platform, p.modelId, 'error', 0, p.latencyMs, 'sim-fail', p.ttfbMs);
});
}
function distribution(runs: number): Map<string, number> {
const counts = new Map<string, number>();
for (let i = 0; i < runs; i++) {
const r = routeRequest(100);
counts.set(r.displayName, (counts.get(r.displayName) ?? 0) + 1);
}
return counts;
}
function pct(n: number, total: number): string {
return `${((n / total) * 100).toFixed(1)}%`.padStart(6);
}
function printDistribution(title: string, counts: Map<string, number>, runs: number) {
console.log(`\n ${title}`);
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]);
for (const [name, n] of sorted) {
const bar = 'β'.repeat(Math.round((n / runs) * 30));
console.log(` ${name.padEnd(22)} ${pct(n, runs)} ${bar}`);
}
}
function printScores() {
const { scores } = getRoutingScores();
console.log(' model rel spd int guard score');
for (const s of scores) {
const guard = s.headroom * s.rateLimit;
console.log(
` ${s.displayName.padEnd(22)} ` +
`${Math.round(s.reliability * 100).toString().padStart(3)} ` +
`${Math.round(s.speed * 100).toString().padStart(3)} ` +
`${Math.round(s.intelligence * 100).toString().padStart(3)} ` +
`${guard.toFixed(2).padStart(5)} ` +
`${s.score.toFixed(3)}`,
);
}
}
function main() {
initDb(':memory:');
seed();
const RUNS = 2000;
console.log('\nββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
console.log(' ROUTING SIMULATION β 4 models, 2000 requests per strategy');
console.log('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
console.log('\n Synthetic profiles:');
for (const p of PROFILES) {
const rate = (p.successes / (p.successes + p.failures) * 100).toFixed(0);
const tps = (p.outTokens * 1000 / p.latencyMs).toFixed(0);
console.log(` ${p.name.padEnd(22)} ${p.sizeLabel.padEnd(9)} success ${rate}% ${tps} tok/s ${p.ttfbMs}ms ttfb`);
}
const strategies: RoutingStrategy[] = ['priority', 'balanced', 'smartest', 'fastest', 'reliable'];
for (const strat of strategies) {
setRoutingStrategy(strat);
refreshStatsCache(getDb(), true);
if (strat === 'balanced') { console.log('\n ββ balanced score breakdown ββ'); printScores(); }
printDistribution(`Strategy: ${strat.toUpperCase()}`, distribution(RUNS), RUNS);
}
// ββ Adaptation: the favored model under 'balanced' suddenly starts failing ββ
console.log('\nββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
console.log(' ADAPTATION β inject a failure burst into the top model');
console.log('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
setRoutingStrategy('balanced');
refreshStatsCache(getDb(), true);
const before = distribution(RUNS);
printDistribution('Before (balanced, steady state)', before, RUNS);
// Find the current favorite and slam it with fresh failures.
const fav = [...before.entries()].sort((a, b) => b[1] - a[1])[0][0];
const favProfile = PROFILES.find(p => p.name === fav)!;
const db = getDb();
const insHist = db.prepare(`
INSERT INTO requests (platform, model_id, key_id, status, input_tokens, output_tokens, latency_ms, error, ttfb_ms)
VALUES (?, ?, 1, 'error', 0, 0, 1000, 'outage', NULL)
`);
for (let i = 0; i < 300; i++) insHist.run(favProfile.platform, favProfile.modelId);
console.log(`\n β Injected 300 fresh failures into "${fav}" (simulated outage)β¦`);
refreshStatsCache(getDb(), true);
printScores();
printDistribution('After (balanced, post-outage)', distribution(RUNS), RUNS);
console.log('');
}
main();
|