jarvis-ai-assistant 0.2.3__py3-none-any.whl → 0.2.5__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 +13 -7
- jarvis/jarvis_agent/edit_file_handler.py +4 -0
- jarvis/jarvis_agent/jarvis.py +22 -25
- jarvis/jarvis_agent/main.py +6 -6
- jarvis/jarvis_code_agent/code_agent.py +273 -11
- jarvis/jarvis_code_analysis/code_review.py +21 -19
- jarvis/jarvis_data/config_schema.json +25 -29
- jarvis/jarvis_git_squash/main.py +3 -3
- jarvis/jarvis_git_utils/git_commiter.py +32 -11
- jarvis/jarvis_mcp/sse_mcp_client.py +4 -6
- jarvis/jarvis_mcp/streamable_mcp_client.py +5 -9
- jarvis/jarvis_rag/retriever.py +1 -1
- jarvis/jarvis_smart_shell/main.py +2 -2
- jarvis/jarvis_stats/__init__.py +13 -0
- jarvis/jarvis_stats/cli.py +404 -0
- jarvis/jarvis_stats/stats.py +538 -0
- jarvis/jarvis_stats/storage.py +381 -0
- jarvis/jarvis_stats/visualizer.py +282 -0
- jarvis/jarvis_tools/cli/main.py +82 -15
- jarvis/jarvis_tools/registry.py +32 -16
- jarvis/jarvis_tools/search_web.py +3 -3
- jarvis/jarvis_tools/virtual_tty.py +315 -26
- jarvis/jarvis_utils/config.py +12 -8
- jarvis/jarvis_utils/git_utils.py +8 -16
- jarvis/jarvis_utils/methodology.py +74 -67
- jarvis/jarvis_utils/utils.py +468 -72
- {jarvis_ai_assistant-0.2.3.dist-info → jarvis_ai_assistant-0.2.5.dist-info}/METADATA +29 -3
- {jarvis_ai_assistant-0.2.3.dist-info → jarvis_ai_assistant-0.2.5.dist-info}/RECORD +33 -28
- {jarvis_ai_assistant-0.2.3.dist-info → jarvis_ai_assistant-0.2.5.dist-info}/entry_points.txt +2 -0
- {jarvis_ai_assistant-0.2.3.dist-info → jarvis_ai_assistant-0.2.5.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.2.3.dist-info → jarvis_ai_assistant-0.2.5.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.2.3.dist-info → jarvis_ai_assistant-0.2.5.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/config.py
CHANGED
@@ -81,10 +81,10 @@ def get_max_token_count(model_group_override: Optional[str] = None) -> int:
|
|
81
81
|
获取模型允许的最大token数量。
|
82
82
|
|
83
83
|
返回:
|
84
|
-
int: 模型能处理的最大token
|
84
|
+
int: 模型能处理的最大token数量,为最大输入token数量的100倍。
|
85
85
|
"""
|
86
|
-
|
87
|
-
return
|
86
|
+
max_input_tokens = get_max_input_token_count(model_group_override)
|
87
|
+
return max_input_tokens * 100
|
88
88
|
|
89
89
|
|
90
90
|
def get_max_input_token_count(model_group_override: Optional[str] = None) -> int:
|
@@ -151,9 +151,7 @@ def _get_resolved_model_config(
|
|
151
151
|
"JARVIS_MODEL",
|
152
152
|
"JARVIS_THINKING_PLATFORM",
|
153
153
|
"JARVIS_THINKING_MODEL",
|
154
|
-
"JARVIS_MAX_TOKEN_COUNT",
|
155
154
|
"JARVIS_MAX_INPUT_TOKEN_COUNT",
|
156
|
-
"JARVIS_MAX_BIG_CONTENT_SIZE",
|
157
155
|
]:
|
158
156
|
if key in GLOBAL_CONFIG_DATA:
|
159
157
|
resolved_config[key] = GLOBAL_CONFIG_DATA[key]
|
@@ -249,10 +247,10 @@ def get_max_big_content_size(model_group_override: Optional[str] = None) -> int:
|
|
249
247
|
获取最大大内容大小。
|
250
248
|
|
251
249
|
返回:
|
252
|
-
int:
|
250
|
+
int: 最大大内容大小,为最大输入token数量的5倍
|
253
251
|
"""
|
254
|
-
|
255
|
-
return
|
252
|
+
max_input_tokens = get_max_input_token_count(model_group_override)
|
253
|
+
return max_input_tokens * 5
|
256
254
|
|
257
255
|
|
258
256
|
def get_pretty_output() -> bool:
|
@@ -262,6 +260,12 @@ def get_pretty_output() -> bool:
|
|
262
260
|
返回:
|
263
261
|
bool: 如果启用PrettyOutput则返回True,默认为True
|
264
262
|
"""
|
263
|
+
import platform
|
264
|
+
|
265
|
+
# Windows系统强制设置为False
|
266
|
+
if platform.system() == "Windows":
|
267
|
+
return False
|
268
|
+
|
265
269
|
return GLOBAL_CONFIG_DATA.get("JARVIS_PRETTY_OUTPUT", False) == True
|
266
270
|
|
267
271
|
|
jarvis/jarvis_utils/git_utils.py
CHANGED
@@ -214,9 +214,7 @@ def handle_commit_workflow() -> bool:
|
|
214
214
|
Returns:
|
215
215
|
bool: 提交是否成功
|
216
216
|
"""
|
217
|
-
if is_confirm_before_apply_patch() and not user_confirm(
|
218
|
-
"是否要提交代码?", default=True
|
219
|
-
):
|
217
|
+
if is_confirm_before_apply_patch() and not user_confirm("是否要提交代码?", default=True):
|
220
218
|
revert_change()
|
221
219
|
return False
|
222
220
|
|
@@ -429,9 +427,7 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
429
427
|
if not in_venv and (
|
430
428
|
"Permission denied" in error_msg or "not writeable" in error_msg
|
431
429
|
):
|
432
|
-
if user_confirm(
|
433
|
-
"检测到权限问题,是否尝试用户级安装(--user)?", True
|
434
|
-
):
|
430
|
+
if user_confirm("检测到权限问题,是否尝试用户级安装(--user)?", True):
|
435
431
|
user_result = subprocess.run(
|
436
432
|
install_cmd + ["--user"],
|
437
433
|
cwd=git_root,
|
@@ -446,9 +442,7 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
446
442
|
PrettyOutput.print(f"代码安装失败: {error_msg}", OutputType.ERROR)
|
447
443
|
return False
|
448
444
|
except Exception as e:
|
449
|
-
PrettyOutput.print(
|
450
|
-
f"安装过程中发生意外错误: {str(e)}", OutputType.ERROR
|
451
|
-
)
|
445
|
+
PrettyOutput.print(f"安装过程中发生意外错误: {str(e)}", OutputType.ERROR)
|
452
446
|
return False
|
453
447
|
# 更新检查日期文件
|
454
448
|
with open(last_check_file, "w") as f:
|
@@ -482,9 +476,7 @@ def get_diff_file_list() -> List[str]:
|
|
482
476
|
subprocess.run(["git", "reset"], check=True)
|
483
477
|
|
484
478
|
if result.returncode != 0:
|
485
|
-
PrettyOutput.print(
|
486
|
-
f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR
|
487
|
-
)
|
479
|
+
PrettyOutput.print(f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR)
|
488
480
|
return []
|
489
481
|
|
490
482
|
return [f for f in result.stdout.splitlines() if f]
|
@@ -533,8 +525,10 @@ def get_recent_commits_with_files() -> List[Dict[str, Any]]:
|
|
533
525
|
],
|
534
526
|
capture_output=True,
|
535
527
|
text=True,
|
528
|
+
encoding="utf-8",
|
529
|
+
errors="replace",
|
536
530
|
)
|
537
|
-
if result.returncode != 0:
|
531
|
+
if result.returncode != 0 or result.stdout is None:
|
538
532
|
return []
|
539
533
|
|
540
534
|
# 解析提交信息
|
@@ -632,9 +626,7 @@ def confirm_add_new_files() -> None:
|
|
632
626
|
need_confirm = True
|
633
627
|
|
634
628
|
if binary_files:
|
635
|
-
output_lines.append(
|
636
|
-
f"检测到{len(binary_files)}个二进制文件(选择N将重新检测)"
|
637
|
-
)
|
629
|
+
output_lines.append(f"检测到{len(binary_files)}个二进制文件(选择N将重新检测)")
|
638
630
|
output_lines.append("二进制文件列表:")
|
639
631
|
output_lines.extend(f" - {file}" for file in binary_files)
|
640
632
|
need_confirm = True
|
@@ -149,6 +149,7 @@ def load_methodology(user_input: str, tool_registery: Optional[Any] = None) -> s
|
|
149
149
|
|
150
150
|
参数:
|
151
151
|
user_input: 用户输入文本,用于提示大模型
|
152
|
+
tool_registery: 工具注册表,用于获取工具列表
|
152
153
|
|
153
154
|
返回:
|
154
155
|
str: 相关的方法论提示,如果未找到方法论则返回空字符串
|
@@ -170,70 +171,87 @@ def load_methodology(user_input: str, tool_registery: Optional[Any] = None) -> s
|
|
170
171
|
return ""
|
171
172
|
print(f"✅ 加载方法论文件完成 (共 {len(methodologies)} 个)")
|
172
173
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
else:
|
179
|
-
platform = PlatformRegistry().get_normal_platform()
|
180
|
-
model_group = None
|
181
|
-
platform.set_suppress_output(False)
|
182
|
-
if not platform:
|
183
|
-
return ""
|
174
|
+
platform = PlatformRegistry().get_normal_platform()
|
175
|
+
platform.set_suppress_output(True)
|
176
|
+
|
177
|
+
# 步骤1:获取所有方法论的标题
|
178
|
+
methodology_titles = list(methodologies.keys())
|
184
179
|
|
185
|
-
#
|
186
|
-
|
180
|
+
# 步骤2:让大模型选择相关性高的方法论
|
181
|
+
selection_prompt = f"""以下是所有可用的方法论标题:
|
187
182
|
|
188
183
|
"""
|
189
|
-
|
190
|
-
|
191
|
-
for problem_type, content in methodologies.items():
|
192
|
-
full_content += f"## {problem_type}\n\n{content}\n\n---\n\n"
|
184
|
+
for i, title in enumerate(methodology_titles, 1):
|
185
|
+
selection_prompt += f"{i}. {title}\n"
|
193
186
|
|
194
|
-
|
195
|
-
|
187
|
+
selection_prompt += f"""
|
188
|
+
以下是可用的工具列表:
|
189
|
+
{prompt}
|
196
190
|
|
197
|
-
|
198
|
-
full_content += f"""
|
199
|
-
请根据以上方法论和可调用的工具内容,规划/总结出以下用户需求的执行步骤: {user_input}
|
191
|
+
用户需求:{user_input}
|
200
192
|
|
201
|
-
|
202
|
-
### 与该任务/需求相关的方法论
|
203
|
-
1. [方法论名字]
|
204
|
-
2. [方法论名字]
|
205
|
-
### 根据以上方法论,规划/总结出执行步骤
|
206
|
-
1. [步骤1]
|
207
|
-
2. [步骤2]
|
208
|
-
3. [步骤3]
|
193
|
+
请分析用户需求,从上述方法论中选择出与需求相关性较高的方法论(可以选择多个)。
|
209
194
|
|
210
|
-
|
211
|
-
|
195
|
+
请严格按照以下格式返回序号:
|
196
|
+
<NUM>序号1,序号2,序号3</NUM>
|
197
|
+
|
198
|
+
例如:<NUM>1,3,5</NUM>
|
199
|
+
|
200
|
+
如果没有相关的方法论,请返回:<NUM>none</NUM>
|
201
|
+
|
202
|
+
注意:只返回<NUM>标签内的内容,不要有其他任何输出。
|
212
203
|
"""
|
213
204
|
|
214
|
-
#
|
215
|
-
|
216
|
-
|
205
|
+
# 获取大模型选择的方法论序号
|
206
|
+
response = platform.chat_until_success(selection_prompt).strip()
|
207
|
+
|
208
|
+
# 重置平台,恢复输出
|
209
|
+
platform.reset()
|
210
|
+
platform.set_suppress_output(False)
|
211
|
+
|
212
|
+
# 从响应中提取<NUM>标签内的内容
|
213
|
+
import re
|
214
|
+
num_match = re.search(r'<NUM>(.*?)</NUM>', response, re.DOTALL)
|
215
|
+
|
216
|
+
if not num_match:
|
217
|
+
# 如果没有找到<NUM>标签,尝试直接解析响应
|
218
|
+
selected_indices_str = response
|
219
|
+
else:
|
220
|
+
selected_indices_str = num_match.group(1).strip()
|
221
|
+
|
222
|
+
if selected_indices_str.lower() == "none":
|
223
|
+
return "没有历史方法论可参考"
|
217
224
|
|
225
|
+
# 解析选择的序号
|
226
|
+
selected_methodologies = {}
|
218
227
|
try:
|
219
|
-
if
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
228
|
+
if selected_indices_str:
|
229
|
+
indices = [int(idx.strip()) for idx in selected_indices_str.split(",") if idx.strip().isdigit()]
|
230
|
+
for idx in indices:
|
231
|
+
if 1 <= idx <= len(methodology_titles):
|
232
|
+
title = methodology_titles[idx - 1]
|
233
|
+
selected_methodologies[title] = methodologies[title]
|
234
|
+
except Exception:
|
235
|
+
# 如果解析失败,返回空结果
|
236
|
+
return "没有历史方法论可参考"
|
237
|
+
|
238
|
+
if not selected_methodologies:
|
239
|
+
return "没有历史方法论可参考"
|
240
|
+
|
241
|
+
# 步骤3:将选择出来的方法论内容提供给大模型生成步骤
|
242
|
+
final_prompt = f"""以下是与用户需求相关的方法论内容:
|
243
|
+
|
244
|
+
"""
|
245
|
+
for problem_type, content in selected_methodologies.items():
|
246
|
+
final_prompt += f"## {problem_type}\n\n{content}\n\n---\n\n"
|
247
|
+
|
248
|
+
final_prompt += f"""以下是所有可用的工具内容:
|
249
|
+
|
250
|
+
{prompt}
|
251
|
+
|
252
|
+
用户需求:{user_input}
|
253
|
+
|
254
|
+
请根据以上方法论和可调用的工具内容,规划/总结出执行步骤。
|
237
255
|
|
238
256
|
请按以下格式回复:
|
239
257
|
### 与该任务/需求相关的方法论
|
@@ -244,22 +262,11 @@ def load_methodology(user_input: str, tool_registery: Optional[Any] = None) -> s
|
|
244
262
|
2. [步骤2]
|
245
263
|
3. [步骤3]
|
246
264
|
|
247
|
-
如果没有匹配的方法论,请输出:没有历史方法论可参考
|
248
265
|
除以上要求外,不要输出任何内容
|
249
266
|
"""
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
# 如果内容不大或上传失败,直接使用chat_until_success
|
254
|
-
return platform.chat_until_success(full_content)
|
255
|
-
|
256
|
-
finally:
|
257
|
-
# 清理临时文件
|
258
|
-
if temp_file_path and os.path.exists(temp_file_path):
|
259
|
-
try:
|
260
|
-
os.remove(temp_file_path)
|
261
|
-
except Exception:
|
262
|
-
pass
|
267
|
+
|
268
|
+
# 如果内容不大,直接使用chat_until_success
|
269
|
+
return platform.chat_until_success(final_prompt)
|
263
270
|
|
264
271
|
except Exception as e:
|
265
272
|
PrettyOutput.print(f"加载方法论失败: {str(e)}", OutputType.ERROR)
|