jarvis-ai-assistant 0.1.99__py3-none-any.whl → 0.1.101__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 (39) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +12 -12
  3. jarvis/jarvis_code_agent/main.py +26 -27
  4. jarvis/jarvis_codebase/main.py +3 -3
  5. jarvis/jarvis_coder/git_utils.py +4 -4
  6. jarvis/jarvis_coder/main.py +2 -8
  7. jarvis/jarvis_coder/patch_handler.py +153 -75
  8. jarvis/jarvis_platform/main.py +2 -2
  9. jarvis/jarvis_rag/main.py +2 -2
  10. jarvis/jarvis_smart_shell/main.py +6 -4
  11. jarvis/models/kimi.py +2 -2
  12. jarvis/models/openai.py +1 -1
  13. jarvis/models/registry.py +35 -12
  14. jarvis/tools/ask_user.py +6 -3
  15. jarvis/tools/chdir.py +9 -5
  16. jarvis/tools/create_code_sub_agent.py +2 -1
  17. jarvis/tools/create_sub_agent.py +2 -1
  18. jarvis/tools/execute_code_modification.py +4 -6
  19. jarvis/tools/execute_shell.py +2 -2
  20. jarvis/tools/file_operation.py +10 -5
  21. jarvis/tools/find_files.py +119 -0
  22. jarvis/tools/generate_tool.py +27 -25
  23. jarvis/tools/methodology.py +13 -7
  24. jarvis/tools/rag.py +9 -5
  25. jarvis/tools/read_webpage.py +4 -2
  26. jarvis/tools/registry.py +25 -15
  27. jarvis/tools/search.py +18 -15
  28. jarvis/tools/select_code_files.py +2 -5
  29. jarvis/tools/thinker.py +7 -5
  30. jarvis/utils.py +53 -34
  31. {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.101.dist-info}/METADATA +9 -8
  32. jarvis_ai_assistant-0.1.101.dist-info/RECORD +51 -0
  33. jarvis/tools/codebase_qa.py +0 -72
  34. jarvis/tools/find_related_files.py +0 -86
  35. jarvis_ai_assistant-0.1.99.dist-info/RECORD +0 -52
  36. {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.101.dist-info}/LICENSE +0 -0
  37. {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.101.dist-info}/WHEEL +0 -0
  38. {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.101.dist-info}/entry_points.txt +0 -0
  39. {jarvis_ai_assistant-0.1.99.dist-info → jarvis_ai_assistant-0.1.101.dist-info}/top_level.txt +0 -0
@@ -8,24 +8,26 @@ from yaspin import yaspin # type: ignore
8
8
  from yaspin.spinners import Spinners # type: ignore
9
9
 
10
10
  from jarvis.models.registry import PlatformRegistry
11
- from jarvis.utils import PrettyOutput, OutputType, get_single_line_input, load_env_from_file
11
+ from jarvis.utils import PrettyOutput, OutputType, 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"""
15
15
  try:
16
+ print("\nGenerated command (can be edited, press Enter to execute, Ctrl+C to cancel):")
16
17
  # Pre-fill input line
17
18
  readline.set_startup_hook(lambda: readline.insert_text(command))
18
19
  try:
19
- edited_command = get_single_line_input("Generated command (can be edited, press Enter to execute, Ctrl+C to cancel)")
20
+ edited_command = input("> ")
20
21
  if edited_command.strip(): # Ensure command is not empty
21
22
  os.system(edited_command)
22
23
  except KeyboardInterrupt:
23
- PrettyOutput.print("Execution cancelled", OutputType.INFO)
24
+ print("\nExecution cancelled")
24
25
  finally:
25
26
  readline.set_startup_hook() # Clear pre-filled
26
27
  except Exception as e:
27
28
  PrettyOutput.print(f"Failed to execute command: {str(e)}", OutputType.ERROR)
28
29
 
30
+
29
31
  def process_request(request: str) -> Optional[str]:
30
32
  """Process user request and return corresponding shell command
31
33
 
@@ -88,7 +90,7 @@ Remember: Only return the command itself, without any additional content.
88
90
 
89
91
  def main():
90
92
  # 创建参数解析器
