mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
af4140efb9
Apply Phoenix Architecture principles to AQE — regenerate internals, conserve the interface. ADR-113 (evals are oracles, durable-first tests, mutation-score gate): - src/validation/oracle-eval.ts grades a generated test by running it against a reference impl + operator mutants (reuses qe-arena, ADR-104); rejects assertion-less output - oracle mode wired into scripts/run-skill-eval.ts (skips under the simulating runner; runs live) - qe-test-generation rewritten durable-first; its eval flipped to oracle - src/feedback/regenerability-gate.ts: mutation-score + regenerability gate (warn-default, opt-in block) - live-validated: Claude sonnet-4-6 clears the oracle 5/5; weak local-model output correctly fails ADR-114 (conservation layer, Phoenix essay 14): - src/validation/conservation-guard.ts + scripts/conservation-guard.ts guard CLI commands, output schemas, and dashboard API against breaking removals (deprecation registry exempts) - policy doc + baselines in verification/conservation/; wired into invariant-check.yml non-blocking LLM provider fixes: - OpenRouterProvider.type was 'openai' but registered under 'openrouter' -> ProviderManager failover never found it; fixed to 'openrouter' end-to-end - Gemini default model gemini-1.5-pro was retired -> gemini-2.5-flash; models/pricing refreshed from the live Gemini ListModels API - scripts/provider-health.ts (npm run providers:health) Cheaper-model eval lanes: - scripts/oracle-model-bench.ts + openrouter-models.ts; openai/gpt-oss-120b clears the oracle ~50-70x cheaper than Claude Sonnet; guide in docs/guides/cheaper-model-eval-lanes.md Verification: npm run build ok; 115 new+touched tests pass; 724 LLM tests pass; lint + parity clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
61 lines
2.4 KiB
TypeScript
61 lines
2.4 KiB
TypeScript
#!/usr/bin/env tsx
|
|
/**
|
|
* List OpenRouter models by price (cheapest first) to pick cheap candidates for
|
|
* the oracle eval lane. Loads .env for OPENROUTER_API_KEY; never prints the key.
|
|
*
|
|
* tsx scripts/openrouter-models.ts # cheapest ~40 non-free models
|
|
* tsx scripts/openrouter-models.ts free # only $0 / :free models
|
|
* tsx scripts/openrouter-models.ts code # filter ids containing "code"
|
|
*/
|
|
|
|
import { readFileSync, existsSync } from 'fs';
|
|
|
|
if (existsSync('.env')) {
|
|
for (const line of readFileSync('.env', 'utf8').split('\n')) {
|
|
const m = /^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)\s*$/.exec(line);
|
|
if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, '');
|
|
}
|
|
}
|
|
|
|
const filter = process.argv[2]?.toLowerCase();
|
|
|
|
async function main(): Promise<void> {
|
|
const key = process.env.OPENROUTER_API_KEY;
|
|
if (!key) {
|
|
console.error('OPENROUTER_API_KEY not set (.env or env).');
|
|
process.exit(1);
|
|
}
|
|
const res = await fetch('https://openrouter.ai/api/v1/models', {
|
|
headers: { Authorization: `Bearer ${key}` },
|
|
});
|
|
if (!res.ok) {
|
|
console.error(`OpenRouter /models failed: ${res.status} ${res.statusText}`);
|
|
process.exit(1);
|
|
}
|
|
const data = (await res.json()) as { data: Array<{ id: string; context_length?: number; pricing?: { prompt?: string; completion?: string } }> };
|
|
|
|
const wantFree = filter === 'free';
|
|
const rows = data.data
|
|
.map((m) => {
|
|
const inP = Number(m.pricing?.prompt ?? '0') * 1e6; // $ per 1M prompt tokens
|
|
const outP = Number(m.pricing?.completion ?? '0') * 1e6; // $ per 1M completion tokens
|
|
return { id: m.id, inP, outP, blended: inP * 0.3 + outP * 0.7, ctx: m.context_length ?? 0 };
|
|
})
|
|
.filter((r) => (wantFree ? r.inP === 0 && r.outP === 0 : r.outP > 0))
|
|
.filter((r) => (filter && !wantFree ? r.id.toLowerCase().includes(filter) : true))
|
|
.sort((a, b) => (wantFree ? b.ctx - a.ctx : a.blended - b.blended));
|
|
|
|
console.log(`OpenRouter ${wantFree ? 'FREE' : 'priced'} models — ${rows.length}${wantFree ? ' (by context)' : ' (cheapest first, blended 30/70)'}\n`);
|
|
console.log(' $/1M in $/1M out ctx model');
|
|
for (const r of rows.slice(0, 40)) {
|
|
console.log(
|
|
` ${r.inP.toFixed(3).padStart(8)} ${r.outP.toFixed(3).padStart(8)} ${String(r.ctx).padStart(7)} ${r.id}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error('error:', e instanceof Error ? e.message : String(e));
|
|
process.exit(1);
|
|
});
|