Skip to content

Rpatel/codebase snapshot #698

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

Merged
merged 9 commits into from
Feb 28, 2025
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: 6 additions & 5 deletions codegen-examples/examples/codegen_app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
########################################################################################################################

# Create the cg_app
cg = CodegenApp(name="codegen-test", repos=["codegen-sh/Kevin-s-Adventure-Game"])
cg = CodegenApp(name="codegen-test", repo="codegen-sh/Kevin-s-Adventure-Game")


@cg.slack.event("app_mention")
Expand All @@ -26,7 +26,7 @@ async def handle_mention(event: SlackEvent):

# Codebase
logger.info("[CODEBASE] Initializing codebase")
codebase = cg.get_codebase("codegen-sh/Kevin-s-Adventure-Game")
codebase = cg.get_codebase()

# Code Agent
logger.info("[CODE_AGENT] Initializing code agent")
Expand All @@ -43,7 +43,7 @@ async def handle_mention(event: SlackEvent):
def handle_pr(event: PullRequestLabeledEvent):
logger.info("PR labeled")
logger.info(f"PR head sha: {event.pull_request.head.sha}")
codebase = cg.get_codebase("codegen-sh/Kevin-s-Adventure-Game")
codebase = cg.get_codebase()

# =====[ Check out commit ]=====
# Might require fetch?
Expand All @@ -62,7 +62,7 @@ def handle_pr(event: PullRequestLabeledEvent):
@cg.linear.event("Issue")
def handle_issue(event: LinearEvent):
logger.info(f"Issue created: {event}")
codebase = cg.get_codebase("codegen-sh/Kevin-s-Adventure-Game")
codebase = cg.get_codebase()
return {"message": "Linear Issue event", "num_files": len(codebase.files), "num_functions": len(codebase.functions)}


Expand All @@ -74,7 +74,7 @@ def handle_issue(event: LinearEvent):

# For deploying local package
REPO_URL = "https://github.com/codegen-sh/codegen-sdk.git"
COMMIT_ID = "26dafad2c319968e14b90806d42c6c7aaa627bb0"
COMMIT_ID = "6a0e101718c247c01399c60b7abf301278a41786"