91
- load_env_from_file()
93
+ init_env()
92
94
  parser = argparse.ArgumentParser(
93
95
  description="Convert natural language requirements to shell commands",
94
96
  formatter_class=argparse.RawDescriptionHelpFormatter,
jarvis/models/kimi.py CHANGED
@@ -35,8 +35,8 @@ class KimiModel(BasePlatform):
35
35
  PrettyOutput.print(" • Find the Authorization header in the request", OutputType.INFO)
36
36
  PrettyOutput.print(" • Copy the token value (remove the 'Bearer ' prefix)", OutputType.INFO)
37
37
  PrettyOutput.print("\n2. Set environment variable:", OutputType.INFO)
38
- PrettyOutput.print(" • Method 1: Create or edit ~/.jarvis_env file:", OutputType.INFO)
39
- PrettyOutput.print(" echo 'KIMI_API_KEY=your_key_here' > ~/.jarvis_env", OutputType.INFO)
38
+ PrettyOutput.print(" • Method 1: Create or edit ~/.jarvis/env file:", OutputType.INFO)
39
+ PrettyOutput.print(" echo 'KIMI_API_KEY=your_key_here' > ~/.jarvis/env", OutputType.INFO)
40
40
  PrettyOutput.print("\n • Method 2: Set environment variable directly:", OutputType.INFO)
41
41
  PrettyOutput.print(" export KIMI_API_KEY=your_key_here", OutputType.INFO)
42
42
  PrettyOutput.print("\nAfter setting, run Jarvis again.", OutputType.INFO)
jarvis/models/openai.py CHANGED
@@ -23,7 +23,7 @@ class OpenAIModel(BasePlatform):
23
23
  PrettyOutput.print(" • OPENAI_API_KEY: API key", OutputType.INFO)
24
24
  PrettyOutput.print(" • OPENAI_API_BASE: (optional) API base address, default using https://api.openai.com/v1", OutputType.INFO)
25
25
  PrettyOutput.print("\nYou can set them in the following ways:", OutputType.INFO)
26
- PrettyOutput.print("1. Create or edit ~/.jarvis_env file:", OutputType.INFO)
26
+ PrettyOutput.print("1. Create or edit ~/.jarvis/env file:", OutputType.INFO)
27
27
  PrettyOutput.print(" OPENAI_API_KEY=your_api_key", OutputType.INFO)
28
28
  PrettyOutput.print(" OPENAI_API_BASE=your_api_base", OutputType.INFO)
29
29
  PrettyOutput.print(" OPENAI_MODEL_NAME=your_model_name", OutputType.INFO)
jarvis/models/registry.py CHANGED
@@ -26,7 +26,7 @@ class PlatformRegistry:
26
26
 
27
27
  @staticmethod
28
28
  def get_platform_dir() -> str:
29
- user_platform_dir = os.path.expanduser("~/.jarvis_models")
29
+ user_platform_dir = os.path.expanduser("~/.jarvis/models")
30
30
  if not os.path.exists(user_platform_dir):
31
31
  try:
32
32
  os.makedirs(user_platform_dir)
@@ -137,22 +137,22 @@ class PlatformRegistry:
137
137
  def get_global_platform_registry():
138
138
  """Get global platform registry"""
139
139
  if PlatformRegistry.global_platform_registry is None:
140
- PlatformRegistry.global_platform_registry = PlatformRegistry()
141
-
142
- # 从用户平台目录加载额外平台
143
- platform_dir = PlatformRegistry.get_platform_dir()
144
- if platform_dir and os.path.exists(platform_dir):
145
- for platform_name, platform_class in PlatformRegistry.load_platform_from_dir(platform_dir).items():
146
- PlatformRegistry.global_platform_registry.register_platform(platform_name, platform_class)
147
- platform_dir = os.path.dirname(__file__)
148
- if platform_dir and os.path.exists(platform_dir):
149
- for platform_name, platform_class in PlatformRegistry.load_platform_from_dir(platform_dir).items():
150
- PlatformRegistry.global_platform_registry.register_platform(platform_name, platform_class)
140
+ PlatformRegistry.global_platform_registry = PlatformRegistry()
151
141
  return PlatformRegistry.global_platform_registry
152
142
 
153
143
  def __init__(self):
154
144
  """Initialize platform registry"""
155
145
  self.platforms: Dict[str, Type[BasePlatform]] = {}
146
+ # 从用户平台目录加载额外平台
147
+ platform_dir = PlatformRegistry.get_platform_dir()
148
+ if platform_dir and os.path.exists(platform_dir):
149
+ for platform_name, platform_class in PlatformRegistry.load_platform_from_dir(platform_dir).items():
150
+ self.register_platform(platform_name, platform_class)
151
+ platform_dir = os.path.dirname(__file__)
152
+ if platform_dir and os.path.exists(platform_dir):
153
+ for platform_name, platform_class in PlatformRegistry.load_platform_from_dir(platform_dir).items():
154
+ self.register_platform(platform_name, platform_class)
155
+
156
156
 
157
157
  def get_normal_platform(self) -> BasePlatform:
158
158
  platform_name = os.environ.get("JARVIS_PLATFORM", "kimi")
@@ -212,6 +212,29 @@ class PlatformRegistry:
212
212
  PrettyOutput.print(f"Create platform failed: {str(e)}", OutputType.ERROR)
213
213
  return None
214
214
 
215
+ def use_platforms(self, platform_names: List[str]):
216
+ """Restrict available platforms to the specified list
217
+
218
+ Args:
219
+ platform_names: List of platform names to use
220
+ """
221
+ self.platforms = {
222
+ name: cls
223
+ for name, cls in self.platforms.items()
224
+ if name in platform_names
225
+ }
226
+
227
+ def dont_use_platforms(self, platform_names: List[str]):
228
+ """Restrict available platforms by excluding the specified list
229
+
230
+ Args:
231
+ platform_names: List of platform names to exclude
232
+ """
233
+ self.platforms = {
234
+ name: cls
235
+ for name, cls in self.platforms.items()
236
+ if name not in platform_names
237
+ }
215
238
  def get_available_platforms(self) -> List[str]:
216
239
  """Get available platform list"""
217
240
  return list(self.platforms.keys())
jarvis/tools/ask_user.py CHANGED
@@ -39,16 +39,19 @@ class AskUserTool:
39
39
  if user_response == "__interrupt__":
40
40
  return {
41
41
  "success": False,
42
- "error": "User canceled input"
42
+ "stdout": "",
43
+ "stderr": "User canceled input"
43
44
  }
44
45
 
45
46
  return {
46
47
  "success": True,
47
- "stdout": user_response
48
+ "stdout": user_response,
49
+ "stderr": ""
48
50
  }
49
51
 
50
52
  except Exception as e:
51
53
  return {
52
54
  "success": False,
53
- "error": f"Failed to ask user: {str(e)}"
55
+ "stdout": "",
56
+ "stderr": f"Failed to ask user: {str(e)}"
54
57
  }
jarvis/tools/chdir.py CHANGED
@@ -38,14 +38,16 @@ class ChdirTool:
38
38
  if not os.path.exists(path):
39
39
  return {
40
40
  "success": False,
41
- "error": f"Directory does not exist: {path}"
41
+ "stdout": "",
42
+ "stderr": f"Directory does not exist: {path}"
42
43
  }
43
44
 
44
45
  # 检查是否是目录
45
46
  if not os.path.isdir(path):
46
47
  return {
47
48
  "success": False,
48
- "error": f"The path is not a directory: {path}"
49
+ "stdout": "",
50
+ "stderr": f"The path is not a directory: {path}"
49
51
  }
50
52
 
51
53
  # 尝试切换目录
@@ -61,12 +63,14 @@ class ChdirTool:
61
63
  except PermissionError:
62
64
  return {
63
65
  "success": False,
64
- "error": f"No permission to access directory: {path}"
66
+ "stdout": "",
67
+ "stderr": f"No permission to access directory: {path}"
65
68
  }
66
69
  except Exception as e:
67
70
  return {
68
71
  "success": False,
69
- "error": f"Failed to switch directory: {str(e)}"
72
+ "stdout": "",
73
+ "stderr": f"Failed to switch directory: {str(e)}"
70
74
  }
71
75
 
72
76
  def main():
@@ -83,7 +87,7 @@ def main():
83
87
  if result["success"]:
84
88
  PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
85
89
  else:
86
- PrettyOutput.print(result["error"], OutputType.ERROR)
90
+ PrettyOutput.print(result["stderr"], OutputType.ERROR)
87
91
 
88
92
  if __name__ == "__main__":
89
93
  main()
@@ -51,5 +51,6 @@ class CodeSubAgentTool:
51
51
  PrettyOutput.print(str(e), OutputType.ERROR)
52
52
  return {
53
53
  "success": False,
54
- "error": f"Failed to execute code development subtask: {str(e)}"
54
+ "stdout": "",
55
+ "stderr": f"Failed to execute code development subtask: {str(e)}"
55
56
  }
@@ -81,5 +81,6 @@ class SubAgentTool:
81
81
  PrettyOutput.print(str(e), OutputType.ERROR)
82
82
  return {
83
83
  "success": False,
84
- "error": f"Sub-agent execution failed: {str(e)}"
84
+ "stdout": "",
85
+ "stderr": f"Sub-agent execution failed: {str(e)}"
85
86
  }
@@ -43,7 +43,7 @@ class CodeModifyTool:
43
43
  patch_handler = PatchHandler()
44
44
 
45
45
  # Apply patches and handle the process
46
- success = patch_handler.handle_patch_application(
46
+ success, additional_info = patch_handler.handle_patch_application(
47
47
  feature=task,
48
48
  structed_plan=structured_plan
49
49
  )
@@ -51,22 +51,20 @@ class CodeModifyTool:
51
51
  if not success:
52
52
  return {
53
53
  "success": False,
54
- "error": "Code modification was cancelled or failed",
55
54
  "stdout": "Changes have been rolled back",
56
- "stderr": ""
55
+ "stderr": additional_info
57
56
  }
58
57
 
59
58
  return {
60
59
  "success": True,
61
60
  "stdout": "Code modifications have been successfully applied and committed",
62
- "stderr": ""
61
+ "stderr": additional_info
63
62
  }
64
63
 
65
64
  except Exception as e:
66
65
  PrettyOutput.print(str(e), OutputType.ERROR)
67
66
  return {
68
67
  "success": False,
69
- "error": f"Failed to execute code modifications: {str(e)}",
70
68
  "stdout": "",
71
- "stderr": str(e)
69
+ "stderr": f"Failed to execute code modifications: {str(e)}"
72
70
  }
@@ -64,7 +64,6 @@ class ShellTool:
64
64
  "success": return_code == 0,
65
65
  "stdout": output,
66
66
  "stderr": "",
67
- "return_code": return_code
68
67
  }
69
68
 
70
69
  except Exception as e:
@@ -74,5 +73,6 @@ class ShellTool:
74
73
  PrettyOutput.print(str(e), OutputType.ERROR)
75
74
  return {
76
75
  "success": False,
77
- "error": str(e)
76
+ "stdout": "",
77
+ "stderr": str(e)
78
78
  }
@@ -57,14 +57,16 @@ class FileOperationTool:
57
57
  if not os.path.exists(filepath):
58
58
  return {
59
59
  "success": False,
60
- "error": f"文件不存在: {filepath}"
60
+ "stdout": "",
61
+ "stderr": f"文件不存在: {filepath}"
61
62
  }
62
63
 
63
64
  # Check file size
64
65
  if os.path.getsize(filepath) > 10 * 1024 * 1024: # 10MB
65
66
  return {
66
67
  "success": False,
67
- "error": "File too large (>10MB)"
68
+ "stdout": "",
69
+ "stderr": "File too large (>10MB)"
68
70
  }
69
71
 
70
72
  content = open(filepath, 'r', encoding=encoding).read()
@@ -79,7 +81,8 @@ class FileOperationTool:
79
81
  if not args.get("content"):
80
82
  return {
81
83
  "success": False,
82
- "error": "Write/append operation requires providing the content parameter"
84
+ "stdout": "",
85
+ "stderr": "Write/append operation requires providing the content parameter"
83
86
  }
84
87
 
85
88
  # Create directory (if it doesn't exist)
@@ -98,12 +101,14 @@ class FileOperationTool:
98
101
  else:
99
102
  return {
100
103
  "success": False,
101
- "error": f"Unknown operation: {operation}"
104
+ "stdout": "",
105
+ "stderr": f"Unknown operation: {operation}"
102
106
  }
103
107
 
104
108
  except Exception as e:
105
109
  PrettyOutput.print(str(e), OutputType.ERROR)
106
110
  return {
107
111
  "success": False,
108
- "error": f"File operation failed: {str(e)}"
112
+ "stdout": "",
113
+ "stderr": f"File operation failed: {str(e)}"
109
114
  }
@@ -0,0 +1,119 @@
1
+ from typing import Dict, Any
2
+
3
+ from jarvis.agent import Agent
4
+ from jarvis.tools.registry import ToolRegistry
5
+ from jarvis.utils import OutputType, PrettyOutput
6
+
7
+ find_files_system_prompt = """You are a Find Files Agent specialized in searching and identifying relevant code files in a codebase. Your task is to find files that are most likely related to the given requirements or problems.
8
+
9
+ SEARCH WORKFLOW:
10
+ 1. Understand Search Requirements
11
+ - Analyze the search query thoroughly
12
+ - Identify key technical terms and concepts
13
+ - Break down complex requirements into searchable terms
14
+
15
+ 2. Execute Search Strategy
16
+ - Use shell commands to search systematically:
17
+ * Search for key terms:
18
+ <TOOL_CALL>
19
+ name: execute_shell
20
+ arguments:
21
+ command: grep -r "pattern" .
22
+ </TOOL_CALL>
23
+ * Find files by name patterns:
24
+ <TOOL_CALL>
25
+ name: execute_shell
26
+ arguments:
27
+ command: find . -name "pattern"
28
+ </TOOL_CALL>
29
+ * Examine file contents:
30
+ <TOOL_CALL>
31
+ name: execute_shell
32
+ arguments:
33
+ command: grep -A 5 -B 5 "pattern" file.py
34
+ </TOOL_CALL>
35
+
36
+ 3. Analyze Results
37
+ - Review each potential file
38
+ - Check file relevance
39
+ - Examine file relationships
40
+ - Consider file dependencies
41
+
42
+ 4. Generate File List
43
+ - List all relevant files
44
+ - Sort by relevance
45
+ - Include brief explanation for each file
46
+ - Format output as YAML
47
+
48
+ OUTPUT FORMAT:
49
+ files:
50
+ - path: path/to/file1
51
+ relevance: "Brief explanation of why this file is relevant"
52
+ - path: path/to/file2
53
+ relevance: "Brief explanation of why this file is relevant"
54
+
55
+ SEARCH BEST PRACTICES:
56
+ - Use multiple search terms
57
+ - Consider file naming conventions
58
+ - Check both file names and contents
59
+ - Look for related files (imports, dependencies)
60
+ - Use grep with context (-A, -B options)
61
+ - Search in specific directories when appropriate
62
+ - Exclude irrelevant directories (like .git, __pycache__)
63
+
64
+ IMPORTANT:
65
+ 1. Focus on finding the most relevant files
66
+ 2. Avoid listing irrelevant files
67
+ 3. Explain relevance clearly but concisely
68
+ 4. Consider both direct and indirect relevance
69
+ 5. Use file content to confirm relevance
70
+ """
71
+
72
+ class FindFilesTool:
73
+ name = "find_files"
74
+ description = "Search and identify relevant code files in the codebase based on requirements or problems"
75
+ parameters = {
76
+ "type": "object",
77
+ "properties": {
78
+ "query": {
79
+ "type": "string",
80
+ "description": "The search query or requirement description"
81
+ }
82
+ },
83
+ "required": ["query"]
84
+ }
85
+
86
+ def execute(self, args: Dict) -> Dict[str, Any]:
87
+ """Execute file search task"""
88
+ try:
89
+ query = args["query"]
90
+
91
+ PrettyOutput.print(f"Creating Find Files agent to search for: {query}", OutputType.INFO)
92
+
93
+ tool_registry = ToolRegistry()
94
+ tool_registry.use_tools(["ask_user", "execute_shell", "file_operation"])
95
+
96
+ # Create find files agent
97
+ find_agent = Agent(
98
+ system_prompt=find_files_system_prompt,
99
+ name="Find Files Agent",
100
+ is_sub_agent=True,
101
+ tool_registry=tool_registry
102
+ )
103
+
104
+ # Execute search
105
+ result = find_agent.run(query)
106
+
107
+ return {
108
+ "success": True,
109
+ "stdout": result,
110
+ "stderr": ""
111
+ }
112
+
113
+ except Exception as e:
114
+ PrettyOutput.print(str(e), OutputType.ERROR)
115
+ return {
116
+ "success": False,
117
+ "stdout": "",
118
+ "stderr": f"Failed to execute file search: {str(e)}"
119
+ }
@@ -32,16 +32,15 @@ class ToolGeneratorTool:
32
32
  }
