CodeAgentbyCrewAi / agent.py
PraneshJs's picture
Update agent.py
4ec4b26 verified
import os
import requests
from typing import List
from crewai import Agent, Task, Crew, Process
from dotenv import load_dotenv
# ✅ Gemini client (modern import)
from google import genai
load_dotenv()
# ---------------------------------
# CONFIG
# ---------------------------------
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
MODEL_NAME = os.getenv("GEMINI_MODEL", "gemini-1.5-flash")
if not GOOGLE_API_KEY:
raise RuntimeError("❌ Missing GOOGLE_API_KEY — get one at https://aistudio.google.com")
client = genai.Client(api_key=GOOGLE_API_KEY)
# ---------------------------------
# SIMPLE GITHUB FETCHER (no embeddings)
# ---------------------------------
def fetch_repo_files(repo_url: str, max_files: int = 10) -> List[str]:
"""Fetch a few code/text files from a GitHub repo using the REST API."""
try:
owner_repo = repo_url.strip().split("github.com/")[-1]
api_url = f"https://api.github.com/repos/{owner_repo}/contents"
headers = {"Authorization": f"token {GITHUB_TOKEN}"} if GITHUB_TOKEN else {}
response = requests.get(api_url, headers=headers)
response.raise_for_status()
data = response.json()
files = []
for f in data:
if f["type"] == "file" and f["name"].endswith((".py", ".js", ".ts", ".md")):
files.append(f["download_url"])
if len(files) >= max_files:
break
return files
except Exception as e:
return [f"⚠️ Error fetching repo: {e}"]
def fetch_file_content(url: str) -> str:
"""Fetch raw file text safely."""
try:
res = requests.get(url, timeout=10)
res.raise_for_status()
return res.text
except Exception as e:
return f"⚠️ Could not fetch {url}\nError: {e}"
# ---------------------------------
# GEMINI WRAPPER
# ---------------------------------
class GeminiLLM:
"""CrewAI-compatible Gemini LLM wrapper."""
def __init__(self, model: str):
self.model = model
def generate(self, prompt: str) -> str:
try:
res = client.models.generate_content(
model=self.model,
contents=prompt,
generation_config={"temperature": 0.6, "max_output_tokens": 2048},
)
return res.text
except Exception as e:
return f"⚠️ Gemini Error: {e}"
# instantiate global LLM
gemini_llm = GeminiLLM(MODEL_NAME)
# ---------------------------------
# AGENTS
# ---------------------------------
def make_agents(repo_url: str):
repo_mapper = Agent(
role="Repository Mapper",
goal="Map project structure, detect tech stack, and summarize key components.",
backstory="You analyze folder trees and dependencies for architecture insights.",
llm=gemini_llm,
verbose=True,
)
code_reviewer = Agent(
role="Code Reviewer",
goal="Perform pragmatic code reviews with clear, actionable feedback.",
backstory="An experienced engineer providing concise improvement tips.",
llm=gemini_llm,
verbose=True,
)
security_auditor = Agent(
role="Security Auditor",
goal="Find and describe security issues, secrets, or risky dependencies.",
backstory="You think like an attacker but document like a pro auditor.",
llm=gemini_llm,
verbose=True,
)
doc_explainer = Agent(
role="Documentation Explainer",
goal="Explain repository purpose, architecture, and how to run or contribute.",
backstory="You make complex projects understandable for new contributors.",
llm=gemini_llm,
verbose=True,
)
manager = Agent(
role="Engineering Manager",
goal="Coordinate all other agents and compile a cohesive final report.",
backstory="A seasoned manager merging all insights into one structured summary.",
allow_delegation=True,
llm=gemini_llm,
verbose=True,
)
return repo_mapper, code_reviewer, security_auditor, doc_explainer, manager
# ---------------------------------
# TASKS
# ---------------------------------
def make_tasks(repo_url: str, brief: str = ""):
repo_files = fetch_repo_files(repo_url)
file_contents = "\n\n".join(fetch_file_content(f) for f in repo_files[:5])
context = (
f"Repository: {repo_url}\n"
f"{'Brief: ' + brief if brief else ''}\n"
f"Fetched files: {', '.join(repo_files[:5])}\n\n"
f"{file_contents[:5000]}"
)
t_map = Task(
description=f"{context}\n\nMap structure, dependencies, and key technologies.",
expected_output="Markdown summary: Structure | Frameworks | Key Files.",
agent_role="Repository Mapper",
)
t_review = Task(
description=f"{context}\n\nPerform a detailed review and suggest refactors.",
expected_output="Code review bullets grouped by improvement type.",
agent_role="Code Reviewer",
)
t_sec = Task(
description=f"{context}\n\nPerform security audit of visible files.",
expected_output="Table: Issue | Evidence | Risk | Fix.",
agent_role="Security Auditor",
)
t_doc = Task(
description=f"{context}\n\nExplain what this repo does and how to run it.",
expected_output="Architecture overview + Quickstart guide.",
agent_role="Documentation Explainer",
)
t_merge = Task(
description="Merge all reports into one well-structured Markdown file with title, TOC, and clear sections.",
expected_output="Final cohesive Markdown report.",
agent_role="Engineering Manager",
)
return t_map, t_review, t_sec, t_doc, t_merge
# ---------------------------------
# RUNNER
# ---------------------------------
def run_repo_review(repo_url: str, brief: str = "") -> str:
repo_mapper, reviewer, auditor, explainer, manager = make_agents(repo_url)
t_map, t_review, t_sec, t_doc, t_merge = make_tasks(repo_url, brief)
crew = Crew(
agents=[repo_mapper, reviewer, auditor, explainer], # manager excluded
tasks=[t_map, t_review, t_sec, t_doc, t_merge],
process=Process.hierarchical,
manager_agent=manager,
verbose=True,
)
result = crew.kickoff()
return str(result)