capscore-agent / api /app /workers /readme_rewriter.py
mathurinacheisoft's picture
Deploy CAPScore (clean recreate)
2a7f679 verified
Raw
History Blame Contribute Delete
5.87 kB
"""
Worker: README Rewriter
Uses Claude (or heuristics) to suggest targeted improvements to a project's README
based on the repository analysis results.
"""
from __future__ import annotations
import asyncio
import json
from typing import List, Optional
import httpx
from ..config import settings
from ..models import ReproResult
from ..llm import complete, strip_code_fences
async def _fetch_readme(github_url: str, timeout: int = 10) -> str:
"""Fetch raw README content from GitHub."""
# Normalize URL: https://github.com/owner/repo -> raw content URL
url = github_url.rstrip("/")
owner_repo = url.replace("https://github.com/", "")
for branch in ("main", "master"):
raw_url = f"https://raw.githubusercontent.com/{owner_repo}/{branch}/README.md"
try:
async with httpx.AsyncClient(timeout=timeout) as client:
resp = await client.get(raw_url)
if resp.status_code == 200:
return resp.text[:4000]
except Exception:
pass
return ""
async def _llm_suggest_readme_fixes(
readme_content: str,
repo_result: Optional[ReproResult],
github_url: str,
) -> List[str]:
"""Generate README suggestions via the shared LLM helper, with heuristic fallback."""
try:
issues_summary = ""
if repo_result:
missing = [k for k, v in repo_result.files_present.items() if not v]
issues_summary = f"\nRepository issues detected: {', '.join(repo_result.issues[:5])}\nMissing files: {', '.join(missing[:5])}"
readme_excerpt = readme_content[:2000] if readme_content else "(No README found)"
prompt = f"""You are a technical writer helping an AI agent developer improve their README for the CROO Agent Store.
Repository: {github_url}{issues_summary}
Current README (truncated):
{readme_excerpt}
Generate exactly 5 concrete, actionable suggestions to improve this README for:
1. Agent marketplace buyers who need to quickly understand what the agent does and how to use it
2. CROO hackathon judges evaluating technical execution and adoption readiness
3. Other AI agents that may want to call this agent via CAP protocol
Format as a JSON array of strings, each suggestion being 1-2 sentences. Focus on:
- Missing quickstart/installation instructions
- Unclear or missing input/output examples
- Missing pricing or SLA information for CAP buyers
- Missing environment variable documentation
- Poor explanation of the agent's unique value proposition
Return ONLY a valid JSON array of 5 strings, no markdown, no explanation."""
text = await complete(prompt, max_tokens=800, temperature=0)
if text is None:
return _heuristic_readme_suggestions(readme_content, repo_result)
suggestions = json.loads(strip_code_fences(text))
return [str(s) for s in suggestions[:5]]
except Exception:
return _heuristic_readme_suggestions(readme_content, repo_result)
def _heuristic_readme_suggestions(
readme_content: str,
repo_result: Optional[ReproResult],
) -> List[str]:
"""Generate README suggestions without LLM."""
suggestions = []
content_lower = readme_content.lower() if readme_content else ""
if not readme_content:
return [
"Add a README.md — this is the first thing judges and buyers will read.",
"Include a one-sentence description of what the agent does and what problem it solves.",
"Add a 'Quick Start' section with copy-paste installation commands.",
"Document all required environment variables with descriptions (no real values).",
"Add an example input and output to show what the agent produces.",
]
if "quick start" not in content_lower and "quickstart" not in content_lower and "getting started" not in content_lower:
suggestions.append(
"Add a 'Quick Start' section with step-by-step commands so buyers can get running in under 5 minutes."
)
if "example" not in content_lower and "sample" not in content_lower:
suggestions.append(
"Include a concrete input/output example so buyers understand exactly what to send and what they'll receive."
)
if "price" not in content_lower and "cost" not in content_lower and "croo" not in content_lower:
suggestions.append(
"Add a 'Pricing' section documenting the cost per call and any SLA guarantees for CAP marketplace buyers."
)
if ".env" not in content_lower and "environment" not in content_lower:
suggestions.append(
"Add an 'Environment Variables' section listing all required variables — ideally referencing .env.example."
)
if repo_result and not repo_result.files_present.get("docker-compose.yml", False):
suggestions.append(
"Add docker-compose.yml and document Docker-based setup in the README for reproducible one-command startup."
)
if len(suggestions) < 5:
suggestions.append(
"Add a badge section (CI status, version, license) at the top to signal project maturity to evaluators."
)
if len(suggestions) < 5:
suggestions.append(
"Add a 'How It Works' section with a short architecture diagram or flowchart showing the agent's decision flow."
)
return suggestions[:5]
async def suggest_readme_fixes(
github_url: str,
repo_result: Optional[ReproResult] = None,
) -> List[str]:
"""
Analyse the project README and return up to 5 targeted improvement suggestions.
Uses Claude if ANTHROPIC_API_KEY is set, otherwise falls back to heuristics.
"""
readme_content = await _fetch_readme(github_url)
suggestions = await _llm_suggest_readme_fixes(readme_content, repo_result, github_url)
return suggestions