Skip to content

Commit d19a66c

Browse files
committed
fix: retry AI fallback once on HTTP 429 with Retry-After backoff
When the GitHub Models API rate-limits the backfill (429), read the Retry-After header (capped at 60s), wait, then retry the request once. If the retry also fails the issue is skipped as before.
1 parent fb481ad commit d19a66c

1 file changed

Lines changed: 33 additions & 30 deletions

File tree

.github/workflows/labeler.yml

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,37 +1337,40 @@ jobs:
13371337
// Optional AI fallback for legacy issues where deterministic matching finds nothing.
13381338
if (useAiGameFallback && desiredGames.size === 0) {
13391339
aiGameAttempts += 1;
1340-
try {
1341-
const res = await fetch(
1342-
`https://models.github.ai/orgs/${owner}/inference/chat/completions`,
1340+
const aiPayload = {
1341+
model: 'openai/gpt-4.1-mini',
1342+
temperature: 0.1,
1343+
max_tokens: 120,
1344+
messages: [
13431345
{
1344-
method: 'POST',
1345-
headers: {
1346-
Accept: 'application/vnd.github+json',
1347-
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
1348-
'X-GitHub-Api-Version': '2026-03-10',
1349-
'Content-Type': 'application/json',
1350-
},
1351-
body: JSON.stringify({
1352-
model: 'openai/gpt-4.1-mini',
1353-
temperature: 0.1,
1354-
max_tokens: 120,
1355-
messages: [
1356-
{
1357-
role: 'system',
1358-
content:
1359-
'Return JSON only. Identify the game referenced in this LinuxGSM issue with high precision.',
1360-
},
1361-
{
1362-
role: 'user',
1363-
content:
1364-
`Title: ${title}\n\nBody:\n${body.slice(0, 2500)}\n\n` +
1365-
'Return JSON: {"detected_game":"string or null","game_confidence":"high|medium|low|null"}',
1366-
},
1367-
],
1368-
}),
1369-
}
1370-
);
1346+
role: 'system',
1347+
content: 'Return JSON only. Identify the game referenced in this LinuxGSM issue with high precision.',
1348+
},
1349+
{
1350+
role: 'user',
1351+
content:
1352+
`Title: ${title}\n\nBody:\n${body.slice(0, 2500)}\n\n` +
1353+
'Return JSON: {"detected_game":"string or null","game_confidence":"high|medium|low|null"}',
1354+
},
1355+
],
1356+
};
1357+
const aiUrl = `https://models.github.ai/orgs/${owner}/inference/chat/completions`;
1358+
const aiHeaders = {
1359+
Accept: 'application/vnd.github+json',
1360+
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
1361+
'X-GitHub-Api-Version': '2026-03-10',
1362+
'Content-Type': 'application/json',
1363+
};
1364+
try {
1365+
let res = await fetch(aiUrl, { method: 'POST', headers: aiHeaders, body: JSON.stringify(aiPayload) });
1366+
1367+
// On 429 honour Retry-After (capped at 60 s) then retry once.
1368+
if (res.status === 429) {
1369+
const retryAfter = Math.min(Number.parseInt(res.headers.get('Retry-After') || '10', 10), 60);
1370+
console.log(`#${rawIssue.number}: AI fallback rate-limited — waiting ${retryAfter}s then retrying…`);
1371+
await new Promise((r) => setTimeout(r, retryAfter * 1000));
1372+
res = await fetch(aiUrl, { method: 'POST', headers: aiHeaders, body: JSON.stringify(aiPayload) });
1373+
}
13711374
13721375
if (res.ok) {
13731376
const data = await res.json();

0 commit comments

Comments
 (0)