Coverage for src/qdrant_loader_mcp_server/mcp/formatters/basic.py: 100%

61 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-08 06:06 +0000

1""" 

2Basic Result Formatters - Core Search Result Formatting. 

3 

4This module handles basic formatting of search results, attachments, 

5and hierarchical results for display in the MCP interface. 

6""" 

7 

8from ...search.components.search_result_models import HybridSearchResult 

9 

10 

11class BasicResultFormatters: 

12 """Handles basic result formatting operations.""" 

13 

14 @staticmethod 

15 def _format_common_fields( 

16 result: HybridSearchResult, is_attachment_view: bool = False 

17 ) -> str: 

18 """Build the base formatted string for a search result. 

19 

20 This consolidates shared formatting between standard search results and 

21 attachment-focused views while preserving the original output order and 

22 conditional branches. 

23 """ 

24 formatted_result = f"Score: {result.score}\n" 

25 formatted_result += f"Text: {result.text}\n" 

26 formatted_result += f"Source: {result.source_type}" 

27 

28 if result.source_title: 

29 formatted_result += f" - {result.source_title}" 

30 

31 # Project information (only shown in non-attachment view to preserve behavior) 

32 if not is_attachment_view: 

33 project_info = result.get_project_info() 

34 if project_info: 

35 formatted_result += f"\n🏗️ {project_info}" 

36 

37 # Attachment info (shown if viewing attachments or the result itself is an attachment) 

38 if is_attachment_view or result.is_attachment: 

39 formatted_result += "\n📎 Attachment" 

40 if result.original_filename: 

41 formatted_result += f": {result.original_filename}" 

42 if result.attachment_context: 

43 formatted_result += f"\n📋 {result.attachment_context}" 

44 if result.parent_document_title: 

45 formatted_result += f"\n📄 Attached to: {result.parent_document_title}" 

46 

47 # Confluence breadcrumb path 

48 if result.source_type == "confluence" and result.breadcrumb_text: 

49 formatted_result += f"\n📍 Path: {result.breadcrumb_text}" 

50 

51 # Source URL appended inline 

52 if result.source_url: 

53 formatted_result += f" ({result.source_url})" 

54 

55 if result.file_path: 

56 formatted_result += f"\nFile: {result.file_path}" 

57 

58 if result.repo_name: 

59 formatted_result += f"\nRepo: {result.repo_name}" 

60 

61 # Additional hierarchy info for Confluence 

62 hierarchy_context = getattr(result, "hierarchy_context", None) 

63 if result.source_type == "confluence" and hierarchy_context: 

64 formatted_result += f"\n🏗️ {hierarchy_context}" 

65 

66 # Parent info (for hierarchy, not for attachment items themselves) 

67 if result.parent_title and not result.is_attachment: 

68 formatted_result += f"\n⬆️ Parent: {result.parent_title}" 

69 

70 # Children count 

71 if result.has_children(): 

72 formatted_result += f"\n⬇️ Children: {result.children_count}" 

73 

74 return formatted_result 

75 

76 @staticmethod 

77 def format_search_result(result: HybridSearchResult) -> str: 

78 """Format a search result for display.""" 

79 return BasicResultFormatters._format_common_fields( 

80 result, is_attachment_view=False 

81 ) 

82 

83 @staticmethod 

84 def format_attachment_search_result(result: HybridSearchResult) -> str: 

85 """Format an attachment search result for display.""" 

86 return BasicResultFormatters._format_common_fields( 

87 result, is_attachment_view=True 

88 ) 

89 

90 @staticmethod 

91 def format_hierarchical_results( 

92 organized_results: dict[str, list[HybridSearchResult]], 

93 ) -> str: 

94 """Format hierarchically organized results for display.""" 

95 formatted_sections = [] 

96 

97 for root_title, results in organized_results.items(): 

98 section = f"📁 **{root_title}** ({len(results)} results)\n" 

99 

100 for result in results: 

101 indent = " " * (getattr(result, "depth", 0) or 0) 

102 section += f"{indent}📄 {result.source_title}" 

103 if hasattr(result, "hierarchy_context") and result.hierarchy_context: 

104 section += f" | {result.hierarchy_context}" 

105 section += f" (Score: {result.score:.3f})\n" 

106 

107 # Add a snippet of the content 

108 content_snippet = ( 

109 result.text[:150] + "..." if len(result.text) > 150 else result.text 

110 ) 

111 section += f"{indent} {content_snippet}\n" 

112 

113 if result.source_url: 

114 section += f"{indent} 🔗 {result.source_url}\n" 

115 section += "\n" 

116 

117 formatted_sections.append(section) 

118 

119 return ( 

120 f"Found {sum(len(results) for results in organized_results.values())} results organized by hierarchy:\n\n" 

121 + "\n".join(formatted_sections) 

122 )