33
33
 
34
34
  def __init__(self):
35
- """初始化工具生成器
36
- """
37
- # 设置工具目录
38
- self.tools_dir = Path.home() / '.jarvis_tools'
35
+ """Initialize tool generator"""
36
+ # Set tool directory
37
+ self.tools_dir = Path.home() / '.jarvis/tools'
39
38
 
40
- # 确保工具目录存在
39
+ # Ensure tool directory exists
41
40
  self.tools_dir.mkdir(parents=True, exist_ok=True)
42
41
 
43
42
  def _generate_tool_code(self, tool_name: str, class_name: str, description: str, parameters: Dict) -> str:
44
- """使用大模型生成工具代码"""
43
+ """Use large model to generate tool code"""
45
44
  model = PlatformRegistry.get_global_platform_registry().get_codegen_platform()
46
45
 
47
46
  prompt = f"""Please generate the code for a Python tool class, with the following requirements, and do not output any content except the code:
@@ -96,36 +95,37 @@ class ExampleTool:
96
95
  PrettyOutput.print(str(e), OutputType.ERROR)
97
96
  return {{
98
97
  "success": False,
99
- "error": str(e)
98
+ "stdout": "",
99
+ "stderr": str(e)
100
100
  }}
101
101
  ```"""
102
102
 
