Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scaffold of pr agent #359

Merged
merged 3 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion python/swe/swekit/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from composio.cli.utils.params import EnumParam, PathParam

from swekit.exceptions import SWEKitError
from swekit.scaffold import AgenticFramework, scaffold
from swekit.scaffold import AgentType, AgenticFramework, scaffold


@click.group(name="swekit")
Expand All @@ -30,18 +30,27 @@ def swekit() -> None:
type=PathParam(),
help="Output directory for the agent",
)
@click.option(
"-t",
"--type",
type=EnumParam(cls=AgentType),
help="Type of agent to scaffold, defaults to SWE",
default=AgentType.SWE,
)
@click.help_option("--help")
def _scaffold(
framework: AgenticFramework,
name: t.Optional[str] = None,
outdir: t.Optional[Path] = None,
agent_type: AgentType = AgentType.SWE,
) -> None:
"""🤖 Scaffold agent using composio toolset."""
try:
output = scaffold(
framework=framework,
name=name,
outdir=outdir,
agent_type=agent_type,
)
click.echo(f"🤖 Scaffolded agent @ {output}")
except SWEKitError as e:
Expand Down
3 changes: 2 additions & 1 deletion python/swe/swekit/scaffold/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Scaffolding Utilities."""

from ._scaffold import AgenticFramework, scaffold
from ._scaffold import AgentType, AgenticFramework, scaffold


__all__ = (
"AgenticFramework",
"AgentType",
"scaffold",
)
28 changes: 22 additions & 6 deletions python/swe/swekit/scaffold/_scaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,40 @@
from swekit.scaffold.templates import PATH as TEMPLATES_PATH


class AgentType(Enum):
"""Agent type."""

SWE = "swe"
PR_REVIEW = "pr_review"


class AgenticFramework(Enum):
"""Agent framework name."""

CREWAI = "crewai"
LLAMAINDEX = "llamaindex"

def load_templates(self) -> t.Dict:
def load_templates(self, agent_type: AgentType) -> t.Dict:
"""Load tempalte string."""
return {
file.name.replace(".template", ".py"): file.read_text(encoding="utf-8")
for file in (TEMPLATES_PATH / self.value).glob("*.template")
}
if agent_type == AgentType.SWE:
return {
file.name.replace(".template", ".py"): file.read_text(encoding="utf-8")
for file in (TEMPLATES_PATH / self.value).glob("*.template")
}
elif agent_type == AgentType.PR_REVIEW:
return {
file.name.replace(".template", ".py"): file.read_text(encoding="utf-8")
for file in (TEMPLATES_PATH / "pr_review" / self.value).glob(
"*.template"
)
}


def scaffold(
framework: AgenticFramework,
name: t.Optional[str] = None,
outdir: t.Optional[Path] = None,
agent_type: AgentType = AgentType.SWE,
) -> Path:
"""Scaffold agent using Composio tools."""
name = name or "agent"
Expand All @@ -38,7 +54,7 @@ def scaffold(
raise SWEKitError(f"Directory already exists @ {output}")
output.mkdir()

for file, template in framework.load_templates().items():
for file, template in framework.load_templates(agent_type).items():
(output / file).write_text(str(template), encoding="utf-8")

return output
100 changes: 100 additions & 0 deletions python/swe/swekit/scaffold/templates/pr_review/crewai/main.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import os
from dotenv import load_dotenv
from composio_openai import Action, ComposioToolSet
from crewai import Agent, Crew, Process, Task
from langchain_openai import ChatOpenAI

from composio.client.collections import TriggerEventData

load_dotenv()


# Initialize the ComposioToolSet
composio_toolset = ComposioToolSet()


# Define the tools
pr_agent_tools = composio_toolset.get_actions(
actions=[
Action.GITHUB_GET_CODE_CHANGES_IN_PR,
Action.GITHUB_PULLS_CREATE_REVIEW_COMMENT,
Action.GITHUB_ISSUES_CREATE,
Action.SLACKBOT_CHAT_POST_MESSAGE,
]
)

channel_id = os.getenv("CHANNEL_ID", "")
if channel_id == "":
channel_id = input("Enter Channel id:")
code_review_assistant_prompt = (
"""
You are an experienced code reviewer.
Your task is to review the provided file diff and give constructive feedback.

Follow these steps:
1. Identify if the file contains significant logic changes.
2. Summarize the changes in the diff in clear and concise English, within 100 words.
3. Provide actionable suggestions if there are any issues in the code.

Once you have decided on the changes, for any TODOs, create a Github issue.
And send the summary of the PR review to """
+ channel_id
+ """ channel on slack. Slack doesn't have markdown and so send a plain text message.
Also add the comprehensive review to the PR as a comment.
"""
)



# Initialize the language model
llm = ChatOpenAI(model="gpt-4o")

# Create CrewAI agent
code_reviewer = Agent(
role="Code Reviewer",
goal=system_goal,
backstory="You are an experienced software engineer with a keen eye for code quality and best practices.",
verbose=True,
allow_delegation=False,
tools=pr_agent_tools,
llm=llm,
)


# Create a task for the agent
def review_code_task(code_to_review):
return Task(
description=f"Review the following code changes and provide feedback: {code_to_review}",
agent=code_reviewer,
)


# Create the crew
code_review_crew = Crew(
agents=[code_reviewer], tasks=[], verbose=2, process=Process.sequential
)

print("Assistant is ready")

# Create a trigger listener
listener = composio_toolset.create_trigger_listener()


@listener.callback(filters={"trigger_name": "github_pull_request_event"})
def review_new_pr(event: TriggerEventData) -> None:
# Using the information from Trigger, execute the agent
code_to_review = str(event.payload)

# Create a new task for this specific code review
task = review_code_task(code_to_review)

# Add the task to the crew and execute
code_review_crew.tasks = [task]
result = code_review_crew.kickoff()

print("Review result:", result)


print("Listener started!")
print("Create a pr to get the review")
listener.listen()
Loading