Spaces:
Sleeping
Sleeping
File size: 3,825 Bytes
763ef0d | 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 | """
Error classifier - identifies error categories from tracebacks/output.
Used by repair engine to produce targeted repair plans.
"""
from __future__ import annotations
import re
from dataclasses import dataclass
from typing import Optional
@dataclass
class ErrorClass:
category: str
detail: str
suggested_fix: str
RULES = [
# python module / pip
(r"ModuleNotFoundError: No module named ['\"]([\w\.\-]+)['\"]", "missing_python_module"),
(r"ImportError: No module named ([\w\.\-]+)", "missing_python_module"),
(r"pip(?:3)?: command not found", "missing_pip"),
# node / npm
(r"command not found: (npm|node|npx)", "missing_node"),
(r"npm ERR! code E?ENOENT", "npm_failure"),
(r"npm ERR! code (E\w+)", "npm_failure"),
# playwright
(r"playwright[^\s]*: command not found", "missing_playwright"),
(r"Executable doesn't exist at .+(chrom|firefox|webkit)", "playwright_browsers_missing"),
(r"BrowserType\.launch:.*Host system is missing dependencies", "playwright_missing_deps"),
# git
(r"fatal: unable to auto-detect email address", "git_identity_missing"),
(r"Please tell me who you are\.", "git_identity_missing"),
(r"fatal: not a git repository", "not_a_git_repo"),
(r"Authentication failed", "git_auth_failed"),
# python version / build
(r"greenlet[^\n]*failed to build", "greenlet_build_failure"),
(r"Could not build wheels for ([\w\-]+)", "python_build_failure"),
(r"requires Python ['\"][^'\"]+['\"]", "python_version_mismatch"),
# network
(r"Could not resolve host", "network_failure"),
(r"Connection refused", "network_failure"),
(r"Read timed out", "network_failure"),
# http
(r"\b429\b", "rate_limited"),
(r"\b401\b|\b403\b", "auth_failure"),
]
def classify(output: str) -> Optional[ErrorClass]:
if not output:
return None
for pattern, category in RULES:
m = re.search(pattern, output)
if m:
detail = m.group(0)
return ErrorClass(category=category, detail=detail, suggested_fix=_fix_for(category, m))
# Generic exception detection
if "Traceback (most recent call last):" in output:
return ErrorClass(category="python_exception", detail="Unclassified Python exception", suggested_fix="inspect traceback and retry")
return None
def _fix_for(category: str, m: re.Match) -> str:
if category == "missing_python_module":
return f"pip install {m.group(1)}"
if category == "missing_pip":
return "ensure python3-pip is installed"
if category == "missing_node":
return "install node + npm"
if category == "npm_failure":
return "delete node_modules and reinstall"
if category == "missing_playwright":
return "pip install playwright && python -m playwright install"
if category == "playwright_browsers_missing":
return "python -m playwright install chromium"
if category == "playwright_missing_deps":
return "python -m playwright install-deps chromium"
if category == "git_identity_missing":
return "git config user.email and user.name"
if category == "not_a_git_repo":
return "git init or cd into repo"
if category == "git_auth_failed":
return "verify GITHUB_TOKEN and remote URL"
if category == "greenlet_build_failure":
return "pin Python 3.11 and install build essentials"
if category == "python_build_failure":
return "install build-essential and retry"
if category == "python_version_mismatch":
return "use Python 3.11"
if category == "network_failure":
return "retry after backoff"
if category == "rate_limited":
return "rotate provider key or wait"
if category == "auth_failure":
return "rotate API key"
return "retry"
|