103
- # 调用模型生成代码
103
+ # Call model to generate code
104
104
  response = model.chat_until_success(prompt)
105
105
 
106
- # 提取代码块
106
+ # Extract code block
107
107
  code_start = response.find("```python")
108
108
  code_end = response.find("```", code_start + 9)
109
109
 
110
110
  if code_start == -1 or code_end == -1:
111
- # 如果没有找到代码块标记,假设整个响应都是代码
111
+ # If code block marker not found, assume the entire response is code
112
112
  return response
113
113
 
114
- # 提取代码块内容(去掉```python和```标记)
114
+ # Extract code block content (remove ```python and ``` markers)
115
115
  code = response[code_start + 9:code_end].strip()
116
116
  return code
117
117
 
118
118
  def execute(self, args: Dict) -> Dict[str, Any]:
119
- """生成工具代码"""
119
+ """Generate tool code"""
120
120
  try:
121
121
  tool_name = args["tool_name"]
122
122
  class_name = args["class_name"]
123
123
  description = args["description"]
124
124
  parameters = args["parameters"]
125
125
 
126
- PrettyOutput.print(f"开始生成工具: {tool_name}", OutputType.INFO)
126
+ PrettyOutput.print(f"Start generating tool: {tool_name}", OutputType.INFO)
127
127
 
