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
@@ -1,7 +1,7 @@
1
1
  from typing import Dict, List, Tuple
2
2
  import os
3
3
  from openai import OpenAI
4
- from jarvis.models.base import BasePlatform
4
+ from jarvis.jarvis_platform.base import BasePlatform
5
5
  from jarvis.utils import PrettyOutput, OutputType
6
6
 
7
7
  class OpenAIModel(BasePlatform):
@@ -1,7 +1,7 @@
1
1
  import mimetypes
2
2
  import os
3
3
  from typing import Dict, List, Tuple
4
- from jarvis.models.base import BasePlatform
4
+ from jarvis.jarvis_platform.base import BasePlatform
5
5
  from jarvis.utils import PrettyOutput, OutputType, get_max_context_length
6
6
  import requests
7
7
  import json
@@ -3,8 +3,8 @@ import inspect
3
3
  import os
4
4
  import sys
5
5
  from typing import Dict, Type, Optional, List
6
- from jarvis.models.base import BasePlatform
7
- from jarvis.utils import PrettyOutput, OutputType
6
+ from jarvis.jarvis_platform.base import BasePlatform
7
+ from jarvis.utils import PrettyOutput, OutputType, get_cheap_model_name, get_cheap_platform_name, get_codegen_model_name, get_codegen_platform_name, get_normal_model_name, get_normal_platform_name, get_thinking_model_name, get_thinking_platform_name
8
8
 
9
9
  REQUIRED_METHODS = [
10
10
  ('chat', ['message']), # 方法名和参数列表
@@ -98,7 +98,7 @@ class PlatformRegistry:
98
98
  # 获取目录的包名
99
99
  package_name = None
100
100
  if directory == os.path.dirname(__file__):
101
- package_name = "jarvis.models"
101
+ package_name = "jarvis.jarvis_platform"
102
102
 
103
103
  # 添加目录到Python路径
104
104
  if directory not in sys.path:
@@ -155,29 +155,29 @@ class PlatformRegistry:
155
155
 
156
156
 
157
157
  def get_normal_platform(self) -> BasePlatform:
158
- platform_name = os.environ.get("JARVIS_PLATFORM", "kimi")
159
- model_name = os.environ.get("JARVIS_MODEL", "kimi")
158
+ platform_name = get_normal_platform_name()
159
+ model_name = get_normal_model_name()
160
160
  platform = self.create_platform(platform_name)
161
161
  platform.set_model_name(model_name) # type: ignore
162
162
  return platform # type: ignore
163
163
 
164
164
  def get_codegen_platform(self) -> BasePlatform:
165
- platform_name = os.environ.get("JARVIS_CODEGEN_PLATFORM", os.environ.get("JARVIS_PLATFORM", "kimi"))
166
- model_name = os.environ.get("JARVIS_CODEGEN_MODEL", os.environ.get("JARVIS_MODEL", "kimi"))
165
+ platform_name = get_codegen_platform_name()
166
+ model_name = get_codegen_model_name()
167
167
  platform = self.create_platform(platform_name)
168
168
  platform.set_model_name(model_name) # type: ignore
169
169
  return platform # type: ignore
170
170
 
171
171
  def get_cheap_platform(self) -> BasePlatform:
172
- platform_name = os.environ.get("JARVIS_CHEAP_PLATFORM", os.environ.get("JARVIS_PLATFORM", "kimi"))
173
- model_name = os.environ.get("JARVIS_CHEAP_MODEL", os.environ.get("JARVIS_MODEL", "kimi"))
172
+ platform_name = get_cheap_platform_name()
173
+ model_name = get_cheap_model_name()
174
174
  platform = self.create_platform(platform_name)
175
175
  platform.set_model_name(model_name) # type: ignore
176
176
  return platform # type: ignore
177
177
 
178
178
  def get_thinking_platform(self) -> BasePlatform:
179
- platform_name = os.environ.get("JARVIS_THINKING_PLATFORM", os.environ.get("JARVIS_PLATFORM", "kimi"))
180
- model_name = os.environ.get("JARVIS_THINKING_MODEL", os.environ.get("JARVIS_MODEL", "kimi"))
179
+ platform_name = get_thinking_platform_name()
180
+ model_name = get_thinking_model_name()
181
181
  platform = self.create_platform(platform_name)
182
182
  platform.set_model_name(model_name) # type: ignore
183
183
  return platform # type: ignore
@@ -1,4 +1,4 @@
1
- from jarvis.models.registry import PlatformRegistry
1
+ from jarvis.jarvis_platform.registry import PlatformRegistry
2
2
  from jarvis.utils import PrettyOutput, OutputType, init_env, get_multiline_input
3
3
 
4
4
  def list_platforms():
@@ -29,7 +29,7 @@ def list_platforms():
29
29
  output += f" • {model_name} - {description}\n"
30
30
  else:
31
31
  output += f" • {model_name}\n"
32
- PrettyOutput.print(output, OutputType.SUCCESS)
32
+ PrettyOutput.print(output, OutputType.SUCCESS, lang="markdown")
33
33
  else:
34
34
  PrettyOutput.print(" • No available model information", OutputType.WARNING)
35
35
 
jarvis/jarvis_rag/main.py CHANGED
@@ -3,14 +3,14 @@ import numpy as np
3
3
  import faiss
4
4
  from typing import List, Tuple, Optional, Dict
5
5
  import pickle
6
- from jarvis.utils import OutputType, PrettyOutput, get_file_md5, get_max_context_length, load_embedding_model, load_rerank_model
6
+ from jarvis.utils import OutputType, PrettyOutput, get_context_window, get_file_md5, get_max_context_length, get_max_paragraph_length, get_min_paragraph_length, get_thread_count, load_embedding_model, load_rerank_model
7
7
  from jarvis.utils import init_env
8
8
  from dataclasses import dataclass
9
9
  from tqdm import tqdm
10
10
  import fitz # PyMuPDF for PDF files
11
11
  from docx import Document as DocxDocument # python-docx for DOCX files
12
12
  from pathlib import Path
13
- from jarvis.models.registry import PlatformRegistry
13
+ from jarvis.jarvis_platform.registry import PlatformRegistry
14
14
  import shutil
15
15
  from datetime import datetime
16
16
  import lzma # 添加 lzma 导入
@@ -142,9 +142,9 @@ class RAGTool:
142
142
  os.chdir(self.root_dir)
143
143
 
144
144
  # Initialize configuration
145
- self.min_paragraph_length = int(os.environ.get("JARVIS_MIN_PARAGRAPH_LENGTH", "50")) # Minimum paragraph length
146
- self.max_paragraph_length = int(os.environ.get("JARVIS_MAX_PARAGRAPH_LENGTH", "1000")) # Maximum paragraph length
147
- self.context_window = int(os.environ.get("JARVIS_CONTEXT_WINDOW", "5")) # Context window size, default前后各5个片段
145
+ self.min_paragraph_length = get_min_paragraph_length() # Minimum paragraph length
146
+ self.max_paragraph_length = get_max_paragraph_length() # Maximum paragraph length
147
+ self.context_window = get_context_window() # Context window size, default前后各5个片段
148
148
  self.max_context_length = int(get_max_context_length() * 0.8)
149
149
 
150
150
  # Initialize data directory
@@ -179,7 +179,7 @@ class RAGTool:
179
179
  ]
