jarvis-ai-assistant 0.1.124__py3-none-any.whl → 0.1.126__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 (70) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +134 -136
  3. jarvis/jarvis_code_agent/code_agent.py +198 -52
  4. jarvis/jarvis_code_agent/file_select.py +6 -19
  5. jarvis/jarvis_code_agent/patch.py +183 -312
  6. jarvis/jarvis_code_agent/shell_input_handler.py +22 -0
  7. jarvis/jarvis_codebase/main.py +89 -86
  8. jarvis/jarvis_dev/main.py +695 -715
  9. jarvis/jarvis_git_squash/__init__.py +0 -0
  10. jarvis/jarvis_git_squash/main.py +81 -0
  11. jarvis/jarvis_lsp/base.py +0 -12
  12. jarvis/jarvis_lsp/cpp.py +1 -10
  13. jarvis/jarvis_lsp/go.py +1 -10
  14. jarvis/jarvis_lsp/python.py +0 -28
  15. jarvis/jarvis_lsp/registry.py +2 -3
  16. jarvis/jarvis_lsp/rust.py +1 -10
  17. jarvis/jarvis_multi_agent/__init__.py +53 -53
  18. jarvis/jarvis_platform/ai8.py +2 -1
  19. jarvis/jarvis_platform/base.py +19 -24
  20. jarvis/jarvis_platform/kimi.py +2 -3
  21. jarvis/jarvis_platform/ollama.py +3 -1
  22. jarvis/jarvis_platform/openai.py +1 -1
  23. jarvis/jarvis_platform/oyi.py +2 -1
  24. jarvis/jarvis_platform/registry.py +2 -1
  25. jarvis/jarvis_platform_manager/main.py +4 -6
  26. jarvis/jarvis_platform_manager/openai_test.py +0 -1
  27. jarvis/jarvis_rag/main.py +5 -2
  28. jarvis/jarvis_smart_shell/main.py +9 -4
  29. jarvis/jarvis_tools/ask_codebase.py +18 -13
  30. jarvis/jarvis_tools/ask_user.py +5 -4
  31. jarvis/jarvis_tools/base.py +22 -8
  32. jarvis/jarvis_tools/chdir.py +8 -9
  33. jarvis/jarvis_tools/code_review.py +19 -20
  34. jarvis/jarvis_tools/create_code_agent.py +6 -6
  35. jarvis/jarvis_tools/create_sub_agent.py +9 -9
  36. jarvis/jarvis_tools/execute_shell.py +55 -20
  37. jarvis/jarvis_tools/execute_shell_script.py +7 -7
  38. jarvis/jarvis_tools/file_operation.py +39 -10
  39. jarvis/jarvis_tools/git_commiter.py +20 -17
  40. jarvis/jarvis_tools/lsp_find_definition.py +8 -8
  41. jarvis/jarvis_tools/lsp_find_references.py +1 -1
  42. jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -11
  43. jarvis/jarvis_tools/lsp_get_document_symbols.py +1 -1
  44. jarvis/jarvis_tools/lsp_prepare_rename.py +8 -8
  45. jarvis/jarvis_tools/methodology.py +10 -7
  46. jarvis/jarvis_tools/rag.py +27 -20
  47. jarvis/jarvis_tools/read_webpage.py +4 -3
  48. jarvis/jarvis_tools/registry.py +143 -140
  49. jarvis/jarvis_tools/{search.py → search_web.py} +10 -7
  50. jarvis/jarvis_tools/select_code_files.py +4 -4
  51. jarvis/jarvis_tools/tool_generator.py +33 -34
  52. jarvis/jarvis_utils/__init__.py +19 -982
  53. jarvis/jarvis_utils/config.py +138 -0
  54. jarvis/jarvis_utils/embedding.py +201 -0
  55. jarvis/jarvis_utils/git_utils.py +120 -0
  56. jarvis/jarvis_utils/globals.py +82 -0
  57. jarvis/jarvis_utils/input.py +161 -0
  58. jarvis/jarvis_utils/methodology.py +128 -0
  59. jarvis/jarvis_utils/output.py +235 -0
  60. jarvis/jarvis_utils/utils.py +150 -0
  61. jarvis_ai_assistant-0.1.126.dist-info/METADATA +305 -0
  62. jarvis_ai_assistant-0.1.126.dist-info/RECORD +74 -0
  63. {jarvis_ai_assistant-0.1.124.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/WHEEL +1 -1
  64. {jarvis_ai_assistant-0.1.124.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/entry_points.txt +1 -0
  65. jarvis/jarvis_tools/lsp_validate_edit.py +0 -141
  66. jarvis/jarvis_tools/read_code.py +0 -191
  67. jarvis_ai_assistant-0.1.124.dist-info/METADATA +0 -460
  68. jarvis_ai_assistant-0.1.124.dist-info/RECORD +0 -65
  69. {jarvis_ai_assistant-0.1.124.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/LICENSE +0 -0
  70. {jarvis_ai_assistant-0.1.124.dist-info → jarvis_ai_assistant-0.1.126.dist-info}/top_level.txt +0 -0
@@ -1,22 +1,24 @@
1
1
  from typing import Dict, Any
2
- from jarvis.jarvis_utils import OutputType, PrettyOutput, dont_use_local_model, find_git_root
3
2
  from jarvis.jarvis_codebase.main import CodeBase
3
+ from jarvis.jarvis_utils.config import dont_use_local_model
4
+ from jarvis.jarvis_utils.git_utils import find_git_root
5
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
4
6
 
5
7
  class AskCodebaseTool:
6
- """Tool for intelligent codebase querying and analysis using CodeBase"""
7
-
8
+ """用于智能代码库查询和分析的工具"""
9
+
8
10
  name = "ask_codebase"
9
- description = "Ask questions about the codebase and get detailed analysis"
11
+ description = "查询代码库问题并获取详细分析"
10
12
  parameters = {
11
13
  "type": "object",
12
14
  "properties": {
13
15
  "question": {
14
16
  "type": "string",
15
- "description": "Question about the codebase"
17
+ "description": "关于代码库的问题"
16
18
  },
17
19
  "top_k": {
18
20
  "type": "integer",
19
- "description": "Number of most relevant files to analyze (optional)",
21
+ "description": "要分析的最相关文件数量(可选)",
20
22
  "default": 20
21
23
  }
22
24
  },
@@ -52,14 +54,20 @@ class AskCodebaseTool:
52
54
  codebase = CodeBase(git_root)
53
55
 
54
56
  # Use ask_codebase method
55
- _, response = codebase.ask_codebase(question, top_k)
56
-
57
+ files, response = codebase.ask_codebase(question, top_k)
58
+
59
+ # Print found files
60
+ if files:
61
+ output = "找到的相关文件:\n"
62
+ for file in files:
63
+ output += f"- {file['file']} ({file['reason']})\n"
64
+ PrettyOutput.print(output, OutputType.INFO, lang="markdown")
65
+
57
66
  return {
58
67
  "success": True,
59
68
  "stdout": response,
60
69
  "stderr": ""
61
70
  }
62
-
63
71
  except Exception as e:
64
72
  error_msg = f"分析代码库失败: {str(e)}"
65
73
  PrettyOutput.print(error_msg, OutputType.WARNING)
@@ -68,8 +76,6 @@ class AskCodebaseTool:
68
76
  "stdout": "",
69
77
  "stderr": error_msg
70
78
  }
71
-
72
-
73
79
  def main():
74
80
  """Command line interface for the tool"""
75
81
  import argparse
@@ -79,7 +85,6 @@ def main():
79
85
  parser.add_argument('--top-k', type=int, help='Number of files to analyze', default=20)
80
86
 
81
87
  args = parser.parse_args()
82
-
83
88
  tool = AskCodebaseTool()
84
89
  result = tool.execute({
85
90
  "question": args.question,
@@ -93,4 +98,4 @@ def main():
93
98
 
94
99
 
95
100
  if __name__ == "__main__":
96
- main()
101
+ main()
@@ -1,16 +1,17 @@
1
1
  from typing import Dict, Any
2
- from jarvis.jarvis_tools.base import Tool
3
- from jarvis.jarvis_utils import get_multiline_input, PrettyOutput, OutputType
2
+
3
+ from jarvis.jarvis_utils.input import get_multiline_input
4
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
4
5
 
5
6
  class AskUserTool:
6
7
  name="ask_user"
7
- description="""Ask the user when information needed to complete the task is missing or when critical decision information is lacking. Users can input multiple lines of text, ending with an empty line. Use cases: 1. Need user to provide more information to complete the task; 2. Need user to make critical decisions; 3. Need user to confirm important operations; 4. Need user to provide additional information"""
8
+ description="""当完成任务所需的信息缺失或关键决策信息不足时,向用户提问。用户可以输入多行文本,以空行结束。使用场景:1. 需要用户提供更多信息以完成任务;2. 需要用户做出关键决策;3. 需要用户确认重要操作;4. 需要用户提供额外信息"""
8
9
  parameters={
9
10
  "type": "object",
10
11
  "properties": {
11
12
  "question": {
12
13
  "type": "string",
13
- "description": "The question to ask the user"
14
+ "description": "要向用户提出的问题"
14
15
  }
15
16
  },
16
17
  "required": ["question"]
@@ -1,23 +1,37 @@
1
1
  from typing import Dict, Any, Callable
2
2
  import json
3
-
4
-
5
-
6
3
  class Tool:
4
+ """工具类,用于封装工具的基本信息和执行方法"""
5
+
7
6
  def __init__(self, name: str, description: str, parameters: Dict, func: Callable):
7
+ """
8
+ 初始化工具对象
9
+
10
+ 参数:
11
+ name (str): 工具名称
12
+ description (str): 工具描述
13
+ parameters (Dict): 工具参数定义
14
+ func (Callable): 工具执行函数
15
+ """
8
16
  self.name = name
9
17
  self.description = description
10
18
  self.parameters = parameters
11
19
  self.func = func
12
-
13
20
  def to_dict(self) -> Dict:
14
- """Convert to tool format"""
21
+ """将工具对象转换为字典格式,主要用于序列化"""
15
22
  return {
16
23
  "name": self.name,
17
24
  "description": self.description,
18
25
  "parameters": json.dumps(self.parameters, ensure_ascii=False)
19
26
  }
20
-
21
27
  def execute(self, arguments: Dict) -> Dict[str, Any]:
22
- """Execute tool function"""
23
- return self.func(arguments)
28
+ """
29
+ 执行工具函数
30
+
31
+ 参数:
32
+ arguments (Dict): 工具执行所需的参数
33
+
34
+ 返回:
35
+ Dict[str, Any]: 工具执行结果
36
+ """
37
+ return self.func(arguments)
@@ -1,16 +1,15 @@
1
1
  from typing import Dict, Any
2
2
  import os
3
- from jarvis.jarvis_utils import PrettyOutput, OutputType
4
3
 
5
4
  class ChdirTool:
6
5
  name = "chdir"
7
- description = "Change current working directory"
6
+ description = "更改当前工作目录"
8
7
  parameters = {
9
8
  "type": "object",
10
9
  "properties": {
11
10
  "path": {
12
11
  "type": "string",
13
- "description": "Directory path to switch to, supports both relative and absolute paths"
12
+ "description": "要切换到的目录路径,支持相对路径和绝对路径"
14
13
  }
15
14
  },
16
15
  "required": ["path"]
@@ -46,7 +45,7 @@ class ChdirTool:
46
45
  return {
47
46
  "success": False,
48
47
  "stdout": "",
49
- "stderr": f"Directory does not exist: {path}"
48
+ "stderr": f"目录不存在: {path}"
50
49
  }
51
50
 
52
51
  # Ensure the path points to a directory, not a file
@@ -54,7 +53,7 @@ class ChdirTool:
54
53
  return {
55
54
  "success": False,
56
55
  "stdout": "",
57
- "stderr": f"The path is not a directory: {path}"
56
+ "stderr": f"路径不是目录: {path}"
58
57
  }
59
58
 
60
59
  # Capture current directory and attempt to change to new path
@@ -63,7 +62,7 @@ class ChdirTool:
63
62
 
64
63
  return {
65
64
  "success": True,
66
- "stdout": f"Changed working directory:\nFrom: {old_path}\nTo: {path}",
65
+ "stdout": f"成功切换工作目录:\n原目录: {old_path}\n新目录: {path}",
67
66
  "stderr": ""
68
67
  }
69
68
 
@@ -72,12 +71,12 @@ class ChdirTool:
72
71
  return {
73
72
  "success": False,
74
73
  "stdout": "",
75
- "stderr": f"No permission to access directory: {path}"
74
+ "stderr": f"无权限访问目录: {path}"
76
75
  }
77
76
  # Catch-all for any other unexpected errors during directory change
78
77
  except Exception as e:
79
78
  return {
80
79
  "success": False,
81
80
  "stdout": "",
82
- "stderr": f"Failed to switch directory: {str(e)}"
83
- }
81
+ "stderr": f"切换目录失败: {str(e)}"
82
+ }
@@ -1,44 +1,41 @@
1
- from typing import Dict, Any, List
1
+ from typing import Dict, Any
2
2
  import subprocess
3
- import yaml
4
3
  from jarvis.jarvis_platform.registry import PlatformRegistry
5
4
  from jarvis.jarvis_tools.registry import ToolRegistry
6
- from jarvis.jarvis_utils import OutputType, PrettyOutput, init_env, find_git_root
7
5
  from jarvis.jarvis_agent import Agent
8
6
  import re
9
7
 
8
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
9
+ from jarvis.jarvis_utils.utils import init_env
10
+
10
11
  class CodeReviewTool:
11
12
  name = "code_review"
12
- description = "Autonomous code review agent for code changes analysis"
13
+ description = "自动代码审查工具,用于分析代码变更"
13
14
  parameters = {
14
15
  "type": "object",
15
16
  "properties": {
16
17
  "review_type": {
17
18
  "type": "string",
18
- "description": "Type of review: 'commit' for specific commit, 'current' for current changes, 'range' for commit range",
19
+ "description": "审查类型:'commit' 审查特定提交,'current' 审查当前变更,'range' 审查提交范围",
19
20
  "enum": ["commit", "current", "range"],
20
21
  "default": "current"
21
22
  },
22
23
  "commit_sha": {
23
24
  "type": "string",
24
- "description": "Target commit SHA to analyze (required for review_type='commit')"
25
+ "description": "要分析的提交SHAreview_type='commit'时必填)"
25
26
  },
26
27
  "start_commit": {
27
28
  "type": "string",
28
- "description": "Start commit SHA (required for review_type='range')"
29
+ "description": "起始提交SHAreview_type='range'时必填)"
29
30
  },
30
31
  "end_commit": {
31
32
  "type": "string",
32
- "description": "End commit SHA (required for review_type='range')"
33
+ "description": "结束提交SHAreview_type='range'时必填)"
33
34
  }
34
35
  },
35
36
  "required": []
36
37
  }
37
38
 
38
- def __init__(self):
39
- init_env()
40
- self.repo_root = find_git_root()
41
-
42
39
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
43
40
  try:
44
41
  review_type = args.get("review_type", "current").strip()
@@ -170,13 +167,13 @@ PROPOSED DEFENSE:
170
167
  agent = Agent(
171
168
  system_prompt=system_prompt,
172
169
  name="Code Review Agent",
173
- summary_prompt="""Please generate a concise summary report of the code review, format as yaml:
170
+ summary_prompt="""Please generate a concise summary report of the code review in Chinese, format as follows:
174
171
  <REPORT>
175
- - file: xxxx.py
176
- location: [start_line_number, end_line_number]
177
- description: # Only describe issues directly observable in the diff
178
- severity: # Critical/Major/Minor based on concrete evidence
179
- suggestion: # Specific, actionable improvements for the observed code
172
+ - 文件: xxxx.py
173
+ 位置: [起始行号, 结束行号]
174
+ 描述: # 仅描述在差异中直接观察到的问题
175
+ 严重程度: # 根据具体证据分为严重/重要/次要
176
+ 建议: # 针对观察到的代码的具体改进建议
180
177
  </REPORT>""",
181
178
  is_sub_agent=True,
182
179
  output_handler=[tool_registry],
@@ -207,6 +204,8 @@ def extract_code_report(result: str) -> str:
207
204
  def main():
208
205
  """CLI entry point"""
209
206
  import argparse
207
+
208
+ init_env()
210
209
 
211
210
  parser = argparse.ArgumentParser(description='Autonomous code review tool')
212
211
  parser.add_argument('--type', choices=['commit', 'current', 'range'], default='current',
@@ -236,7 +235,7 @@ def main():
236
235
  result = tool.execute(tool_args)
237
236
 
238
237
  if result["success"]:
239
- PrettyOutput.section("Autonomous Review Result:", OutputType.SUCCESS)
238
+ PrettyOutput.section("自动代码审查结果:", OutputType.SUCCESS)
240
239
  report = extract_code_report(result["stdout"])
241
240
  PrettyOutput.print(report, OutputType.SUCCESS, lang="yaml")
242
241
 
@@ -244,4 +243,4 @@ def main():
244
243
  PrettyOutput.print(result["stderr"], OutputType.WARNING)
245
244
 
246
245
  if __name__ == "__main__":
247
- main()
246
+ main()
@@ -1,17 +1,17 @@
1
- import os
2
1
  from typing import Dict, Any
3
2
  from jarvis.jarvis_code_agent.code_agent import CodeAgent
4
3
  from jarvis.jarvis_tools.git_commiter import GitCommitTool
5
4
  from jarvis.jarvis_tools.code_review import CodeReviewTool, extract_code_report
6
- from jarvis.jarvis_utils import OutputType, PrettyOutput, has_uncommitted_changes, get_latest_commit_hash
5
+ from jarvis.jarvis_utils.git_utils import get_latest_commit_hash, has_uncommitted_changes
6
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
7
7
 
8
8
  class CreateCodeAgentTool:
9
- """Tool for managing the code development workflow."""
9
+ """用于管理代码开发工作流的工具"""
10
10
 
11
11
  name = "create_code_agent"
12
- description = "Technical code implementation and development process management"
12
+ description = "技术代码实现和开发过程管理工具"
13
13
  parameters = {
14
- "requirement": "Technical specifications for code implementation"
14
+ "requirement": "代码实现的技术规范"
15
15
  }
16
16
 
17
17
 
@@ -109,4 +109,4 @@ def main():
109
109
  PrettyOutput.print(result["stderr"], OutputType.WARNING)
110
110
 
111
111
  if __name__ == "__main__":
112
- main()
112
+ main()
@@ -2,38 +2,38 @@ from typing import Dict, Any
2
2
 
3
3
 
4
4
  from jarvis.jarvis_agent import Agent, origin_agent_system_prompt
5
- from jarvis.jarvis_tools.registry import ToolRegistry
6
- from jarvis.jarvis_utils import OutputType, PrettyOutput
5
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
6
+
7
7
 
8
8
 
9
9
  class SubAgentTool:
10
10
  name = "create_sub_agent"
11
- description = "Create a sub-agent to handle specific tasks, the sub-agent will generate a task summary report"
11
+ description = "创建子代理以处理特定任务,子代理将生成任务总结报告"
12
12
  parameters = {
13
13
  "type": "object",
14
14
  "properties": {
15
15
  "agent_name": {
16
16
  "type": "string",
17
- "description": "Sub-agent name"
17
+ "description": "子代理名称"
18
18
  },
19
19
  "task": {
20
20
  "type": "string",
21
- "description": "Specific task to complete"
21
+ "description": "要完成的特定任务"
22
22
  },
23
23
  "context": {
24
24
  "type": "string",
25
- "description": "Context information related to the task",
25
+ "description": "与任务相关的上下文信息",
26
26
  "default": ""
27
27
  },
28
28
  "goal": {
29
29
  "type": "string",
30
- "description": "Completion goal of the task",
30
+ "description": "任务的完成目标",
31
31
  "default": ""
32
32
  },
33
33
  "files": {
34
34
  "type": "array",
35
35
  "items": {"type": "string"},
36
- "description": "Related file path list, used for file question answering and processing",
36
+ "description": "相关文件路径列表,用于文件问答和处理",
37
37
  "default": []
38
38
  }
39
39
  },
@@ -83,4 +83,4 @@ class SubAgentTool:
83
83
  "success": False,
84
84
  "stdout": "",
85
85
  "stderr": f"Sub-agent execution failed: {str(e)}"
86
- }
86
+ }
@@ -1,55 +1,89 @@
1
+ # Shell command execution module
2
+ #
3
+ # Provides functionality to execute shell commands safely with:
4
+ # - Command escaping
5
+ # - Output capturing
6
+ # - Temporary file management
7
+ # - Error handling
1
8
  from typing import Dict, Any
2
9
  import os
3
10
  import tempfile
4
11
  from pathlib import Path
5
-
6
- from jarvis.jarvis_utils import OutputType, PrettyOutput
7
-
8
-
12
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
9
13
  class ShellTool:
14
+ """Shell command execution tool
15
+
16
+ Attributes:
17
+ name: Tool identifier used in API
18
+ description: Tool description for API documentation
19
+ parameters: JSON schema for command parameters
20
+ """
10
21
  name = "execute_shell"
11
- description = """Execute shell command and return result"""
12
-
22
+ description = "执行Shell命令并返回结果"
13
23
  parameters = {
14
24
  "type": "object",
15
25
  "properties": {
16
26
  "command": {
17
27
  "type": "string",
18
- "description": "Shell command to execute"
28
+ "description": "要执行的Shell命令"
19
29
  }
20
30
  },
21
31
  "required": ["command"]
22
32
  }
23
-
24
-
25
33
  def _escape_command(self, cmd: str) -> str:
26
- """Escape special characters in command"""
34
+ """Escape special characters in command to prevent shell injection
35
+
36
+ Args:
37
+ cmd: Raw command string
38
+
39
+ Returns:
40
+ Escaped command string with single quotes properly handled
41
+ """
27
42
  return cmd.replace("'", "'\"'\"'")
28
-
29
43
  def execute(self, args: Dict) -> Dict[str, Any]:
30
- """Execute shell command"""
44
+ """Execute shell command and capture output
45
+
46
+ Steps:
47
+ 1. Validate and clean input command
48
+ 2. Create temporary file for output capture
49
+ 3. Execute command with output redirection
50
+ 4. Read and process output file
51
+ 5. Clean up temporary resources
52
+ 6. Return structured results
53
+
54
+ Args:
55
+ args: Dictionary containing 'command' parameter
56
+
57
+ Returns:
58
+ Dictionary with:
59
+ - success: Boolean indicating command execution status
60
+ - stdout: Command output
61
+ - stderr: Error message if execution failed
62
+ """
31
63
  try:
64
+ # Get and clean command input
32
65
  command = args["command"].strip()
33
66
 
34
- # Generate temporary file name
67
+ # Generate temporary file name using process ID for uniqueness
35
68
  output_file = os.path.join(tempfile.gettempdir(), f"jarvis_shell_{os.getpid()}.log")
36
69
 
37
- # Escape special characters in command
70
+ # Escape special characters in command to prevent injection
38
71
  escaped_command = self._escape_command(command)
39
72
 
40
- # Modify command to use script
73
+ # Use script command to capture both stdout and stderr
41
74
  tee_command = f"script -q -c '{escaped_command}' {output_file}"
42
75
 
76
+ # Log command execution
43
77
  PrettyOutput.print(f"执行命令: {command}", OutputType.INFO)
44
78
 
45
- # Execute command
79
+ # Execute command and capture return code
46
80
  return_code = os.system(tee_command)
47
81
 
48
- # Read output file
82
+ # Read and process output file
49
83
  try:
50
84
  with open(output_file, 'r', encoding='utf-8', errors='replace') as f:
51
85
  output = f.read()
52
- # Remove header and footer added by script
86
+ # Remove header and footer added by script command
53
87
  if output:
54
88
  lines = output.splitlines()
55
89
  if len(lines) > 2:
@@ -60,6 +94,7 @@ class ShellTool:
60
94
  # Clean up temporary file
61
95
  Path(output_file).unlink(missing_ok=True)
62
96
 
97
+ # Return successful result
63
98
  return {
64
99
  "success": True,
65
100
  "stdout": output,
@@ -67,7 +102,7 @@ class ShellTool:
67
102
  }
68
103
 
69
104
  except Exception as e:
70
- # Ensure temporary file is cleaned up
105
+ # Ensure temporary file is cleaned up even if error occurs
71
106
  if 'output_file' in locals():
72
107
  Path(output_file).unlink(missing_ok=True)
73
108
  PrettyOutput.print(str(e), OutputType.ERROR)
@@ -75,4 +110,4 @@ class ShellTool:
75
110
  "success": False,
76
111
  "stdout": "",
77
112
  "stderr": str(e)
78
- }
113
+ }
@@ -2,17 +2,19 @@ from typing import Dict, Any
2
2
  import os
3
3
  import tempfile
4
4
  from pathlib import Path
5
- from jarvis.jarvis_utils import OutputType, PrettyOutput
5
+
6
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
7
+
6
8
 
7
9
  class ShellScriptTool:
8
10
  name = "execute_shell_script"
9
- description = """Execute shell script file and return result"""
11
+ description = "执行Shell脚本文件并返回结果"
10
12
  parameters = {
11
13
  "type": "object",
12
14
  "properties": {
13
15
  "script_content": {
14
16
  "type": "string",
15
- "description": "Content of the shell script to execute"
17
+ "description": "要执行的Shell脚本内容"
16
18
  }
17
19
  },
18
20
  "required": ["script_content"]
@@ -33,12 +35,10 @@ class ShellScriptTool:
33
35
  try:
34
36
  with open(script_path, 'w', encoding='utf-8') as f:
35
37
  f.write(script_content)
36
- os.chmod(script_path, 0o755) # Make script executable
37
-
38
38
  # Use execute_shell to run the script
39
39
  from jarvis.jarvis_tools.execute_shell import ShellTool
40
40
  shell_tool = ShellTool()
41
- result = shell_tool.execute({"command": script_path})
41
+ result = shell_tool.execute({"command": f"bash {script_path}"})
42
42
 
43
43
  return {
44
44
  "success": result["success"],
@@ -55,4 +55,4 @@ class ShellScriptTool:
55
55
  "success": False,
56
56
  "stdout": "",
57
57
  "stderr": str(e)
58
- }
58
+ }
@@ -1,19 +1,20 @@
1
- from typing import Dict, Any, List, Union
1
+ from typing import Dict, Any
2
2
  import os
3
3
 
4
- from jarvis.jarvis_utils import OutputType, PrettyOutput
4
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
5
+
5
6
 
6
7
 
7
8
  class FileOperationTool:
8
9
  name = "file_operation"
9
- description = "File operations for reading and writing multiple files"
10
+ description = "用于读写多个文件的操作工具"
10
11
  parameters = {
11
12
  "type": "object",
12
13
  "properties": {
13
14
  "operation": {
14
15
  "type": "string",
15
16
  "enum": ["read", "write"],
16
- "description": "Type of file operation to perform (read or write multiple files)"
17
+ "description": "要执行的文件操作类型(读取或写入多个文件)"
17
18
  },
18
19
  "files": {
19
20
  "type": "array",
@@ -25,13 +26,14 @@ class FileOperationTool:
25
26
  },
26
27
  "required": ["path"]
27
28
  },
28
- "description": "List of files to operate on"
29
+ "description": "要操作的文件列表"
29
30
  }
30
31
  },
31
32
  "required": ["operation", "files"]
32
33
  }
33
34
 
34
- def _handle_single_file(self, operation: str, filepath: str, content: str = "") -> Dict[str, Any]:
35
+ def _handle_single_file(self, operation: str, filepath: str, content: str = "",
36
+ start_line: int = 1, end_line: int = -1) -> Dict[str, Any]:
35
37
  """Handle operations for a single file"""
36
38
  try:
37
39
  abs_path = os.path.abspath(filepath)
@@ -54,8 +56,29 @@ class FileOperationTool:
54
56
  "stderr": "File too large (>10MB)"
55
57
  }
56
58
 
57
- content = open(abs_path, 'r', encoding='utf-8').read()
58
- output = f"File: {abs_path}\n{content}"
59
+ with open(abs_path, 'r', encoding='utf-8') as f:
60
+ lines = f.readlines()
61
+
62
+ # Handle line range
63
+ total_lines = len(lines)
64
+ start_line = start_line if start_line >= 0 else total_lines + start_line + 1
65
+ end_line = end_line if end_line >= 0 else total_lines + end_line + 1
66
+ start_line = max(1, min(start_line, total_lines))
67
+ end_line = max(1, min(end_line, total_lines))
68
+ if end_line == -1:
69
+ end_line = total_lines
70
+
71
+ if start_line > end_line:
72
+ error_msg = f"无效的行范围 [{start_line, end_line}] (文件总行数: {total_lines})"
73
+ PrettyOutput.print(error_msg, OutputType.WARNING)
74
+ return {
75
+ "success": False,
76
+ "stdout": "",
77
+ "stderr": error_msg
78
+ }
79
+
80
+ content = "".join(lines[start_line - 1:end_line])
81
+ output = f"\文件: {abs_path}\行: [{start_line}-{end_line}]\n{content}" + "\n\n" + "="*80 + "\n\n"
59
82
 
60
83
  return {
61
84
  "success": True,
@@ -119,7 +142,13 @@ class FileOperationTool:
119
142
  continue
120
143
 
121
144
  content = file_info.get("content", "") if operation == "write" else ""
122
- result = self._handle_single_file(operation, file_info["path"].strip(), content)
145
+ result = self._handle_single_file(
146
+ operation,
147
+ file_info["path"].strip(),
148
+ content,
149
+ file_info.get("start_line", 1),
150
+ file_info.get("end_line", -1)
151
+ )
123
152
 
124
153
  if result["success"]:
125
154
  all_outputs.append(result["stdout"])
@@ -142,4 +171,4 @@ class FileOperationTool:
142
171
  "success": False,
143
172
  "stdout": "",
144
173
  "stderr": f"File operation failed: {str(e)}"
145
- }
174
+ }