From eb14984bcae25d8b46c5829c7691062860cf8ebf Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 12:32:12 -0800 Subject: [PATCH 01/10] . --- src/codegen/extensions/events/app.py | 7 ++- src/codegen/extensions/events/slack.py | 74 ++++++++++++++++++++++++++ src/codegen/integration.py | 39 ++++++++++++++ 3 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 src/codegen/extensions/events/slack.py create mode 100644 src/codegen/integration.py diff --git a/src/codegen/extensions/events/app.py b/src/codegen/extensions/events/app.py index 696a48377..b3a28d1ce 100644 --- a/src/codegen/extensions/events/app.py +++ b/src/codegen/extensions/events/app.py @@ -3,19 +3,22 @@ import modal # deptry: ignore from codegen.extensions.events.linear import Linear +from codegen.extensions.events.slack import Slack logger = logging.getLogger(__name__) class CodegenApp(modal.App): linear: Linear + slack: Slack - def __init__(self, name, modal_api_key, image: modal.Image): + def __init__(self, name, modal_api_key: str, image: modal.Image): self._modal_api_key = modal_api_key self._image = image self._name = name super().__init__(name=name, image=image) - # Expose a attribute that provides the event decorator for different providers. + # Expose attributes that provide event decorators for different providers. self.linear = Linear(self) + self.slack = Slack(self) diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py new file mode 100644 index 000000000..ad19c5540 --- /dev/null +++ b/src/codegen/extensions/events/slack.py @@ -0,0 +1,74 @@ +import functools +import logging +import os +from typing import Any, Callable + +import modal # deptry: ignore +from anthropic import BaseModel +from fastapi import FastAPI, Request +from slack_bolt import App +from slack_bolt.adapter.fastapi import SlackRequestHandler + +from codegen.extensions.events.interface import EventHandlerManagerProtocol + +logger = logging.getLogger(__name__) + + +class RegisteredEventHandler(BaseModel): + handler_func: Callable + + +class Slack(EventHandlerManagerProtocol): + def __init__(self, app: modal.App): + self.app = app + self.bot_token = os.environ["SLACK_BOT_TOKEN"] + self.signing_secret = os.environ["SLACK_SIGNING_SECRET"] + self.registered_handlers = {} + self.slack_app = App(token=self.bot_token, signing_secret=self.signing_secret) + self.handler = SlackRequestHandler(self.slack_app) + + def subscribe_handler_to_webhook(self, web_url: str, event_name: str): + # Slack doesn't require explicit webhook registration like Linear + # The events are handled through the Events API + pass + + def unsubscribe_handler_to_webhook(self, registered_handler: RegisteredEventHandler): + # Slack doesn't require explicit webhook unregistration + pass + + def unsubscribe_all_handlers(self): + self.registered_handlers.clear() + + def event(self, event_name: str): + """Decorator for registering a Slack event handler. + + :param event_name: The name of the Slack event to handle (e.g., 'app_mention', 'message', etc.) + """ + + def decorator(func): + # Register the handler with the app's registry + modal_ready_func = func + func_name = func.__qualname__ + + self.registered_handlers[func_name] = RegisteredEventHandler(handler_func=modal_ready_func) + + # Register the handler with Slack's event system + @self.slack_app.event(event_name) + @functools.wraps(func) + def wrapper(*args: Any, **kwargs: Any): + return func(*args, **kwargs) + + return wrapper + + return decorator + + def get_asgi_app(self) -> FastAPI: + """Get the FastAPI app for handling Slack events.""" + web_app = FastAPI() + + @web_app.post("/slack/events") + async def endpoint(request: Request): + """Handle Slack events and verify requests.""" + return await self.handler.handle(request) + + return web_app diff --git a/src/codegen/integration.py b/src/codegen/integration.py new file mode 100644 index 000000000..39eac1058 --- /dev/null +++ b/src/codegen/integration.py @@ -0,0 +1,39 @@ +"""Slack chatbot for answering questions about FastAPI using Codegen's VectorIndex.""" + +import os +from typing import Any + +import modal +from codegen import Codebase +from codegen.extensions.events.app import CodegenApp +from codegen.shared.enums.programming_language import ProgrammingLanguage +from fastapi import FastAPI, Request +import requests +from slack_bolt import App +from slack_bolt.adapter.fastapi import SlackRequestHandler +from logging import getLogger +from codegen.shared.performance.stopwatch_utils import stopwatch + +# ruff: noqa +from agents.simpe_rag import format_response, simple_rag + +from agents.simple_agent import convert_slack_to_langchain_messages, simple_agent +from images import base_image +import logging + +# set logging to info level +logging.basicConfig(level=logging.INFO) +logger = getLogger(__name__) + +######################################## +# MODAL +######################################## + +app = CodegenApp(name="slack", modal_api_key="", image=base_image) + + +@app.slack.event("app_mention") +def handle_mention(event: dict[str, Any], say: Any): + # Your event handling code here + print("=====[ EVENT ]=====") + print(event) From 9b9649dc273dc249ed7dccfe95b5f99d72d883c4 Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 14:51:14 -0800 Subject: [PATCH 02/10] . --- integration.py | 38 ++++++++++++++++++++++++++ pyproject.toml | 1 + src/codegen/extensions/events/slack.py | 21 ++++++-------- src/codegen/integration.py | 6 +--- uv.lock | 25 +++++++++++++++++ 5 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 integration.py diff --git a/integration.py b/integration.py new file mode 100644 index 000000000..3e2630365 --- /dev/null +++ b/integration.py @@ -0,0 +1,38 @@ +"""Slack chatbot for answering questions about FastAPI using Codegen's VectorIndex.""" + +import logging +from logging import getLogger +from typing import Any + +import modal # deptry: ignore + +from codegen.extensions.events.app import CodegenApp + +# set logging to info level +logging.basicConfig(level=logging.INFO) +logger = getLogger(__name__) + +######################################## +# MODAL +######################################## + +# Create image with dependencies + +image = ( + modal.Image.debian_slim(python_version="3.13") + .apt_install("git") + .pip_install( + "fastapi[standard]", + ) +) + +app = CodegenApp(name="slack", modal_api_key="", image=image) + + +@app.function() +@modal.web_endpoint(method="POST") +@app.slack.event("app_mention") +def handle_mention(event: dict[str, Any], say: Any): + # Your event handling code here + print("=====[ EVENT ]=====") + print(event) diff --git a/pyproject.toml b/pyproject.toml index 9691e960d..ef95ec1f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,7 @@ dependencies = [ "mcp[cli]", "neo4j", "modal>=0.73.45", + "slack-bolt>=1.22.0", ] license = { text = "Apache-2.0" } diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py index ad19c5540..0c88c7d06 100644 --- a/src/codegen/extensions/events/slack.py +++ b/src/codegen/extensions/events/slack.py @@ -4,8 +4,8 @@ from typing import Any, Callable import modal # deptry: ignore -from anthropic import BaseModel -from fastapi import FastAPI, Request +from fastapi import FastAPI +from pydantic import BaseModel from slack_bolt import App from slack_bolt.adapter.fastapi import SlackRequestHandler @@ -18,6 +18,10 @@ class RegisteredEventHandler(BaseModel): handler_func: Callable +# Global FastAPI app for handling Slack events +slack_web_app = FastAPI() + + class Slack(EventHandlerManagerProtocol): def __init__(self, app: modal.App): self.app = app @@ -55,8 +59,8 @@ def decorator(func): # Register the handler with Slack's event system @self.slack_app.event(event_name) @functools.wraps(func) - def wrapper(*args: Any, **kwargs: Any): - return func(*args, **kwargs) + def wrapper(event: dict[str, Any], say: Any): + return func(event, say) return wrapper @@ -64,11 +68,4 @@ def wrapper(*args: Any, **kwargs: Any): def get_asgi_app(self) -> FastAPI: """Get the FastAPI app for handling Slack events.""" - web_app = FastAPI() - - @web_app.post("/slack/events") - async def endpoint(request: Request): - """Handle Slack events and verify requests.""" - return await self.handler.handle(request) - - return web_app + return slack_web_app diff --git a/src/codegen/integration.py b/src/codegen/integration.py index 39eac1058..56ed74aff 100644 --- a/src/codegen/integration.py +++ b/src/codegen/integration.py @@ -15,10 +15,6 @@ from codegen.shared.performance.stopwatch_utils import stopwatch # ruff: noqa -from agents.simpe_rag import format_response, simple_rag - -from agents.simple_agent import convert_slack_to_langchain_messages, simple_agent -from images import base_image import logging # set logging to info level @@ -29,7 +25,7 @@ # MODAL ######################################## -app = CodegenApp(name="slack", modal_api_key="", image=base_image) +app = CodegenApp(name="slack", modal_api_key="") @app.slack.event("app_mention") diff --git a/uv.lock b/uv.lock index a081d8023..bfef81975 100644 --- a/uv.lock +++ b/uv.lock @@ -560,6 +560,7 @@ dependencies = [ { name = "lazy-object-proxy" }, { name = "mcp", extra = ["cli"] }, { name = "mini-racer" }, + { name = "modal" }, { name = "neo4j" }, { name = "networkx" }, { name = "numpy" }, @@ -585,6 +586,7 @@ dependencies = [ { name = "rich-click" }, { name = "rustworkx" }, { name = "sentry-sdk" }, + { name = "slack-bolt" }, { name = "starlette" }, { name = "tabulate" }, { name = "tenacity" }, @@ -681,6 +683,7 @@ requires-dist = [ { name = "lsprotocol", marker = "extra == 'lsp'", specifier = "==2024.0.0b1" }, { name = "mcp", extras = ["cli"] }, { name = "mini-racer", specifier = ">=0.12.4" }, + { name = "modal", specifier = ">=0.73.45" }, { name = "neo4j" }, { name = "networkx", specifier = ">=3.4.1" }, { name = "numpy", specifier = ">=2.2.2" }, @@ -707,6 +710,7 @@ requires-dist = [ { name = "rich-click", specifier = ">=1.8.5" }, { name = "rustworkx", specifier = ">=0.15.1" }, { name = "sentry-sdk", specifier = "==2.20.0" }, + { name = "slack-bolt" }, { name = "starlette", specifier = ">=0.16.0,<1.0.0" }, { name = "tabulate", specifier = ">=0.9.0,<1.0.0" }, { name = "tenacity", specifier = ">=9.0.0" }, @@ -3753,6 +3757,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] +[[package]] +name = "slack-bolt" +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "slack-sdk" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/c4/50b9009135d3189e0120692034f1ae95a2db695253517f14a3a3f12a5a3f/slack_bolt-1.22.0.tar.gz", hash = "sha256:b9c66d088fe3ec8bdd0494278eb500fe58092c2941de86d6822d00f4b3c7c88b", size = 130600 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/2d/fb23c998c43ff8398d7fa1e58bb82e7e735fbdaa0bd4ddaac04b3865bd4c/slack_bolt-1.22.0-py2.py3-none-any.whl", hash = "sha256:349097136a586617e5fb71f40f58a30fa847f664c598577f67a01f99faa1a9eb", size = 229675 }, +] + +[[package]] +name = "slack-sdk" +version = "3.34.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/ff/6eb67fd5bd179fa804dbd859d88d872d3ae343955e63a319a73a132d406f/slack_sdk-3.34.0.tar.gz", hash = "sha256:ff61db7012160eed742285ea91f11c72b7a38a6500a7f6c5335662b4bc6b853d", size = 233629 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/2d/8724ef191cb64907de1e4e4436462955501e00f859a53d0aa794d0d060ff/slack_sdk-3.34.0-py2.py3-none-any.whl", hash = "sha256:c61f57f310d85be83466db5a98ab6ae3bb2e5587437b54fa0daa8fae6a0feffa", size = 292480 }, +] + [[package]] name = "smmap" version = "5.0.2" From 3af83611f5c80c2b4710a057e98cfb63fd5c7371 Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 15:17:13 -0800 Subject: [PATCH 03/10] . --- integration.py | 12 ++++++++---- src/codegen/extensions/events/app.py | 11 ++++++++++- src/codegen/extensions/events/slack.py | 11 ++++++++++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/integration.py b/integration.py index 3e2630365..36ca29ebb 100644 --- a/integration.py +++ b/integration.py @@ -18,18 +18,22 @@ # Create image with dependencies -image = ( + +base_image = ( modal.Image.debian_slim(python_version="3.13") .apt_install("git") .pip_install( - "fastapi[standard]", + "slack-bolt>=1.18.0", + "openai>=1.1.0", + "git+https://github.com/codegen-sh/codegen-sdk.git@eb14984bcae25d8b46c5829c7691062860cf8ebf", ) ) -app = CodegenApp(name="slack", modal_api_key="", image=image) + +app = CodegenApp(name="slack", modal_api_key="", image=base_image) -@app.function() +@app.function(secrets=[modal.Secret.from_dotenv()]) @modal.web_endpoint(method="POST") @app.slack.event("app_mention") def handle_mention(event: dict[str, Any], say: Any): diff --git a/src/codegen/extensions/events/app.py b/src/codegen/extensions/events/app.py index b3a28d1ce..bef41c6d8 100644 --- a/src/codegen/extensions/events/app.py +++ b/src/codegen/extensions/events/app.py @@ -8,11 +8,20 @@ logger = logging.getLogger(__name__) +# Create base image that installs from specific git commit +def create_base_image(repo_url: str, commit_id: str) -> modal.Image: + """Create a base image with dependencies installed from a specific git commit.""" + return modal.Image.debian_slim().pip_install( + "slack-bolt>=1.18.0", + f"git+{repo_url}@{commit_id}", + ) + + class CodegenApp(modal.App): linear: Linear slack: Slack - def __init__(self, name, modal_api_key: str, image: modal.Image): + def __init__(self, name: str, modal_api_key: str, image: modal.Image): self._modal_api_key = modal_api_key self._image = image self._name = name diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py index 0c88c7d06..2dc3b9f1a 100644 --- a/src/codegen/extensions/events/slack.py +++ b/src/codegen/extensions/events/slack.py @@ -4,7 +4,7 @@ from typing import Any, Callable import modal # deptry: ignore -from fastapi import FastAPI +from fastapi import FastAPI, Request from pydantic import BaseModel from slack_bolt import App from slack_bolt.adapter.fastapi import SlackRequestHandler @@ -31,6 +31,15 @@ def __init__(self, app: modal.App): self.slack_app = App(token=self.bot_token, signing_secret=self.signing_secret) self.handler = SlackRequestHandler(self.slack_app) + # Add URL verification endpoint + @slack_web_app.post("/") + async def handle_verification(request: Request): + """Handle Slack URL verification challenge.""" + body = await request.json() + if body.get("type") == "url_verification": + return {"challenge": body["challenge"]} + return await self.handler.handle(request) + def subscribe_handler_to_webhook(self, web_url: str, event_name: str): # Slack doesn't require explicit webhook registration like Linear # The events are handled through the Events API From c3094415fdc8b84f7c9337930548448f115b4db5 Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 15:21:56 -0800 Subject: [PATCH 04/10] . --- integration.py | 2 +- src/codegen/extensions/events/slack.py | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/integration.py b/integration.py index 36ca29ebb..5f4efb7d7 100644 --- a/integration.py +++ b/integration.py @@ -25,7 +25,7 @@ .pip_install( "slack-bolt>=1.18.0", "openai>=1.1.0", - "git+https://github.com/codegen-sh/codegen-sdk.git@eb14984bcae25d8b46c5829c7691062860cf8ebf", + "git+https://github.com/codegen-sh/codegen-sdk.git@3af83611f5c80c2b4710a057e98cfb63fd5c7371", ) ) diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py index 2dc3b9f1a..dcaf746bb 100644 --- a/src/codegen/extensions/events/slack.py +++ b/src/codegen/extensions/events/slack.py @@ -1,7 +1,7 @@ import functools import logging import os -from typing import Any, Callable +from typing import Callable import modal # deptry: ignore from fastapi import FastAPI, Request @@ -35,10 +35,16 @@ def __init__(self, app: modal.App): @slack_web_app.post("/") async def handle_verification(request: Request): """Handle Slack URL verification challenge.""" - body = await request.json() - if body.get("type") == "url_verification": - return {"challenge": body["challenge"]} - return await self.handler.handle(request) + try: + body = await request.json() + # Handle URL verification + if body.get("type") == "url_verification": + return {"challenge": body.get("challenge")} + # Handle all other events + return await self.handler.handle(request) + except Exception as e: + logger.exception(f"Error handling request: {e}") + return {"error": str(e)} def subscribe_handler_to_webhook(self, web_url: str, event_name: str): # Slack doesn't require explicit webhook registration like Linear @@ -68,8 +74,8 @@ def decorator(func): # Register the handler with Slack's event system @self.slack_app.event(event_name) @functools.wraps(func) - def wrapper(event: dict[str, Any], say: Any): - return func(event, say) + def wrapper(*args, **kwargs): + return func(*args, **kwargs) return wrapper From ec7c998fed05fda22bbaf2462baf07023ff6f3a9 Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 15:42:27 -0800 Subject: [PATCH 05/10] . --- integration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration.py b/integration.py index 5f4efb7d7..d4135dc0d 100644 --- a/integration.py +++ b/integration.py @@ -25,7 +25,7 @@ .pip_install( "slack-bolt>=1.18.0", "openai>=1.1.0", - "git+https://github.com/codegen-sh/codegen-sdk.git@3af83611f5c80c2b4710a057e98cfb63fd5c7371", + "git+https://github.com/codegen-sh/codegen-sdk.git@c3094415fdc8b84f7c9337930548448f115b4db5", ) ) From cdb30e93f4c11b440cb293b9f9f5b1ab242052eb Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 17:38:37 -0800 Subject: [PATCH 06/10] . --- src/codegen/extensions/events/slack.py | 52 ++++++++++++++++++++++---- src/codegen/integration.py | 6 ++- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py index dcaf746bb..fae813cba 100644 --- a/src/codegen/extensions/events/slack.py +++ b/src/codegen/extensions/events/slack.py @@ -12,6 +12,7 @@ from codegen.extensions.events.interface import EventHandlerManagerProtocol logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) class RegisteredEventHandler(BaseModel): @@ -22,31 +23,62 @@ class RegisteredEventHandler(BaseModel): slack_web_app = FastAPI() +@slack_web_app.middleware("http") +async def log_requests(request: Request, call_next): + """Log all incoming requests.""" + logger.info(f"[MIDDLEWARE] Received request: {request.method} {request.url}") + try: + body = await request.body() + logger.info(f"[MIDDLEWARE] Request body: {body.decode()}") + except Exception as e: + logger.exception(f"[MIDDLEWARE] Error reading body: {e}") + response = await call_next(request) + logger.info(f"[MIDDLEWARE] Response status: {response.status_code}") + return response + + class Slack(EventHandlerManagerProtocol): def __init__(self, app: modal.App): + logger.info("[INIT] Initializing Slack handler") self.app = app self.bot_token = os.environ["SLACK_BOT_TOKEN"] self.signing_secret = os.environ["SLACK_SIGNING_SECRET"] self.registered_handlers = {} self.slack_app = App(token=self.bot_token, signing_secret=self.signing_secret) self.handler = SlackRequestHandler(self.slack_app) + logger.info("[INIT] Slack handler initialized") # Add URL verification endpoint @slack_web_app.post("/") async def handle_verification(request: Request): """Handle Slack URL verification challenge.""" + logger.info("[ENDPOINT] Received request at root endpoint") try: - body = await request.json() + # Log raw request details + logger.info(f"[ENDPOINT] Headers: {dict(request.headers)}") + body = await request.body() + logger.info(f"[ENDPOINT] Raw body: {body.decode()}") + + # Parse JSON + body_json = await request.json() + logger.info(f"[ENDPOINT] Parsed JSON body: {body_json}") + # Handle URL verification - if body.get("type") == "url_verification": - return {"challenge": body.get("challenge")} + if body_json.get("type") == "url_verification": + logger.info("[ENDPOINT] Handling URL verification") + challenge = body_json.get("challenge") + logger.info(f"[ENDPOINT] Challenge value: {challenge}") + return {"challenge": challenge} + # Handle all other events + logger.info("[ENDPOINT] Passing to Slack handler") return await self.handler.handle(request) except Exception as e: - logger.exception(f"Error handling request: {e}") + logger.exception(f"[ENDPOINT] Error handling request: {e}") return {"error": str(e)} def subscribe_handler_to_webhook(self, web_url: str, event_name: str): + logger.info(f"[WEBHOOK] Subscribing to {event_name} at {web_url}") # Slack doesn't require explicit webhook registration like Linear # The events are handled through the Events API pass @@ -56,18 +88,18 @@ def unsubscribe_handler_to_webhook(self, registered_handler: RegisteredEventHand pass def unsubscribe_all_handlers(self): + logger.info("[HANDLERS] Clearing all handlers") self.registered_handlers.clear() def event(self, event_name: str): - """Decorator for registering a Slack event handler. - - :param event_name: The name of the Slack event to handle (e.g., 'app_mention', 'message', etc.) - """ + """Decorator for registering a Slack event handler.""" + logger.info(f"[EVENT] Registering handler for {event_name}") def decorator(func): # Register the handler with the app's registry modal_ready_func = func func_name = func.__qualname__ + logger.info(f"[EVENT] Registering function {func_name} for {event_name}") self.registered_handlers[func_name] = RegisteredEventHandler(handler_func=modal_ready_func) @@ -75,6 +107,9 @@ def decorator(func): @self.slack_app.event(event_name) @functools.wraps(func) def wrapper(*args, **kwargs): + logger.info(f"[HANDLER] Executing handler {func_name}") + logger.info(f"[HANDLER] Args: {args}") + logger.info(f"[HANDLER] Kwargs: {kwargs}") return func(*args, **kwargs) return wrapper @@ -83,4 +118,5 @@ def wrapper(*args, **kwargs): def get_asgi_app(self) -> FastAPI: """Get the FastAPI app for handling Slack events.""" + logger.info("[APP] Getting ASGI app") return slack_web_app diff --git a/src/codegen/integration.py b/src/codegen/integration.py index 56ed74aff..86e5d61dc 100644 --- a/src/codegen/integration.py +++ b/src/codegen/integration.py @@ -18,18 +18,22 @@ import logging # set logging to info level -logging.basicConfig(level=logging.INFO) +logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = getLogger(__name__) ######################################## # MODAL ######################################## +logger.info("[INIT] Creating CodegenApp") app = CodegenApp(name="slack", modal_api_key="") +logger.info("[INIT] CodegenApp created") @app.slack.event("app_mention") def handle_mention(event: dict[str, Any], say: Any): + logger.info("[HANDLER] Received app_mention event") + logger.info(f"[HANDLER] Event data: {event}") # Your event handling code here print("=====[ EVENT ]=====") print(event) From 832349879e104c7f916a9bdf4b6accb0ec645063 Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 17:48:35 -0800 Subject: [PATCH 07/10] . --- integration.py | 2 +- src/codegen/extensions/events/slack.py | 35 +++++++++++++++++++++----- src/codegen/integration.py | 16 +++++++++++- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/integration.py b/integration.py index d4135dc0d..c36dc02f3 100644 --- a/integration.py +++ b/integration.py @@ -25,7 +25,7 @@ .pip_install( "slack-bolt>=1.18.0", "openai>=1.1.0", - "git+https://github.com/codegen-sh/codegen-sdk.git@c3094415fdc8b84f7c9337930548448f115b4db5", + "git+https://github.com/codegen-sh/codegen-sdk.git@cdb30e93f4c11b440cb293b9f9f5b1ab242052eb", ) ) diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py index fae813cba..4f24146d5 100644 --- a/src/codegen/extensions/events/slack.py +++ b/src/codegen/extensions/events/slack.py @@ -4,7 +4,9 @@ from typing import Callable import modal # deptry: ignore -from fastapi import FastAPI, Request +from fastapi import FastAPI, HTTPException, Request +from fastapi.exceptions import RequestValidationError +from fastapi.responses import JSONResponse from pydantic import BaseModel from slack_bolt import App from slack_bolt.adapter.fastapi import SlackRequestHandler @@ -37,6 +39,26 @@ async def log_requests(request: Request, call_next): return response +@slack_web_app.exception_handler(RequestValidationError) +async def validation_exception_handler(request: Request, exc: RequestValidationError): + """Handle validation errors.""" + logger.error(f"[ERROR] Validation error: {exc.errors()}") + return JSONResponse( + status_code=422, + content={"detail": exc.errors(), "body": exc.body}, + ) + + +@slack_web_app.exception_handler(Exception) +async def general_exception_handler(request: Request, exc: Exception): + """Handle all other exceptions.""" + logger.error(f"[ERROR] Unhandled exception: {exc}") + return JSONResponse( + status_code=500, + content={"detail": str(exc)}, + ) + + class Slack(EventHandlerManagerProtocol): def __init__(self, app: modal.App): logger.info("[INIT] Initializing Slack handler") @@ -48,11 +70,12 @@ def __init__(self, app: modal.App): self.handler = SlackRequestHandler(self.slack_app) logger.info("[INIT] Slack handler initialized") - # Add URL verification endpoint + # Add handlers for both root and /slack/events paths @slack_web_app.post("/") - async def handle_verification(request: Request): - """Handle Slack URL verification challenge.""" - logger.info("[ENDPOINT] Received request at root endpoint") + @slack_web_app.post("/slack/events") + async def handle_slack_events(request: Request): + """Handle all Slack events including verification.""" + logger.info("[ENDPOINT] Received request") try: # Log raw request details logger.info(f"[ENDPOINT] Headers: {dict(request.headers)}") @@ -75,7 +98,7 @@ async def handle_verification(request: Request): return await self.handler.handle(request) except Exception as e: logger.exception(f"[ENDPOINT] Error handling request: {e}") - return {"error": str(e)} + raise HTTPException(status_code=500, detail=str(e)) def subscribe_handler_to_webhook(self, web_url: str, event_name: str): logger.info(f"[WEBHOOK] Subscribing to {event_name} at {web_url}") diff --git a/src/codegen/integration.py b/src/codegen/integration.py index 86e5d61dc..cfa58a0b5 100644 --- a/src/codegen/integration.py +++ b/src/codegen/integration.py @@ -21,12 +21,26 @@ logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = getLogger(__name__) +######################################## +# IMAGE +######################################## + +base_image = ( + modal.Image.debian_slim(python_version="3.13") + .apt_install("git") + .pip_install( + "slack-bolt>=1.18.0", + "openai>=1.1.0", + "git+https://github.com/codegen-sh/codegen-sdk.git@cdb30e93f4c11b440cb293b9f9f5b1ab242052eb", + ) +) + ######################################## # MODAL ######################################## logger.info("[INIT] Creating CodegenApp") -app = CodegenApp(name="slack", modal_api_key="") +app = CodegenApp(name="slack", modal_api_key="", image=base_image) logger.info("[INIT] CodegenApp created") From 33792651fdbdb456ebd33a1dc09d74060e2755ab Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 19:11:17 -0800 Subject: [PATCH 08/10] . --- integration.py | 31 +++--- pyproject.toml | 1 - src/codegen/extensions/events/slack.py | 129 +++++++------------------ src/codegen/integration.py | 53 ---------- uv.lock | 2 +- 5 files changed, 51 insertions(+), 165 deletions(-) delete mode 100644 src/codegen/integration.py diff --git a/integration.py b/integration.py index c36dc02f3..80be90d4d 100644 --- a/integration.py +++ b/integration.py @@ -2,41 +2,44 @@ import logging from logging import getLogger -from typing import Any -import modal # deptry: ignore +import modal from codegen.extensions.events.app import CodegenApp # set logging to info level -logging.basicConfig(level=logging.INFO) +logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = getLogger(__name__) ######################################## -# MODAL +# IMAGE ######################################## -# Create image with dependencies - +REPO_URL = "https://github.com/codegen-sh/codegen-sdk.git" +COMMIT_ID = "abc123" # Replace with actual commit ID +# Create the base image with dependencies base_image = ( modal.Image.debian_slim(python_version="3.13") .apt_install("git") .pip_install( - "slack-bolt>=1.18.0", "openai>=1.1.0", - "git+https://github.com/codegen-sh/codegen-sdk.git@cdb30e93f4c11b440cb293b9f9f5b1ab242052eb", + "fastapi[standard]", + f"git+{REPO_URL}@{COMMIT_ID}", ) ) +######################################## +# MODAL +######################################## +logger.info("[INIT] Creating CodegenApp") app = CodegenApp(name="slack", modal_api_key="", image=base_image) +logger.info("[INIT] CodegenApp created") -@app.function(secrets=[modal.Secret.from_dotenv()]) -@modal.web_endpoint(method="POST") @app.slack.event("app_mention") -def handle_mention(event: dict[str, Any], say: Any): - # Your event handling code here - print("=====[ EVENT ]=====") - print(event) +def handle_mention(event: dict): + logger.info("[HANDLER] Received app_mention event") + logger.info(f"[HANDLER] Event data: {event}") + return {"message": "Event handled successfully"} diff --git a/pyproject.toml b/pyproject.toml index ef95ec1f4..9691e960d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,7 +71,6 @@ dependencies = [ "mcp[cli]", "neo4j", "modal>=0.73.45", - "slack-bolt>=1.22.0", ] license = { text = "Apache-2.0" } diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py index 4f24146d5..8de9f6a90 100644 --- a/src/codegen/extensions/events/slack.py +++ b/src/codegen/extensions/events/slack.py @@ -1,15 +1,8 @@ -import functools import logging -import os from typing import Callable import modal # deptry: ignore -from fastapi import FastAPI, HTTPException, Request -from fastapi.exceptions import RequestValidationError -from fastapi.responses import JSONResponse -from pydantic import BaseModel -from slack_bolt import App -from slack_bolt.adapter.fastapi import SlackRequestHandler +from pydantic import BaseModel, Field from codegen.extensions.events.interface import EventHandlerManagerProtocol @@ -17,93 +10,32 @@ logger.setLevel(logging.DEBUG) -class RegisteredEventHandler(BaseModel): - handler_func: Callable - - -# Global FastAPI app for handling Slack events -slack_web_app = FastAPI() - +class SlackWebhookPayload(BaseModel): + token: str | None = Field(None) + team_id: str | None = Field(None) + api_app_id: str | None = Field(None) + event: dict | None = Field(None) + type: str | None = Field(None) + event_id: str | None = Field(None) + event_time: int | None = Field(None) + challenge: str | None = Field(None) + subtype: str | None = Field(None) -@slack_web_app.middleware("http") -async def log_requests(request: Request, call_next): - """Log all incoming requests.""" - logger.info(f"[MIDDLEWARE] Received request: {request.method} {request.url}") - try: - body = await request.body() - logger.info(f"[MIDDLEWARE] Request body: {body.decode()}") - except Exception as e: - logger.exception(f"[MIDDLEWARE] Error reading body: {e}") - response = await call_next(request) - logger.info(f"[MIDDLEWARE] Response status: {response.status_code}") - return response - -@slack_web_app.exception_handler(RequestValidationError) -async def validation_exception_handler(request: Request, exc: RequestValidationError): - """Handle validation errors.""" - logger.error(f"[ERROR] Validation error: {exc.errors()}") - return JSONResponse( - status_code=422, - content={"detail": exc.errors(), "body": exc.body}, - ) - - -@slack_web_app.exception_handler(Exception) -async def general_exception_handler(request: Request, exc: Exception): - """Handle all other exceptions.""" - logger.error(f"[ERROR] Unhandled exception: {exc}") - return JSONResponse( - status_code=500, - content={"detail": str(exc)}, - ) +class RegisteredEventHandler(BaseModel): + handler_func: Callable class Slack(EventHandlerManagerProtocol): def __init__(self, app: modal.App): logger.info("[INIT] Initializing Slack handler") self.app = app - self.bot_token = os.environ["SLACK_BOT_TOKEN"] - self.signing_secret = os.environ["SLACK_SIGNING_SECRET"] self.registered_handlers = {} - self.slack_app = App(token=self.bot_token, signing_secret=self.signing_secret) - self.handler = SlackRequestHandler(self.slack_app) logger.info("[INIT] Slack handler initialized") - # Add handlers for both root and /slack/events paths - @slack_web_app.post("/") - @slack_web_app.post("/slack/events") - async def handle_slack_events(request: Request): - """Handle all Slack events including verification.""" - logger.info("[ENDPOINT] Received request") - try: - # Log raw request details - logger.info(f"[ENDPOINT] Headers: {dict(request.headers)}") - body = await request.body() - logger.info(f"[ENDPOINT] Raw body: {body.decode()}") - - # Parse JSON - body_json = await request.json() - logger.info(f"[ENDPOINT] Parsed JSON body: {body_json}") - - # Handle URL verification - if body_json.get("type") == "url_verification": - logger.info("[ENDPOINT] Handling URL verification") - challenge = body_json.get("challenge") - logger.info(f"[ENDPOINT] Challenge value: {challenge}") - return {"challenge": challenge} - - # Handle all other events - logger.info("[ENDPOINT] Passing to Slack handler") - return await self.handler.handle(request) - except Exception as e: - logger.exception(f"[ENDPOINT] Error handling request: {e}") - raise HTTPException(status_code=500, detail=str(e)) - def subscribe_handler_to_webhook(self, web_url: str, event_name: str): logger.info(f"[WEBHOOK] Subscribing to {event_name} at {web_url}") - # Slack doesn't require explicit webhook registration like Linear - # The events are handled through the Events API + # Slack doesn't require explicit webhook registration pass def unsubscribe_handler_to_webhook(self, registered_handler: RegisteredEventHandler): @@ -126,20 +58,25 @@ def decorator(func): self.registered_handlers[func_name] = RegisteredEventHandler(handler_func=modal_ready_func) - # Register the handler with Slack's event system - @self.slack_app.event(event_name) - @functools.wraps(func) - def wrapper(*args, **kwargs): - logger.info(f"[HANDLER] Executing handler {func_name}") - logger.info(f"[HANDLER] Args: {args}") - logger.info(f"[HANDLER] Kwargs: {kwargs}") - return func(*args, **kwargs) + # Create the web endpoint for this handler + @self.app.function(secrets=[modal.Secret.from_dotenv()]) + @modal.web_endpoint(method="POST") + def handle_webhook(event: SlackWebhookPayload): + logger.info(f"[HANDLER] Received Slack event type: {event.type}") - return wrapper + # Handle URL verification + if event.type == "url_verification": + logger.info("[HANDLER] Handling URL verification") + return {"challenge": event.challenge} - return decorator + # Handle actual events + elif event.type == "event_callback": + if event.event and event.event.get("type") == event_name: + logger.info(f"[HANDLER] Handling {event_name} event") + return func(event.event) + + return {"message": "Event received but not handled"} - def get_asgi_app(self) -> FastAPI: - """Get the FastAPI app for handling Slack events.""" - logger.info("[APP] Getting ASGI app") - return slack_web_app + return handle_webhook + + return decorator diff --git a/src/codegen/integration.py b/src/codegen/integration.py deleted file mode 100644 index cfa58a0b5..000000000 --- a/src/codegen/integration.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Slack chatbot for answering questions about FastAPI using Codegen's VectorIndex.""" - -import os -from typing import Any - -import modal -from codegen import Codebase -from codegen.extensions.events.app import CodegenApp -from codegen.shared.enums.programming_language import ProgrammingLanguage -from fastapi import FastAPI, Request -import requests -from slack_bolt import App -from slack_bolt.adapter.fastapi import SlackRequestHandler -from logging import getLogger -from codegen.shared.performance.stopwatch_utils import stopwatch - -# ruff: noqa -import logging - -# set logging to info level -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") -logger = getLogger(__name__) - -######################################## -# IMAGE -######################################## - -base_image = ( - modal.Image.debian_slim(python_version="3.13") - .apt_install("git") - .pip_install( - "slack-bolt>=1.18.0", - "openai>=1.1.0", - "git+https://github.com/codegen-sh/codegen-sdk.git@cdb30e93f4c11b440cb293b9f9f5b1ab242052eb", - ) -) - -######################################## -# MODAL -######################################## - -logger.info("[INIT] Creating CodegenApp") -app = CodegenApp(name="slack", modal_api_key="", image=base_image) -logger.info("[INIT] CodegenApp created") - - -@app.slack.event("app_mention") -def handle_mention(event: dict[str, Any], say: Any): - logger.info("[HANDLER] Received app_mention event") - logger.info(f"[HANDLER] Event data: {event}") - # Your event handling code here - print("=====[ EVENT ]=====") - print(event) diff --git a/uv.lock b/uv.lock index bfef81975..52d5446c7 100644 --- a/uv.lock +++ b/uv.lock @@ -710,7 +710,7 @@ requires-dist = [ { name = "rich-click", specifier = ">=1.8.5" }, { name = "rustworkx", specifier = ">=0.15.1" }, { name = "sentry-sdk", specifier = "==2.20.0" }, - { name = "slack-bolt" }, + { name = "slack-bolt", specifier = ">=1.22.0" }, { name = "starlette", specifier = ">=0.16.0,<1.0.0" }, { name = "tabulate", specifier = ">=0.9.0,<1.0.0" }, { name = "tenacity", specifier = ">=9.0.0" }, From e86ac32d2082a3dae5ceef0ec98327dc704c2c69 Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 21:10:09 -0800 Subject: [PATCH 09/10] . --- integration.py | 45 ----------- pyproject.toml | 1 + src/codegen/extensions/events/app.py | 2 +- src/codegen/extensions/events/slack.py | 106 +++++++++++++++---------- uv.lock | 24 +----- 5 files changed, 66 insertions(+), 112 deletions(-) delete mode 100644 integration.py diff --git a/integration.py b/integration.py deleted file mode 100644 index 80be90d4d..000000000 --- a/integration.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Slack chatbot for answering questions about FastAPI using Codegen's VectorIndex.""" - -import logging -from logging import getLogger - -import modal - -from codegen.extensions.events.app import CodegenApp - -# set logging to info level -logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") -logger = getLogger(__name__) - -######################################## -# IMAGE -######################################## - -REPO_URL = "https://github.com/codegen-sh/codegen-sdk.git" -COMMIT_ID = "abc123" # Replace with actual commit ID - -# Create the base image with dependencies -base_image = ( - modal.Image.debian_slim(python_version="3.13") - .apt_install("git") - .pip_install( - "openai>=1.1.0", - "fastapi[standard]", - f"git+{REPO_URL}@{COMMIT_ID}", - ) -) - -######################################## -# MODAL -######################################## - -logger.info("[INIT] Creating CodegenApp") -app = CodegenApp(name="slack", modal_api_key="", image=base_image) -logger.info("[INIT] CodegenApp created") - - -@app.slack.event("app_mention") -def handle_mention(event: dict): - logger.info("[HANDLER] Received app_mention event") - logger.info(f"[HANDLER] Event data: {event}") - return {"message": "Event handled successfully"} diff --git a/pyproject.toml b/pyproject.toml index 9691e960d..389d42452 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,7 @@ dependencies = [ "mcp[cli]", "neo4j", "modal>=0.73.45", + "slack-sdk", ] license = { text = "Apache-2.0" } diff --git a/src/codegen/extensions/events/app.py b/src/codegen/extensions/events/app.py index bef41c6d8..0d1d7b166 100644 --- a/src/codegen/extensions/events/app.py +++ b/src/codegen/extensions/events/app.py @@ -30,4 +30,4 @@ def __init__(self, name: str, modal_api_key: str, image: modal.Image): # Expose attributes that provide event decorators for different providers. self.linear = Linear(self) - self.slack = Slack(self) + self.slack = Slack() diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py index 8de9f6a90..8015de509 100644 --- a/src/codegen/extensions/events/slack.py +++ b/src/codegen/extensions/events/slack.py @@ -1,8 +1,9 @@ import logging -from typing import Callable +import os +from typing import Literal -import modal # deptry: ignore from pydantic import BaseModel, Field +from slack_sdk import WebClient from codegen.extensions.events.interface import EventHandlerManagerProtocol @@ -10,11 +11,40 @@ logger.setLevel(logging.DEBUG) +class RichTextElement(BaseModel): + type: str + user_id: str | None = None + text: str | None = None + + +class RichTextSection(BaseModel): + type: Literal["rich_text_section"] + elements: list[RichTextElement] + + +class Block(BaseModel): + type: Literal["rich_text"] + block_id: str + elements: list[RichTextSection] + + +class SlackEvent(BaseModel): + user: str + type: str + ts: str + client_msg_id: str + text: str + team: str + blocks: list[Block] + channel: str + event_ts: str + + class SlackWebhookPayload(BaseModel): token: str | None = Field(None) team_id: str | None = Field(None) api_app_id: str | None = Field(None) - event: dict | None = Field(None) + event: SlackEvent | None = Field(None) type: str | None = Field(None) event_id: str | None = Field(None) event_time: int | None = Field(None) @@ -22,61 +52,51 @@ class SlackWebhookPayload(BaseModel): subtype: str | None = Field(None) -class RegisteredEventHandler(BaseModel): - handler_func: Callable - - class Slack(EventHandlerManagerProtocol): - def __init__(self, app: modal.App): - logger.info("[INIT] Initializing Slack handler") - self.app = app - self.registered_handlers = {} - logger.info("[INIT] Slack handler initialized") + _client: WebClient | None = None - def subscribe_handler_to_webhook(self, web_url: str, event_name: str): - logger.info(f"[WEBHOOK] Subscribing to {event_name} at {web_url}") - # Slack doesn't require explicit webhook registration - pass + def __init__(self): + self.registered_handlers = {} - def unsubscribe_handler_to_webhook(self, registered_handler: RegisteredEventHandler): - # Slack doesn't require explicit webhook unregistration - pass + @property + def client(self) -> WebClient: + if not self._client: + self._client = WebClient(token=os.environ["SLACK_BOT_TOKEN"]) + return self._client def unsubscribe_all_handlers(self): logger.info("[HANDLERS] Clearing all handlers") self.registered_handlers.clear() + def handle(self, event: SlackWebhookPayload): + logger.info("[HANDLER] Handling Slack event") + if event.type == "url_verification": + return {"challenge": event.challenge} + elif event.type == "event_callback": + event = event.event + if event.type not in self.registered_handlers: + logger.info(f"[HANDLER] No handler found for event type: {event.type}") + return {"message": "Event handled successfully"} + else: + handler = self.registered_handlers[event.type] + return handler(event) + else: + logger.info(f"[HANDLER] No handler found for event type: {event.type}") + return {"message": "Event handled successfully"} + def event(self, event_name: str): """Decorator for registering a Slack event handler.""" logger.info(f"[EVENT] Registering handler for {event_name}") - def decorator(func): + def register_handler(func): # Register the handler with the app's registry - modal_ready_func = func func_name = func.__qualname__ logger.info(f"[EVENT] Registering function {func_name} for {event_name}") - self.registered_handlers[func_name] = RegisteredEventHandler(handler_func=modal_ready_func) - - # Create the web endpoint for this handler - @self.app.function(secrets=[modal.Secret.from_dotenv()]) - @modal.web_endpoint(method="POST") - def handle_webhook(event: SlackWebhookPayload): - logger.info(f"[HANDLER] Received Slack event type: {event.type}") - - # Handle URL verification - if event.type == "url_verification": - logger.info("[HANDLER] Handling URL verification") - return {"challenge": event.challenge} - - # Handle actual events - elif event.type == "event_callback": - if event.event and event.event.get("type") == event_name: - logger.info(f"[HANDLER] Handling {event_name} event") - return func(event.event) - - return {"message": "Event received but not handled"} + def new_func(event): + return func(self.client, event) - return handle_webhook + self.registered_handlers[event_name] = new_func + return new_func - return decorator + return register_handler diff --git a/uv.lock b/uv.lock index 52d5446c7..1c3235312 100644 --- a/uv.lock +++ b/uv.lock @@ -537,6 +537,7 @@ wheels = [ [[package]] name = "codegen" +version = "0.17.1.dev8+g33792651.d20250216" source = { editable = "." } dependencies = [ { name = "anthropic" }, @@ -586,7 +587,6 @@ dependencies = [ { name = "rich-click" }, { name = "rustworkx" }, { name = "sentry-sdk" }, - { name = "slack-bolt" }, { name = "starlette" }, { name = "tabulate" }, { name = "tenacity" }, @@ -710,7 +710,6 @@ requires-dist = [ { name = "rich-click", specifier = ">=1.8.5" }, { name = "rustworkx", specifier = ">=0.15.1" }, { name = "sentry-sdk", specifier = "==2.20.0" }, - { name = "slack-bolt", specifier = ">=1.22.0" }, { name = "starlette", specifier = ">=0.16.0,<1.0.0" }, { name = "tabulate", specifier = ">=0.9.0,<1.0.0" }, { name = "tenacity", specifier = ">=9.0.0" }, @@ -3757,27 +3756,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] -[[package]] -name = "slack-bolt" -version = "1.22.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "slack-sdk" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/68/c4/50b9009135d3189e0120692034f1ae95a2db695253517f14a3a3f12a5a3f/slack_bolt-1.22.0.tar.gz", hash = "sha256:b9c66d088fe3ec8bdd0494278eb500fe58092c2941de86d6822d00f4b3c7c88b", size = 130600 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/2d/fb23c998c43ff8398d7fa1e58bb82e7e735fbdaa0bd4ddaac04b3865bd4c/slack_bolt-1.22.0-py2.py3-none-any.whl", hash = "sha256:349097136a586617e5fb71f40f58a30fa847f664c598577f67a01f99faa1a9eb", size = 229675 }, -] - -[[package]] -name = "slack-sdk" -version = "3.34.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6e/ff/6eb67fd5bd179fa804dbd859d88d872d3ae343955e63a319a73a132d406f/slack_sdk-3.34.0.tar.gz", hash = "sha256:ff61db7012160eed742285ea91f11c72b7a38a6500a7f6c5335662b4bc6b853d", size = 233629 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/2d/8724ef191cb64907de1e4e4436462955501e00f859a53d0aa794d0d060ff/slack_sdk-3.34.0-py2.py3-none-any.whl", hash = "sha256:c61f57f310d85be83466db5a98ab6ae3bb2e5587437b54fa0daa8fae6a0feffa", size = 292480 }, -] - [[package]] name = "smmap" version = "5.0.2" From 744112ecd9dbf6b8f7aba3da13da64af0682f8ea Mon Sep 17 00:00:00 2001 From: jayhack Date: Sat, 15 Feb 2025 21:15:15 -0800 Subject: [PATCH 10/10] . --- src/codegen/extensions/events/app.py | 11 +---------- src/codegen/extensions/events/slack.py | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/codegen/extensions/events/app.py b/src/codegen/extensions/events/app.py index 0d1d7b166..3e004e366 100644 --- a/src/codegen/extensions/events/app.py +++ b/src/codegen/extensions/events/app.py @@ -8,15 +8,6 @@ logger = logging.getLogger(__name__) -# Create base image that installs from specific git commit -def create_base_image(repo_url: str, commit_id: str) -> modal.Image: - """Create a base image with dependencies installed from a specific git commit.""" - return modal.Image.debian_slim().pip_install( - "slack-bolt>=1.18.0", - f"git+{repo_url}@{commit_id}", - ) - - class CodegenApp(modal.App): linear: Linear slack: Slack @@ -30,4 +21,4 @@ def __init__(self, name: str, modal_api_key: str, image: modal.Image): # Expose attributes that provide event decorators for different providers. self.linear = Linear(self) - self.slack = Slack() + self.slack = Slack(self) diff --git a/src/codegen/extensions/events/slack.py b/src/codegen/extensions/events/slack.py index 8015de509..464d8e15b 100644 --- a/src/codegen/extensions/events/slack.py +++ b/src/codegen/extensions/events/slack.py @@ -55,7 +55,7 @@ class SlackWebhookPayload(BaseModel): class Slack(EventHandlerManagerProtocol): _client: WebClient | None = None - def __init__(self): + def __init__(self, app): self.registered_handlers = {} @property