Run evals for all models. (#17123)

This commit is contained in:
Christian Gunderman
2026-01-21 16:38:37 +00:00
committed by GitHub
parent 8605d0d024
commit c43b04b44c
2 changed files with 98 additions and 57 deletions
+8 -1
View File
@@ -22,6 +22,12 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
model:
- 'gemini-3-pro-preview'
- 'gemini-3-flash-preview'
- 'gemini-2.5-pro'
- 'gemini-2.5-flash'
- 'gemini-2.5-flash-lite'
run_attempt: [1, 2, 3] run_attempt: [1, 2, 3]
steps: steps:
- name: 'Checkout' - name: 'Checkout'
@@ -45,6 +51,7 @@ jobs:
- name: 'Run Evals' - name: 'Run Evals'
env: env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}' GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GEMINI_MODEL: '${{ matrix.model }}'
RUN_EVALS: "${{ github.event.inputs.run_all != 'false' }}" RUN_EVALS: "${{ github.event.inputs.run_all != 'false' }}"
run: 'npm run test:all_evals' run: 'npm run test:all_evals'
@@ -52,7 +59,7 @@ jobs:
if: 'always()' if: 'always()'
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4 uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with: with:
name: 'eval-logs-${{ matrix.run_attempt }}' name: 'eval-logs-${{ matrix.model }}-${{ matrix.run_attempt }}'
path: 'evals/logs' path: 'evals/logs'
retention-days: 7 retention-days: 7
+90 -56
View File
@@ -32,11 +32,33 @@ function findReports(dir) {
return reports; return reports;
} }
function getModelFromPath(reportPath) {
const parts = reportPath.split(path.sep);
// Find the part that starts with 'eval-logs-'
const artifactDir = parts.find((p) => p.startsWith('eval-logs-'));
if (!artifactDir) return 'unknown';
const matchNew = artifactDir.match(/^eval-logs-(.+)-(\d+)$/);
if (matchNew) return matchNew[1];
const matchOld = artifactDir.match(/^eval-logs-(\d+)$/);
if (matchOld) return 'gemini-2.5-pro'; // Legacy default
return 'unknown';
}
function getStats(reports) { function getStats(reports) {
const testStats = {}; // Structure: { [model]: { [testName]: { passed, failed, total } } }
const statsByModel = {};
for (const reportPath of reports) { for (const reportPath of reports) {
try { try {
const model = getModelFromPath(reportPath);
if (!statsByModel[model]) {
statsByModel[model] = {};
}
const testStats = statsByModel[model];
const content = fs.readFileSync(reportPath, 'utf-8'); const content = fs.readFileSync(reportPath, 'utf-8');
const json = JSON.parse(content); const json = JSON.parse(content);
@@ -58,7 +80,7 @@ function getStats(reports) {
console.error(`Error processing report at ${reportPath}:`, error); console.error(`Error processing report at ${reportPath}:`, error);
} }
} }
return testStats; return statsByModel;
} }
function fetchHistoricalData() { function fetchHistoricalData() {
@@ -92,7 +114,7 @@ function fetchHistoricalData() {
); );
try { try {
// Download report.json files. // Download report.json files.
// The artifacts are named 'eval-logs-X'. // The artifacts are named 'eval-logs-X' or 'eval-logs-MODEL-X'.
// We use -p to match pattern. // We use -p to match pattern.
execSync( execSync(
`gh run download ${run.databaseId} -p "eval-logs-*" -D "${tmpDir}"`, `gh run download ${run.databaseId} -p "eval-logs-*" -D "${tmpDir}"`,
@@ -103,7 +125,7 @@ function fetchHistoricalData() {
if (runReports.length > 0) { if (runReports.length > 0) {
history.push({ history.push({
run, run,
stats: getStats(runReports), stats: getStats(runReports), // Now returns stats grouped by model
}); });
} }
} catch (error) { } catch (error) {
@@ -122,23 +144,8 @@ function fetchHistoricalData() {
return history; return history;
} }
function generateMarkdown(currentStats, history) { function generateMarkdown(currentStatsByModel, history) {
const totalStats = Object.values(currentStats).reduce( console.log('### Evals Nightly Summary\n');
(acc, stats) => {
acc.passed += stats.passed;
acc.total += stats.total;
return acc;
},
{ passed: 0, total: 0 },
);
const totalPassRate =
totalStats.total > 0
? ((totalStats.passed / totalStats.total) * 100).toFixed(1) + '%'
: 'N/A';
console.log('### Evals Nightly Summary');
console.log(`**Total Pass Rate: ${totalPassRate}**\n`);
console.log( console.log(
'See [evals/README.md](https://github.com/google-gemini/gemini-cli/tree/main/evals) for more details.\n', 'See [evals/README.md](https://github.com/google-gemini/gemini-cli/tree/main/evals) for more details.\n',
); );
@@ -146,53 +153,80 @@ function generateMarkdown(currentStats, history) {
// Reverse history to show oldest first // Reverse history to show oldest first
const reversedHistory = [...history].reverse(); const reversedHistory = [...history].reverse();
// Header const models = Object.keys(currentStatsByModel).sort();
let header = '| Test Name |';
let separator = '| :--- |';
for (const item of reversedHistory) { for (const model of models) {
header += ` [${item.run.databaseId}](${item.run.url}) |`; const currentStats = currentStatsByModel[model];
separator += ' :---: |'; const totalStats = Object.values(currentStats).reduce(
} (acc, stats) => {
acc.passed += stats.passed;
acc.total += stats.total;
return acc;
},
{ passed: 0, total: 0 },
);
// Add Current column last const totalPassRate =
header += ' Current |'; totalStats.total > 0
separator += ' :---: |'; ? ((totalStats.passed / totalStats.total) * 100).toFixed(1) + '%'
: 'N/A';
console.log(header); console.log(`#### Model: ${model}`);
console.log(separator); console.log(`**Total Pass Rate: ${totalPassRate}**\n`);
// Collect all test names // Header
const allTestNames = new Set(Object.keys(currentStats)); let header = '| Test Name |';
for (const item of reversedHistory) { let separator = '| :--- |';
Object.keys(item.stats).forEach((name) => allTestNames.add(name));
}
for (const name of Array.from(allTestNames).sort()) {
const searchUrl = `https://github.com/search?q=repo%3Agoogle-gemini%2Fgemini-cli%20%22${encodeURIComponent(name)}%22&type=code`;
let row = `| [${name}](${searchUrl}) |`;
// History
for (const item of reversedHistory) { for (const item of reversedHistory) {
const stat = item.stats[name]; header += ` [${item.run.databaseId}](${item.run.url}) |`;
if (stat) { separator += ' :---: |';
const passRate = ((stat.passed / stat.total) * 100).toFixed(0) + '%'; }
// Add Current column last
header += ' Current |';
separator += ' :---: |';
console.log(header);
console.log(separator);
// Collect all test names for this model
const allTestNames = new Set(Object.keys(currentStats));
for (const item of reversedHistory) {
if (item.stats[model]) {
Object.keys(item.stats[model]).forEach((name) =>
allTestNames.add(name),
);
}
}
for (const name of Array.from(allTestNames).sort()) {
const searchUrl = `https://github.com/search?q=repo%3Agoogle-gemini%2Fgemini-cli%20%22${encodeURIComponent(name)}%22&type=code`;
let row = `| [${name}](${searchUrl}) |`;
// History
for (const item of reversedHistory) {
const stat = item.stats[model] ? item.stats[model][name] : null;
if (stat) {
const passRate = ((stat.passed / stat.total) * 100).toFixed(0) + '%';
row += ` ${passRate} |`;
} else {
row += ' - |';
}
}
// Current
const curr = currentStats[name];
if (curr) {
const passRate = ((curr.passed / curr.total) * 100).toFixed(0) + '%';
row += ` ${passRate} |`; row += ` ${passRate} |`;
} else { } else {
row += ' - |'; row += ' - |';
} }
}
// Current console.log(row);
const curr = currentStats[name];
if (curr) {
const passRate = ((curr.passed / curr.total) * 100).toFixed(0) + '%';
row += ` ${passRate} |`;
} else {
row += ' - |';
} }
console.log('\n');
console.log(row);
} }
} }