jarvis-ai-assistant 0.1.188__py3-none-any.whl → 0.1.189__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +61 -57
- jarvis/jarvis_code_analysis/code_review.py +15 -14
- jarvis/jarvis_data/config_schema.json +1 -1
- jarvis/jarvis_dev/main.py +6 -6
- jarvis/jarvis_git_details/main.py +1 -1
- jarvis/jarvis_git_utils/git_commiter.py +238 -202
- jarvis/jarvis_platform/base.py +4 -3
- jarvis/jarvis_platform/kimi.py +4 -0
- jarvis/jarvis_platform/tongyi.py +4 -0
- jarvis/jarvis_platform/yuanbao.py +4 -0
- jarvis/jarvis_platform_manager/main.py +4 -0
- jarvis/jarvis_tools/edit_file.py +12 -10
- jarvis/jarvis_tools/file_analyzer.py +5 -2
- jarvis/jarvis_tools/registry.py +23 -17
- jarvis/jarvis_utils/config.py +1 -1
- jarvis/jarvis_utils/methodology.py +9 -11
- {jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/METADATA +2 -2
- {jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/RECORD +23 -23
- {jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/jarvis_agent/__init__.py
CHANGED
@@ -4,8 +4,6 @@ import datetime
|
|
4
4
|
import platform
|
5
5
|
from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple, Union
|
6
6
|
|
7
|
-
from jarvis.jarvis_platform.base import BasePlatform
|
8
|
-
|
9
7
|
# 第三方库导入
|
10
8
|
from yaspin import yaspin # type: ignore
|
11
9
|
|
@@ -224,7 +222,11 @@ class Agent:
|
|
224
222
|
|
225
223
|
# 如果有上传文件,自动禁用方法论
|
226
224
|
self.use_methodology = (
|
227
|
-
False
|
225
|
+
False
|
226
|
+
if files
|
227
|
+
else (
|
228
|
+
use_methodology if use_methodology is not None else is_use_methodology()
|
229
|
+
)
|
228
230
|
)
|
229
231
|
self.use_analysis = (
|
230
232
|
use_analysis if use_analysis is not None else is_use_analysis()
|
@@ -440,24 +442,15 @@ class Agent:
|
|
440
442
|
self.conversation_length += get_context_token_count(response)
|
441
443
|
return response
|
442
444
|
|
443
|
-
def
|
444
|
-
"""
|
445
|
-
|
446
|
-
该方法将:
|
447
|
-
1. 生成关键信息摘要
|
448
|
-
2. 清除对话历史
|
449
|
-
3. 保留系统消息
|
450
|
-
4. 添加摘要作为新上下文
|
451
|
-
5. 重置对话长度计数器
|
445
|
+
def generate_summary(self) -> str:
|
446
|
+
"""生成对话历史摘要
|
452
447
|
|
453
448
|
返回:
|
454
449
|
str: 包含对话摘要的字符串
|
455
450
|
|
456
451
|
注意:
|
457
|
-
|
452
|
+
仅生成摘要,不修改对话状态
|
458
453
|
"""
|
459
|
-
# Create a new model instance to summarize, avoid affecting the main conversation
|
460
|
-
|
461
454
|
with yaspin(text="正在总结对话历史...", color="cyan") as spinner:
|
462
455
|
summary_prompt = """
|
463
456
|
<summary_request>
|
@@ -482,36 +475,48 @@ class Agent:
|
|
482
475
|
</summary_request>
|
483
476
|
"""
|
484
477
|
|
485
|
-
|
486
|
-
|
487
|
-
|
478
|
+
try:
|
479
|
+
with spinner.hidden():
|
480
|
+
summary = self.model.chat_until_success(self.prompt + "\n" + summary_prompt) # type: ignore
|
481
|
+
spinner.text = "总结对话历史完成"
|
482
|
+
spinner.ok("✅")
|
483
|
+
return summary
|
484
|
+
except Exception as e:
|
485
|
+
spinner.text = "总结对话历史失败"
|
486
|
+
spinner.fail("❌")
|
487
|
+
return ""
|
488
488
|
|
489
|
-
|
489
|
+
def _summarize_and_clear_history(self) -> str:
|
490
|
+
"""总结当前对话并清理历史记录
|
490
491
|
|
491
|
-
|
492
|
-
|
492
|
+
该方法将:
|
493
|
+
1. 调用_generate_summary生成摘要
|
494
|
+
2. 清除对话历史
|
495
|
+
3. 保留系统消息
|
496
|
+
4. 添加摘要作为新上下文
|
497
|
+
5. 重置对话长度计数器
|
493
498
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
+
返回:
|
500
|
+
str: 包含对话摘要的字符串
|
501
|
+
|
502
|
+
注意:
|
503
|
+
当上下文长度超过最大值时使用
|
504
|
+
"""
|
505
|
+
summary = self.generate_summary()
|
506
|
+
self.clear_history() # type: ignore
|
507
|
+
|
508
|
+
if not summary:
|
509
|
+
return ""
|
510
|
+
|
511
|
+
return f"""
|
499
512
|
以下是之前对话的关键信息总结:
|
500
|
-
</header>
|
501
513
|
|
502
514
|
<content>
|
503
515
|
{summary}
|
504
516
|
</content>
|
505
517
|
|
506
|
-
<instructions>
|
507
518
|
请基于以上信息继续完成任务。请注意,这是之前对话的摘要,上下文长度已超过限制而被重置。请直接继续任务,无需重复已完成的步骤。如有需要,可以询问用户以获取更多信息。
|
508
|
-
</instructions>
|
509
|
-
</summary>
|
510
519
|
"""
|
511
|
-
except Exception as e:
|
512
|
-
spinner.text = "总结对话历史失败"
|
513
|
-
spinner.fail("❌")
|
514
|
-
return ""
|
515
520
|
|
516
521
|
def _call_tools(self, response: str) -> Tuple[bool, Any]:
|
517
522
|
"""调用工具执行响应
|
@@ -770,32 +775,31 @@ arguments:
|
|
770
775
|
3. 包含错误处理和恢复逻辑
|
771
776
|
4. 自动加载相关方法论(如果是首次运行)
|
772
777
|
"""
|
778
|
+
|
779
|
+
self.prompt = f"{user_input}"
|
773
780
|
try:
|
774
781
|
set_agent(self.name, self)
|
775
782
|
|
776
|
-
self.prompt = f"{user_input}"
|
777
|
-
|
778
|
-
if self.first:
|
779
|
-
# 如果有上传文件,先上传文件
|
780
|
-
if self.files and isinstance(self.model, BasePlatform) and hasattr(self.model, "upload_files"):
|
781
|
-
self.model.upload_files(self.files)
|
782
|
-
self.prompt = f"{user_input}"
|
783
|
-
|
784
|
-
# 如果启用方法论且没有上传文件,上传方法论
|
785
|
-
elif self.use_methodology:
|
786
|
-
platform = self.model if hasattr(self.model, "upload_files") else None
|
787
|
-
if platform and upload_methodology(platform):
|
788
|
-
self.prompt = f"{user_input}"
|
789
|
-
else:
|
790
|
-
# 上传失败则回退到本地加载
|
791
|
-
msg = user_input
|
792
|
-
for handler in self.input_handler:
|
793
|
-
msg, _ = handler(msg, self)
|
794
|
-
self.prompt = f"{user_input}\n\n以下是历史类似问题的执行经验,可参考:\n{load_methodology(msg, self.get_tool_registry())}"
|
795
|
-
|
796
|
-
self.first = False
|
797
|
-
|
798
783
|
while True:
|
784
|
+
if self.first:
|
785
|
+
# 如果有上传文件,先上传文件
|
786
|
+
if (
|
787
|
+
self.files
|
788
|
+
and self.model
|
789
|
+
and self.model.support_upload_files()
|
790
|
+
):
|
791
|
+
self.model.upload_files(self.files)
|
792
|
+
|
793
|
+
# 如果启用方法论且没有上传文件,上传方法论
|
794
|
+
elif self.use_methodology:
|
795
|
+
if not self.model or not upload_methodology(self.model):
|
796
|
+
# 上传失败则回退到本地加载
|
797
|
+
msg = self.prompt
|
798
|
+
for handler in self.input_handler:
|
799
|
+
msg, _ = handler(msg, self)
|
800
|
+
self.prompt = f"{self.prompt}\n\n以下是历史类似问题的执行经验,可参考:\n{load_methodology(msg, self.get_tool_registry())}"
|
801
|
+
|
802
|
+
self.first = False
|
799
803
|
try:
|
800
804
|
current_response = self._call_model(self.prompt, True)
|
801
805
|
self.prompt = ""
|
@@ -836,7 +840,7 @@ arguments:
|
|
836
840
|
PrettyOutput.print(f"任务失败: {str(e)}", OutputType.ERROR)
|
837
841
|
return f"Task failed: {str(e)}"
|
838
842
|
|
839
|
-
def
|
843
|
+
def clear_history(self):
|
840
844
|
"""清空对话历史但保留系统提示
|
841
845
|
|
842
846
|
该方法将:
|
@@ -588,25 +588,33 @@ class CodeReviewTool:
|
|
588
588
|
temp_file.flush()
|
589
589
|
|
590
590
|
try:
|
591
|
-
upload_success = False
|
592
591
|
# Check if content is too large
|
593
592
|
is_large_content = is_context_overflow(diff_output)
|
594
593
|
|
595
594
|
# Upload the file to the agent's model
|
596
|
-
if is_large_content
|
595
|
+
if is_large_content:
|
596
|
+
if not agent.model or not agent.model.support_upload_files():
|
597
|
+
return {
|
598
|
+
"success": False,
|
599
|
+
"stdout": "",
|
600
|
+
"stderr": "代码差异太大,无法处理"
|
601
|
+
}
|
602
|
+
|
597
603
|
with yaspin(text="正在上传代码差异文件...", color="cyan") as spinner:
|
598
604
|
upload_success = agent.model.upload_files([temp_file_path])
|
599
605
|
if upload_success:
|
600
606
|
spinner.ok("✅")
|
601
607
|
PrettyOutput.print(f"已成功上传代码差异文件", OutputType.SUCCESS)
|
602
608
|
else:
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
609
|
+
return {
|
610
|
+
"success": False,
|
611
|
+
"stdout": "",
|
612
|
+
"stderr": "上传代码差异文件失败"
|
613
|
+
}
|
614
|
+
|
607
615
|
|
608
616
|
# Prepare the prompt based on upload status
|
609
|
-
if
|
617
|
+
if is_large_content:
|
610
618
|
# When file is uploaded, reference it in the prompt
|
611
619
|
complete_prompt = user_prompt + f"""
|
612
620
|
|
@@ -619,13 +627,6 @@ class CodeReviewTool:
|
|
619
627
|
# Run the agent with the prompt
|
620
628
|
result = agent.run(complete_prompt)
|
621
629
|
else:
|
622
|
-
if is_large_content:
|
623
|
-
return {
|
624
|
-
"success": False,
|
625
|
-
"stdout": "",
|
626
|
-
"stderr": "错误:上传代码差异文件失败"
|
627
|
-
}
|
628
|
-
# Include the diff directly in the prompt for smaller content
|
629
630
|
complete_prompt = user_prompt + "\n\n代码差异内容:\n```diff\n" + diff_output + "\n```"
|
630
631
|
result = agent.run(complete_prompt)
|
631
632
|
finally:
|
jarvis/jarvis_dev/main.py
CHANGED
@@ -1160,42 +1160,42 @@ def create_dev_team() -> MultiAgent:
|
|
1160
1160
|
description="Project Manager - Coordinates team and manages project delivery",
|
1161
1161
|
system_prompt=PM_PROMPT_WITH_TOOLS,
|
1162
1162
|
output_handler=[PM_output_handler],
|
1163
|
-
platform=PlatformRegistry().
|
1163
|
+
platform=PlatformRegistry().get_normal_platform(),
|
1164
1164
|
),
|
1165
1165
|
dict(
|
1166
1166
|
name="BA",
|
1167
1167
|
description="Business Analyst - Analyzes and documents requirements",
|
1168
1168
|
system_prompt=BA_PROMPT_WITH_TOOLS,
|
1169
1169
|
output_handler=[BA_output_handler],
|
1170
|
-
platform=PlatformRegistry().
|
1170
|
+
platform=PlatformRegistry().get_normal_platform(),
|
1171
1171
|
),
|
1172
1172
|
dict(
|
1173
1173
|
name="SA",
|
1174
1174
|
description="Solution Architect - Designs technical solutions",
|
1175
1175
|
system_prompt=SA_PROMPT_WITH_TOOLS,
|
1176
1176
|
output_handler=[SA_output_handler],
|
1177
|
-
platform=PlatformRegistry().
|
1177
|
+
platform=PlatformRegistry().get_normal_platform(),
|
1178
1178
|
),
|
1179
1179
|
dict(
|
1180
1180
|
name="TL",
|
1181
1181
|
description="Technical Lead - Leads development team and ensures technical quality",
|
1182
1182
|
system_prompt=TL_PROMPT_WITH_TOOLS,
|
1183
1183
|
output_handler=[TL_output_handler],
|
1184
|
-
platform=PlatformRegistry().
|
1184
|
+
platform=PlatformRegistry().get_normal_platform(),
|
1185
1185
|
),
|
1186
1186
|
dict(
|
1187
1187
|
name="DEV",
|
1188
1188
|
description="Developer - Implements features and writes code",
|
1189
1189
|
system_prompt=DEV_PROMPT_WITH_TOOLS,
|
1190
1190
|
output_handler=[DEV_output_handler],
|
1191
|
-
platform=PlatformRegistry().
|
1191
|
+
platform=PlatformRegistry().get_normal_platform(),
|
1192
1192
|
),
|
1193
1193
|
dict(
|
1194
1194
|
name="QA",
|
1195
1195
|
description="Quality Assurance - Ensures product quality through testing",
|
1196
1196
|
system_prompt=QA_PROMPT_WITH_TOOLS,
|
1197
1197
|
output_handler=[QA_output_handler],
|
1198
|
-
platform=PlatformRegistry().
|
1198
|
+
platform=PlatformRegistry().get_normal_platform(),
|
1199
1199
|
)
|
1200
1200
|
]
|
1201
1201
|
|
@@ -207,7 +207,7 @@ class GitCommitAnalyzer:
|
|
207
207
|
[检查代码是否符合行业最佳实践和项目规范]
|
208
208
|
{ct("REPORT")}""",
|
209
209
|
output_handler=[tool_registry],
|
210
|
-
platform=PlatformRegistry().
|
210
|
+
platform=PlatformRegistry().get_normal_platform(),
|
211
211
|
auto_complete=True
|
212
212
|
)
|
213
213
|
|
@@ -12,8 +12,7 @@ from yaspin import yaspin
|
|
12
12
|
|
13
13
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
14
14
|
from jarvis.jarvis_utils.config import get_git_commit_prompt
|
15
|
-
from jarvis.jarvis_utils.git_utils import
|
16
|
-
has_uncommitted_changes)
|
15
|
+
from jarvis.jarvis_utils.git_utils import find_git_root, has_uncommitted_changes
|
17
16
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
18
17
|
from jarvis.jarvis_utils.tag import ct, ot
|
19
18
|
from jarvis.jarvis_utils.utils import init_env, is_context_overflow
|
@@ -22,48 +21,59 @@ from jarvis.jarvis_utils.utils import init_env, is_context_overflow
|
|
22
21
|
class GitCommitTool:
|
23
22
|
name = "git_commit_agent"
|
24
23
|
description = "根据代码变更自动生成并执行Git提交"
|
25
|
-
labels = [
|
24
|
+
labels = ["git", "version_control"]
|
26
25
|
parameters = {
|
27
26
|
"type": "object",
|
28
27
|
"properties": {
|
29
28
|
"root_dir": {
|
30
29
|
"type": "string",
|
31
30
|
"description": "Git仓库的根目录路径(可选)",
|
32
|
-
"default": "."
|
31
|
+
"default": ".",
|
33
32
|
},
|
34
|
-
"prefix": {
|
35
|
-
|
36
|
-
"description": "提交信息前缀(可选)",
|
37
|
-
"default": ""
|
38
|
-
},
|
39
|
-
"suffix": {
|
40
|
-
"type": "string",
|
41
|
-
"description": "提交信息后缀(可选)",
|
42
|
-
"default": ""
|
43
|
-
}
|
33
|
+
"prefix": {"type": "string", "description": "提交信息前缀(可选)", "default": ""},
|
34
|
+
"suffix": {"type": "string", "description": "提交信息后缀(可选)", "default": ""},
|
44
35
|
},
|
45
|
-
"required": []
|
36
|
+
"required": [],
|
46
37
|
}
|
47
|
-
|
38
|
+
|
39
|
+
def _extract_commit_message(self, message) -> Optional[str]:
|
48
40
|
"""Raw extraction preserving all characters"""
|
49
41
|
r = re.search(
|
50
42
|
r"(?i)" + ot("COMMIT_MESSAGE") + r"\s*([\s\S]*?)\s*" + ct("COMMIT_MESSAGE"),
|
51
|
-
message
|
43
|
+
message,
|
52
44
|
)
|
53
45
|
if r:
|
54
46
|
# 直接返回原始内容,仅去除外围空白
|
55
47
|
return r.group(1).strip()
|
56
48
|
return None
|
57
49
|
|
58
|
-
def _get_last_commit_hash(self):
|
50
|
+
def _get_last_commit_hash(self) -> str:
|
59
51
|
process = subprocess.Popen(
|
60
52
|
["git", "log", "-1", "--pretty=%H"],
|
61
53
|
stdout=subprocess.PIPE,
|
62
|
-
stderr=subprocess.PIPE
|
54
|
+
stderr=subprocess.PIPE,
|
63
55
|
)
|
64
56
|
stdout, _ = process.communicate()
|
65
57
|
return stdout.decode().strip()
|
66
58
|
|
59
|
+
def _prepare_git_environment(self, root_dir: str) -> Optional[str]:
|
60
|
+
"""Prepare git environment by changing directory and checking for changes"""
|
61
|
+
original_dir = os.getcwd()
|
62
|
+
os.chdir(root_dir)
|
63
|
+
find_git_root()
|
64
|
+
if not has_uncommitted_changes():
|
65
|
+
PrettyOutput.print("没有未提交的更改", OutputType.SUCCESS)
|
66
|
+
return None
|
67
|
+
return original_dir
|
68
|
+
|
69
|
+
def _stage_changes(self, spinner) -> None:
|
70
|
+
"""Stage all changes for commit"""
|
71
|
+
spinner.text = "正在添加文件到提交..."
|
72
|
+
subprocess.Popen(
|
73
|
+
["git", "add", "."], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
74
|
+
).wait()
|
75
|
+
spinner.write("✅ 添加文件到提交")
|
76
|
+
|
67
77
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
68
78
|
"""Execute automatic commit process with support for multi-line messages and special characters"""
|
69
79
|
try:
|
@@ -71,214 +81,240 @@ class GitCommitTool:
|
|
71
81
|
prefix = args.get("prefix", "")
|
72
82
|
suffix = args.get("suffix", "")
|
73
83
|
|
74
|
-
#
|
75
|
-
|
84
|
+
# Prepare git environment
|
85
|
+
result = self._prepare_git_environment(root_dir)
|
86
|
+
if result is None:
|
87
|
+
return {"success": True, "stdout": "No changes to commit", "stderr": ""}
|
88
|
+
original_dir = result
|
76
89
|
|
77
|
-
|
78
|
-
#
|
79
|
-
|
90
|
+
with yaspin(text="正在初始化提交流程...", color="cyan") as spinner:
|
91
|
+
# 添加文件到暂存区
|
92
|
+
self._stage_changes(spinner)
|
80
93
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
94
|
+
# 获取差异
|
95
|
+
spinner.text = "正在获取代码差异..."
|
96
|
+
# 获取文件列表
|
97
|
+
files_cmd = ["git", "diff", "--cached", "--name-only"]
|
98
|
+
process = subprocess.Popen(
|
99
|
+
files_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
100
|
+
)
|
101
|
+
files_output = process.communicate()[0].decode()
|
102
|
+
files = [f.strip() for f in files_output.split("\n") if f.strip()]
|
103
|
+
file_count = len(files)
|
85
104
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
subprocess.
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
105
|
+
# 获取完整差异
|
106
|
+
process = subprocess.Popen(
|
107
|
+
["git", "diff", "--cached", "--exit-code"],
|
108
|
+
stdout=subprocess.PIPE,
|
109
|
+
stderr=subprocess.PIPE,
|
110
|
+
)
|
111
|
+
diff = process.communicate()[0].decode()
|
112
|
+
spinner.write(f"✅ 获取差异 ({file_count} 个文件)")
|
113
|
+
try:
|
114
|
+
temp_diff_file_path = None
|
115
|
+
# 生成提交信息
|
116
|
+
spinner.text = "正在生成提交消息..."
|
95
117
|
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
118
|
+
# 准备提示信息
|
119
|
+
custom_prompt = get_git_commit_prompt()
|
120
|
+
base_prompt = (
|
121
|
+
custom_prompt
|
122
|
+
if custom_prompt
|
123
|
+
else f"""根据代码差异生成提交信息:
|
124
|
+
提交信息应使用中文书写
|
125
|
+
# 格式模板
|
126
|
+
必须使用以下格式:
|
127
|
+
|
128
|
+
<类型>(<范围>): <主题>
|
129
|
+
|
130
|
+
[可选] 详细描述变更内容和原因
|
131
|
+
|
132
|
+
# 格式规则
|
133
|
+
1. 类型: fix(修复bug), feat(新功能), docs(文档), style(格式), refactor(重构), test(测试), chore(其他)
|
134
|
+
2. 范围表示变更的模块或组件 (例如: auth, database, ui)
|
135
|
+
3. 主题行不超过72个字符,不以句号结尾,使用祈使语气
|
136
|
+
4. 如有详细描述,使用空行分隔主题和详细描述
|
137
|
+
5. 详细描述部分应解释"是什么"和"为什么",而非"如何"
|
138
|
+
6. 仅输出提交信息,不要输出其他内容
|
139
|
+
"""
|
114
140
|
)
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
# 准备提示信息
|
123
|
-
custom_prompt = get_git_commit_prompt()
|
124
|
-
base_prompt = custom_prompt if custom_prompt else f'''根据代码差异生成提交信息:
|
125
|
-
提交信息应使用中文书写
|
126
|
-
# 格式模板
|
127
|
-
必须使用以下格式:
|
141
|
+
base_prompt += f"""
|
142
|
+
# 输出格式
|
143
|
+
{ot("COMMIT_MESSAGE")}
|
144
|
+
commit信息
|
145
|
+
{ct("COMMIT_MESSAGE")}
|
146
|
+
"""
|
128
147
|
|
129
|
-
|
130
|
-
|
131
|
-
|
148
|
+
# 获取模型并尝试上传文件
|
149
|
+
platform = PlatformRegistry().get_normal_platform()
|
150
|
+
upload_success = False
|
132
151
|
|
133
|
-
|
134
|
-
|
135
|
-
2. 范围表示变更的模块或组件 (例如: auth, database, ui)
|
136
|
-
3. 主题行不超过72个字符,不以句号结尾,使用祈使语气
|
137
|
-
4. 如有详细描述,使用空行分隔主题和详细描述
|
138
|
-
5. 详细描述部分应解释"是什么"和"为什么",而非"如何"
|
139
|
-
6. 仅输出提交信息,不要输出其他内容
|
140
|
-
'''
|
141
|
-
base_prompt += f"""
|
142
|
-
# 输出格式
|
143
|
-
{ot("COMMIT_MESSAGE")}
|
144
|
-
commit信息
|
145
|
-
{ct("COMMIT_MESSAGE")}
|
146
|
-
"""
|
152
|
+
# Check if content is too large
|
153
|
+
is_large_content = is_context_overflow(diff)
|
147
154
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
except Exception as e:
|
171
|
-
spinner.write(f"⚠️ 上传文件时出错: {str(e)}")
|
172
|
-
upload_success = False
|
173
|
-
# 根据上传状态准备完整的提示
|
155
|
+
if is_large_content:
|
156
|
+
if not platform.support_upload_files():
|
157
|
+
spinner.text = "差异文件太大,无法处理"
|
158
|
+
spinner.fail("❌")
|
159
|
+
return {
|
160
|
+
"success": False,
|
161
|
+
"stdout": "",
|
162
|
+
"stderr": "错误:差异文件太大,无法处理",
|
163
|
+
}
|
164
|
+
spinner.text = "正在上传代码差异文件..."
|
165
|
+
with spinner.hidden():
|
166
|
+
# 创建临时文件并写入差异内容
|
167
|
+
with tempfile.NamedTemporaryFile(
|
168
|
+
mode="w", suffix=".diff", delete=False
|
169
|
+
) as temp_diff_file:
|
170
|
+
temp_diff_file_path = temp_diff_file.name
|
171
|
+
temp_diff_file.write(diff)
|
172
|
+
temp_diff_file.flush()
|
173
|
+
spinner.write(f"✅ 差异内容已写入临时文件")
|
174
|
+
upload_success = platform.upload_files(
|
175
|
+
[temp_diff_file_path]
|
176
|
+
)
|
174
177
|
if upload_success:
|
175
|
-
|
176
|
-
spinner.text = "正在生成提交消息..."
|
177
|
-
# 使用上传的文件
|
178
|
-
prompt = base_prompt + f'''
|
179
|
-
# 变更概述
|
180
|
-
- 变更文件数量: {file_count} 个文件
|
181
|
-
- 已上传包含完整代码差异的文件
|
182
|
-
|
183
|
-
请详细分析已上传的代码差异文件,生成符合上述格式的提交信息。
|
184
|
-
'''
|
185
|
-
commit_message = platform.chat_until_success(prompt)
|
178
|
+
spinner.write("✅ 成功上传代码差异文件")
|
186
179
|
else:
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
# 如果成功提取,就跳出循环
|
206
|
-
if extracted_message:
|
207
|
-
commit_message = extracted_message
|
208
|
-
# 应用prefix和suffix
|
209
|
-
if prefix:
|
210
|
-
commit_message = f"{prefix} {commit_message}"
|
211
|
-
if suffix:
|
212
|
-
commit_message = f"{commit_message}\n{suffix}"
|
213
|
-
break
|
214
|
-
prompt = f"""格式错误,请按照以下格式重新生成提交信息:
|
215
|
-
{ot("COMMIT_MESSAGE")}
|
216
|
-
commit信息
|
217
|
-
{ct("COMMIT_MESSAGE")}
|
218
|
-
"""
|
219
|
-
commit_message = platform.chat_until_success(prompt)
|
220
|
-
spinner.write("✅ 生成提交消息")
|
180
|
+
spinner.text = "上传代码差异文件失败"
|
181
|
+
spinner.fail("❌")
|
182
|
+
return {
|
183
|
+
"success": False,
|
184
|
+
"stdout": "",
|
185
|
+
"stderr": "错误:上传代码差异文件失败",
|
186
|
+
}
|
187
|
+
# 根据上传状态准备完整的提示
|
188
|
+
if is_large_content:
|
189
|
+
# 尝试生成提交信息
|
190
|
+
spinner.text = "正在生成提交消息..."
|
191
|
+
# 使用上传的文件
|
192
|
+
prompt = (
|
193
|
+
base_prompt
|
194
|
+
+ f"""
|
195
|
+
# 变更概述
|
196
|
+
- 变更文件数量: {file_count} 个文件
|
197
|
+
- 已上传包含完整代码差异的文件
|
221
198
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
199
|
+
请详细分析已上传的代码差异文件,生成符合上述格式的提交信息。
|
200
|
+
"""
|
201
|
+
)
|
202
|
+
commit_message = platform.chat_until_success(prompt)
|
203
|
+
else:
|
204
|
+
prompt = (
|
205
|
+
base_prompt
|
206
|
+
+ f"""
|
207
|
+
# 分析材料
|
208
|
+
{diff}
|
209
|
+
"""
|
210
|
+
)
|
211
|
+
commit_message = platform.chat_until_success(prompt)
|
235
212
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
213
|
+
while True:
|
214
|
+
# 只在特定情况下重新获取commit_message
|
215
|
+
if (
|
216
|
+
not upload_success
|
217
|
+
and not is_large_content
|
218
|
+
and not commit_message
|
219
|
+
):
|
220
|
+
commit_message = platform.chat_until_success(prompt)
|
221
|
+
extracted_message = self._extract_commit_message(commit_message)
|
222
|
+
# 如果成功提取,就跳出循环
|
223
|
+
if extracted_message:
|
224
|
+
commit_message = extracted_message
|
225
|
+
# 应用prefix和suffix
|
226
|
+
if prefix:
|
227
|
+
commit_message = f"{prefix} {commit_message}"
|
228
|
+
if suffix:
|
229
|
+
commit_message = f"{commit_message}\n{suffix}"
|
230
|
+
break
|
231
|
+
prompt = f"""格式错误,请按照以下格式重新生成提交信息:
|
232
|
+
{ot("COMMIT_MESSAGE")}
|
233
|
+
commit信息
|
234
|
+
{ct("COMMIT_MESSAGE")}
|
235
|
+
"""
|
236
|
+
commit_message = platform.chat_until_success(prompt)
|
237
|
+
spinner.write("✅ 生成提交消息")
|
246
238
|
|
247
|
-
|
239
|
+
# 执行提交
|
240
|
+
spinner.text = "正在准备提交..."
|
241
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=True) as tmp_file:
|
242
|
+
tmp_file.write(commit_message)
|
243
|
+
tmp_file.flush()
|
244
|
+
spinner.text = "正在执行提交..."
|
245
|
+
commit_cmd = ["git", "commit", "-F", tmp_file.name]
|
246
|
+
subprocess.Popen(
|
247
|
+
commit_cmd,
|
248
|
+
stdout=subprocess.DEVNULL,
|
249
|
+
stderr=subprocess.DEVNULL,
|
250
|
+
).wait()
|
251
|
+
spinner.write("✅ 提交")
|
248
252
|
|
249
|
-
|
250
|
-
"
|
251
|
-
"
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
253
|
+
commit_hash = self._get_last_commit_hash()
|
254
|
+
spinner.text = "完成提交"
|
255
|
+
spinner.ok("✅")
|
256
|
+
finally:
|
257
|
+
# 清理临时差异文件
|
258
|
+
if temp_diff_file_path is not None and os.path.exists(
|
259
|
+
temp_diff_file_path
|
260
|
+
):
|
261
|
+
try:
|
262
|
+
os.unlink(temp_diff_file_path)
|
263
|
+
except Exception as e:
|
264
|
+
spinner.write(f"⚠️ 无法删除临时文件: {str(e)}")
|
260
265
|
|
266
|
+
PrettyOutput.print(
|
267
|
+
f"提交哈希: {commit_hash}\n提交消息: {commit_message}", OutputType.SUCCESS
|
268
|
+
)
|
269
|
+
|
270
|
+
return {
|
271
|
+
"success": True,
|
272
|
+
"stdout": yaml.safe_dump(
|
273
|
+
{"commit_hash": commit_hash, "commit_message": commit_message},
|
274
|
+
allow_unicode=True,
|
275
|
+
),
|
276
|
+
"stderr": "",
|
277
|
+
}
|
261
278
|
except Exception as e:
|
262
279
|
PrettyOutput.print(f"提交失败: {str(e)}", OutputType.ERROR)
|
263
280
|
return {
|
264
281
|
"success": False,
|
265
282
|
"stdout": "",
|
266
|
-
"stderr": f"Commit failed: {str(e)}"
|
283
|
+
"stderr": f"Commit failed: {str(e)}",
|
267
284
|
}
|
285
|
+
finally:
|
286
|
+
# Always restore original directory
|
287
|
+
os.chdir(original_dir)
|
288
|
+
|
268
289
|
|
269
290
|
def main():
|
270
291
|
init_env("欢迎使用 Jarvis-GitCommitTool,您的Git提交助手已准备就绪!")
|
271
|
-
parser = argparse.ArgumentParser(description=
|
272
|
-
parser.add_argument(
|
273
|
-
|
274
|
-
|
292
|
+
parser = argparse.ArgumentParser(description="Git commit tool")
|
293
|
+
parser.add_argument(
|
294
|
+
"--root-dir", type=str, default=".", help="Root directory of the Git repository"
|
295
|
+
)
|
296
|
+
parser.add_argument(
|
297
|
+
"--prefix",
|
298
|
+
type=str,
|
299
|
+
default="",
|
300
|
+
help="Prefix to prepend to commit message (separated by space)",
|
301
|
+
)
|
302
|
+
parser.add_argument(
|
303
|
+
"--suffix",
|
304
|
+
type=str,
|
305
|
+
default="",
|
306
|
+
help="Suffix to append to commit message (separated by newline)",
|
307
|
+
)
|
275
308
|
args = parser.parse_args()
|
276
309
|
tool = GitCommitTool()
|
277
|
-
tool.execute(
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
310
|
+
tool.execute(
|
311
|
+
{
|
312
|
+
"root_dir": args.root_dir,
|
313
|
+
"prefix": args.prefix if hasattr(args, "prefix") else "",
|
314
|
+
"suffix": args.suffix if hasattr(args, "suffix") else "",
|
315
|
+
}
|
316
|
+
)
|
317
|
+
|
282
318
|
|
283
319
|
if __name__ == "__main__":
|
284
|
-
sys.exit(main())
|
320
|
+
sys.exit(main())
|
jarvis/jarvis_platform/base.py
CHANGED
@@ -49,6 +49,10 @@ class BasePlatform(ABC):
|
|
49
49
|
def upload_files(self, file_list: List[str]) -> bool:
|
50
50
|
raise NotImplementedError("upload_files is not implemented")
|
51
51
|
|
52
|
+
@abstractmethod
|
53
|
+
def support_upload_files(self) -> bool:
|
54
|
+
"""Check if platform supports upload files"""
|
55
|
+
return False
|
52
56
|
|
53
57
|
|
54
58
|
def _chat(self, message: str):
|
@@ -56,9 +60,6 @@ class BasePlatform(ABC):
|
|
56
60
|
start_time = time.time()
|
57
61
|
|
58
62
|
input_token_count = get_context_token_count(message)
|
59
|
-
if is_context_overflow(message):
|
60
|
-
PrettyOutput.print("错误:输入内容超过最大限制", OutputType.WARNING)
|
61
|
-
return "错误:输入内容超过最大限制"
|
62
63
|
|
63
64
|
if input_token_count > get_max_input_token_count():
|
64
65
|
max_chunk_size = get_max_input_token_count() - 1024 # 留出一些余量
|
jarvis/jarvis_platform/kimi.py
CHANGED
@@ -90,6 +90,10 @@ class KimiModel(BasePlatform):
|
|
90
90
|
|
91
91
|
response = while_success(lambda: requests.post(url, headers=headers, data=payload), sleep_time=5)
|
92
92
|
return response.json()
|
93
|
+
|
94
|
+
def support_upload_files(self) -> bool:
|
95
|
+
"""Check if platform supports upload files"""
|
96
|
+
return True
|
93
97
|
|
94
98
|
def _upload_file(self, file_path: str, presigned_url: str) -> bool:
|
95
99
|
"""Upload file to presigned URL"""
|
jarvis/jarvis_platform/tongyi.py
CHANGED
@@ -67,6 +67,10 @@ class TongyiPlatform(BasePlatform):
|
|
67
67
|
def _generate_request_id(self):
|
68
68
|
self.request_id = str(uuid.uuid4()).replace("-", "")
|
69
69
|
|
70
|
+
def support_upload_files(self) -> bool:
|
71
|
+
"""Check if platform supports upload files"""
|
72
|
+
return True
|
73
|
+
|
70
74
|
def chat(self, message: str) -> Generator[str, None, None]:
|
71
75
|
if not self.request_id:
|
72
76
|
self._generate_request_id()
|
@@ -107,6 +107,10 @@ class YuanbaoPlatform(BasePlatform):
|
|
107
107
|
PrettyOutput.print(f"错误:创建会话失败:{e}", OutputType.ERROR)
|
108
108
|
return False
|
109
109
|
|
110
|
+
def support_upload_files(self) -> bool:
|
111
|
+
"""Check if platform supports upload files"""
|
112
|
+
return True
|
113
|
+
|
110
114
|
def upload_files(self, file_list: List[str]) -> bool:
|
111
115
|
"""上传文件到元宝平台
|
112
116
|
|
@@ -105,6 +105,10 @@ def chat_with_model(platform_name: str, model_name: str):
|
|
105
105
|
# Remove quotes if present
|
106
106
|
if (file_path.startswith('"') and file_path.endswith('"')) or (file_path.startswith("'") and file_path.endswith("'")):
|
107
107
|
file_path = file_path[1:-1]
|
108
|
+
|
109
|
+
if not platform.support_upload_files():
|
110
|
+
PrettyOutput.print("平台不支持上传文件", OutputType.ERROR)
|
111
|
+
continue
|
108
112
|
|
109
113
|
PrettyOutput.print(f"正在上传文件: {file_path}", OutputType.INFO)
|
110
114
|
if platform.upload_files([file_path]):
|
jarvis/jarvis_tools/edit_file.py
CHANGED
@@ -286,11 +286,11 @@ def slow_edit(filepath: str, patch_content: str, spinner: Yaspin) -> Tuple[bool,
|
|
286
286
|
model = PlatformRegistry().get_normal_platform()
|
287
287
|
try:
|
288
288
|
file_content = FileOperationTool().execute({"operation":"read", "files":[{"path":filepath}]})["stdout"]
|
289
|
-
|
289
|
+
is_large_context = is_context_overflow(file_content)
|
290
290
|
upload_success = False
|
291
291
|
# 读取原始文件内容
|
292
292
|
with spinner.hidden():
|
293
|
-
if
|
293
|
+
if is_large_context and model.support_upload_files() and model.upload_files([filepath]):
|
294
294
|
upload_success = True
|
295
295
|
|
296
296
|
|
@@ -340,19 +340,21 @@ def slow_edit(filepath: str, patch_content: str, spinner: Yaspin) -> Tuple[bool,
|
|
340
340
|
"""
|
341
341
|
|
342
342
|
for _ in range(3):
|
343
|
-
|
344
|
-
|
343
|
+
if is_large_context:
|
344
|
+
if upload_success:
|
345
|
+
response = model.chat_until_success(main_prompt)
|
346
|
+
else:
|
347
|
+
file_prompt = f"""
|
348
|
+
# 原始代码
|
349
|
+
{file_content}
|
350
|
+
"""
|
351
|
+
response = model.chat_until_success(main_prompt + file_prompt)
|
352
|
+
else:
|
345
353
|
file_prompt = f"""
|
346
354
|
# 原始代码
|
347
355
|
{file_content}
|
348
356
|
"""
|
349
|
-
|
350
357
|
response = model.chat_until_success(main_prompt + file_prompt)
|
351
|
-
else:
|
352
|
-
if upload_success:
|
353
|
-
response = model.chat_until_success(main_prompt)
|
354
|
-
else:
|
355
|
-
return False, "文件上传失败"
|
356
358
|
|
357
359
|
# 解析差异化补丁
|
358
360
|
diff_blocks = re.finditer(ot("DIFF")+r'\s*>{4,} SEARCH\n?(.*?)\n?={4,}\n?(.*?)\s*<{4,} REPLACE\n?'+ct("DIFF"),
|
@@ -30,6 +30,10 @@ class FileAnalyzerTool:
|
|
30
30
|
"required": ["file_paths", "prompt"]
|
31
31
|
}
|
32
32
|
|
33
|
+
@staticmethod
|
34
|
+
def check() -> bool:
|
35
|
+
return PlatformRegistry().get_thinking_platform().support_upload_files()
|
36
|
+
|
33
37
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
34
38
|
"""执行文件分析操作
|
35
39
|
|
@@ -62,8 +66,7 @@ class FileAnalyzerTool:
|
|
62
66
|
}
|
63
67
|
|
64
68
|
# 创建thinking平台实例
|
65
|
-
|
66
|
-
platform = platform_registry.get_thinking_platform()
|
69
|
+
platform = PlatformRegistry().get_thinking_platform()
|
67
70
|
|
68
71
|
if not platform:
|
69
72
|
return {
|
jarvis/jarvis_tools/registry.py
CHANGED
@@ -7,6 +7,7 @@ import tempfile
|
|
7
7
|
from pathlib import Path
|
8
8
|
from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple
|
9
9
|
|
10
|
+
from numpy import place
|
10
11
|
import yaml
|
11
12
|
|
12
13
|
from jarvis.jarvis_mcp import McpClient
|
@@ -18,7 +19,7 @@ from jarvis.jarvis_tools.base import Tool
|
|
18
19
|
from jarvis.jarvis_utils.config import get_data_dir
|
19
20
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
20
21
|
from jarvis.jarvis_utils.tag import ct, ot
|
21
|
-
from jarvis.jarvis_utils.utils import
|
22
|
+
from jarvis.jarvis_utils.utils import is_context_overflow
|
22
23
|
|
23
24
|
tool_call_help = f"""
|
24
25
|
<tool_system_guide>
|
@@ -648,6 +649,9 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
648
649
|
want = tool_call["want"]
|
649
650
|
args["agent"] = agent
|
650
651
|
|
652
|
+
from jarvis.jarvis_agent import Agent
|
653
|
+
agent_instance: Agent = agent
|
654
|
+
|
651
655
|
if isinstance(args, str):
|
652
656
|
try:
|
653
657
|
args = json.loads(args)
|
@@ -676,23 +680,25 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
676
680
|
tmp_file.flush()
|
677
681
|
|
678
682
|
try:
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
# 尝试上传文件
|
684
|
-
upload_success = platform.upload_files([output_file])
|
685
|
-
|
683
|
+
if agent_instance.model and agent_instance.model.support_upload_files():
|
684
|
+
summary = agent_instance.generate_summary()
|
685
|
+
agent_instance.clear_history()
|
686
|
+
upload_success = agent_instance.model.upload_files([output_file])
|
686
687
|
if upload_success:
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
{
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
688
|
+
prompt = f"""
|
689
|
+
以下是之前对话的关键信息总结:
|
690
|
+
|
691
|
+
<content>
|
692
|
+
{summary}
|
693
|
+
</content>
|
694
|
+
|
695
|
+
上传的文件是以下工具执行结果:
|
696
|
+
{yaml.safe_dump({"name":name, "arguments":args, "want":want})}
|
697
|
+
|
698
|
+
请根据以上信息,继续完成任务。
|
699
|
+
"""
|
700
|
+
return prompt
|
701
|
+
# 使用上传的文件生成摘要
|
696
702
|
return self._truncate_output(output)
|
697
703
|
finally:
|
698
704
|
# 清理临时文件
|
jarvis/jarvis_utils/config.py
CHANGED
@@ -203,7 +203,7 @@ def get_max_big_content_size() -> int:
|
|
203
203
|
返回:
|
204
204
|
int: 最大大内容大小
|
205
205
|
"""
|
206
|
-
return int(GLOBAL_CONFIG_DATA.get('JARVIS_MAX_BIG_CONTENT_SIZE', '
|
206
|
+
return int(GLOBAL_CONFIG_DATA.get('JARVIS_MAX_BIG_CONTENT_SIZE', '160000'))
|
207
207
|
|
208
208
|
def get_pretty_output() -> bool:
|
209
209
|
"""
|
@@ -119,9 +119,8 @@ def upload_methodology(platform: BasePlatform) -> bool:
|
|
119
119
|
return False
|
120
120
|
|
121
121
|
try:
|
122
|
-
|
123
|
-
|
124
|
-
return False
|
122
|
+
return platform.upload_files([temp_file_path])
|
123
|
+
|
125
124
|
finally:
|
126
125
|
if temp_file_path and os.path.exists(temp_file_path):
|
127
126
|
try:
|
@@ -214,12 +213,11 @@ def load_methodology(user_input: str, tool_registery: Optional[Any] = None) -> s
|
|
214
213
|
spinner.ok("✅")
|
215
214
|
|
216
215
|
# 尝试上传文件
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
return platform.chat_until_success(base_prompt + f"""
|
216
|
+
upload_success = platform.upload_files([temp_file_path])
|
217
|
+
|
218
|
+
if upload_success:
|
219
|
+
# 使用上传的文件生成摘要
|
220
|
+
return platform.chat_until_success(base_prompt + f"""
|
223
221
|
请根据已上传的方法论和可调用的工具文件内容,规划/总结出以下用户需求的执行步骤: {user_input}
|
224
222
|
|
225
223
|
请按以下格式回复:
|
@@ -234,8 +232,8 @@ def load_methodology(user_input: str, tool_registery: Optional[Any] = None) -> s
|
|
234
232
|
如果没有匹配的方法论,请输出:没有历史方法论可参考
|
235
233
|
除以上要求外,不要输出任何内容
|
236
234
|
""")
|
237
|
-
|
238
|
-
|
235
|
+
else:
|
236
|
+
return "没有历史方法论可参考"
|
239
237
|
# 如果内容不大或上传失败,直接使用chat_until_success
|
240
238
|
return platform.chat_until_success(full_content)
|
241
239
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: jarvis-ai-assistant
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.189
|
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
|
@@ -238,7 +238,7 @@ OPENAI_API_BASE: https://api.openai.com/v1 # 可选,默认为官方API地址
|
|
238
238
|
| `JARVIS_CONFIRM_BEFORE_APPLY_PATCH` | true | 应用补丁前是否需要确认 |
|
239
239
|
| `JARVIS_MAX_TOOL_CALL_COUNT` | 20 | 最大连续工具调用次数,如果是0表示无限制 |
|
240
240
|
| `JARVIS_AUTO_UPDATE` | true | 是否自动更新Jarvis(仅在以git仓库方式安装时有效) |
|
241
|
-
| `JARVIS_MAX_BIG_CONTENT_SIZE` |
|
241
|
+
| `JARVIS_MAX_BIG_CONTENT_SIZE` | 160000 | 最大大内容大小 |
|
242
242
|
| `JARVIS_PRETTY_OUTPUT` | false | 是否启用PrettyOutput |
|
243
243
|
| `JARVIS_GIT_COMMIT_PROMPT` | "" | 自定义git提交信息生成提示模板 |
|
244
244
|
| `JARVIS_PRINT_PROMPT` | false | 是否打印提示 |
|
@@ -1,5 +1,5 @@
|
|
1
|
-
jarvis/__init__.py,sha256=
|
2
|
-
jarvis/jarvis_agent/__init__.py,sha256=
|
1
|
+
jarvis/__init__.py,sha256=3RRAnaRmOaQpveMGk6AbLpN-Ndluqiwh0tdrx6SLMdg,74
|
2
|
+
jarvis/jarvis_agent/__init__.py,sha256=utqI92rkiqiVR2zk5N-IQe2CeMSl-sNiLU429dLoGVw,30487
|
3
3
|
jarvis/jarvis_agent/builtin_input_handler.py,sha256=f4DaEHPakXcAbgykFP-tiOQP6fh_yGFlZx_h91_j2tQ,1529
|
4
4
|
jarvis/jarvis_agent/file_input_handler.py,sha256=OfoYI5on6w5BDUUg4OadFcfWzMsUF70GNrlt9QyauvA,4181
|
5
5
|
jarvis/jarvis_agent/jarvis.py,sha256=gOZfTwVlG-GZxPjgCoSiIcFsl4RwwfPA0CGUjE5J7oU,6249
|
@@ -9,7 +9,7 @@ jarvis/jarvis_agent/shell_input_handler.py,sha256=pi3AtPKrkKc6K9e99S1djKXQ_XrxtP
|
|
9
9
|
jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
10
|
jarvis/jarvis_code_agent/code_agent.py,sha256=2TG_Hi_2mbiZHUcWnxYs4C30eYpgSedtIYZLs7BbyUk,15827
|
11
11
|
jarvis/jarvis_code_agent/lint.py,sha256=TZlhNbeaoLzO9DzExjN5GAjrt66owd8lyQV56LTfkrs,4370
|
12
|
-
jarvis/jarvis_code_analysis/code_review.py,sha256=
|
12
|
+
jarvis/jarvis_code_analysis/code_review.py,sha256=45MPcXullg55w6E0Xhm2dDj6TGmkUxNNI2LJWexnTKQ,30123
|
13
13
|
jarvis/jarvis_code_analysis/checklists/__init__.py,sha256=cKQ_FOGy5TQgM-YkRCqORo-mUOZaPAJ9VDmZoFX58us,78
|
14
14
|
jarvis/jarvis_code_analysis/checklists/c_cpp.py,sha256=SXPpYCNeCtU1PpKdKPiYDuOybfY9vaL0ejDn4imxDwA,1317
|
15
15
|
jarvis/jarvis_code_analysis/checklists/csharp.py,sha256=vS-cu6RCGg5SyK9MJ3RE381gt3xYl-yea3Bj2UQEcwQ,2420
|
@@ -30,15 +30,15 @@ jarvis/jarvis_code_analysis/checklists/shell.py,sha256=IXQkWHwA-4GUQz3WUs7l6hEy7
|
|
30
30
|
jarvis/jarvis_code_analysis/checklists/sql.py,sha256=ecKKT6wJAibn8R0NxGZDNlm4teYXvF3CAJvVk8mmX7w,2355
|
31
31
|
jarvis/jarvis_code_analysis/checklists/swift.py,sha256=YcsYFxAitHqOtBZjG-RV9-KNM7X5lIcl6zlEI9XfmfM,2566
|
32
32
|
jarvis/jarvis_code_analysis/checklists/web.py,sha256=-Pnj1FQTsGVZUQK7-4ptDsGd7a22Cs0585jRAPT2SdQ,3943
|
33
|
-
jarvis/jarvis_data/config_schema.json,sha256=
|
33
|
+
jarvis/jarvis_data/config_schema.json,sha256=u_I8KawgwUltW-tVw3t37rLv4TqdBynZaNGhOFH2Zf8,6397
|
34
34
|
jarvis/jarvis_data/huggingface.tar.gz,sha256=dWKnc_tvyx-I_ZkXo91O0b38KxDmLW1ZbmJ3E6fCl_k,1120205
|
35
|
-
jarvis/jarvis_dev/main.py,sha256=
|
35
|
+
jarvis/jarvis_dev/main.py,sha256=MG2DhDwXsOgCya558o7TJRMZlN3Diprk7UjEEVNdm6A,40630
|
36
36
|
jarvis/jarvis_event/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
37
|
jarvis/jarvis_git_details/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
-
jarvis/jarvis_git_details/main.py,sha256=
|
38
|
+
jarvis/jarvis_git_details/main.py,sha256=4L60eVDBMv6RbocnVlzfOx7JZkHTzop3q7qui9d9LuU,9005
|
39
39
|
jarvis/jarvis_git_squash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
40
|
jarvis/jarvis_git_squash/main.py,sha256=q8-r0TtVOaCqY_uYwnWAY76k8YCDd5se_feB6ZWKo9M,2278
|
41
|
-
jarvis/jarvis_git_utils/git_commiter.py,sha256=
|
41
|
+
jarvis/jarvis_git_utils/git_commiter.py,sha256=BpJ8py2JMnp8jcukyM3vxGNWtjOLTIvgqYOx-5OhvZo,13037
|
42
42
|
jarvis/jarvis_mcp/__init__.py,sha256=NF_vqRxaNyz8ColcpRh0bOkinV90YLAKHEN--jkP-B8,2114
|
43
43
|
jarvis/jarvis_mcp/sse_mcp_client.py,sha256=QNA7HqFvLbvhNaFp3ZsXzs2Rm6_gHUMcpd4t4qAzymY,23485
|
44
44
|
jarvis/jarvis_mcp/stdio_mcp_client.py,sha256=IEkas4ojP5J0TdVaUglvlEp61RyezBtuejv4lN3n1I4,11831
|
@@ -47,15 +47,15 @@ jarvis/jarvis_methodology/main.py,sha256=HhEArlKI5PCpGnBCwVrXMuDn2z84LgpgK7-aGSQ
|
|
47
47
|
jarvis/jarvis_multi_agent/__init__.py,sha256=Xab5sFltJmX_9MoXqanmZs6FqKfUb2v_pG29Vk8ZXaw,4311
|
48
48
|
jarvis/jarvis_multi_agent/main.py,sha256=KeGv8sdpSgTjW6VE4-tQ8BWDC_a0aE_4R3OqzPBd5N4,1646
|
49
49
|
jarvis/jarvis_platform/__init__.py,sha256=0YnsUoM4JkIBOtImFdjfuDbrqQZT3dEaAwSJ62DrpCc,104
|
50
|
-
jarvis/jarvis_platform/base.py,sha256=
|
50
|
+
jarvis/jarvis_platform/base.py,sha256=C_50l5kc2P1OP8NH4JbaMZdY-aWOfhfuECoUlRCriU8,7029
|
51
51
|
jarvis/jarvis_platform/human.py,sha256=xwaTZ1zdrAYZZFXxkbHvUdECwCGsic0kgAFUncUr45g,2567
|
52
|
-
jarvis/jarvis_platform/kimi.py,sha256=
|
52
|
+
jarvis/jarvis_platform/kimi.py,sha256=5-LUcvBoL_1Y8HZom9pkNFHO7ghstNCPEobVrVESOi4,12101
|
53
53
|
jarvis/jarvis_platform/openai.py,sha256=VyX3bR1rGxrJdWOtUBf8PgSL9n06KaNbOewL1urzOnk,4741
|
54
54
|
jarvis/jarvis_platform/registry.py,sha256=3djxE8AB4gwrdAOvRSL0612Rt_CcsaZhzZ0_oXHu6xk,7820
|
55
|
-
jarvis/jarvis_platform/tongyi.py,sha256=
|
56
|
-
jarvis/jarvis_platform/yuanbao.py,sha256=
|
55
|
+
jarvis/jarvis_platform/tongyi.py,sha256=1cecb2GofJ_7J3xEj_fBj4Ns7XuGIn5CpCi_DFmiP4s,21063
|
56
|
+
jarvis/jarvis_platform/yuanbao.py,sha256=yOj5T3lo45ULrFkwHXdAsiLhfv141V0sPQplHGeLKNg,20751
|
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=7XfiP19Gv88sFkS__v83a-JTI-VUuyH3lWLr4_jTq1w,25863
|
59
59
|
jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
60
60
|
jarvis/jarvis_smart_shell/main.py,sha256=k59o5UD7merbsPhJQzae95ThTmZY2EcNHB3Ov6kb0PA,5291
|
61
61
|
jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -65,15 +65,15 @@ jarvis/jarvis_tools/chdir.py,sha256=DNKVFrWqu6t_sZ2ipv99s6802QR4cSGlqKlmaI--arE,
|
|
65
65
|
jarvis/jarvis_tools/code_plan.py,sha256=gWR0lzY62x2PxWKoMRBqW6jq7zQuO8vhpjC4TcHSYjk,7685
|
66
66
|
jarvis/jarvis_tools/create_code_agent.py,sha256=-nHfo5O5pDIG5IX3w1ClQafGvGcdI2_w75-KGrD-gUQ,3458
|
67
67
|
jarvis/jarvis_tools/create_sub_agent.py,sha256=lyFrrg4V0yXULmU3vldwGp_euZjwZzJcRU6mJ20zejY,3023
|
68
|
-
jarvis/jarvis_tools/edit_file.py,sha256=
|
68
|
+
jarvis/jarvis_tools/edit_file.py,sha256=s8HqG8qHDrYjCwIioeBpGvw7Aw-iEEZoUyRJFqdjcQA,18453
|
69
69
|
jarvis/jarvis_tools/execute_script.py,sha256=IA1SkcnwBB9PKG2voBNx5N9GXL303OC7OOtdqRfqWOk,6428
|
70
|
-
jarvis/jarvis_tools/file_analyzer.py,sha256=
|
70
|
+
jarvis/jarvis_tools/file_analyzer.py,sha256=UuQmti-eBocJB6ivMINmOvSuXxBxOqmbQ3RsQlyueWs,4918
|
71
71
|
jarvis/jarvis_tools/file_operation.py,sha256=WloC1-oPJLwgICu4WBc9f7XA8N_Ggl73QQ5CxM2XTlE,9464
|
72
72
|
jarvis/jarvis_tools/generate_new_tool.py,sha256=dLfOliIUm0ovLrHcZAhKm7lqhxwACv8mnGxxGtLJ--o,5960
|
73
73
|
jarvis/jarvis_tools/methodology.py,sha256=m7cQmVhhQpUUl_uYTVvcW0JBovQLx5pWTXh_8K77HsU,5237
|
74
74
|
jarvis/jarvis_tools/read_code.py,sha256=pL2SwZDsJbJMXo4stW96quFsLgbtPVIAW-h4sDKsLtM,6274
|
75
75
|
jarvis/jarvis_tools/read_webpage.py,sha256=PFAYuKjay9j6phWzyuZ99ZfNaHJljmRWAgS0bsvbcvE,2219
|
76
|
-
jarvis/jarvis_tools/registry.py,sha256=
|
76
|
+
jarvis/jarvis_tools/registry.py,sha256=kSl41tvwdiHaE3nwR9BI94GibjsKWczogZ76y0nFycw,25058
|
77
77
|
jarvis/jarvis_tools/rewrite_file.py,sha256=3V2l7kG5DG9iRimBce-1qCRuJPL0QM32SBTzOl2zCqM,7004
|
78
78
|
jarvis/jarvis_tools/search_web.py,sha256=rzxrCOTEo-MmLQrKI4k-AbfidUfJUeCPK4f5ZJy48G8,952
|
79
79
|
jarvis/jarvis_tools/virtual_tty.py,sha256=8E_n-eC-RRPTqYx6BI5Q2RnorY8dbhKFBfAjIiRQROA,16397
|
@@ -81,19 +81,19 @@ jarvis/jarvis_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
81
81
|
jarvis/jarvis_tools/cli/main.py,sha256=3UuU9tk5cQAS0rfNPXgdtnAd5uDB7v0Exo0_I9sJHRE,6355
|
82
82
|
jarvis/jarvis_utils/__init__.py,sha256=x5lbQRH1uOulmWr1IEqNMLXNmDHbqQQot7d1uhKFg4M,851
|
83
83
|
jarvis/jarvis_utils/builtin_replace_map.py,sha256=n4gBUwAJDABUhQu9qIiIHWNfPk_T7chfNk5ygCiOPtE,2931
|
84
|
-
jarvis/jarvis_utils/config.py,sha256=
|
84
|
+
jarvis/jarvis_utils/config.py,sha256=Z7pZsSYXJkc2RzUhJ-_VvQA3xOLo6LEo4nEE1ftyQY8,7104
|
85
85
|
jarvis/jarvis_utils/embedding.py,sha256=J8YAqIEj16TJIPEG24uvUlPHeN-5zq0JW_hbNLizQug,3832
|
86
86
|
jarvis/jarvis_utils/file_processors.py,sha256=G5kQI7vCGIDnjgAB5J1dYIR102u6WUv3IhcWFfDh_gs,2977
|
87
87
|
jarvis/jarvis_utils/git_utils.py,sha256=k0rrMAbKwnD7hztmtegxtFFiCzyID4p2oHKTycE2Q-4,15070
|
88
88
|
jarvis/jarvis_utils/globals.py,sha256=6JWtB1XoD-wEFiMzZNA790ixlZ_OsJEYUM_B8EwkOE8,2277
|
89
89
|
jarvis/jarvis_utils/input.py,sha256=FkLW7MXL8awQUghFLQnW1r5F1wV8K3EZeVPwHFRHJTo,7458
|
90
|
-
jarvis/jarvis_utils/methodology.py,sha256=
|
90
|
+
jarvis/jarvis_utils/methodology.py,sha256=6vf__ahwJZ2I62mWGAvh2C-G6pq930Dh_EkrY1VpduQ,8485
|
91
91
|
jarvis/jarvis_utils/output.py,sha256=QboL42GtG_dnvd1O64sl8o72mEBhXNRADPXQMXgDE7Q,9661
|
92
92
|
jarvis/jarvis_utils/tag.py,sha256=YJHmuedLb7_AiqvKQetHr4R1FxyzIh7HN0RRkWMmYbU,429
|
93
93
|
jarvis/jarvis_utils/utils.py,sha256=dTFIN6EV48BuC4VOyvcVcj4P0tsWysc9ennbMRhLJjk,10960
|
94
|
-
jarvis_ai_assistant-0.1.
|
95
|
-
jarvis_ai_assistant-0.1.
|
96
|
-
jarvis_ai_assistant-0.1.
|
97
|
-
jarvis_ai_assistant-0.1.
|
98
|
-
jarvis_ai_assistant-0.1.
|
99
|
-
jarvis_ai_assistant-0.1.
|
94
|
+
jarvis_ai_assistant-0.1.189.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
|
95
|
+
jarvis_ai_assistant-0.1.189.dist-info/METADATA,sha256=5e88_48MijaBca9j4CP0kRRaAwtt6H6WSJOf0BsrYtQ,15922
|
96
|
+
jarvis_ai_assistant-0.1.189.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
97
|
+
jarvis_ai_assistant-0.1.189.dist-info/entry_points.txt,sha256=Gy3DOP1PYLMK0GCj4rrP_9lkOyBQ39EK_lKGUSwn41E,869
|
98
|
+
jarvis_ai_assistant-0.1.189.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
99
|
+
jarvis_ai_assistant-0.1.189.dist-info/RECORD,,
|
File without changes
|
{jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/entry_points.txt
RENAMED
File without changes
|
{jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{jarvis_ai_assistant-0.1.188.dist-info → jarvis_ai_assistant-0.1.189.dist-info}/top_level.txt
RENAMED
File without changes
|