Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .clinerules
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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.
50 changes: 48 additions & 2 deletions bot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import re
import json
import logging
import discord
Expand Down Expand Up @@ -163,16 +164,40 @@ async def _get_or_create_thread(message: discord.Message, channel: discord.TextC
return None


def is_query_covered(query: str) -> bool:
"""Check if the query contains keywords covered in .clinerules using word boundaries."""
q = query.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:
# 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


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."""
if message.author.bot:
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
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if not is_in_thread and not is_in_configured_channel:
if not is_in_configured_channel:
return

author = message.author
Expand Down Expand Up @@ -212,6 +237,27 @@ 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):
# 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: "
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:
Expand Down
Loading