jarvis-ai-assistant 0.3.30__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 +458 -152
- jarvis/jarvis_agent/agent_manager.py +17 -13
- 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 +329 -0
- jarvis/jarvis_agent/file_methodology_manager.py +3 -4
- jarvis/jarvis_agent/jarvis.py +628 -55
- 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 +34 -10
- 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 +105 -9
- jarvis/jarvis_agent/session_manager.py +2 -3
- jarvis/jarvis_agent/share_manager.py +20 -22
- jarvis/jarvis_agent/shell_input_handler.py +1 -2
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +31 -6
- 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/utils.py +5 -1
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +786 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +575 -0
- jarvis/jarvis_c2rust/collector.py +250 -0
- jarvis/jarvis_c2rust/constants.py +26 -0
- jarvis/jarvis_c2rust/library_replacer.py +1254 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1272 -0
- jarvis/jarvis_c2rust/loaders.py +207 -0
- jarvis/jarvis_c2rust/models.py +28 -0
- jarvis/jarvis_c2rust/optimizer.py +2157 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2983 -0
- jarvis/jarvis_c2rust/utils.py +385 -0
- jarvis/jarvis_code_agent/build_validation_config.py +132 -0
- jarvis/jarvis_code_agent/code_agent.py +1371 -220
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +65 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +106 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +72 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +70 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +53 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +47 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +61 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +153 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +648 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +49 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +299 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +215 -0
- 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 +269 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +281 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +605 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +252 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +58 -0
- jarvis/jarvis_code_agent/lint.py +501 -8
- jarvis/jarvis_code_agent/utils.py +141 -0
- jarvis/jarvis_code_analysis/code_review.py +493 -584
- jarvis/jarvis_data/config_schema.json +128 -12
- jarvis/jarvis_git_squash/main.py +4 -5
- jarvis/jarvis_git_utils/git_commiter.py +82 -75
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -29
- jarvis/jarvis_mcp/stdio_mcp_client.py +12 -13
- 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 +287 -55
- jarvis/jarvis_multi_agent/main.py +36 -4
- jarvis/jarvis_platform/base.py +524 -202
- jarvis/jarvis_platform/human.py +7 -8
- jarvis/jarvis_platform/kimi.py +30 -36
- jarvis/jarvis_platform/openai.py +88 -25
- jarvis/jarvis_platform/registry.py +26 -10
- jarvis/jarvis_platform/tongyi.py +24 -25
- jarvis/jarvis_platform/yuanbao.py +32 -43
- jarvis/jarvis_platform_manager/main.py +66 -77
- jarvis/jarvis_platform_manager/service.py +8 -13
- jarvis/jarvis_rag/cli.py +53 -55
- 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 +305 -0
- jarvis/jarvis_sec/agents.py +143 -0
- jarvis/jarvis_sec/analysis.py +276 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +139 -0
- 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 +336 -0
- jarvis/jarvis_sec/review.py +453 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/utils.py +499 -0
- jarvis/jarvis_sec/verification.py +848 -0
- jarvis/jarvis_sec/workflow.py +226 -0
- jarvis/jarvis_smart_shell/main.py +38 -87
- jarvis/jarvis_stats/cli.py +2 -2
- jarvis/jarvis_stats/stats.py +8 -8
- jarvis/jarvis_stats/storage.py +15 -21
- jarvis/jarvis_stats/visualizer.py +1 -1
- jarvis/jarvis_tools/clear_memory.py +3 -20
- jarvis/jarvis_tools/cli/main.py +21 -23
- jarvis/jarvis_tools/edit_file.py +1019 -132
- jarvis/jarvis_tools/execute_script.py +83 -25
- jarvis/jarvis_tools/file_analyzer.py +6 -9
- jarvis/jarvis_tools/generate_new_tool.py +14 -21
- jarvis/jarvis_tools/lsp_client.py +1552 -0
- jarvis/jarvis_tools/methodology.py +2 -3
- jarvis/jarvis_tools/read_code.py +1736 -35
- jarvis/jarvis_tools/read_symbols.py +140 -0
- jarvis/jarvis_tools/read_webpage.py +12 -13
- jarvis/jarvis_tools/registry.py +427 -200
- jarvis/jarvis_tools/retrieve_memory.py +20 -19
- jarvis/jarvis_tools/rewrite_file.py +72 -158
- jarvis/jarvis_tools/save_memory.py +3 -15
- jarvis/jarvis_tools/search_web.py +18 -18
- jarvis/jarvis_tools/sub_agent.py +36 -43
- jarvis/jarvis_tools/sub_code_agent.py +25 -26
- jarvis/jarvis_tools/virtual_tty.py +55 -33
- jarvis/jarvis_utils/clipboard.py +7 -10
- jarvis/jarvis_utils/config.py +232 -45
- jarvis/jarvis_utils/embedding.py +8 -5
- jarvis/jarvis_utils/fzf.py +8 -8
- jarvis/jarvis_utils/git_utils.py +225 -36
- jarvis/jarvis_utils/globals.py +3 -3
- jarvis/jarvis_utils/http.py +1 -1
- jarvis/jarvis_utils/input.py +99 -48
- jarvis/jarvis_utils/jsonnet_compat.py +465 -0
- jarvis/jarvis_utils/methodology.py +52 -48
- jarvis/jarvis_utils/utils.py +819 -491
- jarvis_ai_assistant-0.7.6.dist-info/METADATA +600 -0
- jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +4 -0
- jarvis/jarvis_agent/config.py +0 -92
- jarvis/jarvis_agent/edit_file_handler.py +0 -296
- jarvis/jarvis_platform/ai8.py +0 -332
- jarvis/jarvis_tools/ask_user.py +0 -54
- jarvis_ai_assistant-0.3.30.dist-info/METADATA +0 -381
- jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Jsonnet 兼容层 - 提供类似 json5.loads() 的接口"""
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import _jsonnet
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _fix_jsonnet_multiline_strings(s: str) -> tuple[str, dict]:
|
|
11
|
+
"""
|
|
12
|
+
修复 jsonnet ||| 多行字符串的缩进问题。
|
|
13
|
+
|
|
14
|
+
jsonnet 要求 ||| 之后的第一行内容必须有缩进(至少一个空格),
|
|
15
|
+
否则会报错 "text block's first line must start with whitespace"。
|
|
16
|
+
|
|
17
|
+
此函数会自动检测并修复这个问题。
|
|
18
|
+
|
|
19
|
+
参数:
|
|
20
|
+
s: 输入字符串
|
|
21
|
+
|
|
22
|
+
返回:
|
|
23
|
+
(修复后的字符串, 第一行原始缩进信息字典)
|
|
24
|
+
缩进信息字典的键是修复后字符串中 ||| 多行字符串的标记,
|
|
25
|
+
值是第一行的原始缩进级别(如果第一行原本有缩进但后续行没有)
|
|
26
|
+
"""
|
|
27
|
+
if not isinstance(s, str):
|
|
28
|
+
return s
|
|
29
|
+
|
|
30
|
+
import re
|
|
31
|
+
|
|
32
|
+
# 匹配 ||| 多行字符串模式
|
|
33
|
+
# 格式:||| 后跟可选空白和换行,然后是内容,最后是 |||
|
|
34
|
+
# 使用非贪婪匹配,确保匹配到最近的 |||
|
|
35
|
+
pattern = r'(\|\|\|)(\s*\n)(.*?)(\n\s*\|\|\|)'
|
|
36
|
+
|
|
37
|
+
def fix_match(match):
|
|
38
|
+
start_marker = match.group(1) # |||
|
|
39
|
+
whitespace_after = match.group(2) # 空白和换行
|
|
40
|
+
content = match.group(3) # 多行内容
|
|
41
|
+
end_marker = match.group(4) # 换行、空白和 |||
|
|
42
|
+
|
|
43
|
+
# jsonnet 要求结束标记 ||| 必须单独一行且没有缩进(从行首开始)
|
|
44
|
+
# 无论原来是什么格式,统一修复为 '\n|||'
|
|
45
|
+
end_marker = '\n|||'
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# 如果内容为空,返回修复后的结束标记
|
|
49
|
+
if not content.strip():
|
|
50
|
+
return start_marker + whitespace_after + content + end_marker, {}
|
|
51
|
+
|
|
52
|
+
# 按行分割内容
|
|
53
|
+
|
|
54
|
+
lines = content.split('\n')
|
|
55
|
+
|
|
56
|
+
# 确定缩进级别:
|
|
57
|
+
# 1. 如果第一行有缩进,使用第一行的缩进级别
|
|
58
|
+
# 2. 如果第一行是空行,查找第一个非空行的缩进级别
|
|
59
|
+
# 3. 如果第一行没有缩进,使用默认的一个空格
|
|
60
|
+
# 4. 如果所有行都为空,使用默认的一个空格
|
|
61
|
+
indent_level = 1 # 默认缩进级别
|
|
62
|
+
first_line_has_indent = False
|
|
63
|
+
first_line_indent = 0
|
|
64
|
+
|
|
65
|
+
if lines:
|
|
66
|
+
first_line = lines[0]
|
|
67
|
+
if first_line.strip() and first_line.startswith((' ', '\t')):
|
|
68
|
+
# 第一行已有缩进,记录其缩进级别
|
|
69
|
+
first_line_indent = len(first_line) - len(first_line.lstrip())
|
|
70
|
+
first_line_has_indent = True
|
|
71
|
+
indent_level = first_line_indent
|
|
72
|
+
# 确保至少有一个空格
|
|
73
|
+
if indent_level == 0:
|
|
74
|
+
indent_level = 1
|
|
75
|
+
elif not first_line.strip():
|
|
76
|
+
# 第一行是空行,查找第一个非空行的缩进级别
|
|
77
|
+
for line in lines[1:]:
|
|
78
|
+
if line.strip():
|
|
79
|
+
if line.startswith((' ', '\t')):
|
|
80
|
+
# 找到第一个非空行,使用其缩进级别
|
|
81
|
+
indent_level = len(line) - len(line.lstrip())
|
|
82
|
+
# 确保至少有一个空格
|
|
83
|
+
if indent_level == 0:
|
|
84
|
+
indent_level = 1
|
|
85
|
+
else:
|
|
86
|
+
# 第一个非空行没有缩进,使用默认的一个空格
|
|
87
|
+
indent_level = 1
|
|
88
|
+
break
|
|
89
|
+
|
|
90
|
+
# 对每一行都统一缩进级别
|
|
91
|
+
# jsonnet 的 ||| 要求所有行都有相同的缩进级别,并会去除所有行的最小共同缩进前缀
|
|
92
|
+
# 为了保留第一行的缩进,我们需要:
|
|
93
|
+
# 1. 让所有行都有相同的缩进(满足 jsonnet 的要求)
|
|
94
|
+
# 2. 记录第一行的原始缩进级别,以便在解析后恢复
|
|
95
|
+
# 3. 在解析后,为第一行添加原始缩进
|
|
96
|
+
|
|
97
|
+
# 检查是否有后续行没有缩进(需要修复)
|
|
98
|
+
has_unindented_lines = False
|
|
99
|
+
if first_line_has_indent:
|
|
100
|
+
for line in lines[1:]:
|
|
101
|
+
if line.strip() and not line.startswith((' ', '\t')):
|
|
102
|
+
has_unindented_lines = True
|
|
103
|
+
break
|
|
104
|
+
|
|
105
|
+
# 记录所有行的原始缩进信息(用于恢复)
|
|
106
|
+
# 如果存在不同缩进级别的行,我们需要记录每行的原始缩进
|
|
107
|
+
original_indents = {} # 键:行内容(去除缩进后),值:原始缩进级别
|
|
108
|
+
has_mixed_indents = False
|
|
109
|
+
|
|
110
|
+
# 记录所有行的原始缩进信息(无论是否混合缩进,都需要记录以便恢复)
|
|
111
|
+
if lines:
|
|
112
|
+
seen_indents = set()
|
|
113
|
+
for line in lines:
|
|
114
|
+
|
|
115
|
+
if line.strip():
|
|
116
|
+
line_indent = len(line) - len(line.lstrip())
|
|
117
|
+
seen_indents.add(line_indent)
|
|
118
|
+
line_content = line.lstrip()
|
|
119
|
+
# 记录原始缩进(包括0缩进的情况,用特殊值标记)
|
|
120
|
+
original_indents[line_content] = line_indent
|
|
121
|
+
|
|
122
|
+
# 如果有多个不同的缩进级别,说明是混合缩进
|
|
123
|
+
if len(seen_indents) > 1:
|
|
124
|
+
has_mixed_indents = True
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# 如果第一行有缩进,但后续行没有,我们也需要记录
|
|
128
|
+
if first_line_has_indent and has_unindented_lines:
|
|
129
|
+
has_mixed_indents = True
|
|
130
|
+
# 记录第一行的原始缩进
|
|
131
|
+
first_line_content = lines[0].lstrip()
|
|
132
|
+
original_indents[first_line_content] = first_line_indent
|
|
133
|
+
|
|
134
|
+
# jsonnet的text block规则:所有行缩进必须 >= 首行缩进
|
|
135
|
+
# 因此我们统一所有行为相同的基础缩进,通过恢复逻辑还原原始缩进
|
|
136
|
+
base_indent = 1 # 统一使用1空格缩进
|
|
137
|
+
|
|
138
|
+
# 统一所有行的缩进为基础缩进(满足jsonnet要求)
|
|
139
|
+
|
|
140
|
+
for i in range(len(lines)):
|
|
141
|
+
line = lines[i]
|
|
142
|
+
if line.strip(): # 只处理非空行
|
|
143
|
+
line_content = line.lstrip()
|
|
144
|
+
lines[i] = ' ' * base_indent + line_content
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# 重新组合内容
|
|
148
|
+
fixed_content = '\n'.join(lines)
|
|
149
|
+
|
|
150
|
+
# 返回修复后的内容和原始缩进信息
|
|
151
|
+
# 只要有混合缩进,就返回缩进信息以便恢复
|
|
152
|
+
indent_info = original_indents if has_mixed_indents else {}
|
|
153
|
+
|
|
154
|
+
return start_marker + whitespace_after + fixed_content + end_marker, indent_info
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# 使用 DOTALL 标志,使 . 匹配换行符
|
|
158
|
+
# 收集所有修复后的内容和缩进信息
|
|
159
|
+
all_indent_info = {}
|
|
160
|
+
fixed_parts = []
|
|
161
|
+
last_end = 0
|
|
162
|
+
|
|
163
|
+
for match in re.finditer(pattern, s, flags=re.DOTALL):
|
|
164
|
+
# 添加匹配前的部分
|
|
165
|
+
fixed_parts.append(s[last_end:match.start()])
|
|
166
|
+
|
|
167
|
+
# 修复匹配的部分
|
|
168
|
+
fixed_content, indent_info = fix_match(match)
|
|
169
|
+
fixed_parts.append(fixed_content)
|
|
170
|
+
|
|
171
|
+
# 合并缩进信息
|
|
172
|
+
all_indent_info.update(indent_info)
|
|
173
|
+
|
|
174
|
+
last_end = match.end()
|
|
175
|
+
|
|
176
|
+
# 添加剩余部分
|
|
177
|
+
fixed_parts.append(s[last_end:])
|
|
178
|
+
fixed = ''.join(fixed_parts)
|
|
179
|
+
|
|
180
|
+
return fixed, all_indent_info
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _restore_first_line_indent(obj: Any, indent_info: dict) -> Any:
|
|
184
|
+
"""
|
|
185
|
+
恢复第一行的原始缩进。
|
|
186
|
+
|
|
187
|
+
参数:
|
|
188
|
+
obj: 解析后的对象
|
|
189
|
+
indent_info: 缩进信息字典
|
|
190
|
+
|
|
191
|
+
返回:
|
|
192
|
+
恢复缩进后的对象
|
|
193
|
+
"""
|
|
194
|
+
if not indent_info:
|
|
195
|
+
return obj
|
|
196
|
+
|
|
197
|
+
if isinstance(obj, dict):
|
|
198
|
+
return {k: _restore_first_line_indent(v, indent_info) for k, v in obj.items()}
|
|
199
|
+
elif isinstance(obj, list):
|
|
200
|
+
return [_restore_first_line_indent(item, indent_info) for item in obj]
|
|
201
|
+
elif isinstance(obj, str):
|
|
202
|
+
# 检查字符串的每一行是否原本有缩进
|
|
203
|
+
# 如果存在原始缩进信息,恢复每行的原始缩进
|
|
204
|
+
if indent_info:
|
|
205
|
+
lines = obj.split('\n')
|
|
206
|
+
restored_lines = []
|
|
207
|
+
for line in lines:
|
|
208
|
+
if line.strip():
|
|
209
|
+
# 去除当前行的缩进,获取内容
|
|
210
|
+
line_content = line.lstrip()
|
|
211
|
+
# 检查是否有对应的原始缩进信息
|
|
212
|
+
if line_content in indent_info:
|
|
213
|
+
# 恢复原始缩进
|
|
214
|
+
original_indent = indent_info[line_content]
|
|
215
|
+
restored_lines.append(' ' * original_indent + line_content)
|
|
216
|
+
else:
|
|
217
|
+
# 没有原始缩进信息,保持原样
|
|
218
|
+
restored_lines.append(line)
|
|
219
|
+
else:
|
|
220
|
+
# 空行保持原样
|
|
221
|
+
restored_lines.append(line)
|
|
222
|
+
return '\n'.join(restored_lines)
|
|
223
|
+
return obj
|
|
224
|
+
else:
|
|
225
|
+
return obj
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _convert_backtick_multiline_strings(s: str) -> str:
|
|
229
|
+
"""
|
|
230
|
+
将 JSON 值中的 ``` 多行字符串标识转换为 |||。
|
|
231
|
+
|
|
232
|
+
此函数识别 JSON 值位置(如 "key": ```)的 ``` 标记,并将其转换为 |||,
|
|
233
|
+
以便与 jsonnet 的 ||| 多行字符串语法兼容。
|
|
234
|
+
|
|
235
|
+
识别规则:
|
|
236
|
+
- 在 JSON 值位置(冒号后)的 ``` 会被转换为 |||
|
|
237
|
+
- 已经去除 markdown 代码块标记后,剩余的 ``` 通常是多行字符串标识
|
|
238
|
+
|
|
239
|
+
参数:
|
|
240
|
+
s: 输入字符串(应该已经去除 markdown 代码块标记)
|
|
241
|
+
|
|
242
|
+
返回:
|
|
243
|
+
转换后的字符串(``` 转换为 |||)
|
|
244
|
+
"""
|
|
245
|
+
if not isinstance(s, str):
|
|
246
|
+
return s
|
|
247
|
+
|
|
248
|
+
import re
|
|
249
|
+
|
|
250
|
+
# 匹配 JSON 值中的 ``` 多行字符串
|
|
251
|
+
# 格式:": ``` 或 ":``` 后跟可选空白和换行,然后是内容,最后是换行和 ```
|
|
252
|
+
# 使用非贪婪匹配,确保匹配到最近的 ```
|
|
253
|
+
# 注意:这个模式匹配的是 JSON 值位置(冒号后)的 ```
|
|
254
|
+
pattern = r'(:\s*)(```)(\s*\n)(.*?)(\n\s*```)'
|
|
255
|
+
|
|
256
|
+
def convert_match(match):
|
|
257
|
+
colon = match.group(1) # 冒号和可选空白
|
|
258
|
+
match.group(2) # ``` (保留用于匹配,但不使用)
|
|
259
|
+
whitespace_after = match.group(3) # 空白和换行
|
|
260
|
+
content = match.group(4) # 多行内容
|
|
261
|
+
match.group(5) # 换行、空白和 ``` (保留用于匹配,但不使用)
|
|
262
|
+
|
|
263
|
+
# 将 ``` 转换为 |||
|
|
264
|
+
return colon + '|||' + whitespace_after + content + '\n|||'
|
|
265
|
+
|
|
266
|
+
# 替换所有匹配的模式
|
|
267
|
+
result = re.sub(pattern, convert_match, s, flags=re.DOTALL)
|
|
268
|
+
|
|
269
|
+
return result
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _strip_markdown_code_blocks(s: str) -> str:
|
|
273
|
+
"""
|
|
274
|
+
去除字符串中的 markdown 代码块标记(如 ```json5、```json、``` 等)
|
|
275
|
+
|
|
276
|
+
支持以下场景:
|
|
277
|
+
- 代码块前后有空白/换行:\n```json\n{...}\n```
|
|
278
|
+
- 代码块不在字符串开头:prefix\n```json\n{...}\n```
|
|
279
|
+
- 标准格式:```json\n{...}\n```
|
|
280
|
+
|
|
281
|
+
参数:
|
|
282
|
+
s: 输入字符串
|
|
283
|
+
|
|
284
|
+
返回:
|
|
285
|
+
清理后的字符串
|
|
286
|
+
"""
|
|
287
|
+
if not isinstance(s, str):
|
|
288
|
+
return s
|
|
289
|
+
|
|
290
|
+
import re
|
|
291
|
+
|
|
292
|
+
# 先去除首尾空白,但保留内部结构
|
|
293
|
+
block = s.strip()
|
|
294
|
+
|
|
295
|
+
# 使用正则表达式匹配并去除代码块标记
|
|
296
|
+
# 尝试多种模式,从严格到宽松
|
|
297
|
+
|
|
298
|
+
# 模式1:标准格式,代码块在开头和结尾
|
|
299
|
+
# 匹配:```language + 可选空白 + 可选换行 + 内容 + 可选换行 + 可选空白 + ```
|
|
300
|
+
pattern1 = r'^```[a-zA-Z0-9_+-]*\s*\n?(.*?)\n?\s*```\s*$'
|
|
301
|
+
match = re.match(pattern1, block, re.DOTALL)
|
|
302
|
+
if match:
|
|
303
|
+
return match.group(1).strip()
|
|
304
|
+
|
|
305
|
+
# 模式2:代码块前后可能有额外空白/换行,但要求代码块在字符串的开头或结尾
|
|
306
|
+
# 只匹配整个字符串被代码块包裹的情况,不匹配 JSON 值内部的 ```
|
|
307
|
+
# 匹配:字符串开头(可选空白)+ ```language + 可选空白 + 换行 + 内容 + 换行 + 可选空白 + ``` + 字符串结尾(可选空白)
|
|
308
|
+
pattern2 = r'^\s*```[a-zA-Z0-9_+-]*\s*\n(.*?)\n\s*```\s*$'
|
|
309
|
+
match = re.match(pattern2, block, re.DOTALL)
|
|
310
|
+
if match:
|
|
311
|
+
return match.group(1).strip()
|
|
312
|
+
|
|
313
|
+
# 模式3:更宽松的匹配,不要求换行,但要求代码块在字符串的开头或结尾
|
|
314
|
+
# 只匹配整个字符串被代码块包裹的情况,不匹配 JSON 值内部的 ```
|
|
315
|
+
# 匹配:字符串开头(可选空白)+ ```language + 可选空白 + 内容 + 可选空白 + ``` + 字符串结尾(可选空白)
|
|
316
|
+
pattern3 = r'^\s*```[a-zA-Z0-9_+-]*\s*(.*?)\s*```\s*$'
|
|
317
|
+
match = re.match(pattern3, block, re.DOTALL)
|
|
318
|
+
if match:
|
|
319
|
+
return match.group(1).strip()
|
|
320
|
+
|
|
321
|
+
# 如果正则都不匹配,尝试手动去除(向后兼容)
|
|
322
|
+
# 但只处理整个字符串被代码块包裹的情况(代码块在开头且结尾也有 ```)
|
|
323
|
+
block_stripped = block.strip()
|
|
324
|
+
if block_stripped.startswith("```") and block_stripped.rstrip().endswith("```"):
|
|
325
|
+
# 找到开头的 ``` 后的内容
|
|
326
|
+
after_start = 3 # 跳过 ```
|
|
327
|
+
# 跳过语言标识(如果有)
|
|
328
|
+
while after_start < len(block_stripped) and block_stripped[after_start] not in ('\n', '\r', ' ', '\t'):
|
|
329
|
+
after_start += 1
|
|
330
|
+
# 跳过空白字符
|
|
331
|
+
while after_start < len(block_stripped) and block_stripped[after_start] in (' ', '\t'):
|
|
332
|
+
after_start += 1
|
|
333
|
+
# 跳过换行符(如果有)
|
|
334
|
+
if after_start < len(block_stripped) and block_stripped[after_start] in ('\n', '\r'):
|
|
335
|
+
after_start += 1
|
|
336
|
+
# 处理 \r\n
|
|
337
|
+
if after_start < len(block_stripped) and block_stripped[after_start] == '\n' and block_stripped[after_start - 1] == '\r':
|
|
338
|
+
after_start += 1
|
|
339
|
+
|
|
340
|
+
# 找到结尾的 ``` 的位置
|
|
341
|
+
before_end = block_stripped.rfind("```")
|
|
342
|
+
if before_end > after_start:
|
|
343
|
+
# 提取内容(去除结尾的 ``` 和前面的空白)
|
|
344
|
+
content = block_stripped[after_start:before_end].rstrip()
|
|
345
|
+
return content
|
|
346
|
+
|
|
347
|
+
return block.strip()
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def loads(s: str) -> Any:
|
|
351
|
+
"""
|
|
352
|
+
解析 JSON/Jsonnet 格式的字符串,返回 Python 对象
|
|
353
|
+
|
|
354
|
+
使用 jsonnet 来解析,支持 JSON5 特性(注释、尾随逗号、||| 或 ``` 分隔符多行字符串等)
|
|
355
|
+
|
|
356
|
+
自动处理:
|
|
357
|
+
- markdown 代码块标记:如果输入包含 ```json5、```json、``` 等代码块标记,
|
|
358
|
+
会自动去除这些标记后再解析。
|
|
359
|
+
- ``` 多行字符串:支持使用 ``` 代替 ||| 作为多行字符串标识(在 JSON 值位置)。
|
|
360
|
+
- ||| 多行字符串缩进:自动为 ||| 多行字符串的第一行添加必要的缩进,
|
|
361
|
+
避免 "text block's first line must start with whitespace" 错误。
|
|
362
|
+
|
|
363
|
+
参数:
|
|
364
|
+
s: 要解析的字符串(可能包含 markdown 代码块标记)
|
|
365
|
+
|
|
366
|
+
返回:
|
|
367
|
+
解析后的 Python 对象
|
|
368
|
+
|
|
369
|
+
异常:
|
|
370
|
+
ValueError: 如果解析失败
|
|
371
|
+
"""
|
|
372
|
+
if not isinstance(s, str) or not s.strip():
|
|
373
|
+
raise ValueError("输入字符串为空")
|
|
374
|
+
|
|
375
|
+
# 自动去除 markdown 代码块标记
|
|
376
|
+
cleaned = _strip_markdown_code_blocks(s)
|
|
377
|
+
|
|
378
|
+
# 验证:确保没有残留的代码块标记(在字符串开头或结尾)
|
|
379
|
+
# 字符串内容中的 ``` 是合法的,不需要处理
|
|
380
|
+
cleaned_stripped = cleaned.strip()
|
|
381
|
+
if cleaned_stripped.startswith("```") or cleaned_stripped.rstrip().endswith("```"):
|
|
382
|
+
# 如果还有代码块标记,可能是手动去除逻辑没有正确工作
|
|
383
|
+
# 再次尝试去除(防止边界情况)
|
|
384
|
+
cleaned = _strip_markdown_code_blocks(cleaned)
|
|
385
|
+
cleaned_stripped = cleaned.strip()
|
|
386
|
+
# 如果仍然有,说明可能是格式问题,记录警告但继续处理
|
|
387
|
+
if cleaned_stripped.startswith("```") or cleaned_stripped.rstrip().endswith("```"):
|
|
388
|
+
# 最后尝试:手动去除开头和结尾的 ```
|
|
389
|
+
while cleaned_stripped.startswith("```"):
|
|
390
|
+
# 找到第一个换行或字符串结尾
|
|
391
|
+
first_newline = cleaned_stripped.find("\n", 3)
|
|
392
|
+
if first_newline >= 0:
|
|
393
|
+
cleaned_stripped = cleaned_stripped[first_newline + 1:]
|
|
394
|
+
else:
|
|
395
|
+
# 没有换行,可能是 ```language 格式
|
|
396
|
+
cleaned_stripped = cleaned_stripped[3:].lstrip()
|
|
397
|
+
# 跳过语言标识
|
|
398
|
+
while cleaned_stripped and cleaned_stripped[0] not in ('\n', '\r', ' ', '\t'):
|
|
399
|
+
cleaned_stripped = cleaned_stripped[1:]
|
|
400
|
+
break
|
|
401
|
+
while cleaned_stripped.rstrip().endswith("```"):
|
|
402
|
+
last_backticks = cleaned_stripped.rfind("```")
|
|
403
|
+
if last_backticks >= 0:
|
|
404
|
+
cleaned_stripped = cleaned_stripped[:last_backticks].rstrip()
|
|
405
|
+
else:
|
|
406
|
+
break
|
|
407
|
+
cleaned = cleaned_stripped
|
|
408
|
+
|
|
409
|
+
# 将 JSON 值中的 ``` 多行字符串标识转换为 |||
|
|
410
|
+
cleaned = _convert_backtick_multiline_strings(cleaned)
|
|
411
|
+
|
|
412
|
+
# 自动修复 ||| 多行字符串的缩进问题
|
|
413
|
+
cleaned, indent_info = _fix_jsonnet_multiline_strings(cleaned)
|
|
414
|
+
|
|
415
|
+
# 使用 jsonnet 解析,支持 JSON5 和 Jsonnet 语法
|
|
416
|
+
try:
|
|
417
|
+
result_json = _jsonnet.evaluate_snippet("<input>", cleaned)
|
|
418
|
+
except RuntimeError as e:
|
|
419
|
+
# 提供更详细的错误信息
|
|
420
|
+
error_msg = str(e)
|
|
421
|
+
if "Could not lex the character" in error_msg or "`" in error_msg:
|
|
422
|
+
# 检查是否还有残留的代码块标记
|
|
423
|
+
if "```" in cleaned:
|
|
424
|
+
# 找到所有 ``` 的位置
|
|
425
|
+
import re
|
|
426
|
+
matches = list(re.finditer(r'```', cleaned))
|
|
427
|
+
for match in matches:
|
|
428
|
+
pos = match.start()
|
|
429
|
+
context = cleaned[max(0, pos-30):min(len(cleaned), pos+50)]
|
|
430
|
+
# 检查是否在字符串内部(被引号包围)
|
|
431
|
+
before = cleaned[:pos]
|
|
432
|
+
# 简单检查:如果前面有奇数个引号,说明在字符串内部
|
|
433
|
+
quote_count = before.count('"') - before.count('\\"')
|
|
434
|
+
if quote_count % 2 == 0:
|
|
435
|
+
# 不在字符串内部,可能是残留的代码块标记
|
|
436
|
+
raise ValueError(
|
|
437
|
+
f"检测到残留的代码块标记 ``` 在位置 {pos}。"
|
|
438
|
+
f"上下文: {repr(context)}。"
|
|
439
|
+
f"原始错误: {error_msg}"
|
|
440
|
+
)
|
|
441
|
+
raise ValueError(f"JSON 解析失败: {error_msg}")
|
|
442
|
+
|
|
443
|
+
# jsonnet 返回的是 JSON 字符串,需要再次解析
|
|
444
|
+
result = json.loads(result_json)
|
|
445
|
+
|
|
446
|
+
# 如果第一行原本有缩进,恢复第一行的缩进
|
|
447
|
+
if indent_info:
|
|
448
|
+
result = _restore_first_line_indent(result, indent_info)
|
|
449
|
+
|
|
450
|
+
return result
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def dumps(obj: Any, **kwargs) -> str:
|
|
454
|
+
"""
|
|
455
|
+
将 Python 对象序列化为 JSON 字符串
|
|
456
|
+
|
|
457
|
+
参数:
|
|
458
|
+
obj: 要序列化的对象
|
|
459
|
+
**kwargs: 传递给 json.dumps 的其他参数
|
|
460
|
+
|
|
461
|
+
返回:
|
|
462
|
+
JSON 字符串
|
|
463
|
+
"""
|
|
464
|
+
return json.dumps(obj, **kwargs)
|
|
465
|
+
|
|
@@ -20,7 +20,6 @@ from jarvis.jarvis_utils.config import (
|
|
|
20
20
|
get_central_methodology_repo,
|
|
21
21
|
get_max_input_token_count,
|
|
22
22
|
)
|
|
23
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
24
23
|
from jarvis.jarvis_utils.utils import daily_check_git_updates
|
|
25
24
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
26
25
|
|
|
@@ -37,7 +36,7 @@ def _get_methodology_directory() -> str:
|
|
|
37
36
|
try:
|
|
38
37
|
os.makedirs(methodology_dir, exist_ok=True)
|
|
39
38
|
except Exception as e:
|
|
40
|
-
|
|
39
|
+
print(f"❌ 创建方法论目录失败: {str(e)}")
|
|
41
40
|
return methodology_dir
|
|
42
41
|
|
|
43
42
|
|
|
@@ -54,25 +53,27 @@ def _load_all_methodologies() -> Dict[str, str]:
|
|
|
54
53
|
# 如果配置了中心方法论仓库,将其添加到加载路径
|
|
55
54
|
central_repo = get_central_methodology_repo()
|
|
56
55
|
if central_repo:
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
56
|
+
# 支持本地目录路径或Git仓库URL
|
|
57
|
+
expanded = os.path.expanduser(os.path.expandvars(central_repo))
|
|
58
|
+
if os.path.isdir(expanded):
|
|
59
|
+
# 直接使用本地目录(支持Git仓库的子目录)
|
|
60
|
+
methodology_dirs.append(expanded)
|
|
61
|
+
else:
|
|
62
|
+
# 中心方法论仓库存储在数据目录下的特定位置
|
|
63
|
+
central_repo_path = os.path.join(get_data_dir(), "central_methodology_repo")
|
|
64
|
+
methodology_dirs.append(central_repo_path)
|
|
65
|
+
|
|
66
|
+
# 确保中心方法论仓库被克隆/更新
|
|
67
|
+
if not os.path.exists(central_repo_path):
|
|
68
|
+
try:
|
|
69
|
+
import subprocess
|
|
70
|
+
|
|
71
|
+
print(f"ℹ️ 正在克隆中心方法论仓库: {central_repo}")
|
|
72
|
+
subprocess.run(
|
|
73
|
+
["git", "clone", central_repo, central_repo_path], check=True
|
|
74
|
+
)
|
|
75
|
+
except Exception as e:
|
|
76
|
+
print(f"❌ 克隆中心方法论仓库失败: {str(e)}")
|
|
76
77
|
|
|
77
78
|
# --- 全局每日更新检查 ---
|
|
78
79
|
daily_check_git_updates(methodology_dirs, "methodologies")
|
|
@@ -104,9 +105,9 @@ def _load_all_methodologies() -> Dict[str, str]:
|
|
|
104
105
|
|
|
105
106
|
# 统一打印目录警告与文件加载失败信息
|
|
106
107
|
if warn_dirs:
|
|
107
|
-
|
|
108
|
+
print("⚠️ " + "\n⚠️ ".join(warn_dirs))
|
|
108
109
|
if error_lines:
|
|
109
|
-
|
|
110
|
+
print("⚠️ " + "\n⚠️ ".join(error_lines))
|
|
110
111
|
return all_methodologies
|
|
111
112
|
|
|
112
113
|
|
|
@@ -139,7 +140,7 @@ def _create_methodology_temp_file(methodologies: Dict[str, str]) -> Optional[str
|
|
|
139
140
|
|
|
140
141
|
return temp_path
|
|
141
142
|
except Exception as e:
|
|
142
|
-
|
|
143
|
+
print(f"❌ 创建方法论临时文件失败: {str(e)}")
|
|
143
144
|
return None
|
|
144
145
|
|
|
145
146
|
|
|
@@ -155,12 +156,12 @@ def upload_methodology(platform: BasePlatform, other_files: List[str] = []) -> b
|
|
|
155
156
|
"""
|
|
156
157
|
methodology_dir = _get_methodology_directory()
|
|
157
158
|
if not os.path.exists(methodology_dir):
|
|
158
|
-
|
|
159
|
+
print("⚠️ 方法论文档不存在")
|
|
159
160
|
return False
|
|
160
161
|
|
|
161
162
|
methodologies = _load_all_methodologies()
|
|
162
163
|
if not methodologies:
|
|
163
|
-
|
|
164
|
+
print("⚠️ 没有可用的方法论文档")
|
|
164
165
|
return False
|
|
165
166
|
|
|
166
167
|
temp_file_path = _create_methodology_temp_file(methodologies)
|
|
@@ -206,24 +207,23 @@ def load_methodology(
|
|
|
206
207
|
|
|
207
208
|
try:
|
|
208
209
|
# 加载所有方法论
|
|
209
|
-
|
|
210
|
+
print("📁 加载方法论文件...")
|
|
210
211
|
methodologies = _load_all_methodologies()
|
|
211
212
|
if not methodologies:
|
|
212
|
-
|
|
213
|
+
print("⚠️ 没有找到方法论文件")
|
|
213
214
|
return ""
|
|
214
|
-
|
|
215
|
-
f"加载方法论文件完成 (共 {len(methodologies)} 个)", OutputType.SUCCESS
|
|
216
|
-
)
|
|
215
|
+
print(f"✅ 加载方法论文件完成 (共 {len(methodologies)} 个)")
|
|
217
216
|
|
|
218
217
|
if platform_name:
|
|
219
218
|
platform = PlatformRegistry().create_platform(platform_name)
|
|
220
219
|
if platform and model_name:
|
|
221
220
|
platform.set_model_name(model_name)
|
|
222
221
|
else:
|
|
223
|
-
|
|
222
|
+
# 方法论推荐使用cheap模型以降低成本
|
|
223
|
+
platform = PlatformRegistry().get_cheap_platform()
|
|
224
224
|
|
|
225
225
|
if not platform:
|
|
226
|
-
|
|
226
|
+
print("❌ 无法创建平台实例")
|
|
227
227
|
return ""
|
|
228
228
|
|
|
229
229
|
platform.set_suppress_output(True)
|
|
@@ -297,9 +297,21 @@ def load_methodology(
|
|
|
297
297
|
if not selected_methodologies:
|
|
298
298
|
return "没有历史方法论可参考"
|
|
299
299
|
|
|
300
|
-
#
|
|
301
|
-
|
|
302
|
-
|
|
300
|
+
# 优先使用剩余token数量,回退到输入窗口限制
|
|
301
|
+
methodology_token_limit = None
|
|
302
|
+
try:
|
|
303
|
+
remaining_tokens = platform.get_remaining_token_count()
|
|
304
|
+
# 使用剩余token的2/3作为限制,保留1/3作为安全余量
|
|
305
|
+
methodology_token_limit = int(remaining_tokens * 2 / 3)
|
|
306
|
+
if methodology_token_limit <= 0:
|
|
307
|
+
methodology_token_limit = None
|
|
308
|
+
except Exception:
|
|
309
|
+
pass
|
|
310
|
+
|
|
311
|
+
# 回退方案:使用输入窗口的2/3
|
|
312
|
+
if methodology_token_limit is None:
|
|
313
|
+
max_input_tokens = get_max_input_token_count()
|
|
314
|
+
methodology_token_limit = int(max_input_tokens * 2 / 3)
|
|
303
315
|
|
|
304
316
|
# 步骤3:将选择出来的方法论内容提供给大模型生成步骤
|
|
305
317
|
# 首先构建基础提示词部分
|
|
@@ -341,10 +353,7 @@ def load_methodology(
|
|
|
341
353
|
|
|
342
354
|
# 检查是否会超过token限制
|
|
343
355
|
if total_methodology_tokens + methodology_tokens > available_tokens:
|
|
344
|
-
|
|
345
|
-
f"达到方法论token限制 ({total_methodology_tokens}/{available_tokens}),停止加载更多方法论",
|
|
346
|
-
OutputType.INFO,
|
|
347
|
-
)
|
|
356
|
+
print(f"ℹ️ 达到方法论token限制 ({total_methodology_tokens}/{available_tokens}),停止加载更多方法论")
|
|
348
357
|
break
|
|
349
358
|
|
|
350
359
|
final_prompt += methodology_text
|
|
@@ -353,21 +362,16 @@ def load_methodology(
|
|
|
353
362
|
|
|
354
363
|
# 如果一个方法论都没有加载成功
|
|
355
364
|
if selected_count == 0:
|
|
356
|
-
|
|
357
|
-
"警告:由于token限制,无法加载任何方法论内容", OutputType.WARNING
|
|
358
|
-
)
|
|
365
|
+
print("⚠️ 警告:由于token限制,无法加载任何方法论内容")
|
|
359
366
|
return "没有历史方法论可参考"
|
|
360
367
|
|
|
361
368
|
final_prompt += suffix_prompt
|
|
362
369
|
|
|
363
|
-
|
|
364
|
-
f"成功加载 {selected_count} 个方法论,总token数: {total_methodology_tokens}",
|
|
365
|
-
OutputType.INFO,
|
|
366
|
-
)
|
|
370
|
+
print(f"ℹ️ 成功加载 {selected_count} 个方法论,总token数: {total_methodology_tokens}")
|
|
367
371
|
|
|
368
372
|
# 如果内容不大,直接使用chat_until_success
|
|
369
373
|
return platform.chat_until_success(final_prompt)
|
|
370
374
|
|
|
371
375
|
except Exception as e:
|
|
372
|
-
|
|
376
|
+
print(f"❌ 加载方法论失败: {str(e)}")
|
|
373
377
|
return ""
|