Skip to content

Commit 8d89b57

Browse files
authored
feat: Implement Hugging Face-based CI failure analysis and update wor… (#52)
* feat: Implement Hugging Face-based CI failure analysis and update workflow name * feat: Implement Hugging Face-based CI failure analysis and update workflow name
1 parent 8073080 commit 8d89b57

2 files changed

Lines changed: 48 additions & 27 deletions

File tree

.github/workflows/ci-copilot-prompt.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ jobs:
108108
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
109109
HF_API_TOKEN: ${{ secrets.HF_API_TOKEN }}
110110
# Prefer known, ungated default to avoid 404s:
111-
HF_MODEL: ${{ vars.HF_MODEL || 'mistralai/Mistral-7B-Instruct-v0.2' }}
111+
HF_MODEL: ${{ vars.HF_MODEL || 'HuggingFaceTB/SmolLM3-3B' }}
112112
ANALYZER_MAX_HIGHLIGHTS: ${{ vars.ANALYZER_MAX_HIGHLIGHTS || '200' }}
113113
HF_MAX_NEW_TOKENS: ${{ vars.HF_MAX_NEW_TOKENS || '800' }}
114114
run: |

scripts/HfCiFailureAnalyzer.java

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* If not set, a sane default list is used (see DEFAULT_FALLBACKS).
1313
* - HF_MAX_NEW_TOKENS, ANALYZER_MAX_HIGHLIGHTS (see workflow)
1414
*/
15+
1516
import java.io.*;
1617
import java.net.URI;
1718
import java.net.http.*;
@@ -210,15 +211,15 @@ private static String analyzeWithHuggingFaceOrFallback(String token, String mode
210211
try {
211212
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(20)).build();
212213
String body = """
213-
{
214-
"inputs": %s,
215-
"parameters": {
216-
"max_new_tokens": %d,
217-
"temperature": 0.2,
218-
"return_full_text": false
219-
}
220-
}
221-
""".formatted(jsonString(prompt), maxNewTokens);
214+
{
215+
"inputs": %s,
216+
"parameters": {
217+
"max_new_tokens": %d,
218+
"temperature": 0.2,
219+
"return_full_text": false
220+
}
221+
}
222+
""".formatted(jsonString(prompt), maxNewTokens);
222223

223224
HttpRequest request = HttpRequest.newBuilder()
224225
.uri(URI.create("https://api-inference.huggingface.co/models/" + model))
@@ -270,8 +271,11 @@ private static class PreflightResult {
270271
final boolean ok;
271272
final int status;
272273
final String note;
274+
273275
PreflightResult(boolean ok, int status, String note) {
274-
this.ok = ok; this.status = status; this.note = note == null ? "" : note;
276+
this.ok = ok;
277+
this.status = status;
278+
this.note = note == null ? "" : note;
275279
}
276280
}
277281

@@ -282,8 +286,8 @@ private static PreflightResult preflightHF(String token, String model) {
282286
try {
283287
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(15)).build();
284288
String body = """
285-
{"inputs":"preflight","parameters":{"max_new_tokens":1,"temperature":0.0,"return_full_text":false}}
286-
""";
289+
{"inputs":"preflight","parameters":{"max_new_tokens":1,"temperature":0.0,"return_full_text":false}}
290+
""";
287291
HttpRequest req = HttpRequest.newBuilder()
288292
.uri(URI.create("https://api-inference.huggingface.co/models/" + trimmedModel))
289293
.timeout(Duration.ofSeconds(30))
@@ -318,22 +322,22 @@ private static int parseEstimatedTimeSeconds(String json, int def) {
318322
num.append(json.charAt(end++));
319323
}
320324
double seconds = Double.parseDouble(num.toString());
321-
return Math.max(1, (int)Math.ceil(seconds));
325+
return Math.max(1, (int) Math.ceil(seconds));
322326
} catch (Exception e) {
323327
return def;
324328
}
325329
}
326330

