Spaces:
Paused
Paused
| """Code Quality Agent - Scores structure, complexity, dependency health, docs, tests, CI, maintainability.""" | |
| from typing import Dict, Any | |
| from base_agent import BaseAgent, AgentOutput | |
| class CodeQualityAgent(BaseAgent): | |
| """Deterministically scores code quality without LLMs.""" | |
| def __init__(self): | |
| super().__init__("CodeQuality") | |
| def _assess_structure(self, repo_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """Assess repository structure quality.""" | |
| evidence = {} | |
| size = repo_data.get("size", 0) | |
| has_readme = repo_data.get("has_readme", False) | |
| has_package = any([ | |
| repo_data.get("has_package_json", False), | |
| repo_data.get("has_requirements_txt", False), | |
| repo_data.get("has_setup_py", False), | |
| repo_data.get("has_pyproject_toml", False), | |
| repo_data.get("has_cargo_toml", False), | |
| repo_data.get("has_go_mod", False) | |
| ]) | |
| has_ci = repo_data.get("has_ci", False) | |
| has_makefile = repo_data.get("has_makefile", False) | |
| has_dockerfile = repo_data.get("has_dockerfile", False) | |
| evidence["size_kb"] = size | |
| evidence["has_readme"] = has_readme | |
| evidence["has_package_manager"] = has_package | |
| evidence["has_ci"] = has_ci | |
| evidence["has_makefile"] = has_makefile | |
| evidence["has_dockerfile"] = has_dockerfile | |
| # Structure score | |
| structure_score = 0 | |
| if has_readme: | |
| structure_score += 20 | |
| if has_package: | |
| structure_score += 20 | |
| if has_ci: | |
| structure_score += 20 | |
| if has_makefile: | |
| structure_score += 15 | |
| if has_dockerfile: | |
| structure_score += 15 | |
| # Size penalty (too large = complexity risk) | |
| if size > 100000: # > 100MB | |
| structure_score *= 0.7 | |
| elif size > 10000: # > 10MB | |
| structure_score *= 0.85 | |
| evidence["structure_score"] = structure_score | |
| return { | |
| "score": structure_score, | |
| "evidence": evidence | |
| } | |
| def _assess_complexity(self, repo_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """Assess code complexity based on indirect signals.""" | |
| evidence = {} | |
| size = repo_data.get("size", 0) | |
| contributors = repo_data.get("contributors", 0) | |
| open_issues = repo_data.get("open_issues", 0) | |
| commits_last_year = repo_data.get("commits_last_year", 0) | |
| evidence["size_kb"] = size | |
| evidence["contributors"] = contributors | |
| evidence["open_issues"] = open_issues | |
| evidence["commits_last_year"] = commits_last_year | |
| # Complexity score (lower is better for maintainability) | |
| complexity_score = 100 # Start with best | |
| # Size indicates complexity | |
| if size > 100000: | |
| complexity_score -= 40 | |
| elif size > 10000: | |
| complexity_score -= 25 | |
| elif size > 1000: | |
| complexity_score -= 10 | |
| # Many contributors suggests complex codebase | |
| if contributors > 20: | |
| complexity_score -= 20 | |
| elif contributors > 10: | |
| complexity_score -= 10 | |
| # High issue count suggests complexity or debt | |
| if open_issues > 100: | |
| complexity_score -= 20 | |
| elif open_issues > 50: | |
| complexity_score -= 10 | |
| # High commit frequency suggests active maintenance | |
| if commits_last_year > 100: | |
| complexity_score += 10 | |
| elif commits_last_year > 50: | |
| complexity_score += 5 | |
| complexity_score = max(0, min(complexity_score, 100)) | |
| evidence["complexity_score"] = complexity_score | |
| return { | |
| "score": complexity_score, | |
| "evidence": evidence | |
| } | |
| def _assess_dependency_health(self, repo_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """Assess dependency health based on package manager presence.""" | |
| evidence = {} | |
| has_package = any([ | |
| repo_data.get("has_package_json", False), | |
| repo_data.get("has_requirements_txt", False), | |
| repo_data.get("has_setup_py", False), | |
| repo_data.get("has_pyproject_toml", False), | |
| repo_data.get("has_cargo_toml", False), | |
| repo_data.get("has_go_mod", False) | |
| ]) | |
| has_ci = repo_data.get("has_ci", False) | |
| commits_last_year = repo_data.get("commits_last_year", 0) | |
| evidence["has_package_manager"] = has_package | |
| evidence["has_ci"] = has_ci | |
| evidence["commits_last_year"] = commits_last_year | |
| # Dependency health score | |
| dep_health = 0 | |
| if has_package: | |
| dep_health += 40 | |
| if has_ci: | |
| dep_health += 30 # CI likely tests dependencies | |
| if commits_last_year > 0: | |
| dep_health += 30 # Active maintenance = updated deps | |
| evidence["dependency_health_score"] = dep_health | |
| return { | |
| "score": dep_health, | |
| "evidence": evidence | |
| } | |
| def _assess_documentation(self, repo_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """Assess documentation quality.""" | |
| evidence = {} | |
| has_readme = repo_data.get("has_readme", False) | |
| readme_size = repo_data.get("readme_size", 0) | |
| has_wiki = repo_data.get("has_wiki", False) | |
| has_pages = repo_data.get("has_pages", False) | |
| evidence["has_readme"] = has_readme | |
| evidence["readme_size"] = readme_size | |
| evidence["has_wiki"] = has_wiki | |
| evidence["has_pages"] = has_pages | |
| # Documentation score | |
| doc_score = 0 | |
| if has_readme: | |
| doc_score += 40 | |
| if readme_size > 1000: # Substantial README | |
| doc_score += 20 | |
| if has_wiki: | |
| doc_score += 20 | |
| if has_pages: | |
| doc_score += 20 | |
| evidence["documentation_score"] = doc_score | |
| return { | |
| "score": doc_score, | |
| "evidence": evidence | |
| } | |
| def _assess_tests(self, repo_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """Assess test coverage based on indirect signals.""" | |
| evidence = {} | |
| has_ci = repo_data.get("has_ci", False) | |
| has_package = any([ | |
| repo_data.get("has_package_json", False), | |
| repo_data.get("has_requirements_txt", False), | |
| repo_data.get("has_setup_py", False), | |
| repo_data.get("has_pyproject_toml", False), | |
| repo_data.get("has_cargo_toml", False), | |
| repo_data.get("has_go_mod", False) | |
| ]) | |
| evidence["has_ci"] = has_ci | |
| evidence["has_package_manager"] = has_package | |
| # Test score (proxy-based) | |
| test_score = 0 | |
| if has_ci: | |
| test_score += 50 # CI likely runs tests | |
| if has_package: | |
| test_score += 30 # Package manager enables testing | |
| test_score += 20 # Base score for potential | |
| evidence["test_score"] = test_score | |
| return { | |
| "score": test_score, | |
| "evidence": evidence | |
| } | |
| def _assess_maintainability(self, repo_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """Assess maintainability.""" | |
| evidence = {} | |
| contributors = repo_data.get("contributors", 0) | |
| commits_last_year = repo_data.get("commits_last_year", 0) | |
| open_issues = repo_data.get("open_issues", 0) | |
| is_archived = repo_data.get("archived", False) | |
| license_key = repo_data.get("license") | |
| evidence["contributors"] = contributors | |
| evidence["commits_last_year"] = commits_last_year | |
| evidence["open_issues"] = open_issues | |
| evidence["is_archived"] = is_archived | |
| evidence["license"] = license_key | |
| # Maintainability score | |
| maintainability = 0 | |
| # Active contributors | |
| if contributors >= 1: | |
| maintainability += 20 | |
| if contributors >= 3: | |
| maintainability += 10 | |
| # Recent activity | |
| if commits_last_year > 0: | |
| maintainability += 20 | |
| if commits_last_year > 12: | |
| maintainability += 10 | |
| # Issue backlog | |
| if open_issues < 10: | |
| maintainability += 20 | |
| elif open_issues < 50: | |
| maintainability += 10 | |
| # Not archived | |
| if not is_archived: | |
| maintainability += 10 | |
| # Has license | |
| if license_key: | |
| maintainability += 10 | |
| evidence["maintainability_score"] = maintainability | |
| return { | |
| "score": maintainability, | |
| "evidence": evidence | |
| } | |
| def analyze(self, repo_data: Dict[str, Any]) -> AgentOutput: | |
| """ | |
| Analyze code quality across multiple dimensions. | |
| """ | |
| evidence = {} | |
| # Assess all dimensions | |
| structure = self._assess_structure(repo_data) | |
| complexity = self._assess_complexity(repo_data) | |
| dep_health = self._assess_dependency_health(repo_data) | |
| documentation = self._assess_documentation(repo_data) | |
| tests = self._assess_tests(repo_data) | |
| maintainability = self._assess_maintainability(repo_data) | |
| # Store evidence | |
| evidence["structure"] = structure["evidence"] | |
| evidence["complexity"] = complexity["evidence"] | |
| evidence["dependency_health"] = dep_health["evidence"] | |
| evidence["documentation"] = documentation["evidence"] | |
| evidence["tests"] = tests["evidence"] | |
| evidence["maintainability"] = maintainability["evidence"] | |
| # Calculate overall code quality score | |
| # Weighted combination | |
| quality_score = ( | |
| 0.20 * structure["score"] + | |
| 0.15 * complexity["score"] + | |
| 0.15 * dep_health["score"] + | |
| 0.20 * documentation["score"] + | |
| 0.15 * tests["score"] + | |
| 0.15 * maintainability["score"] | |
| ) | |
| evidence["overall_code_quality"] = quality_score | |
| # Confidence based on data availability | |
| required_fields = ["size", "has_readme", "has_ci", "contributors"] | |
| completeness = sum(1 for field in required_fields if field in repo_data) | |
| confidence = completeness / len(required_fields) | |
| return AgentOutput( | |
| score=round(quality_score, 2), | |
| evidence=evidence, | |
| confidence=confidence, | |
| hash="" | |
| ) | |