CodeAgentbyCrewAi / agent.py
PraneshJs's picture
Update agent.py
c43538b verified
raw
history blame
7.01 kB
# agent.py
import os
from typing import Optional, List
from crewai import Agent, Task, Crew, Process
from crewai_tools import GithubSearchTool
from google import genai # Gemini client (google-genai package)
from dotenv import load_dotenv
load_dotenv()
# ---------------------------
# CONFIG
# ---------------------------
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
if not GOOGLE_API_KEY:
raise RuntimeError("❌ Missing GOOGLE_API_KEY (get one from https://aistudio.google.com)")
# Gemini Client
client = genai.Client(api_key=GOOGLE_API_KEY)
MODEL_NAME = os.getenv("GEMINI_MODEL", "gemini-1.5-flash")
DEFAULT_CONTENT_TYPES = ["code", "pr", "issue", "repo"]
# ---------------------------
# Gemini Embedding Adapter (Free Embeddings)
# ---------------------------
class GeminiEmbedding:
"""Uses Google Gemini text-embedding-004 model (free tier)"""
def __init__(self, model="text-embedding-004", api_key=None):
self.model = model
self.client = genai.Client(api_key=api_key or GOOGLE_API_KEY)
def embed_documents(self, texts: List[str]) -> List[List[float]]:
vectors = []
for text in texts:
try:
res = self.client.models.embed_content(model=self.model, contents=text)
vectors.append(res.embedding.values)
except Exception as e:
print(f"⚠️ Embedding error: {e}")
vectors.append([])
return vectors
def embed_query(self, text: str) -> List[float]:
try:
res = self.client.models.embed_content(model=self.model, contents=text)
return res.embedding.values
except Exception as e:
print(f"⚠️ Embedding query error: {e}")
return []
# ---------------------------
# Gemini LLM Wrapper
# ---------------------------
class GeminiLLM:
def __init__(self, model: str):
self.model = model
def generate(self, prompt: str) -> str:
"""CrewAI-compatible LLM generate method."""
try:
response = client.models.generate_content(
model=self.model,
contents=prompt,
generation_config={"temperature": 0.7, "max_output_tokens": 1024}
)
return response.text
except Exception as e:
return f"⚠️ Gemini API error: {e}"
# Instantiate LLM + embedder
gemini_llm = GeminiLLM(MODEL_NAME)
embedder = GeminiEmbedding(api_key=GOOGLE_API_KEY)
# ---------------------------
# GitHub Tool using free embeddings
# ---------------------------
def github_tool(repo_url: Optional[str] = None) -> GithubSearchTool:
"""Create a GitHub Search Tool with free Gemini embeddings (no OpenAI key)."""
if not GITHUB_TOKEN:
raise RuntimeError("Missing GITHUB_TOKEN in environment.")
if repo_url:
return GithubSearchTool(
github_repo=repo_url,
gh_token=GITHUB_TOKEN,
content_types=DEFAULT_CONTENT_TYPES,
embedder=embedder,
)
return GithubSearchTool(
gh_token=GITHUB_TOKEN,
content_types=DEFAULT_CONTENT_TYPES,
embedder=embedder,
)
# ---------------------------
# AGENTS
# ---------------------------
def make_agents(repo_url: str):
repo_search = github_tool(repo_url)
repo_mapper = Agent(
role="Repository Mapper",
goal="Map repo structure, dependencies, and frameworks.",
backstory="Understands directory trees, tech stacks, and configuration files.",
tools=[repo_search],
llm=gemini_llm,
verbose=True,
)
code_reviewer = Agent(
role="Code Reviewer",
goal="Perform code review for quality, structure, and clarity.",
backstory="A senior engineer giving actionable review comments with examples.",
tools=[repo_search],
llm=gemini_llm,
verbose=True,
)
security_auditor = Agent(
role="Security Auditor",
goal="Identify secrets, vulnerabilities, unsafe APIs, and dependencies.",
backstory="A white-hat hacker finding issues and giving fixes.",
tools=[repo_search],
llm=gemini_llm,
verbose=True,
)
doc_explainer = Agent(
role="Documentation Explainer",
goal="Summarize architecture, data flow, and how to run the project.",
backstory="Explains tech systems simply and clearly with examples.",
tools=[repo_search],
llm=gemini_llm,
verbose=True,
)
manager = Agent(
role="Engineering Manager",
goal="Coordinate all agents and compile a clear, cohesive final report.",
backstory="Ensures a professional, well-structured final document.",
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 = ""):
prefix = f"Target Repository: {repo_url}\nBrief: {brief}\nInclude file paths where relevant."
t_map = Task(
description=f"{prefix}\nMap the repository structure, dependencies, languages, and build tools.",
expected_output="Markdown-formatted repository map with bullets and paths.",
agent_role="Repository Mapper",
)
t_review = Task(
description=f"{prefix}\nPerform detailed code review (readability, refactors, testing, etc.).",
expected_output="Actionable review bullets grouped by issue type.",
agent_role="Code Reviewer",
)
t_sec = Task(
description=f"{prefix}\nPerform security audit (secrets, vulnerabilities, dependencies).",
expected_output="Security findings table (Issue | Evidence | Risk | Fix).",
agent_role="Security Auditor",
)
t_doc = Task(
description=f"{prefix}\nExplain architecture, modules, data flow, setup, and usage.",
expected_output="Readable explanation with Quickstart and architecture overview.",
agent_role="Documentation Explainer",
)
t_merge = Task(
description="Merge all outputs into a clean, single Markdown report with clear sections and TOC.",
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],
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)