128
- # 生成工具代码
128
+ # Generate tool code
129
129
  tool_code = self._generate_tool_code(
130
130
  tool_name,
131
131
  class_name,
@@ -133,34 +133,35 @@ class ExampleTool:
133
133
  parameters
134
134
  )
135
135
 
136
- # 获取工具文件路径
136
+ # Get tool file path
137
137
  tool_file = self.tools_dir / f"{tool_name}.py"
138
138
 
139
- # 写入工具文件
139
+ # Write tool file
140
140
  with open(tool_file, "w", encoding="utf-8") as f:
141
141
  f.write(tool_code)
142
142
 
143
- # 创建或更新 __init__.py
143
+ # Create or update __init__.py
144
144
  init_file = self.tools_dir / "__init__.py"
145
145
  if not init_file.exists():
146
146
  with open(init_file, "w", encoding="utf-8") as f:
147
147
  f.write("# Jarvis Tools\n")
148
148
 
149
- # 注册工具
149
+ # Register tool
150
150
  success = ToolRegistry.get_global_tool_registry().register_tool_by_file(str(tool_file))
151
151
  if not success:
152
152
  return {
153
153
  "success": False,
154
- "error": "工具生成成功但注册失败"
154
+ "stdout": "",
155
+ "stderr": "Tool generated successfully but registration failed"
155
156
  }
