Skip to content

Commit a247ba9

Browse files
committed
Added changes suggested by mentor
minimized regex use in github_toolkit.py and some changes in react_prompt
1 parent c52a4bf commit a247ba9

File tree

5 files changed

+32
-68
lines changed

5 files changed

+32
-68
lines changed

backend/app/agents/devrel/github/github_toolkit.py

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
import logging
22
import os
3+
import json
4+
import re
35
from typing import Dict, Any
46
from langchain_google_genai import ChatGoogleGenerativeAI
57
from langchain_core.messages import HumanMessage
68
from app.core.config import settings
79
from .prompts.intent_analysis import GITHUB_INTENT_ANALYSIS_PROMPT
810
from .tools.search import handle_web_search
911
from .tools.github_support import handle_github_supp
10-
# TODO: Implement all tools
1112
from .tools.contributor_recommendation import handle_contributor_recommendation
12-
# from .tools.repository_query import handle_repo_query
13-
# from .tools.issue_creation import handle_issue_creation
14-
# from .tools.documentation_generation import handle_documentation_generation
1513
from .tools.general_github_help import handle_general_github_help
14+
1615
logger = logging.getLogger(__name__)
1716

1817
DEFAULT_ORG = os.getenv("GITHUB_ORG")
1918

19+
2020
def normalize_org(org_from_user: str = None) -> str:
21-
"""
22-
Always fallback to env org if user does not specify one.
23-
"""
21+
"""Fallback to env org if user does not specify one."""
2422
if org_from_user and org_from_user.strip():
2523
return org_from_user.strip()
2624
return DEFAULT_ORG
@@ -52,41 +50,29 @@ def __init__(self):
5250
]
5351

5452
async def classify_intent(self, user_query: str) -> Dict[str, Any]:
55-
"""
56-
Classify intent and return classification with reasoning.
57-
58-
Args:
59-
user_query: The user's request or question
60-
61-
Returns:
62-
Dictionary containing classification, reasoning, and confidence
63-
"""
53+
"""Classify intent and return classification with reasoning."""
6454
logger.info(f"Classifying intent for query: {user_query[:100]}")
6555

6656
try:
6757
prompt = GITHUB_INTENT_ANALYSIS_PROMPT.format(user_query=user_query)
6858
response = await self.llm.ainvoke([HumanMessage(content=prompt)])
6959

70-
import json
71-
import re
72-
7360
content = response.content.strip()
7461

75-
candidates = []
76-
cb = re.search(r'```(?:json)?\s*({[\s\S]*?})\s*```', content, flags=re.IGNORECASE)
77-
if cb:
78-
candidates.append(cb.group(1))
79-
candidates.extend(m.group(0) for m in re.finditer(r'\{[\s\S]*?\}', content))
80-
81-
result = None
82-
for payload in candidates:
83-
try:
84-
result = json.loads(payload)
85-
break
86-
except json.JSONDecodeError:
87-
continue
88-
if result is None:
89-
raise json.JSONDecodeError("No valid JSON object found in LLM response", content, 0)
62+
try:
63+
result = json.loads(content)
64+
except json.JSONDecodeError:
65+
match = re.search(r"\{.*\}", content, re.DOTALL)
66+
if match:
67+
result = json.loads(match.group())
68+
else:
69+
logger.error(f"Invalid JSON in LLM response: {content}")
70+
return {
71+
"classification": "general_github_help",
72+
"reasoning": "Failed to parse LLM response as JSON",
73+
"confidence": "low",
74+
"query": user_query
75+
}
9076

9177
classification = result.get("classification")
9278
if classification not in self.tools:
@@ -96,21 +82,12 @@ async def classify_intent(self, user_query: str) -> Dict[str, Any]:
9682

9783
result["query"] = user_query
9884

99-
logger.info(f"Classified intent as for query: {user_query} is: {classification}")
85+
logger.info(f"Classified intent for query: {user_query} -> {classification}")
10086
logger.info(f"Reasoning: {result.get('reasoning', 'No reasoning provided')}")
10187
logger.info(f"Confidence: {result.get('confidence', 'unknown')}")
10288

10389
return result
10490

105-
except json.JSONDecodeError as e:
106-
logger.error(f"Error parsing JSON response from LLM: {str(e)}")
107-
logger.error(f"Raw response: {response.content}")
108-
return {
109-
"classification": "general_github_help",
110-
"reasoning": f"Failed to parse LLM response: {str(e)}",
111-
"confidence": "low",
112-
"query": user_query
113-
}
11491
except Exception as e:
11592
logger.error(f"Error in intent classification: {str(e)}")
11693
return {
@@ -121,9 +98,7 @@ async def classify_intent(self, user_query: str) -> Dict[str, Any]:
12198
}
12299

