From 63836518cc6335e4758943ec39a9fe1320d7c705 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Wed, 21 Jan 2026 02:25:42 +0530 Subject: [PATCH 01/14] Divided Devrai in 3 modes --- backend/app/api/__init__.py | 4 +- backend/app/api/router.py | 41 +++--- backend/app/api/v1/health.py | 54 +++++--- backend/app/core/config/settings.py | 82 ++++++++--- backend/app/database/supabase/client.py | 15 +- backend/integrations/discord/bot.py | 48 +++++-- backend/integrations/discord/cogs.py | 173 ++++++++++++++++++++---- backend/main.py | 130 +++++++++++++----- 8 files changed, 409 insertions(+), 138 deletions(-) diff --git a/backend/app/api/__init__.py b/backend/app/api/__init__.py index 75059e88..2c38c6ea 100644 --- a/backend/app/api/__init__.py +++ b/backend/app/api/__init__.py @@ -6,6 +6,6 @@ - v1: Version 1 API endpoints """ -from .router import api_router +from .router import core_router, get_auth_router -__all__ = ["api_router"] +__all__ = ["core_router", "get_auth_router"] diff --git a/backend/app/api/router.py b/backend/app/api/router.py index 67cd1e56..a4288257 100644 --- a/backend/app/api/router.py +++ b/backend/app/api/router.py @@ -1,26 +1,33 @@ from fastapi import APIRouter -from .v1.auth import router as auth_router from .v1.health import router as health_router -from .v1.integrations import router as integrations_router -api_router = APIRouter() - -api_router.include_router( - auth_router, - prefix="/v1/auth", - tags=["Authentication"] -) - -api_router.include_router( +core_router = APIRouter() +# -------- Core Router --------------- +core_router.include_router( health_router, prefix="/v1", tags=["Health"] ) -api_router.include_router( - integrations_router, - prefix="/v1/integrations", - tags=["Integrations"] -) +# -------- Auth router (OPTIONAL) -------- +auth_router= APIRouter() + +def get_auth_router() -> APIRouter: + router= APIRouter() + from .v1.auth import router as auth_router + from .v1.integrations import router as integrations_router + router.include_router( + auth_router, + prefix="/v1/auth", + tags=["Authentication"] + ) + + router.include_router( + integrations_router, + prefix="/v1/integrations", + tags=["Integrations"] + ) + + return router -__all__ = ["api_router"] +__all__ = ["core_router", "auth_router"] diff --git a/backend/app/api/v1/health.py b/backend/app/api/v1/health.py index a60ef0a5..38cf2afe 100644 --- a/backend/app/api/v1/health.py +++ b/backend/app/api/v1/health.py @@ -1,18 +1,13 @@ import logging -from fastapi import APIRouter, HTTPException, Depends -from app.database.weaviate.client import get_weaviate_client -from app.core.dependencies import get_app_instance -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from main import DevRAIApplication +from fastapi import APIRouter, HTTPException, Request +from app.core.config import settings router = APIRouter() logger = logging.getLogger(__name__) - +services={} @router.get("/health") -async def health_check(app_instance: "DevRAIApplication" = Depends(get_app_instance)): +async def health_check(request: Request): """ General health check endpoint to verify services are running. @@ -20,15 +15,18 @@ async def health_check(app_instance: "DevRAIApplication" = Depends(get_app_insta dict: Status of the application and its services """ try: - async with get_weaviate_client() as client: - weaviate_ready = await client.is_ready() + if settings.code_intelligence_enabled: + from app.database.weaviate.client import get_weaviate_client + async with get_weaviate_client() as client: + services["weaviate"] = ( + "ready" if await client.is_ready() else "not_ready" + ) + else: + services["weaviate"] = "disabled" return { "status": "healthy", - "services": { - "weaviate": "ready" if weaviate_ready else "not_ready", - "discord_bot": "running" if app_instance.discord_bot and not app_instance.discord_bot.is_closed() else "stopped" - } + "services": services, } except Exception as e: logger.error(f"Health check failed: {e}") @@ -45,8 +43,11 @@ async def health_check(app_instance: "DevRAIApplication" = Depends(get_app_insta async def weaviate_health(): """Check specifically Weaviate service health.""" try: - async with get_weaviate_client() as client: - is_ready = await client.is_ready() + is_ready = None + if settings.code_intelligence_enabled: + from app.database.weaviate.client import get_weaviate_client + async with get_weaviate_client() as client: + is_ready = await client.is_ready() return { "service": "weaviate", @@ -65,15 +66,24 @@ async def weaviate_health(): @router.get("/health/discord") -async def discord_health(app_instance: "DevRAIApplication" = Depends(get_app_instance)): +async def discord_health(request: Request): """Check specifically Discord bot health.""" try: - bot_status = "running" if app_instance.discord_bot and not app_instance.discord_bot.is_closed() else "stopped" - + app_instance = request.app.state.app_instance + + services = { + "discord_bot": ( + "running" + if app_instance.discord_bot + and not app_instance.discord_bot.is_closed() + else "stopped" + ) + } return { "service": "discord_bot", - "status": bot_status - } + "status": services + } + except Exception as e: logger.error(f"Discord bot health check failed: {e}") raise HTTPException( diff --git a/backend/app/core/config/settings.py b/backend/app/core/config/settings.py index 1349a02f..40e050ea 100644 --- a/backend/app/core/config/settings.py +++ b/backend/app/core/config/settings.py @@ -2,23 +2,29 @@ from dotenv import load_dotenv from pydantic import field_validator, ConfigDict from typing import Optional +import os load_dotenv() class Settings(BaseSettings): + ## CORE (minimal code) + backend_url: str ="" + + ## OPTIONAL + # Gemini LLM API Key - gemini_api_key: str = "" + gemini_api_key: Optional[str] = None # Tavily API Key - tavily_api_key: str = "" + tavily_api_key: Optional[str] = None # Platforms - github_token: str = "" - discord_bot_token: str = "" + github_token: Optional[str] = None + discord_bot_token: Optional[str] = None # DB configuration - supabase_url: str - supabase_key: str + supabase_url: Optional[str] = None + supabase_key: Optional[str] = None # LangSmith Tracing langsmith_tracing: bool = False @@ -36,23 +42,59 @@ class Settings(BaseSettings): # RabbitMQ configuration rabbitmq_url: Optional[str] = None - # Backend URL - backend_url: str = "" - # Onboarding UX toggles onboarding_show_oauth_button: bool = True - @field_validator("supabase_url", "supabase_key", mode="before") - @classmethod - def _not_empty(cls, v, field): - if not v: - raise ValueError(f"{field.name} must be set") - return v - - model_config = ConfigDict( - env_file=".env", - extra="ignore" - ) # to prevent errors from extra env variables + # @field_validator("supabase_url", "supabase_key", mode="before") + # @classmethod + # def _not_empty(cls, v, field): + # if not v: + # raise ValueError(f"{field.name} must be set") + # return v + + # model_config = ConfigDict( + # env_file=".env", + # extra="ignore" + # ) # to prevent errors from extra env variables + + # ------------------ + # Derived feature gates + # ------------------ + + @property + def discord_enabled(self) -> bool: + return bool(self.discord_bot_token) and bool(self.gemini_api_key) + + # @property + # def llm_enabled(self) -> bool: + # """ + # Gemini reasoning/chat for Discord. + # Explicitly tied to Discord + Gemini key. + # """ + # return self.discord_enabled and bool(self.gemini_api_key) + + @property + def github_enabled(self) -> bool: + """ + GitHub verification + OAuth. + """ + return self.discord_enabled and all([ + self.github_token, + self.supabase_url, + self.supabase_key, + ]) + + @property + def code_intelligence_enabled(self) -> bool: + """ + FalkorDB / GraphRAG / indexing. + """ + return self.github_enabled and all([ + os.getenv("FALKORDB_HOST"), + os.getenv("FALKORDB_PORT"), + os.getenv("CODEGRAPH_BACKEND_URL"), + os.getenv("CODEGRAPH_SECRET_TOKEN"), + ]) settings = Settings() diff --git a/backend/app/database/supabase/client.py b/backend/app/database/supabase/client.py index b0f5fa7c..14bad852 100644 --- a/backend/app/database/supabase/client.py +++ b/backend/app/database/supabase/client.py @@ -1,13 +1,18 @@ from app.core.config import settings from supabase._async.client import AsyncClient -supabase_client: AsyncClient = AsyncClient( - settings.supabase_url, - settings.supabase_key -) +_client: AsyncClient | None = None def get_supabase_client() -> AsyncClient: + global _client """ Returns a shared asynchronous Supabase client instance. """ - return supabase_client + if _client is None: + if not settings.supabase_url or not settings.supabase_key: + raise RuntimeError("Supabase is not configured") + _client = AsyncClient( + settings.supabase_url, + settings.supabase_key, + ) + return _client diff --git a/backend/integrations/discord/bot.py b/backend/integrations/discord/bot.py index dbb7c3a4..ec1e5e0b 100644 --- a/backend/integrations/discord/bot.py +++ b/backend/integrations/discord/bot.py @@ -1,16 +1,17 @@ import discord from discord.ext import commands import logging -from typing import Dict, Any, Optional -from app.core.orchestration.queue_manager import AsyncQueueManager, QueuePriority -from app.classification.classification_router import ClassificationRouter +from typing import Dict, Any, Optional,TYPE_CHECKING +from app.core.config import settings +if TYPE_CHECKING: + from app.core.orchestration.queue_manager import AsyncQueueManager, QueuePriority logger = logging.getLogger(__name__) class DiscordBot(commands.Bot): """Discord bot with LangGraph agent integration""" - def __init__(self, queue_manager: AsyncQueueManager, **kwargs): + def __init__(self, queue_manager: Optional["AsyncQueueManager"] = None, **kwargs): intents = discord.Intents.default() intents.message_content = True intents.guilds = True @@ -25,18 +26,29 @@ def __init__(self, queue_manager: AsyncQueueManager, **kwargs): ) self.queue_manager = queue_manager - self.classifier = ClassificationRouter() + self.classifier = None self.active_threads: Dict[str, str] = {} - self._register_queue_handlers() - - def _register_queue_handlers(self): - """Register handlers for queue messages""" - self.queue_manager.register_handler("discord_response", self._handle_agent_response) - + self._queue_handlers_registered = False + + def get_classifier(self): + if self.classifier is None: + from app.classification.classification_router import ClassificationRouter + self.classifier = ClassificationRouter() + return self.classifier + async def on_ready(self): """Bot ready event""" logger.info(f'Enhanced Discord bot logged in as {self.user}') print(f'Bot is ready! Logged in as {self.user}') + + if self.queue_manager and settings.code_intelligence_enabled: + if not self._queue_handlers_registered: + self.queue_manager.register_handler( + "discord_response", + self._handle_agent_response + ) + self._queue_handlers_registered = True + try: synced = await self.tree.sync() print(f"Synced {len(synced)} slash command(s)") @@ -48,11 +60,12 @@ async def on_message(self, message): if message.author == self.user: return - if message.interaction_metadata is not None: + # if message.interaction_metadata is not None: + if message.interaction is not None: return try: - triage_result = await self.classifier.should_process_message( + triage_result = await self.get_classifier().should_process_message( message.content, { "channel_id": str(message.channel.id), @@ -69,6 +82,13 @@ async def on_message(self, message): async def _handle_devrel_message(self, message, triage_result: Dict[str, Any]): """This now handles both new requests and follow-ups in threads.""" + if not self.queue_manager: + await message.channel.send( + "⚠️ Advanced processing is currently disabled. " + "I can still help with basic questions!" + ) + return + try: user_id = str(message.author.id) thread_id = await self._get_or_create_thread(message, user_id) @@ -142,4 +162,4 @@ async def _handle_agent_response(self, response_data: Dict[str, Any]): else: logger.error(f"Thread {thread_id} not found for agent response") except Exception as e: - logger.error(f"Error handling agent response: {str(e)}") + logger.error(f"Error handling agent response: {str(e)}") \ No newline at end of file diff --git a/backend/integrations/discord/cogs.py b/backend/integrations/discord/cogs.py index 64fd0b7f..d87e38d7 100644 --- a/backend/integrations/discord/cogs.py +++ b/backend/integrations/discord/cogs.py @@ -3,36 +3,83 @@ import discord from discord import app_commands from discord.ext import commands, tasks +from typing import Optional, TYPE_CHECKING -from app.agents.devrel.onboarding.messages import ( - build_encourage_verification_message, - build_new_user_welcome, - build_verified_capabilities_intro, - build_verified_welcome, -) from app.core.config import settings -from app.core.orchestration.queue_manager import AsyncQueueManager, QueuePriority -from app.services.auth.management import get_or_create_user_by_discord -from app.services.auth.supabase import login_with_github -from app.services.auth.verification import create_verification_session, cleanup_expired_tokens -from app.services.codegraph.repo_service import RepoService from integrations.discord.bot import DiscordBot -from integrations.discord.views import OAuthView, OnboardingView, build_final_handoff_embed + +if TYPE_CHECKING: + from app.core.orchestration.queue_manager import AsyncQueueManager logger = logging.getLogger(__name__) +# ---interactions---- +async def send_github_unavailable(interaction: discord.Interaction): + embed = discord.Embed( + title="❌ GitHub Verification Unavailable", + description=( + "GitHub verification is currently disabled on this server.\n\n" + "You can continue using other features, or try again later." + ), + color=discord.Color.red(), + ) + await interaction.followup.send(embed=embed, ephemeral=True) +async def falkor_unavailable(interaction: discord.Interaction): + embed = discord.Embed( + title="❌ Code Intelligence Unavailable", + description=( + "Repository indexing and code analysis are currently disabled.\n\n" + "**Possible reasons:**\n" + "• FalkorDB is not configured\n" + "• Background queue is disabled\n\n" + "You can still use basic DevRel and GitHub features." + ), + color=discord.Color.red(), + ) + + # Safe send (works whether deferred or not) + if interaction.response.is_done(): + await interaction.followup.send(embed=embed, ephemeral=True) + else: + await interaction.response.send_message(embed=embed, ephemeral=True) + +# ---- user dms ---- +async def send_github_unavailable_dm(user: discord.abc.User): + embed = discord.Embed( + title="🔒 GitHub Verification Disabled", + description=( + "GitHub account linking is currently unavailable.\n\n" + "**Why this may happen:**\n" + "• GitHub OAuth is not configured\n" + "• Supabase is disabled\n\n" + "You can still use the bot for general help and questions." + ), + color=discord.Color.orange(), + ) + + try: + await user.send(embed=embed) + except discord.Forbidden: + # User has DMs disabled — silently ignore + pass + except Exception as e: + logger.exception(f"Failed to send GitHub unavailable DM to {user}: {e}") + + class DevRelCommands(commands.Cog): - def __init__(self, bot: DiscordBot, queue_manager: AsyncQueueManager): + def __init__(self, bot: DiscordBot, queue_manager: Optional["AsyncQueueManager"] = None): self.bot = bot self.queue = queue_manager def cog_load(self): """Called when the cog is loaded""" - self.cleanup_expired_tokens.start() + if settings.github_enabled: + self.cleanup_expired_tokens.start() def cog_unload(self): - self.cleanup_expired_tokens.cancel() + if settings.github_enabled and self.cleanup_expired_tokens.is_running(): + self.cleanup_expired_tokens.cancel() @tasks.loop(minutes=5) async def cleanup_expired_tokens(self): @@ -58,32 +105,65 @@ async def reset_thread(self, interaction: discord.Interaction): "user_id": user_id, "cleanup_reason": "manual_reset" } - await self.queue.enqueue(cleanup, QueuePriority.HIGH) self.bot.active_threads.pop(user_id, None) - await interaction.response.send_message("Your DevRel thread & memory have been reset!", ephemeral=True) + + if self.queue: + from app.core.orchestration.queue_manager import QueuePriority + await self.queue.enqueue(cleanup, QueuePriority.HIGH) + + await interaction.response.send_message( + "Your DevRel thread has been reset!", + ephemeral=True, + ) @app_commands.command(name="help", description="Show DevRel assistant help.") async def help_devrel(self, interaction: discord.Interaction): embed = discord.Embed( title="DevRel Assistant Help", - description="I can help you with Devr.AI related questions!", + description="Available commands on this server:", color=discord.Color.blue() ) + embed.add_field( - name="Commands", + name="Basic", value=( "• `/reset` - Reset your DevRel thread and memory\n" - "• `/help` - Show this help message\n" - "• `/verify_github` - Link your GitHub account\n" - "• `/verification_status` - Check your verification status\n" + "• `/help` - Show this help message" ), inline=False ) + + if settings.github_enabled: + embed.add_field( + name="GitHub", + value=( + "• `/verify_github` - Link your GitHub account\n" + "• `/verification_status` - Check your verification status" + ), + inline=False + ) + if settings.code_intelligence_enabled: + embed.add_field( + name="Code Intelligence", + value=( + "• `/index_repository` - Index a GitHub repository\n" + "• `/delete_index` - Delete an indexed repository\n" + "• `/list_indexed_repos` - List your indexed repositories" + ), + inline=False + ) await interaction.response.send_message(embed=embed) @app_commands.command(name="verification_status", description="Check your GitHub verification status.") async def verification_status(self, interaction: discord.Interaction): + if not settings.github_enabled: + logger.info("Verification blocked: GitHub/Supabase not configured") + await send_github_unavailable(interaction) + return + + from integrations.discord.views import OAuthView, OnboardingView, build_final_handoff_embed + from app.services.auth.management import get_or_create_user_by_discord try: user_profile = await get_or_create_user_by_discord( discord_id=str(interaction.user.id), @@ -110,8 +190,17 @@ async def verification_status(self, interaction: discord.Interaction): @app_commands.command(name="verify_github", description="Link your GitHub account.") async def verify_github(self, interaction: discord.Interaction): + if not settings.github_enabled: + logger.info("Verification blocked: GitHub/Supabase not configured") + await send_github_unavailable(interaction) + return try: await interaction.response.defer(ephemeral=True) + + from integrations.discord.views import OAuthView, OnboardingView, build_final_handoff_embed + from app.services.auth.management import get_or_create_user_by_discord + from app.services.auth.supabase import login_with_github + from app.services.auth.verification import create_verification_session user_profile = await get_or_create_user_by_discord( discord_id=str(interaction.user.id), @@ -190,7 +279,14 @@ async def verify_github(self, interaction: discord.Interaction): @app_commands.describe(repository="GitHub URL or owner/repo (e.g., AOSSIE-Org/Devr.AI)") async def index_repository(self, interaction: discord.Interaction, repository: str): """Index a GitHub repository into FalkorDB code graph""" + if not settings.code_intelligence_enabled: + logger.info("Idexing blocked: FalkorDB not configured") + await falkor_unavailable(interaction) + return + await interaction.response.defer(thinking=True) + + from app.services.codegraph.repo_service import RepoService try: service = RepoService() @@ -317,8 +413,13 @@ async def _run_index_and_update(): @app_commands.describe(repository="Repository name (owner/repo)") async def delete_index(self, interaction: discord.Interaction, repository: str): """Delete a repository index""" + if not settings.code_intelligence_enabled(): + logger.info("Deletion of index blocked: FalkorDB not configured") + await falkor_unavailable(interaction) + return + await interaction.response.defer(thinking=True) - + from app.services.codegraph.repo_service import RepoService try: service = RepoService() logger.info(f"Delete request from {interaction.user.id}: {repository}") @@ -364,8 +465,14 @@ async def delete_index(self, interaction: discord.Interaction, repository: str): @app_commands.command(name="list_indexed_repos", description="List your indexed repositories") async def list_indexed_repos(self, interaction: discord.Interaction): """List user's indexed repositories""" + if not settings.code_intelligence_enabled: + logger.info("list indexed repo blocked: FalkorDB not configured") + await falkor_unavailable(interaction) + return + await interaction.response.defer() - + from app.services.codegraph.repo_service import RepoService + try: service = RepoService() repos = await service.list_repos(str(interaction.user.id)) @@ -398,7 +505,8 @@ async def list_indexed_repos(self, interaction: discord.Interaction): async def setup(bot: commands.Bot): """This function is called by the bot to load the cog.""" - await bot.add_cog(DevRelCommands(bot, bot.queue_manager)) + queue = getattr(bot, "queue_manager", None) + await bot.add_cog(DevRelCommands(bot, queue)) await bot.add_cog(OnboardingCog(bot)) @@ -458,7 +566,22 @@ async def _send_onboarding_flow(self, user: discord.abc.User) -> str: - "dm_forbidden": cannot DM the user - "error": unexpected error (fallback attempted) """ + if not settings.github_enabled: + logger.info("Verification blocked: GitHub/Supabase not configured") + await send_github_unavailable_dm(user) + return "auth_unavailable" try: + from app.agents.devrel.onboarding.messages import ( + build_encourage_verification_message, + build_new_user_welcome, + build_verified_capabilities_intro, + build_verified_welcome, + ) + from integrations.discord.views import OnboardingView, build_final_handoff_embed + + from app.services.auth.verification import create_verification_session + from app.services.auth.supabase import login_with_github + from app.services.auth.management import get_or_create_user_by_discord # Ensure DB record exists profile = await get_or_create_user_by_discord( discord_id=str(user.id), diff --git a/backend/main.py b/backend/main.py index b7ad80a6..5dc53c35 100644 --- a/backend/main.py +++ b/backend/main.py @@ -7,13 +7,11 @@ from fastapi import FastAPI, Response from fastapi.middleware.cors import CORSMiddleware -from app.api.router import api_router +from app.api.router import core_router, get_auth_router from app.core.config import settings -from app.core.orchestration.agent_coordinator import AgentCoordinator -from app.core.orchestration.queue_manager import AsyncQueueManager -from app.database.weaviate.client import get_weaviate_client -from integrations.discord.bot import DiscordBot -from discord.ext import commands +# if settings.code_intelligence_enabled: +# from app.core.orchestration.queue_manager import AsyncQueueManager +# from app.database.weaviate.client import get_weaviate_client # DevRel commands are now loaded dynamically (commented out below) # from integrations.discord.cogs import DevRelCommands @@ -32,30 +30,60 @@ class DevRAIApplication: def __init__(self): """Initializes all services required by the application.""" self.weaviate_client = None - self.queue_manager = AsyncQueueManager() - self.agent_coordinator = AgentCoordinator(self.queue_manager) - self.discord_bot = DiscordBot(self.queue_manager) + self.discord_bot = None + self.agent_coordinator = None + + # Discord always exists if enabled + if settings.discord_enabled: + from integrations.discord.bot import DiscordBot + from discord.ext import commands + self.discord_bot = DiscordBot(queue_manager=None) + + if settings.code_intelligence_enabled: + from app.core.orchestration.queue_manager import AsyncQueueManager + from app.database.weaviate.client import get_weaviate_client + from app.core.orchestration.agent_coordinator import AgentCoordinator + + self.queue_manager = AsyncQueueManager() + self.discord_bot= DiscordBot(self.queue_manager) + self.agent_coordinator = AgentCoordinator(self.queue_manager) async def start_background_tasks(self): - """Starts the Discord bot and queue workers in the background.""" + """Starts the background.""" try: - logger.info("Starting background tasks (Discord Bot & Queue Manager)...") - - await self.test_weaviate_connection() - - await self.queue_manager.start(num_workers=3) - - # --- Load commands inside the async startup function --- - try: - await self.discord_bot.load_extension("integrations.discord.cogs") - except (ImportError, commands.ExtensionError) as e: - logger.error("Failed to load Discord cog extension: %s", e) - - # Start the bot as a background task. - asyncio.create_task( - self.discord_bot.start(settings.discord_bot_token) - ) - logger.info("Background tasks started successfully!") + # Discord Mode + if settings.discord_enabled: + # 1. Start queue + if settings.code_intelligence_enabled: + await self.queue_manager.start(num_workers=3) + + # 2. Discord + try: + await self.discord_bot.load_extension("integrations.discord.cogs") + asyncio.create_task( + self.discord_bot.start(settings.discord_bot_token) + ) + except Exception as e: + logger.exception("Discord startup failed: %s",e) + self.discord_bot = None + + # Full Mode + if settings.code_intelligence_enabled: + # Weaviate + try: + await self.test_weaviate_connection() + except Exception as e: + logger.warning("Weaviate disabled: %s", e) + self.weaviate_enabled = False + + + logger.info( + "Background services ready | queue=%s weaviate=%s discord=%s", + bool(settings.rabbitmq_url), + self.weaviate_client, + bool(self.discord_bot), + ) + except Exception as e: logger.error(f"Error during background task startup: {e}", exc_info=True) await self.stop_background_tasks() @@ -63,6 +91,9 @@ async def start_background_tasks(self): async def test_weaviate_connection(self): """Test Weaviate connection during startup.""" + if not settings.code_intelligence_enabled: + logger.info("Weaviate Is for Full Mode") + return try: async with get_weaviate_client() as client: if await client.is_ready(): @@ -75,7 +106,7 @@ async def stop_background_tasks(self): """Stops all background tasks and connections gracefully.""" logger.info("Stopping background tasks and closing connections...") try: - if not self.discord_bot.is_closed(): + if settings.discord_enabled and not self.discord_bot.is_closed(): await self.discord_bot.close() logger.info("Discord bot has been closed.") except Exception as e: @@ -123,19 +154,52 @@ async def favicon(): """Return empty favicon to prevent 404 logs""" return Response(status_code=204) -api.include_router(api_router) +api.include_router(core_router) +if settings.github_enabled: + api.include_router(get_auth_router()) + if __name__ == "__main__": required_vars = [ - "DISCORD_BOT_TOKEN", "SUPABASE_URL", "SUPABASE_KEY", - "BACKEND_URL", "GEMINI_API_KEY", "TAVILY_API_KEY", "GITHUB_TOKEN" + "BACKEND_URL" ] + optional_vars = { + "supabase": ["SUPABASE_URL", "SUPABASE_KEY"], + "discord" : ["DISCORD_BOT_TOKEN"], + "llm":["GEMINI_API_KEY"], + "queue": ["RABBITMQ_URL"], + "search": ["TAVILY_API_KEY"], + "github": ["GITHUB_TOKEN"] + } missing_vars = [var for var in required_vars if not getattr(settings, var.lower(), None)] if missing_vars: - logger.error(f"Missing required environment variables: {', '.join(missing_vars)}") - sys.exit(1) + raise RuntimeError(f"Core backend misconfigured. Missing: {','.join(missing_vars)} ") + + capabilities = { + "discord_enabled": settings.discord_enabled, + "llm_enabled": bool(settings.gemini_api_key), + "github_enabled": settings.github_enabled, + "code_intelligence": settings.code_intelligence_enabled, + "search_enabled": bool(settings.tavily_api_key), + "queue_enabled": bool(settings.rabbitmq_url), + } + + if settings.code_intelligence_enabled: + mode = "full" + elif settings.github_enabled: + mode = "discord+github" + elif settings.discord_enabled: + mode = "discord" + else: + mode = "minimal" + + logger.info( + "Startup | mode=%s | capabilities=%s" , + mode, + {k: v for k, v in capabilities.items() if v}, + ) uvicorn.run( "__main__:api", From fbd04f3d2a441d67fde62f050642b23976b159f5 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Thu, 29 Jan 2026 19:46:10 +0530 Subject: [PATCH 02/14] Removed dead code --- backend/app/core/config/settings.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/backend/app/core/config/settings.py b/backend/app/core/config/settings.py index 40e050ea..376e0a84 100644 --- a/backend/app/core/config/settings.py +++ b/backend/app/core/config/settings.py @@ -65,14 +65,6 @@ class Settings(BaseSettings): def discord_enabled(self) -> bool: return bool(self.discord_bot_token) and bool(self.gemini_api_key) - # @property - # def llm_enabled(self) -> bool: - # """ - # Gemini reasoning/chat for Discord. - # Explicitly tied to Discord + Gemini key. - # """ - # return self.discord_enabled and bool(self.gemini_api_key) - @property def github_enabled(self) -> bool: """ From 95983d36f5ef6a047c8e72126f67b36f1126851a Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Thu, 29 Jan 2026 20:08:44 +0530 Subject: [PATCH 03/14] Removed comments --- backend/app/core/config/settings.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/backend/app/core/config/settings.py b/backend/app/core/config/settings.py index 376e0a84..77520945 100644 --- a/backend/app/core/config/settings.py +++ b/backend/app/core/config/settings.py @@ -44,19 +44,6 @@ class Settings(BaseSettings): # Onboarding UX toggles onboarding_show_oauth_button: bool = True - - # @field_validator("supabase_url", "supabase_key", mode="before") - # @classmethod - # def _not_empty(cls, v, field): - # if not v: - # raise ValueError(f"{field.name} must be set") - # return v - - # model_config = ConfigDict( - # env_file=".env", - # extra="ignore" - # ) # to prevent errors from extra env variables - # ------------------ # Derived feature gates # ------------------ From b890e67151ecf807583b099f3aac43483dea854f Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Fri, 30 Jan 2026 00:17:01 +0530 Subject: [PATCH 04/14] seperated discord msg handler and queuemanager --- backend/app/llm/chat.py | 22 ++++++++++++++++++++ backend/integrations/discord/bot.py | 31 +++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 backend/app/llm/chat.py diff --git a/backend/app/llm/chat.py b/backend/app/llm/chat.py new file mode 100644 index 00000000..49ada4ac --- /dev/null +++ b/backend/app/llm/chat.py @@ -0,0 +1,22 @@ +from langchain_google_genai import ChatGoogleGenerativeAI +from langchain_core.messages import HumanMessage +from app.core.config import settings + +async def chat_completion(prompt: str, context: dict | None = None) -> str: + """ + Stateless LLM chat used in discord-only mode. + No agents, no memory, no queue. + """ + # if not settings.llm_enabled: + # return "LLM responses are currently disabled." + + llm = ChatGoogleGenerativeAI( + model=settings.classification_agent_model, + temperature=0.7, + google_api_key=settings.gemini_api_key, + ) + + response = await llm.ainvoke( + [HumanMessage(content=prompt)] + ) + return response.content diff --git a/backend/integrations/discord/bot.py b/backend/integrations/discord/bot.py index ec1e5e0b..a65eb42b 100644 --- a/backend/integrations/discord/bot.py +++ b/backend/integrations/discord/bot.py @@ -79,14 +79,37 @@ async def on_message(self, message): except Exception as e: logger.error(f"Error processing message: {str(e)}") + + async def _handle_basic_discord_chat(self, message): + """ + Stateless Discord-only reply. + No classification, no memory, no queue, no agent. + """ + try: + from app.llm.chat import chat_completion # your LLM wrapper + + reply = await chat_completion( + message.content, + context={ + "platform": "discord", + "mode": "discord_only", + "user_id": str(message.author.id), + }, + ) + + await message.channel.send(reply) + except Exception as e: + logger.exception("Basic Discord-only chat failed") + await message.channel.send( + "Sorry — I had trouble answering that just now." + ) + + async def _handle_devrel_message(self, message, triage_result: Dict[str, Any]): """This now handles both new requests and follow-ups in threads.""" if not self.queue_manager: - await message.channel.send( - "⚠️ Advanced processing is currently disabled. " - "I can still help with basic questions!" - ) + await self._handle_basic_discord_chat(message) return try: From ffaae72c3ef983eea2245d933f5c0cfa6a1b07e4 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Fri, 30 Jan 2026 22:37:39 +0530 Subject: [PATCH 05/14] Divided discord and fullmode query handling --- backend/integrations/discord/bot.py | 82 ++++++++++++++++------------ backend/integrations/discord/cogs.py | 6 +- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/backend/integrations/discord/bot.py b/backend/integrations/discord/bot.py index a65eb42b..67dc15e1 100644 --- a/backend/integrations/discord/bot.py +++ b/backend/integrations/discord/bot.py @@ -80,42 +80,46 @@ async def on_message(self, message): except Exception as e: logger.error(f"Error processing message: {str(e)}") - async def _handle_basic_discord_chat(self, message): - """ - Stateless Discord-only reply. - No classification, no memory, no queue, no agent. - """ - try: - from app.llm.chat import chat_completion # your LLM wrapper + async def _handle_devrel_message(self, message, triage_result: Dict[str, Any]): + """This now handles both new requests and follow-ups in threads.""" + user_id = str(message.author.id) + thread_id = await self._get_or_create_thread(message, user_id) - reply = await chat_completion( - message.content, - context={ - "platform": "discord", - "mode": "discord_only", - "user_id": str(message.author.id), - }, - ) + # UX is shared + if thread_id: + thread = self.get_channel(int(thread_id)) + if thread: + await thread.send("I'm processing your request, please hold on...") - await message.channel.send(reply) + # 🔀 execution split + if self.queue_manager: + await self._handle_devrel_with_queue(message, triage_result, thread_id) + else: + await self._handle_devrel_direct(message, triage_result, thread_id) - except Exception as e: + async def _handle_devrel_direct(self,message, triage_result, thread_id): + try: + response = await self._basic_discord_response(message.content) + + if thread_id: + thread = self.get_channel(int(thread_id)) + if thread: + await thread.send(response) + else: + await message.channel.send(response) + + except Exception: logger.exception("Basic Discord-only chat failed") - await message.channel.send( - "Sorry — I had trouble answering that just now." + thread = self.get_channel(int(thread_id)) + await thread.send("Sorry, I ran into an issue answering that." ) - - async def _handle_devrel_message(self, message, triage_result: Dict[str, Any]): - """This now handles both new requests and follow-ups in threads.""" - if not self.queue_manager: - await self._handle_basic_discord_chat(message) - return - + async def _handle_devrel_with_queue(self, message, triage_result, thread_id): try: + from app.core.orchestration.queue_manager import QueuePriority + user_id = str(message.author.id) - thread_id = await self._get_or_create_thread(message, user_id) - + agent_message = { "type": "devrel_request", "id": f"discord_{message.id}", @@ -141,13 +145,6 @@ async def _handle_devrel_message(self, message, triage_result: Dict[str, Any]): priority = priority_map.get(triage_result.get("priority"), QueuePriority.MEDIUM) await self.queue_manager.enqueue(agent_message, priority) - # --- "PROCESSING" MESSAGE RESTORED --- - if thread_id: - thread = self.get_channel(int(thread_id)) - if thread: - await thread.send("I'm processing your request, please hold on...") - # ------------------------------------ - except Exception as e: logger.error(f"Error handling DevRel message: {str(e)}") @@ -171,7 +168,22 @@ async def _get_or_create_thread(self, message, user_id: str) -> Optional[str]: except Exception as e: logger.error(f"Failed to create thread: {e}") return str(message.channel.id) + + async def _basic_discord_response(self, content: str) -> str: + """ + Stateless Discord-only reply. + No memory, no queue, no agent. + """ + from app.llm.chat import chat_completion + return await chat_completion( + content, + context={ + "platform": "discord", + "mode": "discord_only", + }, + ) + async def _handle_agent_response(self, response_data: Dict[str, Any]): try: thread_id = response_data.get("thread_id") diff --git a/backend/integrations/discord/cogs.py b/backend/integrations/discord/cogs.py index d87e38d7..568f5d82 100644 --- a/backend/integrations/discord/cogs.py +++ b/backend/integrations/discord/cogs.py @@ -173,13 +173,13 @@ async def verification_status(self, interaction: discord.Interaction): ) if user_profile.is_verified and user_profile.github_id: embed = discord.Embed(title="✅ Verification Status", - color=discord.Color.green()) + color=discord.Color.green()) embed.add_field(name="GitHub Account", value=f"`{user_profile.github_username}`", inline=True) embed.add_field(name="Status", value="✅ Verified", inline=True) else: embed = discord.Embed(title="❌ Verification Status", - description="Your GitHub account is not linked.", - color=discord.Color.red()) + description="Your GitHub account is not linked.", + color=discord.Color.red()) embed.add_field(name="Next Steps", value="Use `/verify_github` to link your GitHub account.", inline=False) From 36bd888e306be0cd9922c513907e5281364fab94 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Sat, 31 Jan 2026 18:40:58 +0530 Subject: [PATCH 06/14] Fixed minor issues --- backend/integrations/discord/cogs.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/integrations/discord/cogs.py b/backend/integrations/discord/cogs.py index 568f5d82..fc54831e 100644 --- a/backend/integrations/discord/cogs.py +++ b/backend/integrations/discord/cogs.py @@ -110,11 +110,16 @@ async def reset_thread(self, interaction: discord.Interaction): if self.queue: from app.core.orchestration.queue_manager import QueuePriority await self.queue.enqueue(cleanup, QueuePriority.HIGH) - - await interaction.response.send_message( + await interaction.response.send_message( "Your DevRel thread has been reset!", ephemeral=True, ) + else: + await interaction.response.send_message( + "Your DevRel thread has been cleared locally. " + "(Full memory reset unavailable in current mode.)", + ephemeral=True, + ) @app_commands.command(name="help", description="Show DevRel assistant help.") async def help_devrel(self, interaction: discord.Interaction): @@ -280,7 +285,7 @@ async def verify_github(self, interaction: discord.Interaction): async def index_repository(self, interaction: discord.Interaction, repository: str): """Index a GitHub repository into FalkorDB code graph""" if not settings.code_intelligence_enabled: - logger.info("Idexing blocked: FalkorDB not configured") + logger.info("Indexing blocked: FalkorDB not configured") await falkor_unavailable(interaction) return From 266b475ec56bc7d61857e99859e22fab5ea668fc Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Wed, 4 Feb 2026 22:01:50 +0530 Subject: [PATCH 07/14] Address CodeRabbit feedback --- backend/app/api/router.py | 6 +-- backend/app/api/v1/health.py | 60 ++++++++++++------------- backend/app/core/config/settings.py | 2 +- backend/app/database/supabase/client.py | 9 +++- backend/integrations/discord/bot.py | 12 ++++- backend/integrations/discord/cogs.py | 11 +++-- backend/main.py | 3 ++ 7 files changed, 60 insertions(+), 43 deletions(-) diff --git a/backend/app/api/router.py b/backend/app/api/router.py index a4288257..6f2877b9 100644 --- a/backend/app/api/router.py +++ b/backend/app/api/router.py @@ -9,9 +9,7 @@ tags=["Health"] ) -# -------- Auth router (OPTIONAL) -------- -auth_router= APIRouter() - +# -------- Auth router -------- def get_auth_router() -> APIRouter: router= APIRouter() from .v1.auth import router as auth_router @@ -30,4 +28,4 @@ def get_auth_router() -> APIRouter: return router -__all__ = ["core_router", "auth_router"] +__all__ = ["core_router", "get_auth_router"] diff --git a/backend/app/api/v1/health.py b/backend/app/api/v1/health.py index 38cf2afe..1713bb40 100644 --- a/backend/app/api/v1/health.py +++ b/backend/app/api/v1/health.py @@ -4,7 +4,22 @@ router = APIRouter() logger = logging.getLogger(__name__) -services={} + +async def get_weaviate_status() -> str: + if not settings.code_intelligence_enabled: + return "disabled" + + from app.database.weaviate.client import get_weaviate_client + async with get_weaviate_client() as client: + return "ready" if await client.is_ready() else "not_ready" + + +def get_discord_status(app_instance) -> str: + if not settings.discord_enabled: + return "disabled" + + bot = app_instance.discord_bot + return "running" if bot and not bot.is_closed() else "stopped" @router.get("/health") async def health_check(request: Request): @@ -15,19 +30,15 @@ async def health_check(request: Request): dict: Status of the application and its services """ try: - if settings.code_intelligence_enabled: - from app.database.weaviate.client import get_weaviate_client - async with get_weaviate_client() as client: - services["weaviate"] = ( - "ready" if await client.is_ready() else "not_ready" - ) - else: - services["weaviate"] = "disabled" - + services = { + "weaviate": await get_weaviate_status(), + "discord": get_discord_status(request.app.state.app_instance), + } + return { "status": "healthy", "services": services, - } + } except Exception as e: logger.error(f"Health check failed: {e}") raise HTTPException( @@ -43,16 +54,11 @@ async def health_check(request: Request): async def weaviate_health(): """Check specifically Weaviate service health.""" try: - is_ready = None - if settings.code_intelligence_enabled: - from app.database.weaviate.client import get_weaviate_client - async with get_weaviate_client() as client: - is_ready = await client.is_ready() - return { "service": "weaviate", - "status": "ready" if is_ready else "not_ready" - } + "status": await get_weaviate_status(), + } + except Exception as e: logger.error(f"Weaviate health check failed: {e}") raise HTTPException( @@ -69,21 +75,11 @@ async def weaviate_health(): async def discord_health(request: Request): """Check specifically Discord bot health.""" try: - app_instance = request.app.state.app_instance - - services = { - "discord_bot": ( - "running" - if app_instance.discord_bot - and not app_instance.discord_bot.is_closed() - else "stopped" - ) - } return { "service": "discord_bot", - "status": services - } - + "status": get_discord_status(request.app.state.app_instance), + } + except Exception as e: logger.error(f"Discord bot health check failed: {e}") raise HTTPException( diff --git a/backend/app/core/config/settings.py b/backend/app/core/config/settings.py index 77520945..33ddd733 100644 --- a/backend/app/core/config/settings.py +++ b/backend/app/core/config/settings.py @@ -57,7 +57,7 @@ def github_enabled(self) -> bool: """ GitHub verification + OAuth. """ - return self.discord_enabled and all([ + return self.discord_enabled and bool(self.backend_url) and all([ self.github_token, self.supabase_url, self.supabase_key, diff --git a/backend/app/database/supabase/client.py b/backend/app/database/supabase/client.py index 14bad852..ff158c97 100644 --- a/backend/app/database/supabase/client.py +++ b/backend/app/database/supabase/client.py @@ -10,7 +10,14 @@ def get_supabase_client() -> AsyncClient: """ if _client is None: if not settings.supabase_url or not settings.supabase_key: - raise RuntimeError("Supabase is not configured") + missing = [] + if not settings.supabase_url: + missing.append("SUPABASE_URL") + if not settings.supabase_key: + missing.append("SUPABASE_KEY") + raise RuntimeError( + f"Supabase misconfigured. Missing: {', '.join(missing)}" + ) _client = AsyncClient( settings.supabase_url, settings.supabase_key, diff --git a/backend/integrations/discord/bot.py b/backend/integrations/discord/bot.py index 67dc15e1..38d011da 100644 --- a/backend/integrations/discord/bot.py +++ b/backend/integrations/discord/bot.py @@ -108,8 +108,18 @@ async def _handle_devrel_direct(self,message, triage_result, thread_id): else: await message.channel.send(response) - except Exception: + except Exception as e: logger.exception("Basic Discord-only chat failed") + # Fall back to original channel if thread unavailable + try: + if thread_id: + thread = self.get_channel(int("thread_id")) + if thread: + await thread.send("Sorry, I ran into an issue answering that.") + return + await message.channel.send("Sorry, I ran into an issue answering that.") + except Exception: + logger.exception("Failed to send error message") thread = self.get_channel(int(thread_id)) await thread.send("Sorry, I ran into an issue answering that." ) diff --git a/backend/integrations/discord/cogs.py b/backend/integrations/discord/cogs.py index fc54831e..7eb05dec 100644 --- a/backend/integrations/discord/cogs.py +++ b/backend/integrations/discord/cogs.py @@ -24,7 +24,11 @@ async def send_github_unavailable(interaction: discord.Interaction): ), color=discord.Color.red(), ) - await interaction.followup.send(embed=embed, ephemeral=True) + if interaction.response.is_done(): + await interaction.followup.send(embed=embed, ephemeral=True) + else: + await interaction.response.send_message(embed=embed, ephemeral=True) + async def falkor_unavailable(interaction: discord.Interaction): embed = discord.Embed( title="❌ Code Intelligence Unavailable", @@ -37,8 +41,7 @@ async def falkor_unavailable(interaction: discord.Interaction): ), color=discord.Color.red(), ) - - # Safe send (works whether deferred or not) + # Safe send if interaction.response.is_done(): await interaction.followup.send(embed=embed, ephemeral=True) else: @@ -418,7 +421,7 @@ async def _run_index_and_update(): @app_commands.describe(repository="Repository name (owner/repo)") async def delete_index(self, interaction: discord.Interaction, repository: str): """Delete a repository index""" - if not settings.code_intelligence_enabled(): + if not settings.code_intelligence_enabled: logger.info("Deletion of index blocked: FalkorDB not configured") await falkor_unavailable(interaction) return diff --git a/backend/main.py b/backend/main.py index 5dc53c35..2eb9d8da 100644 --- a/backend/main.py +++ b/backend/main.py @@ -38,11 +38,13 @@ def __init__(self): from integrations.discord.bot import DiscordBot from discord.ext import commands self.discord_bot = DiscordBot(queue_manager=None) + self.queue_manager = None if settings.code_intelligence_enabled: from app.core.orchestration.queue_manager import AsyncQueueManager from app.database.weaviate.client import get_weaviate_client from app.core.orchestration.agent_coordinator import AgentCoordinator + self.weaviate_client = get_weaviate_client() self.queue_manager = AsyncQueueManager() self.discord_bot= DiscordBot(self.queue_manager) @@ -95,6 +97,7 @@ async def test_weaviate_connection(self): logger.info("Weaviate Is for Full Mode") return try: + from app.database.weaviate.client import get_weaviate_client async with get_weaviate_client() as client: if await client.is_ready(): logger.info("Weaviate connection successful and ready") From 47d44b58d2ae6a38243e04620d99aa4c73fb1b7e Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Thu, 5 Feb 2026 21:43:22 +0530 Subject: [PATCH 08/14] Address review: guard discord_bot --- backend/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.py b/backend/main.py index 2eb9d8da..463508eb 100644 --- a/backend/main.py +++ b/backend/main.py @@ -109,7 +109,7 @@ async def stop_background_tasks(self): """Stops all background tasks and connections gracefully.""" logger.info("Stopping background tasks and closing connections...") try: - if settings.discord_enabled and not self.discord_bot.is_closed(): + if settings.discord_enabled and self.discord_bot and not self.discord_bot.is_closed(): await self.discord_bot.close() logger.info("Discord bot has been closed.") except Exception as e: From 72a49866b9ff0c63f7e598599c4d1eb8aba8b8dd Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Thu, 5 Feb 2026 21:56:47 +0530 Subject: [PATCH 09/14] Address review: guard discord_bot --- backend/main.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/backend/main.py b/backend/main.py index 463508eb..efd243a8 100644 --- a/backend/main.py +++ b/backend/main.py @@ -31,6 +31,7 @@ def __init__(self): """Initializes all services required by the application.""" self.weaviate_client = None self.discord_bot = None + self._discord_task = None self.agent_coordinator = None # Discord always exists if enabled @@ -51,7 +52,10 @@ def __init__(self): self.agent_coordinator = AgentCoordinator(self.queue_manager) async def start_background_tasks(self): - """Starts the background.""" + """ + Start all enabled background services including the Discord bot, + queue workers, and code intelligence dependencies. + """ try: # Discord Mode if settings.discord_enabled: @@ -62,7 +66,7 @@ async def start_background_tasks(self): # 2. Discord try: await self.discord_bot.load_extension("integrations.discord.cogs") - asyncio.create_task( + self._discord_task = asyncio.create_task( self.discord_bot.start(settings.discord_bot_token) ) except Exception as e: @@ -76,7 +80,6 @@ async def start_background_tasks(self): await self.test_weaviate_connection() except Exception as e: logger.warning("Weaviate disabled: %s", e) - self.weaviate_enabled = False logger.info( From 8838e18a95c14905dd45a623f1693c7f17e73ce6 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Thu, 5 Feb 2026 22:28:11 +0530 Subject: [PATCH 10/14] Address review --- backend/app/core/config/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/app/core/config/settings.py b/backend/app/core/config/settings.py index 33ddd733..e45d9b86 100644 --- a/backend/app/core/config/settings.py +++ b/backend/app/core/config/settings.py @@ -66,9 +66,10 @@ def github_enabled(self) -> bool: @property def code_intelligence_enabled(self) -> bool: """ - FalkorDB / GraphRAG / indexing. + Runs DevrAI in full mode. """ return self.github_enabled and all([ + self.rabbitmq_url, os.getenv("FALKORDB_HOST"), os.getenv("FALKORDB_PORT"), os.getenv("CODEGRAPH_BACKEND_URL"), From e5f6e5ccb29295f6bfb43868eca8ebbfe82b69c5 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Sun, 8 Feb 2026 20:14:15 +0530 Subject: [PATCH 11/14] Updated .env.example accordingly --- backend/.env.example | 45 ++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/backend/.env.example b/backend/.env.example index ec5b1e6e..8fb44912 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -2,37 +2,42 @@ # PORT=8000 # CORS_ORIGINS=http://localhost:3000 -SUPABASE_URL="https://.supabase.co" -SUPABASE_KEY="ey...cnGQk" - -DISCORD_BOT_TOKEN="MTM5...5Vr7fw0m9PGAllLfyztCs" -ENABLE_DISCORD_BOT="true" - -GITHUB_TOKEN="ghp_...3IOhGP970vnjYK" # EMBEDDING_MODEL=BAAI/bge-small-en-v1.5 # EMBEDDING_MAX_BATCH_SIZE=32 # EMBEDDING_DEVICE=cpu -# FalkorDB Configuration -FALKORDB_HOST=localhost -FALKORDB_PORT=6379 -CODEGRAPH_BACKEND_URL=http://localhost:5000 -CODEGRAPH_SECRET_TOKEN=DevRAI_CodeGraph_Secret +#1. backend only +BACKEND_URL=http://localhost:8000 + +#2. Discord-only mode (no GitHub, no Supabase) +DISCORD_BOT_TOKEN="MTM5...5Vr7fw0m9PGAllLfyztCs" +ENABLE_DISCORD_BOT="true" +GEMINI_API_KEY="AIz...ct527D5h-IJCRaXE" GEMINI_MODEL=gemini-2.0-flash -SECRET_TOKEN=DevRAI_CodeGraph_Secret -CODE_GRAPH_PUBLIC=1 + +#3. Supabase setting (Discord + Github + Supabase) +SUPABASE_URL="https://...supabase.co" +SUPABASE_KEY="ey...cnGQk" +GITHUB_TOKEN=ghp_...3IOhGP970vnjYK + +#4. Full mode (FalkorDB + CodeGraph + Agents)-- +# FalkorDB Configuration +FALKORDB_HOST=localhost +FALKORDB_PORT=6379 +CODEGRAPH_BACKEND_URL=http://localhost:5000 +CODEGRAPH_SECRET_TOKEN=DevRAI_CodeGraph_Secret +SECRET_TOKEN=DevRAI_CodeGraph_Secret +CODE_GRAPH_PUBLIC=1 FLASK_RUN_HOST=0.0.0.0 FLASK_RUN_PORT=5000 -BACKEND_URL="http://localhost:8000" - -GEMINI_API_KEY="AIz...ct527D5h-IJCRaXE" -TAVILY_API_KEY="tvly-dev-....1G2k3ivF56SJfWJ4" +RABBITMQ_URL=amqp://localhost:5672/ +TAVILY_API_KEY="tvly-dev-....1G2k3ivF56SJfWJ4" # Langsmith -LANGSMITH_TRACING="true" -LANGSMITH_ENDPOINT="https://api.smith.langchain.com" +LANGSMITH_TRACING="true" +LANGSMITH_ENDPOINT="https://api.smith.langchain.com" LANGSMITH_API_KEY="lsv2_pt...d9d989_953d073741" LANGSMITH_PROJECT="devr" From cba5fdc378b9f1b76de6063a912ca2481133a5d7 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Sun, 8 Feb 2026 20:36:25 +0530 Subject: [PATCH 12/14] Adress Review: Put dummy values --- backend/.env.example | 17 ++++++++--------- backend/app/core/config/settings.py | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/backend/.env.example b/backend/.env.example index 8fb44912..5d746e83 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -11,34 +11,33 @@ BACKEND_URL=http://localhost:8000 #2. Discord-only mode (no GitHub, no Supabase) -DISCORD_BOT_TOKEN="MTM5...5Vr7fw0m9PGAllLfyztCs" +DISCORD_BOT_TOKEN="your_discord_bot_token" ENABLE_DISCORD_BOT="true" -GEMINI_API_KEY="AIz...ct527D5h-IJCRaXE" +GEMINI_API_KEY="your_gemini_api_key" GEMINI_MODEL=gemini-2.0-flash #3. Supabase setting (Discord + Github + Supabase) SUPABASE_URL="https://...supabase.co" -SUPABASE_KEY="ey...cnGQk" -GITHUB_TOKEN=ghp_...3IOhGP970vnjYK +SUPABASE_KEY="your_supabase_key" +GITHUB_TOKEN="your_github_token" -#4. Full mode (FalkorDB + CodeGraph + Agents)-- +#4. Full mode (FalkorDB + CodeGraph + Agents) # FalkorDB Configuration FALKORDB_HOST=localhost FALKORDB_PORT=6379 CODEGRAPH_BACKEND_URL=http://localhost:5000 -CODEGRAPH_SECRET_TOKEN=DevRAI_CodeGraph_Secret -SECRET_TOKEN=DevRAI_CodeGraph_Secret +SECRET_TOKEN="your_codegraph_secret" CODE_GRAPH_PUBLIC=1 FLASK_RUN_HOST=0.0.0.0 FLASK_RUN_PORT=5000 RABBITMQ_URL=amqp://localhost:5672/ -TAVILY_API_KEY="tvly-dev-....1G2k3ivF56SJfWJ4" +TAVILY_API_KEY="your_tavily_api_key" # Langsmith LANGSMITH_TRACING="true" LANGSMITH_ENDPOINT="https://api.smith.langchain.com" -LANGSMITH_API_KEY="lsv2_pt...d9d989_953d073741" +LANGSMITH_API_KEY="your_langsmith_api_key" LANGSMITH_PROJECT="devr" ORG_NAME=AOSSIE diff --git a/backend/app/core/config/settings.py b/backend/app/core/config/settings.py index e45d9b86..d8905999 100644 --- a/backend/app/core/config/settings.py +++ b/backend/app/core/config/settings.py @@ -73,7 +73,7 @@ def code_intelligence_enabled(self) -> bool: os.getenv("FALKORDB_HOST"), os.getenv("FALKORDB_PORT"), os.getenv("CODEGRAPH_BACKEND_URL"), - os.getenv("CODEGRAPH_SECRET_TOKEN"), + os.getenv("SECRET_TOKEN"), ]) From 081ef3ab19c4b32000ea9211c5f957a28d3cdf75 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Sun, 8 Feb 2026 20:47:35 +0530 Subject: [PATCH 13/14] Adress Review --- backend/.env.example | 1 - backend/app/core/config/settings.py | 16 +++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/backend/.env.example b/backend/.env.example index 5d746e83..449f2ca6 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -12,7 +12,6 @@ BACKEND_URL=http://localhost:8000 #2. Discord-only mode (no GitHub, no Supabase) DISCORD_BOT_TOKEN="your_discord_bot_token" -ENABLE_DISCORD_BOT="true" GEMINI_API_KEY="your_gemini_api_key" GEMINI_MODEL=gemini-2.0-flash diff --git a/backend/app/core/config/settings.py b/backend/app/core/config/settings.py index d8905999..6a3f6433 100644 --- a/backend/app/core/config/settings.py +++ b/backend/app/core/config/settings.py @@ -8,7 +8,7 @@ class Settings(BaseSettings): ## CORE (minimal code) - backend_url: str ="" + backend_url: str ## OPTIONAL @@ -38,6 +38,12 @@ class Settings(BaseSettings): classification_agent_model: str = "gemini-2.0-flash" agent_timeout: int = 30 max_retries: int = 3 + + # FalkorDB / CodeGraph + falkordb_host: Optional[str] = None + falkordb_port: Optional[str] = None + codegraph_backend_url: Optional[str] = None + secret_token: Optional[str] = None # RabbitMQ configuration rabbitmq_url: Optional[str] = None @@ -70,10 +76,10 @@ def code_intelligence_enabled(self) -> bool: """ return self.github_enabled and all([ self.rabbitmq_url, - os.getenv("FALKORDB_HOST"), - os.getenv("FALKORDB_PORT"), - os.getenv("CODEGRAPH_BACKEND_URL"), - os.getenv("SECRET_TOKEN"), + self.falkordb_host, + self.falkordb_port, + self.codegraph_backend_url, + self.secret_token, ]) From f224c04020f92c03fe42062aee74fa3ff8751b17 Mon Sep 17 00:00:00 2001 From: tanii1125 Date: Sun, 8 Feb 2026 20:59:42 +0530 Subject: [PATCH 14/14] Remove trailing whitespace --- backend/.env.example | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/.env.example b/backend/.env.example index 449f2ca6..99f49f84 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -9,33 +9,33 @@ #1. backend only BACKEND_URL=http://localhost:8000 - + #2. Discord-only mode (no GitHub, no Supabase) DISCORD_BOT_TOKEN="your_discord_bot_token" GEMINI_API_KEY="your_gemini_api_key" GEMINI_MODEL=gemini-2.0-flash #3. Supabase setting (Discord + Github + Supabase) -SUPABASE_URL="https://...supabase.co" +SUPABASE_URL="https://...supabase.co" SUPABASE_KEY="your_supabase_key" GITHUB_TOKEN="your_github_token" #4. Full mode (FalkorDB + CodeGraph + Agents) # FalkorDB Configuration -FALKORDB_HOST=localhost -FALKORDB_PORT=6379 -CODEGRAPH_BACKEND_URL=http://localhost:5000 +FALKORDB_HOST=localhost +FALKORDB_PORT=6379 +CODEGRAPH_BACKEND_URL=http://localhost:5000 SECRET_TOKEN="your_codegraph_secret" -CODE_GRAPH_PUBLIC=1 +CODE_GRAPH_PUBLIC=1 FLASK_RUN_HOST=0.0.0.0 FLASK_RUN_PORT=5000 RABBITMQ_URL=amqp://localhost:5672/ -TAVILY_API_KEY="your_tavily_api_key" +TAVILY_API_KEY="your_tavily_api_key" # Langsmith -LANGSMITH_TRACING="true" -LANGSMITH_ENDPOINT="https://api.smith.langchain.com" +LANGSMITH_TRACING="true" +LANGSMITH_ENDPOINT="https://api.smith.langchain.com" LANGSMITH_API_KEY="your_langsmith_api_key" LANGSMITH_PROJECT="devr"