156
157
 
157
158
  return {
158
159
  "success": True,
159
- "stdout": f"工具已生成并注册到Jarvis\n"
160
- f"工具目录: {self.tools_dir}\n"
161
- f"工具名称: {tool_name}\n"
162
- f"工具描述: {description}\n"
163
- f"工具参数: {parameters}",
160
+ "stdout": f"Tool generated and registered to Jarvis\n"
161
+ f"Tool directory: {self.tools_dir}\n"
162
+ f"Tool name: {tool_name}\n"
163
+ f"Tool description: {description}\n"
164
+ f"Tool parameters: {parameters}",
164
165
  "stderr": ""
165
166
  }
166
167
 
@@ -168,5 +169,6 @@ class ExampleTool:
168
169
  PrettyOutput.print(str(e), OutputType.ERROR)
169
170
  return {
170
171
  "success": False,
171
- "error": f"生成工具失败: {str(e)}"
172
+ "stdout": "",
173
+ "stderr": f"Failed to generate tool: {str(e)}"
172
174
  }
@@ -32,7 +32,7 @@ class MethodologyTool:
32
32
 
33
33
  def __init__(self):
34
34
  """Initialize the experience management tool"""
35
- self.methodology_file = os.path.expanduser("~/.jarvis_methodology")
35
+ self.methodology_file = os.path.expanduser("~/.jarvis/methodology")
36
36
  self._ensure_file_exists()