327331
private static String buildPrompt(String ctx, String jobsSummary, String highlights) {
328332
String instruction = """
329-
You are a senior CI/CD debugging assistant.
330-
Based on the CI context, failed jobs/steps summary, and the Error Highlights below, provide:
331-
1) Top 1–3 likely root causes (ranked by confidence; cite key lines/files/commands).
332-
2) The minimal fix to make CI pass (concrete commands or code changes).
333-
3) Next steps to verify or further debug (specific commands/files/log keywords).
334-
If this resembles dependency/cache/permission/concurrency/timeout/environment/test flakiness,
335-
call it out and provide a proven template fix. Keep the answer concise and structured.
336-
""";
333+
You are a senior CI/CD debugging assistant.
334+
Based on the CI context, failed jobs/steps summary, and the Error Highlights below, provide:
335+
1) Top 1–3 likely root causes (ranked by confidence; cite key lines/files/commands).
336+
2) The minimal fix to make CI pass (concrete commands or code changes).
337+
3) Next steps to verify or further debug (specific commands/files/log keywords).
338+
If this resembles dependency/cache/permission/concurrency/timeout/environment/test flakiness,
339+
call it out and provide a proven template fix. Keep the answer concise and structured.
340+
""";
337341
String prompt = "CI Context:\n" + ctx + "\n\n" +
338342
"Failed jobs/steps summary:\n" + jobsSummary + "\n\n" +
339343
"Error Highlights:\n" + highlights + "\n\n" +
@@ -378,9 +382,15 @@ private static String extractErrorHighlights(String text, int maxLines) {
378382

379383
// ----------------- Rule-based fallback -----------------
380384

381-
private record Rule(String name, Pattern pattern, String explanation, List<String> minimalFix, List<String> nextSteps) {}
382-
private record DiagnosisEntry(Rule rule, int score, List<String> samples) {}
383-
private record DiagnosisResult(List<DiagnosisEntry> entries) {}
385+
private record Rule(String name, Pattern pattern, String explanation, List<String> minimalFix,
386+
List<String> nextSteps) {
387+
}
388+
389+
private record DiagnosisEntry(Rule rule, int score, List<String> samples) {
390+
}
391+
392+
private record DiagnosisResult(List<DiagnosisEntry> entries) {
393+
}
384394

385395
private static String ruleBasedAnalysis(String highlights) {
386396
List<Rule> rules = defaultRules();
@@ -598,6 +608,7 @@ private static String runProcess(String[] cmd) throws IOException, InterruptedEx
598608
private static String jsonString(String s) {
599609
return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n") + "\"";
600610
}
611+
601612
private static String extractJsonField(String json, String field) {
602613
String key = "\"" + field + "\"";
603614
int i = json.indexOf(key);
@@ -618,17 +629,27 @@ private static String extractJsonField(String json, String field) {
618629
String val = json.substring(startQuote + 1, end);
619630
return val.replace("\\n", "\n").replace("\\\"", "\"");
620631
}
632+
621633
private static String requireEnv(String key) {
622634
String v = System.getenv(key);
623635
if (isBlank(v)) throw new IllegalStateException("Missing environment variable: " + key);
624636
return v;
625637
}
638+
626639
private static String getenvOr(String key, String def) {
627640
String v = System.getenv(key);
628641
return isBlank(v) ? def : v;
629642
}
643+
630644
private static int parseIntSafe(String s, int def) {
631-
try { return Integer.parseInt(s.trim()); } catch (Exception e) { return def; }
645+
try {
646+
return Integer.parseInt(s.trim());
647+
} catch (Exception e) {
648+
return def;
649+
}
650+
}
651+
652+
private static boolean isBlank(String s) {
653+
return s == null || s.trim().isEmpty();
632654
}
633-
private static boolean isBlank(String s) { return s == null || s.trim().isEmpty(); }
634655
}

0 commit comments

Comments
 (0)