CodeAgentbyCrewAi / agent.py
PraneshJs's picture
Update agent.py
4ec4b26 verified
Raw
History Blame Contribute Delete
6.36 kB
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)