37
37
 
38
38
  def _ensure_file_exists(self):
@@ -80,7 +80,8 @@ class MethodologyTool:
80
80
  if not operation or not problem_type:
81
81
  return {
82
82
  "success": False,
83
- "error": "Missing required parameters: operation and problem_type"
83
+ "stdout": "",
84
+ "stderr": "Missing required parameters: operation and problem_type"
84
85
  }
85
86
 
86
87
  methodologies = self._load_methodologies()
@@ -97,14 +98,16 @@ class MethodologyTool:
97
98
  else:
98
99
  return {
99
100
  "success": False,
100
- "error": f"Methodology for problem type '{problem_type}' not found"
101
+ "stdout": "",
102
+ "stderr": f"Methodology for problem type '{problem_type}' not found"
101
103
  }
102
104
 
103
105
  elif operation in ["update", "add"]:
104
106
  if not content:
105
107
  return {
106
108
  "success": False,
107
- "error": "Need to provide methodology content"
109
+ "stdout": "",
110
+ "stderr": "Need to provide methodology content"
108
111
  }
109
112
 
110
113
  methodologies[problem_type] = content
@@ -113,19 +116,22 @@ class MethodologyTool:
113
116
  action = "Update" if problem_type in methodologies else "Add"
114
117
  return {
115
118
  "success": True,
116
- "stdout": f"{action} methodology for problem type '{problem_type}'"
119
+ "stdout": f"{action} methodology for problem type '{problem_type}'",
120
+ "stderr": ""
117
121
  }
118
122
 
119
123
  else:
120
124
  return {
121
125
  "success": False,
122
- "error": f"Unsupported operation type: {operation}"
126
+ "stdout": "",
127
+ "stderr": f"Unsupported operation type: {operation}"
123
128
  }
124
129
 
125
130
  except Exception as e:
126
131
  return {
127
132
  "success": False,
128
- "error": f"Execution failed: {str(e)}"
133
+ "stdout": "",
134
+ "stderr": f"Execution failed: {str(e)}"
129
135
  }
130
136
 
131
137
  def get_methodology(self, problem_type: str) -> Optional[str]: