From 5f1554ecfc7892c4e4ef0f647bac2bded0fd1f5a Mon Sep 17 00:00:00 2001 From: kpj2006 <24ucs074@lnmiit.ac.in> Date: Fri, 19 Jun 2026 22:11:55 +0530 Subject: [PATCH 1/3] feat: implement OOD query filtering in bot logic and enforce scoped interaction guidelines via .clinerules --- .clinerules | 8 +++++++- bot.py | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/.clinerules b/.clinerules index da8e3fb..e798975 100644 --- a/.clinerules +++ b/.clinerules @@ -80,4 +80,10 @@ Bot: - Avoid long explanations unless asked # === GOAL === -Act like a mentor helping users complete an AOSSIE template repo step-by-step. \ No newline at end of file +Act like a mentor helping users complete an AOSSIE template repo step-by-step. + +# === CLARIFYING FLOW FOR OOD/UNSUPPORTED QUERIES === +If the user's question does not match setup, README, contribute, or error topics: +- Acknowledge that the query does not directly match the standard template tasks. +- Ask a friendly, concise clarifying question to guide them back to one of the supported tasks (setup, README, contributing, or error debugging). +- Under no circumstances should you generate answers outside these core categories. \ No newline at end of file diff --git a/bot.py b/bot.py index c258633..ac0dff9 100644 --- a/bot.py +++ b/bot.py @@ -163,6 +163,26 @@ async def _get_or_create_thread(message: discord.Message, channel: discord.TextC return None +def is_query_covered(query: str, context: str = "") -> bool: + """Check if the query or its conversation context contains keywords covered in .clinerules.""" + q = query.lower() + ctx = context.lower() + + # Predefined keyword maps based on .clinerules + categories = { + "setup": ["setup", "install", "run", "build", "clone", "docker", "env", "start", "dev server", "npm run dev"], + "readme": ["readme", "read me", "documentation", "project name", "description", "user flow", "feature"], + "contribute": ["contribute", "contributor", "fork", "pr", "pull request", "issue", "branch", "git", "onboarding"], + "error": ["error", "exception", "bug", "fail", "crash", "issue", "logs", "broken", "debug", "not working"] + } + + for cat, keywords in categories.items(): + for kw in keywords: + if kw in q or (ctx and kw in ctx): + return True + return False + + async def process_message(message: discord.Message): """Process a single message: new messages in the main channel spawn a thread, messages in existing threads continue the conversation there.""" @@ -170,9 +190,12 @@ async def process_message(message: discord.Message): return is_in_thread = isinstance(message.channel, discord.Thread) - is_in_configured_channel = message.channel.id == DISCORD_CHANNEL_ID_INT + is_in_configured_channel = ( + (message.channel.parent.id if is_in_thread else message.channel.id) + == DISCORD_CHANNEL_ID_INT + ) - if not is_in_thread and not is_in_configured_channel: + if not is_in_configured_channel: return author = message.author @@ -212,6 +235,24 @@ async def process_message(message: discord.Message): else: full_prompt = message.content + # Check if the query has sufficient information/context based on .clinerules + if not is_query_covered(message.content, conversation_context): + full_prompt = ( + f"The user is asking: '{message.content}'. " + f"This query is not covered by the standard guidelines in .clinerules. " + f"Generate a polite response asking the user to clarify if they need help with: " + f"1. Setting up the project template\n" + f"2. Writing or updating the README\n" + f"3. Contributing to the repository\n" + f"4. Debugging an error\n" + f"Keep the response short, friendly, and under 5 lines." + ) + await _log_gap( + message.content, + "insufficient_info", + thread_id=thread.id, + ) + response_text, used_fallback = await generate_ollama_response(full_prompt, skill_context) if used_fallback or not skill_context: From 2473e32fcc44b15c7eb5b576124370f150d8fc5f Mon Sep 17 00:00:00 2001 From: kpj2006 <24ucs074@lnmiit.ac.in> Date: Fri, 19 Jun 2026 22:33:26 +0530 Subject: [PATCH 2/3] refactor: update query coverage check to use word-boundary regex and improve LLM prompt context inclusion --- bot.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/bot.py b/bot.py index ac0dff9..f0af464 100644 --- a/bot.py +++ b/bot.py @@ -1,4 +1,5 @@ import os +import re import json import logging import discord @@ -163,10 +164,9 @@ async def _get_or_create_thread(message: discord.Message, channel: discord.TextC return None -def is_query_covered(query: str, context: str = "") -> bool: - """Check if the query or its conversation context contains keywords covered in .clinerules.""" +def is_query_covered(query: str) -> bool: + """Check if the query contains keywords covered in .clinerules using word boundaries.""" q = query.lower() - ctx = context.lower() # Predefined keyword maps based on .clinerules categories = { @@ -178,7 +178,9 @@ def is_query_covered(query: str, context: str = "") -> bool: for cat, keywords in categories.items(): for kw in keywords: - if kw in q or (ctx and kw in ctx): + # Use raw pattern and re.escape for safety, matching word boundaries for the keyword/phrase + pattern = r'\b' + re.escape(kw) + r'\b' + if re.search(pattern, q): return True return False @@ -236,8 +238,11 @@ async def process_message(message: discord.Message): full_prompt = message.content # Check if the query has sufficient information/context based on .clinerules - if not is_query_covered(message.content, conversation_context): + if not is_query_covered(message.content): + # Pass conversation context explicitly to the LLM so it has thread history for the clarifying question + history_str = f"Previous conversation history:\n{conversation_context}\n\n" if conversation_context else "" full_prompt = ( + f"{history_str}" f"The user is asking: '{message.content}'. " f"This query is not covered by the standard guidelines in .clinerules. " f"Generate a polite response asking the user to clarify if they need help with: " From 15db778016c86fdab8aa703e7bd1e8ab2ad0e24e Mon Sep 17 00:00:00 2001 From: kpj2006 <24ucs074@lnmiit.ac.in> Date: Fri, 19 Jun 2026 22:37:16 +0530 Subject: [PATCH 3/3] fix: use parent_id attribute instead of parent.id for thread channel identification --- bot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot.py b/bot.py index f0af464..a0453b8 100644 --- a/bot.py +++ b/bot.py @@ -193,7 +193,7 @@ async def process_message(message: discord.Message): is_in_thread = isinstance(message.channel, discord.Thread) is_in_configured_channel = ( - (message.channel.parent.id if is_in_thread else message.channel.id) + (message.channel.parent_id if is_in_thread else message.channel.id) == DISCORD_CHANNEL_ID_INT )