jarvis-ai-assistant 0.7.0__py3-none-any.whl → 0.7.8__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.8.dist-info}/METADATA +205 -70
- jarvis_ai_assistant-0.7.8.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.8.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.8.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.8.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.8.dist-info}/top_level.txt +0 -0
jarvis/jarvis_agent/__init__.py
CHANGED
|
@@ -25,16 +25,13 @@ from jarvis.jarvis_agent.tool_executor import execute_tool_call
|
|
|
25
25
|
from jarvis.jarvis_agent.memory_manager import MemoryManager
|
|
26
26
|
from jarvis.jarvis_memory_organizer.memory_organizer import MemoryOrganizer
|
|
27
27
|
from jarvis.jarvis_agent.task_analyzer import TaskAnalyzer
|
|
28
|
-
from jarvis.jarvis_agent.task_planner import TaskPlanner
|
|
29
28
|
from jarvis.jarvis_agent.file_methodology_manager import FileMethodologyManager
|
|
30
29
|
from jarvis.jarvis_agent.prompts import (
|
|
31
30
|
DEFAULT_SUMMARY_PROMPT,
|
|
32
31
|
SUMMARY_REQUEST_PROMPT,
|
|
33
|
-
TASK_ANALYSIS_PROMPT
|
|
32
|
+
TASK_ANALYSIS_PROMPT, # noqa: F401
|
|
34
33
|
)
|
|
35
34
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
36
|
-
from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
|
|
37
|
-
from jarvis.jarvis_agent.rewrite_file_handler import RewriteFileHandler
|
|
38
35
|
from jarvis.jarvis_agent.prompt_manager import PromptManager
|
|
39
36
|
from jarvis.jarvis_agent.event_bus import EventBus
|
|
40
37
|
from jarvis.jarvis_agent.run_loop import AgentRunLoop
|
|
@@ -76,20 +73,19 @@ from jarvis.jarvis_utils.config import (
|
|
|
76
73
|
is_use_methodology,
|
|
77
74
|
get_tool_filter_threshold,
|
|
78
75
|
get_after_tool_call_cb_dirs,
|
|
79
|
-
get_plan_max_depth,
|
|
80
|
-
is_plan_enabled,
|
|
81
76
|
get_addon_prompt_threshold,
|
|
77
|
+
is_enable_memory_organizer,
|
|
82
78
|
)
|
|
83
79
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
84
80
|
from jarvis.jarvis_utils.globals import (
|
|
85
81
|
delete_agent,
|
|
86
82
|
get_interrupt,
|
|
83
|
+
get_short_term_memories,
|
|
87
84
|
make_agent_name,
|
|
88
85
|
set_agent,
|
|
89
86
|
set_interrupt,
|
|
90
87
|
)
|
|
91
88
|
from jarvis.jarvis_utils.input import get_multiline_input, user_confirm
|
|
92
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
93
89
|
from jarvis.jarvis_utils.tag import ot
|
|
94
90
|
|
|
95
91
|
|
|
@@ -138,6 +134,10 @@ def show_agent_startup_stats(
|
|
|
138
134
|
if project_memory_dir.exists():
|
|
139
135
|
project_memory_count = len(list(project_memory_dir.glob("*.json")))
|
|
140
136
|
|
|
137
|
+
# 检查短期记忆
|
|
138
|
+
short_term_memories = get_short_term_memories()
|
|
139
|
+
short_term_memory_count = len(short_term_memories) if short_term_memories else 0
|
|
140
|
+
|
|
141
141
|
# 获取当前工作目录
|
|
142
142
|
current_dir = os.getcwd()
|
|
143
143
|
|
|
@@ -157,6 +157,12 @@ def show_agent_startup_stats(
|
|
|
157
157
|
f"📝 项目记忆: [bold magenta]{project_memory_count}[/bold magenta]"
|
|
158
158
|
)
|
|
159
159
|
|
|
160
|
+
# 如果有短期记忆,添加到统计信息中
|
|
161
|
+
if short_term_memory_count > 0:
|
|
162
|
+
stats_parts.append(
|
|
163
|
+
f"💭 短期记忆: [bold blue]{short_term_memory_count}[/bold blue]"
|
|
164
|
+
)
|
|
165
|
+
|
|
160
166
|
stats_text = Text.from_markup(" | ".join(stats_parts), justify="center")
|
|
161
167
|
|
|
162
168
|
# 创建包含欢迎信息和统计信息的面板内容
|
|
@@ -180,7 +186,7 @@ def show_agent_startup_stats(
|
|
|
180
186
|
console.print(Align.center(panel))
|
|
181
187
|
|
|
182
188
|
except Exception as e:
|
|
183
|
-
|
|
189
|
+
print(f"⚠️ 加载统计信息失败: {e}")
|
|
184
190
|
|
|
185
191
|
|
|
186
192
|
origin_agent_system_prompt = f"""
|
|
@@ -251,9 +257,15 @@ class Agent:
|
|
|
251
257
|
def clear_history(self):
|
|
252
258
|
"""
|
|
253
259
|
Clears the current conversation history by delegating to the session manager.
|
|
254
|
-
|
|
260
|
+
直接调用关键流程函数,事件总线仅用于非关键流程(如日志、监控等)。
|
|
255
261
|
"""
|
|
256
|
-
#
|
|
262
|
+
# 关键流程:直接调用 memory_manager 确保记忆提示
|
|
263
|
+
try:
|
|
264
|
+
self.memory_manager._ensure_memory_prompt(agent=self)
|
|
265
|
+
except Exception:
|
|
266
|
+
pass
|
|
267
|
+
|
|
268
|
+
# 非关键流程:广播清理历史前事件(用于日志、监控等)
|
|
257
269
|
try:
|
|
258
270
|
self.event_bus.emit(BEFORE_HISTORY_CLEAR, agent=self)
|
|
259
271
|
except Exception:
|
|
@@ -263,6 +275,8 @@ class Agent:
|
|
|
263
275
|
self.session.clear_history()
|
|
264
276
|
# 重置 addon_prompt 跳过轮数计数器
|
|
265
277
|
self._addon_prompt_skip_rounds = 0
|
|
278
|
+
# 重置没有工具调用的计数器
|
|
279
|
+
self._no_tool_call_count = 0
|
|
266
280
|
|
|
267
281
|
# 重置后重新设置系统提示词,确保系统约束仍然生效
|
|
268
282
|
try:
|
|
@@ -270,7 +284,7 @@ class Agent:
|
|
|
270
284
|
except Exception:
|
|
271
285
|
pass
|
|
272
286
|
|
|
273
|
-
#
|
|
287
|
+
# 非关键流程:广播清理历史后的事件(用于日志、监控等)
|
|
274
288
|
try:
|
|
275
289
|
self.event_bus.emit(AFTER_HISTORY_CLEAR, agent=self)
|
|
276
290
|
except Exception:
|
|
@@ -316,19 +330,14 @@ class Agent:
|
|
|
316
330
|
use_tools: Optional[List[str]] = None,
|
|
317
331
|
execute_tool_confirm: Optional[bool] = None,
|
|
318
332
|
need_summary: bool = True,
|
|
319
|
-
auto_summary_rounds: Optional[int] = None,
|
|
320
333
|
multiline_inputer: Optional[Callable[[str], str]] = None,
|
|
321
334
|
use_methodology: Optional[bool] = None,
|
|
322
335
|
use_analysis: Optional[bool] = None,
|
|
323
336
|
force_save_memory: Optional[bool] = None,
|
|
324
|
-
disable_file_edit: bool = False,
|
|
325
337
|
files: Optional[List[str]] = None,
|
|
326
338
|
confirm_callback: Optional[Callable[[str, bool], bool]] = None,
|
|
327
339
|
non_interactive: Optional[bool] = None,
|
|
328
340
|
in_multi_agent: Optional[bool] = None,
|
|
329
|
-
plan: Optional[bool] = None,
|
|
330
|
-
plan_max_depth: Optional[int] = None,
|
|
331
|
-
plan_depth: int = 0,
|
|
332
341
|
agent_type: str = "normal",
|
|
333
342
|
**kwargs,
|
|
334
343
|
):
|
|
@@ -349,9 +358,6 @@ class Agent:
|
|
|
349
358
|
force_save_memory: 是否强制保存记忆
|
|
350
359
|
confirm_callback: 用户确认回调函数,签名为 (tip: str, default: bool) -> bool;默认使用CLI的user_confirm
|
|
351
360
|
non_interactive: 是否以非交互模式运行(优先级最高,覆盖环境变量与配置)
|
|
352
|
-
plan: 是否启用任务规划与子任务拆分(默认从配置加载;启用后在进入主循环前评估是否需要将任务拆分为 <SUB_TASK> 列表,逐一由子Agent执行并汇总结果)
|
|
353
|
-
plan_max_depth: 任务规划的最大层数(默认3,可通过配置 JARVIS_PLAN_MAX_DEPTH 或入参覆盖)
|
|
354
|
-
plan_depth: 当前规划层数(内部用于递归控制,子Agent会在父基础上+1)
|
|
355
361
|
"""
|
|
356
362
|
# 基础属性初始化(仅根据入参设置原始值;实际生效的默认回退在 _init_config 中统一解析)
|
|
357
363
|
# 标识与描述
|
|
@@ -361,14 +367,11 @@ class Agent:
|
|
|
361
367
|
# 行为控制开关(原始入参值)
|
|
362
368
|
self.auto_complete = bool(auto_complete)
|
|
363
369
|
self.need_summary = bool(need_summary)
|
|
364
|
-
# 自动摘要轮次:None 表示使用配置文件中的默认值,由 AgentRunLoop 决定最终取值
|
|
365
|
-
self.auto_summary_rounds = auto_summary_rounds
|
|
366
370
|
self.use_methodology = use_methodology
|
|
367
371
|
self.use_analysis = use_analysis
|
|
368
372
|
self.execute_tool_confirm = execute_tool_confirm
|
|
369
373
|
self.summary_prompt = summary_prompt
|
|
370
374
|
self.force_save_memory = force_save_memory
|
|
371
|
-
self.disable_file_edit = bool(disable_file_edit)
|
|
372
375
|
# 资源与环境
|
|
373
376
|
self.model_group = model_group
|
|
374
377
|
self.files = files or []
|
|
@@ -376,25 +379,16 @@ class Agent:
|
|
|
376
379
|
self.non_interactive = non_interactive
|
|
377
380
|
# 多智能体运行标志:用于控制非交互模式下的自动完成行为
|
|
378
381
|
self.in_multi_agent = bool(in_multi_agent)
|
|
379
|
-
# 任务规划:优先使用入参,否则回退到配置
|
|
380
|
-
self.plan = bool(plan) if plan is not None else is_plan_enabled()
|
|
381
|
-
# 规划深度与上限
|
|
382
|
-
try:
|
|
383
|
-
self.plan_max_depth = (
|
|
384
|
-
int(plan_max_depth) if plan_max_depth is not None else int(get_plan_max_depth())
|
|
385
|
-
)
|
|
386
|
-
except Exception:
|
|
387
|
-
self.plan_max_depth = 2
|
|
388
|
-
try:
|
|
389
|
-
self.plan_depth = int(plan_depth)
|
|
390
|
-
except Exception:
|
|
391
|
-
self.plan_depth = 0
|
|
392
382
|
# 运行时状态
|
|
393
383
|
self.first = True
|
|
394
384
|
self.run_input_handlers_next_turn = False
|
|
395
385
|
self.user_data: Dict[str, Any] = {}
|
|
396
386
|
# 记录连续未添加 addon_prompt 的轮数
|
|
397
387
|
self._addon_prompt_skip_rounds: int = 0
|
|
388
|
+
# 记录连续没有工具调用的次数(用于非交互模式下的工具使用提示)
|
|
389
|
+
self._no_tool_call_count: int = 0
|
|
390
|
+
|
|
391
|
+
self._agent_type = "normal"
|
|
398
392
|
|
|
399
393
|
|
|
400
394
|
# 用户确认回调:默认使用 CLI 的 user_confirm,可由外部注入以支持 TUI/GUI
|
|
@@ -472,8 +466,14 @@ class Agent:
|
|
|
472
466
|
self.task_analyzer = TaskAnalyzer(self)
|
|
473
467
|
self.file_methodology_manager = FileMethodologyManager(self)
|
|
474
468
|
self.prompt_manager = PromptManager(self)
|
|
475
|
-
|
|
476
|
-
|
|
469
|
+
|
|
470
|
+
# 如果配置了强制保存记忆,确保 save_memory 工具可用
|
|
471
|
+
if self.force_save_memory:
|
|
472
|
+
self._ensure_save_memory_tool()
|
|
473
|
+
|
|
474
|
+
# 如果启用了分析,确保 methodology 工具可用
|
|
475
|
+
if self.use_analysis:
|
|
476
|
+
self._ensure_methodology_tool()
|
|
477
477
|
|
|
478
478
|
# 设置系统提示词
|
|
479
479
|
self._setup_system_prompt()
|
|
@@ -485,6 +485,7 @@ class Agent:
|
|
|
485
485
|
self.get_tool_registry(), # type: ignore
|
|
486
486
|
platform_name=self.model.platform_name(), # type: ignore
|
|
487
487
|
)
|
|
488
|
+
|
|
488
489
|
# 动态加载工具调用后回调
|
|
489
490
|
self._load_after_tool_callbacks()
|
|
490
491
|
|
|
@@ -495,9 +496,7 @@ class Agent:
|
|
|
495
496
|
|
|
496
497
|
maybe_model = PlatformRegistry().create_platform(platform_name)
|
|
497
498
|
if maybe_model is None:
|
|
498
|
-
|
|
499
|
-
f"平台 {platform_name} 不存在,将使用普通模型", OutputType.WARNING
|
|
500
|
-
)
|
|
499
|
+
print(f"⚠️ 平台 {platform_name} 不存在,将使用普通模型")
|
|
501
500
|
maybe_model = PlatformRegistry().get_normal_platform()
|
|
502
501
|
|
|
503
502
|
# 在此处收敛为非可选类型,确保后续赋值满足类型检查
|
|
@@ -521,11 +520,7 @@ class Agent:
|
|
|
521
520
|
):
|
|
522
521
|
"""初始化各种处理器"""
|
|
523
522
|
default_handlers: List[Any] = [ToolRegistry()]
|
|
524
|
-
if not getattr(self, "disable_file_edit", False):
|
|
525
|
-
default_handlers.extend([EditFileHandler(), RewriteFileHandler()])
|
|
526
523
|
handlers = output_handler or default_handlers
|
|
527
|
-
if getattr(self, "disable_file_edit", False):
|
|
528
|
-
handlers = [h for h in handlers if not isinstance(h, (EditFileHandler, RewriteFileHandler))]
|
|
529
524
|
self.output_handler = handlers
|
|
530
525
|
self.set_use_tools(use_tools)
|
|
531
526
|
self.input_handler = [
|
|
@@ -538,15 +533,7 @@ class Agent:
|
|
|
538
533
|
def _setup_system_prompt(self):
|
|
539
534
|
"""设置系统提示词"""
|
|
540
535
|
try:
|
|
541
|
-
|
|
542
|
-
prompt_text = self.prompt_manager.build_system_prompt()
|
|
543
|
-
else:
|
|
544
|
-
action_prompt = self.get_tool_usage_prompt()
|
|
545
|
-
prompt_text = f"""
|
|
546
|
-
{self.system_prompt}
|
|
547
|
-
|
|
548
|
-
{action_prompt}
|
|
549
|
-
"""
|
|
536
|
+
prompt_text = self.prompt_manager.build_system_prompt()
|
|
550
537
|
self.model.set_system_prompt(prompt_text) # type: ignore
|
|
551
538
|
except Exception:
|
|
552
539
|
# 回退到原始行为,确保兼容性
|
|
@@ -567,6 +554,19 @@ class Agent:
|
|
|
567
554
|
"""Gets user data from the session."""
|
|
568
555
|
return self.session.get_user_data(key)
|
|
569
556
|
|
|
557
|
+
def get_remaining_token_count(self) -> int:
|
|
558
|
+
"""获取剩余可用的token数量
|
|
559
|
+
|
|
560
|
+
返回:
|
|
561
|
+
int: 剩余可用的token数量,如果无法获取则返回0
|
|
562
|
+
"""
|
|
563
|
+
if not self.model:
|
|
564
|
+
return 0
|
|
565
|
+
try:
|
|
566
|
+
return self.model.get_remaining_token_count()
|
|
567
|
+
except Exception:
|
|
568
|
+
return 0
|
|
569
|
+
|
|
570
570
|
def set_use_tools(self, use_tools):
|
|
571
571
|
"""设置要使用的工具列表"""
|
|
572
572
|
for handler in self.output_handler:
|
|
@@ -590,8 +590,10 @@ class Agent:
|
|
|
590
590
|
otherwise, fall back to calling with a single argument for compatibility.
|
|
591
591
|
"""
|
|
592
592
|
# 优先通过用户交互封装,便于未来替换 UI
|
|
593
|
-
|
|
593
|
+
try:
|
|
594
594
|
return self.user_interaction.multiline_input(tip, print_on_empty)
|
|
595
|
+
except Exception:
|
|
596
|
+
pass
|
|
595
597
|
try:
|
|
596
598
|
# Try to pass the keyword for enhanced input handler
|
|
597
599
|
return self.multiline_inputer(tip, print_on_empty=print_on_empty) # type: ignore
|
|
@@ -679,7 +681,7 @@ class Agent:
|
|
|
679
681
|
pass
|
|
680
682
|
|
|
681
683
|
except Exception as e:
|
|
682
|
-
|
|
684
|
+
print(f"⚠️ 从 {file_path} 加载回调失败: {e}")
|
|
683
685
|
finally:
|
|
684
686
|
if added_path:
|
|
685
687
|
try:
|
|
@@ -687,7 +689,7 @@ class Agent:
|
|
|
687
689
|
except ValueError:
|
|
688
690
|
pass
|
|
689
691
|
except Exception as e:
|
|
690
|
-
|
|
692
|
+
print(f"⚠️ 加载回调目录时发生错误: {e}")
|
|
691
693
|
|
|
692
694
|
def save_session(self) -> bool:
|
|
693
695
|
"""Saves the current session state by delegating to the session manager."""
|
|
@@ -707,6 +709,58 @@ class Agent:
|
|
|
707
709
|
return handler
|
|
708
710
|
return None
|
|
709
711
|
|
|
712
|
+
def _ensure_save_memory_tool(self) -> None:
|
|
713
|
+
"""如果配置了强制保存记忆,确保 save_memory 工具在 use_tools 列表中"""
|
|
714
|
+
try:
|
|
715
|
+
tool_registry = self.get_tool_registry()
|
|
716
|
+
if not tool_registry:
|
|
717
|
+
return
|
|
718
|
+
|
|
719
|
+
# 检查 save_memory 工具是否已注册(工具默认都会注册)
|
|
720
|
+
if not tool_registry.get_tool("save_memory"):
|
|
721
|
+
# 如果工具本身不存在,则无法使用,直接返回
|
|
722
|
+
return
|
|
723
|
+
|
|
724
|
+
# 检查 save_memory 是否在 use_tools 列表中
|
|
725
|
+
# 如果 use_tools 为 None,表示使用所有工具,无需添加
|
|
726
|
+
if self.use_tools is None:
|
|
727
|
+
return
|
|
728
|
+
|
|
729
|
+
# 如果 save_memory 不在 use_tools 列表中,则添加
|
|
730
|
+
if "save_memory" not in self.use_tools:
|
|
731
|
+
self.use_tools.append("save_memory")
|
|
732
|
+
# 更新工具注册表的工具列表
|
|
733
|
+
self.set_use_tools(self.use_tools)
|
|
734
|
+
except Exception:
|
|
735
|
+
# 忽略所有错误,不影响主流程
|
|
736
|
+
pass
|
|
737
|
+
|
|
738
|
+
def _ensure_methodology_tool(self) -> None:
|
|
739
|
+
"""如果启用了分析,确保 methodology 工具在 use_tools 列表中"""
|
|
740
|
+
try:
|
|
741
|
+
tool_registry = self.get_tool_registry()
|
|
742
|
+
if not tool_registry:
|
|
743
|
+
return
|
|
744
|
+
|
|
745
|
+
# 检查 methodology 工具是否已注册(工具默认都会注册)
|
|
746
|
+
if not tool_registry.get_tool("methodology"):
|
|
747
|
+
# 如果工具本身不存在,则无法使用,直接返回
|
|
748
|
+
return
|
|
749
|
+
|
|
750
|
+
# 检查 methodology 是否在 use_tools 列表中
|
|
751
|
+
# 如果 use_tools 为 None,表示使用所有工具,无需添加
|
|
752
|
+
if self.use_tools is None:
|
|
753
|
+
return
|
|
754
|
+
|
|
755
|
+
# 如果 methodology 不在 use_tools 列表中,则添加
|
|
756
|
+
if "methodology" not in self.use_tools:
|
|
757
|
+
self.use_tools.append("methodology")
|
|
758
|
+
# 更新工具注册表的工具列表
|
|
759
|
+
self.set_use_tools(self.use_tools)
|
|
760
|
+
except Exception:
|
|
761
|
+
# 忽略所有错误,不影响主流程
|
|
762
|
+
pass
|
|
763
|
+
|
|
710
764
|
def get_event_bus(self) -> EventBus:
|
|
711
765
|
"""获取事件总线实例"""
|
|
712
766
|
return self.event_bus
|
|
@@ -819,7 +873,7 @@ class Agent:
|
|
|
819
873
|
return message
|
|
820
874
|
|
|
821
875
|
def _manage_conversation_length(self, message: str) -> str:
|
|
822
|
-
"""
|
|
876
|
+
"""管理对话长度计数;摘要触发由剩余token数量在 AgentRunLoop 中统一处理(剩余token低于20%时触发)。"""
|
|
823
877
|
self.session.conversation_length += get_context_token_count(message)
|
|
824
878
|
|
|
825
879
|
|
|
@@ -844,7 +898,7 @@ class Agent:
|
|
|
844
898
|
# 防御: 模型可能返回空响应(None或空字符串),统一为空字符串并告警
|
|
845
899
|
if not response:
|
|
846
900
|
try:
|
|
847
|
-
|
|
901
|
+
print("⚠️ 模型返回空响应,已使用空字符串回退。")
|
|
848
902
|
except Exception:
|
|
849
903
|
pass
|
|
850
904
|
response = ""
|
|
@@ -864,9 +918,13 @@ class Agent:
|
|
|
864
918
|
|
|
865
919
|
return response
|
|
866
920
|
|
|
867
|
-
def generate_summary(self) -> str:
|
|
921
|
+
def generate_summary(self, for_token_limit: bool = False) -> str:
|
|
868
922
|
"""生成对话历史摘要
|
|
869
923
|
|
|
924
|
+
参数:
|
|
925
|
+
for_token_limit: 如果为True,表示由于token限制触发的summary,使用SUMMARY_REQUEST_PROMPT
|
|
926
|
+
如果为False,表示任务完成时的summary,使用用户传入的summary_prompt
|
|
927
|
+
|
|
870
928
|
返回:
|
|
871
929
|
str: 包含对话摘要的字符串
|
|
872
930
|
|
|
@@ -877,24 +935,31 @@ class Agent:
|
|
|
877
935
|
try:
|
|
878
936
|
if not self.model:
|
|
879
937
|
raise RuntimeError("Model not initialized")
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
938
|
+
|
|
939
|
+
print("🔍 开始生成对话历史摘要...")
|
|
940
|
+
|
|
941
|
+
if for_token_limit:
|
|
942
|
+
# token限制触发的summary:使用SUMMARY_REQUEST_PROMPT进行上下文压缩
|
|
885
943
|
prompt_to_use = self.session.prompt + "\n" + SUMMARY_REQUEST_PROMPT
|
|
944
|
+
else:
|
|
945
|
+
# 任务完成时的summary:使用用户传入的summary_prompt或DEFAULT_SUMMARY_PROMPT
|
|
946
|
+
safe_summary_prompt = self.summary_prompt or ""
|
|
947
|
+
if isinstance(safe_summary_prompt, str) and safe_summary_prompt.strip() != "":
|
|
948
|
+
prompt_to_use = safe_summary_prompt
|
|
949
|
+
else:
|
|
950
|
+
prompt_to_use = DEFAULT_SUMMARY_PROMPT
|
|
886
951
|
|
|
887
952
|
summary = self.model.chat_until_success(prompt_to_use) # type: ignore
|
|
888
953
|
# 防御: 可能返回空响应(None或空字符串),统一为空字符串并告警
|
|
889
954
|
if not summary:
|
|
890
955
|
try:
|
|
891
|
-
|
|
956
|
+
print("⚠️ 总结模型返回空响应,已使用空字符串回退。")
|
|
892
957
|
except Exception:
|
|
893
958
|
pass
|
|
894
959
|
summary = ""
|
|
895
960
|
return summary
|
|
896
961
|
except Exception:
|
|
897
|
-
|
|
962
|
+
print("❌ 总结对话历史失败")
|
|
898
963
|
return ""
|
|
899
964
|
|
|
900
965
|
def _summarize_and_clear_history(self) -> str:
|
|
@@ -914,11 +979,6 @@ class Agent:
|
|
|
914
979
|
注意:
|
|
915
980
|
当上下文长度超过最大值时使用
|
|
916
981
|
"""
|
|
917
|
-
# 在清理历史之前,提示用户保存重要记忆(事件驱动触发实际保存)
|
|
918
|
-
if self.force_save_memory:
|
|
919
|
-
PrettyOutput.print(
|
|
920
|
-
"对话历史即将被总结和清理,请先保存重要信息...", OutputType.INFO
|
|
921
|
-
)
|
|
922
982
|
|
|
923
983
|
if self._should_use_file_upload():
|
|
924
984
|
return self._handle_history_with_file_upload()
|
|
@@ -931,20 +991,28 @@ class Agent:
|
|
|
931
991
|
|
|
932
992
|
def _handle_history_with_summary(self) -> str:
|
|
933
993
|
"""使用摘要方式处理历史"""
|
|
934
|
-
summary
|
|
994
|
+
# token限制触发的summary,使用SUMMARY_REQUEST_PROMPT
|
|
995
|
+
summary = self.generate_summary(for_token_limit=True)
|
|
935
996
|
|
|
936
997
|
# 先获取格式化的摘要消息
|
|
937
998
|
formatted_summary = ""
|
|
938
999
|
if summary:
|
|
939
1000
|
formatted_summary = self._format_summary_message(summary)
|
|
940
1001
|
|
|
941
|
-
#
|
|
942
|
-
|
|
943
|
-
|
|
1002
|
+
# 关键流程:直接调用 memory_manager 确保记忆提示
|
|
1003
|
+
try:
|
|
1004
|
+
self.memory_manager._ensure_memory_prompt(agent=self)
|
|
1005
|
+
except Exception:
|
|
1006
|
+
pass
|
|
1007
|
+
|
|
1008
|
+
# 非关键流程:广播清理历史前事件(用于日志、监控等)
|
|
944
1009
|
try:
|
|
945
1010
|
self.event_bus.emit(BEFORE_HISTORY_CLEAR, agent=self)
|
|
946
1011
|
except Exception:
|
|
947
1012
|
pass
|
|
1013
|
+
|
|
1014
|
+
# 清理历史(但不清理prompt,因为prompt会在builtin_input_handler中设置)
|
|
1015
|
+
if self.model:
|
|
948
1016
|
self.model.reset()
|
|
949
1017
|
# 重置后重新设置系统提示词,确保系统约束仍然生效
|
|
950
1018
|
self._setup_system_prompt()
|
|
@@ -952,7 +1020,10 @@ class Agent:
|
|
|
952
1020
|
self.session.clear_history()
|
|
953
1021
|
# 重置 addon_prompt 跳过轮数计数器
|
|
954
1022
|
self._addon_prompt_skip_rounds = 0
|
|
955
|
-
#
|
|
1023
|
+
# 重置没有工具调用的计数器
|
|
1024
|
+
self._no_tool_call_count = 0
|
|
1025
|
+
|
|
1026
|
+
# 非关键流程:广播清理历史后的事件(用于日志、监控等)
|
|
956
1027
|
try:
|
|
957
1028
|
self.event_bus.emit(AFTER_HISTORY_CLEAR, agent=self)
|
|
958
1029
|
except Exception:
|
|
@@ -962,15 +1033,25 @@ class Agent:
|
|
|
962
1033
|
|
|
963
1034
|
def _handle_history_with_file_upload(self) -> str:
|
|
964
1035
|
"""使用文件上传方式处理历史"""
|
|
965
|
-
#
|
|
1036
|
+
# 关键流程:直接调用 memory_manager 确保记忆提示
|
|
1037
|
+
try:
|
|
1038
|
+
self.memory_manager._ensure_memory_prompt(agent=self)
|
|
1039
|
+
except Exception:
|
|
1040
|
+
pass
|
|
1041
|
+
|
|
1042
|
+
# 非关键流程:广播清理历史前事件(用于日志、监控等)
|
|
966
1043
|
try:
|
|
967
1044
|
self.event_bus.emit(BEFORE_HISTORY_CLEAR, agent=self)
|
|
968
1045
|
except Exception:
|
|
969
1046
|
pass
|
|
1047
|
+
|
|
970
1048
|
result = self.file_methodology_manager.handle_history_with_file_upload()
|
|
971
1049
|
# 重置 addon_prompt 跳过轮数计数器
|
|
972
1050
|
self._addon_prompt_skip_rounds = 0
|
|
973
|
-
#
|
|
1051
|
+
# 重置没有工具调用的计数器
|
|
1052
|
+
self._no_tool_call_count = 0
|
|
1053
|
+
|
|
1054
|
+
# 非关键流程:广播清理历史后的事件(用于日志、监控等)
|
|
974
1055
|
try:
|
|
975
1056
|
self.event_bus.emit(AFTER_HISTORY_CLEAR, agent=self)
|
|
976
1057
|
except Exception:
|
|
@@ -1010,7 +1091,9 @@ class Agent:
|
|
|
1010
1091
|
# - TaskAnalyzer 通过订阅 before_summary/task_completed 事件执行分析与满意度收集
|
|
1011
1092
|
# - MemoryManager 通过订阅 before_history_clear/task_completed 事件执行记忆保存(受 force_save_memory 控制)
|
|
1012
1093
|
# 为减少耦合,这里不再直接调用上述组件,保持行为由事件触发
|
|
1013
|
-
|
|
1094
|
+
# 仅在启用自动记忆整理时检查并整理记忆
|
|
1095
|
+
if is_enable_memory_organizer():
|
|
1096
|
+
self._check_and_organize_memory()
|
|
1014
1097
|
|
|
1015
1098
|
result = "任务完成"
|
|
1016
1099
|
|
|
@@ -1020,8 +1103,20 @@ class Agent:
|
|
|
1020
1103
|
safe_summary_prompt = self.summary_prompt or ""
|
|
1021
1104
|
if isinstance(safe_summary_prompt, str) and safe_summary_prompt.strip() == "":
|
|
1022
1105
|
safe_summary_prompt = DEFAULT_SUMMARY_PROMPT
|
|
1023
|
-
# 注意:不要写回 session.prompt
|
|
1024
|
-
|
|
1106
|
+
# 注意:不要写回 session.prompt,避免回调修改/清空后导致使用空prompt
|
|
1107
|
+
|
|
1108
|
+
# 关键流程:直接调用 task_analyzer 执行任务分析
|
|
1109
|
+
try:
|
|
1110
|
+
self.task_analyzer._on_before_summary(
|
|
1111
|
+
agent=self,
|
|
1112
|
+
prompt=safe_summary_prompt,
|
|
1113
|
+
auto_completed=auto_completed,
|
|
1114
|
+
need_summary=self.need_summary,
|
|
1115
|
+
)
|
|
1116
|
+
except Exception:
|
|
1117
|
+
pass
|
|
1118
|
+
|
|
1119
|
+
# 非关键流程:广播将要生成总结事件(用于日志、监控等)
|
|
1025
1120
|
try:
|
|
1026
1121
|
self.event_bus.emit(
|
|
1027
1122
|
BEFORE_SUMMARY,
|
|
@@ -1040,13 +1135,13 @@ class Agent:
|
|
|
1040
1135
|
# 防御: 总结阶段模型可能返回空响应(None或空字符串),统一为空字符串并告警
|
|
1041
1136
|
if not ret:
|
|
1042
1137
|
try:
|
|
1043
|
-
|
|
1138
|
+
print("⚠️ 总结阶段模型返回空响应,已使用空字符串回退。")
|
|
1044
1139
|
except Exception:
|
|
1045
1140
|
pass
|
|
1046
1141
|
ret = ""
|
|
1047
1142
|
result = ret
|
|
1048
1143
|
|
|
1049
|
-
#
|
|
1144
|
+
# 非关键流程:广播完成总结事件(用于日志、监控等)
|
|
1050
1145
|
try:
|
|
1051
1146
|
self.event_bus.emit(
|
|
1052
1147
|
AFTER_SUMMARY,
|
|
@@ -1056,7 +1151,26 @@ class Agent:
|
|
|
1056
1151
|
except Exception:
|
|
1057
1152
|
pass
|
|
1058
1153
|
|
|
1059
|
-
|
|
1154
|
+
# 关键流程:直接调用 task_analyzer 和 memory_manager
|
|
1155
|
+
try:
|
|
1156
|
+
self.task_analyzer._on_task_completed(
|
|
1157
|
+
agent=self,
|
|
1158
|
+
auto_completed=auto_completed,
|
|
1159
|
+
need_summary=self.need_summary,
|
|
1160
|
+
)
|
|
1161
|
+
except Exception:
|
|
1162
|
+
pass
|
|
1163
|
+
|
|
1164
|
+
try:
|
|
1165
|
+
self.memory_manager._ensure_memory_prompt(
|
|
1166
|
+
agent=self,
|
|
1167
|
+
auto_completed=auto_completed,
|
|
1168
|
+
need_summary=self.need_summary,
|
|
1169
|
+
)
|
|
1170
|
+
except Exception:
|
|
1171
|
+
pass
|
|
1172
|
+
|
|
1173
|
+
# 非关键流程:广播任务完成事件(用于日志、监控等)
|
|
1060
1174
|
try:
|
|
1061
1175
|
self.event_bus.emit(
|
|
1062
1176
|
TASK_COMPLETED,
|
|
@@ -1077,10 +1191,12 @@ class Agent:
|
|
|
1077
1191
|
|
|
1078
1192
|
"""
|
|
1079
1193
|
# 优先使用 PromptManager 以保持逻辑集中
|
|
1080
|
-
|
|
1194
|
+
try:
|
|
1081
1195
|
return self.prompt_manager.build_default_addon_prompt(need_complete)
|
|
1196
|
+
except Exception:
|
|
1197
|
+
pass
|
|
1082
1198
|
|
|
1083
|
-
#
|
|
1199
|
+
# 结构化系统指令(回退方案)
|
|
1084
1200
|
action_handlers = ", ".join([handler.name() for handler in self.output_handler])
|
|
1085
1201
|
|
|
1086
1202
|
# 任务完成提示
|
|
@@ -1104,8 +1220,10 @@ class Agent:
|
|
|
1104
1220
|
如果没有完成,请进行下一步操作:
|
|
1105
1221
|
- 仅包含一个操作
|
|
1106
1222
|
- 如果信息不明确,请请求用户补充
|
|
1107
|
-
- 如果执行过程中连续失败5
|
|
1223
|
+
- 如果执行过程中连续失败5次,请请求用户操作
|
|
1108
1224
|
- 操作列表:{action_handlers}{memory_prompts}
|
|
1225
|
+
|
|
1226
|
+
注意:如果当前部分任务已完成,之前的上下文价值不大,可以输出<!!!SUMMARY!!!>标记来触发总结并清空历史,以便开始新的任务阶段。
|
|
1109
1227
|
</system_prompt>
|
|
1110
1228
|
|
|
1111
1229
|
请继续。
|
|
@@ -1131,7 +1249,19 @@ class Agent:
|
|
|
1131
1249
|
self.session.prompt = f"{user_input}"
|
|
1132
1250
|
try:
|
|
1133
1251
|
set_agent(self.name, self)
|
|
1134
|
-
|
|
1252
|
+
|
|
1253
|
+
# 关键流程:直接调用 memory_manager 重置任务状态
|
|
1254
|
+
try:
|
|
1255
|
+
self.memory_manager._on_task_started(
|
|
1256
|
+
agent=self,
|
|
1257
|
+
name=self.name,
|
|
1258
|
+
description=self.description,
|
|
1259
|
+
user_input=self.session.prompt,
|
|
1260
|
+
)
|
|
1261
|
+
except Exception:
|
|
1262
|
+
pass
|
|
1263
|
+
|
|
1264
|
+
# 非关键流程:广播任务开始事件(用于日志、监控等)
|
|
1135
1265
|
try:
|
|
1136
1266
|
self.event_bus.emit(
|
|
1137
1267
|
TASK_STARTED,
|
|
@@ -1142,16 +1272,9 @@ class Agent:
|
|
|
1142
1272
|
)
|
|
1143
1273
|
except Exception:
|
|
1144
1274
|
pass
|
|
1145
|
-
# 如启用规划模式,先判断是否需要拆分并调度子任务
|
|
1146
|
-
if self.plan:
|
|
1147
|
-
try:
|
|
1148
|
-
self._maybe_plan_and_dispatch(self.session.prompt)
|
|
1149
|
-
except Exception:
|
|
1150
|
-
# 防御式处理,规划失败不影响主流程
|
|
1151
|
-
pass
|
|
1152
1275
|
return self._main_loop()
|
|
1153
1276
|
except Exception as e:
|
|
1154
|
-
|
|
1277
|
+
print(f"❌ 任务失败: {str(e)}")
|
|
1155
1278
|
return f"Task failed: {str(e)}"
|
|
1156
1279
|
|
|
1157
1280
|
def _main_loop(self) -> Any:
|
|
@@ -1277,37 +1400,21 @@ class Agent:
|
|
|
1277
1400
|
"use_tools": use_tools_param,
|
|
1278
1401
|
"execute_tool_confirm": self.execute_tool_confirm,
|
|
1279
1402
|
"need_summary": self.need_summary,
|
|
1280
|
-
"auto_summary_rounds": self.auto_summary_rounds,
|
|
1281
1403
|
"multiline_inputer": self.multiline_inputer,
|
|
1282
1404
|
"use_methodology": self.use_methodology,
|
|
1283
1405
|
"use_analysis": self.use_analysis,
|
|
1284
1406
|
"force_save_memory": self.force_save_memory,
|
|
1285
|
-
"disable_file_edit": self.disable_file_edit,
|
|
1286
1407
|
"files": self.files,
|
|
1287
1408
|
"confirm_callback": self.confirm_callback,
|
|
1288
1409
|
"non_interactive": True,
|
|
1289
1410
|
"in_multi_agent": True,
|
|
1290
|
-
"plan": self.plan, # 继承父Agent的规划开关
|
|
1291
|
-
"plan_depth": self.plan_depth + 1, # 子Agent层数+1
|
|
1292
|
-
"plan_max_depth": self.plan_max_depth, # 继承上限
|
|
1293
1411
|
}
|
|
1294
1412
|
|
|
1295
|
-
def _maybe_plan_and_dispatch(self, task_text: str) -> None:
|
|
1296
|
-
"""委托给 TaskPlanner 执行任务规划与子任务调度,保持向后兼容。"""
|
|
1297
|
-
try:
|
|
1298
|
-
if hasattr(self, "task_planner") and self.task_planner:
|
|
1299
|
-
# 优先使用初始化时注入的规划器
|
|
1300
|
-
self.task_planner.maybe_plan_and_dispatch(task_text) # type: ignore[attr-defined]
|
|
1301
|
-
else:
|
|
1302
|
-
# 防御式回退:临时创建规划器以避免因未初始化导致的崩溃
|
|
1303
|
-
from jarvis.jarvis_agent.task_planner import TaskPlanner
|
|
1304
|
-
TaskPlanner(self, plan_depth=self.plan_depth, plan_max_depth=self.plan_max_depth).maybe_plan_and_dispatch(task_text)
|
|
1305
|
-
except Exception:
|
|
1306
|
-
# 规划失败不影响主流程
|
|
1307
|
-
pass
|
|
1308
|
-
|
|
1309
1413
|
def _filter_tools_if_needed(self, task: str):
|
|
1310
|
-
"""如果工具数量超过阈值,使用大模型筛选相关工具
|
|
1414
|
+
"""如果工具数量超过阈值,使用大模型筛选相关工具
|
|
1415
|
+
|
|
1416
|
+
注意:仅筛选用户自定义工具,内置工具不参与筛选(始终保留)
|
|
1417
|
+
"""
|
|
1311
1418
|
tool_registry = self.get_tool_registry()
|
|
1312
1419
|
if not isinstance(tool_registry, ToolRegistry):
|
|
1313
1420
|
return
|
|
@@ -1317,10 +1424,16 @@ class Agent:
|
|
|
1317
1424
|
if len(all_tools) <= threshold:
|
|
1318
1425
|
return
|
|
1319
1426
|
|
|
1320
|
-
#
|
|
1427
|
+
# 获取用户自定义工具(非内置工具),仅对这些工具进行筛选
|
|
1428
|
+
custom_tools = tool_registry.get_custom_tools()
|
|
1429
|
+
if not custom_tools:
|
|
1430
|
+
# 没有用户自定义工具,无需筛选
|
|
1431
|
+
return
|
|
1432
|
+
|
|
1433
|
+
# 为工具选择构建提示(仅包含用户自定义工具)
|
|
1321
1434
|
tools_prompt_part = ""
|
|
1322
1435
|
tool_names = []
|
|
1323
|
-
for i, tool in enumerate(
|
|
1436
|
+
for i, tool in enumerate(custom_tools, 1):
|
|
1324
1437
|
tool_names.append(tool["name"])
|
|
1325
1438
|
tools_prompt_part += f"{i}. {tool['name']}: {tool['description']}\n"
|
|
1326
1439
|
|
|
@@ -1338,9 +1451,7 @@ class Agent:
|
|
|
1338
1451
|
请根据用户任务,从列表中选择最相关的工具。
|
|
1339
1452
|
请仅返回所选工具的编号,以逗号分隔。例如:1, 5, 12
|
|
1340
1453
|
"""
|
|
1341
|
-
|
|
1342
|
-
f"工具数量超过{threshold}个,正在使用AI筛选相关工具...", OutputType.INFO
|
|
1343
|
-
)
|
|
1454
|
+
print(f"ℹ️ 工具数量超过{threshold}个,正在使用AI筛选相关工具...")
|
|
1344
1455
|
# 广播工具筛选开始事件
|
|
1345
1456
|
try:
|
|
1346
1457
|
self.event_bus.emit(
|
|
@@ -1373,13 +1484,13 @@ class Agent:
|
|
|
1373
1484
|
if selected_tool_names:
|
|
1374
1485
|
# 移除重复项
|
|
1375
1486
|
selected_tool_names = sorted(list(set(selected_tool_names)))
|
|
1376
|
-
|
|
1487
|
+
# 合并内置工具名称和筛选出的用户自定义工具名称
|
|
1488
|
+
builtin_names = list(tool_registry._builtin_tool_names)
|
|
1489
|
+
final_tool_names = sorted(list(set(builtin_names + selected_tool_names)))
|
|
1490
|
+
tool_registry.use_tools(final_tool_names)
|
|
1377
1491
|
# 使用筛选后的工具列表重新设置系统提示
|
|
1378
1492
|
self._setup_system_prompt()
|
|
1379
|
-
|
|
1380
|
-
f"已筛选出 {len(selected_tool_names)} 个相关工具: {', '.join(selected_tool_names)}",
|
|
1381
|
-
OutputType.SUCCESS,
|
|
1382
|
-
)
|
|
1493
|
+
print(f"✅ 已筛选出 {len(selected_tool_names)} 个相关工具: {', '.join(selected_tool_names)}")
|
|
1383
1494
|
# 广播工具筛选事件
|
|
1384
1495
|
try:
|
|
1385
1496
|
self.event_bus.emit(
|
|
@@ -1393,9 +1504,7 @@ class Agent:
|
|
|
1393
1504
|
except Exception:
|
|
1394
1505
|
pass
|
|
1395
1506
|
else:
|
|
1396
|
-
|
|
1397
|
-
"AI 未能筛选出任何相关工具,将使用所有工具。", OutputType.WARNING
|
|
1398
|
-
)
|
|
1507
|
+
print("⚠️ AI 未能筛选出任何相关工具,将使用所有工具。")
|
|
1399
1508
|
# 广播工具筛选事件(无筛选结果)
|
|
1400
1509
|
try:
|
|
1401
1510
|
self.event_bus.emit(
|
|
@@ -1410,9 +1519,7 @@ class Agent:
|
|
|
1410
1519
|
pass
|
|
1411
1520
|
|
|
1412
1521
|
except Exception as e:
|
|
1413
|
-
|
|
1414
|
-
f"工具筛选失败: {e},将使用所有工具。", OutputType.ERROR
|
|
1415
|
-
)
|
|
1522
|
+
print(f"❌ 工具筛选失败: {e},将使用所有工具。")
|
|
1416
1523
|
|
|
1417
1524
|
def _check_and_organize_memory(self):
|
|
1418
1525
|
"""
|
|
@@ -1429,7 +1536,7 @@ class Agent:
|
|
|
1429
1536
|
"global",
|
|
1430
1537
|
)
|
|
1431
1538
|
except Exception as e:
|
|
1432
|
-
|
|
1539
|
+
print(f"⚠️ 检查记忆库时发生意外错误: {e}")
|
|
1433
1540
|
|
|
1434
1541
|
def _perform_memory_check(self, memory_type: str, base_path: Path, scope_name: str):
|
|
1435
1542
|
"""执行特定范围的记忆检查和整理"""
|
|
@@ -1470,11 +1577,8 @@ class Agent:
|
|
|
1470
1577
|
f"并且存在3个以上标签重叠的记忆。\n"
|
|
1471
1578
|
f"是否立即整理记忆库以优化性能和相关性?"
|
|
1472
1579
|
)
|
|
1473
|
-
if self.confirm_callback(prompt,
|
|
1474
|
-
|
|
1475
|
-
f"正在开始整理 '{scope_name}' ({memory_type}) 记忆库...",
|
|
1476
|
-
OutputType.INFO,
|
|
1477
|
-
)
|
|
1580
|
+
if self.confirm_callback(prompt, False):
|
|
1581
|
+
print(f"ℹ️ 正在开始整理 '{scope_name}' ({memory_type}) 记忆库...")
|
|
1478
1582
|
organizer.organize_memories(memory_type, min_overlap=3)
|
|
1479
1583
|
else:
|
|
1480
|
-
|
|
1584
|
+
print(f"ℹ️ 已取消 '{scope_name}' 记忆库整理。")
|