jarvis-ai-assistant 0.3.30__py3-none-any.whl → 0.7.0__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 +289 -87
- jarvis/jarvis_agent/agent_manager.py +17 -8
- jarvis/jarvis_agent/edit_file_handler.py +374 -86
- jarvis/jarvis_agent/event_bus.py +1 -1
- jarvis/jarvis_agent/file_context_handler.py +79 -0
- jarvis/jarvis_agent/jarvis.py +601 -43
- jarvis/jarvis_agent/main.py +32 -2
- jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
- jarvis/jarvis_agent/run_loop.py +38 -5
- jarvis/jarvis_agent/share_manager.py +8 -1
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +5 -2
- jarvis/jarvis_agent/task_planner.py +496 -0
- jarvis/jarvis_agent/utils.py +5 -1
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +751 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +613 -0
- jarvis/jarvis_c2rust/collector.py +258 -0
- jarvis/jarvis_c2rust/library_replacer.py +1122 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
- jarvis/jarvis_c2rust/optimizer.py +960 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2325 -0
- jarvis/jarvis_code_agent/build_validation_config.py +133 -0
- jarvis/jarvis_code_agent/code_agent.py +1171 -94
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
- jarvis/jarvis_code_agent/lint.py +270 -8
- jarvis/jarvis_code_agent/utils.py +142 -0
- jarvis/jarvis_code_analysis/code_review.py +483 -569
- jarvis/jarvis_data/config_schema.json +97 -8
- jarvis/jarvis_git_utils/git_commiter.py +38 -26
- jarvis/jarvis_mcp/sse_mcp_client.py +2 -2
- jarvis/jarvis_mcp/stdio_mcp_client.py +1 -1
- jarvis/jarvis_memory_organizer/memory_organizer.py +1 -1
- jarvis/jarvis_multi_agent/__init__.py +239 -25
- jarvis/jarvis_multi_agent/main.py +37 -1
- jarvis/jarvis_platform/base.py +103 -51
- jarvis/jarvis_platform/openai.py +26 -1
- jarvis/jarvis_platform/yuanbao.py +1 -1
- jarvis/jarvis_platform_manager/service.py +2 -2
- jarvis/jarvis_rag/cli.py +4 -4
- jarvis/jarvis_sec/__init__.py +3605 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +116 -0
- jarvis/jarvis_sec/report.py +257 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/workflow.py +219 -0
- jarvis/jarvis_stats/cli.py +1 -1
- jarvis/jarvis_stats/stats.py +1 -1
- jarvis/jarvis_stats/visualizer.py +1 -1
- jarvis/jarvis_tools/cli/main.py +1 -0
- jarvis/jarvis_tools/execute_script.py +46 -9
- jarvis/jarvis_tools/generate_new_tool.py +3 -1
- jarvis/jarvis_tools/read_code.py +275 -12
- jarvis/jarvis_tools/read_symbols.py +141 -0
- jarvis/jarvis_tools/read_webpage.py +5 -3
- jarvis/jarvis_tools/registry.py +73 -35
- jarvis/jarvis_tools/search_web.py +15 -11
- jarvis/jarvis_tools/sub_agent.py +24 -42
- jarvis/jarvis_tools/sub_code_agent.py +14 -13
- jarvis/jarvis_tools/virtual_tty.py +1 -1
- jarvis/jarvis_utils/config.py +187 -35
- jarvis/jarvis_utils/embedding.py +3 -0
- jarvis/jarvis_utils/git_utils.py +181 -6
- jarvis/jarvis_utils/globals.py +3 -3
- jarvis/jarvis_utils/http.py +1 -1
- jarvis/jarvis_utils/input.py +78 -2
- jarvis/jarvis_utils/methodology.py +25 -19
- jarvis/jarvis_utils/utils.py +644 -359
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/METADATA +85 -1
- jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +4 -0
- jarvis/jarvis_agent/config.py +0 -92
- jarvis/jarvis_tools/edit_file.py +0 -179
- jarvis/jarvis_tools/rewrite_file.py +0 -191
- jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/config.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import os
|
|
3
3
|
from functools import lru_cache
|
|
4
|
-
from typing import Any, Dict, List, Optional
|
|
4
|
+
from typing import Any, Dict, List, Optional, cast
|
|
5
5
|
|
|
6
|
-
import yaml
|
|
6
|
+
import yaml
|
|
7
7
|
|
|
8
8
|
from jarvis.jarvis_utils.builtin_replace_map import BUILTIN_REPLACE_MAP
|
|
9
9
|
|
|
@@ -37,7 +37,7 @@ def get_git_commit_prompt() -> str:
|
|
|
37
37
|
返回:
|
|
38
38
|
str: Git提交信息生成提示模板,如果未配置则返回空字符串
|
|
39
39
|
"""
|
|
40
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_GIT_COMMIT_PROMPT", "")
|
|
40
|
+
return cast(str, GLOBAL_CONFIG_DATA.get("JARVIS_GIT_COMMIT_PROMPT", ""))
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
# 输出窗口预留大小
|
|
@@ -76,17 +76,6 @@ def get_replace_map() -> dict:
|
|
|
76
76
|
return {**BUILTIN_REPLACE_MAP, **file_map}
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
def get_max_token_count(model_group_override: Optional[str] = None) -> int:
|
|
80
|
-
"""
|
|
81
|
-
获取模型允许的最大token数量。
|
|
82
|
-
|
|
83
|
-
返回:
|
|
84
|
-
int: 模型能处理的最大token数量,为最大输入token数量的100倍。
|
|
85
|
-
"""
|
|
86
|
-
max_input_tokens = get_max_input_token_count(model_group_override)
|
|
87
|
-
return max_input_tokens * 100
|
|
88
|
-
|
|
89
|
-
|
|
90
79
|
def get_max_input_token_count(model_group_override: Optional[str] = None) -> int:
|
|
91
80
|
"""
|
|
92
81
|
获取模型允许的最大输入token数量。
|
|
@@ -112,7 +101,7 @@ def get_shell_name() -> str:
|
|
|
112
101
|
4. 如果都未配置,则默认返回bash
|
|
113
102
|
"""
|
|
114
103
|
shell_path = GLOBAL_CONFIG_DATA.get("SHELL", os.getenv("SHELL", "/bin/bash"))
|
|
115
|
-
return os.path.basename(shell_path).lower()
|
|
104
|
+
return cast(str, os.path.basename(shell_path).lower())
|
|
116
105
|
|
|
117
106
|
|
|
118
107
|
def _apply_llm_group_env_override(group_config: Dict[str, Any]) -> None:
|
|
@@ -190,7 +179,7 @@ def get_normal_platform_name(model_group_override: Optional[str] = None) -> str:
|
|
|
190
179
|
str: 平台名称,默认为'yuanbao'
|
|
191
180
|
"""
|
|
192
181
|
config = _get_resolved_model_config(model_group_override)
|
|
193
|
-
return config.get("JARVIS_PLATFORM", "yuanbao")
|
|
182
|
+
return cast(str, config.get("JARVIS_PLATFORM", "yuanbao"))
|
|
194
183
|
|
|
195
184
|
|
|
196
185
|
def get_normal_model_name(model_group_override: Optional[str] = None) -> str:
|
|
@@ -201,7 +190,7 @@ def get_normal_model_name(model_group_override: Optional[str] = None) -> str:
|
|
|
201
190
|
str: 模型名称,默认为'deep_seek_v3'
|
|
202
191
|
"""
|
|
203
192
|
config = _get_resolved_model_config(model_group_override)
|
|
204
|
-
return config.get("JARVIS_MODEL", "deep_seek_v3")
|
|
193
|
+
return cast(str, config.get("JARVIS_MODEL", "deep_seek_v3"))
|
|
205
194
|
|
|
206
195
|
|
|
207
196
|
def _deprecated_platform_name_v1(model_group_override: Optional[str] = None) -> str:
|
|
@@ -235,7 +224,7 @@ def is_execute_tool_confirm() -> bool:
|
|
|
235
224
|
返回:
|
|
236
225
|
bool: 如果需要确认则返回True,默认为False
|
|
237
226
|
"""
|
|
238
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_EXECUTE_TOOL_CONFIRM", False)
|
|
227
|
+
return cast(bool, GLOBAL_CONFIG_DATA.get("JARVIS_EXECUTE_TOOL_CONFIRM", False))
|
|
239
228
|
|
|
240
229
|
|
|
241
230
|
def is_confirm_before_apply_patch() -> bool:
|
|
@@ -245,7 +234,24 @@ def is_confirm_before_apply_patch() -> bool:
|
|
|
245
234
|
返回:
|
|
246
235
|
bool: 如果需要确认则返回True,默认为False
|
|
247
236
|
"""
|
|
248
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_CONFIRM_BEFORE_APPLY_PATCH", False)
|
|
237
|
+
return cast(bool, GLOBAL_CONFIG_DATA.get("JARVIS_CONFIRM_BEFORE_APPLY_PATCH", False))
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def get_patch_format() -> str:
|
|
241
|
+
"""
|
|
242
|
+
获取补丁格式。
|
|
243
|
+
|
|
244
|
+
- "search": 仅使用精确匹配的 `SEARCH` 模式。此模式对能力较弱的模型更稳定,因为它要求代码片段完全匹配。
|
|
245
|
+
- "search_range": 仅使用 `SEARCH_START` 和 `SEARCH_END` 的范围匹配模式。此模式对能力较强的模型更灵活,因为它允许在代码块内部进行修改,而不要求整个块完全匹配。
|
|
246
|
+
- "all": 同时支持以上两种模式(默认)。
|
|
247
|
+
|
|
248
|
+
返回:
|
|
249
|
+
str: "all", "search", or "search_range"
|
|
250
|
+
"""
|
|
251
|
+
mode = GLOBAL_CONFIG_DATA.get("JARVIS_PATCH_FORMAT", "all")
|
|
252
|
+
if mode in ["all", "search", "search_range"]:
|
|
253
|
+
return cast(str, mode)
|
|
254
|
+
return "all"
|
|
249
255
|
|
|
250
256
|
|
|
251
257
|
def get_data_dir() -> str:
|
|
@@ -257,7 +263,7 @@ def get_data_dir() -> str:
|
|
|
257
263
|
如果未设置或为空,则使用~/.jarvis作为默认值
|
|
258
264
|
"""
|
|
259
265
|
return os.path.expanduser(
|
|
260
|
-
GLOBAL_CONFIG_DATA.get("JARVIS_DATA_PATH", "~/.jarvis").strip()
|
|
266
|
+
cast(str, GLOBAL_CONFIG_DATA.get("JARVIS_DATA_PATH", "~/.jarvis")).strip()
|
|
261
267
|
)
|
|
262
268
|
|
|
263
269
|
|
|
@@ -285,7 +291,7 @@ def get_pretty_output() -> bool:
|
|
|
285
291
|
if platform.system() == "Windows":
|
|
286
292
|
return False
|
|
287
293
|
|
|
288
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_PRETTY_OUTPUT", True)
|
|
294
|
+
return cast(bool, GLOBAL_CONFIG_DATA.get("JARVIS_PRETTY_OUTPUT", True))
|
|
289
295
|
|
|
290
296
|
|
|
291
297
|
def is_use_methodology() -> bool:
|
|
@@ -295,7 +301,7 @@ def is_use_methodology() -> bool:
|
|
|
295
301
|
返回:
|
|
296
302
|
bool: 如果启用方法论则返回True,默认为True
|
|
297
303
|
"""
|
|
298
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_USE_METHODOLOGY", True)
|
|
304
|
+
return cast(bool, GLOBAL_CONFIG_DATA.get("JARVIS_USE_METHODOLOGY", True))
|
|
299
305
|
|
|
300
306
|
|
|
301
307
|
def is_use_analysis() -> bool:
|
|
@@ -305,7 +311,7 @@ def is_use_analysis() -> bool:
|
|
|
305
311
|
返回:
|
|
306
312
|
bool: 如果启用任务分析则返回True,默认为True
|
|
307
313
|
"""
|
|
308
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_USE_ANALYSIS", True)
|
|
314
|
+
return cast(bool, GLOBAL_CONFIG_DATA.get("JARVIS_USE_ANALYSIS", True))
|
|
309
315
|
|
|
310
316
|
|
|
311
317
|
def get_tool_load_dirs() -> List[str]:
|
|
@@ -399,7 +405,7 @@ def get_central_methodology_repo() -> str:
|
|
|
399
405
|
返回:
|
|
400
406
|
str: 中心方法论Git仓库地址,如果未配置则返回空字符串
|
|
401
407
|
"""
|
|
402
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_CENTRAL_METHODOLOGY_REPO", "")
|
|
408
|
+
return cast(str, GLOBAL_CONFIG_DATA.get("JARVIS_CENTRAL_METHODOLOGY_REPO", ""))
|
|
403
409
|
|
|
404
410
|
|
|
405
411
|
def get_central_tool_repo() -> str:
|
|
@@ -409,7 +415,7 @@ def get_central_tool_repo() -> str:
|
|
|
409
415
|
返回:
|
|
410
416
|
str: 中心工具Git仓库地址,如果未配置则返回空字符串
|
|
411
417
|
"""
|
|
412
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_CENTRAL_TOOL_REPO", "")
|
|
418
|
+
return cast(str, GLOBAL_CONFIG_DATA.get("JARVIS_CENTRAL_TOOL_REPO", ""))
|
|
413
419
|
|
|
414
420
|
|
|
415
421
|
def is_print_prompt() -> bool:
|
|
@@ -419,7 +425,7 @@ def is_print_prompt() -> bool:
|
|
|
419
425
|
返回:
|
|
420
426
|
bool: 如果打印提示则返回True,默认为True
|
|
421
427
|
"""
|
|
422
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_PRINT_PROMPT", False)
|
|
428
|
+
return cast(bool, GLOBAL_CONFIG_DATA.get("JARVIS_PRINT_PROMPT", False))
|
|
423
429
|
|
|
424
430
|
|
|
425
431
|
def is_print_error_traceback() -> bool:
|
|
@@ -452,6 +458,36 @@ def is_enable_static_analysis() -> bool:
|
|
|
452
458
|
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_STATIC_ANALYSIS", True) is True
|
|
453
459
|
|
|
454
460
|
|
|
461
|
+
def is_enable_build_validation() -> bool:
|
|
462
|
+
"""
|
|
463
|
+
获取是否启用构建验证。
|
|
464
|
+
|
|
465
|
+
返回:
|
|
466
|
+
bool: 如果启用构建验证则返回True,默认为True
|
|
467
|
+
"""
|
|
468
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_BUILD_VALIDATION", True) is True
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def is_enable_impact_analysis() -> bool:
|
|
472
|
+
"""
|
|
473
|
+
获取是否启用编辑影响范围分析。
|
|
474
|
+
|
|
475
|
+
返回:
|
|
476
|
+
bool: 如果启用影响范围分析则返回True,默认为True
|
|
477
|
+
"""
|
|
478
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_IMPACT_ANALYSIS", True) is True
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def get_build_validation_timeout() -> int:
|
|
482
|
+
"""
|
|
483
|
+
获取构建验证的超时时间(秒)。
|
|
484
|
+
|
|
485
|
+
返回:
|
|
486
|
+
int: 超时时间,默认为30秒
|
|
487
|
+
"""
|
|
488
|
+
return int(GLOBAL_CONFIG_DATA.get("JARVIS_BUILD_VALIDATION_TIMEOUT", 30))
|
|
489
|
+
|
|
490
|
+
|
|
455
491
|
def get_git_check_mode() -> str:
|
|
456
492
|
"""
|
|
457
493
|
获取Git校验模式。
|
|
@@ -473,7 +509,7 @@ def get_mcp_config() -> List[Dict[str, Any]]:
|
|
|
473
509
|
返回:
|
|
474
510
|
List[Dict[str, Any]]: MCP配置项列表,如果未配置则返回空列表
|
|
475
511
|
"""
|
|
476
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_MCP", [])
|
|
512
|
+
return cast(List[Dict[str, Any]], GLOBAL_CONFIG_DATA.get("JARVIS_MCP", []))
|
|
477
513
|
|
|
478
514
|
|
|
479
515
|
# ==============================================================================
|
|
@@ -550,7 +586,7 @@ def get_rag_embedding_model() -> str:
|
|
|
550
586
|
str: 嵌入模型的名称
|
|
551
587
|
"""
|
|
552
588
|
config = _get_resolved_rag_config()
|
|
553
|
-
return config.get("embedding_model", "BAAI/bge-m3")
|
|
589
|
+
return cast(str, config.get("embedding_model", "BAAI/bge-m3"))
|
|
554
590
|
|
|
555
591
|
|
|
556
592
|
def get_rag_rerank_model() -> str:
|
|
@@ -561,7 +597,7 @@ def get_rag_rerank_model() -> str:
|
|
|
561
597
|
str: rerank模型的名称
|
|
562
598
|
"""
|
|
563
599
|
config = _get_resolved_rag_config()
|
|
564
|
-
return config.get("rerank_model", "BAAI/bge-reranker-v2-m3")
|
|
600
|
+
return cast(str, config.get("rerank_model", "BAAI/bge-reranker-v2-m3"))
|
|
565
601
|
|
|
566
602
|
|
|
567
603
|
def get_rag_embedding_cache_path() -> str:
|
|
@@ -671,7 +707,7 @@ def get_tool_use_list() -> List[str]:
|
|
|
671
707
|
List[str]: 要使用的工具名称列表,空列表表示使用所有工具
|
|
672
708
|
"""
|
|
673
709
|
config = _get_resolved_tool_config()
|
|
674
|
-
return config.get("use", [])
|
|
710
|
+
return cast(List[str], config.get("use", []))
|
|
675
711
|
|
|
676
712
|
|
|
677
713
|
def get_tool_dont_use_list() -> List[str]:
|
|
@@ -682,7 +718,7 @@ def get_tool_dont_use_list() -> List[str]:
|
|
|
682
718
|
List[str]: 不使用的工具名称列表
|
|
683
719
|
"""
|
|
684
720
|
config = _get_resolved_tool_config()
|
|
685
|
-
return config.get("dont_use", [])
|
|
721
|
+
return cast(List[str], config.get("dont_use", []))
|
|
686
722
|
|
|
687
723
|
|
|
688
724
|
def get_tool_filter_threshold() -> int:
|
|
@@ -694,28 +730,144 @@ def get_tool_filter_threshold() -> int:
|
|
|
694
730
|
"""
|
|
695
731
|
return int(GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_FILTER_THRESHOLD", 30))
|
|
696
732
|
|
|
733
|
+
def get_plan_max_depth() -> int:
|
|
734
|
+
"""
|
|
735
|
+
获取任务规划的最大层数。
|
|
736
|
+
|
|
737
|
+
返回:
|
|
738
|
+
int: 最大规划层数,默认为2(可通过 GLOBAL_CONFIG_DATA['JARVIS_PLAN_MAX_DEPTH'] 配置)
|
|
739
|
+
"""
|
|
740
|
+
try:
|
|
741
|
+
return int(GLOBAL_CONFIG_DATA.get("JARVIS_PLAN_MAX_DEPTH", 2))
|
|
742
|
+
except Exception:
|
|
743
|
+
return 2
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
def is_plan_enabled() -> bool:
|
|
747
|
+
"""
|
|
748
|
+
获取是否默认启用任务规划。
|
|
749
|
+
|
|
750
|
+
返回:
|
|
751
|
+
bool: 如果启用任务规划则返回True,默认为True
|
|
752
|
+
"""
|
|
753
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_PLAN_ENABLED", True) is True
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
def get_auto_summary_rounds() -> int:
|
|
757
|
+
"""
|
|
758
|
+
获取基于对话轮次的自动总结阈值。
|
|
759
|
+
|
|
760
|
+
返回:
|
|
761
|
+
int: 轮次阈值,默认20
|
|
762
|
+
"""
|
|
763
|
+
try:
|
|
764
|
+
return int(GLOBAL_CONFIG_DATA.get("JARVIS_AUTO_SUMMARY_ROUNDS", 50))
|
|
765
|
+
except Exception:
|
|
766
|
+
return 50
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
def get_script_execution_timeout() -> int:
|
|
773
|
+
"""
|
|
774
|
+
获取脚本执行的超时时间(秒)。
|
|
775
|
+
|
|
776
|
+
返回:
|
|
777
|
+
int: 超时时间,默认为300秒(5分钟)
|
|
778
|
+
"""
|
|
779
|
+
return int(GLOBAL_CONFIG_DATA.get("JARVIS_SCRIPT_EXECUTION_TIMEOUT", 300))
|
|
780
|
+
|
|
697
781
|
|
|
698
782
|
def is_enable_git_repo_jca_switch() -> bool:
|
|
699
783
|
"""
|
|
700
784
|
是否启用:在初始化环境前检测Git仓库并提示可切换到代码开发模式(jca)
|
|
701
|
-
|
|
785
|
+
默认开启
|
|
702
786
|
"""
|
|
703
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_GIT_JCA_SWITCH",
|
|
787
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_GIT_JCA_SWITCH", True) is True
|
|
704
788
|
|
|
705
789
|
|
|
706
790
|
def is_enable_builtin_config_selector() -> bool:
|
|
707
791
|
"""
|
|
708
792
|
是否启用:在进入默认通用代理前,列出可用配置(agent/multi_agent/roles)供选择
|
|
709
|
-
|
|
793
|
+
默认开启
|
|
710
794
|
"""
|
|
711
795
|
return (
|
|
712
|
-
GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_STARTUP_CONFIG_SELECTOR",
|
|
796
|
+
GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_STARTUP_CONFIG_SELECTOR", True) is True
|
|
713
797
|
)
|
|
714
798
|
|
|
715
799
|
|
|
800
|
+
def is_save_session_history() -> bool:
|
|
801
|
+
"""
|
|
802
|
+
是否保存会话记录。
|
|
803
|
+
|
|
804
|
+
返回:
|
|
805
|
+
bool: 如果要保存会话记录则返回True, 默认为False
|
|
806
|
+
"""
|
|
807
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_SAVE_SESSION_HISTORY", False) is True
|
|
808
|
+
|
|
809
|
+
|
|
716
810
|
def is_immediate_abort() -> bool:
|
|
717
811
|
"""
|
|
718
812
|
是否启用立即中断:当在对话过程中检测到用户中断信号时,立即停止输出并返回。
|
|
719
813
|
默认关闭
|
|
720
814
|
"""
|
|
721
815
|
return GLOBAL_CONFIG_DATA.get("JARVIS_IMMEDIATE_ABORT", False) is True
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def is_non_interactive() -> bool:
|
|
819
|
+
"""
|
|
820
|
+
获取是否启用非交互模式。
|
|
821
|
+
|
|
822
|
+
返回:
|
|
823
|
+
bool: 如果启用非交互模式则返回True,默认为False
|
|
824
|
+
"""
|
|
825
|
+
# 优先读取环境变量,确保 CLI 标志生效且不被配置覆盖
|
|
826
|
+
try:
|
|
827
|
+
import os
|
|
828
|
+
v = os.getenv("JARVIS_NON_INTERACTIVE")
|
|
829
|
+
if v is not None:
|
|
830
|
+
val = str(v).strip().lower()
|
|
831
|
+
if val in ("1", "true", "yes", "on"):
|
|
832
|
+
return True
|
|
833
|
+
if val in ("0", "false", "no", "off"):
|
|
834
|
+
return False
|
|
835
|
+
except Exception:
|
|
836
|
+
# 忽略环境变量解析异常,回退到配置
|
|
837
|
+
pass
|
|
838
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_NON_INTERACTIVE", False) is True
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def is_skip_predefined_tasks() -> bool:
|
|
842
|
+
"""
|
|
843
|
+
是否跳过预定义任务加载。
|
|
844
|
+
|
|
845
|
+
返回:
|
|
846
|
+
bool: 如果跳过预定义任务加载则返回True,默认为False
|
|
847
|
+
"""
|
|
848
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_SKIP_PREDEFINED_TASKS", False) is True
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
def get_addon_prompt_threshold() -> int:
|
|
852
|
+
"""
|
|
853
|
+
获取附加提示的触发阈值(字符数)。
|
|
854
|
+
|
|
855
|
+
当消息长度超过此阈值时,会自动添加默认的附加提示。
|
|
856
|
+
|
|
857
|
+
返回:
|
|
858
|
+
int: 触发阈值,默认为1024
|
|
859
|
+
"""
|
|
860
|
+
try:
|
|
861
|
+
return int(GLOBAL_CONFIG_DATA.get("JARVIS_ADDON_PROMPT_THRESHOLD", 1024))
|
|
862
|
+
except Exception:
|
|
863
|
+
return 1024
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
def is_enable_intent_recognition() -> bool:
|
|
867
|
+
"""
|
|
868
|
+
获取是否启用意图识别功能。
|
|
869
|
+
|
|
870
|
+
返回:
|
|
871
|
+
bool: 是否启用意图识别,默认为True(可通过 GLOBAL_CONFIG_DATA['JARVIS_ENABLE_INTENT_RECOGNITION'] 配置)
|
|
872
|
+
"""
|
|
873
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_INTENT_RECOGNITION", True) is True
|
jarvis/jarvis_utils/embedding.py
CHANGED
jarvis/jarvis_utils/git_utils.py
CHANGED
|
@@ -14,7 +14,7 @@ import os
|
|
|
14
14
|
import re
|
|
15
15
|
import subprocess
|
|
16
16
|
import sys
|
|
17
|
-
from typing import Any, Dict, List, Set, Tuple
|
|
17
|
+
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
18
18
|
|
|
19
19
|
from jarvis.jarvis_utils.config import get_data_dir, is_confirm_before_apply_patch
|
|
20
20
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
@@ -34,7 +34,13 @@ def find_git_root_and_cd(start_dir: str = ".") -> str:
|
|
|
34
34
|
"""
|
|
35
35
|
os.chdir(start_dir)
|
|
36
36
|
try:
|
|
37
|
-
|
|
37
|
+
result = subprocess.run(
|
|
38
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
39
|
+
capture_output=True,
|
|
40
|
+
text=True,
|
|
41
|
+
check=True,
|
|
42
|
+
)
|
|
43
|
+
git_root = result.stdout.strip()
|
|
38
44
|
if not git_root:
|
|
39
45
|
subprocess.run(["git", "init"], check=True)
|
|
40
46
|
git_root = os.path.abspath(".")
|
|
@@ -209,6 +215,126 @@ def revert_change() -> None:
|
|
|
209
215
|
PrettyOutput.print(f"恢复更改失败: {str(e)}", OutputType.ERROR)
|
|
210
216
|
|
|
211
217
|
|
|
218
|
+
def detect_large_code_deletion(threshold: int = 200) -> Optional[Dict[str, int]]:
|
|
219
|
+
"""检测是否有大量代码删除
|
|
220
|
+
|
|
221
|
+
参数:
|
|
222
|
+
threshold: 净删除行数阈值,默认200行
|
|
223
|
+
|
|
224
|
+
返回:
|
|
225
|
+
Optional[Dict[str, int]]: 如果检测到大量删除,返回包含统计信息的字典:
|
|
226
|
+
{
|
|
227
|
+
'insertions': int, # 新增行数
|
|
228
|
+
'deletions': int, # 删除行数
|
|
229
|
+
'net_deletions': int # 净删除行数
|
|
230
|
+
}
|
|
231
|
+
如果没有大量删除或发生错误,返回None
|
|
232
|
+
"""
|
|
233
|
+
try:
|
|
234
|
+
# 临时暂存所有文件以便获取完整的diff统计
|
|
235
|
+
subprocess.run(["git", "add", "-N", "."], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
236
|
+
|
|
237
|
+
# 检查是否有HEAD
|
|
238
|
+
head_check = subprocess.run(
|
|
239
|
+
["git", "rev-parse", "--verify", "HEAD"],
|
|
240
|
+
stderr=subprocess.DEVNULL,
|
|
241
|
+
stdout=subprocess.DEVNULL,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
if head_check.returncode == 0:
|
|
245
|
+
# 有HEAD,获取相对于HEAD的diff统计
|
|
246
|
+
diff_result = subprocess.run(
|
|
247
|
+
["git", "diff", "HEAD", "--shortstat"],
|
|
248
|
+
capture_output=True,
|
|
249
|
+
text=True,
|
|
250
|
+
encoding="utf-8",
|
|
251
|
+
errors="replace",
|
|
252
|
+
check=False,
|
|
253
|
+
)
|
|
254
|
+
else:
|
|
255
|
+
# 空仓库,获取工作区diff统计
|
|
256
|
+
diff_result = subprocess.run(
|
|
257
|
+
["git", "diff", "--shortstat"],
|
|
258
|
+
capture_output=True,
|
|
259
|
+
text=True,
|
|
260
|
+
encoding="utf-8",
|
|
261
|
+
errors="replace",
|
|
262
|
+
check=False,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# 重置暂存区
|
|
266
|
+
subprocess.run(["git", "reset"], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
267
|
+
|
|
268
|
+
# 解析插入和删除行数
|
|
269
|
+
if diff_result.returncode == 0 and diff_result.stdout:
|
|
270
|
+
insertions = 0
|
|
271
|
+
deletions = 0
|
|
272
|
+
insertions_match = re.search(r"(\d+)\s+insertions?\(\+\)", diff_result.stdout)
|
|
273
|
+
deletions_match = re.search(r"(\d+)\s+deletions?\(\-\)", diff_result.stdout)
|
|
274
|
+
if insertions_match:
|
|
275
|
+
insertions = int(insertions_match.group(1))
|
|
276
|
+
if deletions_match:
|
|
277
|
+
deletions = int(deletions_match.group(1))
|
|
278
|
+
|
|
279
|
+
# 检查是否有大量代码删除(净删除超过阈值)
|
|
280
|
+
net_deletions = deletions - insertions
|
|
281
|
+
if net_deletions > threshold:
|
|
282
|
+
return {
|
|
283
|
+
'insertions': insertions,
|
|
284
|
+
'deletions': deletions,
|
|
285
|
+
'net_deletions': net_deletions
|
|
286
|
+
}
|
|
287
|
+
return None
|
|
288
|
+
except Exception:
|
|
289
|
+
# 如果检查过程中出错,返回None
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def confirm_large_code_deletion(detection_result: Dict[str, int]) -> bool:
|
|
294
|
+
"""询问用户是否确认大量代码删除
|
|
295
|
+
|
|
296
|
+
参数:
|
|
297
|
+
detection_result: 检测结果字典,包含 'insertions', 'deletions', 'net_deletions'
|
|
298
|
+
|
|
299
|
+
返回:
|
|
300
|
+
bool: 如果用户确认,返回True;如果用户拒绝,返回False
|
|
301
|
+
"""
|
|
302
|
+
insertions = detection_result['insertions']
|
|
303
|
+
deletions = detection_result['deletions']
|
|
304
|
+
net_deletions = detection_result['net_deletions']
|
|
305
|
+
|
|
306
|
+
PrettyOutput.print(
|
|
307
|
+
f"⚠️ 检测到大量代码删除:净删除 {net_deletions} 行(删除 {deletions} 行,新增 {insertions} 行)",
|
|
308
|
+
OutputType.WARNING,
|
|
309
|
+
)
|
|
310
|
+
if not user_confirm(
|
|
311
|
+
"此补丁包含大量代码删除,是否合理?", default=True
|
|
312
|
+
):
|
|
313
|
+
# 用户认为不合理,拒绝提交
|
|
314
|
+
revert_change()
|
|
315
|
+
PrettyOutput.print(
|
|
316
|
+
"已拒绝本次提交(用户认为补丁不合理)", OutputType.INFO
|
|
317
|
+
)
|
|
318
|
+
return False
|
|
319
|
+
return True
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def check_large_code_deletion(threshold: int = 200) -> bool:
|
|
323
|
+
"""检查是否有大量代码删除并询问用户确认
|
|
324
|
+
|
|
325
|
+
参数:
|
|
326
|
+
threshold: 净删除行数阈值,默认200行
|
|
327
|
+
|
|
328
|
+
返回:
|
|
329
|
+
bool: 如果检测到大量删除且用户拒绝提交,返回False;否则返回True
|
|
330
|
+
"""
|
|
331
|
+
detection_result = detect_large_code_deletion(threshold)
|
|
332
|
+
if detection_result is None:
|
|
333
|
+
return True
|
|
334
|
+
|
|
335
|
+
return confirm_large_code_deletion(detection_result)
|
|
336
|
+
|
|
337
|
+
|
|
212
338
|
def handle_commit_workflow() -> bool:
|
|
213
339
|
"""Handle the git commit workflow and return the commit details.
|
|
214
340
|
|
|
@@ -229,6 +355,10 @@ def handle_commit_workflow() -> bool:
|
|
|
229
355
|
if not has_uncommitted_changes():
|
|
230
356
|
return False
|
|
231
357
|
|
|
358
|
+
# 在提交前检查是否有大量代码删除
|
|
359
|
+
if not check_large_code_deletion():
|
|
360
|
+
return False
|
|
361
|
+
|
|
232
362
|
# 获取当前分支的提交总数
|
|
233
363
|
commit_result = subprocess.run(
|
|
234
364
|
["git", "rev-list", "--count", "HEAD"], capture_output=True, text=True
|
|
@@ -291,7 +421,13 @@ def get_modified_line_ranges() -> Dict[str, List[Tuple[int, int]]]:
|
|
|
291
421
|
行号从1开始。
|
|
292
422
|
"""
|
|
293
423
|
# 获取所有文件的Git差异
|
|
294
|
-
|
|
424
|
+
# 仅用于解析修改行范围,减少上下文以降低输出体积和解析成本
|
|
425
|
+
proc = subprocess.run(
|
|
426
|
+
["git", "show", "--no-color"],
|
|
427
|
+
capture_output=True,
|
|
428
|
+
text=True,
|
|
429
|
+
)
|
|
430
|
+
diff_output = proc.stdout
|
|
295
431
|
|
|
296
432
|
# 解析差异以获取修改的文件及其行范围
|
|
297
433
|
result: Dict[str, List[Tuple[int, int]]] = {}
|
|
@@ -329,7 +465,7 @@ def is_file_in_git_repo(filepath: str) -> bool:
|
|
|
329
465
|
|
|
330
466
|
# 检查文件路径是否在仓库根目录下
|
|
331
467
|
return os.path.abspath(filepath).startswith(os.path.abspath(repo_root))
|
|
332
|
-
except:
|
|
468
|
+
except Exception:
|
|
333
469
|
return False
|
|
334
470
|
|
|
335
471
|
|
|
@@ -610,7 +746,7 @@ def get_recent_commits_with_files() -> List[Dict[str, Any]]:
|
|
|
610
746
|
if files_result.returncode == 0:
|
|
611
747
|
file_lines = files_result.stdout.splitlines()
|
|
612
748
|
unique_files: Set[str] = set(filter(None, file_lines))
|
|
613
|
-
commit["files"] = list(unique_files)[:20] #
|
|
749
|
+
commit["files"] = list(unique_files)[:20] # 限制最多20个文件
|
|
614
750
|
|
|
615
751
|
return commits
|
|
616
752
|
|
|
@@ -705,8 +841,47 @@ def confirm_add_new_files() -> None:
|
|
|
705
841
|
|
|
706
842
|
if not user_confirm(
|
|
707
843
|
"是否要添加这些变更(如果不需要请修改.gitignore文件以忽略不需要的文件)?",
|
|
708
|
-
|
|
844
|
+
True,
|
|
709
845
|
):
|
|
846
|
+
# 用户选择 N:自动将未跟踪文件列表添加到仓库根目录的 .gitignore
|
|
847
|
+
try:
|
|
848
|
+
repo_root_result = subprocess.run(
|
|
849
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
850
|
+
capture_output=True,
|
|
851
|
+
text=True,
|
|
852
|
+
check=True,
|
|
853
|
+
)
|
|
854
|
+
repo_root = repo_root_result.stdout.strip() or "."
|
|
855
|
+
except Exception:
|
|
856
|
+
repo_root = "."
|
|
857
|
+
gitignore_path = os.path.join(repo_root, ".gitignore")
|
|
858
|
+
|
|
859
|
+
# 仅对未跟踪的新文件进行忽略(已跟踪文件无法通过 .gitignore 忽略)
|
|
860
|
+
files_to_ignore = sorted(set(new_files))
|
|
861
|
+
|
|
862
|
+
# 读取已存在的 .gitignore 以避免重复添加
|
|
863
|
+
existing_lines: Set[str] = set()
|
|
864
|
+
try:
|
|
865
|
+
if os.path.exists(gitignore_path):
|
|
866
|
+
with open(gitignore_path, "r", encoding="utf-8") as f:
|
|
867
|
+
existing_lines = set(line.strip() for line in f if line.strip())
|
|
868
|
+
except Exception:
|
|
869
|
+
existing_lines = set()
|
|
870
|
+
|
|
871
|
+
# 追加未存在的文件路径到 .gitignore(使用相对于仓库根目录的路径)
|
|
872
|
+
try:
|
|
873
|
+
with open(gitignore_path, "a", encoding="utf-8") as f:
|
|
874
|
+
for file in files_to_ignore:
|
|
875
|
+
abs_path = os.path.abspath(file)
|
|
876
|
+
rel_path = os.path.relpath(abs_path, repo_root)
|
|
877
|
+
# 避免无效的相对路径(不应出现 .. 前缀),有则回退用原始值
|
|
878
|
+
entry = rel_path if not rel_path.startswith("..") else file
|
|
879
|
+
if entry not in existing_lines:
|
|
880
|
+
f.write(entry + "\n")
|
|
881
|
+
PrettyOutput.print("已将未跟踪文件添加到 .gitignore,正在重新检测...", OutputType.INFO)
|
|
882
|
+
except Exception as e:
|
|
883
|
+
PrettyOutput.print(f"更新 .gitignore 失败: {str(e)}", OutputType.WARNING)
|
|
884
|
+
|
|
710
885
|
continue
|
|
711
886
|
|
|
712
887
|
break
|
jarvis/jarvis_utils/globals.py
CHANGED
|
@@ -19,9 +19,9 @@ MAX_HISTORY_SIZE = 50
|
|
|
19
19
|
short_term_memories: List[Dict[str, Any]] = []
|
|
20
20
|
MAX_SHORT_TERM_MEMORIES = 100
|
|
21
21
|
|
|
22
|
-
import colorama
|
|
23
|
-
from rich.console import Console
|
|
24
|
-
from rich.theme import Theme
|
|
22
|
+
import colorama # noqa: E402
|
|
23
|
+
from rich.console import Console # noqa: E402
|
|
24
|
+
from rich.theme import Theme # noqa: E402
|
|
25
25
|
|
|
26
26
|
# 初始化colorama以支持跨平台的彩色文本
|
|
27
27
|
colorama.init()
|