jarvis-ai-assistant 0.1.176__py3-none-any.whl → 0.1.177__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 +12 -10
- jarvis/jarvis_agent/jarvis.py +10 -10
- jarvis/jarvis_agent/main.py +6 -6
- jarvis/jarvis_code_agent/code_agent.py +10 -6
- jarvis/jarvis_code_analysis/code_review.py +1 -1
- jarvis/jarvis_dev/main.py +1 -1
- jarvis/jarvis_git_details/main.py +1 -1
- jarvis/jarvis_git_squash/main.py +1 -1
- jarvis/jarvis_git_utils/git_commiter.py +1 -1
- jarvis/jarvis_multi_agent/main.py +1 -1
- jarvis/jarvis_platform/base.py +6 -3
- jarvis/jarvis_platform/yuanbao.py +1 -1
- jarvis/jarvis_platform_manager/main.py +1 -1
- jarvis/jarvis_smart_shell/main.py +4 -2
- jarvis/jarvis_tools/ask_codebase.py +1 -1
- jarvis/jarvis_tools/cli/main.py +28 -1
- jarvis/jarvis_tools/edit_file.py +163 -103
- jarvis/jarvis_tools/read_code.py +0 -2
- jarvis/jarvis_tools/registry.py +30 -0
- jarvis/jarvis_utils/config.py +3 -3
- jarvis/jarvis_utils/output.py +36 -7
- jarvis/jarvis_utils/utils.py +19 -1
- {jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/METADATA +4 -4
- {jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/RECORD +29 -29
- {jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/WHEEL +1 -1
- {jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/jarvis_agent/__init__.py
CHANGED
|
@@ -340,15 +340,17 @@ class Agent:
|
|
|
340
340
|
complete_prompt = f"- 输出{ot('!!!COMPLETE!!!')}" if need_complete and self.auto_complete else ""
|
|
341
341
|
|
|
342
342
|
addon_prompt = f"""
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
-
|
|
349
|
-
-
|
|
350
|
-
-
|
|
351
|
-
|
|
343
|
+
[系统提示开始]
|
|
344
|
+
请判断是否已经完成任务,如果已经完成:
|
|
345
|
+
- 说明完成原因,不需要再有新的操作
|
|
346
|
+
{complete_prompt}
|
|
347
|
+
如果没有完成,请进行下一步操作:
|
|
348
|
+
- 仅包含一个操作
|
|
349
|
+
- 如果信息不明确,请请求用户补充
|
|
350
|
+
- 如果执行过程中连续失败5次,请使用ask_user询问用户操作
|
|
351
|
+
- 操作列表:
|
|
352
|
+
{action_handlers}
|
|
353
|
+
[系统提示结束]
|
|
352
354
|
|
|
353
355
|
请继续。
|
|
354
356
|
"""
|
|
@@ -490,7 +492,7 @@ class Agent:
|
|
|
490
492
|
return False, f"操作失败:检测到多个操作。一次只能执行一个操作。尝试执行的操作:{', '.join([handler.name() for handler in tool_list])}"
|
|
491
493
|
if len(tool_list) == 0:
|
|
492
494
|
return False, ""
|
|
493
|
-
if self.tool_call_count >= self.max_tool_call_count:
|
|
495
|
+
if self.max_tool_call_count > 0 and self.tool_call_count >= self.max_tool_call_count:
|
|
494
496
|
if user_confirm(f"工具调用次数超过限制,是否继续执行?", True):
|
|
495
497
|
self.reset_tool_call_count()
|
|
496
498
|
else:
|
jarvis/jarvis_agent/jarvis.py
CHANGED
|
@@ -3,7 +3,7 @@ import argparse
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
-
from typing import Dict #
|
|
6
|
+
from typing import Dict, List, Tuple # 增加必要的类型导入
|
|
7
7
|
|
|
8
8
|
from jarvis.jarvis_utils.config import get_data_dir
|
|
9
9
|
from prompt_toolkit import prompt
|
|
@@ -39,10 +39,10 @@ def _load_tasks() -> Dict[str, str]:
|
|
|
39
39
|
for name, desc in user_tasks.items():
|
|
40
40
|
if desc:
|
|
41
41
|
tasks[str(name)] = str(desc)
|
|
42
|
-
spinner.text = "预定义任务加载完成"
|
|
42
|
+
spinner.text = f"预定义任务加载完成{pre_command_path}"
|
|
43
43
|
spinner.ok("✅")
|
|
44
44
|
except (yaml.YAMLError, OSError):
|
|
45
|
-
spinner.text = "预定义任务加载失败"
|
|
45
|
+
spinner.text = f"预定义任务加载失败{pre_command_path}"
|
|
46
46
|
spinner.fail("❌")
|
|
47
47
|
|
|
48
48
|
# Check .jarvis/pre-command in current directory
|
|
@@ -58,10 +58,10 @@ def _load_tasks() -> Dict[str, str]:
|
|
|
58
58
|
for name, desc in local_tasks.items():
|
|
59
59
|
if desc:
|
|
60
60
|
tasks[str(name)] = str(desc)
|
|
61
|
-
spinner.text = "预定义任务加载完成"
|
|
61
|
+
spinner.text = f"预定义任务加载完成{pre_command_path}"
|
|
62
62
|
spinner.ok("✅")
|
|
63
63
|
except (yaml.YAMLError, OSError):
|
|
64
|
-
spinner.text = "预定义任务加载失败"
|
|
64
|
+
spinner.text = f"预定义任务加载失败{pre_command_path}"
|
|
65
65
|
spinner.fail("❌")
|
|
66
66
|
|
|
67
67
|
return tasks
|
|
@@ -90,6 +90,7 @@ def _select_task(tasks: Dict[str, str]) -> str:
|
|
|
90
90
|
return ""
|
|
91
91
|
if 1 <= choice <= len(task_names):
|
|
92
92
|
selected_task = tasks[task_names[choice - 1]]
|
|
93
|
+
PrettyOutput.print(f"将要执行任务:\n {selected_task}", OutputType.INFO)
|
|
93
94
|
# 询问是否需要补充信息
|
|
94
95
|
need_additional = user_confirm("需要为此任务添加补充信息吗?", default=False)
|
|
95
96
|
if need_additional:
|
|
@@ -105,11 +106,10 @@ def _select_task(tasks: Dict[str, str]) -> str:
|
|
|
105
106
|
PrettyOutput.print(f"选择任务失败: {str(val_err)}", OutputType.ERROR)
|
|
106
107
|
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
109
|
def main() -> None:
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
init_env("欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!")
|
|
113
113
|
parser = argparse.ArgumentParser(description='Jarvis AI assistant')
|
|
114
114
|
parser.add_argument('-p', '--platform', type=str, help='Platform to use')
|
|
115
115
|
parser.add_argument('-m', '--model', type=str, help='Model to use')
|
|
@@ -138,7 +138,7 @@ def main() -> None:
|
|
|
138
138
|
|
|
139
139
|
tasks = _load_tasks()
|
|
140
140
|
if tasks and (selected_task := _select_task(tasks)):
|
|
141
|
-
PrettyOutput.print(f"
|
|
141
|
+
PrettyOutput.print(f"开始执行任务: \n{selected_task}", OutputType.INFO)
|
|
142
142
|
agent.run(selected_task)
|
|
143
143
|
sys.exit(0)
|
|
144
144
|
|
jarvis/jarvis_agent/main.py
CHANGED
|
@@ -9,13 +9,13 @@ from jarvis.jarvis_utils.utils import init_env
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def load_config(config_path: str) -> dict:
|
|
12
|
-
"""
|
|
12
|
+
"""从YAML文件加载配置
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
config_path:
|
|
14
|
+
参数:
|
|
15
|
+
config_path: YAML配置文件的路径
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
dict:
|
|
17
|
+
返回:
|
|
18
|
+
dict: 配置字典
|
|
19
19
|
"""
|
|
20
20
|
if not os.path.exists(config_path):
|
|
21
21
|
PrettyOutput.print(f"配置文件 {config_path} 不存在,使用默认配置", OutputType.WARNING)
|
|
@@ -32,7 +32,7 @@ def load_config(config_path: str) -> dict:
|
|
|
32
32
|
def main():
|
|
33
33
|
"""Main entry point for Jarvis agent"""
|
|
34
34
|
# Initialize environment
|
|
35
|
-
init_env()
|
|
35
|
+
init_env("欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!")
|
|
36
36
|
|
|
37
37
|
# Set up argument parser
|
|
38
38
|
parser = argparse.ArgumentParser(description='Jarvis AI assistant')
|
|
@@ -31,7 +31,7 @@ from jarvis.jarvis_utils.git_utils import (
|
|
|
31
31
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
32
32
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
33
33
|
from jarvis.jarvis_utils.utils import init_env, user_confirm
|
|
34
|
-
|
|
34
|
+
from jarvis import __version__
|
|
35
35
|
|
|
36
36
|
class CodeAgent:
|
|
37
37
|
"""Jarvis系统的代码修改代理。
|
|
@@ -372,10 +372,14 @@ class CodeAgent:
|
|
|
372
372
|
final_ret += f"# 应用补丁:\n```diff\n{diff}\n```"
|
|
373
373
|
|
|
374
374
|
# 修改后的提示逻辑
|
|
375
|
-
addon_prompt = "
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
375
|
+
addon_prompt = """
|
|
376
|
+
[系统提示开始]
|
|
377
|
+
如果对应语言有静态检查工具,请使用静态检查工具检查修改的代码,如果本次修改引入了警告和错误,请根据警告和错误信息修复代码
|
|
378
|
+
在引入警告和错误都被修复的前提下,如果用户的需求未完成,请继续修改代码,如果已经完成,请终止,不要实现任何超出用户需求外的内容
|
|
379
|
+
如果有任何信息不明确,调用工具获取信息
|
|
380
|
+
每次响应必须且只能包含一个操作
|
|
381
|
+
[系统提示结束]
|
|
382
|
+
"""
|
|
379
383
|
|
|
380
384
|
agent.set_addon_prompt(addon_prompt)
|
|
381
385
|
|
|
@@ -403,7 +407,7 @@ class CodeAgent:
|
|
|
403
407
|
|
|
404
408
|
def main() -> None:
|
|
405
409
|
"""Jarvis主入口点。"""
|
|
406
|
-
init_env()
|
|
410
|
+
init_env("欢迎使用 Jarvis-CodeAgent,您的代码工程助手已准备就绪!")
|
|
407
411
|
|
|
408
412
|
parser = argparse.ArgumentParser(description='Jarvis Code Agent')
|
|
409
413
|
parser.add_argument('-p', '--platform', type=str,
|
|
@@ -661,7 +661,7 @@ def main():
|
|
|
661
661
|
"""CLI entry point"""
|
|
662
662
|
import argparse
|
|
663
663
|
|
|
664
|
-
init_env()
|
|
664
|
+
init_env("欢迎使用 Jarvis-CodeReview,您的代码审查助手已准备就绪!")
|
|
665
665
|
|
|
666
666
|
parser = argparse.ArgumentParser(description='Autonomous code review tool')
|
|
667
667
|
subparsers = parser.add_subparsers(dest='type')
|
jarvis/jarvis_dev/main.py
CHANGED
|
@@ -1257,7 +1257,7 @@ def create_dev_team() -> MultiAgent:
|
|
|
1257
1257
|
def main():
|
|
1258
1258
|
"""Main entry point for the development team simulation."""
|
|
1259
1259
|
|
|
1260
|
-
init_env()
|
|
1260
|
+
init_env("欢迎使用 Jarvis-Dev,您的开发团队已准备就绪!")
|
|
1261
1261
|
|
|
1262
1262
|
# Create the development team
|
|
1263
1263
|
dev_team = create_dev_team()
|
|
@@ -233,7 +233,7 @@ def main():
|
|
|
233
233
|
"""主函数,用于命令行接口"""
|
|
234
234
|
import argparse
|
|
235
235
|
|
|
236
|
-
init_env()
|
|
236
|
+
init_env("欢迎使用 Jarvis-GitCommitAnalyzer,您的Git Commit分析助手已准备就绪!")
|
|
237
237
|
|
|
238
238
|
parser = argparse.ArgumentParser(description='Git Commit Analyzer')
|
|
239
239
|
group = parser.add_mutually_exclusive_group(required=True)
|
jarvis/jarvis_git_squash/main.py
CHANGED
|
@@ -46,7 +46,7 @@ class GitSquashTool:
|
|
|
46
46
|
PrettyOutput.print(f"压缩提交失败: {str(e)}", OutputType.WARNING)
|
|
47
47
|
|
|
48
48
|
def main():
|
|
49
|
-
init_env()
|
|
49
|
+
init_env("欢迎使用 Jarvis-GitSquash,您的Git压缩助手已准备就绪!")
|
|
50
50
|
parser = argparse.ArgumentParser(description='Git squash tool')
|
|
51
51
|
parser.add_argument('commit_hash', type=str, help='Base commit hash to squash from')
|
|
52
52
|
parser.add_argument('--lang', type=str, default='Chinese', help='Language for commit messages')
|
|
@@ -265,7 +265,7 @@ class GitCommitTool:
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
def main():
|
|
268
|
-
init_env()
|
|
268
|
+
init_env("欢迎使用 Jarvis-GitCommitTool,您的Git提交助手已准备就绪!")
|
|
269
269
|
parser = argparse.ArgumentParser(description='Git commit tool')
|
|
270
270
|
parser.add_argument('--lang', type=str, default='Chinese', help='Language for commit messages')
|
|
271
271
|
parser.add_argument('--root-dir', type=str, default='.', help='Root directory of the Git repository')
|
|
@@ -10,7 +10,7 @@ def main():
|
|
|
10
10
|
Returns:
|
|
11
11
|
最终处理结果
|
|
12
12
|
"""
|
|
13
|
-
init_env()
|
|
13
|
+
init_env("欢迎使用 Jarvis-MultiAgent,您的多智能体系统已准备就绪!")
|
|
14
14
|
import argparse
|
|
15
15
|
parser = argparse.ArgumentParser(description="多智能体系统启动器")
|
|
16
16
|
parser.add_argument("--config", "-c", required=True, help="YAML配置文件路径")
|
jarvis/jarvis_platform/base.py
CHANGED
|
@@ -58,7 +58,7 @@ class BasePlatform(ABC):
|
|
|
58
58
|
|
|
59
59
|
if input_token_count > get_max_input_token_count():
|
|
60
60
|
max_chunk_size = get_max_input_token_count() - 1024 # 留出一些余量
|
|
61
|
-
min_chunk_size =
|
|
61
|
+
min_chunk_size = get_max_input_token_count() - 2048
|
|
62
62
|
inputs = split_text_into_chunks(message, max_chunk_size, min_chunk_size)
|
|
63
63
|
with yaspin(text="正在提交长上下文...", color="cyan") as spinner:
|
|
64
64
|
prefix_prompt = f"""
|
|
@@ -66,10 +66,13 @@ class BasePlatform(ABC):
|
|
|
66
66
|
"""
|
|
67
67
|
while_true(lambda: while_success(lambda: self.chat(prefix_prompt), 5), 5)
|
|
68
68
|
submit_count = 0
|
|
69
|
+
length = 0
|
|
69
70
|
for input in inputs:
|
|
70
71
|
submit_count += 1
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
length += len(input)
|
|
73
|
+
spinner.text = f"正在提交第{submit_count}部分(共{len(inputs)}部分({length}/{len(message)}))"
|
|
74
|
+
list(while_true(lambda: while_success(lambda: self.chat(f"<part_content>{input}</part_content>请返回已收到"), 5), 5))
|
|
75
|
+
spinner.write(f"提交第{submit_count}部分完成,当前进度:{length}/{len(message)}")
|
|
73
76
|
spinner.text = "提交完成"
|
|
74
77
|
spinner.ok("✅")
|
|
75
78
|
response = while_true(lambda: while_success(lambda: self._chat("内容已经全部提供完毕,请继续"), 5), 5)
|
|
@@ -294,7 +294,7 @@ class YuanbaoPlatform(BasePlatform):
|
|
|
294
294
|
with open(file_path, 'rb') as file:
|
|
295
295
|
file_content = file.read()
|
|
296
296
|
|
|
297
|
-
spinner.write(f"ℹ️
|
|
297
|
+
spinner.write(f"ℹ️ 上传文件大小: {len(file_content)}")
|
|
298
298
|
|
|
299
299
|
# Prepare headers for PUT request
|
|
300
300
|
host = f"{upload_info['bucketName']}.{upload_info.get('accelerateDomain', 'cos.accelerate.myqcloud.com')}"
|
|
@@ -606,7 +606,7 @@ def main():
|
|
|
606
606
|
"""Main function"""
|
|
607
607
|
import argparse
|
|
608
608
|
|
|
609
|
-
init_env()
|
|
609
|
+
init_env("欢迎使用 Jarvis-PlatformManager,您的平台管理助手已准备就绪!")
|
|
610
610
|
|
|
611
611
|
parser = argparse.ArgumentParser(description='Jarvis AI 平台')
|
|
612
612
|
subparsers = parser.add_subparsers(dest='command', help='可用子命令')
|
|
@@ -5,6 +5,8 @@ import os
|
|
|
5
5
|
import sys
|
|
6
6
|
from typing import Optional
|
|
7
7
|
|
|
8
|
+
from sympy import false
|
|
9
|
+
|
|
8
10
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
9
11
|
from jarvis.jarvis_utils.config import get_shell_name
|
|
10
12
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
@@ -113,8 +115,8 @@ def process_request(request: str) -> Optional[str]:
|
|
|
113
115
|
return None
|
|
114
116
|
|
|
115
117
|
def main() -> int:
|
|
116
|
-
# 创建参数解析器
|
|
117
|
-
init_env()
|
|
118
|
+
# 创建参数解析器s
|
|
119
|
+
init_env("")
|
|
118
120
|
parser = argparse.ArgumentParser(
|
|
119
121
|
description="将自然语言要求转换为shell命令",
|
|
120
122
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
jarvis/jarvis_tools/cli/main.py
CHANGED
|
@@ -29,7 +29,7 @@ def main() -> int:
|
|
|
29
29
|
import argparse
|
|
30
30
|
import json
|
|
31
31
|
|
|
32
|
-
init_env()
|
|
32
|
+
init_env("欢迎使用 Jarvis-Tools,您的工具系统已准备就绪!")
|
|
33
33
|
|
|
34
34
|
parser = argparse.ArgumentParser(description="Jarvis 工具系统命令行界面")
|
|
35
35
|
subparsers = parser.add_subparsers(dest="command", help="命令")
|
|
@@ -47,6 +47,10 @@ def main() -> int:
|
|
|
47
47
|
"--args-file", type=str, help="从文件加载工具参数 (JSON格式)"
|
|
48
48
|
)
|
|
49
49
|
|
|
50
|
+
# 统计子命令
|
|
51
|
+
stat_parser = subparsers.add_parser("stat", help="显示工具调用统计信息")
|
|
52
|
+
stat_parser.add_argument("--json", action="store_true", help="以JSON格式输出")
|
|
53
|
+
|
|
50
54
|
args = parser.parse_args()
|
|
51
55
|
|
|
52
56
|
# 初始化工具注册表
|
|
@@ -72,6 +76,29 @@ def main() -> int:
|
|
|
72
76
|
print(f" 参数:")
|
|
73
77
|
print(tool["parameters"]) # 显示详细参数信息
|
|
74
78
|
|
|
79
|
+
elif args.command == "stat":
|
|
80
|
+
from tabulate import tabulate
|
|
81
|
+
stats = registry._get_tool_stats()
|
|
82
|
+
tools = registry.get_all_tools()
|
|
83
|
+
|
|
84
|
+
# 构建统计表格数据
|
|
85
|
+
table_data = []
|
|
86
|
+
for tool in tools:
|
|
87
|
+
name = tool["name"]
|
|
88
|
+
count = stats.get(name, 0)
|
|
89
|
+
table_data.append([name, count])
|
|
90
|
+
|
|
91
|
+
# 按调用次数降序排序
|
|
92
|
+
table_data.sort(key=lambda x: x[1], reverse=True)
|
|
93
|
+
|
|
94
|
+
if args.json:
|
|
95
|
+
print(json.dumps(dict(table_data), indent=2))
|
|
96
|
+
else:
|
|
97
|
+
PrettyOutput.section("工具调用统计", OutputType.SYSTEM)
|
|
98
|
+
print(tabulate(table_data, headers=["工具名称", "调用次数"], tablefmt="grid"))
|
|
99
|
+
|
|
100
|
+
return 0
|
|
101
|
+
|
|
75
102
|
elif args.command == "call":
|
|
76
103
|
tool_name = args.tool_name
|
|
77
104
|
tool_obj = registry.get_tool(tool_name)
|
jarvis/jarvis_tools/edit_file.py
CHANGED
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
- 完善的错误处理和回滚机制
|
|
15
15
|
- 严格的格式保持要求
|
|
16
16
|
"""
|
|
17
|
+
from typing import List
|
|
17
18
|
import re
|
|
18
19
|
from typing import Any, Dict, Tuple
|
|
19
20
|
|
|
20
21
|
import yaml
|
|
21
22
|
from yaspin import yaspin
|
|
23
|
+
from yaspin.core import Yaspin
|
|
22
24
|
|
|
23
25
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
24
26
|
from jarvis.jarvis_tools.file_operation import FileOperationTool
|
|
@@ -32,30 +34,27 @@ class FileSearchReplaceTool:
|
|
|
32
34
|
name = "edit_file"
|
|
33
35
|
description = """代码编辑工具,用于编辑单个文件
|
|
34
36
|
|
|
35
|
-
#
|
|
37
|
+
# 代码补丁生成指南
|
|
36
38
|
|
|
37
39
|
## 重要提示
|
|
38
40
|
此工具可以查看和修改单个文件的代码,只需提供要修改的代码片段即可。应尽量精简内容,只包含必要的上下文和修改部分。特别注意:不要提供完整文件内容,只提供需要修改的部分及其上下文!
|
|
39
41
|
|
|
40
42
|
## 基本使用
|
|
41
43
|
1. 指定需要修改的文件路径
|
|
42
|
-
2.
|
|
43
|
-
3.
|
|
44
|
+
2. 提供一组或多组修改,每个修改包含"reason"、"search"和"replace"
|
|
45
|
+
3. 每个修改中,"search"必须包含足够的上下文确保能在文件中**唯一匹配**
|
|
44
46
|
|
|
45
47
|
## 核心原则
|
|
46
48
|
1. **精准修改**:只提供需要修改的代码部分及其上下文,不需要展示整个文件内容
|
|
47
49
|
2. **最小补丁原则**:始终生成最小范围的补丁,只包含必要的上下文和实际修改
|
|
48
|
-
3.
|
|
49
|
-
|
|
50
|
-
##
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if condition: # 修改这行
|
|
57
|
-
return new_value
|
|
58
|
-
```
|
|
50
|
+
3. **上下文完整性**:确保提供的上下文能唯一标识修改位置,避免匹配到多处
|
|
51
|
+
|
|
52
|
+
## 输出格式规范
|
|
53
|
+
- 每个修改必须包含SEARCH部分和REPLACE部分
|
|
54
|
+
- SEARCH部分是需要查找的原始代码,必须能在原文件中**唯一匹配**
|
|
55
|
+
- REPLACE部分是替换后的新代码
|
|
56
|
+
- 如果修改较大,可以使用多个修改块
|
|
57
|
+
|
|
59
58
|
"""
|
|
60
59
|
parameters = {
|
|
61
60
|
"type": "object",
|
|
@@ -74,12 +73,15 @@ class FileSearchReplaceTool:
|
|
|
74
73
|
"type": "string",
|
|
75
74
|
"description": "修改的原因"
|
|
76
75
|
},
|
|
77
|
-
"
|
|
76
|
+
"search": {
|
|
78
77
|
"type": "string",
|
|
79
|
-
"description": "
|
|
78
|
+
"description": "需要查找的原始代码"
|
|
79
|
+
},
|
|
80
|
+
"replace": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"description": "替换后的新代码"
|
|
80
83
|
}
|
|
81
84
|
},
|
|
82
|
-
"required": ["reason", "patch"]
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
},
|
|
@@ -141,8 +143,10 @@ class FileSearchReplaceTool:
|
|
|
141
143
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
142
144
|
content = f.read()
|
|
143
145
|
original_content = content
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
with yaspin(text=f"正在处理文件 {file_path}...", color="cyan") as spinner:
|
|
147
|
+
success, temp_content = fast_edit(file_path, changes, spinner)
|
|
148
|
+
if not success:
|
|
149
|
+
success, temp_content = slow_edit(file_path, yaml.safe_dump(changes), spinner)
|
|
146
150
|
|
|
147
151
|
# 只有当所有替换操作都成功时,才写回文件
|
|
148
152
|
if success and (temp_content != original_content or not file_exists):
|
|
@@ -207,29 +211,42 @@ class FileSearchReplaceTool:
|
|
|
207
211
|
"stdout": "",
|
|
208
212
|
"stderr": error_msg + "\n" + "\n".join(stderr_messages)
|
|
209
213
|
}
|
|
214
|
+
|
|
210
215
|
|
|
211
216
|
|
|
212
|
-
def
|
|
217
|
+
def slow_edit(filepath: str, patch_content: str, spinner: Yaspin) -> Tuple[bool, str]:
|
|
213
218
|
"""执行精确的文件编辑操作,使用AI模型生成差异补丁并应用。
|
|
214
|
-
|
|
215
|
-
|
|
219
|
+
|
|
220
|
+
核心功能:
|
|
216
221
|
1. 使用AI模型分析补丁内容并生成精确的代码差异
|
|
217
222
|
2. 应用生成的差异补丁到目标文件
|
|
218
|
-
3.
|
|
219
|
-
|
|
223
|
+
3. 提供3次重试机制确保操作可靠性
|
|
224
|
+
4. 支持大文件处理(自动上传到模型平台)
|
|
225
|
+
5. 严格的格式一致性检查
|
|
226
|
+
|
|
220
227
|
参数:
|
|
221
|
-
filepath: 要编辑的文件路径
|
|
222
|
-
patch_content: YAML
|
|
223
|
-
|
|
228
|
+
filepath: 要编辑的文件路径(绝对或相对路径)
|
|
229
|
+
patch_content: YAML格式的补丁内容,包含:
|
|
230
|
+
- reason: 修改原因描述
|
|
231
|
+
- search: 需要查找的原始代码(必须包含足够上下文)
|
|
232
|
+
- replace: 替换后的新代码
|
|
233
|
+
spinner: Yaspin实例,用于显示处理状态
|
|
234
|
+
|
|
224
235
|
返回值:
|
|
225
236
|
Tuple[bool, str]:
|
|
226
|
-
- 第一个元素表示操作是否成功
|
|
227
|
-
- 第二个元素是修改后的文件内容(成功时)
|
|
228
|
-
|
|
237
|
+
- 第一个元素表示操作是否成功(True/False)
|
|
238
|
+
- 第二个元素是修改后的文件内容(成功时)或空字符串(失败时)
|
|
239
|
+
|
|
229
240
|
异常处理:
|
|
230
|
-
1.
|
|
231
|
-
2.
|
|
232
|
-
3.
|
|
241
|
+
1. 文件不存在或权限不足时会捕获异常并返回失败
|
|
242
|
+
2. 模型生成补丁失败时会自动重试最多3次
|
|
243
|
+
3. 补丁应用失败时会自动回滚文件修改
|
|
244
|
+
|
|
245
|
+
实现细节:
|
|
246
|
+
1. 检查文件是否在工作目录下(影响版本控制)
|
|
247
|
+
2. 根据文件大小决定是否上传到模型平台
|
|
248
|
+
3. 使用精确的DIFF格式解析模型生成的补丁
|
|
249
|
+
4. 确保补丁应用前进行唯一性匹配检查
|
|
233
250
|
"""
|
|
234
251
|
import os
|
|
235
252
|
work_dir = os.path.abspath(os.curdir)
|
|
@@ -237,20 +254,19 @@ def patch_apply(filepath: str, patch_content: str) -> Tuple[bool, str]:
|
|
|
237
254
|
if not filepath.startswith(work_dir):
|
|
238
255
|
PrettyOutput.print(f"文件 {filepath} 不在工作目录 {work_dir} 下,不会进行版本控制管理", OutputType.WARNING)
|
|
239
256
|
model = PlatformRegistry().get_normal_platform()
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
upload_success = True
|
|
257
|
+
try:
|
|
258
|
+
file_content = FileOperationTool().execute({"operation":"read", "files":[{"path":filepath}]})["stdout"]
|
|
259
|
+
need_upload_file = is_context_overflow(file_content)
|
|
260
|
+
upload_success = False
|
|
261
|
+
# 读取原始文件内容
|
|
262
|
+
with spinner.hidden():
|
|
263
|
+
if need_upload_file and model.upload_files([filepath]):
|
|
264
|
+
upload_success = True
|
|
249
265
|
|
|
250
266
|
|
|
251
|
-
|
|
267
|
+
model.set_suppress_output(True)
|
|
252
268
|
|
|
253
|
-
|
|
269
|
+
main_prompt = f"""
|
|
254
270
|
# 代码补丁生成专家指南
|
|
255
271
|
|
|
256
272
|
## 任务描述
|
|
@@ -292,66 +308,110 @@ def patch_apply(filepath: str, patch_content: str) -> Tuple[bool, str]:
|
|
|
292
308
|
{"<" * 5} REPLACE
|
|
293
309
|
{ct("DIFF")}
|
|
294
310
|
"""
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
311
|
+
|
|
312
|
+
for _ in range(3):
|
|
313
|
+
file_prompt = ""
|
|
314
|
+
if not need_upload_file:
|
|
315
|
+
file_prompt = f"""
|
|
316
|
+
# 原始代码
|
|
317
|
+
{file_content}
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
response = model.chat_until_success(main_prompt + file_prompt)
|
|
321
|
+
else:
|
|
322
|
+
if upload_success:
|
|
323
|
+
response = model.chat_until_success(main_prompt)
|
|
305
324
|
else:
|
|
306
|
-
|
|
307
|
-
response = model.chat_until_success(main_prompt)
|
|
308
|
-
else:
|
|
309
|
-
return False, ""
|
|
310
|
-
|
|
311
|
-
# 解析差异化补丁
|
|
312
|
-
diff_blocks = re.finditer(ot("DIFF")+r'\s*>{4,} SEARCH\n?(.*?)\n?={4,}\n?(.*?)\s*<{4,} REPLACE\n?'+ct("DIFF"),
|
|
313
|
-
response, re.DOTALL)
|
|
314
|
-
|
|
315
|
-
# 读取原始文件内容
|
|
316
|
-
with open(filepath, 'r', encoding='utf-8', errors="ignore") as f:
|
|
317
|
-
file_content = f.read()
|
|
318
|
-
|
|
319
|
-
# 应用所有差异化补丁
|
|
320
|
-
modified_content = file_content
|
|
321
|
-
patch_count = 0
|
|
322
|
-
success = True
|
|
323
|
-
for match in diff_blocks:
|
|
324
|
-
search_text = match.group(1).strip()
|
|
325
|
-
replace_text = match.group(2).strip()
|
|
326
|
-
patch_count += 1
|
|
327
|
-
# 检查搜索文本是否存在于文件中
|
|
328
|
-
if search_text in modified_content:
|
|
329
|
-
# 如果有多处,报错
|
|
330
|
-
if modified_content.count(search_text) > 1:
|
|
331
|
-
spinner.write(f"❌ 补丁 #{patch_count} 应用失败:找到多个匹配的代码段")
|
|
332
|
-
success = False
|
|
333
|
-
break
|
|
334
|
-
# 应用替换
|
|
335
|
-
modified_content = modified_content.replace(
|
|
336
|
-
search_text, replace_text)
|
|
337
|
-
spinner.write(f"✅ 补丁 #{patch_count} 应用成功")
|
|
338
|
-
else:
|
|
339
|
-
spinner.write(f"❌ 补丁 #{patch_count} 应用失败:无法找到匹配的代码段")
|
|
340
|
-
success = False
|
|
341
|
-
break
|
|
342
|
-
if not success:
|
|
343
|
-
revert_file(filepath)
|
|
344
|
-
continue
|
|
325
|
+
return False, ""
|
|
345
326
|
|
|
327
|
+
# 解析差异化补丁
|
|
328
|
+
diff_blocks = re.finditer(ot("DIFF")+r'\s*>{4,} SEARCH\n?(.*?)\n?={4,}\n?(.*?)\s*<{4,} REPLACE\n?'+ct("DIFF"),
|
|
329
|
+
response, re.DOTALL)
|
|
346
330
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
331
|
+
patches = []
|
|
332
|
+
for match in diff_blocks:
|
|
333
|
+
patches.append({
|
|
334
|
+
"search": match.group(1).strip(),
|
|
335
|
+
"replace": match.group(2).strip()
|
|
336
|
+
})
|
|
353
337
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
338
|
+
success, modified_content = fast_edit(filepath, patches, spinner)
|
|
339
|
+
if success:
|
|
340
|
+
return True, modified_content
|
|
341
|
+
spinner.text = f"文件 {filepath} 修改失败"
|
|
342
|
+
spinner.fail("❌")
|
|
343
|
+
return False, ""
|
|
344
|
+
|
|
345
|
+
except Exception as e:
|
|
346
|
+
spinner.text = f"文件修改失败: {str(e)}"
|
|
347
|
+
spinner.fail("❌")
|
|
348
|
+
return False, ""
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def fast_edit(filepath: str, patches: List[Dict[str,str]], spinner: Yaspin) -> Tuple[bool, str]:
|
|
352
|
+
"""快速应用预先生成的补丁到目标文件。
|
|
353
|
+
|
|
354
|
+
核心功能:
|
|
355
|
+
1. 直接应用已生成的代码补丁
|
|
356
|
+
2. 执行严格的唯一匹配检查
|
|
357
|
+
3. 提供详细的补丁应用状态反馈
|
|
358
|
+
4. 失败时自动回滚文件修改
|
|
359
|
+
|
|
360
|
+
参数:
|
|
361
|
+
filepath: 要编辑的文件路径(绝对或相对路径)
|
|
362
|
+
patches: 补丁列表,每个补丁包含:
|
|
363
|
+
- search: 需要查找的原始代码
|
|
364
|
+
- replace: 替换后的新代码
|
|
365
|
+
spinner: Yaspin实例,用于显示处理状态
|
|
366
|
+
|
|
367
|
+
返回值:
|
|
368
|
+
Tuple[bool, str]:
|
|
369
|
+
- 第一个元素表示操作是否成功(True/False)
|
|
370
|
+
- 第二个元素是修改后的文件内容(成功时)或空字符串(失败时)
|
|
371
|
+
|
|
372
|
+
异常处理:
|
|
373
|
+
1. 文件不存在或权限不足时会捕获异常并返回失败
|
|
374
|
+
2. 补丁不匹配或有多处匹配时会返回失败
|
|
375
|
+
3. 失败时会自动回滚文件修改
|
|
376
|
+
|
|
377
|
+
实现细节:
|
|
378
|
+
1. 读取文件内容到内存
|
|
379
|
+
2. 依次应用每个补丁,检查唯一匹配性
|
|
380
|
+
3. 记录每个补丁的应用状态
|
|
381
|
+
4. 所有补丁成功应用后才写入文件
|
|
382
|
+
"""
|
|
383
|
+
# 读取原始文件内容
|
|
384
|
+
with open(filepath, 'r', encoding='utf-8', errors="ignore") as f:
|
|
385
|
+
file_content = f.read()
|
|
386
|
+
|
|
387
|
+
# 应用所有差异化补丁
|
|
388
|
+
modified_content = file_content
|
|
389
|
+
patch_count = 0
|
|
390
|
+
success = True
|
|
391
|
+
for patch in patches:
|
|
392
|
+
search_text = patch["search"]
|
|
393
|
+
replace_text = patch["replace"]
|
|
394
|
+
patch_count += 1
|
|
395
|
+
# 检查搜索文本是否存在于文件中
|
|
396
|
+
if search_text in modified_content:
|
|
397
|
+
# 如果有多处,报错
|
|
398
|
+
if modified_content.count(search_text) > 1:
|
|
399
|
+
spinner.write(f"❌ 补丁 #{patch_count} 应用失败:找到多个匹配的代码段")
|
|
400
|
+
success = False
|
|
401
|
+
break
|
|
402
|
+
# 应用替换
|
|
403
|
+
modified_content = modified_content.replace(
|
|
404
|
+
search_text, replace_text)
|
|
405
|
+
spinner.write(f"✅ 补丁 #{patch_count} 应用成功")
|
|
406
|
+
else:
|
|
407
|
+
spinner.write(f"❌ 补丁 #{patch_count} 应用失败:无法找到匹配的代码段")
|
|
408
|
+
success = False
|
|
409
|
+
break
|
|
410
|
+
if not success:
|
|
411
|
+
revert_file(filepath)
|
|
412
|
+
return False, ""
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
spinner.text = f"文件 {filepath} 修改完成,应用了 {patch_count} 个补丁"
|
|
416
|
+
spinner.ok("✅")
|
|
417
|
+
return True, modified_content
|
jarvis/jarvis_tools/read_code.py
CHANGED
jarvis/jarvis_tools/registry.py
CHANGED
|
@@ -178,6 +178,32 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
178
178
|
self._load_external_tools()
|
|
179
179
|
self._load_mcp_tools()
|
|
180
180
|
|
|
181
|
+
def _get_tool_stats(self) -> Dict[str, int]:
|
|
182
|
+
"""从数据目录获取工具调用统计"""
|
|
183
|
+
stats_file = Path(get_data_dir()) / "tool_stat.yaml"
|
|
184
|
+
if stats_file.exists():
|
|
185
|
+
try:
|
|
186
|
+
with open(stats_file, "r", encoding="utf-8") as f:
|
|
187
|
+
return yaml.safe_load(f) or {}
|
|
188
|
+
except Exception as e:
|
|
189
|
+
PrettyOutput.print(
|
|
190
|
+
f"加载工具调用统计失败: {str(e)}", OutputType.WARNING
|
|
191
|
+
)
|
|
192
|
+
return {}
|
|
193
|
+
|
|
194
|
+
def _update_tool_stats(self, name: str) -> None:
|
|
195
|
+
"""更新工具调用统计"""
|
|
196
|
+
stats = self._get_tool_stats()
|
|
197
|
+
stats[name] = stats.get(name, 0) + 1
|
|
198
|
+
stats_file = Path(get_data_dir()) / "tool_stat.yaml"
|
|
199
|
+
try:
|
|
200
|
+
with open(stats_file, "w", encoding="utf-8") as f:
|
|
201
|
+
yaml.safe_dump(stats, f)
|
|
202
|
+
except Exception as e:
|
|
203
|
+
PrettyOutput.print(
|
|
204
|
+
f"保存工具调用统计失败: {str(e)}", OutputType.WARNING
|
|
205
|
+
)
|
|
206
|
+
|
|
181
207
|
def use_tools(self, name: List[str]) -> None:
|
|
182
208
|
"""使用指定工具
|
|
183
209
|
|
|
@@ -559,6 +585,10 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
559
585
|
"stderr": f"工具 {name} 不存在,可用的工具有: {', '.join(self.tools.keys())}",
|
|
560
586
|
"stdout": "",
|
|
561
587
|
}
|
|
588
|
+
|
|
589
|
+
# 更新工具调用统计
|
|
590
|
+
self._update_tool_stats(name)
|
|
591
|
+
|
|
562
592
|
return tool.execute(arguments)
|
|
563
593
|
|
|
564
594
|
def _format_tool_output(self, stdout: str, stderr: str) -> str:
|
jarvis/jarvis_utils/config.py
CHANGED
|
@@ -38,7 +38,7 @@ def get_max_token_count() -> int:
|
|
|
38
38
|
返回:
|
|
39
39
|
int: 模型能处理的最大token数量。
|
|
40
40
|
"""
|
|
41
|
-
return int(os.getenv('JARVIS_MAX_TOKEN_COUNT', '
|
|
41
|
+
return int(os.getenv('JARVIS_MAX_TOKEN_COUNT', '960000'))
|
|
42
42
|
|
|
43
43
|
def get_max_input_token_count() -> int:
|
|
44
44
|
"""
|
|
@@ -158,9 +158,9 @@ def get_max_big_content_size() -> int:
|
|
|
158
158
|
获取最大大内容大小。
|
|
159
159
|
|
|
160
160
|
返回:
|
|
161
|
-
int:
|
|
161
|
+
int: 最大大内容大小
|
|
162
162
|
"""
|
|
163
|
-
return int(os.getenv('JARVIS_MAX_BIG_CONTENT_SIZE', '
|
|
163
|
+
return int(os.getenv('JARVIS_MAX_BIG_CONTENT_SIZE', '1024000'))
|
|
164
164
|
|
|
165
165
|
def get_pretty_output() -> bool:
|
|
166
166
|
"""
|
jarvis/jarvis_utils/output.py
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"""
|
|
11
11
|
from enum import Enum
|
|
12
12
|
from datetime import datetime
|
|
13
|
-
from typing import Optional
|
|
13
|
+
from typing import Optional, Tuple
|
|
14
14
|
from rich.panel import Panel
|
|
15
15
|
from rich.text import Text
|
|
16
16
|
from rich.syntax import Syntax
|
|
@@ -19,7 +19,7 @@ from pygments.lexers import guess_lexer
|
|
|
19
19
|
from pygments.util import ClassNotFound
|
|
20
20
|
from jarvis.jarvis_utils.config import get_pretty_output
|
|
21
21
|
from jarvis.jarvis_utils.globals import console, get_agent_list
|
|
22
|
-
|
|
22
|
+
from rich.box import SIMPLE
|
|
23
23
|
class OutputType(Enum):
|
|
24
24
|
"""
|
|
25
25
|
输出类型枚举,用于分类和样式化不同类型的消息。
|
|
@@ -139,7 +139,7 @@ class PrettyOutput:
|
|
|
139
139
|
Text: 格式化后的rich Text对象
|
|
140
140
|
"""
|
|
141
141
|
icon = PrettyOutput._ICONS.get(output_type, "")
|
|
142
|
-
formatted = f"{icon}
|
|
142
|
+
formatted = f"{icon} "
|
|
143
143
|
if timestamp:
|
|
144
144
|
formatted+=f"[{datetime.now().strftime('%H:%M:%S')}][{output_type.value}]"
|
|
145
145
|
agent_info = get_agent_list()
|
|
@@ -190,7 +190,7 @@ class PrettyOutput:
|
|
|
190
190
|
|
|
191
191
|
lang = lang if lang is not None else PrettyOutput._detect_language(text, default_lang='markdown')
|
|
192
192
|
header = Text(PrettyOutput._format(output_type, timestamp), style=header_styles[output_type])
|
|
193
|
-
content = Syntax(text, lang, theme="
|
|
193
|
+
content = Syntax(text, lang, theme="monokai", word_wrap=True, background_color=styles[output_type]["bgcolor"])
|
|
194
194
|
panel = Panel(
|
|
195
195
|
content,
|
|
196
196
|
border_style=header_styles[output_type],
|
|
@@ -202,8 +202,11 @@ class PrettyOutput:
|
|
|
202
202
|
if get_pretty_output():
|
|
203
203
|
console.print(panel)
|
|
204
204
|
else:
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
if len(text.strip().splitlines()) > 1:
|
|
206
|
+
console.print(header)
|
|
207
|
+
console.print(content)
|
|
208
|
+
else:
|
|
209
|
+
console.print(header, content)
|
|
207
210
|
if traceback:
|
|
208
211
|
console.print_exception()
|
|
209
212
|
@staticmethod
|
|
@@ -224,4 +227,30 @@ class PrettyOutput:
|
|
|
224
227
|
console.print(panel)
|
|
225
228
|
else:
|
|
226
229
|
console.print(text)
|
|
227
|
-
|
|
230
|
+
|
|
231
|
+
@staticmethod
|
|
232
|
+
def print_gradient_text(text: str, start_color: Tuple[int, int, int], end_color: Tuple[int, int, int]) -> None:
|
|
233
|
+
"""打印带有渐变色彩的文本。
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
text: 要打印的文本
|
|
237
|
+
start_color: 起始RGB颜色元组 (r, g, b)
|
|
238
|
+
end_color: 结束RGB颜色元组 (r, g, b)
|
|
239
|
+
"""
|
|
240
|
+
lines = text.strip('\n').split('\n')
|
|
241
|
+
total_lines = len(lines)
|
|
242
|
+
colored_lines = []
|
|
243
|
+
for i, line in enumerate(lines):
|
|
244
|
+
# 计算当前行的渐变颜色
|
|
245
|
+
r = int(start_color[0] + (end_color[0] - start_color[0]) * i / (total_lines - 1))
|
|
246
|
+
g = int(start_color[1] + (end_color[1] - start_color[1]) * i / (total_lines - 1))
|
|
247
|
+
b = int(start_color[2] + (end_color[2] - start_color[2]) * i / (total_lines - 1))
|
|
248
|
+
|
|
249
|
+
# 使用ANSI转义序列设置颜色
|
|
250
|
+
colored_lines.append(f"\033[38;2;{r};{g};{b}m{line}\033[0m")
|
|
251
|
+
colored_text = Text('\n'.join(colored_lines), style=OutputType.TOOL.value, justify="center")
|
|
252
|
+
panel = Panel(
|
|
253
|
+
colored_text,
|
|
254
|
+
box=SIMPLE
|
|
255
|
+
)
|
|
256
|
+
console.print(panel)
|
jarvis/jarvis_utils/utils.py
CHANGED
|
@@ -5,11 +5,13 @@ import hashlib
|
|
|
5
5
|
import tarfile
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any, Callable
|
|
8
|
+
|
|
9
|
+
from jarvis import __version__
|
|
8
10
|
from jarvis.jarvis_utils.config import get_max_big_content_size, get_data_dir
|
|
9
11
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
10
12
|
from jarvis.jarvis_utils.input import get_single_line_input
|
|
11
13
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
12
|
-
def init_env() -> None:
|
|
14
|
+
def init_env(welcome_str: str) -> None:
|
|
13
15
|
"""初始化环境变量从jarvis_data/env文件
|
|
14
16
|
|
|
15
17
|
功能:
|
|
@@ -18,6 +20,22 @@ def init_env() -> None:
|
|
|
18
20
|
3. 处理文件读取异常
|
|
19
21
|
4. 检查git仓库状态并在落后时更新
|
|
20
22
|
"""
|
|
23
|
+
|
|
24
|
+
jarvis_ascii_art = f"""
|
|
25
|
+
██╗ █████╗ ██████╗ ██╗ ██╗██╗███████╗
|
|
26
|
+
██║██╔══██╗██╔══██╗██║ ██║██║██╔════╝
|
|
27
|
+
██║███████║██████╔╝██║ ██║██║███████╗
|
|
28
|
+
██╗██║██╔══██║██╔══██╗╚██╗ ██╔╝██║╚════██║
|
|
29
|
+
╚████║██║ ██║██║ ██║ ╚████╔╝ ██║███████║
|
|
30
|
+
╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═══╝ ╚═╝╚══════╝
|
|
31
|
+
{welcome_str}
|
|
32
|
+
|
|
33
|
+
https://github.com/skyfireitdiy/Jarvis
|
|
34
|
+
v{__version__}
|
|
35
|
+
"""
|
|
36
|
+
if welcome_str:
|
|
37
|
+
PrettyOutput.print_gradient_text(jarvis_ascii_art, (0, 120, 255), (0, 255, 200))
|
|
38
|
+
|
|
21
39
|
jarvis_dir = Path(get_data_dir())
|
|
22
40
|
env_file = jarvis_dir / "env"
|
|
23
41
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.177
|
|
4
4
|
Summary: Jarvis: An AI assistant that uses tools to interact with the system
|
|
5
5
|
Home-page: https://github.com/skyfireitdiy/Jarvis
|
|
6
6
|
Author: skyfire
|
|
@@ -201,7 +201,7 @@ OPENAI_API_BASE=https://api.openai.com/v1 # 可选,默认为官方API地址
|
|
|
201
201
|
### 环境变量配置
|
|
202
202
|
| 变量名称 | 默认值 | 说明 |
|
|
203
203
|
|----------|--------|------|
|
|
204
|
-
| `JARVIS_MAX_TOKEN_COUNT` |
|
|
204
|
+
| `JARVIS_MAX_TOKEN_COUNT` | 960000 | 上下文窗口的最大token数量 |
|
|
205
205
|
| `JARVIS_MAX_INPUT_TOKEN_COUNT` | 32000 | 输入的最大token数量 |
|
|
206
206
|
| `JARVIS_AUTO_COMPLETE` | false | 是否启用自动完成功能(任务判定完成的时候会自动终止) |
|
|
207
207
|
| `JARVIS_SHELL_NAME` | bash | 系统shell名称 |
|
|
@@ -211,9 +211,9 @@ OPENAI_API_BASE=https://api.openai.com/v1 # 可选,默认为官方API地址
|
|
|
211
211
|
| `JARVIS_THINKING_MODEL` | JARVIS_MODEL | 推理任务使用的模型 |
|
|
212
212
|
| `JARVIS_EXECUTE_TOOL_CONFIRM` | false | 执行工具前是否需要确认 |
|
|
213
213
|
| `JARVIS_CONFIRM_BEFORE_APPLY_PATCH` | true | 应用补丁前是否需要确认 |
|
|
214
|
-
| `JARVIS_MAX_TOOL_CALL_COUNT` | 20 |
|
|
214
|
+
| `JARVIS_MAX_TOOL_CALL_COUNT` | 20 | 最大连续工具调用次数,如果是0表示无限制 |
|
|
215
215
|
| `JARVIS_AUTO_UPDATE` | true | 是否自动更新Jarvis(仅在以git仓库方式安装时有效) |
|
|
216
|
-
| `JARVIS_MAX_BIG_CONTENT_SIZE` |
|
|
216
|
+
| `JARVIS_MAX_BIG_CONTENT_SIZE` | 1024000 | 最大大内容大小 |
|
|
217
217
|
| `JARVIS_PRETTY_OUTPUT` | false | 是否启用PrettyOutput |
|
|
218
218
|
|
|
219
219
|
所有配置编写到`~/.jarvis/env`文件中即可生效。
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
jarvis/__init__.py,sha256=
|
|
2
|
-
jarvis/jarvis_agent/__init__.py,sha256=
|
|
1
|
+
jarvis/__init__.py,sha256=0MngHgwvNC88-Zyu-Vgu75cfUiHVHhf7dT3ntn_mOvQ,74
|
|
2
|
+
jarvis/jarvis_agent/__init__.py,sha256=sDUOtM7Y-BQt2WBavx2bV5OkHD_iMGV32FfSu4IEa3s,29175
|
|
3
3
|
jarvis/jarvis_agent/builtin_input_handler.py,sha256=KhvlV_QdB3P-M0TCkWvdxidNie1jU7KoMOqTIXCpwwA,1529
|
|
4
|
-
jarvis/jarvis_agent/jarvis.py,sha256=
|
|
5
|
-
jarvis/jarvis_agent/main.py,sha256=
|
|
4
|
+
jarvis/jarvis_agent/jarvis.py,sha256=h3-FsL9Y4GtbNPk6qWYs2t6VB8CKabY7_UNe58tzucE,6142
|
|
5
|
+
jarvis/jarvis_agent/main.py,sha256=jvxnBmm4BM13quaCip2PC1-DkAX0MAU25b8nhHIQ5xM,2667
|
|
6
6
|
jarvis/jarvis_agent/output_handler.py,sha256=7qori-RGrQmdiFepoEe3oPPKJIvRt90l_JDmvCoa4zA,1219
|
|
7
7
|
jarvis/jarvis_agent/shell_input_handler.py,sha256=pi3AtPKrkKc6K9e99S1djKXQ_XrxtP6FrSWebQmRT6E,1261
|
|
8
8
|
jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
jarvis/jarvis_code_agent/code_agent.py,sha256=
|
|
10
|
-
jarvis/jarvis_code_analysis/code_review.py,sha256=
|
|
9
|
+
jarvis/jarvis_code_agent/code_agent.py,sha256=9SBMlLWNGR6lqVD7xZaLjokka-yoNGb-OxpHtJjCf_k,17166
|
|
10
|
+
jarvis/jarvis_code_analysis/code_review.py,sha256=9zfVY_u_WSRIKQ69lXeW-pOunh5lYYyQe9i_zEO3m2k,30212
|
|
11
11
|
jarvis/jarvis_code_analysis/checklists/__init__.py,sha256=cKQ_FOGy5TQgM-YkRCqORo-mUOZaPAJ9VDmZoFX58us,78
|
|
12
12
|
jarvis/jarvis_code_analysis/checklists/c_cpp.py,sha256=SXPpYCNeCtU1PpKdKPiYDuOybfY9vaL0ejDn4imxDwA,1317
|
|
13
13
|
jarvis/jarvis_code_analysis/checklists/csharp.py,sha256=vS-cu6RCGg5SyK9MJ3RE381gt3xYl-yea3Bj2UQEcwQ,2420
|
|
@@ -29,12 +29,12 @@ jarvis/jarvis_code_analysis/checklists/sql.py,sha256=ecKKT6wJAibn8R0NxGZDNlm4teY
|
|
|
29
29
|
jarvis/jarvis_code_analysis/checklists/swift.py,sha256=YcsYFxAitHqOtBZjG-RV9-KNM7X5lIcl6zlEI9XfmfM,2566
|
|
30
30
|
jarvis/jarvis_code_analysis/checklists/web.py,sha256=-Pnj1FQTsGVZUQK7-4ptDsGd7a22Cs0585jRAPT2SdQ,3943
|
|
31
31
|
jarvis/jarvis_data/huggingface.tar.gz,sha256=dWKnc_tvyx-I_ZkXo91O0b38KxDmLW1ZbmJ3E6fCl_k,1120205
|
|
32
|
-
jarvis/jarvis_dev/main.py,sha256=
|
|
32
|
+
jarvis/jarvis_dev/main.py,sha256=kyCLm2Ta-iMK20m62O7_rB-Biy_bGxpqrLrLtMOkT5c,43022
|
|
33
33
|
jarvis/jarvis_git_details/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
-
jarvis/jarvis_git_details/main.py,sha256=
|
|
34
|
+
jarvis/jarvis_git_details/main.py,sha256=lYx2tSaV1cKCvs3iRf-gHwotg-sljvxC4iPeODpBnbA,9007
|
|
35
35
|
jarvis/jarvis_git_squash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
-
jarvis/jarvis_git_squash/main.py,sha256=
|
|
37
|
-
jarvis/jarvis_git_utils/git_commiter.py,sha256=
|
|
36
|
+
jarvis/jarvis_git_squash/main.py,sha256=nGygczZlRbczKAU8LEFLHQVjpgCkbGx7GQQcwo57cSo,2276
|
|
37
|
+
jarvis/jarvis_git_utils/git_commiter.py,sha256=58ZhxwDdYzMH9-uvVe2dazQfq8uNcZTJQq7SMJEFsic,13020
|
|
38
38
|
jarvis/jarvis_lsp/base.py,sha256=ZngrQ4NUy9iPrXORcw4QR-tWZi2G79nsfqeqqkaxSZ0,2054
|
|
39
39
|
jarvis/jarvis_lsp/cpp.py,sha256=WL7rItrwFkYRSZzQHnoOoQ-EDho7Jd6BOaCn1UgsQ3A,3165
|
|
40
40
|
jarvis/jarvis_lsp/go.py,sha256=FkBJAeJex8jamn44o_cpYCygSTGMnsykJGrnkVFlTww,3482
|
|
@@ -46,27 +46,27 @@ jarvis/jarvis_mcp/sse_mcp_client.py,sha256=FOVzroTw-pifmnF0qdsoQ6KweDCQ0Gxs6d6jl
|
|
|
46
46
|
jarvis/jarvis_mcp/stdio_mcp_client.py,sha256=KO0ewJuLBZLNqG4EGJcBOtn-8VJIipkq84ENvSwgQAo,11830
|
|
47
47
|
jarvis/jarvis_methodology/main.py,sha256=QJUMIb9o8JO-l207X5UIbazZKJYKG3F4iuUKtkm0dmg,11840
|
|
48
48
|
jarvis/jarvis_multi_agent/__init__.py,sha256=Xab5sFltJmX_9MoXqanmZs6FqKfUb2v_pG29Vk8ZXaw,4311
|
|
49
|
-
jarvis/jarvis_multi_agent/main.py,sha256=
|
|
49
|
+
jarvis/jarvis_multi_agent/main.py,sha256=Ax3Oe0mjcW567VhFYPt3H5MwqLS1VdxKCeiNgXltmXk,1644
|
|
50
50
|
jarvis/jarvis_platform/__init__.py,sha256=0YnsUoM4JkIBOtImFdjfuDbrqQZT3dEaAwSJ62DrpCc,104
|
|
51
|
-
jarvis/jarvis_platform/base.py,sha256=
|
|
51
|
+
jarvis/jarvis_platform/base.py,sha256=ioIEtuEVuXCdLpPofR9c-lqvADM-pCz5XOMQVKq8xeI,6740
|
|
52
52
|
jarvis/jarvis_platform/human.py,sha256=1Jh9xigQaU78WVvsIMaVH0i6QRhaSA1oaErv9BdntF8,2565
|
|
53
53
|
jarvis/jarvis_platform/kimi.py,sha256=p18Ydb_0rgnK3-WZXKUtTBQTh7Da33O277PKWOMqBhA,13106
|
|
54
54
|
jarvis/jarvis_platform/openai.py,sha256=ln-OYxZkWaSY9oDoBPMmMh2TDGN40iTtUURLk8batvQ,4159
|
|
55
55
|
jarvis/jarvis_platform/registry.py,sha256=UjCdPT9WIRxU-F0uuPpKmKRRCcNNxjr-bRTEPgRSNx4,7740
|
|
56
|
-
jarvis/jarvis_platform/yuanbao.py,sha256=
|
|
56
|
+
jarvis/jarvis_platform/yuanbao.py,sha256=Vi8D3lhTOwg2-PmMj7HHRXKg-dViI2ghtJcxm3tf8nc,21669
|
|
57
57
|
jarvis/jarvis_platform_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
58
|
-
jarvis/jarvis_platform_manager/main.py,sha256=
|
|
58
|
+
jarvis/jarvis_platform_manager/main.py,sha256=cpnqYWjb2fU2uhrTtYyyrKpe6rta2NniYjZE6BjLG8k,25675
|
|
59
59
|
jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
-
jarvis/jarvis_smart_shell/main.py,sha256=
|
|
60
|
+
jarvis/jarvis_smart_shell/main.py,sha256=v3DXutU-lBYABxB1tURHPcdTJuoT3gthdXl8O5tOGJw,5208
|
|
61
61
|
jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
62
|
-
jarvis/jarvis_tools/ask_codebase.py,sha256=
|
|
62
|
+
jarvis/jarvis_tools/ask_codebase.py,sha256=bdYZlEdKGFQjYL90Qo3ybgxicFPU8g3mQtLH8exmliU,10063
|
|
63
63
|
jarvis/jarvis_tools/ask_user.py,sha256=cWSLG33b79IbIZEWsSNV5RHvGX6eo3nTM8TUhOMnGh8,2167
|
|
64
64
|
jarvis/jarvis_tools/base.py,sha256=SR4dmrgYj3lNmtVDhHtItPvptTqCfw5SGRhgPT3I6ss,1189
|
|
65
65
|
jarvis/jarvis_tools/chdir.py,sha256=wYVBqWF5kaUkKqH3cUAOKUsACzYsFtCCJJyd8UJsp4o,2706
|
|
66
66
|
jarvis/jarvis_tools/code_plan.py,sha256=EzLdbJnVCkJ7lL8XIQyuDJdxU1i3CFiBpqyNG-GdJw8,7753
|
|
67
67
|
jarvis/jarvis_tools/create_code_agent.py,sha256=cxYkjr4rhI2EWpK78psZSRB9mxiP1IUT0SEfFIqCJzY,3411
|
|
68
68
|
jarvis/jarvis_tools/create_sub_agent.py,sha256=ppTOFRd0ygSJUFr3oQ8IrCLOqbZ7vwnbdadfTDjpDgs,3025
|
|
69
|
-
jarvis/jarvis_tools/edit_file.py,sha256=
|
|
69
|
+
jarvis/jarvis_tools/edit_file.py,sha256=EqyLcnLNqFAhIn3g_wZs78qeGFPJh4Rieldbt5l4FHY,16226
|
|
70
70
|
jarvis/jarvis_tools/execute_script.py,sha256=cc0NlPwhkZinEexqT63d1ofEkzQddVWGsZOCVL1v_60,5739
|
|
71
71
|
jarvis/jarvis_tools/file_analyzer.py,sha256=tzU1cPKyDa54hVZewP0bDzdsjvdjGQ1BRt5k8N4li3s,4868
|
|
72
72
|
jarvis/jarvis_tools/file_operation.py,sha256=lP8EpsnSdA3FW8ofSAdoA8qPGMAG3UhYd6LFEzOFUVY,9044
|
|
@@ -74,29 +74,29 @@ jarvis/jarvis_tools/find_methodology.py,sha256=FwGKSV4fHNkiAnaVUwP8GkqXl8PEqMPZB
|
|
|
74
74
|
jarvis/jarvis_tools/generate_new_tool.py,sha256=ctpkHBihsHhO6sLpF5lJue244EFJtdEQMuxR-_oV9r4,10282
|
|
75
75
|
jarvis/jarvis_tools/lsp_get_diagnostics.py,sha256=paz1CVZ2Y8nk0U74n1QiG01oDINiZqpVlPc2f4_B150,5346
|
|
76
76
|
jarvis/jarvis_tools/methodology.py,sha256=Md8W2et0xUiuTjUSRCdnlwEPYqah2dCAAkxW_95BXBY,5238
|
|
77
|
-
jarvis/jarvis_tools/read_code.py,sha256=
|
|
77
|
+
jarvis/jarvis_tools/read_code.py,sha256=dOG7bafutOhjLiU7NH-o7E_o6pJrXH98SAGRJ36Yj9Q,5897
|
|
78
78
|
jarvis/jarvis_tools/read_webpage.py,sha256=LLvAOvaQJodaeNJKQ6dU9MYEE227NMdHyLs7esluUQ4,2217
|
|
79
|
-
jarvis/jarvis_tools/registry.py,sha256=
|
|
79
|
+
jarvis/jarvis_tools/registry.py,sha256=ISgelm0E1mNj0bikJxN9fA1VGzm23pVkWv-j7E3gWHY,23792
|
|
80
80
|
jarvis/jarvis_tools/rewrite_file.py,sha256=rEPPSNU7uF1iKfEW9npEpZJ2LSoQXjt2OC-_troBToE,7003
|
|
81
81
|
jarvis/jarvis_tools/search_web.py,sha256=-h1WYOqTcYC_8fdkm-4RfwKpbtLTVxOfRROul51NgO0,951
|
|
82
82
|
jarvis/jarvis_tools/virtual_tty.py,sha256=AKAaKY5KcPxifNQoXjzHaL4U6EUVA7irHLwVvz2wLVs,16396
|
|
83
83
|
jarvis/jarvis_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
84
|
-
jarvis/jarvis_tools/cli/main.py,sha256=
|
|
84
|
+
jarvis/jarvis_tools/cli/main.py,sha256=FkBUh7TgvZu6CZfQAKdu0zYm27fSfA6OK4H_m8h_4Mw,6354
|
|
85
85
|
jarvis/jarvis_utils/__init__.py,sha256=l-fsyQ-KzyqAhrJYur8eZAqsgaifGzSm24R2qtRGJ0g,849
|
|
86
86
|
jarvis/jarvis_utils/builtin_replace_map.py,sha256=A-cJ8deht2vDl2iKRhoZ7qECyJ6sboVH5Zx-L9vIBUs,4314
|
|
87
|
-
jarvis/jarvis_utils/config.py,sha256=
|
|
87
|
+
jarvis/jarvis_utils/config.py,sha256=CuumaSrwSaSdt_bJVqjuH3u45ZKafm7MQANqO5NZDXk,4756
|
|
88
88
|
jarvis/jarvis_utils/embedding.py,sha256=s7ze8-talEED9VXZm1QK5tPdfyj6sXJLP031tDkXeI4,3831
|
|
89
89
|
jarvis/jarvis_utils/file_processors.py,sha256=tSZSMJ4qCJ_lXI0dyLgJ0j5qEh6CDXDSVI7vQiFmcuQ,2976
|
|
90
90
|
jarvis/jarvis_utils/git_utils.py,sha256=MxhUcQ_gFUFyBxBiorEJ1wUk9a2TerFdq3-Z11FB-AE,11324
|
|
91
91
|
jarvis/jarvis_utils/globals.py,sha256=Zs0chxA_giYiolYvawFFpcnTWgCUnn6GEusAh42jbz8,2275
|
|
92
92
|
jarvis/jarvis_utils/input.py,sha256=qGf2q-yWhgT-OX-j_WYi7aZ11jYmuFNiMz2_W1nUOiM,7432
|
|
93
93
|
jarvis/jarvis_utils/methodology.py,sha256=9dmtj6Ei2CRUdQP9TA_xToqZPYcm5_DQovwnRkEShsA,8626
|
|
94
|
-
jarvis/jarvis_utils/output.py,sha256=
|
|
94
|
+
jarvis/jarvis_utils/output.py,sha256=jrZMPl4RGaw8i-IFN4JwkH3wB9QDl002Car5eENDE9c,9657
|
|
95
95
|
jarvis/jarvis_utils/tag.py,sha256=YJHmuedLb7_AiqvKQetHr4R1FxyzIh7HN0RRkWMmYbU,429
|
|
96
|
-
jarvis/jarvis_utils/utils.py,sha256=
|
|
97
|
-
jarvis_ai_assistant-0.1.
|
|
98
|
-
jarvis_ai_assistant-0.1.
|
|
99
|
-
jarvis_ai_assistant-0.1.
|
|
100
|
-
jarvis_ai_assistant-0.1.
|
|
101
|
-
jarvis_ai_assistant-0.1.
|
|
102
|
-
jarvis_ai_assistant-0.1.
|
|
96
|
+
jarvis/jarvis_utils/utils.py,sha256=yXSSQwgwho3MpQWvJN1uRvRPsFvkKqhvQrbDz3ZyyxU,5390
|
|
97
|
+
jarvis_ai_assistant-0.1.177.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
|
|
98
|
+
jarvis_ai_assistant-0.1.177.dist-info/METADATA,sha256=Yt6Tjk7wG7gh0nyyRhYtMPu0-_pg0mTvcIlDrqOuT2g,14629
|
|
99
|
+
jarvis_ai_assistant-0.1.177.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
100
|
+
jarvis_ai_assistant-0.1.177.dist-info/entry_points.txt,sha256=rjj61tZ7ahLi1R-JkJmX-IzIPPHD8mnwDZap1CnMe2s,973
|
|
101
|
+
jarvis_ai_assistant-0.1.177.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
102
|
+
jarvis_ai_assistant-0.1.177.dist-info/RECORD,,
|
{jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{jarvis_ai_assistant-0.1.176.dist-info → jarvis_ai_assistant-0.1.177.dist-info}/top_level.txt
RENAMED
|
File without changes
|