jarvis-ai-assistant 0.1.98__py3-none-any.whl → 0.1.99__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 (40) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +199 -157
  3. jarvis/jarvis_code_agent/__init__.py +0 -0
  4. jarvis/jarvis_code_agent/main.py +203 -0
  5. jarvis/jarvis_codebase/main.py +412 -284
  6. jarvis/jarvis_coder/file_select.py +209 -0
  7. jarvis/jarvis_coder/git_utils.py +64 -2
  8. jarvis/jarvis_coder/main.py +11 -389
  9. jarvis/jarvis_coder/patch_handler.py +84 -14
  10. jarvis/jarvis_coder/plan_generator.py +49 -7
  11. jarvis/jarvis_rag/main.py +9 -9
  12. jarvis/jarvis_smart_shell/main.py +5 -7
  13. jarvis/models/base.py +6 -1
  14. jarvis/models/ollama.py +2 -2
  15. jarvis/models/registry.py +3 -6
  16. jarvis/tools/ask_user.py +6 -6
  17. jarvis/tools/codebase_qa.py +5 -7
  18. jarvis/tools/create_code_sub_agent.py +55 -0
  19. jarvis/tools/{sub_agent.py → create_sub_agent.py} +4 -1
  20. jarvis/tools/execute_code_modification.py +72 -0
  21. jarvis/tools/{file_ops.py → file_operation.py} +13 -14
  22. jarvis/tools/find_related_files.py +86 -0
  23. jarvis/tools/methodology.py +25 -25
  24. jarvis/tools/rag.py +32 -32
  25. jarvis/tools/registry.py +72 -36
  26. jarvis/tools/search.py +1 -1
  27. jarvis/tools/select_code_files.py +64 -0
  28. jarvis/utils.py +153 -49
  29. {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/METADATA +1 -1
  30. jarvis_ai_assistant-0.1.99.dist-info/RECORD +52 -0
  31. {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/entry_points.txt +2 -1
  32. jarvis/main.py +0 -155
  33. jarvis/tools/coder.py +0 -69
  34. jarvis_ai_assistant-0.1.98.dist-info/RECORD +0 -47
  35. /jarvis/tools/{shell.py → execute_shell.py} +0 -0
  36. /jarvis/tools/{generator.py → generate_tool.py} +0 -0
  37. /jarvis/tools/{webpage.py → read_webpage.py} +0 -0
  38. {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/LICENSE +0 -0
  39. {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/WHEEL +0 -0
  40. {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,7 @@ from jarvis.utils import OutputType, PrettyOutput
5
5
 
6
6
 
7
7
  class MethodologyTool:
8
- """经验管理工具"""
8
+ """Experience management tool"""
9
9
 
10
10
  name = "methodology"
11
11
  description = "Manage problem-solving methodologies, supporting add, update, and delete operations"
@@ -31,47 +31,47 @@ class MethodologyTool:
31
31
  }
32
32
 
33
33
  def __init__(self):
34
- """初始化经验管理工具"""
34
+ """Initialize the experience management tool"""
35
35
  self.methodology_file = os.path.expanduser("~/.jarvis_methodology")
36
36
  self._ensure_file_exists()
37
37
 
38
38
  def _ensure_file_exists(self):
39
- """确保方法论文件存在"""
39
+ """Ensure the methodology file exists"""
40
40
  if not os.path.exists(self.methodology_file):
41
41
  try:
42
42
  with open(self.methodology_file, 'w', encoding='utf-8') as f:
43
43
  yaml.safe_dump({}, f, allow_unicode=True)
44
44
  except Exception as e:
45
- PrettyOutput.print(f"创建方法论文件失败: {str(e)}", OutputType.ERROR)
45
+ PrettyOutput.print(f"Failed to create methodology file: {str(e)}", OutputType.ERROR)
46
46
 
47
47
  def _load_methodologies(self) -> Dict:
48
- """加载所有方法论"""
48
+ """Load all methodologies"""
49
49
  try:
50
50
  with open(self.methodology_file, 'r', encoding='utf-8') as f:
51
51
  return yaml.safe_load(f) or {}
52
52
  except Exception as e:
53
- PrettyOutput.print(f"加载方法论失败: {str(e)}", OutputType.ERROR)
53
+ PrettyOutput.print(f"Failed to load methodologies: {str(e)}", OutputType.ERROR)
54
54
  return {}
55
55
 
56
56
  def _save_methodologies(self, methodologies: Dict):
57
- """保存所有方法论"""
57
+ """Save all methodologies"""
58
58
  try:
59
59
  with open(self.methodology_file, 'w', encoding='utf-8') as f:
60
60
  yaml.safe_dump(methodologies, f, allow_unicode=True)
61
61
  except Exception as e:
62
- PrettyOutput.print(f"保存方法论失败: {str(e)}", OutputType.ERROR)
62
+ PrettyOutput.print(f"Failed to save methodologies: {str(e)}", OutputType.ERROR)
63
63
 
64
64
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
65
- """执行方法论管理操作
65
+ """Execute the operation of managing methodologies
66
66
 
67
67
  Args:
68
- args: 包含操作参数的字典
69
- - operation: 操作类型 (delete/update/add)
70
- - problem_type: 问题类型
71
- - content: 方法论内容 (update/add 时必需)
68
+ args: A dictionary containing the operation parameters
69
+ - operation: The operation type (delete/update/add)
70
+ - problem_type: The problem type
71
+ - content: The methodology content (required for update/add)
72
72
 
73
73
  Returns:
74
- Dict[str, Any]: 包含执行结果的字典
74
+ Dict[str, Any]: A dictionary containing the execution result
75
75
  """
76
76
  operation = args.get("operation")
77
77
  problem_type = args.get("problem_type")
@@ -80,7 +80,7 @@ class MethodologyTool:
80
80
  if not operation or not problem_type:
81
81
  return {
82
82
  "success": False,
83
- "error": "缺少必要参数: operation problem_type"
83
+ "error": "Missing required parameters: operation and problem_type"
84
84
  }
85
85
 
86
86
  methodologies = self._load_methodologies()
@@ -92,50 +92,50 @@ class MethodologyTool:
92
92
  self._save_methodologies(methodologies)
93
93
  return {
94
94
  "success": True,
95
- "stdout": f"已删除问题类型 '{problem_type}' 的方法论"
95
+ "stdout": f"Deleted methodology for problem type '{problem_type}'"
96
96
  }
97
97
  else:
98
98
  return {
99
99
  "success": False,
100
- "error": f"未找到问题类型 '{problem_type}' 的方法论"
100
+ "error": f"Methodology for problem type '{problem_type}' not found"
101
101
  }
102
102
 
103
103
  elif operation in ["update", "add"]:
104
104
  if not content:
105
105
  return {
106
106
  "success": False,
107
- "error": "需要提供方法论内容"
107
+ "error": "Need to provide methodology content"
108
108
  }
109
109
 
110
110
  methodologies[problem_type] = content
111
111
  self._save_methodologies(methodologies)
112
112
 
113
- action = "更新" if problem_type in methodologies else "添加"
113
+ action = "Update" if problem_type in methodologies else "Add"
114
114
  return {
115
115
  "success": True,
116
- "stdout": f"{action}问题类型 '{problem_type}' 的方法论"
116
+ "stdout": f"{action} methodology for problem type '{problem_type}'"
117
117
  }
118
118
 
119
119
  else:
120
120
  return {
121
121
  "success": False,
122
- "error": f"不支持的操作类型: {operation}"
122
+ "error": f"Unsupported operation type: {operation}"
123
123
  }
124
124
 
125
125
  except Exception as e:
126
126
  return {
127
127
  "success": False,
128
- "error": f"执行失败: {str(e)}"
128
+ "error": f"Execution failed: {str(e)}"
129
129
  }
130
130
 
131
131
  def get_methodology(self, problem_type: str) -> Optional[str]:
132
- """获取指定问题类型的方法论
132
+ """Get the methodology for a specific problem type
133
133
 
134
134
  Args:
135
- problem_type: 问题类型
135
+ problem_type: The problem type
136
136
 
137
137
  Returns:
138
- Optional[str]: 方法论内容,如果不存在则返回 None
138
+ Optional[str]: The methodology content, or None if it does not exist
139
139
  """
140
140
  methodologies = self._load_methodologies()
141
141
  return methodologies.get(problem_type)
jarvis/tools/rag.py CHANGED
@@ -27,71 +27,71 @@ class RAGTool:
27
27
  }
28
28
 
29
29
  def __init__(self):
30
- """初始化 RAG 工具"""
31
- self.rag_instances = {} # 缓存不同目录的 RAG 实例
30
+ """Initialize RAG tool"""
31
+ self.rag_instances = {} # Cache RAG instances for different directories
32
32
 
33
33
  def _get_rag_instance(self, dir_path: str) -> RAGCore:
34
- """获取或创建 RAG 实例
34
+ """Get or create RAG instance
35
35
 
36
36
  Args:
37
- dir_path: 文档目录的绝对路径
37
+ dir_path: The absolute path of the document directory
38
38
 
39
39
  Returns:
40
- RAGCore: RAG 实例
40
+ RAGCore: RAG instance
41
41
  """
42
42
  if dir_path not in self.rag_instances:
43
43
  self.rag_instances[dir_path] = RAGCore(dir_path)
44
44
  return self.rag_instances[dir_path]
45
45
 
46
46
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
47
- """执行文档问答
47
+ """Execute document question and answer
48
48
 
49
49
  Args:
50
- args: 包含参数的字典
51
- - dir: 文档目录路径
52
- - question: 要询问的问题
53
- - rebuild_index: 是否重建索引
50
+ args: A dictionary containing parameters
51
+ - dir: The document directory path
52
+ - question: The question to ask
53
+ - rebuild_index: Whether to rebuild the index
54
54
 
55
55
  Returns:
56
- Dict[str, Any]: 执行结果
56
+ Dict[str, Any]: The execution result
57
57
  """
58
58
  try:
59
- # 获取参数
60
- dir_path = os.path.expanduser(args["dir"]) # 展开 ~ 等路径
61
- dir_path = os.path.abspath(dir_path) # 转换为绝对路径
59
+ # Get parameters
60
+ dir_path = os.path.expanduser(args["dir"]) # Expand ~ paths
61
+ dir_path = os.path.abspath(dir_path) # Convert to absolute path
62
62
  question = args["question"]
63
63
  rebuild_index = args.get("rebuild_index", False)
64
64
 
65
- # 检查目录是否存在
65
+ # Check if the directory exists
66
66
  if not os.path.exists(dir_path):
67
67
  return {
68
68
  "success": False,
69
- "error": f"目录不存在: {dir_path}"
69
+ "error": f"Directory does not exist: {dir_path}"
70
70
  }
71
71
 
72
- # 检查是否是目录
72
+ # Check if it is a directory
73
73
  if not os.path.isdir(dir_path):
74
74
  return {
75
75
  "success": False,
76
- "error": f"路径不是目录: {dir_path}"
76
+ "error": f"The path is not a directory: {dir_path}"
77
77
  }
78
78
 
79
- # 获取 RAG 实例
79
+ # Get RAG instance
80
80
  rag = self._get_rag_instance(dir_path)
81
81
 
82
- # 如果需要重建索引或索引不存在
82
+ # If you need to rebuild the index or the index does not exist
83
83
  if rebuild_index or not rag.is_index_built():
84
- PrettyOutput.print("正在构建文档索引...", OutputType.INFO)
84
+ PrettyOutput.print("Building document index...", OutputType.INFO)
85
85
  rag.build_index(dir_path)
86
86
 
87
- # 执行问答
88
- PrettyOutput.print(f"问题: {question}", OutputType.INFO)
87
+ # Execute question and answer
88
+ PrettyOutput.print(f"Question: {question}", OutputType.INFO)
89
89
  response = rag.ask(question)
90
90
 
91
91
  if response is None:
92
92
  return {
93
93
  "success": False,
94
- "error": "未能获取答案,可能是没有找到相关文档"
94
+ "error": "Failed to get answer, possibly no relevant documents found"
95
95
  }
96
96
 
97
97
  return {
@@ -101,20 +101,20 @@ class RAGTool:
101
101
  }
102
102
 
103
103
  except Exception as e:
104
- PrettyOutput.print(f"文档问答失败: {str(e)}", OutputType.ERROR)
104
+ PrettyOutput.print(f"Document question and answer failed: {str(e)}", OutputType.ERROR)
105
105
  return {
106
106
  "success": False,
107
- "error": f"执行失败: {str(e)}"
107
+ "error": f"Execution failed: {str(e)}"
108
108
  }
109
109
 
110
110
  def main():
111
- """命令行直接运行工具"""
111
+ """Run the tool directly from the command line"""
112
112
  import argparse
113
113
 
114
- parser = argparse.ArgumentParser(description='文档问答工具')
115
- parser.add_argument('--dir', required=True, help='文档目录路径')
116
- parser.add_argument('--question', required=True, help='要询问的问题')
117
- parser.add_argument('--rebuild', action='store_true', help='重建索引')
114
+ parser = argparse.ArgumentParser(description='Document question and answer tool')
115
+ parser.add_argument('--dir', required=True, help='Document directory path')
116
+ parser.add_argument('--question', required=True, help='The question to ask')
117
+ parser.add_argument('--rebuild', action='store_true', help='Rebuild index')
118
118
  args = parser.parse_args()
119
119
 
120
120
  tool = RAGTool()
@@ -125,7 +125,7 @@ def main():
125
125
  })
126
126
 
127
127
  if result["success"]:
128
- PrettyOutput.print("\n回答:", OutputType.INFO)
128
+ PrettyOutput.print("\nAnswer:", OutputType.INFO)
129
129
  PrettyOutput.print(result["stdout"], OutputType.INFO)
130
130
  else:
131
131
  PrettyOutput.print(result["error"], OutputType.ERROR)
jarvis/tools/registry.py CHANGED
@@ -10,67 +10,93 @@ from jarvis.tools.base import Tool
10
10
  from jarvis.utils import OutputType, PrettyOutput, get_max_context_length
11
11
 
12
12
 
13
+
14
+ def load_tools() -> str:
15
+ """Load tools"""
16
+ PrettyOutput.section("Available tools", OutputType.PLANNING)
17
+ tools = ToolRegistry.get_global_tool_registry().get_all_tools()
18
+ if tools:
19
+ tools_prompt = "Available tools:\n"
20
+ for tool in tools:
21
+ PrettyOutput.print(f"{tool['name']}: {tool['description']}", OutputType.INFO)
22
+ tools_prompt += f"- Name: {tool['name']}\n"
23
+ tools_prompt += f" Description: {tool['description']}\n"
24
+ tools_prompt += f" Parameters: {tool['parameters']}\n"
25
+ tools_prompt += f" Usage Format: <TOOL_CALL>\n"
26
+ tools_prompt += """
27
+ Tool Usage Format:
28
+
29
+ <TOOL_CALL>
30
+ name: tool_name
31
+ arguments:
32
+ param1: value1
33
+ param2: value2
34
+ </TOOL_CALL>
35
+ ---------------------------------------------
36
+ """
37
+ return tools_prompt
38
+ return ""
39
+
13
40
  class ToolRegistry:
14
41
  global_tool_registry = None # type: ignore
15
42
  def __init__(self):
16
- """初始化工具注册器
17
- """
43
+ """Initialize tool registry"""
18
44
  self.tools: Dict[str, Tool] = {}
19
- # 加载内置工具和外部工具
45
+ # Load built-in tools and external tools
20
46
  self._load_builtin_tools()
21
47
  self._load_external_tools()
22
- # 确保 max_context_length 是整数
48
+ # Ensure max_context_length is an integer
23
49
  self.max_context_length = int(get_max_context_length() * 0.8)
24
50
 
25
51
  @staticmethod
26
52
  def get_global_tool_registry():
27
- """获取全局工具注册器"""
53
+ """Get the global tool registry"""
28
54
  if ToolRegistry.global_tool_registry is None:
29
55
  ToolRegistry.global_tool_registry = ToolRegistry()
30
56
  return ToolRegistry.global_tool_registry
31
57
 
32
58
  def _load_builtin_tools(self):
33
- """从内置tools目录加载工具"""
59
+ """Load tools from the built-in tools directory"""
34
60
  tools_dir = Path(__file__).parent
35
61
 
36
- # 遍历目录下的所有.py文件
62
+ # Iterate through all .py files in the directory
37
63
  for file_path in tools_dir.glob("*.py"):
38
- # 跳过基础文件和__init__.py
64
+ # Skip base.py and __init__.py
39
65
  if file_path.name in ["base.py", "__init__.py", "registry.py"]:
40
66
  continue
41
67
 
42
68
  self.register_tool_by_file(str(file_path))
43
69
 
44
70
  def _load_external_tools(self):
45
- """从~/.jarvis_tools加载外部工具"""
71
+ """Load external tools from ~/.jarvis_tools"""
46
72
  external_tools_dir = Path.home() / '.jarvis_tools'
47
73
  if not external_tools_dir.exists():
48
74
  return
49
75
 
50
- # 遍历目录下的所有.py文件
76
+ # Iterate through all .py files in the directory
51
77
  for file_path in external_tools_dir.glob("*.py"):
52
- # 跳过__init__.py
78
+ # Skip __init__.py
53
79
  if file_path.name == "__init__.py":
54
80
  continue
55
81
 
56
82
  self.register_tool_by_file(str(file_path))
57
83
 
58
84
  def register_tool_by_file(self, file_path: str):
59
- """从指定文件加载并注册工具
85
+ """Load and register tools from a specified file
60
86
 
61
87
  Args:
62
- file_path: 工具文件的路径
88
+ file_path: The path of the tool file
63
89
 
64
90
  Returns:
65
- bool: 是否成功加载工具
91
+ bool: Whether the tool is loaded successfully
66
92
  """
67
93
  try:
68
- p_file_path = Path(file_path).resolve() # 获取绝对路径
94
+ p_file_path = Path(file_path).resolve() # Get the absolute path
69
95
  if not p_file_path.exists() or not p_file_path.is_file():
70
96
  PrettyOutput.print(f"File does not exist: {p_file_path}", OutputType.ERROR)
71
97
  return False
72
98
 
73
- # 动态导入模块
99
+ # Dynamically import the module
74
100
  module_name = p_file_path.stem
75
101
  spec = importlib.util.spec_from_file_location(module_name, p_file_path) # type: ignore
76
102
  if not spec or not spec.loader:
@@ -78,30 +104,29 @@ class ToolRegistry:
78
104
  return False
79
105
 
80
106
  module = importlib.util.module_from_spec(spec) # type: ignore
81
- sys.modules[module_name] = module # 添加到 sys.modules 以支持相对导入
107
+ sys.modules[module_name] = module # Add to sys.modules to support relative imports
82
108
  spec.loader.exec_module(module)
83
109
 
84
- # 查找模块中的工具类
110
+ # Find the tool class in the module
85
111
  tool_found = False
86
112
  for item_name in dir(module):
87
113
  item = getattr(module, item_name)
88
- # 检查是否是类,并且有必要的属性
114
+ # Check if it is a class and has the necessary attributes
89
115
  if (isinstance(item, type) and
90
116
  hasattr(item, 'name') and
91
117
  hasattr(item, 'description') and
92
118
  hasattr(item, 'parameters')):
93
119
 
94
- # 实例化工具类,传入模型和输出处理器
120
+ # Instantiate the tool class, passing in the model and output processor
95
121
  tool_instance = item()
96
122
 
97
- # 注册工具
123
+ # Register the tool
98
124
  self.register_tool(
99
125
  name=tool_instance.name,
100
126
  description=tool_instance.description,
101
127
  parameters=tool_instance.parameters,
102
128
  func=tool_instance.execute
103
129
  )
104
- PrettyOutput.print(f"Loaded tool from {p_file_path}: {tool_instance.name}: {tool_instance.description}", OutputType.SUCCESS)
105
130
  tool_found = True
106
131
  break
107
132
 
@@ -116,43 +141,54 @@ class ToolRegistry:
116
141
  return False
117
142
 
118
143
  def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
119
- """注册新工具"""
144
+ """Register a new tool"""
120
145
  self.tools[name] = Tool(name, description, parameters, func)
121
146
 
122
147
  def get_tool(self, name: str) -> Optional[Tool]:
123
- """获取工具"""
148
+ """Get a tool"""
124
149
  return self.tools.get(name)
125
150
 
126
151
  def get_all_tools(self) -> List[Dict]:
127
- """获取所有工具的Ollama格式定义"""
152
+ """Get all tools in Ollama format definition"""
128
153
  return [tool.to_dict() for tool in self.tools.values()]
129
154
 
130
155
  def execute_tool(self, name: str, arguments: Dict) -> Dict[str, Any]:
131
- """执行指定工具"""
156
+ """Execute a specified tool"""
132
157
  tool = self.get_tool(name)
133
158
  if tool is None:
134
- return {"success": False, "error": f"Tool {name} does not exist"}
159
+ return {"success": False, "error": f"Tool {name} does not exist, available tools: {', '.join(self.tools.keys())}"}
135
160
  return tool.execute(arguments)
136
161
 
137
162
  def handle_tool_calls(self, tool_calls: List[Dict]) -> str:
138
- """处理工具调用,只处理第一个工具"""
163
+ """Handle tool calls, only process the first tool"""
139
164
  try:
140
165
  if not tool_calls:
141
166
  return ""
142
167
 
143
- # 只处理第一个工具调用
168
+ # Only process the first tool call
144
169
  tool_call = tool_calls[0]
145
170
  name = tool_call["name"]
146
171
  args = tool_call["arguments"]
172
+
173
+ tool_call_help = """
174
+ Tool Usage Format:
175
+
176
+ <TOOL_CALL>
177
+ name: tool_name
178
+ arguments:
179
+ param1: value1
180
+ param2: value2
181
+ </TOOL_CALL>
182
+ """
147
183
 
148
184
  if isinstance(args, str):
149
185
  try:
150
186
  args = json.loads(args)
151
187
  except json.JSONDecodeError:
152
- PrettyOutput.print(f"Invalid tool parameters format: {name}", OutputType.ERROR)
188
+ PrettyOutput.print(f"Invalid tool parameters format: {name} {tool_call_help}", OutputType.ERROR)
153
189
  return ""
154
190
 
155
- # 显示工具调用信息
191
+ # Display tool call information
156
192
  PrettyOutput.section(f"Executing tool: {name}", OutputType.TOOL)
157
193
  if isinstance(args, dict):
158
194
  for key, value in args.items():
@@ -160,10 +196,10 @@ class ToolRegistry:
160
196
  else:
161
197
  PrettyOutput.print(f"Parameter: {args}", OutputType.DEBUG)
162
198
 
163
- # 执行工具调用
199
+ # Execute tool call
164
200
  result = self.execute_tool(name, args)
165
201
 
166
- # 处理结果
202
+ # Process the result
167
203
  if result["success"]:
168
204
  stdout = result["stdout"]
169
205
  stderr = result.get("stderr", "")
@@ -173,16 +209,16 @@ class ToolRegistry:
173
209
  if stderr:
174
210
  output_parts.append(f"Error:\n{stderr}")
175
211
  output = "\n\n".join(output_parts)
176
- output = "No output and error" if not output else output
212
+ output = "Tool execution successful, no output and error" if not output else output
177
213
  PrettyOutput.section("Execution successful", OutputType.SUCCESS)
178
214
 
179
- # 如果输出超过4k字符,使用大模型总结
215
+ # If the output exceeds 4k characters, use a large model to summarize
180
216
  if len(output) > self.max_context_length:
181
217
  try:
182
218
  PrettyOutput.print("Output is too long, summarizing...", OutputType.PROGRESS)
183
219
  model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
184
220
 
185
- # 如果输出超过最大上下文长度,只取最后部分
221
+ # If the output exceeds the maximum context length, only take the last part
186
222
  max_len = self.max_context_length
187
223
  if len(output) > max_len:
188
224
  output_to_summarize = output[-max_len:]
jarvis/tools/search.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from typing import Dict, Any, List
2
2
  from jarvis.models.registry import PlatformRegistry
3
3
  from jarvis.utils import PrettyOutput, OutputType
4
- from jarvis.tools.webpage import WebpageTool
4
+ from jarvis.tools.read_webpage import WebpageTool
5
5
  from playwright.sync_api import sync_playwright
6
6
  from urllib.parse import quote
7
7
 
@@ -0,0 +1,64 @@
1
+ from typing import Dict, Any, List
2
+
3
+ from jarvis.utils import OutputType, PrettyOutput
4
+ from jarvis.jarvis_coder.file_select import select_files
5
+
6
+
7
+ class CodeFileSelecterTool:
8
+ name = "select_code_files"
9
+ description = "Select and manage code files for modification with interactive file selection"
10
+ parameters = {
11
+ "type": "object",
12
+ "properties": {
13
+ "related_files": {
14
+ "type": "array",
15
+ "items": {
16
+ "type": "string",
17
+ },
18
+ "description": "List of initially related files",
19
+ "default": []
20
+ },
21
+ "root_dir": {
22
+ "type": "string",
23
+ "description": "Root directory of the codebase",
24
+ "default": "."
25
+ }
26
+ },
27
+ "required": ["related_files"]
28
+ }
29
+
30
+ def execute(self, args: Dict) -> Dict[str, Any]:
31
+ """Execute interactive file selection"""
32
+ try:
33
+ related_files = args["related_files"]
34
+ root_dir = args.get("root_dir", ".")
35
+
36
+ PrettyOutput.print("Starting interactive file selection...", OutputType.INFO)
37
+
38
+ # Use file_select module to handle file selection
39
+ selected_files = select_files(
40
+ related_files=related_files,
41
+ root_dir=root_dir
42
+ )
43
+
44
+ # Format output for display
45
+ output = "Selected files:\n"
46
+ for file in selected_files:
47
+ output += f"- {file}\n"
48
+
49
+ return {
50
+ "success": True,
51
+ "stdout": output,
52
+ "stderr": "",
53
+ "selected_files": selected_files # Return the selected files for other tools to use
54
+ }
55
+
56
+ except Exception as e:
57
+ PrettyOutput.print(str(e), OutputType.ERROR)
58
+ return {
59
+ "success": False,
60
+ "error": f"Failed to select files: {str(e)}",
61
+ "stdout": "",
62
+ "stderr": str(e),
63
+ "selected_files": [] # Return empty list on error
64
+ }