jarvis-ai-assistant 0.1.103__py3-none-any.whl → 0.1.105__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jarvis-ai-assistant might be problematic. Click here for more details.

Files changed (65) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +124 -67
  3. jarvis/jarvis_code_agent/code_agent.py +133 -22
  4. jarvis/jarvis_code_agent/file_select.py +4 -6
  5. jarvis/jarvis_code_agent/patch.py +6 -7
  6. jarvis/jarvis_code_agent/relevant_files.py +163 -41
  7. jarvis/jarvis_codebase/main.py +43 -29
  8. jarvis/jarvis_lsp/base.py +143 -0
  9. jarvis/jarvis_lsp/cpp.py +134 -0
  10. jarvis/jarvis_lsp/go.py +140 -0
  11. jarvis/jarvis_lsp/python.py +135 -0
  12. jarvis/jarvis_lsp/registry.py +234 -0
  13. jarvis/jarvis_lsp/rust.py +142 -0
  14. jarvis/jarvis_platform/__init__.py +3 -0
  15. jarvis/{models → jarvis_platform}/ai8.py +1 -1
  16. jarvis/{models → jarvis_platform}/kimi.py +1 -1
  17. jarvis/{models → jarvis_platform}/ollama.py +1 -1
  18. jarvis/{models → jarvis_platform}/openai.py +1 -1
  19. jarvis/{models → jarvis_platform}/oyi.py +1 -1
  20. jarvis/{models → jarvis_platform}/registry.py +11 -11
  21. jarvis/{jarvis_platform → jarvis_platform_manager}/main.py +2 -2
  22. jarvis/jarvis_rag/main.py +8 -8
  23. jarvis/jarvis_smart_shell/main.py +3 -3
  24. jarvis/jarvis_tools/__init__.py +0 -0
  25. jarvis/{tools → jarvis_tools}/ask_codebase.py +1 -4
  26. jarvis/{tools → jarvis_tools}/ask_user.py +1 -1
  27. jarvis/{tools → jarvis_tools}/chdir.py +2 -37
  28. jarvis/jarvis_tools/code_review.py +236 -0
  29. jarvis/jarvis_tools/create_code_agent.py +115 -0
  30. jarvis/{tools → jarvis_tools}/create_sub_agent.py +1 -1
  31. jarvis/jarvis_tools/deep_thinking.py +160 -0
  32. jarvis/jarvis_tools/deep_thinking_agent.py +146 -0
  33. jarvis/{tools → jarvis_tools}/git_commiter.py +3 -3
  34. jarvis/jarvis_tools/lsp_find_definition.py +134 -0
  35. jarvis/jarvis_tools/lsp_find_references.py +111 -0
  36. jarvis/jarvis_tools/lsp_get_diagnostics.py +121 -0
  37. jarvis/jarvis_tools/lsp_get_document_symbols.py +87 -0
  38. jarvis/jarvis_tools/lsp_prepare_rename.py +130 -0
  39. jarvis/jarvis_tools/lsp_validate_edit.py +141 -0
  40. jarvis/{tools → jarvis_tools}/methodology.py +6 -1
  41. jarvis/{tools → jarvis_tools}/rag.py +1 -1
  42. jarvis/{tools → jarvis_tools}/read_code.py +0 -31
  43. jarvis/{tools → jarvis_tools}/registry.py +6 -5
  44. jarvis/{tools → jarvis_tools}/search.py +2 -2
  45. jarvis/utils.py +71 -28
  46. {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/METADATA +98 -62
  47. jarvis_ai_assistant-0.1.105.dist-info/RECORD +62 -0
  48. {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/entry_points.txt +4 -4
  49. jarvis/models/__init__.py +0 -3
  50. jarvis/tools/code_review.py +0 -163
  51. jarvis/tools/create_code_sub_agent.py +0 -30
  52. jarvis/tools/create_code_test_agent.py +0 -115
  53. jarvis/tools/create_ctags_agent.py +0 -176
  54. jarvis/tools/find_in_codebase.py +0 -108
  55. jarvis_ai_assistant-0.1.103.dist-info/RECORD +0 -51
  56. /jarvis/{models → jarvis_platform}/base.py +0 -0
  57. /jarvis/{tools → jarvis_platform_manager}/__init__.py +0 -0
  58. /jarvis/{tools → jarvis_tools}/base.py +0 -0
  59. /jarvis/{tools → jarvis_tools}/execute_shell.py +0 -0
  60. /jarvis/{tools → jarvis_tools}/file_operation.py +0 -0
  61. /jarvis/{tools → jarvis_tools}/read_webpage.py +0 -0
  62. /jarvis/{tools → jarvis_tools}/select_code_files.py +0 -0
  63. {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/LICENSE +0 -0
  64. {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/WHEEL +0 -0
  65. {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,160 @@
1
+ import os
2
+ from typing import Dict, Any
3
+ from jarvis.jarvis_platform.registry import PlatformRegistry
4
+ from jarvis.utils import OutputType, PrettyOutput
5
+
6
+ class DeepThinkingTool:
7
+ """Tool for deep thinking about user requirements using thinking platform."""
8
+
9
+ name = "deep_thinking"
10
+ description = "Analyze and think deeply about user requirements"
11
+ parameters = {
12
+ "requirement": "The requirement or question to think about",
13
+ "mode": {
14
+ "type": "string",
15
+ "description": "Thinking mode: analysis/solution/critique",
16
+ "enum": ["analysis", "solution", "critique"],
17
+ "default": "analysis"
18
+ }
19
+ }
20
+
21
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
22
+ try:
23
+ requirement = args.get("requirement", "")
24
+ mode = args.get("mode", "analysis")
25
+
26
+ if not requirement:
27
+ return {
28
+ "success": False,
29
+ "stderr": "Requirement must be provided",
30
+ "stdout": ""
31
+ }
32
+
33
+ # Get thinking platform
34
+ platform = PlatformRegistry().get_thinking_platform()
35
+
36
+ # Build prompt based on mode
37
+ if mode == "analysis":
38
+ prompt = f"""Please analyze this requirement deeply. Consider:
39
+
40
+ 1. Core Objectives:
41
+ - What is the fundamental goal?
42
+ - What are the key requirements?
43
+ - What are the implicit needs?
44
+
45
+ 2. Scope Analysis:
46
+ - What is included/excluded?
47
+ - What are the boundaries?
48
+ - What are potential edge cases?
49
+
50
+ 3. Challenges:
51
+ - What are the technical challenges?
52
+ - What are potential risks?
53
+ - What needs special attention?
54
+
55
+ 4. Dependencies:
56
+ - What are the prerequisites?
57
+ - What systems will be affected?
58
+ - What integrations are needed?
59
+
60
+ Requirement to analyze:
61
+ {requirement}
62
+
63
+ Please provide a structured analysis."""
64
+
65
+ elif mode == "solution":
66
+ prompt = f"""Please think deeply about potential solutions. Consider:
67
+
68
+ 1. Solution Approaches:
69
+ - What are possible approaches?
70
+ - What are the pros/cons of each?
71
+ - What is the recommended approach?
72
+
73
+ 2. Implementation Strategy:
74
+ - How should this be implemented?
75
+ - What are the key steps?
76
+ - What is the suggested order?
77
+
78
+ 3. Technical Considerations:
79
+ - What technologies should be used?
80
+ - What patterns would work best?
81
+ - What should be avoided?
82
+
83
+ 4. Risk Mitigation:
84
+ - How to handle potential issues?
85
+ - What safeguards are needed?
86
+ - What should be tested carefully?
87
+
88
+ Requirement to solve:
89
+ {requirement}
90
+
91
+ Please provide a structured solution plan."""
92
+
93
+ else: # critique
94
+ prompt = f"""Please critique this requirement carefully. Consider:
95
+
96
+ 1. Clarity:
97
+ - Is it clearly defined?
98
+ - Are there ambiguities?
99
+ - What needs clarification?
100
+
101
+ 2. Completeness:
102
+ - Are all aspects covered?
103
+ - What might be missing?
104
+ - Are edge cases considered?
105
+
106
+ 3. Feasibility:
107
+ - Is it technically feasible?
108
+ - Are there resource constraints?
109
+ - What are potential blockers?
110
+
111
+ 4. Improvements:
112
+ - How could it be better?
113
+ - What should be added/removed?
114
+ - What alternatives exist?
115
+
116
+ Requirement to critique:
117
+ {requirement}
118
+
119
+ Please provide a structured critique."""
120
+
121
+ # Get thinking result
122
+ result = platform.chat_until_success(prompt)
123
+
124
+ return {
125
+ "success": True,
126
+ "stdout": result,
127
+ "stderr": ""
128
+ }
129
+
130
+ except Exception as e:
131
+ return {
132
+ "success": False,
133
+ "stderr": f"Thinking failed: {str(e)}",
134
+ "stdout": ""
135
+ }
136
+
137
+ def main():
138
+ """CLI entry point"""
139
+ import argparse
140
+
141
+ parser = argparse.ArgumentParser(description='Deep thinking tool')
142
+ parser.add_argument('requirement', help='Requirement to think about')
143
+ parser.add_argument('--mode', choices=['analysis', 'solution', 'critique'],
144
+ default='analysis', help='Thinking mode')
145
+
146
+ args = parser.parse_args()
147
+
148
+ tool = DeepThinkingTool()
149
+ result = tool.execute({
150
+ "requirement": args.requirement,
151
+ "mode": args.mode
152
+ })
153
+
154
+ if result["success"]:
155
+ PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
156
+ else:
157
+ PrettyOutput.print(result["stderr"], OutputType.ERROR)
158
+
159
+ if __name__ == "__main__":
160
+ main()
@@ -0,0 +1,146 @@
1
+ import os
2
+ from typing import Dict, Any
3
+ from jarvis.agent import Agent
4
+ from jarvis.jarvis_platform.registry import PlatformRegistry
5
+ from jarvis.jarvis_tools.registry import ToolRegistry
6
+ from jarvis.utils import OutputType, PrettyOutput
7
+
8
+ class DeepThinkingAgentTool:
9
+ """Tool for deep thinking using an agent with thinking platform."""
10
+
11
+ name = "deep_thinking_agent"
12
+ description = "Use an agent to think deeply about problems and solutions"
13
+ parameters = {
14
+ "question": "The question or problem to think about"
15
+ }
16
+
17
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
18
+ try:
19
+ question = args.get("question", "")
20
+ if not question:
21
+ return {
22
+ "success": False,
23
+ "stderr": "Question must be provided",
24
+ "stdout": ""
25
+ }
26
+
27
+ # Initialize tool registry
28
+ tool_registry = ToolRegistry()
29
+ tool_registry.dont_use_tools([
30
+ "deep_thinking_agent"
31
+ ])
32
+
33
+ # Define system prompt for thinking agent
34
+ system_prompt = """You are a deep thinking agent that carefully analyzes problems and proposes solutions.
35
+
36
+ THINKING PROCESS:
37
+ 1. Initial Analysis
38
+ ```
39
+ Thought: Let me first understand the core problem...
40
+ Action: Use deep_thinking with mode=analysis
41
+ Observation: The analysis shows...
42
+
43
+ Thought: I need more information about...
44
+ Action: Use appropriate tool (search/ask_user/ask_codebase)
45
+ Observation: Found that...
46
+ ```
47
+
48
+ 2. Solution Exploration
49
+ ```
50
+ Thought: Let me explore possible solutions...
51
+ Action: Use deep_thinking with mode=solution
52
+ Observation: The potential solutions are...
53
+
54
+ Thought: I should validate these approaches...
55
+ Action: Use appropriate tool to verify
56
+ Observation: Verification shows...
57
+ ```
58
+
59
+ 3. Critical Review
60
+ ```
61
+ Thought: Let me critique the proposed solution...
62
+ Action: Use deep_thinking with mode=critique
63
+ Observation: The critique reveals...
64
+
65
+ Thought: These points need addressing...
66
+ Action: Revise solution based on critique
67
+ Observation: The improved solution...
68
+ ```
69
+
70
+ 4. Final Recommendation
71
+ ```
72
+ Thought: Synthesize all findings...
73
+ Action: Compile final recommendation
74
+ Output: Detailed solution with rationale
75
+ ```
76
+
77
+ GUIDELINES:
78
+ - Use deep_thinking tool for structured analysis
79
+ - Validate assumptions with search/ask_user
80
+ - Consider multiple perspectives
81
+ - Provide evidence for conclusions
82
+ - Be thorough but practical
83
+ - Focus on actionable recommendations
84
+
85
+ Please proceed with the analysis and provide a comprehensive response."""
86
+
87
+ # Create agent with thinking platform
88
+ agent = Agent(
89
+ system_prompt=system_prompt,
90
+ name="DeepThinkingAgent",
91
+ tool_registry=tool_registry,
92
+ platform=PlatformRegistry().get_thinking_platform(),
93
+ auto_complete=True,
94
+ is_sub_agent=True,
95
+ summary_prompt="""Please provide a structured summary of your thinking process and conclusions:
96
+
97
+ <THINKING_SUMMARY>
98
+ Analysis:
99
+ [Key findings from analysis]
100
+
101
+ Solutions:
102
+ [Proposed solutions and rationale]
103
+
104
+ Critique:
105
+ [Critical considerations]
106
+
107
+ Recommendation:
108
+ [Final recommendation with justification]
109
+ </THINKING_SUMMARY>"""
110
+ )
111
+
112
+ # Run agent
113
+ result = agent.run(question)
114
+
115
+ return {
116
+ "success": True,
117
+ "stdout": result,
118
+ "stderr": ""
119
+ }
120
+
121
+ except Exception as e:
122
+ return {
123
+ "success": False,
124
+ "stderr": f"Deep thinking failed: {str(e)}",
125
+ "stdout": ""
126
+ }
127
+
128
+ def main():
129
+ """CLI entry point"""
130
+ import argparse
131
+
132
+ parser = argparse.ArgumentParser(description='Deep thinking agent')
133
+ parser.add_argument('question', help='Question or problem to think about')
134
+
135
+ args = parser.parse_args()
136
+
137
+ tool = DeepThinkingAgentTool()
138
+ result = tool.execute({"question": args.question})
139
+
140
+ if result["success"]:
141
+ PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
142
+ else:
143
+ PrettyOutput.print(result["stderr"], OutputType.ERROR)
144
+
145
+ if __name__ == "__main__":
146
+ main()
@@ -4,8 +4,8 @@ from typing import Dict, Any
4
4
 
5
5
  import yaml
6
6
  from jarvis.agent import Agent
7
- from jarvis.models.registry import PlatformRegistry
8
- from jarvis.tools.registry import ToolRegistry
7
+ from jarvis.jarvis_platform.registry import PlatformRegistry
8
+ from jarvis.jarvis_tools.registry import ToolRegistry
9
9
  from jarvis.utils import OutputType, PrettyOutput, init_env
10
10
  import sys
11
11
 
@@ -31,7 +31,7 @@ class GitCommitTool:
31
31
  os.system("git add .")
32
32
  PrettyOutput.print("Get diff...", OutputType.SYSTEM)
33
33
  diff = os.popen("git diff --cached --exit-code").read()
34
- PrettyOutput.print(diff, OutputType.CODE)
34
+ PrettyOutput.print(diff, OutputType.CODE, lang="diff")
35
35
  prompt = f'''Please generate a commit message for the following changes.
36
36
  Format:
37
37
  <COMMIT_MESSAGE>
@@ -0,0 +1,134 @@
1
+ import os
2
+ from typing import Dict, Any
3
+ from jarvis.jarvis_lsp.registry import LSPRegistry
4
+
5
+ class LSPFindDefinitionTool:
6
+ """Tool for finding symbol definitions in code using LSP."""
7
+
8
+ name = "lsp_find_definition"
9
+ description = "Find the definition of a symbol in code"
10
+ parameters = {
11
+ "file_path": "Path to the file containing the symbol",
12
+ "line": "Line number (0-based) of the symbol",
13
+ "character": "Character position in the line",
14
+ "language": f"Programming language of the file ({', '.join(LSPRegistry.get_global_lsp_registry().get_supported_languages())})"
15
+ }
16
+
17
+ @staticmethod
18
+ def check() -> bool:
19
+ """Check if any LSP server is available."""
20
+ registry = LSPRegistry.get_global_lsp_registry()
21
+ return len(registry.get_supported_languages()) > 0
22
+
23
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
24
+ """Execute the tool."""
25
+ file_path = args.get("file_path", "")
26
+ line = args.get("line", None)
27
+ character = args.get("character", None)
28
+ language = args.get("language", "")
29
+
30
+ # Validate inputs
31
+ if not all([file_path, line is not None, character is not None, language]):
32
+ return {
33
+ "success": False,
34
+ "stderr": "All parameters (file_path, line, character, language) must be provided",
35
+ "stdout": ""
36
+ }
37
+
38
+ try:
39
+ line = int(line)
40
+ character = int(character)
41
+ except ValueError:
42
+ return {
43
+ "success": False,
44
+ "stderr": "Line and character must be integers",
45
+ "stdout": ""
46
+ }
47
+
48
+ if not os.path.exists(file_path):
49
+ return {
50
+ "success": False,
51
+ "stderr": f"File not found: {file_path}",
52
+ "stdout": ""
53
+ }
54
+
55
+ # Get LSP instance
56
+ registry = LSPRegistry.get_global_lsp_registry()
57
+ lsp = registry.create_lsp(language)
58
+
59
+ if not lsp:
60
+ return {
61
+ "success": False,
62
+ "stderr": f"No LSP support for language: {language}",
63
+ "stdout": ""
64
+ }
65
+
66
+ try:
67
+ # Initialize LSP
68
+ if not lsp.initialize(os.path.dirname(os.path.abspath(file_path))):
69
+ return {
70
+ "success": False,
71
+ "stderr": "LSP initialization failed",
72
+ "stdout": ""
73
+ }
74
+
75
+ # Get symbol at position
76
+ symbol = LSPRegistry.get_text_at_position(file_path, line, character)
77
+ if not symbol:
78
+ return {
79
+ "success": False,
80
+ "stderr": f"No symbol found at position {line}:{character}",
81
+ "stdout": ""
82
+ }
83
+
84
+ # Find definition
85
+ defn = lsp.find_definition(file_path, (line, character))
86
+
87
+ if not defn:
88
+ return {
89
+ "success": True,
90
+ "stdout": f"No definition found for '{symbol}'",
91
+ "stderr": ""
92
+ }
93
+
94
+ # Format output
95
+ def_line = defn["range"]["start"]["line"]
96
+ def_char = defn["range"]["start"]["character"]
97
+ context = LSPRegistry.get_line_at_position(defn["uri"], def_line).strip()
98
+
99
+ output = [
100
+ f"Definition of '{symbol}':",
101
+ f"File: {defn['uri']}",
102
+ f"Line {def_line + 1}, Col {def_char + 1}: {context}"
103
+ ]
104
+
105
+ # Get a few lines of context around the definition
106
+ try:
107
+ with open(defn["uri"], 'r') as f:
108
+ lines = f.readlines()
109
+ start = max(0, def_line - 2)
110
+ end = min(len(lines), def_line + 3)
111
+
112
+ if start < def_line:
113
+ output.append("\nContext:")
114
+ for i in range(start, end):
115
+ prefix = ">" if i == def_line else " "
116
+ output.append(f"{prefix} {i+1:4d} | {lines[i].rstrip()}")
117
+ except Exception:
118
+ pass
119
+
120
+ return {
121
+ "success": True,
122
+ "stdout": "\n".join(output),
123
+ "stderr": ""
124
+ }
125
+
126
+ except Exception as e:
127
+ return {
128
+ "success": False,
129
+ "stderr": f"Error finding definition: {str(e)}",
130
+ "stdout": ""
131
+ }
132
+ finally:
133
+ if lsp:
134
+ lsp.shutdown()
@@ -0,0 +1,111 @@
1
+ import os
2
+ from typing import Dict, Any
3
+ from jarvis.jarvis_lsp.registry import LSPRegistry
4
+
5
+ class LSPFindReferencesTool:
6
+ """Tool for finding references to symbols in code using LSP."""
7
+
8
+ name = "lsp_find_references"
9
+ description = "Find all references to a symbol in code"
10
+ parameters = {
11
+ "file_path": "Path to the file containing the symbol",
12
+ "line": "Line number (0-based) of the symbol",
13
+ "character": "Character position in the line",
14
+ "language": f"Programming language of the file ({', '.join(LSPRegistry.get_global_lsp_registry().get_supported_languages())})"
15
+ }
16
+
17
+ @staticmethod
18
+ def check() -> bool:
19
+ """Check if any LSP server is available."""
20
+ registry = LSPRegistry.get_global_lsp_registry()
21
+ return len(registry.get_supported_languages()) > 0
22
+
23
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
24
+ """Execute the tool."""
25
+ file_path = args.get("file_path", "")
26
+ line = args.get("line", None)
27
+ character = args.get("character", None)
28
+ language = args.get("language", "")
29
+
30
+ # Validate inputs
31
+ if not all([file_path, line is not None, character is not None, language]):
32
+ return {
33
+ "success": False,
34
+ "stderr": "All parameters (file_path, line, character, language) must be provided",
35
+ "stdout": ""
36
+ }
37
+
38
+ try:
39
+ line = int(line)
40
+ character = int(character)
41
+ except ValueError:
42
+ return {
43
+ "success": False,
44
+ "stderr": "Line and character must be integers",
45
+ "stdout": ""
46
+ }
47
+
48
+ if not os.path.exists(file_path):
49
+ return {
50
+ "success": False,
51
+ "stderr": f"File not found: {file_path}",
52
+ "stdout": ""
53
+ }
54
+
55
+ # Get LSP instance
56
+ registry = LSPRegistry.get_global_lsp_registry()
57
+ lsp = registry.create_lsp(language)
58
+
59
+ if not lsp:
60
+ return {
61
+ "success": False,
62
+ "stderr": f"No LSP support for language: {language}",
63
+ "stdout": ""
64
+ }
65
+
66
+ try:
67
+ # Initialize LSP
68
+ if not lsp.initialize(os.path.dirname(os.path.abspath(file_path))):
69
+ return {
70
+ "success": False,
71
+ "stderr": "LSP initialization failed",
72
+ "stdout": ""
73
+ }
74
+
75
+ # Get symbol at position
76
+ symbol = LSPRegistry.get_text_at_position(file_path, line, character)
77
+ if not symbol:
78
+ return {
79
+ "success": False,
80
+ "stderr": f"No symbol found at position {line}:{character}",
81
+ "stdout": ""
82
+ }
83
+
84
+ # Find references
85
+ refs = lsp.find_references(file_path, (line, character))
86
+
87
+ # Format output
88
+ output = [f"References to '{symbol}':\n"]
89
+ for ref in refs:
90
+ ref_line = ref["range"]["start"]["line"]
91
+ ref_char = ref["range"]["start"]["character"]
92
+ context = LSPRegistry.get_line_at_position(ref["uri"], ref_line).strip()
93
+ output.append(f"File: {ref['uri']}")
94
+ output.append(f"Line {ref_line + 1}, Col {ref_char + 1}: {context}")
95
+ output.append("-" * 40)
96
+
97
+ return {
98
+ "success": True,
99
+ "stdout": "\n".join(output) if len(refs) > 0 else f"No references found for '{symbol}'",
100
+ "stderr": ""
101
+ }
102
+
103
+ except Exception as e:
104
+ return {
105
+ "success": False,
106
+ "stderr": f"Error finding references: {str(e)}",
107
+ "stdout": ""
108
+ }
109
+ finally:
110
+ if lsp:
111
+ lsp.shutdown()
@@ -0,0 +1,121 @@
1
+ import os
2
+ from typing import Dict, Any
3
+ from jarvis.jarvis_lsp.registry import LSPRegistry
4
+
5
+ class LSPGetDiagnosticsTool:
6
+ """Tool for getting diagnostics (errors, warnings) from code using LSP."""
7
+
8
+ name = "lsp_get_diagnostics"
9
+ description = "Get diagnostic information (errors, warnings) from code files"
10
+ parameters = {
11
+ "file_path": "Path to the file to analyze",
12
+ "language": f"Programming language of the file ({', '.join(LSPRegistry.get_global_lsp_registry().get_supported_languages())})"
13
+ }
14
+
15
+ @staticmethod
16
+ def check() -> bool:
17
+ """Check if any LSP server is available."""
18
+ registry = LSPRegistry.get_global_lsp_registry()
19
+ return len(registry.get_supported_languages()) > 0
20
+
21
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
22
+ """Execute the tool."""
23
+ file_path = args.get("file_path", "")
24
+ language = args.get("language", "")
25
+
26
+ # Validate inputs
27
+ if not all([file_path, language]):
28
+ return {
29
+ "success": False,
30
+ "stderr": "Both file_path and language must be provided",
31
+ "stdout": ""
32
+ }
33
+
34
+ if not os.path.exists(file_path):
35
+ return {
36
+ "success": False,
37
+ "stderr": f"File not found: {file_path}",
38
+ "stdout": ""
39
+ }
40
+
41
+ # Get LSP instance
42
+ registry = LSPRegistry.get_global_lsp_registry()
43
+ lsp = registry.create_lsp(language)
44
+
45
+ if not lsp:
46
+ return {
47
+ "success": False,
48
+ "stderr": f"No LSP support for language: {language}",
49
+ "stdout": ""
50
+ }
51
+
52
+ try:
53
+ # Initialize LSP
54
+ if not lsp.initialize(os.path.dirname(os.path.abspath(file_path))):
55
+ return {
56
+ "success": False,
57
+ "stderr": "LSP initialization failed",
58
+ "stdout": ""
59
+ }
60
+
61
+ # Get diagnostics
62
+ diagnostics = lsp.get_diagnostics(file_path)
63
+
64
+ if not diagnostics:
65
+ return {
66
+ "success": True,
67
+ "stdout": "No issues found in the file",
68
+ "stderr": ""
69
+ }
70
+
71
+ # Format output
72
+ output = ["Diagnostics:"]
73
+ severity_map = {1: "Error", 2: "Warning", 3: "Info", 4: "Hint"}
74
+
75
+ # Sort diagnostics by severity and line number
76
+ sorted_diagnostics = sorted(
77
+ diagnostics,
78
+ key=lambda x: (x["severity"], x["range"]["start"]["line"])
79
+ )
80
+
81
+ for diag in sorted_diagnostics:
82
+ severity = severity_map.get(diag["severity"], "Unknown")
83
+ start = diag["range"]["start"]
84
+ line = LSPRegistry.get_line_at_position(file_path, start["line"]).strip()
85
+
86
+ output.extend([
87
+ f"\n{severity} at line {start['line'] + 1}, column {start['character'] + 1}:",
88
+ f"Message: {diag['message']}",
89
+ f"Code: {line}",
90
+ "-" * 60
91
+ ])
92
+
93
+ # Add related information if available
94
+ if diag.get("relatedInformation"):
95
+ output.append("Related information:")
96
+ for info in diag["relatedInformation"]:
97
+ info_line = LSPRegistry.get_line_at_position(
98
+ info["location"]["uri"],
99
+ info["location"]["range"]["start"]["line"]
100
+ ).strip()
101
+ output.extend([
102
+ f" - {info['message']}",
103
+ f" at {info['location']['uri']}:{info['location']['range']['start']['line'] + 1}",
104
+ f" {info_line}"
105
+ ])
106
+
107
+ return {
108
+ "success": True,
109
+ "stdout": "\n".join(output),
110
+ "stderr": ""
111
+ }
112
+
113
+ except Exception as e:
114
+ return {
115
+ "success": False,
116
+ "stderr": f"Error getting diagnostics: {str(e)}",
117
+ "stdout": ""
118
+ }
119
+ finally:
120
+ if lsp:
121
+ lsp.shutdown()