# Create the base image with dependencies
base_image = (
Expand All @@ -97,4 +97,5 @@ def handle_issue(event: LinearEvent):
@app.function(image=base_image, secrets=[modal.Secret.from_dotenv()])
@modal.asgi_app()
def fastapi_app():
print("Starting codegen fastapi app")
return cg.app
3 changes: 3 additions & 0 deletions codegen-examples/examples/codegen_app/codegen_app_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from app import app

app = app
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ANTHROPIC_API_KEY="..."
SLACK_BOT_TOKEN="..."
GITHUB_TOKEN="..."
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from event_handlers import app

app = app
135 changes: 135 additions & 0 deletions codegen-examples/examples/snapshot_event_handler/event_handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
from codegen.agents.code_agent import CodeAgent
from codegen.extensions.events.codegen_app import CodegenApp
from codegen.extensions.linear.types import LinearEvent
from codegen.extensions.slack.types import SlackEvent
from codegen.extensions.events.modal.base import CodebaseEventsApp, EventRouterMixin
from codegen.extensions.github.types.pull_request import PullRequestLabeledEvent
from pr_tasks import lint_for_dev_import_violations, review_with_codegen_agent
from typing import Literal
from dotenv import load_dotenv
from fastapi import FastAPI, Request
from classy_fastapi import Routable, post
import modal
import logging

load_dotenv(".env")


logging.basicConfig(level=logging.INFO, force=True)
logger = logging.getLogger(__name__)

codegen_events_app = modal.App("codegen-events-router")

SNAPSHOT_DICT_ID = "codegen-events-codebase-snapshots"


REPO_URL = "https://github.com/codegen-sh/codegen-sdk.git"
COMMIT_ID = "f398107d31bbd53fc77bc9c5f8763d2dc8fcae5b"

# Create the base image with dependencies
base_image = (
modal.Image.debian_slim(python_version="3.13")
.apt_install("git")
.pip_install(
# =====[ Codegen ]=====
# "codegen",
f"git+{REPO_URL}@{COMMIT_ID}",
# =====[ Rest ]=====
"openai>=1.1.0",
"fastapi[standard]",
"slack_sdk",
"classy-fastapi>=0.6.1",
)
)


event_handlers_app = modal.App("codegen-event-handlers")


@event_handlers_app.cls(image=base_image, secrets=[modal.Secret.from_dotenv(".env")], enable_memory_snapshot=True, container_idle_timeout=300)
class CustomEventHandlersAPI(CodebaseEventsApp):
commit: str = modal.parameter(default="79114f67ccfe8700416cd541d1c7c43659a95342")
repo_org: str = modal.parameter(default="codegen-sh")
repo_name: str = modal.parameter(default="Kevin-s-Adventure-Game")
snapshot_index_id: str = SNAPSHOT_DICT_ID

def setup_handlers(self, cg: CodegenApp):
@cg.slack.event("app_mention")
async def handle_mention(event: SlackEvent):
logger.info("[APP_MENTION] Received cg_app_mention event")

# Codebase
logger.info("[CODEBASE] Initializing codebase")
codebase = cg.get_codebase()

# Code Agent
logger.info("[CODE_AGENT] Initializing code agent")
agent = CodeAgent(codebase=codebase)

logger.info("[CODE_AGENT] Running code agent")
response = agent.run(event.text)

cg.slack.client.chat_postMessage(channel=event.channel, text=response, thread_ts=event.ts)

return {"message": "Mentioned", "received_text": event.text, "response": response}

@cg.github.event("pull_request:labeled")
def handle_pr(event: PullRequestLabeledEvent):
logger.info("PR labeled")
logger.info(f"PR head sha: {event.pull_request.head.sha}")

codebase = cg.get_codebase()
logger.info(f"Codebase: {codebase.name} codebase.repo: {codebase.repo_path}")

# =====[ Check out commit ]=====
# Might require fetch?
logger.info("> Checking out commit")
codebase.checkout(commit=event.pull_request.head.sha)

logger.info("> Running PR Lints")
# LINT CODEMOD
lint_for_dev_import_violations(codebase, event)

# REVIEW CODEMOD
review_with_codegen_agent(codebase, event)

return {"message": "PR event handled", "num_files": len(codebase.files), "num_functions": len(codebase.functions)}

@cg.linear.event("Issue")
def handle_issue(event: LinearEvent):
logger.info(f"Issue created: {event}")
codebase = cg.get_codebase()
return {"message": "Linear Issue event", "num_files": len(codebase.files), "num_functions": len(codebase.functions)}


@codegen_events_app.cls(image=base_image, secrets=[modal.Secret.from_dotenv(".env")])
class WebhookEventRouterAPI(EventRouterMixin, Routable):
snapshot_index_id: str = SNAPSHOT_DICT_ID

def get_event_handler_cls(self):
modal_cls = modal.Cls.from_name(app_name="Events", name="CustomEventHandlersAPI")
return modal_cls

@post("/{org}/{repo}/{provider}/events")
async def handle_event(self, org: str, repo: str, provider: Literal["slack", "github", "linear"], request: Request):
# Define the route for the webhook url sink, it will need to indicate the repo repo org, and the provider
return await super().handle_event(org, repo, provider, request)

@modal.asgi_app()
def api(self):
"""Run the FastAPI app with the Router."""
event_api = FastAPI()
route_view = WebhookEventRouterAPI()
event_api.include_router(route_view.router)
return event_api


# Setup a cron job to trigger updates to the codebase snapshots.
@codegen_events_app.function(schedule=modal.Cron("*/10 * * * *"), image=base_image, secrets=[modal.Secret.from_dotenv(".env")])
def refresh_repository_snapshots():
WebhookEventRouterAPI().refresh_repository_snapshots(snapshot_index_id=SNAPSHOT_DICT_ID)


app = modal.App("Events", secrets=[modal.Secret.from_dotenv(".env")])
app.include(event_handlers_app)
app.include(codegen_events_app)
78 changes: 78 additions & 0 deletions codegen-examples/examples/snapshot_event_handler/pr_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import logging
from codegen.agents.code_agent import CodeAgent
from codegen.extensions.github.types.pull_request import PullRequestLabeledEvent

from codegen.extensions.langchain.tools import GithubCreatePRCommentTool, GithubCreatePRReviewCommentTool, GithubViewPRTool
from codegen.sdk.core.codebase import Codebase

logging.basicConfig(level=logging.INFO, force=True)
logger = logging.getLogger(__name__)


def lint_for_dev_import_violations(codebase: Codebase, event: PullRequestLabeledEvent):
patch, commit_shas, modified_symbols = codebase.get_modified_symbols_in_pr(event.pull_request.number)
modified_files = set(commit_shas.keys())

DIR_NAME = "packages/next/src/client/components/react-dev-overlay"
directory = codebase.get_directory(DIR_NAME)

# Initialize a list to store all violations
violations = []

print("modified_files", modified_files)

# Check if directory exists before proceeding
if directory is not None and hasattr(directory, "files"):
for file in directory.files:
print("checking file", file.filepath)
for imp in file.inbound_imports:
print("file", imp.file.filepath)
print("checking import", imp.import_statement)
# Check if the import is from outside the directory and is in the modified files
if imp.file not in directory and imp.file.filepath in modified_files:
# Skip require statements
if "require" in imp.import_statement:
continue
violation = f"- Violation in `{file.filepath}`: Importing from `{imp.file.filepath}` ([link]({imp.github_url}))"
violations.append(violation)
logger.info(f"Found violation: {violation}")

# Only create a PR comment if violations are found
if violations:
review_attention_message = "## Dev Import Violations Found\n\n"
review_attention_message += "The following files have imports that violate development overlay rules:\n\n"
review_attention_message += "\n".join(violations)
review_attention_message += "\n\nPlease ensure that development imports are not imported in production code."

# Create PR comment with the formatted message
codebase._op.create_pr_comment(event.pull_request.number, review_attention_message)


def review_with_codegen_agent(codebase: Codebase, event: PullRequestLabeledEvent):
review_initial_message = "CodegenBot is starting to review the PR please wait..."
comment = codebase._op.create_pr_comment(event.number, review_initial_message)
# Define tools first
pr_tools = [
GithubViewPRTool(codebase),
GithubCreatePRCommentTool(codebase),
GithubCreatePRReviewCommentTool(codebase),
]

# Create agent with the defined tools
agent = CodeAgent(codebase=codebase, tools=pr_tools)

# Using a prompt from SWE Bench
prompt = f"""
Hey CodegenBot!

Here's a SWE task for you. Please Review this pull request!
{event.pull_request.url}
Do not terminate until have reviewed the pull request and are satisfied with your review.

Review this Pull request like the señor ingenier you are
be explicit about the changes, produce a short summary, and point out possible improvements where pressent dont be self congratulatory stick to the facts
use the tools at your disposal to create propper pr reviews include code snippets if needed, and suggest improvements if feel its necesary
"""
# Run the agent
agent.run(prompt)
comment.delete()
32 changes: 32 additions & 0 deletions codegen-examples/examples/snapshot_event_handler/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[project]
name = "codegen-examples"
version = "0.0.0"
readme = "README.md"
requires-python = ">=3.12, <3.14"
dependencies = [
"fastapi-utils>=0.8.0",
"fastapi[standard]>=0.115.9",
"modal>=0.73.72",
"fastapi-restful[all]>=0.6.0",
"classy-fastapi>=0.6.1",
"codegen@git+https://github.com/codegen-sh/codegen-sdk.git@f398107d31bbd53fc77bc9c5f8763d2dc8fcae5b",
]
license = { file = "LICENSE" }
classifiers = [
"License :: OSI Approved :: Apache Software License",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development",
"Development Status :: 4 - Beta",
"Environment :: MacOS X",
"Programming Language :: Python :: 3",
"Programming Language :: Python",
]

[tool.ruff]
line-length = 200
exclude = ["**/input_repo/**", "**/output_repo/**", "**/repositories/**"]

[tool.uv]
cache-keys = [{ git = { commit = true, tags = true } }]
Loading
Loading