1111import sys
1212from pathlib import Path
1313from typing import Annotated , Any
14+ from urllib .parse import quote_plus
1415
1516from pydantic import Field
1617
2122
2223logger = logging .getLogger (__name__ )
2324
25+ # GitHub issue template URLs
26+ RUNTIME_BUG_URL = "https://github.com/homeassistant-ai/ha-mcp/issues/new?template=runtime_bug.md"
27+ AGENT_BEHAVIOR_URL = "https://github.com/homeassistant-ai/ha-mcp/issues/new?template=agent_behavior_feedback.md"
28+
2429
2530def _detect_installation_method () -> str :
2631 """
@@ -226,6 +231,16 @@ async def ha_report_issue(
226231 # Anonymization instructions
227232 anonymization_guide = _generate_anonymization_guide ()
228233
234+ # Generate suggested title
235+ suggested_title = _generate_bug_title (diagnostic_info , recent_logs )
236+
237+ # Generate search keywords and URLs for duplicate check
238+ search_keywords = _generate_search_keywords (diagnostic_info , recent_logs )
239+ duplicate_check_urls = [
240+ f"https://github.com/homeassistant-ai/ha-mcp/issues?q=is%3Aissue+{ quote_plus (keyword )} "
241+ for keyword in search_keywords [:3 ] # Limit to top 3 keywords
242+ ]
243+
229244 return {
230245 "success" : True ,
231246 "diagnostic_info" : diagnostic_info ,
@@ -237,21 +252,35 @@ async def ha_report_issue(
237252 "runtime_bug_template" : runtime_bug_template ,
238253 "agent_behavior_template" : agent_behavior_template ,
239254 "anonymization_guide" : anonymization_guide ,
255+ "suggested_title" : suggested_title ,
256+ "duplicate_check_urls" : duplicate_check_urls ,
240257 "instructions" : (
241- "ANALYZE THE CONVERSATION to determine which template to present:\n \n "
242- "🐛 Present RUNTIME_BUG_TEMPLATE if:\n "
243- " - User reports an error, failure, or unexpected behavior in ha-mcp\n "
244- " - A tool returned an error or incorrect result\n "
245- " - Something is broken or not working\n "
246- " Submit at: https://github.com/homeassistant-ai/ha-mcp/issues/new?template=runtime_bug.md\n \n "
247- "🤖 Present AGENT_BEHAVIOR_TEMPLATE if:\n "
248- " - User mentions YOU (the agent) used the wrong tool\n "
249- " - User suggests YOU should have done something differently\n "
250- " - User reports YOUR inefficiency or mistakes\n "
251- " Submit at: https://github.com/homeassistant-ai/ha-mcp/issues/new?template=agent_behavior_feedback.md\n \n "
252- "If UNCLEAR which type, ASK: 'Are you reporting a bug in ha-mcp, or providing feedback on how I used the tools?'\n \n "
253- "Present the chosen template to the user. Ask them to fill in the description sections. "
254- "Remind them to follow the anonymization_guide to protect their privacy."
258+ "WORKFLOW FOR PRESENTING BUG REPORTS:\n \n "
259+ "1. **Check for duplicates FIRST** (before presenting the template):\n "
260+ " - Use the duplicate_check_urls to search for similar issues\n "
261+ " - If gh CLI is available: use `gh issue list --search \" keyword\" `\n "
262+ " - Otherwise: inform user to check the duplicate_check_urls\n "
263+ " - If duplicates found, ask user if they want to comment on existing issue instead\n \n "
264+ "2. **Determine which template to present**:\n "
265+ " - ANALYZE THE CONVERSATION to determine which template to present\n \n "
266+ " 🐛 Present RUNTIME_BUG_TEMPLATE if:\n "
267+ " - User reports an error, failure, or unexpected behavior in ha-mcp\n "
268+ " - A tool returned an error or incorrect result\n "
269+ " - Something is broken or not working\n \n "
270+ " 🤖 Present AGENT_BEHAVIOR_TEMPLATE if:\n "
271+ " - User mentions YOU (the agent) used the wrong tool\n "
272+ " - User suggests YOU should have done something differently\n "
273+ " - User reports YOUR inefficiency or mistakes\n \n "
274+ " If UNCLEAR which type, ASK: 'Are you reporting a bug in ha-mcp, or providing feedback on how I used the tools?'\n \n "
275+ "3. **Present the report to the user**:\n "
276+ " a. Show the suggested_title (user can edit if needed)\n "
277+ " b. Present the chosen template IN A MARKDOWN CODE BLOCK (```markdown...```) for easy copy/paste\n "
278+ " c. PROMINENTLY display the submission URL at the top:\n "
279+ f" - Runtime bugs: { RUNTIME_BUG_URL } \n "
280+ f" - Agent behavior: { AGENT_BEHAVIOR_URL } \n "
281+ " d. Ask them to fill in the description sections\n "
282+ " e. Remind them to follow the anonymization_guide to protect their privacy\n \n "
283+ "CRITICAL: Always present templates in markdown code blocks (```markdown...```) so users can copy/paste easily!"
255284 ),
256285 }
257286
@@ -322,6 +351,84 @@ def _extract_error_messages(logs: list[dict[str, Any]]) -> list[str]:
322351 return error_messages
323352
324353
354+ def _generate_bug_title (
355+ diagnostic_info : dict [str , Any ],
356+ recent_logs : list [dict [str , Any ]],
357+ ) -> str :
358+ """
359+ Generate a concise bug title (single line, ~60 chars max).
360+
361+ Strategy:
362+ 1. If there are error messages, use the most recent one as basis
363+ 2. Otherwise, use generic template based on connection status
364+ 3. Truncate to ~60 chars max
365+ """
366+ title = ""
367+ # Try to get the most recent error directly from logs
368+ for log in reversed (recent_logs ):
369+ error_msg = log .get ("error_message" )
370+ if error_msg :
371+ tool_name = log .get ("tool_name" , "unknown" )
372+ title = f"{ tool_name } : { error_msg } "
373+ break
374+
375+ if not title :
376+ # No errors - check connection status
377+ conn_status = diagnostic_info .get ("connection_status" , "Unknown" )
378+ if "Error" in conn_status or "Failed" in conn_status :
379+ title = f"Connection issue: { conn_status } "
380+ else :
381+ title = "Issue with ha-mcp"
382+
383+ # Truncate to ~60 chars, trying to preserve words
384+ if len (title ) > 60 :
385+ title = title [:57 ] + "..."
386+
387+ return title
388+
389+
390+ def _generate_search_keywords (
391+ diagnostic_info : dict [str , Any ],
392+ recent_logs : list [dict [str , Any ]],
393+ ) -> list [str ]:
394+ """
395+ Generate search keywords for duplicate issue detection.
396+
397+ Returns a list of keywords to search for similar issues.
398+ """
399+ keywords = set ()
400+
401+ # Find the most recent error from logs
402+ last_error_log = next ((log for log in reversed (recent_logs ) if log .get ("error_message" )), None )
403+
404+ if last_error_log :
405+ tool_name = last_error_log .get ("tool_name" )
406+ if tool_name :
407+ keywords .add (tool_name )
408+
409+ error_msg = last_error_log .get ("error_message" , "" ).lower ()
410+ # Common error patterns
411+ if "connection" in error_msg :
412+ keywords .add ("connection" )
413+ if "timeout" in error_msg :
414+ keywords .add ("timeout" )
415+ if "authentication" in error_msg or "auth" in error_msg :
416+ keywords .add ("authentication" )
417+ if "not found" in error_msg :
418+ keywords .add ("not found" )
419+
420+ # Add connection-based keywords
421+ conn_status = diagnostic_info .get ("connection_status" , "Unknown" )
422+ if "Error" in conn_status or "Failed" in conn_status :
423+ keywords .add ("connection" )
424+
425+ # Default to generic search if no specific keywords
426+ if not keywords :
427+ keywords .add ("bug" )
428+
429+ return list (keywords )
430+
431+
325432def _generate_runtime_bug_template (
326433 diagnostic_info : dict [str , Any ],
327434 log_summary : str ,
@@ -365,7 +472,7 @@ def _generate_runtime_bug_template(
365472> All environment info and logs below were collected automatically.
366473
367474**Submit this report at:**
368- https://github.com/homeassistant-ai/ha-mcp/issues/new?template=runtime_bug.md
475+ { RUNTIME_BUG_URL }
369476
370477---
371478
@@ -456,7 +563,7 @@ def _generate_agent_behavior_template(
456563> Tool call history was collected automatically to help analyze agent behavior.
457564
458565**Submit this feedback at:**
459- https://github.com/homeassistant-ai/ha-mcp/issues/new?template=agent_behavior_feedback.md
566+ { AGENT_BEHAVIOR_URL }
460567
461568---
462569
0 commit comments