180
180
 
181
181
  # Add thread related configuration
182
- self.thread_count = int(os.environ.get("JARVIS_THREAD_COUNT", os.cpu_count() or 4))
182
+ self.thread_count = get_thread_count()
183
183
  self.vector_lock = Lock() # Protect vector list concurrency
184
184
 
185
185
  def _load_cache(self):
@@ -699,7 +699,7 @@ Content: {doc.content}
699
699
  output = f"""File: {doc.metadata['file_path']}\n"""
700
700
  output += f"""Fragment {doc.metadata['chunk_index'] + 1}/{doc.metadata['total_chunks']}\n"""
701
701
  output += f"""Content:\n{doc.content}\n"""
702
- PrettyOutput.print(output, output_type=OutputType.INFO)
702
+ PrettyOutput.print(output, output_type=OutputType.INFO, lang="markdown")
703
703
 
704
704
  # Build base prompt
705
705
  base_prompt = f"""Please answer the user's question based on the following document fragments. If the document content is not sufficient to answer the question completely, please clearly indicate.
@@ -792,7 +792,7 @@ def main():
792
792
  output = f"""File: {doc.metadata['file_path']}\n"""
793
793
  output += f"""Fragment {doc.metadata['chunk_index'] + 1}/{doc.metadata['total_chunks']}\n"""
794
794
  output += f"""Content:\n{doc.content}\n"""
795
- PrettyOutput.print(output, output_type=OutputType.INFO)
795
+ PrettyOutput.print(output, output_type=OutputType.INFO, lang="markdown")
796
796
  return 0
797
797
 
798
798
  if args.ask:
@@ -7,8 +7,8 @@ from typing import Optional
7
7
  from yaspin import yaspin # type: ignore
8
8
  from yaspin.spinners import Spinners # type: ignore
9
9
 
10
- from jarvis.models.registry import PlatformRegistry
11
- from jarvis.utils import PrettyOutput, OutputType, init_env
10
+ from jarvis.jarvis_platform.registry import PlatformRegistry
11
+ from jarvis.utils import PrettyOutput, OutputType, get_shell_name, init_env
12
12
 
13
13
  def execute_command(command: str) -> None:
14
14
  """Show command and allow user to edit, then execute, Ctrl+C to cancel"""
@@ -42,7 +42,7 @@ def process_request(request: str) -> Optional[str]:
42
42
  model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
43
43
  model.set_suppress_output(True)
44
44
 
45
- shell = os.environ.get("SHELL") or "bash"
45
+ shell = get_shell_name()
46
46
  current_path = os.getcwd()
47
47
 
48
48
  # Set system prompt
File without changes
@@ -87,13 +87,10 @@ def main():
87
87
  })
88
88
 
89
89
  if result["success"]:
90
- print(result["stdout"])
90
+ PrettyOutput.print(result["stdout"], OutputType.INFO, lang="markdown")
91
91
  else:
92
92
  PrettyOutput.print(result["stderr"], OutputType.ERROR)
93
- return 1
94
93
 
95
- return 0
96
-
97
94
 
98
95
  if __name__ == "__main__":
99
96
  main()
@@ -1,5 +1,5 @@
1
1
  from typing import Dict, Any
2
- from jarvis.tools.base import Tool
2
+ from jarvis.jarvis_tools.base import Tool
3
3
  from jarvis.utils import get_multiline_input, PrettyOutput, OutputType
4
4
 
5
5
  class AskUserTool:
@@ -3,8 +3,6 @@ import os
3
3
  from jarvis.utils import PrettyOutput, OutputType
4
4
 
5
5
  class ChdirTool:
6
- """修改当前工作目录的工具"""
7
-
8
6
  name = "chdir"
9
7
  description = "Change current working directory"
10
8
  parameters = {
@@ -19,22 +17,10 @@ class ChdirTool:
19
17
  }
20
18
 
21
19
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
22
- """执行目录切换
23
-
24
- Args:
25
- args: 包含 path 参数的字典
26
-
27
- Returns:
28
- 执行结果字典,包含:
29
- - success: 是否成功
30
- - stdout: 成功时的输出信息
31
- - error: 失败时的错误信息
32
- """
33
20
  try:
34
- path = os.path.expanduser(args["path"].strip()) # 展开 ~ 等路径
35
- path = os.path.abspath(path) # 转换为绝对路径
21
+ path = os.path.expanduser(args["path"].strip())
22
+ path = os.path.abspath(path)
36
23
 
37
- # 检查目录是否存在
38
24
  if not os.path.exists(path):
39
25
  return {
40
26
  "success": False,
@@ -42,7 +28,6 @@ class ChdirTool:
42
28
  "stderr": f"Directory does not exist: {path}"
43
29
  }
44
30
 
45
- # 检查是否是目录
46
31
  if not os.path.isdir(path):
47
32
  return {
48
33
  "success": False,
@@ -50,7 +35,6 @@ class ChdirTool:
50
35
  "stderr": f"The path is not a directory: {path}"
51
36
  }
52
37
 
53
- # 尝试切换目录
54
38
  old_path = os.getcwd()
55
39
  os.chdir(path)
56
40
 
@@ -72,22 +56,3 @@ class ChdirTool:
72
56
  "stdout": "",
73
57
  "stderr": f"Failed to switch directory: {str(e)}"
74
58
  }
75
-
76
- def main():
77
- """命令行直接运行工具"""
78
- import argparse
79
-
80
- parser = argparse.ArgumentParser(description='Change current working directory')
81
- parser.add_argument('path', help='Directory path to switch to, supports both relative and absolute paths')
82
- args = parser.parse_args()
83
-
84
- tool = ChdirTool()
85
- result = tool.execute({"path": args.path})
86
-
87
- if result["success"]:
88
- PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
89
- else:
90
- PrettyOutput.print(result["stderr"], OutputType.ERROR)
91
-
92
- if __name__ == "__main__":
93
- main()
@@ -0,0 +1,236 @@
1
+ from typing import Dict, Any, List
2
+ import subprocess
3
+ import yaml
4
+ from jarvis.jarvis_platform.registry import PlatformRegistry
5
+ from jarvis.jarvis_tools.registry import ToolRegistry
6
+ from jarvis.utils import OutputType, PrettyOutput, init_env, find_git_root
7
+ from jarvis.agent import Agent
8
+ import re
9
+
10
+ class CodeReviewTool:
11
+ name = "code_review"
12
+ description = "Autonomous code review agent for code changes analysis"
13
+ parameters = {
14
+ "type": "object",
15
+ "properties": {
16
+ "review_type": {
17
+ "type": "string",
18
+ "description": "Type of review: 'commit' for specific commit, 'current' for current changes, 'range' for commit range",
19
+ "enum": ["commit", "current", "range"],
20
+ "default": "current"
21
+ },
22
+ "commit_sha": {
23
+ "type": "string",
24
+ "description": "Target commit SHA to analyze (required for review_type='commit')"
25
+ },
26
+ "start_commit": {
27
+ "type": "string",
28
+ "description": "Start commit SHA (required for review_type='range')"
29
+ },
30
+ "end_commit": {
31
+ "type": "string",
32
+ "description": "End commit SHA (required for review_type='range')"
33
+ }
34
+ },
35
+ "required": []
36
+ }
37
+
38
+ def __init__(self):
39
+ init_env()
40
+ self.repo_root = find_git_root()
41
+
42
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
43
+ try:
44
+ review_type = args.get("review_type", "current").strip()
45
+
46
+ # Build git diff command based on review type
47
+ if review_type == "commit":
48
+ if "commit_sha" not in args:
49
+ return {
50
+ "success": False,
51
+ "stdout": {},
52
+ "stderr": "commit_sha is required for commit review type"
53
+ }
54
+ commit_sha = args["commit_sha"].strip()
55
+ diff_cmd = f"git show {commit_sha} | cat -"
56
+ elif review_type == "range":
57
+ if "start_commit" not in args or "end_commit" not in args:
58
+ return {
59
+ "success": False,
60
+ "stdout": {},
61
+ "stderr": "start_commit and end_commit are required for range review type"
62
+ }
63
+ start_commit = args["start_commit"].strip()
64
+ end_commit = args["end_commit"].strip()
65
+ diff_cmd = f"git diff {start_commit}..{end_commit} | cat -"
66
+ else: # current changes
67
+ diff_cmd = "git diff HEAD | cat -"
68
+
69
+ # Execute git diff command
70
+ try:
71
+ diff_output = subprocess.check_output(diff_cmd, shell=True, text=True)
72
+ if not diff_output:
73
+ return {
74
+ "success": False,
75
+ "stdout": {},
76
+ "stderr": "No changes to review"
77
+ }
78
+ PrettyOutput.print(diff_output, OutputType.CODE, lang="diff")
79
+ except subprocess.CalledProcessError as e:
80
+ return {
81
+ "success": False,
82
+ "stdout": {},
83
+ "stderr": f"Failed to get diff: {str(e)}"
84
+ }
85
+
86
+ system_prompt = """You are an autonomous code review expert. Perform in-depth analysis following these guidelines:
87
+
88
+ IMPORTANT:
89
+ - Only analyze the provided diff content
90
+ - Do NOT make assumptions about code not shown
91
+ - Do NOT invent or imagine potential issues
92
+ - Report ONLY issues that can be directly observed
93
+ - If something is unclear, state it explicitly rather than making assumptions
94
+
95
+ REVIEW FOCUS AREAS:
96
+ 1. Requirement Alignment:
97
+ - Verify implementation matches original requirements
98
+ - Check for missing functionality
99
+ - Identify over-implementation
100
+
101
+ 2. Code Quality:
102
+ - Code readability and structure
103
+ - Proper error handling
104
+ - Code duplication
105
+ - Adherence to style guides
106
+ - Meaningful variable/method names
107
+
108
+ 3. Security:
109
+ - Input validation
110
+ - Authentication/Authorization checks
111
+ - Sensitive data handling
112
+ - Potential injection vulnerabilities
113
+ - Secure communication practices
114
+
115
+ 4. Testing:
116
+ - Test coverage for new code
117
+ - Edge case handling
118
+ - Test readability and maintainability
119
+ - Missing test scenarios
120
+
121
+ 5. Performance:
122
+ - Algorithm efficiency
123
+ - Unnecessary resource consumption
124
+ - Proper caching mechanisms
125
+ - Database query optimization
126
+
127
+ 6. Maintainability:
128
+ - Documentation quality
129
+ - Logging and monitoring
130
+ - Configuration management
131
+ - Technical debt indicators
132
+
133
+ 7. Operational Considerations:
134
+ - Backward compatibility
135
+ - Migration script safety
136
+ - Environment-specific configurations
137
+ - Deployment impacts
138
+
139
+ REVIEW PROCESS:
140
+ 1. Retrieve full commit context using git commands
141
+ 2. Analyze code changes line-by-line
142
+ 3. Cross-reference with project standards
143
+ 4. Verify test coverage adequacy
144
+ 5. Check documentation updates
145
+ 6. Generate prioritized findings
146
+
147
+ OUTPUT REQUIREMENTS:
148
+ - Categorize issues by severity (Critical/Major/Minor)
149
+ - Reference specific code locations
150
+ - Provide concrete examples from the diff
151
+ - Suggest actionable improvements based on observed code
152
+ - Highlight security risks clearly with evidence from the code
153
+ - Separate technical debt from blockers
154
+ - If certain aspects cannot be reviewed due to limited context, note this explicitly
155
+ - Do not speculate about code not shown in the diff
156
+ """
157
+ tool_registry = ToolRegistry()
158
+ tool_registry.dont_use_tools(["code_review"])
159
+ agent = Agent(
160
+ system_prompt=system_prompt,
161
+ name="Code Review Agent",
162
+ summary_prompt="""Please generate a concise summary report of the code review, format as yaml:
163
+ <REPORT>
164
+ - file: xxxx.py
165
+ location: [start_line_number, end_line_number]
166
+ description: # Only describe issues directly observable in the diff
167
+ severity: # Critical/Major/Minor based on concrete evidence
168
+ suggestion: # Specific, actionable improvements for the observed code
169
+ </REPORT>""",
170
+ is_sub_agent=True,
171
+ tool_registry=tool_registry,
172
+ platform=PlatformRegistry().get_thinking_platform(),
173
+ auto_complete=True
174
+ )
175
+ result = agent.run(diff_output)
176
+ return {
177
+ "success": True,
178
+ "stdout": result,
179
+ "stderr": ""
180
+ }
181
+
182
+ except Exception as e:
183
+ return {
184
+ "success": False,
185
+ "stdout": {},
186
+ "stderr": f"Review failed: {str(e)}"
187
+ }
188
+
189
+
190
+ def extract_code_report(result: str) -> str:
191
+ sm = re.search(r"<REPORT>(.*?)</REPORT>", result, re.DOTALL)
192
+ if sm:
193
+ return sm.group(1)
194
+ return ""
195
+
196
+ def main():
197
+ """CLI entry point"""
198
+ import argparse
199
+
200
+ parser = argparse.ArgumentParser(description='Autonomous code review tool')
201
+ parser.add_argument('--type', choices=['commit', 'current', 'range'], default='current',
202
+ help='Type of review: commit, current changes, or commit range')
203
+ parser.add_argument('--commit', help='Commit SHA to review (required for commit type)')
204
+ parser.add_argument('--start-commit', help='Start commit SHA (required for range type)')
205
+ parser.add_argument('--end-commit', help='End commit SHA (required for range type)')
206
+ args = parser.parse_args()
207
+
208
+ # Validate arguments
209
+ if args.type == 'commit' and not args.commit:
210
+ parser.error("--commit is required when type is 'commit'")
211
+ if args.type == 'range' and (not args.start_commit or not args.end_commit):
212
+ parser.error("--start-commit and --end-commit are required when type is 'range'")
213
+
214
+ tool = CodeReviewTool()
215
+ tool_args = {
216
+ "review_type": args.type
217
+ }
218
+ if args.commit:
219
+ tool_args["commit_sha"] = args.commit
220
+ if args.start_commit:
221
+ tool_args["start_commit"] = args.start_commit
222
+ if args.end_commit:
223
+ tool_args["end_commit"] = args.end_commit
224
+
225
+ result = tool.execute(tool_args)
226
+
227
+ if result["success"]:
228
+ PrettyOutput.section("Autonomous Review Result:", OutputType.SUCCESS)
229
+ report = extract_code_report(result["stdout"])
230
+ PrettyOutput.print(report, OutputType.SUCCESS, lang="yaml")
231
+
232
+ else:
233
+ PrettyOutput.print(result["stderr"], OutputType.ERROR)
234
+
235
+ if __name__ == "__main__":
236
+ main()
@@ -0,0 +1,115 @@
1
+ import os
2
+ from typing import Dict, Any
3
+ from jarvis.jarvis_code_agent.code_agent import CodeAgent
4
+ from jarvis.jarvis_tools.git_commiter import GitCommitTool
5
+ from jarvis.jarvis_tools.code_review import CodeReviewTool, extract_code_report
6
+ from jarvis.utils import OutputType, PrettyOutput, has_uncommitted_changes
7
+
8
+ class CreateCodeAgentTool:
9
+ """Tool for managing the code development workflow."""
10
+
11
+ name = "create_code_agent"
12
+ description = "Manage code development workflow including commit, development, and review"
13
+ parameters = {
14
+ "requirement": "The development requirement or task description"
15
+ }
16
+
17
+ def _get_current_commit(self) -> str:
18
+ """Get current commit hash."""
19
+ return os.popen("git rev-parse HEAD").read().strip()
20
+
21
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
22
+ try:
23
+ requirement = args.get("requirement", "")
24
+ if not requirement:
25
+ return {
26
+ "success": False,
27
+ "stderr": "Requirement must be provided",
28
+ "stdout": ""
29
+ }
30
+
31
+ # Step 1: Handle uncommitted changes
32
+ start_commit = None
33
+ if has_uncommitted_changes():
34
+ PrettyOutput.print("Found uncommitted changes, committing first...", OutputType.INFO)
35
+ git_commiter = GitCommitTool()
36
+ result = git_commiter.execute({})
37
+ if not result["success"]:
38
+ return {
39
+ "success": False,
40
+ "stderr": "Failed to commit changes: " + result["stderr"],
41
+ "stdout": ""
42
+ }
43
+
44
+ # Get current commit hash
45
+ start_commit = self._get_current_commit()
46
+
47
+ # Step 2: Development
48
+ PrettyOutput.print("Starting development...", OutputType.INFO)
49
+ agent = CodeAgent()
50
+ agent.run(requirement)
51
+
52
+ # Get new commit hash after development
53
+ end_commit = self._get_current_commit()
54
+
55
+ # Step 3: Code Review
56
+ PrettyOutput.print("Starting code review...", OutputType.INFO)
57
+ reviewer = CodeReviewTool()
58
+ review_result = reviewer.execute({
59
+ "review_type": "range",
60
+ "start_commit": start_commit,
61
+ "end_commit": end_commit
62
+ })
63
+
64
+ if not review_result["success"]:
65
+ return {
66
+ "success": False,
67
+ "stderr": "Code review failed: " + review_result["stderr"],
68
+ "stdout": ""
69
+ }
70
+
71
+ # Step 4: Generate Summary
72
+ summary = f"""Development Summary:
73
+
74
+ Start Commit: {start_commit}
75
+ End Commit: {end_commit}
76
+
77
+ Requirement:
78
+ {requirement}
79
+
80
+ Code Review Result:
81
+ {extract_code_report(review_result["stdout"])}
82
+ """
83
+
84
+ return {
85
+ "success": True,
86
+ "stdout": summary,
87
+ "stderr": ""
88
+ }
89
+
90
+ except Exception as e:
91
+ return {
92
+ "success": False,
93
+ "stderr": f"Development workflow failed: {str(e)}",
94
+ "stdout": ""
95
+ }
96
+
97
+ def main():
98
+ """CLI entry point"""
99
+ import argparse
100
+
101
+ parser = argparse.ArgumentParser(description='Code development workflow tool')
102
+ parser.add_argument('requirement', help='Development requirement or task description')
103
+
104
+ args = parser.parse_args()
105
+
106
+ tool = CreateCodeAgentTool()
107
+ result = tool.execute({"requirement": args.requirement})
108
+
109
+ if result["success"]:
110
+ PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
111
+ else:
112
+ PrettyOutput.print(result["stderr"], OutputType.ERROR)
113
+
114
+ if __name__ == "__main__":
115
+ main()
@@ -2,7 +2,7 @@ from typing import Dict, Any
2
2
 
3
3
 
4
4
  from jarvis.agent import Agent, origin_agent_system_prompt
5
- from jarvis.tools.registry import ToolRegistry
5
+ from jarvis.jarvis_tools.registry import ToolRegistry
6
6
  from jarvis.utils import OutputType, PrettyOutput
7
7
 
8
8