123100
async def execute(self, query: str) -> Dict[str, Any]:
124-
"""
125-
Main execution method - classifies intent and delegates to appropriate tools
126-
"""
101+
"""Main execution method - classifies intent and delegates to appropriate tools"""
127102
logger.info(f"Executing GitHub toolkit for query: {query[:100]}")
128103

129104
try:
@@ -140,13 +115,10 @@ async def execute(self, query: str) -> Dict[str, Any]:
140115
result["org_used"] = org
141116
elif classification == "repo_support":
142117
result = "Not implemented"
143-
# result = await handle_repo_query(query)
144118
elif classification == "issue_creation":
145119
result = "Not implemented"
146-
# result = await handle_issue_creation(query)
147120
elif classification == "documentation_generation":
148121
result = "Not implemented"
149-
# result = await handle_documentation_generation(query)
150122
elif classification == "web_search":
151123
result = await handle_web_search(query)
152124
else:

backend/app/agents/devrel/github/services/github_mcp_client.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
logger = logging.getLogger(__name__)
88

99
class GitHubMCPClient:
10-
"""
11-
Client for communicating with the GitHub MCP server.
12-
"""
10+
"""Client for communicating with the GitHub MCP server."""
1311

1412
def __init__(self, mcp_server_url: str = "http://localhost:8001"):
1513
self.mcp_server_url = mcp_server_url
@@ -91,9 +89,7 @@ async def list_org_repos(self, org: str) -> Union[List[Dict[str, Any]], Dict[str
9189

9290

9391
async def is_server_available(self) -> bool:
94-
"""
95-
Health check for MCP server.
96-
"""
92+
"""Health check for MCP server."""
9793
if not self.session:
9894
return False
9995

backend/app/agents/devrel/github/services/github_mcp_service.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,8 @@ def repo_query(self, owner: str, repo: str) -> dict:
4949
}
5050

5151
def list_repo_issues(self, owner: str, repo: str, state: str = "open") -> list:
52-
"""
53-
Fetch issues from a given repository.
54-
:param owner: repository owner (user/org)
55-
:param repo: repository name
56-
:param state: 'open', 'closed', or 'all'
57-
"""
52+
"""Fetch issues from a given repository."""
53+
5854
url = f"{self.base_url}/repos/{owner}/{repo}/issues?state={state}&per_page=50"
5955
headers = self._headers()
6056
try:

backend/app/agents/devrel/github/tools/github_support.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ async def handle_github_supp(query: str, org: Optional[str] = None):
3737
if match:
3838
org, repo_name = match.group(1), match.group(2)
3939

40-
# --- owner/repo format ---
40+
# owner/repo format
4141
if not repo_name:
4242
match = OWNER_REPO_RE.search(query)
4343
if match:
4444
org, repo_name = match.group(1), match.group(2)
4545

46-
# ---"<name> repo" pattern ---
46+
# "<name> repo" pattern
4747
if not repo_name:
4848
match = REPO_NAME_RE.search(query)
4949
if match:
@@ -53,7 +53,7 @@ async def handle_github_supp(query: str, org: Optional[str] = None):
5353
# Fallback org if none detected
5454
org = org or DEFAULT_ORG
5555

56-
# --- Top repos ---
56+
# Top repos
5757
if "top" in q and "repo" in q:
5858
repos = await github_mcp_service.get_org_repositories(org)
5959
if isinstance(repos, dict) and "error" in repos:
@@ -65,7 +65,7 @@ async def handle_github_supp(query: str, org: Optional[str] = None):
6565
"repositories": repos,
6666
}
6767

68-
# --- Issues, stars, forks, stats ---
68+
# Issues, stars, forks, stats
6969
if any(word in q for word in ["issue", "star", "fork", "stat", "stats"]):
7070
if repo_name:
7171
if "issue" in q:
@@ -92,7 +92,7 @@ async def handle_github_supp(query: str, org: Optional[str] = None):
9292
return {"status": "error", "message": f"Failed to fetch repositories for {org}", "details": repos}
9393
return {"status": "success", "message": f"Repositories for {org}", "repositories": repos}
9494

95-
# --- General repo list (fallback) ---
95+
# General repo list
9696
repos = await github_mcp_service.get_org_repositories(org)
9797
if isinstance(repos, dict) and "error" in repos:
9898
return {

backend/app/agents/devrel/prompts/react_prompt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
{tool_results}
1414
1515
AVAILABLE ACTIONS:
16-
1. web_search - Search the web for external information (ONLY if you cannot find info in GitHub or FAQs)
16+
1. web_search - Search the web for external information
1717
2. faq_handler - Answer common questions from knowledge base
1818
3. onboarding - Welcome new users and guide exploration
1919
4. github_toolkit - Handle ANY GitHub-related queries such as:

0 commit comments

Comments
 (0)