jarvis-ai-assistant 0.7.8__py3-none-any.whl → 1.0.2__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 +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""CodeAgent 影响分析模块"""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
7
|
+
|
|
8
|
+
# -*- coding: utf-8 -*-
|
|
9
|
+
from typing import List
|
|
10
|
+
from typing import Optional
|
|
11
|
+
from typing import Tuple
|
|
12
|
+
|
|
13
|
+
from jarvis.jarvis_code_agent.code_analyzer import ContextManager
|
|
14
|
+
from jarvis.jarvis_code_agent.code_analyzer import ImpactAnalyzer
|
|
15
|
+
from jarvis.jarvis_code_agent.code_analyzer import parse_git_diff_to_edits
|
|
16
|
+
from jarvis.jarvis_code_agent.code_analyzer.impact_analyzer import Edit
|
|
17
|
+
from jarvis.jarvis_utils.config import is_enable_impact_analysis
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ImpactManager:
|
|
21
|
+
"""影响分析管理器"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, root_dir: str, context_manager: ContextManager):
|
|
24
|
+
self.root_dir = root_dir
|
|
25
|
+
self.context_manager = context_manager
|
|
26
|
+
|
|
27
|
+
def update_context_for_modified_files(self, modified_files: List[str]) -> None:
|
|
28
|
+
"""更新上下文管理器:当文件被修改后,更新符号表和依赖图"""
|
|
29
|
+
if not modified_files:
|
|
30
|
+
return
|
|
31
|
+
PrettyOutput.auto_print("🔄 正在更新代码上下文...")
|
|
32
|
+
for file_path in modified_files:
|
|
33
|
+
import os
|
|
34
|
+
|
|
35
|
+
if os.path.exists(file_path):
|
|
36
|
+
try:
|
|
37
|
+
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
38
|
+
content = f.read()
|
|
39
|
+
self.context_manager.update_context_for_file(file_path, content)
|
|
40
|
+
except Exception:
|
|
41
|
+
# 如果读取文件失败,跳过更新
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def analyze_edit_impact(self, modified_files: List[str]) -> Optional[Any]:
|
|
45
|
+
"""进行影响范围分析(如果启用)
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
ImpactReport: 影响分析报告,如果未启用或失败则返回None
|
|
49
|
+
"""
|
|
50
|
+
if not is_enable_impact_analysis():
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
PrettyOutput.auto_print("🔍 正在进行变更影响分析...")
|
|
54
|
+
try:
|
|
55
|
+
impact_analyzer = ImpactAnalyzer(self.context_manager)
|
|
56
|
+
all_edits = []
|
|
57
|
+
import os
|
|
58
|
+
|
|
59
|
+
for file_path in modified_files:
|
|
60
|
+
if os.path.exists(file_path):
|
|
61
|
+
edits = parse_git_diff_to_edits(file_path, self.root_dir)
|
|
62
|
+
all_edits.extend(edits)
|
|
63
|
+
|
|
64
|
+
if not all_edits:
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
# 按文件分组编辑
|
|
68
|
+
edits_by_file: Dict[str, List[Edit]] = {}
|
|
69
|
+
for edit in all_edits:
|
|
70
|
+
if edit.file_path not in edits_by_file:
|
|
71
|
+
edits_by_file[edit.file_path] = []
|
|
72
|
+
edits_by_file[edit.file_path].append(edit)
|
|
73
|
+
|
|
74
|
+
# 对每个文件进行影响分析
|
|
75
|
+
impact_report = None
|
|
76
|
+
for file_path, edits in edits_by_file.items():
|
|
77
|
+
report = impact_analyzer.analyze_edit_impact(file_path, edits)
|
|
78
|
+
if report:
|
|
79
|
+
# 合并报告
|
|
80
|
+
if impact_report is None:
|
|
81
|
+
impact_report = report
|
|
82
|
+
else:
|
|
83
|
+
# 合并多个报告,去重
|
|
84
|
+
impact_report.affected_files = list(
|
|
85
|
+
set(impact_report.affected_files + report.affected_files)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# 合并符号(基于文件路径和名称去重)
|
|
89
|
+
symbol_map: Dict[Tuple[str, str, str], Any] = {}
|
|
90
|
+
for symbol in (
|
|
91
|
+
impact_report.affected_symbols + report.affected_symbols
|
|
92
|
+
):
|
|
93
|
+
key = (
|
|
94
|
+
symbol.file_path,
|
|
95
|
+
symbol.name,
|
|
96
|
+
str(symbol.line_start),
|
|
97
|
+
)
|
|
98
|
+
if key not in symbol_map:
|
|
99
|
+
symbol_map[key] = symbol
|
|
100
|
+
impact_report.affected_symbols = list(symbol_map.values())
|
|
101
|
+
|
|
102
|
+
impact_report.affected_tests = list(
|
|
103
|
+
set(impact_report.affected_tests + report.affected_tests)
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# 合并接口变更(基于符号名和文件路径去重)
|
|
107
|
+
interface_map: Dict[Tuple[str, str, str], Any] = {}
|
|
108
|
+
for change in (
|
|
109
|
+
impact_report.interface_changes + report.interface_changes
|
|
110
|
+
):
|
|
111
|
+
key = (
|
|
112
|
+
change.file_path,
|
|
113
|
+
change.symbol_name,
|
|
114
|
+
str(change.change_type),
|
|
115
|
+
)
|
|
116
|
+
if key not in interface_map:
|
|
117
|
+
interface_map[key] = change
|
|
118
|
+
impact_report.interface_changes = list(interface_map.values())
|
|
119
|
+
|
|
120
|
+
impact_report.impacts.extend(report.impacts)
|
|
121
|
+
|
|
122
|
+
# 合并建议
|
|
123
|
+
impact_report.recommendations = list(
|
|
124
|
+
set(impact_report.recommendations + report.recommendations)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# 使用更高的风险等级
|
|
128
|
+
if (
|
|
129
|
+
report.risk_level.value == "high"
|
|
130
|
+
or impact_report.risk_level.value == "high"
|
|
131
|
+
):
|
|
132
|
+
impact_report.risk_level = (
|
|
133
|
+
report.risk_level
|
|
134
|
+
if report.risk_level.value == "high"
|
|
135
|
+
else impact_report.risk_level
|
|
136
|
+
)
|
|
137
|
+
elif report.risk_level.value == "medium":
|
|
138
|
+
impact_report.risk_level = report.risk_level
|
|
139
|
+
|
|
140
|
+
return impact_report
|
|
141
|
+
except Exception as e:
|
|
142
|
+
# 影响分析失败不应该影响主流程,仅记录日志
|
|
143
|
+
PrettyOutput.auto_print(f"⚠️ 影响范围分析失败: {e}")
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
def handle_impact_report(
|
|
147
|
+
self, impact_report: Optional[Any], agent: Any, final_ret: str
|
|
148
|
+
) -> str:
|
|
149
|
+
"""处理影响范围分析报告
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
impact_report: 影响分析报告
|
|
153
|
+
agent: Agent实例
|
|
154
|
+
final_ret: 当前的结果字符串
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
更新后的结果字符串
|
|
158
|
+
"""
|
|
159
|
+
if not impact_report:
|
|
160
|
+
return final_ret
|
|
161
|
+
|
|
162
|
+
impact_summary = impact_report.to_string(self.root_dir)
|
|
163
|
+
final_ret += f"\n\n{impact_summary}\n"
|
|
164
|
+
|
|
165
|
+
# 如果是高风险,在提示词中提醒
|
|
166
|
+
if impact_report.risk_level.value == "high":
|
|
167
|
+
agent.set_addon_prompt(
|
|
168
|
+
f"{agent.get_addon_prompt() or ''}\n\n"
|
|
169
|
+
f"⚠️ 高风险编辑警告:\n"
|
|
170
|
+
f"检测到此编辑为高风险操作,请仔细检查以下内容:\n"
|
|
171
|
+
f"- 受影响文件: {len(impact_report.affected_files)} 个\n"
|
|
172
|
+
f"- 接口变更: {len(impact_report.interface_changes)} 个\n"
|
|
173
|
+
f"- 相关测试: {len(impact_report.affected_tests)} 个\n"
|
|
174
|
+
f"建议运行相关测试并检查所有受影响文件。"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return final_ret
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""CodeAgent 静态分析模块"""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
|
|
6
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
7
|
+
|
|
8
|
+
# -*- coding: utf-8 -*-
|
|
9
|
+
from typing import Any
|
|
10
|
+
from typing import List
|
|
11
|
+
from typing import Optional
|
|
12
|
+
from typing import Tuple
|
|
13
|
+
|
|
14
|
+
from jarvis.jarvis_code_agent.lint import LINT_COMMAND_TEMPLATES_BY_FILE
|
|
15
|
+
from jarvis.jarvis_code_agent.lint import get_lint_commands_for_files
|
|
16
|
+
from jarvis.jarvis_code_agent.lint import group_commands_by_template
|
|
17
|
+
from jarvis.jarvis_utils.config import is_enable_static_analysis
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class LintManager:
|
|
21
|
+
"""静态分析管理器"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, root_dir: str):
|
|
24
|
+
self.root_dir = root_dir
|
|
25
|
+
|
|
26
|
+
def run_static_analysis(
|
|
27
|
+
self, modified_files: List[str]
|
|
28
|
+
) -> List[Tuple[str, str, int, str]]:
|
|
29
|
+
"""执行静态分析
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
modified_files: 修改的文件列表
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
[(file_path, command, returncode, output), ...] 格式的结果列表
|
|
36
|
+
只返回有错误或警告的结果(returncode != 0)
|
|
37
|
+
"""
|
|
38
|
+
if not modified_files:
|
|
39
|
+
return []
|
|
40
|
+
|
|
41
|
+
# 获取所有lint命令
|
|
42
|
+
commands = get_lint_commands_for_files(modified_files, self.root_dir)
|
|
43
|
+
if not commands:
|
|
44
|
+
return []
|
|
45
|
+
|
|
46
|
+
# 输出静态检查日志
|
|
47
|
+
file_count = len(modified_files)
|
|
48
|
+
files_str = ", ".join(os.path.basename(f) for f in modified_files[:3])
|
|
49
|
+
if file_count > 3:
|
|
50
|
+
files_str += f" 等{file_count}个文件"
|
|
51
|
+
# 从命令中提取工具名(第一个单词)
|
|
52
|
+
tool_names = list(set(cmd[1].split()[0] for cmd in commands if cmd[1].split()))
|
|
53
|
+
tools_str = ", ".join(tool_names[:3])
|
|
54
|
+
if len(tool_names) > 3:
|
|
55
|
+
tools_str += f" 等{len(tool_names)}个工具"
|
|
56
|
+
PrettyOutput.auto_print("🔍 静态检查中...")
|
|
57
|
+
|
|
58
|
+
results = []
|
|
59
|
+
# 记录每个文件的检查结果
|
|
60
|
+
file_results = [] # [(file_name, command, status, message), ...]
|
|
61
|
+
|
|
62
|
+
# 按命令模板分组,相同工具可以批量执行
|
|
63
|
+
grouped = group_commands_by_template(commands)
|
|
64
|
+
|
|
65
|
+
for template_key, file_commands in grouped.items():
|
|
66
|
+
for file_path, command in file_commands:
|
|
67
|
+
file_name = os.path.basename(file_path)
|
|
68
|
+
try:
|
|
69
|
+
# 检查文件是否存在
|
|
70
|
+
abs_file_path = (
|
|
71
|
+
os.path.join(self.root_dir, file_path)
|
|
72
|
+
if not os.path.isabs(file_path)
|
|
73
|
+
else file_path
|
|
74
|
+
)
|
|
75
|
+
if not os.path.exists(abs_file_path):
|
|
76
|
+
file_results.append((file_name, command, "跳过", "文件不存在"))
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
# 打印执行的命令
|
|
80
|
+
PrettyOutput.auto_print(f"ℹ️ 执行: {command}")
|
|
81
|
+
|
|
82
|
+
# 执行命令
|
|
83
|
+
result = subprocess.run(
|
|
84
|
+
command,
|
|
85
|
+
shell=True,
|
|
86
|
+
cwd=self.root_dir,
|
|
87
|
+
capture_output=True,
|
|
88
|
+
text=True,
|
|
89
|
+
encoding="utf-8",
|
|
90
|
+
errors="replace",
|
|
91
|
+
timeout=600, # 600秒超时
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# 只记录有错误或警告的结果
|
|
95
|
+
if result.returncode != 0:
|
|
96
|
+
output = result.stdout + result.stderr
|
|
97
|
+
if output.strip(): # 有输出才记录
|
|
98
|
+
results.append(
|
|
99
|
+
(
|
|
100
|
+
file_path,
|
|
101
|
+
command,
|
|
102
|
+
result.returncode,
|
|
103
|
+
output,
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
file_results.append(
|
|
107
|
+
(file_name, command, "失败", "发现问题")
|
|
108
|
+
)
|
|
109
|
+
# 失败时打印检查结果
|
|
110
|
+
output_preview = (
|
|
111
|
+
output[:2000] if len(output) > 2000 else output
|
|
112
|
+
)
|
|
113
|
+
PrettyOutput.auto_print(
|
|
114
|
+
f"⚠️ 检查失败 ({file_name}):\n{output_preview}"
|
|
115
|
+
)
|
|
116
|
+
if len(output) > 2000:
|
|
117
|
+
PrettyOutput.auto_print(
|
|
118
|
+
f"⚠️ ... (输出已截断,共 {len(output)} 字符)"
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
file_results.append((file_name, command, "通过", ""))
|
|
122
|
+
else:
|
|
123
|
+
file_results.append((file_name, command, "通过", ""))
|
|
124
|
+
|
|
125
|
+
except subprocess.TimeoutExpired:
|
|
126
|
+
results.append((file_path, command, -1, "执行超时(600秒)"))
|
|
127
|
+
file_results.append(
|
|
128
|
+
(file_name, command, "超时", "执行超时(600秒)")
|
|
129
|
+
)
|
|
130
|
+
PrettyOutput.auto_print(
|
|
131
|
+
f"⚠️ 检查超时 ({file_name}): 执行超时(600秒)"
|
|
132
|
+
)
|
|
133
|
+
except FileNotFoundError:
|
|
134
|
+
# 工具未安装,跳过
|
|
135
|
+
file_results.append((file_name, command, "跳过", "工具未安装"))
|
|
136
|
+
continue
|
|
137
|
+
except Exception as e:
|
|
138
|
+
# 其他错误,记录但继续
|
|
139
|
+
PrettyOutput.auto_print(f"⚠️ 执行lint命令失败: {command}, 错误: {e}")
|
|
140
|
+
file_results.append(
|
|
141
|
+
(file_name, command, "失败", f"执行失败: {str(e)[:50]}")
|
|
142
|
+
)
|
|
143
|
+
continue
|
|
144
|
+
|
|
145
|
+
# 一次性打印所有检查结果
|
|
146
|
+
if file_results:
|
|
147
|
+
total_files = len(file_results)
|
|
148
|
+
passed_count = sum(
|
|
149
|
+
1 for _, _, status, _ in file_results if status == "通过"
|
|
150
|
+
)
|
|
151
|
+
failed_count = sum(
|
|
152
|
+
1 for _, _, status, _ in file_results if status == "失败"
|
|
153
|
+
)
|
|
154
|
+
timeout_count = sum(
|
|
155
|
+
1 for _, _, status, _ in file_results if status == "超时"
|
|
156
|
+
)
|
|
157
|
+
sum(1 for _, _, status, _ in file_results if status == "跳过")
|
|
158
|
+
|
|
159
|
+
# 收缩为一行的结果摘要
|
|
160
|
+
summary = f"🔍 静态检查: {total_files}个文件"
|
|
161
|
+
if failed_count > 0:
|
|
162
|
+
summary += f", {failed_count}失败"
|
|
163
|
+
if timeout_count > 0:
|
|
164
|
+
summary += f", {timeout_count}超时"
|
|
165
|
+
if passed_count == total_files:
|
|
166
|
+
summary += " ✅全部通过"
|
|
167
|
+
|
|
168
|
+
if failed_count > 0 or timeout_count > 0:
|
|
169
|
+
PrettyOutput.auto_print(f"⚠️ {summary}")
|
|
170
|
+
else:
|
|
171
|
+
PrettyOutput.auto_print(f"✅ {summary}")
|
|
172
|
+
else:
|
|
173
|
+
PrettyOutput.auto_print("✅ 静态检查完成")
|
|
174
|
+
|
|
175
|
+
return results
|
|
176
|
+
|
|
177
|
+
def format_lint_results(self, results: List[Tuple[str, str, int, str]]) -> str:
|
|
178
|
+
"""格式化lint结果
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
results: [(file_path, command, returncode, output), ...]
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
格式化的错误信息字符串
|
|
185
|
+
"""
|
|
186
|
+
if not results:
|
|
187
|
+
return ""
|
|
188
|
+
|
|
189
|
+
lines = []
|
|
190
|
+
for file_path, command, returncode, output in results:
|
|
191
|
+
# 从命令中提取工具名(第一个单词)
|
|
192
|
+
tool_name = command.split()[0] if command.split() else "unknown"
|
|
193
|
+
lines.append(f"工具: {tool_name}")
|
|
194
|
+
lines.append(f"文件: {file_path}")
|
|
195
|
+
lines.append(f"命令: {command}")
|
|
196
|
+
if returncode == -1:
|
|
197
|
+
lines.append(f"错误: {output}")
|
|
198
|
+
else:
|
|
199
|
+
# 限制输出长度,避免过长
|
|
200
|
+
output_preview = output[:1000] if len(output) > 1000 else output
|
|
201
|
+
lines.append(f"输出:\n{output_preview}")
|
|
202
|
+
if len(output) > 1000:
|
|
203
|
+
lines.append(f"... (输出已截断,共 {len(output)} 字符)")
|
|
204
|
+
lines.append("") # 空行分隔
|
|
205
|
+
|
|
206
|
+
return "\n".join(lines)
|
|
207
|
+
|
|
208
|
+
def handle_static_analysis(
|
|
209
|
+
self,
|
|
210
|
+
modified_files: List[str],
|
|
211
|
+
build_validation_result: Optional[Any],
|
|
212
|
+
config: Any,
|
|
213
|
+
agent: Any,
|
|
214
|
+
final_ret: str,
|
|
215
|
+
) -> str:
|
|
216
|
+
"""处理静态分析
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
更新后的结果字符串
|
|
220
|
+
"""
|
|
221
|
+
# 检查是否启用静态分析
|
|
222
|
+
if not is_enable_static_analysis():
|
|
223
|
+
PrettyOutput.auto_print("ℹ️ 静态分析已禁用,跳过静态检查")
|
|
224
|
+
return final_ret
|
|
225
|
+
|
|
226
|
+
# 检查是否有可用的lint工具
|
|
227
|
+
def get_lint_tool_names(file_path: str) -> List[str]:
|
|
228
|
+
"""获取文件的lint工具名称列表"""
|
|
229
|
+
filename = os.path.basename(file_path)
|
|
230
|
+
filename_lower = filename.lower()
|
|
231
|
+
templates = LINT_COMMAND_TEMPLATES_BY_FILE.get(filename_lower, [])
|
|
232
|
+
if not templates:
|
|
233
|
+
ext = os.path.splitext(filename)[1]
|
|
234
|
+
if ext:
|
|
235
|
+
templates = LINT_COMMAND_TEMPLATES_BY_FILE.get(ext.lower(), [])
|
|
236
|
+
# 提取工具名(命令模板的第一个单词)
|
|
237
|
+
return [
|
|
238
|
+
template.split()[0] if template.split() else "unknown"
|
|
239
|
+
for template in templates
|
|
240
|
+
]
|
|
241
|
+
|
|
242
|
+
lint_tools_info = "\n".join(
|
|
243
|
+
f" - {file}: 使用 {'、'.join(get_lint_tool_names(file))}"
|
|
244
|
+
for file in modified_files
|
|
245
|
+
if get_lint_tool_names(file)
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if not lint_tools_info:
|
|
249
|
+
PrettyOutput.auto_print("ℹ️ 未找到可用的静态检查工具,跳过静态检查")
|
|
250
|
+
return final_ret
|
|
251
|
+
|
|
252
|
+
# 如果构建验证失败且未禁用,不进行静态分析(避免重复错误)
|
|
253
|
+
# 如果构建验证已禁用,则进行静态分析(因为只做了基础静态检查)
|
|
254
|
+
should_skip_static = (
|
|
255
|
+
build_validation_result
|
|
256
|
+
and not build_validation_result.success
|
|
257
|
+
and not config.is_build_validation_disabled()
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
if should_skip_static:
|
|
261
|
+
PrettyOutput.auto_print("ℹ️ 构建验证失败,跳过静态分析(避免重复错误)")
|
|
262
|
+
return final_ret
|
|
263
|
+
|
|
264
|
+
# 直接执行静态扫描
|
|
265
|
+
lint_results = self.run_static_analysis(modified_files)
|
|
266
|
+
if lint_results:
|
|
267
|
+
# 有错误或警告,让大模型修复
|
|
268
|
+
errors_summary = self.format_lint_results(lint_results)
|
|
269
|
+
# 打印完整的检查结果
|
|
270
|
+
PrettyOutput.auto_print(f"⚠️ 静态扫描发现问题:\n{errors_summary}")
|
|
271
|
+
addon_prompt = f"""
|
|
272
|
+
静态扫描发现以下问题,请根据错误信息修复代码:
|
|
273
|
+
|
|
274
|
+
{errors_summary}
|
|
275
|
+
|
|
276
|
+
请仔细检查并修复所有问题。
|
|
277
|
+
"""
|
|
278
|
+
agent.set_addon_prompt(addon_prompt)
|
|
279
|
+
final_ret += "\n\n⚠️ 静态扫描发现问题,已提示修复\n"
|
|
280
|
+
else:
|
|
281
|
+
final_ret += "\n\n✅ 静态扫描通过\n"
|
|
282
|
+
|
|
283
|
+
return final_ret
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""CodeAgent LLM 询问模块"""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
7
|
+
|
|
8
|
+
# -*- coding: utf-8 -*-
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
12
|
+
from jarvis.jarvis_utils.config import get_normal_model_name
|
|
13
|
+
from jarvis.jarvis_utils.config import get_normal_platform_name
|
|
14
|
+
from jarvis.jarvis_utils.globals import get_global_model_group
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class LLMManager:
|
|
18
|
+
"""LLM 询问管理器"""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self, parent_model: Optional[Any] = None, model_group: Optional[str] = None
|
|
22
|
+
):
|
|
23
|
+
"""初始化LLM管理器
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
parent_model: 父Agent的模型实例(已废弃,保留参数兼容性)
|
|
27
|
+
model_group: 模型组名称,如果提供则优先使用,否则使用全局模型组
|
|
28
|
+
"""
|
|
29
|
+
# 保存配置信息,用于后续创建 LLM 实例
|
|
30
|
+
self._platform_name = None
|
|
31
|
+
self._model_name = None
|
|
32
|
+
# 优先使用传入的model_group,否则使用全局模型组
|
|
33
|
+
self._model_group = model_group or get_global_model_group()
|
|
34
|
+
|
|
35
|
+
# 根据 model_group 获取配置(不再从 parent_model 继承)
|
|
36
|
+
# 使用普通模型,LLM询问可以降低成本
|
|
37
|
+
if self._model_group:
|
|
38
|
+
try:
|
|
39
|
+
self._platform_name = get_normal_platform_name(self._model_group)
|
|
40
|
+
self._model_name = get_normal_model_name(self._model_group)
|
|
41
|
+
except Exception:
|
|
42
|
+
# 如果从 model_group 解析失败,回退到从 parent_model 获取的值
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
# 如果仍未获取到,使用默认配置
|
|
46
|
+
if not self._platform_name:
|
|
47
|
+
self._platform_name = get_normal_platform_name(None)
|
|
48
|
+
if not self._model_name:
|
|
49
|
+
self._model_name = get_normal_model_name(None)
|
|
50
|
+
|
|
51
|
+
def _create_llm_model(self):
|
|
52
|
+
"""创建新的 LLM 模型实例
|
|
53
|
+
|
|
54
|
+
每次调用都创建新的实例,避免上下文窗口累积。
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
LLM 模型实例
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
ValueError: 如果无法创建LLM模型
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
registry = PlatformRegistry.get_global_platform_registry()
|
|
64
|
+
|
|
65
|
+
# 创建平台实例
|
|
66
|
+
if self._platform_name:
|
|
67
|
+
llm_model = registry.create_platform(self._platform_name)
|
|
68
|
+
if llm_model is None:
|
|
69
|
+
# 如果创建失败,使用普通平台
|
|
70
|
+
llm_model = registry.get_normal_platform()
|
|
71
|
+
else:
|
|
72
|
+
llm_model = registry.get_normal_platform()
|
|
73
|
+
|
|
74
|
+
if not llm_model:
|
|
75
|
+
raise ValueError("无法创建LLM模型实例")
|
|
76
|
+
|
|
77
|
+
# 先设置模型组(如果从父Agent获取到),因为 model_group 可能会影响模型名称的解析
|
|
78
|
+
if self._model_group:
|
|
79
|
+
try:
|
|
80
|
+
llm_model.set_model_group(self._model_group)
|
|
81
|
+
except Exception:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
# 然后设置模型名称(如果从父Agent或model_group获取到)
|
|
85
|
+
if self._model_name:
|
|
86
|
+
try:
|
|
87
|
+
llm_model.set_model_name(self._model_name)
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
# 设置抑制输出,因为这是后台任务
|
|
92
|
+
llm_model.set_suppress_output(True)
|
|
93
|
+
|
|
94
|
+
return llm_model
|
|
95
|
+
except Exception as e:
|
|
96
|
+
raise ValueError(f"无法创建LLM模型: {e}")
|
|
97
|
+
|
|
98
|
+
def ask_llm_about_large_deletion(
|
|
99
|
+
self, detection_result: Dict[str, int], preview: str
|
|
100
|
+
) -> bool:
|
|
101
|
+
"""询问大模型大量代码删除是否合理
|
|
102
|
+
|
|
103
|
+
参数:
|
|
104
|
+
detection_result: 检测结果字典,包含 'insertions', 'deletions', 'net_deletions'
|
|
105
|
+
preview: 补丁预览内容
|
|
106
|
+
|
|
107
|
+
返回:
|
|
108
|
+
bool: 如果大模型认为合理返回True,否则返回False
|
|
109
|
+
"""
|
|
110
|
+
insertions = detection_result["insertions"]
|
|
111
|
+
deletions = detection_result["deletions"]
|
|
112
|
+
net_deletions = detection_result["net_deletions"]
|
|
113
|
+
|
|
114
|
+
prompt = f"""检测到大量代码删除,请判断是否合理:
|
|
115
|
+
|
|
116
|
+
统计信息:
|
|
117
|
+
- 新增行数: {insertions}
|
|
118
|
+
- 删除行数: {deletions}
|
|
119
|
+
- 净删除行数: {net_deletions}
|
|
120
|
+
|
|
121
|
+
补丁预览:
|
|
122
|
+
{preview}
|
|
123
|
+
|
|
124
|
+
请仔细分析以上代码变更,判断这些大量代码删除是否合理。可能的情况包括:
|
|
125
|
+
1. 重构代码,删除冗余或过时的代码
|
|
126
|
+
2. 简化实现,用更简洁的代码替换复杂的实现
|
|
127
|
+
3. 删除未使用的代码或功能
|
|
128
|
+
4. 错误地删除了重要代码
|
|
129
|
+
|
|
130
|
+
请使用以下协议回答(必须包含且仅包含以下标记之一):
|
|
131
|
+
- 如果认为这些删除是合理的,回答: <!!!YES!!!>
|
|
132
|
+
- 如果认为这些删除不合理或存在风险,回答: <!!!NO!!!>
|
|
133
|
+
|
|
134
|
+
请严格按照协议格式回答,不要添加其他内容。
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
PrettyOutput.auto_print("🤖 正在询问大模型判断大量代码删除是否合理...")
|
|
139
|
+
# 每次调用都创建新的 LLM 实例,避免上下文窗口累积
|
|
140
|
+
llm_model = self._create_llm_model()
|
|
141
|
+
response = llm_model.chat_until_success(prompt)
|
|
142
|
+
|
|
143
|
+
# 使用确定的协议标记解析回答
|
|
144
|
+
if "<!!!YES!!!>" in response:
|
|
145
|
+
PrettyOutput.auto_print("✅ 大模型确认:代码删除合理")
|
|
146
|
+
return True
|
|
147
|
+
elif "<!!!NO!!!>" in response:
|
|
148
|
+
PrettyOutput.auto_print("⚠️ 大模型确认:代码删除不合理")
|
|
149
|
+
return False
|
|
150
|
+
else:
|
|
151
|
+
# 如果无法找到协议标记,默认认为不合理(保守策略)
|
|
152
|
+
PrettyOutput.auto_print(
|
|
153
|
+
f"⚠️ 无法找到协议标记,默认认为不合理。回答内容: {response[:200]}"
|
|
154
|
+
)
|
|
155
|
+
return False
|
|
156
|
+
except Exception as e:
|
|
157
|
+
# 如果询问失败,默认认为不合理(保守策略)
|
|
158
|
+
PrettyOutput.auto_print(f"⚠️ 询问大模型失败: {str(e)},默认认为不合理")
|
|
159
|
+
return False
|