jarvis-ai-assistant 0.7.0__py3-none-any.whl → 0.7.6__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 +243 -139
- jarvis/jarvis_agent/agent_manager.py +5 -10
- jarvis/jarvis_agent/builtin_input_handler.py +2 -6
- jarvis/jarvis_agent/config_editor.py +2 -7
- jarvis/jarvis_agent/event_bus.py +82 -12
- jarvis/jarvis_agent/file_context_handler.py +265 -15
- jarvis/jarvis_agent/file_methodology_manager.py +3 -4
- jarvis/jarvis_agent/jarvis.py +113 -98
- jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
- jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
- jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
- jarvis/jarvis_agent/language_support_info.py +486 -0
- jarvis/jarvis_agent/main.py +6 -12
- jarvis/jarvis_agent/memory_manager.py +7 -16
- jarvis/jarvis_agent/methodology_share_manager.py +10 -16
- jarvis/jarvis_agent/prompt_manager.py +1 -1
- jarvis/jarvis_agent/prompts.py +193 -171
- jarvis/jarvis_agent/protocols.py +8 -12
- jarvis/jarvis_agent/run_loop.py +77 -14
- jarvis/jarvis_agent/session_manager.py +2 -3
- jarvis/jarvis_agent/share_manager.py +12 -21
- jarvis/jarvis_agent/shell_input_handler.py +1 -2
- jarvis/jarvis_agent/task_analyzer.py +26 -4
- jarvis/jarvis_agent/task_manager.py +11 -27
- jarvis/jarvis_agent/tool_executor.py +2 -3
- jarvis/jarvis_agent/tool_share_manager.py +12 -24
- jarvis/jarvis_agent/web_server.py +55 -20
- jarvis/jarvis_c2rust/__init__.py +5 -5
- jarvis/jarvis_c2rust/cli.py +461 -499
- jarvis/jarvis_c2rust/collector.py +45 -53
- jarvis/jarvis_c2rust/constants.py +26 -0
- jarvis/jarvis_c2rust/library_replacer.py +264 -132
- jarvis/jarvis_c2rust/llm_module_agent.py +162 -190
- jarvis/jarvis_c2rust/loaders.py +207 -0
- jarvis/jarvis_c2rust/models.py +28 -0
- jarvis/jarvis_c2rust/optimizer.py +1592 -395
- jarvis/jarvis_c2rust/transpiler.py +1722 -1064
- jarvis/jarvis_c2rust/utils.py +385 -0
- jarvis/jarvis_code_agent/build_validation_config.py +2 -3
- jarvis/jarvis_code_agent/code_agent.py +394 -320
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +3 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +4 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +17 -2
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +3 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +36 -4
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +9 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +9 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +12 -1
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +22 -5
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +57 -32
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +62 -6
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +8 -9
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +290 -5
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +21 -3
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +72 -4
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +35 -3
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +52 -2
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +73 -1
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +306 -152
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +193 -18
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +18 -8
- jarvis/jarvis_code_agent/lint.py +258 -27
- jarvis/jarvis_code_agent/utils.py +0 -1
- jarvis/jarvis_code_analysis/code_review.py +19 -24
- jarvis/jarvis_data/config_schema.json +53 -26
- jarvis/jarvis_git_squash/main.py +4 -5
- jarvis/jarvis_git_utils/git_commiter.py +44 -49
- jarvis/jarvis_mcp/sse_mcp_client.py +20 -27
- jarvis/jarvis_mcp/stdio_mcp_client.py +11 -12
- jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
- jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
- jarvis/jarvis_methodology/main.py +32 -48
- jarvis/jarvis_multi_agent/__init__.py +79 -61
- jarvis/jarvis_multi_agent/main.py +3 -7
- jarvis/jarvis_platform/base.py +469 -199
- jarvis/jarvis_platform/human.py +7 -8
- jarvis/jarvis_platform/kimi.py +30 -36
- jarvis/jarvis_platform/openai.py +65 -27
- jarvis/jarvis_platform/registry.py +26 -10
- jarvis/jarvis_platform/tongyi.py +24 -25
- jarvis/jarvis_platform/yuanbao.py +31 -42
- jarvis/jarvis_platform_manager/main.py +66 -77
- jarvis/jarvis_platform_manager/service.py +8 -13
- jarvis/jarvis_rag/cli.py +49 -51
- jarvis/jarvis_rag/embedding_manager.py +13 -18
- jarvis/jarvis_rag/llm_interface.py +8 -9
- jarvis/jarvis_rag/query_rewriter.py +10 -21
- jarvis/jarvis_rag/rag_pipeline.py +24 -27
- jarvis/jarvis_rag/reranker.py +4 -5
- jarvis/jarvis_rag/retriever.py +28 -30
- jarvis/jarvis_sec/__init__.py +220 -3520
- jarvis/jarvis_sec/agents.py +143 -0
- jarvis/jarvis_sec/analysis.py +276 -0
- jarvis/jarvis_sec/cli.py +29 -6
- jarvis/jarvis_sec/clustering.py +1439 -0
- jarvis/jarvis_sec/file_manager.py +427 -0
- jarvis/jarvis_sec/parsers.py +73 -0
- jarvis/jarvis_sec/prompts.py +268 -0
- jarvis/jarvis_sec/report.py +83 -4
- jarvis/jarvis_sec/review.py +453 -0
- jarvis/jarvis_sec/utils.py +499 -0
- jarvis/jarvis_sec/verification.py +848 -0
- jarvis/jarvis_sec/workflow.py +7 -0
- jarvis/jarvis_smart_shell/main.py +38 -87
- jarvis/jarvis_stats/cli.py +1 -1
- jarvis/jarvis_stats/stats.py +7 -7
- jarvis/jarvis_stats/storage.py +15 -21
- jarvis/jarvis_tools/clear_memory.py +3 -20
- jarvis/jarvis_tools/cli/main.py +20 -23
- jarvis/jarvis_tools/edit_file.py +1066 -0
- jarvis/jarvis_tools/execute_script.py +42 -21
- jarvis/jarvis_tools/file_analyzer.py +6 -9
- jarvis/jarvis_tools/generate_new_tool.py +11 -20
- jarvis/jarvis_tools/lsp_client.py +1552 -0
- jarvis/jarvis_tools/methodology.py +2 -3
- jarvis/jarvis_tools/read_code.py +1525 -87
- jarvis/jarvis_tools/read_symbols.py +2 -3
- jarvis/jarvis_tools/read_webpage.py +7 -10
- jarvis/jarvis_tools/registry.py +370 -181
- jarvis/jarvis_tools/retrieve_memory.py +20 -19
- jarvis/jarvis_tools/rewrite_file.py +105 -0
- jarvis/jarvis_tools/save_memory.py +3 -15
- jarvis/jarvis_tools/search_web.py +3 -7
- jarvis/jarvis_tools/sub_agent.py +17 -6
- jarvis/jarvis_tools/sub_code_agent.py +14 -16
- jarvis/jarvis_tools/virtual_tty.py +54 -32
- jarvis/jarvis_utils/clipboard.py +7 -10
- jarvis/jarvis_utils/config.py +98 -63
- jarvis/jarvis_utils/embedding.py +5 -5
- jarvis/jarvis_utils/fzf.py +8 -8
- jarvis/jarvis_utils/git_utils.py +81 -67
- jarvis/jarvis_utils/input.py +24 -49
- jarvis/jarvis_utils/jsonnet_compat.py +465 -0
- jarvis/jarvis_utils/methodology.py +33 -35
- jarvis/jarvis_utils/utils.py +245 -202
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/METADATA +205 -70
- jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
- jarvis/jarvis_agent/edit_file_handler.py +0 -584
- jarvis/jarvis_agent/rewrite_file_handler.py +0 -141
- jarvis/jarvis_agent/task_planner.py +0 -496
- jarvis/jarvis_platform/ai8.py +0 -332
- jarvis/jarvis_tools/ask_user.py +0 -54
- jarvis_ai_assistant-0.7.0.dist-info/RECORD +0 -192
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/config.py
CHANGED
|
@@ -63,13 +63,7 @@ def get_replace_map() -> dict:
|
|
|
63
63
|
if not os.path.exists(replace_map_path):
|
|
64
64
|
return BUILTIN_REPLACE_MAP.copy()
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
PrettyOutput.print(
|
|
69
|
-
"警告:使用replace_map.yaml进行配置的方式已被弃用,将在未来版本中移除。"
|
|
70
|
-
"请迁移到使用GLOBAL_CONFIG_DATA中的JARVIS_REPLACE_MAP配置。",
|
|
71
|
-
output_type=OutputType.WARNING,
|
|
72
|
-
)
|
|
66
|
+
print("⚠️ 警告:使用replace_map.yaml进行配置的方式已被弃用,将在未来版本中移除。请迁移到使用GLOBAL_CONFIG_DATA中的JARVIS_REPLACE_MAP配置。")
|
|
73
67
|
|
|
74
68
|
with open(replace_map_path, "r", encoding="utf-8", errors="ignore") as file:
|
|
75
69
|
file_map = yaml.safe_load(file) or {}
|
|
@@ -139,10 +133,24 @@ def _get_resolved_model_config(
|
|
|
139
133
|
model_groups = GLOBAL_CONFIG_DATA.get("JARVIS_LLM_GROUPS", [])
|
|
140
134
|
|
|
141
135
|
if model_group_name and isinstance(model_groups, list):
|
|
136
|
+
found = False
|
|
142
137
|
for group_item in model_groups:
|
|
143
138
|
if isinstance(group_item, dict) and model_group_name in group_item:
|
|
144
139
|
group_config = group_item[model_group_name]
|
|
140
|
+
found = True
|
|
145
141
|
break
|
|
142
|
+
|
|
143
|
+
# 当显式指定了模型组但未找到时,报错并退出
|
|
144
|
+
if model_group_override and not found:
|
|
145
|
+
print(f"❌ 错误:指定的模型组 '{model_group_name}' 不存在于配置中。")
|
|
146
|
+
print("ℹ️ 可用的模型组: " +
|
|
147
|
+
", ".join(
|
|
148
|
+
list(group.keys())[0]
|
|
149
|
+
for group in model_groups
|
|
150
|
+
if isinstance(group, dict)
|
|
151
|
+
) if model_groups else "无可用模型组")
|
|
152
|
+
import sys
|
|
153
|
+
sys.exit(1)
|
|
146
154
|
|
|
147
155
|
_apply_llm_group_env_override(group_config)
|
|
148
156
|
|
|
@@ -157,6 +165,10 @@ def _get_resolved_model_config(
|
|
|
157
165
|
"JARVIS_PLATFORM",
|
|
158
166
|
"JARVIS_MODEL",
|
|
159
167
|
"JARVIS_MAX_INPUT_TOKEN_COUNT",
|
|
168
|
+
"JARVIS_CHEAP_PLATFORM",
|
|
169
|
+
"JARVIS_CHEAP_MODEL",
|
|
170
|
+
"JARVIS_SMART_PLATFORM",
|
|
171
|
+
"JARVIS_SMART_MODEL",
|
|
160
172
|
]
|
|
161
173
|
for key in override_keys:
|
|
162
174
|
if key in GLOBAL_CONFIG_DATA:
|
|
@@ -176,10 +188,10 @@ def get_normal_platform_name(model_group_override: Optional[str] = None) -> str:
|
|
|
176
188
|
获取正常操作的平台名称。
|
|
177
189
|
|
|
178
190
|
返回:
|
|
179
|
-
str: 平台名称,默认为'
|
|
191
|
+
str: 平台名称,默认为'openai'
|
|
180
192
|
"""
|
|
181
193
|
config = _get_resolved_model_config(model_group_override)
|
|
182
|
-
return cast(str, config.get("JARVIS_PLATFORM", "
|
|
194
|
+
return cast(str, config.get("JARVIS_PLATFORM", "openai"))
|
|
183
195
|
|
|
184
196
|
|
|
185
197
|
def get_normal_model_name(model_group_override: Optional[str] = None) -> str:
|
|
@@ -187,10 +199,10 @@ def get_normal_model_name(model_group_override: Optional[str] = None) -> str:
|
|
|
187
199
|
获取正常操作的模型名称。
|
|
188
200
|
|
|
189
201
|
返回:
|
|
190
|
-
str: 模型名称,默认为'
|
|
202
|
+
str: 模型名称,默认为'gpt-5'
|
|
191
203
|
"""
|
|
192
204
|
config = _get_resolved_model_config(model_group_override)
|
|
193
|
-
return cast(str, config.get("JARVIS_MODEL", "
|
|
205
|
+
return cast(str, config.get("JARVIS_MODEL", "gpt-5"))
|
|
194
206
|
|
|
195
207
|
|
|
196
208
|
def _deprecated_platform_name_v1(model_group_override: Optional[str] = None) -> str:
|
|
@@ -217,6 +229,62 @@ def _deprecated_model_name_v1(model_group_override: Optional[str] = None) -> str
|
|
|
217
229
|
return get_normal_model_name(model_group_override)
|
|
218
230
|
|
|
219
231
|
|
|
232
|
+
def get_cheap_platform_name(model_group_override: Optional[str] = None) -> str:
|
|
233
|
+
"""
|
|
234
|
+
获取廉价操作的平台名称。
|
|
235
|
+
|
|
236
|
+
返回:
|
|
237
|
+
str: 平台名称,如果未配置则回退到正常操作平台
|
|
238
|
+
"""
|
|
239
|
+
config = _get_resolved_model_config(model_group_override)
|
|
240
|
+
cheap_platform = config.get("JARVIS_CHEAP_PLATFORM")
|
|
241
|
+
if cheap_platform:
|
|
242
|
+
return cast(str, cheap_platform)
|
|
243
|
+
return get_normal_platform_name(model_group_override)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def get_cheap_model_name(model_group_override: Optional[str] = None) -> str:
|
|
247
|
+
"""
|
|
248
|
+
获取廉价操作的模型名称。
|
|
249
|
+
|
|
250
|
+
返回:
|
|
251
|
+
str: 模型名称,如果未配置则回退到正常操作模型
|
|
252
|
+
"""
|
|
253
|
+
config = _get_resolved_model_config(model_group_override)
|
|
254
|
+
cheap_model = config.get("JARVIS_CHEAP_MODEL")
|
|
255
|
+
if cheap_model:
|
|
256
|
+
return cast(str, cheap_model)
|
|
257
|
+
return get_normal_model_name(model_group_override)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def get_smart_platform_name(model_group_override: Optional[str] = None) -> str:
|
|
261
|
+
"""
|
|
262
|
+
获取智能操作的平台名称。
|
|
263
|
+
|
|
264
|
+
返回:
|
|
265
|
+
str: 平台名称,如果未配置则回退到正常操作平台
|
|
266
|
+
"""
|
|
267
|
+
config = _get_resolved_model_config(model_group_override)
|
|
268
|
+
smart_platform = config.get("JARVIS_SMART_PLATFORM")
|
|
269
|
+
if smart_platform:
|
|
270
|
+
return cast(str, smart_platform)
|
|
271
|
+
return get_normal_platform_name(model_group_override)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def get_smart_model_name(model_group_override: Optional[str] = None) -> str:
|
|
275
|
+
"""
|
|
276
|
+
获取智能操作的模型名称。
|
|
277
|
+
|
|
278
|
+
返回:
|
|
279
|
+
str: 模型名称,如果未配置则回退到正常操作模型
|
|
280
|
+
"""
|
|
281
|
+
config = _get_resolved_model_config(model_group_override)
|
|
282
|
+
smart_model = config.get("JARVIS_SMART_MODEL")
|
|
283
|
+
if smart_model:
|
|
284
|
+
return cast(str, smart_model)
|
|
285
|
+
return get_normal_model_name(model_group_override)
|
|
286
|
+
|
|
287
|
+
|
|
220
288
|
def is_execute_tool_confirm() -> bool:
|
|
221
289
|
"""
|
|
222
290
|
检查工具执行是否需要确认。
|
|
@@ -237,28 +305,11 @@ def is_confirm_before_apply_patch() -> bool:
|
|
|
237
305
|
return cast(bool, GLOBAL_CONFIG_DATA.get("JARVIS_CONFIRM_BEFORE_APPLY_PATCH", False))
|
|
238
306
|
|
|
239
307
|
|
|
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"
|
|
255
|
-
|
|
256
|
-
|
|
257
308
|
def get_data_dir() -> str:
|
|
258
309
|
"""
|
|
259
310
|
获取Jarvis数据存储目录路径。
|
|
260
311
|
|
|
261
|
-
返回:
|
|
312
|
+
返回:
|
|
262
313
|
str: 数据目录路径,优先从JARVIS_DATA_PATH环境变量获取,
|
|
263
314
|
如果未设置或为空,则使用~/.jarvis作为默认值
|
|
264
315
|
"""
|
|
@@ -730,40 +781,6 @@ def get_tool_filter_threshold() -> int:
|
|
|
730
781
|
"""
|
|
731
782
|
return int(GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_FILTER_THRESHOLD", 30))
|
|
732
783
|
|
|
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
784
|
|
|
768
785
|
|
|
769
786
|
|
|
@@ -871,3 +888,21 @@ def is_enable_intent_recognition() -> bool:
|
|
|
871
888
|
bool: 是否启用意图识别,默认为True(可通过 GLOBAL_CONFIG_DATA['JARVIS_ENABLE_INTENT_RECOGNITION'] 配置)
|
|
872
889
|
"""
|
|
873
890
|
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_INTENT_RECOGNITION", True) is True
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
def is_enable_memory_organizer() -> bool:
|
|
894
|
+
"""
|
|
895
|
+
获取是否启用自动记忆整理功能。
|
|
896
|
+
|
|
897
|
+
返回:
|
|
898
|
+
bool: 是否启用自动记忆整理,默认为False(可通过 GLOBAL_CONFIG_DATA['JARVIS_ENABLE_MEMORY_ORGANIZER'] 配置)
|
|
899
|
+
"""
|
|
900
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_MEMORY_ORGANIZER", False) is True
|
|
901
|
+
def get_conversation_turn_threshold() -> int:
|
|
902
|
+
"""
|
|
903
|
+
获取对话轮次阈值,用于触发总结。
|
|
904
|
+
|
|
905
|
+
返回:
|
|
906
|
+
int: 对话轮次阈值,默认为50
|
|
907
|
+
"""
|
|
908
|
+
return int(GLOBAL_CONFIG_DATA.get("JARVIS_CONVERSATION_TURN_THRESHOLD", 50))
|
jarvis/jarvis_utils/embedding.py
CHANGED
|
@@ -3,7 +3,6 @@ import os
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import List
|
|
5
5
|
|
|
6
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
6
|
|
|
8
7
|
# 设置tiktoken缓存目录
|
|
9
8
|
script_dir = Path(__file__).parent
|
|
@@ -28,10 +27,11 @@ def get_context_token_count(text: str) -> int:
|
|
|
28
27
|
import tiktoken
|
|
29
28
|
|
|
30
29
|
encoding = tiktoken.get_encoding("cl100k_base")
|
|
31
|
-
|
|
30
|
+
# 调整token计算为原来的10/7倍
|
|
31
|
+
return int(len(encoding.encode(text)) * 10 / 7)
|
|
32
32
|
except Exception as e:
|
|
33
|
-
|
|
34
|
-
return len(text) // 4 # 每个token大约4
|
|
33
|
+
print(f"⚠️ 计算token失败: {str(e)}")
|
|
34
|
+
return int(len(text) // 4 * 10 / 7) # 每个token大约4个字符的粗略估计,调整为10/7倍
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def split_text_into_chunks(
|
|
@@ -80,6 +80,6 @@ def split_text_into_chunks(
|
|
|
80
80
|
return chunks
|
|
81
81
|
|
|
82
82
|
except Exception as e:
|
|
83
|
-
|
|
83
|
+
print(f"⚠️ 文本分割失败: {str(e)}")
|
|
84
84
|
# 发生错误时回退到简单的字符分割
|
|
85
85
|
return [text[i : i + max_length] for i in range(0, len(text), max_length)]
|
jarvis/jarvis_utils/fzf.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
"""FZF
|
|
2
|
+
"""FZF选择器工具。"""
|
|
3
3
|
import shutil
|
|
4
4
|
import subprocess
|
|
5
5
|
from typing import List, Optional, Union, Dict, Any, cast
|
|
@@ -10,15 +10,15 @@ def fzf_select(
|
|
|
10
10
|
key: Optional[str] = None,
|
|
11
11
|
) -> Optional[str]:
|
|
12
12
|
"""
|
|
13
|
-
|
|
13
|
+
使用fzf从列表中选择一个项目。
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
options:
|
|
17
|
-
prompt:
|
|
18
|
-
key:
|
|
15
|
+
参数:
|
|
16
|
+
options: 可供选择的字符串或字典列表。
|
|
17
|
+
prompt: 在fzf中显示的提示信息。
|
|
18
|
+
key: 如果options是字典列表,则此参数指定要显示的键名。
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
返回:
|
|
21
|
+
选中的项目,如果fzf不可用或选择被取消则返回None。
|
|
22
22
|
"""
|
|
23
23
|
if shutil.which("fzf") is None:
|
|
24
24
|
return None
|
jarvis/jarvis_utils/git_utils.py
CHANGED
|
@@ -17,7 +17,6 @@ import sys
|
|
|
17
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
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
21
20
|
from jarvis.jarvis_utils.input import user_confirm
|
|
22
21
|
from jarvis.jarvis_utils.utils import is_rag_installed
|
|
23
22
|
|
|
@@ -111,7 +110,7 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
|
|
|
111
110
|
)
|
|
112
111
|
if result.returncode != 0:
|
|
113
112
|
error_msg = result.stderr.decode("utf-8", errors="replace")
|
|
114
|
-
|
|
113
|
+
print(f"❌ 获取commit历史失败: {error_msg}")
|
|
115
114
|
return []
|
|
116
115
|
|
|
117
116
|
output = result.stdout.decode("utf-8", errors="replace")
|
|
@@ -123,7 +122,7 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
|
|
|
123
122
|
return commits
|
|
124
123
|
|
|
125
124
|
except Exception as e:
|
|
126
|
-
|
|
125
|
+
print(f"❌ 获取commit历史异常: {str(e)}")
|
|
127
126
|
return []
|
|
128
127
|
|
|
129
128
|
|
|
@@ -172,6 +171,59 @@ def get_diff() -> str:
|
|
|
172
171
|
return f"发生意外错误: {str(e)}"
|
|
173
172
|
|
|
174
173
|
|
|
174
|
+
def get_diff_between_commits(start_hash: str, end_hash: Optional[str] = None) -> str:
|
|
175
|
+
"""获取两个commit之间的差异
|
|
176
|
+
|
|
177
|
+
参数:
|
|
178
|
+
start_hash: 起始commit哈希值(不包含)
|
|
179
|
+
end_hash: 结束commit哈希值(包含),如果为None则使用HEAD
|
|
180
|
+
|
|
181
|
+
返回:
|
|
182
|
+
str: 差异内容或错误信息
|
|
183
|
+
"""
|
|
184
|
+
try:
|
|
185
|
+
if end_hash is None:
|
|
186
|
+
# 如果end_hash为None,使用HEAD
|
|
187
|
+
end_hash = "HEAD"
|
|
188
|
+
|
|
189
|
+
# 检查start_hash是否存在
|
|
190
|
+
start_check = subprocess.run(
|
|
191
|
+
["git", "rev-parse", "--verify", start_hash],
|
|
192
|
+
stderr=subprocess.PIPE,
|
|
193
|
+
stdout=subprocess.PIPE,
|
|
194
|
+
)
|
|
195
|
+
if start_check.returncode != 0:
|
|
196
|
+
return f"起始commit不存在: {start_hash}"
|
|
197
|
+
|
|
198
|
+
# 检查end_hash是否存在
|
|
199
|
+
end_check = subprocess.run(
|
|
200
|
+
["git", "rev-parse", "--verify", end_hash],
|
|
201
|
+
stderr=subprocess.PIPE,
|
|
202
|
+
stdout=subprocess.PIPE,
|
|
203
|
+
)
|
|
204
|
+
if end_check.returncode != 0:
|
|
205
|
+
return f"结束commit不存在: {end_hash}"
|
|
206
|
+
|
|
207
|
+
# 获取两个commit之间的差异
|
|
208
|
+
result = subprocess.run(
|
|
209
|
+
["git", "diff", f"{start_hash}..{end_hash}"],
|
|
210
|
+
capture_output=True,
|
|
211
|
+
text=False,
|
|
212
|
+
check=True,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
return result.stdout.decode("utf-8")
|
|
217
|
+
except UnicodeDecodeError:
|
|
218
|
+
return result.stdout.decode("utf-8", errors="replace")
|
|
219
|
+
|
|
220
|
+
except subprocess.CalledProcessError as e:
|
|
221
|
+
error_msg = e.stderr.decode("utf-8", errors="replace") if e.stderr else str(e)
|
|
222
|
+
return f"获取commit差异失败: {error_msg}"
|
|
223
|
+
except Exception as e:
|
|
224
|
+
return f"发生意外错误: {str(e)}"
|
|
225
|
+
|
|
226
|
+
|
|
175
227
|
def revert_file(filepath: str) -> None:
|
|
176
228
|
"""增强版git恢复,处理新文件"""
|
|
177
229
|
import subprocess
|
|
@@ -191,7 +243,7 @@ def revert_file(filepath: str) -> None:
|
|
|
191
243
|
subprocess.run(["git", "clean", "-f", "--", filepath], check=True)
|
|
192
244
|
except subprocess.CalledProcessError as e:
|
|
193
245
|
error_msg = e.stderr.decode("utf-8", errors="replace") if e.stderr else str(e)
|
|
194
|
-
|
|
246
|
+
print(f"❌ 恢复文件失败: {error_msg}")
|
|
195
247
|
|
|
196
248
|
|
|
197
249
|
# 修改后的恢复函数
|
|
@@ -212,10 +264,10 @@ def revert_change() -> None:
|
|
|
212
264
|
subprocess.run(["git", "reset", "--hard", "HEAD"], check=True)
|
|
213
265
|
subprocess.run(["git", "clean", "-fd"], check=True)
|
|
214
266
|
except subprocess.CalledProcessError as e:
|
|
215
|
-
|
|
267
|
+
print(f"❌ 恢复更改失败: {str(e)}")
|
|
216
268
|
|
|
217
269
|
|
|
218
|
-
def detect_large_code_deletion(threshold: int =
|
|
270
|
+
def detect_large_code_deletion(threshold: int = 30) -> Optional[Dict[str, int]]:
|
|
219
271
|
"""检测是否有大量代码删除
|
|
220
272
|
|
|
221
273
|
参数:
|
|
@@ -290,49 +342,23 @@ def detect_large_code_deletion(threshold: int = 200) -> Optional[Dict[str, int]]
|
|
|
290
342
|
return None
|
|
291
343
|
|
|
292
344
|
|
|
293
|
-
|
|
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
|
|
345
|
+
# confirm_large_code_deletion函数已废弃,统一使用大模型询问
|
|
320
346
|
|
|
321
347
|
|
|
322
|
-
def check_large_code_deletion(threshold: int =
|
|
323
|
-
"""
|
|
348
|
+
def check_large_code_deletion(threshold: int = 30) -> bool:
|
|
349
|
+
"""检查是否有大量代码删除
|
|
324
350
|
|
|
325
351
|
参数:
|
|
326
352
|
threshold: 净删除行数阈值,默认200行
|
|
327
353
|
|
|
328
354
|
返回:
|
|
329
|
-
bool:
|
|
355
|
+
bool: 始终返回True,由调用方统一处理大模型询问
|
|
330
356
|
"""
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
return True
|
|
357
|
+
# 检测功能现在由调用方统一处理
|
|
358
|
+
return True
|
|
334
359
|
|
|
335
|
-
|
|
360
|
+
# 直接返回True,让调用方统一处理大模型询问
|
|
361
|
+
return True
|
|
336
362
|
|
|
337
363
|
|
|
338
364
|
def handle_commit_workflow() -> bool:
|
|
@@ -530,23 +556,17 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
|
530
556
|
and remote_tag_result.returncode == 0
|
|
531
557
|
and local_tag_result.stdout.strip() != remote_tag_result.stdout.strip()
|
|
532
558
|
):
|
|
533
|
-
|
|
534
|
-
f"检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...",
|
|
535
|
-
OutputType.INFO,
|
|
536
|
-
)
|
|
559
|
+
print(f"ℹ️ 检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...")
|
|
537
560
|
subprocess.run(
|
|
538
561
|
["git", "checkout", remote_tag_result.stdout.strip()],
|
|
539
562
|
cwd=git_root,
|
|
540
563
|
check=True,
|
|
541
564
|
)
|
|
542
|
-
|
|
543
|
-
f"Jarvis已更新到tag {remote_tag_result.stdout.strip()}",
|
|
544
|
-
OutputType.SUCCESS,
|
|
545
|
-
)
|
|
565
|
+
print(f"✅ Jarvis已更新到tag {remote_tag_result.stdout.strip()}")
|
|
546
566
|
|
|
547
567
|
# 执行pip安装更新代码
|
|
548
568
|
try:
|
|
549
|
-
|
|
569
|
+
print("ℹ️ 正在安装更新后的代码...")
|
|
550
570
|
|
|
551
571
|
# 检查是否在虚拟环境中
|
|
552
572
|
in_venv = hasattr(sys, "real_prefix") or (
|
|
@@ -603,7 +623,7 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
|
603
623
|
)
|
|
604
624
|
|
|
605
625
|
if result.returncode == 0:
|
|
606
|
-
|
|
626
|
+
print("✅ 代码更新安装成功")
|
|
607
627
|
return True
|
|
608
628
|
|
|
609
629
|
# 处理权限错误
|
|
@@ -621,23 +641,21 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
|
621
641
|
text=True,
|
|
622
642
|
)
|
|
623
643
|
if user_result.returncode == 0:
|
|
624
|
-
|
|
644
|
+
print("✅ 用户级代码安装成功")
|
|
625
645
|
return True
|
|
626
646
|
error_msg = user_result.stderr.strip()
|
|
627
647
|
|
|
628
|
-
|
|
648
|
+
print(f"❌ 代码安装失败: {error_msg}")
|
|
629
649
|
return False
|
|
630
650
|
except Exception as e:
|
|
631
|
-
|
|
632
|
-
f"安装过程中发生意外错误: {str(e)}", OutputType.ERROR
|
|
633
|
-
)
|
|
651
|
+
print(f"❌ 安装过程中发生意外错误: {str(e)}")
|
|
634
652
|
return False
|
|
635
653
|
# 更新检查日期文件
|
|
636
654
|
with open(last_check_file, "w") as f:
|
|
637
655
|
f.write(today_str)
|
|
638
656
|
return False
|
|
639
657
|
except Exception as e:
|
|
640
|
-
|
|
658
|
+
print(f"⚠️ Git仓库更新检查失败: {e}")
|
|
641
659
|
return False
|
|
642
660
|
finally:
|
|
643
661
|
os.chdir(curr_dir)
|
|
@@ -664,18 +682,16 @@ def get_diff_file_list() -> List[str]:
|
|
|
664
682
|
subprocess.run(["git", "reset"], check=True)
|
|
665
683
|
|
|
666
684
|
if result.returncode != 0:
|
|
667
|
-
|
|
668
|
-
f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR
|
|
669
|
-
)
|
|
685
|
+
print(f"❌ 获取差异文件列表失败: {result.stderr}")
|
|
670
686
|
return []
|
|
671
687
|
|
|
672
688
|
return [f for f in result.stdout.splitlines() if f]
|
|
673
689
|
|
|
674
690
|
except subprocess.CalledProcessError as e:
|
|
675
|
-
|
|
691
|
+
print(f"❌ 获取差异文件列表失败: {str(e)}")
|
|
676
692
|
return []
|
|
677
693
|
except Exception as e:
|
|
678
|
-
|
|
694
|
+
print(f"❌ 获取差异文件列表异常: {str(e)}")
|
|
679
695
|
return []
|
|
680
696
|
|
|
681
697
|
|
|
@@ -824,10 +840,8 @@ def confirm_add_new_files() -> None:
|
|
|
824
840
|
need_confirm = True
|
|
825
841
|
|
|
826
842
|
if output_lines:
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
OutputType.WARNING if need_confirm else OutputType.INFO,
|
|
830
|
-
)
|
|
843
|
+
emoji = "⚠️ " if need_confirm else "ℹ️ "
|
|
844
|
+
print(emoji + ("\n" + emoji).join(output_lines))
|
|
831
845
|
|
|
832
846
|
return need_confirm
|
|
833
847
|
|
|
@@ -878,9 +892,9 @@ def confirm_add_new_files() -> None:
|
|
|
878
892
|
entry = rel_path if not rel_path.startswith("..") else file
|
|
879
893
|
if entry not in existing_lines:
|
|
880
894
|
f.write(entry + "\n")
|
|
881
|
-
|
|
895
|
+
print("ℹ️ 已将未跟踪文件添加到 .gitignore,正在重新检测...")
|
|
882
896
|
except Exception as e:
|
|
883
|
-
|
|
897
|
+
print(f"⚠️ 更新 .gitignore 失败: {str(e)}")
|
|
884
898
|
|
|
885
899
|
continue
|
|
886
900
|
|