jarvis-ai-assistant 0.7.16__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.16.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.16.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
"""
|
|
3
2
|
方法论导入导出命令行工具
|
|
4
3
|
|
|
@@ -10,23 +9,25 @@
|
|
|
10
9
|
|
|
11
10
|
import hashlib
|
|
12
11
|
import json
|
|
12
|
+
|
|
13
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
14
|
+
|
|
15
|
+
# -*- coding: utf-8 -*-
|
|
13
16
|
import os
|
|
14
17
|
|
|
15
18
|
import typer
|
|
16
|
-
import yaml
|
|
19
|
+
import yaml
|
|
17
20
|
|
|
18
21
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
19
|
-
from jarvis.jarvis_utils.methodology import
|
|
20
|
-
|
|
21
|
-
_load_all_methodologies,
|
|
22
|
-
)
|
|
22
|
+
from jarvis.jarvis_utils.methodology import _get_methodology_directory
|
|
23
|
+
from jarvis.jarvis_utils.methodology import _load_all_methodologies
|
|
23
24
|
|
|
24
25
|
app = typer.Typer(help="方法论管理工具")
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
@app.command("import")
|
|
28
29
|
def import_methodology(
|
|
29
|
-
input_file: str = typer.Argument(..., help="要导入的方法论文件路径")
|
|
30
|
+
input_file: str = typer.Argument(..., help="要导入的方法论文件路径"),
|
|
30
31
|
):
|
|
31
32
|
"""导入方法论文件(合并策略)"""
|
|
32
33
|
try:
|
|
@@ -54,9 +55,11 @@ def import_methodology(
|
|
|
54
55
|
indent=2,
|
|
55
56
|
)
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
PrettyOutput.auto_print(
|
|
59
|
+
f"✅ 成功导入 {len(import_data)} 个方法论(总计 {len(merged_data)} 个)"
|
|
60
|
+
)
|
|
58
61
|
except (ValueError, OSError) as e:
|
|
59
|
-
|
|
62
|
+
PrettyOutput.auto_print(f"❌ 导入失败: {str(e)}")
|
|
60
63
|
raise typer.Exit(code=1)
|
|
61
64
|
|
|
62
65
|
|
|
@@ -69,9 +72,11 @@ def export_methodology(output_file: str = typer.Argument(..., help="导出文件
|
|
|
69
72
|
with open(output_file, "w", encoding="utf-8") as f:
|
|
70
73
|
json.dump(methodologies, f, ensure_ascii=False, indent=2)
|
|
71
74
|
|
|
72
|
-
|
|
75
|
+
PrettyOutput.auto_print(
|
|
76
|
+
f"✅ 成功导出 {len(methodologies)} 个方法论到 {output_file}"
|
|
77
|
+
)
|
|
73
78
|
except (OSError, TypeError) as e:
|
|
74
|
-
|
|
79
|
+
PrettyOutput.auto_print(f"❌ 导出失败: {str(e)}")
|
|
75
80
|
raise typer.Exit(code=1)
|
|
76
81
|
|
|
77
82
|
|
|
@@ -82,23 +87,23 @@ def list_methodologies():
|
|
|
82
87
|
methodologies = _load_all_methodologies()
|
|
83
88
|
|
|
84
89
|
if not methodologies:
|
|
85
|
-
|
|
90
|
+
PrettyOutput.auto_print("ℹ️ 没有找到方法论")
|
|
86
91
|
return
|
|
87
92
|
|
|
88
93
|
# 先拼接再统一打印,避免在循环中逐条输出造成信息稀疏
|
|
89
94
|
lines = ["可用方法论:"]
|
|
90
95
|
for i, (problem_type, _) in enumerate(methodologies.items(), 1):
|
|
91
96
|
lines.append(f"{i}. {problem_type}")
|
|
92
|
-
joined_lines =
|
|
93
|
-
|
|
97
|
+
joined_lines = "\n".join(lines)
|
|
98
|
+
PrettyOutput.auto_print(f"ℹ️ {joined_lines}")
|
|
94
99
|
except (OSError, ValueError) as e:
|
|
95
|
-
|
|
100
|
+
PrettyOutput.auto_print(f"❌ 列出方法论失败: {str(e)}")
|
|
96
101
|
raise typer.Exit(code=1)
|
|
97
102
|
|
|
98
103
|
|
|
99
104
|
@app.command("extract")
|
|
100
105
|
def extract_methodology(
|
|
101
|
-
input_file: str = typer.Argument(..., help="要提取方法论的文本文件路径")
|
|
106
|
+
input_file: str = typer.Argument(..., help="要提取方法论的文本文件路径"),
|
|
102
107
|
):
|
|
103
108
|
"""从文本文件中提取方法论"""
|
|
104
109
|
try:
|
|
@@ -138,20 +143,20 @@ def extract_methodology(
|
|
|
138
143
|
"""
|
|
139
144
|
|
|
140
145
|
# 调用大模型平台提取方法论
|
|
141
|
-
|
|
146
|
+
PrettyOutput.auto_print("ℹ️ 正在提取方法论...")
|
|
142
147
|
try:
|
|
143
148
|
response = platform.chat_until_success(prompt)
|
|
144
149
|
except Exception as e:
|
|
145
|
-
|
|
146
|
-
|
|
150
|
+
PrettyOutput.auto_print("❌ 提取失败")
|
|
151
|
+
PrettyOutput.auto_print(f"❌ 提取方法论失败: {str(e)}")
|
|
147
152
|
raise typer.Exit(code=1)
|
|
148
153
|
|
|
149
154
|
# 提取YAML部分
|
|
150
155
|
methodologies_start = response.find("<methodologies>") + len("<methodologies>")
|
|
151
156
|
methodologies_end = response.find("</methodologies>")
|
|
152
157
|
if methodologies_start == -1 or methodologies_end == -1:
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
PrettyOutput.auto_print("❌ 响应格式无效")
|
|
159
|
+
PrettyOutput.auto_print("❌ 大模型未返回有效的<methodologies>格式")
|
|
155
160
|
raise typer.Exit(code=1)
|
|
156
161
|
|
|
157
162
|
yaml_content = response[methodologies_start:methodologies_end].strip()
|
|
@@ -162,14 +167,14 @@ def extract_methodology(
|
|
|
162
167
|
item["problem_type"]: item["content"] for item in data
|
|
163
168
|
}
|
|
164
169
|
except (yaml.YAMLError, KeyError, TypeError) as e:
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
PrettyOutput.auto_print("❌ YAML解析失败")
|
|
171
|
+
PrettyOutput.auto_print(f"❌ YAML解析错误: {str(e)}")
|
|
167
172
|
raise typer.Exit(code=1)
|
|
168
173
|
|
|
169
174
|
if not extracted_methodologies:
|
|
170
|
-
|
|
175
|
+
PrettyOutput.auto_print("⚠️ 未提取到有效方法论")
|
|
171
176
|
return
|
|
172
|
-
|
|
177
|
+
PrettyOutput.auto_print("✅ 提取到有效方法论")
|
|
173
178
|
|
|
174
179
|
# 加载现有方法论
|
|
175
180
|
existing_methodologies = _load_all_methodologies()
|
|
@@ -191,15 +196,17 @@ def extract_methodology(
|
|
|
191
196
|
indent=2,
|
|
192
197
|
)
|
|
193
198
|
|
|
194
|
-
|
|
199
|
+
PrettyOutput.auto_print(
|
|
200
|
+
f"✅ 成功从文件提取 {len(extracted_methodologies)} 个方法论(总计 {len(merged_data)} 个)"
|
|
201
|
+
)
|
|
195
202
|
except Exception as e:
|
|
196
|
-
|
|
203
|
+
PrettyOutput.auto_print(f"❌ 提取失败: {str(e)}")
|
|
197
204
|
raise typer.Exit(code=1)
|
|
198
205
|
|
|
199
206
|
|
|
200
207
|
@app.command("extract-url")
|
|
201
208
|
def extract_methodology_from_url(
|
|
202
|
-
url: str = typer.Argument(..., help="要提取方法论的URL")
|
|
209
|
+
url: str = typer.Argument(..., help="要提取方法论的URL"),
|
|
203
210
|
):
|
|
204
211
|
"""从URL提取方法论"""
|
|
205
212
|
try:
|
|
@@ -236,20 +243,20 @@ def extract_methodology_from_url(
|
|
|
236
243
|
6. 内容字段使用|保留多行格式
|
|
237
244
|
"""
|
|
238
245
|
# 调用大模型平台提取方法论
|
|
239
|
-
|
|
246
|
+
PrettyOutput.auto_print("ℹ️ 正在从URL提取方法论...")
|
|
240
247
|
try:
|
|
241
248
|
response = platform.chat_until_success(prompt)
|
|
242
249
|
except Exception as e:
|
|
243
|
-
|
|
244
|
-
|
|
250
|
+
PrettyOutput.auto_print("❌ 提取失败")
|
|
251
|
+
PrettyOutput.auto_print(f"❌ 提取方法论失败: {str(e)}")
|
|
245
252
|
raise typer.Exit(code=1)
|
|
246
253
|
|
|
247
254
|
# 提取YAML部分
|
|
248
255
|
methodologies_start = response.find("<methodologies>") + len("<methodologies>")
|
|
249
256
|
methodologies_end = response.find("</methodologies>")
|
|
250
257
|
if methodologies_start == -1 or methodologies_end == -1:
|
|
251
|
-
|
|
252
|
-
|
|
258
|
+
PrettyOutput.auto_print("❌ 响应格式无效")
|
|
259
|
+
PrettyOutput.auto_print("❌ 大模型未返回有效的<methodologies>格式")
|
|
253
260
|
raise typer.Exit(code=1)
|
|
254
261
|
|
|
255
262
|
yaml_content = response[methodologies_start:methodologies_end].strip()
|
|
@@ -260,14 +267,14 @@ def extract_methodology_from_url(
|
|
|
260
267
|
item["problem_type"]: item["content"] for item in data
|
|
261
268
|
}
|
|
262
269
|
except (yaml.YAMLError, KeyError, TypeError) as e:
|
|
263
|
-
|
|
264
|
-
|
|
270
|
+
PrettyOutput.auto_print("❌ YAML解析失败")
|
|
271
|
+
PrettyOutput.auto_print(f"❌ YAML解析错误: {str(e)}")
|
|
265
272
|
raise typer.Exit(code=1)
|
|
266
273
|
|
|
267
274
|
if not extracted_methodologies:
|
|
268
|
-
|
|
275
|
+
PrettyOutput.auto_print("⚠️ 未提取到有效方法论")
|
|
269
276
|
return
|
|
270
|
-
|
|
277
|
+
PrettyOutput.auto_print("✅ 提取到有效方法论")
|
|
271
278
|
|
|
272
279
|
# 加载现有方法论
|
|
273
280
|
existing_methodologies = _load_all_methodologies()
|
|
@@ -289,9 +296,11 @@ def extract_methodology_from_url(
|
|
|
289
296
|
indent=2,
|
|
290
297
|
)
|
|
291
298
|
|
|
292
|
-
|
|
299
|
+
PrettyOutput.auto_print(
|
|
300
|
+
f"✅ 成功从URL提取 {len(extracted_methodologies)} 个方法论(总计 {len(merged_data)} 个)"
|
|
301
|
+
)
|
|
293
302
|
except Exception as e:
|
|
294
|
-
|
|
303
|
+
PrettyOutput.auto_print(f"❌ 从URL提取失败: {str(e)}")
|
|
295
304
|
raise typer.Exit(code=1)
|
|
296
305
|
|
|
297
306
|
|
|
@@ -1,22 +1,37 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from jarvis.jarvis_utils.jsonnet_compat import loads as json_loads
|
|
3
1
|
import re
|
|
4
|
-
from typing import Any
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Dict
|
|
4
|
+
from typing import List
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from typing import Tuple
|
|
7
|
+
from typing import Union
|
|
5
8
|
|
|
6
9
|
from jarvis.jarvis_agent import Agent
|
|
7
10
|
from jarvis.jarvis_agent.output_handler import OutputHandler
|
|
8
11
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
9
|
-
|
|
12
|
+
|
|
13
|
+
# -*- coding: utf-8 -*-
|
|
14
|
+
from jarvis.jarvis_utils.jsonnet_compat import loads as json_loads
|
|
15
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
16
|
+
from jarvis.jarvis_utils.tag import ct
|
|
17
|
+
from jarvis.jarvis_utils.tag import ot
|
|
10
18
|
|
|
11
19
|
|
|
12
20
|
class MultiAgent(OutputHandler):
|
|
13
|
-
def __init__(
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
agents_config: List[Dict],
|
|
24
|
+
main_agent_name: str,
|
|
25
|
+
common_system_prompt: str = "",
|
|
26
|
+
non_interactive: Optional[bool] = None,
|
|
27
|
+
):
|
|
14
28
|
self.agents_config = agents_config
|
|
15
29
|
self.agents_config_map = {c["name"]: c for c in agents_config}
|
|
16
30
|
self.agents: Dict[str, Agent] = {}
|
|
17
31
|
self.main_agent_name = main_agent_name
|
|
18
32
|
self.original_question: Optional[str] = None
|
|
19
33
|
self.common_system_prompt: str = common_system_prompt
|
|
34
|
+
self.non_interactive = non_interactive
|
|
20
35
|
|
|
21
36
|
def prompt(self) -> str:
|
|
22
37
|
_multiline_example_msg = """ {
|
|
@@ -114,7 +129,9 @@ class MultiAgent(OutputHandler):
|
|
|
114
129
|
missing = []
|
|
115
130
|
if not to_val:
|
|
116
131
|
missing.append("to")
|
|
117
|
-
if content_val is None or (
|
|
132
|
+
if content_val is None or (
|
|
133
|
+
isinstance(content_val, str) and content_val.strip() == ""
|
|
134
|
+
):
|
|
118
135
|
# 允许空格/空行被视为缺失
|
|
119
136
|
missing.append("content")
|
|
120
137
|
if missing:
|
|
@@ -133,9 +150,15 @@ class MultiAgent(OutputHandler):
|
|
|
133
150
|
return False, guidance
|
|
134
151
|
# 类型校验
|
|
135
152
|
if not isinstance(to_val, str):
|
|
136
|
-
return
|
|
153
|
+
return (
|
|
154
|
+
False,
|
|
155
|
+
"SEND_MESSAGE 字段类型错误:to 必须为字符串。修复建议:将 to 改为字符串,如 to: ChapterPolisher",
|
|
156
|
+
)
|
|
137
157
|
if not isinstance(content_val, str):
|
|
138
|
-
return
|
|
158
|
+
return (
|
|
159
|
+
False,
|
|
160
|
+
"SEND_MESSAGE 字段类型错误:content 必须为字符串。修复建议:将 content 改为字符串",
|
|
161
|
+
)
|
|
139
162
|
# 目标校验
|
|
140
163
|
if to_val not in self.agents_config_map:
|
|
141
164
|
available = ", ".join(self.agents_config_map.keys())
|
|
@@ -145,14 +168,14 @@ class MultiAgent(OutputHandler):
|
|
|
145
168
|
f"可用智能体:[{available}]\n"
|
|
146
169
|
"修复建议:\n"
|
|
147
170
|
"- 将 to 修改为上述可用智能体之一\n"
|
|
148
|
-
"- 或检查配置中是否遗漏了该智能体的定义"
|
|
171
|
+
"- 或检查配置中是否遗漏了该智能体的定义",
|
|
149
172
|
)
|
|
150
173
|
# 通过校验,交给上层发送
|
|
151
174
|
return True, {"to": to_val, "content": content_val}
|
|
152
175
|
elif len(parsed) > 1:
|
|
153
176
|
return (
|
|
154
177
|
False,
|
|
155
|
-
"检测到多个 SEND_MESSAGE 块。一次只能发送一个消息。\n修复建议:合并消息或分多轮发送,每轮仅保留一个 SEND_MESSAGE 块。"
|
|
178
|
+
"检测到多个 SEND_MESSAGE 块。一次只能发送一个消息。\n修复建议:合并消息或分多轮发送,每轮仅保留一个 SEND_MESSAGE 块。",
|
|
156
179
|
)
|
|
157
180
|
# 未成功解析,进行诊断并返回可操作指导
|
|
158
181
|
try:
|
|
@@ -173,10 +196,11 @@ class MultiAgent(OutputHandler):
|
|
|
173
196
|
"to: 目标Agent名称\n"
|
|
174
197
|
"content: |2\n"
|
|
175
198
|
" 这里填写要发送的消息内容\n"
|
|
176
|
-
f"{ct_tag}"
|
|
199
|
+
f"{ct_tag}",
|
|
177
200
|
)
|
|
178
201
|
# 尝试提取原始块并指出 JSON 问题
|
|
179
202
|
import re as _re
|
|
203
|
+
|
|
180
204
|
pattern = _re.compile(
|
|
181
205
|
rf"{_re.escape(ot_tag)}[ \t]*\n(.*?)(?:\n)?[ \t]*{_re.escape(ct_tag)}",
|
|
182
206
|
_re.DOTALL,
|
|
@@ -192,7 +216,7 @@ class MultiAgent(OutputHandler):
|
|
|
192
216
|
return (
|
|
193
217
|
False,
|
|
194
218
|
"SEND_MESSAGE 格式错误:未能识别完整的消息块。\n"
|
|
195
|
-
"修复建议:确保起止标签在单独行上,且中间内容为合法的 JSON,包含 to 与 content 字段。"
|
|
219
|
+
"修复建议:确保起止标签在单独行上,且中间内容为合法的 JSON,包含 to 与 content 字段。",
|
|
196
220
|
)
|
|
197
221
|
raw = blocks[0]
|
|
198
222
|
try:
|
|
@@ -205,7 +229,7 @@ class MultiAgent(OutputHandler):
|
|
|
205
229
|
"示例:\n"
|
|
206
230
|
f"{ot('SEND_MESSAGE')}\n"
|
|
207
231
|
'{{\n "to": "目标Agent名称",\n "content": "这里填写要发送的消息内容"\n}}\n'
|
|
208
|
-
f"{ct('SEND_MESSAGE')}"
|
|
232
|
+
f"{ct('SEND_MESSAGE')}",
|
|
209
233
|
)
|
|
210
234
|
missing_keys = [k for k in ("to", "content") if k not in msg_obj]
|
|
211
235
|
if missing_keys:
|
|
@@ -216,7 +240,7 @@ class MultiAgent(OutputHandler):
|
|
|
216
240
|
"示例:\n"
|
|
217
241
|
f"{ot('SEND_MESSAGE')}\n"
|
|
218
242
|
'{{\n "to": "目标Agent名称",\n "content": "这里填写要发送的消息内容"\n}}\n'
|
|
219
|
-
f"{ct('SEND_MESSAGE')}"
|
|
243
|
+
f"{ct('SEND_MESSAGE')}",
|
|
220
244
|
)
|
|
221
245
|
# 针对值类型的提示(更细)
|
|
222
246
|
if not isinstance(msg_obj.get("to"), str):
|
|
@@ -234,7 +258,7 @@ class MultiAgent(OutputHandler):
|
|
|
234
258
|
"示例:\n"
|
|
235
259
|
f"{ot('SEND_MESSAGE')}\n"
|
|
236
260
|
'{{\n "to": "目标Agent名称",\n "content": "这里填写要发送的消息内容"\n}}\n'
|
|
237
|
-
f"{ct('SEND_MESSAGE')}"
|
|
261
|
+
f"{ct('SEND_MESSAGE')}",
|
|
238
262
|
)
|
|
239
263
|
except Exception as e:
|
|
240
264
|
return (
|
|
@@ -251,7 +275,7 @@ class MultiAgent(OutputHandler):
|
|
|
251
275
|
"或使用多行字符串(推荐使用 ||| 或 ``` 分隔符):\n"
|
|
252
276
|
f"{ot('SEND_MESSAGE')}\n"
|
|
253
277
|
'{{\n "to": "目标Agent名称",\n "content": |||\n多行消息内容\n可以包含换行\n包含"双引号"和\'单引号\'都无需转义\n更清晰易读\n |||\n}}\n'
|
|
254
|
-
f"{ct('SEND_MESSAGE')}"
|
|
278
|
+
f"{ct('SEND_MESSAGE')}",
|
|
255
279
|
)
|
|
256
280
|
|
|
257
281
|
def name(self) -> str:
|
|
@@ -314,6 +338,9 @@ class MultiAgent(OutputHandler):
|
|
|
314
338
|
# 非主智能体统一禁用自动补全,防止多智能体并行时误触发自动交互
|
|
315
339
|
if name != self.main_agent_name:
|
|
316
340
|
config["auto_complete"] = False
|
|
341
|
+
# 继承 MultiAgent 的 non_interactive 设置(如果配置中未显式指定)
|
|
342
|
+
if self.non_interactive is not None and "non_interactive" not in config:
|
|
343
|
+
config["non_interactive"] = self.non_interactive
|
|
317
344
|
|
|
318
345
|
# Prepend common system prompt if configured
|
|
319
346
|
common_sp = getattr(self, "common_system_prompt", "")
|
|
@@ -351,7 +378,7 @@ class MultiAgent(OutputHandler):
|
|
|
351
378
|
|
|
352
379
|
if not isinstance(msg, Dict):
|
|
353
380
|
# Should not happen if agent.run() returns str or Dict
|
|
354
|
-
|
|
381
|
+
PrettyOutput.auto_print(f"⚠️ 未知消息类型: {type(msg)}")
|
|
355
382
|
break
|
|
356
383
|
|
|
357
384
|
# Generate a brief summary via direct model call to avoid run-loop recursion
|
|
@@ -373,24 +400,26 @@ class MultiAgent(OutputHandler):
|
|
|
373
400
|
- 仅输出纯文本,不包含任何指令或工具调用
|
|
374
401
|
- 使用简洁的要点式表述
|
|
375
402
|
""".strip()
|
|
376
|
-
summary_any: Any = agent.model.chat_until_success(
|
|
403
|
+
summary_any: Any = agent.model.chat_until_success(
|
|
377
404
|
f"{agent.session.prompt}\n{multi_agent_summary_prompt}"
|
|
378
405
|
)
|
|
379
|
-
summary_text =
|
|
406
|
+
summary_text = (
|
|
407
|
+
summary_any.strip() if isinstance(summary_any, str) else ""
|
|
408
|
+
)
|
|
380
409
|
except Exception:
|
|
381
410
|
summary_text = ""
|
|
382
411
|
prompt = f"""
|
|
383
412
|
Please handle this message:
|
|
384
413
|
from: {last_agent_name}
|
|
385
414
|
summary_of_sender_work: {summary_text}
|
|
386
|
-
content: {msg[
|
|
415
|
+
content: {msg["content"]}
|
|
387
416
|
"""
|
|
388
417
|
to_agent_name = msg.get("to")
|
|
389
418
|
if not to_agent_name:
|
|
390
419
|
return "消息中未指定 `to` 字段"
|
|
391
420
|
|
|
392
421
|
if to_agent_name not in self.agents_config_map:
|
|
393
|
-
|
|
422
|
+
PrettyOutput.auto_print(f"⚠️ 未找到智能体 {to_agent_name},正在重试...")
|
|
394
423
|
agent = self._get_agent(last_agent_name)
|
|
395
424
|
if not agent:
|
|
396
425
|
return f"智能体 {last_agent_name} 未找到"
|
|
@@ -399,7 +428,9 @@ content: {msg['content']}
|
|
|
399
428
|
)
|
|
400
429
|
continue
|
|
401
430
|
|
|
402
|
-
|
|
431
|
+
PrettyOutput.auto_print(
|
|
432
|
+
f"ℹ️ {last_agent_name} 正在向 {to_agent_name} 发送消息..."
|
|
433
|
+
)
|
|
403
434
|
|
|
404
435
|
# Keep a reference to the sender before switching to the receiver
|
|
405
436
|
sender_agent = agent
|
|
@@ -412,7 +443,9 @@ content: {msg['content']}
|
|
|
412
443
|
sender_config = self.agents_config_map.get(last_agent_name, {})
|
|
413
444
|
if sender_config.get("clear_after_send_message"):
|
|
414
445
|
if sender_agent:
|
|
415
|
-
|
|
446
|
+
PrettyOutput.auto_print(
|
|
447
|
+
f"ℹ️ 清除智能体 {last_agent_name} 在发送消息后的历史记录..."
|
|
448
|
+
)
|
|
416
449
|
sender_agent.clear_history()
|
|
417
450
|
|
|
418
451
|
last_agent_name = agent.name
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
4
|
import typer
|
|
5
|
-
import yaml
|
|
6
|
-
import os
|
|
5
|
+
import yaml
|
|
7
6
|
|
|
8
7
|
from jarvis.jarvis_multi_agent import MultiAgent
|
|
8
|
+
from jarvis.jarvis_utils.config import set_config
|
|
9
9
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
10
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
10
11
|
from jarvis.jarvis_utils.utils import init_env
|
|
11
|
-
from jarvis.jarvis_utils.config import set_config
|
|
12
12
|
|
|
13
13
|
app = typer.Typer(help="多智能体系统启动器")
|
|
14
14
|
|
|
@@ -23,29 +23,25 @@ def cli(
|
|
|
23
23
|
None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
|
|
24
24
|
),
|
|
25
25
|
non_interactive: bool = typer.Option(
|
|
26
|
-
False,
|
|
26
|
+
False,
|
|
27
|
+
"-n",
|
|
28
|
+
"--non-interactive",
|
|
29
|
+
help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟",
|
|
27
30
|
),
|
|
28
31
|
):
|
|
29
32
|
"""从YAML配置文件初始化并运行多智能体系统"""
|
|
30
|
-
# CLI 标志:非交互模式(不依赖配置文件)
|
|
31
|
-
if non_interactive:
|
|
32
|
-
try:
|
|
33
|
-
os.environ["JARVIS_NON_INTERACTIVE"] = "true"
|
|
34
|
-
except Exception:
|
|
35
|
-
pass
|
|
36
|
-
# 注意:全局配置同步在 init_env 之后执行,避免被覆盖
|
|
37
33
|
# 非交互模式要求从命令行传入任务
|
|
38
34
|
if non_interactive and not (user_input and str(user_input).strip()):
|
|
39
|
-
|
|
35
|
+
PrettyOutput.auto_print(
|
|
36
|
+
"❌ 非交互模式已启用:必须使用 --input 传入任务内容,因多行输入不可用。"
|
|
37
|
+
)
|
|
40
38
|
raise typer.Exit(code=2)
|
|
41
39
|
init_env()
|
|
42
|
-
|
|
40
|
+
|
|
43
41
|
# 在初始化环境后同步 CLI 选项到全局配置,避免被 init_env 覆盖
|
|
44
42
|
try:
|
|
45
|
-
if non_interactive:
|
|
46
|
-
set_config("JARVIS_NON_INTERACTIVE", True)
|
|
47
43
|
if model_group:
|
|
48
|
-
set_config("
|
|
44
|
+
set_config("llm_group", str(model_group))
|
|
49
45
|
except Exception:
|
|
50
46
|
# 静默忽略同步异常,不影响主流程
|
|
51
47
|
pass
|
|
@@ -65,7 +61,8 @@ def cli(
|
|
|
65
61
|
multi_agent = MultiAgent(
|
|
66
62
|
agents_config,
|
|
67
63
|
main_agent_name,
|
|
68
|
-
common_system_prompt=str(config_data.get("common_system_prompt", "") or "")
|
|
64
|
+
common_system_prompt=str(config_data.get("common_system_prompt", "") or ""),
|
|
65
|
+
non_interactive=non_interactive if non_interactive else None,
|
|
69
66
|
)
|
|
70
67
|
final_input = (
|
|
71
68
|
user_input
|
|
@@ -81,7 +78,7 @@ def cli(
|
|
|
81
78
|
except typer.Exit:
|
|
82
79
|
return
|
|
83
80
|
except (ValueError, RuntimeError, yaml.YAMLError) as e:
|
|
84
|
-
|
|
81
|
+
PrettyOutput.auto_print(f"❌ 错误: {str(e)}")
|
|
85
82
|
raise typer.Exit(code=1)
|
|
86
83
|
|
|
87
84
|
|