jarvis-ai-assistant 0.1.132__py3-none-any.whl → 0.1.138__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +330 -347
- jarvis/jarvis_agent/builtin_input_handler.py +16 -6
- jarvis/jarvis_agent/file_input_handler.py +9 -9
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +12 -13
- jarvis/jarvis_agent/output_handler.py +3 -3
- jarvis/jarvis_agent/patch.py +92 -64
- jarvis/jarvis_agent/shell_input_handler.py +5 -3
- jarvis/jarvis_code_agent/code_agent.py +263 -177
- jarvis/jarvis_code_agent/file_select.py +24 -24
- jarvis/jarvis_dev/main.py +45 -59
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +179 -0
- jarvis/jarvis_git_squash/main.py +7 -7
- jarvis/jarvis_lsp/base.py +11 -53
- jarvis/jarvis_lsp/cpp.py +13 -28
- jarvis/jarvis_lsp/go.py +13 -28
- jarvis/jarvis_lsp/python.py +8 -27
- jarvis/jarvis_lsp/registry.py +21 -83
- jarvis/jarvis_lsp/rust.py +15 -30
- jarvis/jarvis_methodology/main.py +101 -0
- jarvis/jarvis_multi_agent/__init__.py +10 -51
- jarvis/jarvis_multi_agent/main.py +43 -0
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/ai8.py +67 -89
- jarvis/jarvis_platform/base.py +14 -13
- jarvis/jarvis_platform/kimi.py +25 -28
- jarvis/jarvis_platform/ollama.py +24 -26
- jarvis/jarvis_platform/openai.py +15 -19
- jarvis/jarvis_platform/oyi.py +48 -50
- jarvis/jarvis_platform/registry.py +29 -44
- jarvis/jarvis_platform/yuanbao.py +39 -43
- jarvis/jarvis_platform_manager/main.py +81 -81
- jarvis/jarvis_platform_manager/openai_test.py +21 -21
- jarvis/jarvis_rag/file_processors.py +18 -18
- jarvis/jarvis_rag/main.py +262 -278
- jarvis/jarvis_smart_shell/main.py +12 -12
- jarvis/jarvis_tools/ask_codebase.py +85 -78
- jarvis/jarvis_tools/ask_user.py +8 -8
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +9 -9
- jarvis/jarvis_tools/code_review.py +40 -21
- jarvis/jarvis_tools/create_code_agent.py +15 -15
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- jarvis/jarvis_tools/execute_python_script.py +3 -3
- jarvis/jarvis_tools/execute_shell.py +11 -11
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_analyzer.py +116 -105
- jarvis/jarvis_tools/file_operation.py +22 -20
- jarvis/jarvis_tools/find_caller.py +105 -40
- jarvis/jarvis_tools/find_methodolopy.py +65 -0
- jarvis/jarvis_tools/find_symbol.py +123 -39
- jarvis/jarvis_tools/function_analyzer.py +140 -57
- jarvis/jarvis_tools/git_commiter.py +10 -10
- jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
- jarvis/jarvis_tools/methodology.py +22 -67
- jarvis/jarvis_tools/project_analyzer.py +137 -53
- jarvis/jarvis_tools/rag.py +15 -20
- jarvis/jarvis_tools/read_code.py +25 -23
- jarvis/jarvis_tools/read_webpage.py +31 -31
- jarvis/jarvis_tools/registry.py +72 -52
- jarvis/jarvis_tools/search_web.py +23 -353
- jarvis/jarvis_tools/tool_generator.py +19 -19
- jarvis/jarvis_utils/config.py +36 -96
- jarvis/jarvis_utils/embedding.py +83 -83
- jarvis/jarvis_utils/git_utils.py +20 -20
- jarvis/jarvis_utils/globals.py +18 -6
- jarvis/jarvis_utils/input.py +10 -9
- jarvis/jarvis_utils/methodology.py +141 -140
- jarvis/jarvis_utils/output.py +13 -13
- jarvis/jarvis_utils/utils.py +23 -71
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +6 -15
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +4 -3
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- jarvis/jarvis_tools/select_code_files.py +0 -62
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +0 -82
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
jarvis/jarvis_tools/registry.py
CHANGED
|
@@ -85,21 +85,40 @@ class ToolRegistry(OutputHandler):
|
|
|
85
85
|
if self._extract_tool_calls(response):
|
|
86
86
|
return True
|
|
87
87
|
return False
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
def prompt(self) -> str:
|
|
90
90
|
"""加载工具"""
|
|
91
91
|
tools = self.get_all_tools()
|
|
92
92
|
if tools:
|
|
93
93
|
tools_prompt = "## 可用工具:\n"
|
|
94
94
|
for tool in tools:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
try:
|
|
96
|
+
tools_prompt += f"- 名称: {tool['name']}\n"
|
|
97
|
+
tools_prompt += f" 描述: {tool['description']}\n"
|
|
98
|
+
tools_prompt += " 参数: |\n"
|
|
99
|
+
|
|
100
|
+
# 生成格式化的YAML参数
|
|
101
|
+
yaml_params = yaml.dump(
|
|
102
|
+
tool['parameters'],
|
|
103
|
+
allow_unicode=True,
|
|
104
|
+
indent=4,
|
|
105
|
+
sort_keys=False,
|
|
106
|
+
width=120 # 增加行宽限制
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# 添加缩进并移除尾部空格
|
|
110
|
+
for line in yaml_params.split('\n'):
|
|
111
|
+
tools_prompt += f" {line.rstrip()}\n"
|
|
112
|
+
|
|
113
|
+
except yaml.YAMLError as e:
|
|
114
|
+
PrettyOutput.print(f"工具 {tool['name']} 参数序列化失败: {str(e)}", OutputType.ERROR)
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
tools_prompt += tool_call_help.rstrip() # 移除帮助文本尾部空格
|
|
99
118
|
return tools_prompt
|
|
100
119
|
return ""
|
|
101
|
-
|
|
102
|
-
def handle(self, response: str) -> Tuple[bool, Any]:
|
|
120
|
+
|
|
121
|
+
def handle(self, response: str, agent: Any) -> Tuple[bool, Any]:
|
|
103
122
|
tool_calls = self._extract_tool_calls(response)
|
|
104
123
|
if len(tool_calls) > 1:
|
|
105
124
|
PrettyOutput.print(f"操作失败:检测到多个操作。一次只能执行一个操作。尝试执行的操作:{', '.join([tool_call['name'] for tool_call in tool_calls])}", OutputType.WARNING)
|
|
@@ -107,7 +126,7 @@ class ToolRegistry(OutputHandler):
|
|
|
107
126
|
if len(tool_calls) == 0:
|
|
108
127
|
return False, ""
|
|
109
128
|
tool_call = tool_calls[0]
|
|
110
|
-
return False, self.handle_tool_calls(tool_call)
|
|
129
|
+
return False, self.handle_tool_calls(tool_call, agent)
|
|
111
130
|
|
|
112
131
|
def __init__(self):
|
|
113
132
|
"""初始化工具注册表"""
|
|
@@ -132,13 +151,13 @@ class ToolRegistry(OutputHandler):
|
|
|
132
151
|
def _load_builtin_tools(self):
|
|
133
152
|
"""从内置工具目录加载工具"""
|
|
134
153
|
tools_dir = Path(__file__).parent
|
|
135
|
-
|
|
154
|
+
|
|
136
155
|
# 遍历目录中的所有.py文件
|
|
137
156
|
for file_path in tools_dir.glob("*.py"):
|
|
138
157
|
# 跳过base.py和__init__.py
|
|
139
158
|
if file_path.name in ["base.py", "__init__.py", "registry.py"]:
|
|
140
159
|
continue
|
|
141
|
-
|
|
160
|
+
|
|
142
161
|
self.register_tool_by_file(str(file_path))
|
|
143
162
|
|
|
144
163
|
def _load_external_tools(self):
|
|
@@ -146,21 +165,21 @@ class ToolRegistry(OutputHandler):
|
|
|
146
165
|
external_tools_dir = Path.home() / '.jarvis/tools'
|
|
147
166
|
if not external_tools_dir.exists():
|
|
148
167
|
return
|
|
149
|
-
|
|
168
|
+
|
|
150
169
|
# 遍历目录中的所有.py文件
|
|
151
170
|
for file_path in external_tools_dir.glob("*.py"):
|
|
152
171
|
# 跳过__init__.py
|
|
153
172
|
if file_path.name == "__init__.py":
|
|
154
173
|
continue
|
|
155
|
-
|
|
174
|
+
|
|
156
175
|
self.register_tool_by_file(str(file_path))
|
|
157
176
|
|
|
158
177
|
def register_tool_by_file(self, file_path: str):
|
|
159
178
|
"""从指定文件加载并注册工具
|
|
160
|
-
|
|
179
|
+
|
|
161
180
|
参数:
|
|
162
181
|
file_path: 工具文件的路径
|
|
163
|
-
|
|
182
|
+
|
|
164
183
|
返回:
|
|
165
184
|
bool: 工具是否加载成功
|
|
166
185
|
"""
|
|
@@ -169,35 +188,35 @@ class ToolRegistry(OutputHandler):
|
|
|
169
188
|
if not p_file_path.exists() or not p_file_path.is_file():
|
|
170
189
|
PrettyOutput.print(f"文件不存在: {p_file_path}", OutputType.ERROR)
|
|
171
190
|
return False
|
|
172
|
-
|
|
191
|
+
|
|
173
192
|
# 临时将父目录添加到sys.path
|
|
174
193
|
parent_dir = str(p_file_path.parent)
|
|
175
194
|
sys.path.insert(0, parent_dir)
|
|
176
|
-
|
|
195
|
+
|
|
177
196
|
try:
|
|
178
197
|
# 使用标准导入机制导入模块
|
|
179
198
|
module_name = p_file_path.stem
|
|
180
199
|
module = __import__(module_name)
|
|
181
|
-
|
|
200
|
+
|
|
182
201
|
# 在模块中查找工具类
|
|
183
202
|
tool_found = False
|
|
184
203
|
for item_name in dir(module):
|
|
185
204
|
item = getattr(module, item_name)
|
|
186
205
|
# 检查是否是类并具有必要属性
|
|
187
|
-
if (isinstance(item, type) and
|
|
188
|
-
hasattr(item, 'name') and
|
|
189
|
-
hasattr(item, 'description') and
|
|
206
|
+
if (isinstance(item, type) and
|
|
207
|
+
hasattr(item, 'name') and
|
|
208
|
+
hasattr(item, 'description') and
|
|
190
209
|
hasattr(item, 'parameters') and
|
|
191
|
-
hasattr(item, 'execute') and
|
|
210
|
+
hasattr(item, 'execute') and
|
|
192
211
|
item.name == module_name):
|
|
193
212
|
|
|
194
213
|
if hasattr(item, "check"):
|
|
195
214
|
if not item.check():
|
|
196
215
|
continue
|
|
197
|
-
|
|
216
|
+
|
|
198
217
|
# 实例化工具类
|
|
199
218
|
tool_instance = item()
|
|
200
|
-
|
|
219
|
+
|
|
201
220
|
# 注册工具
|
|
202
221
|
self.register_tool(
|
|
203
222
|
name=tool_instance.name,
|
|
@@ -207,29 +226,29 @@ class ToolRegistry(OutputHandler):
|
|
|
207
226
|
)
|
|
208
227
|
tool_found = True
|
|
209
228
|
break
|
|
210
|
-
|
|
229
|
+
|
|
211
230
|
if not tool_found:
|
|
212
231
|
return False
|
|
213
|
-
|
|
232
|
+
|
|
214
233
|
return True
|
|
215
|
-
|
|
234
|
+
|
|
216
235
|
finally:
|
|
217
236
|
# 从sys.path中移除目录
|
|
218
237
|
sys.path.remove(parent_dir)
|
|
219
|
-
|
|
238
|
+
|
|
220
239
|
except Exception as e:
|
|
221
240
|
PrettyOutput.print(f"从 {Path(file_path).name} 加载工具失败: {str(e)}", OutputType.ERROR)
|
|
222
241
|
return False
|
|
223
242
|
@staticmethod
|
|
224
243
|
def _extract_tool_calls(content: str) -> List[Dict]:
|
|
225
244
|
"""从内容中提取工具调用。
|
|
226
|
-
|
|
245
|
+
|
|
227
246
|
参数:
|
|
228
247
|
content: 包含工具调用的内容
|
|
229
|
-
|
|
248
|
+
|
|
230
249
|
返回:
|
|
231
250
|
List[Dict]: 包含名称和参数的提取工具调用列表
|
|
232
|
-
|
|
251
|
+
|
|
233
252
|
异常:
|
|
234
253
|
Exception: 如果工具调用缺少必要字段
|
|
235
254
|
"""
|
|
@@ -264,12 +283,13 @@ class ToolRegistry(OutputHandler):
|
|
|
264
283
|
return {"success": False, "stderr": f"工具 {name} 不存在,可用的工具有: {', '.join(self.tools.keys())}", "stdout": ""}
|
|
265
284
|
return tool.execute(arguments)
|
|
266
285
|
|
|
267
|
-
def handle_tool_calls(self, tool_call: Dict) -> str:
|
|
286
|
+
def handle_tool_calls(self, tool_call: Dict, agent: Any) -> str:
|
|
268
287
|
"""处理工具调用,只处理第一个工具"""
|
|
269
288
|
try:
|
|
270
289
|
# 只处理第一个工具调用
|
|
271
290
|
name = tool_call["name"]
|
|
272
291
|
args = tool_call["arguments"]
|
|
292
|
+
args["agent"] = agent
|
|
273
293
|
|
|
274
294
|
tool_call_help = f"""
|
|
275
295
|
# 🛠️ 工具使用系统
|
|
@@ -330,14 +350,14 @@ arguments:
|
|
|
330
350
|
- 创建虚构对话
|
|
331
351
|
- 在没有所需信息的情况下继续
|
|
332
352
|
"""
|
|
333
|
-
|
|
353
|
+
|
|
334
354
|
if isinstance(args, str):
|
|
335
355
|
try:
|
|
336
356
|
args = json.loads(args)
|
|
337
357
|
except json.JSONDecodeError:
|
|
338
358
|
PrettyOutput.print(f"工具参数格式无效: {name} {tool_call_help}", OutputType.ERROR)
|
|
339
359
|
return ""
|
|
340
|
-
|
|
360
|
+
|
|
341
361
|
# Execute tool call
|
|
342
362
|
result = self.execute_tool(name, args)
|
|
343
363
|
|
|
@@ -350,14 +370,14 @@ arguments:
|
|
|
350
370
|
output_parts.append(f"错误:\n{stderr}")
|
|
351
371
|
output = "\n\n".join(output_parts)
|
|
352
372
|
output = "无输出和错误" if not output else output
|
|
353
|
-
|
|
373
|
+
|
|
354
374
|
# Process the result
|
|
355
375
|
if result["success"]:
|
|
356
376
|
# If the output exceeds 4k characters, use a large model to summarize
|
|
357
377
|
if get_context_token_count(output) > self.max_token_count:
|
|
358
378
|
PrettyOutput.section("输出过长,正在总结...", OutputType.SYSTEM)
|
|
359
379
|
try:
|
|
360
|
-
|
|
380
|
+
|
|
361
381
|
model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
362
382
|
model.set_suppress_output(False)
|
|
363
383
|
# If the output exceeds the maximum context length, only take the last part
|
|
@@ -391,7 +411,7 @@ arguments:
|
|
|
391
411
|
PrettyOutput.print(f"总结失败: {str(e)}", OutputType.ERROR)
|
|
392
412
|
output = f"输出过长 ({len(output)} 字符),建议查看原始输出。\n前300字符预览:\n{output[:300]}..."
|
|
393
413
|
return output
|
|
394
|
-
|
|
414
|
+
|
|
395
415
|
except Exception as e:
|
|
396
416
|
PrettyOutput.print(f"工具执行失败:{str(e)}", OutputType.ERROR)
|
|
397
417
|
return f"工具调用失败: {str(e)}"
|
|
@@ -419,13 +439,13 @@ def main():
|
|
|
419
439
|
call_parser.add_argument('--args-file', type=str, help='从文件加载工具参数 (JSON格式)')
|
|
420
440
|
|
|
421
441
|
args = parser.parse_args()
|
|
422
|
-
|
|
442
|
+
|
|
423
443
|
# 初始化工具注册表
|
|
424
444
|
registry = ToolRegistry()
|
|
425
|
-
|
|
445
|
+
|
|
426
446
|
if args.command == 'list':
|
|
427
447
|
tools = registry.get_all_tools()
|
|
428
|
-
|
|
448
|
+
|
|
429
449
|
if args.json:
|
|
430
450
|
if args.detailed:
|
|
431
451
|
print(json.dumps(tools, indent=2, ensure_ascii=False))
|
|
@@ -445,17 +465,17 @@ def main():
|
|
|
445
465
|
req_mark = "*" if param_name in required else ""
|
|
446
466
|
desc = param_info.get('description', '无描述')
|
|
447
467
|
print(f" - {param_name}{req_mark}: {desc}")
|
|
448
|
-
|
|
468
|
+
|
|
449
469
|
elif args.command == 'call':
|
|
450
470
|
tool_name = args.tool_name
|
|
451
471
|
tool = registry.get_tool(tool_name)
|
|
452
|
-
|
|
472
|
+
|
|
453
473
|
if not tool:
|
|
454
474
|
PrettyOutput.print(f"错误: 工具 '{tool_name}' 不存在", OutputType.ERROR)
|
|
455
475
|
available_tools = ", ".join([t["name"] for t in registry.get_all_tools()])
|
|
456
476
|
print(f"可用工具: {available_tools}")
|
|
457
477
|
return 1
|
|
458
|
-
|
|
478
|
+
|
|
459
479
|
# 获取参数
|
|
460
480
|
tool_args = {}
|
|
461
481
|
if args.args:
|
|
@@ -464,7 +484,7 @@ def main():
|
|
|
464
484
|
except json.JSONDecodeError:
|
|
465
485
|
PrettyOutput.print("错误: 参数必须是有效的JSON格式", OutputType.ERROR)
|
|
466
486
|
return 1
|
|
467
|
-
|
|
487
|
+
|
|
468
488
|
elif args.args_file:
|
|
469
489
|
try:
|
|
470
490
|
with open(args.args_file, 'r', encoding='utf-8') as f:
|
|
@@ -472,11 +492,11 @@ def main():
|
|
|
472
492
|
except (json.JSONDecodeError, FileNotFoundError) as e:
|
|
473
493
|
PrettyOutput.print(f"错误: 无法从文件加载参数: {str(e)}", OutputType.ERROR)
|
|
474
494
|
return 1
|
|
475
|
-
|
|
495
|
+
|
|
476
496
|
# 检查必需参数
|
|
477
497
|
required_params = tool.parameters.get('required', [])
|
|
478
498
|
missing_params = [p for p in required_params if p not in tool_args]
|
|
479
|
-
|
|
499
|
+
|
|
480
500
|
if missing_params:
|
|
481
501
|
PrettyOutput.print(f"错误: 缺少必需参数: {', '.join(missing_params)}", OutputType.ERROR)
|
|
482
502
|
print("\n参数说明:")
|
|
@@ -486,30 +506,30 @@ def main():
|
|
|
486
506
|
desc = param_info.get('description', '无描述')
|
|
487
507
|
print(f" - {param_name}: {desc}")
|
|
488
508
|
return 1
|
|
489
|
-
|
|
509
|
+
|
|
490
510
|
# 执行工具
|
|
491
511
|
with yaspin(text=f"正在执行工具 {tool_name}...").dots12:
|
|
492
512
|
result = registry.execute_tool(tool_name, tool_args)
|
|
493
|
-
|
|
513
|
+
|
|
494
514
|
# 显示结果
|
|
495
515
|
if result["success"]:
|
|
496
516
|
PrettyOutput.section(f"工具 {tool_name} 执行成功", OutputType.SUCCESS)
|
|
497
517
|
else:
|
|
498
518
|
PrettyOutput.section(f"工具 {tool_name} 执行失败", OutputType.ERROR)
|
|
499
|
-
|
|
519
|
+
|
|
500
520
|
if result.get("stdout"):
|
|
501
521
|
print("\n输出:")
|
|
502
522
|
print(result["stdout"])
|
|
503
|
-
|
|
523
|
+
|
|
504
524
|
if result.get("stderr"):
|
|
505
525
|
PrettyOutput.print("\n错误:", OutputType.ERROR)
|
|
506
526
|
print(result["stderr"])
|
|
507
|
-
|
|
527
|
+
|
|
508
528
|
return 0 if result["success"] else 1
|
|
509
|
-
|
|
529
|
+
|
|
510
530
|
else:
|
|
511
531
|
parser.print_help()
|
|
512
|
-
|
|
532
|
+
|
|
513
533
|
return 0
|
|
514
534
|
|
|
515
535
|
|