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.
Files changed (279) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +567 -222
  3. jarvis/jarvis_agent/agent_manager.py +19 -12
  4. jarvis/jarvis_agent/builtin_input_handler.py +79 -11
  5. jarvis/jarvis_agent/config_editor.py +7 -2
  6. jarvis/jarvis_agent/event_bus.py +24 -13
  7. jarvis/jarvis_agent/events.py +19 -1
  8. jarvis/jarvis_agent/file_context_handler.py +67 -64
  9. jarvis/jarvis_agent/file_methodology_manager.py +38 -24
  10. jarvis/jarvis_agent/jarvis.py +186 -114
  11. jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
  12. jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
  13. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
  14. jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
  15. jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
  16. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
  17. jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
  18. jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
  19. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
  20. jarvis/jarvis_agent/language_support_info.py +250 -219
  21. jarvis/jarvis_agent/main.py +19 -23
  22. jarvis/jarvis_agent/memory_manager.py +9 -6
  23. jarvis/jarvis_agent/methodology_share_manager.py +21 -15
  24. jarvis/jarvis_agent/output_handler.py +4 -2
  25. jarvis/jarvis_agent/prompt_builder.py +7 -6
  26. jarvis/jarvis_agent/prompt_manager.py +113 -8
  27. jarvis/jarvis_agent/prompts.py +317 -85
  28. jarvis/jarvis_agent/protocols.py +5 -2
  29. jarvis/jarvis_agent/run_loop.py +192 -32
  30. jarvis/jarvis_agent/session_manager.py +7 -3
  31. jarvis/jarvis_agent/share_manager.py +23 -13
  32. jarvis/jarvis_agent/shell_input_handler.py +12 -8
  33. jarvis/jarvis_agent/stdio_redirect.py +25 -26
  34. jarvis/jarvis_agent/task_analyzer.py +29 -23
  35. jarvis/jarvis_agent/task_list.py +869 -0
  36. jarvis/jarvis_agent/task_manager.py +26 -23
  37. jarvis/jarvis_agent/tool_executor.py +6 -5
  38. jarvis/jarvis_agent/tool_share_manager.py +24 -14
  39. jarvis/jarvis_agent/user_interaction.py +3 -3
  40. jarvis/jarvis_agent/utils.py +9 -1
  41. jarvis/jarvis_agent/web_bridge.py +37 -17
  42. jarvis/jarvis_agent/web_output_sink.py +5 -2
  43. jarvis/jarvis_agent/web_server.py +165 -36
  44. jarvis/jarvis_c2rust/__init__.py +1 -1
  45. jarvis/jarvis_c2rust/cli.py +260 -141
  46. jarvis/jarvis_c2rust/collector.py +37 -18
  47. jarvis/jarvis_c2rust/constants.py +60 -0
  48. jarvis/jarvis_c2rust/library_replacer.py +242 -1010
  49. jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
  50. jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
  51. jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
  52. jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
  53. jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
  54. jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
  55. jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
  56. jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
  57. jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
  58. jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
  59. jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
  60. jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
  61. jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
  62. jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
  63. jarvis/jarvis_c2rust/loaders.py +28 -10
  64. jarvis/jarvis_c2rust/models.py +5 -2
  65. jarvis/jarvis_c2rust/optimizer.py +192 -1974
  66. jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
  67. jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
  68. jarvis/jarvis_c2rust/optimizer_config.py +49 -0
  69. jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
  70. jarvis/jarvis_c2rust/optimizer_options.py +48 -0
  71. jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
  72. jarvis/jarvis_c2rust/optimizer_report.py +52 -0
  73. jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
  74. jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
  75. jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
  76. jarvis/jarvis_c2rust/scanner.py +229 -166
  77. jarvis/jarvis_c2rust/transpiler.py +531 -2732
  78. jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
  79. jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
  80. jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
  81. jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
  82. jarvis/jarvis_c2rust/transpiler_config.py +178 -0
  83. jarvis/jarvis_c2rust/transpiler_context.py +122 -0
  84. jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
  85. jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
  86. jarvis/jarvis_c2rust/transpiler_git.py +163 -0
  87. jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
  88. jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
  89. jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
  90. jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
  91. jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
  92. jarvis/jarvis_c2rust/utils.py +269 -79
  93. jarvis/jarvis_code_agent/after_change.py +233 -0
  94. jarvis/jarvis_code_agent/build_validation_config.py +37 -30
  95. jarvis/jarvis_code_agent/builtin_rules.py +68 -0
  96. jarvis/jarvis_code_agent/code_agent.py +976 -1517
  97. jarvis/jarvis_code_agent/code_agent_build.py +227 -0
  98. jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
  99. jarvis/jarvis_code_agent/code_agent_git.py +525 -0
  100. jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
  101. jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
  102. jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
  103. jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
  104. jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
  105. jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
  106. jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
  107. jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
  108. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
  109. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
  110. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
  111. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
  112. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
  113. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
  114. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
  115. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
  116. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
  117. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
  118. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
  119. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
  120. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
  121. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
  122. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
  123. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
  124. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
  125. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
  126. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
  127. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
  128. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
  129. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
  130. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
  131. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
  132. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
  133. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
  134. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
  135. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
  136. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
  137. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
  138. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
  139. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
  140. jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
  141. jarvis/jarvis_code_agent/lint.py +223 -524
  142. jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
  143. jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
  144. jarvis/jarvis_code_agent/rules/code_review.md +115 -0
  145. jarvis/jarvis_code_agent/rules/documentation.md +165 -0
  146. jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
  147. jarvis/jarvis_code_agent/rules/performance.md +158 -0
  148. jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
  149. jarvis/jarvis_code_agent/rules/security.md +160 -0
  150. jarvis/jarvis_code_agent/rules/tdd.md +78 -0
  151. jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
  152. jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
  153. jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
  154. jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
  155. jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
  156. jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
  157. jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
  158. jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
  159. jarvis/jarvis_code_agent/utils.py +36 -26
  160. jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
  161. jarvis/jarvis_code_analysis/code_review.py +64 -33
  162. jarvis/jarvis_data/config_schema.json +285 -192
  163. jarvis/jarvis_git_squash/main.py +8 -6
  164. jarvis/jarvis_git_utils/git_commiter.py +53 -76
  165. jarvis/jarvis_mcp/__init__.py +5 -2
  166. jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
  167. jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
  168. jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
  169. jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
  170. jarvis/jarvis_methodology/main.py +48 -39
  171. jarvis/jarvis_multi_agent/__init__.py +56 -23
  172. jarvis/jarvis_multi_agent/main.py +15 -18
  173. jarvis/jarvis_platform/base.py +179 -111
  174. jarvis/jarvis_platform/human.py +27 -16
  175. jarvis/jarvis_platform/kimi.py +52 -45
  176. jarvis/jarvis_platform/openai.py +101 -40
  177. jarvis/jarvis_platform/registry.py +51 -33
  178. jarvis/jarvis_platform/tongyi.py +68 -38
  179. jarvis/jarvis_platform/yuanbao.py +59 -43
  180. jarvis/jarvis_platform_manager/main.py +68 -76
  181. jarvis/jarvis_platform_manager/service.py +24 -14
  182. jarvis/jarvis_rag/README_CONFIG.md +314 -0
  183. jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
  184. jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
  185. jarvis/jarvis_rag/__init__.py +57 -4
  186. jarvis/jarvis_rag/cache.py +3 -1
  187. jarvis/jarvis_rag/cli.py +48 -68
  188. jarvis/jarvis_rag/embedding_interface.py +39 -0
  189. jarvis/jarvis_rag/embedding_manager.py +7 -230
  190. jarvis/jarvis_rag/embeddings/__init__.py +41 -0
  191. jarvis/jarvis_rag/embeddings/base.py +114 -0
  192. jarvis/jarvis_rag/embeddings/cohere.py +66 -0
  193. jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
  194. jarvis/jarvis_rag/embeddings/local.py +260 -0
  195. jarvis/jarvis_rag/embeddings/openai.py +62 -0
  196. jarvis/jarvis_rag/embeddings/registry.py +293 -0
  197. jarvis/jarvis_rag/llm_interface.py +8 -6
  198. jarvis/jarvis_rag/query_rewriter.py +8 -9
  199. jarvis/jarvis_rag/rag_pipeline.py +61 -52
  200. jarvis/jarvis_rag/reranker.py +7 -75
  201. jarvis/jarvis_rag/reranker_interface.py +32 -0
  202. jarvis/jarvis_rag/rerankers/__init__.py +41 -0
  203. jarvis/jarvis_rag/rerankers/base.py +109 -0
  204. jarvis/jarvis_rag/rerankers/cohere.py +67 -0
  205. jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
  206. jarvis/jarvis_rag/rerankers/jina.py +79 -0
  207. jarvis/jarvis_rag/rerankers/local.py +89 -0
  208. jarvis/jarvis_rag/rerankers/registry.py +293 -0
  209. jarvis/jarvis_rag/retriever.py +58 -43
  210. jarvis/jarvis_sec/__init__.py +66 -141
  211. jarvis/jarvis_sec/agents.py +21 -17
  212. jarvis/jarvis_sec/analysis.py +80 -33
  213. jarvis/jarvis_sec/checkers/__init__.py +7 -13
  214. jarvis/jarvis_sec/checkers/c_checker.py +356 -164
  215. jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
  216. jarvis/jarvis_sec/cli.py +43 -21
  217. jarvis/jarvis_sec/clustering.py +430 -272
  218. jarvis/jarvis_sec/file_manager.py +99 -55
  219. jarvis/jarvis_sec/parsers.py +9 -6
  220. jarvis/jarvis_sec/prompts.py +4 -3
  221. jarvis/jarvis_sec/report.py +44 -22
  222. jarvis/jarvis_sec/review.py +180 -107
  223. jarvis/jarvis_sec/status.py +50 -41
  224. jarvis/jarvis_sec/types.py +3 -0
  225. jarvis/jarvis_sec/utils.py +160 -83
  226. jarvis/jarvis_sec/verification.py +411 -181
  227. jarvis/jarvis_sec/workflow.py +132 -21
  228. jarvis/jarvis_smart_shell/main.py +28 -41
  229. jarvis/jarvis_stats/cli.py +14 -12
  230. jarvis/jarvis_stats/stats.py +28 -19
  231. jarvis/jarvis_stats/storage.py +14 -8
  232. jarvis/jarvis_stats/visualizer.py +12 -7
  233. jarvis/jarvis_tools/base.py +5 -2
  234. jarvis/jarvis_tools/clear_memory.py +13 -9
  235. jarvis/jarvis_tools/cli/main.py +23 -18
  236. jarvis/jarvis_tools/edit_file.py +572 -873
  237. jarvis/jarvis_tools/execute_script.py +10 -7
  238. jarvis/jarvis_tools/file_analyzer.py +7 -8
  239. jarvis/jarvis_tools/meta_agent.py +287 -0
  240. jarvis/jarvis_tools/methodology.py +5 -3
  241. jarvis/jarvis_tools/read_code.py +305 -1438
  242. jarvis/jarvis_tools/read_symbols.py +50 -17
  243. jarvis/jarvis_tools/read_webpage.py +19 -18
  244. jarvis/jarvis_tools/registry.py +435 -156
  245. jarvis/jarvis_tools/retrieve_memory.py +16 -11
  246. jarvis/jarvis_tools/save_memory.py +8 -6
  247. jarvis/jarvis_tools/search_web.py +31 -31
  248. jarvis/jarvis_tools/sub_agent.py +32 -28
  249. jarvis/jarvis_tools/sub_code_agent.py +44 -60
  250. jarvis/jarvis_tools/task_list_manager.py +1811 -0
  251. jarvis/jarvis_tools/virtual_tty.py +29 -19
  252. jarvis/jarvis_utils/__init__.py +4 -0
  253. jarvis/jarvis_utils/builtin_replace_map.py +2 -1
  254. jarvis/jarvis_utils/clipboard.py +9 -8
  255. jarvis/jarvis_utils/collections.py +331 -0
  256. jarvis/jarvis_utils/config.py +699 -194
  257. jarvis/jarvis_utils/dialogue_recorder.py +294 -0
  258. jarvis/jarvis_utils/embedding.py +6 -3
  259. jarvis/jarvis_utils/file_processors.py +7 -1
  260. jarvis/jarvis_utils/fzf.py +9 -3
  261. jarvis/jarvis_utils/git_utils.py +71 -42
  262. jarvis/jarvis_utils/globals.py +116 -32
  263. jarvis/jarvis_utils/http.py +6 -2
  264. jarvis/jarvis_utils/input.py +318 -83
  265. jarvis/jarvis_utils/jsonnet_compat.py +119 -104
  266. jarvis/jarvis_utils/methodology.py +37 -28
  267. jarvis/jarvis_utils/output.py +201 -44
  268. jarvis/jarvis_utils/utils.py +986 -628
  269. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
  270. jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
  271. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
  272. jarvis/jarvis_tools/generate_new_tool.py +0 -205
  273. jarvis/jarvis_tools/lsp_client.py +0 -1552
  274. jarvis/jarvis_tools/rewrite_file.py +0 -105
  275. jarvis_ai_assistant-0.7.16.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -5,10 +5,15 @@ import os
5
5
  import platform
6
6
  import re
7
7
  import sys
8
- from pathlib import Path
9
8
  from enum import Enum
10
- from typing import Any, Callable, Dict, List, Optional, Tuple, Union
11
-
9
+ from pathlib import Path
10
+ from typing import Any
11
+ from typing import Callable
12
+ from typing import Dict
13
+ from typing import List
14
+ from typing import Optional
15
+ from typing import Tuple
16
+ from typing import Union
12
17
 
13
18
  # 第三方库导入
14
19
  from rich.align import Align
@@ -16,76 +21,73 @@ from rich.console import Console
16
21
  from rich.panel import Panel
17
22
  from rich.text import Text
18
23
 
24
+ from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
25
+ from jarvis.jarvis_agent.event_bus import EventBus
26
+ from jarvis.jarvis_agent.events import AFTER_ADDON_PROMPT
27
+ from jarvis.jarvis_agent.events import AFTER_HISTORY_CLEAR
28
+ from jarvis.jarvis_agent.events import AFTER_MODEL_CALL
29
+ from jarvis.jarvis_agent.events import AFTER_SUMMARY
30
+ from jarvis.jarvis_agent.events import AFTER_TOOL_CALL
31
+ from jarvis.jarvis_agent.events import BEFORE_ADDON_PROMPT
32
+ from jarvis.jarvis_agent.events import BEFORE_HISTORY_CLEAR
33
+ from jarvis.jarvis_agent.events import BEFORE_MODEL_CALL
34
+ from jarvis.jarvis_agent.events import BEFORE_SUMMARY
35
+ from jarvis.jarvis_agent.events import BEFORE_TOOL_FILTER
36
+ from jarvis.jarvis_agent.events import INTERRUPT_TRIGGERED
37
+ from jarvis.jarvis_agent.events import TASK_COMPLETED
38
+ from jarvis.jarvis_agent.events import TASK_STARTED
39
+ from jarvis.jarvis_agent.events import TOOL_FILTERED
40
+ from jarvis.jarvis_agent.file_context_handler import file_context_handler
41
+ from jarvis.jarvis_agent.file_methodology_manager import FileMethodologyManager
42
+ from jarvis.jarvis_agent.memory_manager import MemoryManager
43
+
19
44
  # 本地库导入
20
45
  # jarvis_agent 相关
21
46
  from jarvis.jarvis_agent.prompt_builder import build_action_prompt
47
+ from jarvis.jarvis_agent.prompt_manager import PromptManager
48
+ from jarvis.jarvis_agent.prompts import DEFAULT_SUMMARY_PROMPT
49
+ from jarvis.jarvis_agent.prompts import SUMMARY_REQUEST_PROMPT
22
50
  from jarvis.jarvis_agent.protocols import OutputHandlerProtocol
51
+ from jarvis.jarvis_agent.run_loop import AgentRunLoop
23
52
  from jarvis.jarvis_agent.session_manager import SessionManager
24
- from jarvis.jarvis_agent.tool_executor import execute_tool_call
25
- from jarvis.jarvis_agent.memory_manager import MemoryManager
26
- from jarvis.jarvis_memory_organizer.memory_organizer import MemoryOrganizer
53
+ from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
27
54
  from jarvis.jarvis_agent.task_analyzer import TaskAnalyzer
28
- from jarvis.jarvis_agent.file_methodology_manager import FileMethodologyManager
29
- from jarvis.jarvis_agent.prompts import (
30
- DEFAULT_SUMMARY_PROMPT,
31
- SUMMARY_REQUEST_PROMPT,
32
- TASK_ANALYSIS_PROMPT, # noqa: F401
33
- )
34
- from jarvis.jarvis_tools.registry import ToolRegistry
35
- from jarvis.jarvis_agent.prompt_manager import PromptManager
36
- from jarvis.jarvis_agent.event_bus import EventBus
37
- from jarvis.jarvis_agent.run_loop import AgentRunLoop
38
- from jarvis.jarvis_agent.events import (
39
- BEFORE_SUMMARY,
40
- AFTER_SUMMARY,
41
- TASK_COMPLETED,
42
- TASK_STARTED,
43
- BEFORE_ADDON_PROMPT,
44
- AFTER_ADDON_PROMPT,
45
- BEFORE_HISTORY_CLEAR,
46
- AFTER_HISTORY_CLEAR,
47
- BEFORE_MODEL_CALL,
48
- AFTER_MODEL_CALL,
49
- INTERRUPT_TRIGGERED,
50
- BEFORE_TOOL_FILTER,
51
- TOOL_FILTERED,
52
- AFTER_TOOL_CALL,
53
- )
55
+ from jarvis.jarvis_agent.task_list import TaskListManager
56
+ from jarvis.jarvis_agent.tool_executor import execute_tool_call
54
57
  from jarvis.jarvis_agent.user_interaction import UserInteractionHandler
55
58
  from jarvis.jarvis_agent.utils import join_prompts
56
- from jarvis.jarvis_utils.methodology import _load_all_methodologies
57
- from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
58
- from jarvis.jarvis_agent.file_context_handler import file_context_handler
59
- from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
59
+ from jarvis.jarvis_memory_organizer.memory_organizer import MemoryOrganizer
60
60
 
61
61
  # jarvis_platform 相关
62
62
  from jarvis.jarvis_platform.base import BasePlatform
63
63
  from jarvis.jarvis_platform.registry import PlatformRegistry
64
+ from jarvis.jarvis_tools.registry import ToolRegistry
64
65
 
65
66
  # jarvis_utils 相关
66
- from jarvis.jarvis_utils.config import (
67
- get_data_dir,
68
- get_normal_model_name,
69
- get_normal_platform_name,
70
- is_execute_tool_confirm,
71
- is_force_save_memory,
72
- is_use_analysis,
73
- is_use_methodology,
74
- get_tool_filter_threshold,
75
- get_after_tool_call_cb_dirs,
76
- get_addon_prompt_threshold,
77
- is_enable_memory_organizer,
78
- )
67
+ from jarvis.jarvis_utils.config import get_addon_prompt_threshold
68
+ from jarvis.jarvis_utils.config import get_after_tool_call_cb_dirs
69
+ from jarvis.jarvis_utils.config import get_data_dir
70
+ from jarvis.jarvis_utils.config import get_normal_model_name
71
+ from jarvis.jarvis_utils.config import get_normal_platform_name
72
+ from jarvis.jarvis_utils.config import get_tool_filter_threshold
73
+ from jarvis.jarvis_utils.config import is_enable_memory_organizer
74
+ from jarvis.jarvis_utils.config import is_execute_tool_confirm
75
+ from jarvis.jarvis_utils.config import is_force_save_memory
76
+ from jarvis.jarvis_utils.config import is_use_analysis
77
+ from jarvis.jarvis_utils.config import is_use_methodology
79
78
  from jarvis.jarvis_utils.embedding import get_context_token_count
80
- from jarvis.jarvis_utils.globals import (
81
- delete_agent,
82
- get_interrupt,
83
- get_short_term_memories,
84
- make_agent_name,
85
- set_agent,
86
- set_interrupt,
87
- )
88
- from jarvis.jarvis_utils.input import get_multiline_input, user_confirm
79
+ from jarvis.jarvis_utils.globals import clear_current_agent
80
+ from jarvis.jarvis_utils.globals import get_interrupt
81
+ from jarvis.jarvis_utils.globals import get_short_term_memories
82
+ from jarvis.jarvis_utils.globals import make_agent_name
83
+ from jarvis.jarvis_utils.globals import set_global_model_group
84
+ from jarvis.jarvis_utils.globals import set_interrupt
85
+ from jarvis.jarvis_utils.globals import set_current_agent
86
+ from jarvis.jarvis_utils.input import get_multiline_input
87
+ from jarvis.jarvis_utils.input import user_confirm
88
+ from jarvis.jarvis_utils.methodology import _load_all_methodologies
89
+ from jarvis.jarvis_utils.output import PrettyOutput
90
+ from jarvis.jarvis_utils.tag import ct
89
91
  from jarvis.jarvis_utils.tag import ot
90
92
 
91
93
 
@@ -143,7 +145,9 @@ def show_agent_startup_stats(
143
145
 
144
146
  # 构建欢迎信息
145
147
  platform = platform_name or get_normal_platform_name()
146
- welcome_message = f"{agent_name} 初始化完成 - 使用 {platform} 平台 {model_name} 模型"
148
+ welcome_message = (
149
+ f"{agent_name} 初始化完成 - 使用 {platform} 平台 {model_name} 模型"
150
+ )
147
151
 
148
152
  stats_parts = [
149
153
  f"📚 本地方法论: [bold cyan]{methodology_count}[/bold cyan]",
@@ -186,54 +190,47 @@ def show_agent_startup_stats(
186
190
  console.print(Align.center(panel))
187
191
 
188
192
  except Exception as e:
189
- print(f"⚠️ 加载统计信息失败: {e}")
193
+ PrettyOutput.auto_print(f"⚠️ 加载统计信息失败: {e}")
190
194
 
191
195
 
192
196
  origin_agent_system_prompt = f"""
193
197
  <role>
194
- # 🤖 角色
195
- 你是一个专业的任务执行助手,根据用户需求制定并执行详细的计划。
198
+ # 🤖 Jarvis Agent
199
+ 你是一个专业的任务执行助手,根据用户需求制定并执行详细计划。
196
200
  </role>
197
201
 
198
- <rules>
199
- # ❗ 核心规则
200
- 1. **单步操作**: 每个响应必须包含且仅包含一个工具调用。
201
- 2. **任务终结**: 当任务完成时,明确指出任务已完成。这是唯一可以不调用工具的例外。
202
- 3. **无响应错误**: 空响应或仅有分析无工具调用的响应是致命错误,会导致系统挂起。
203
- 4. **决策即工具**: 所有的决策和分析都必须通过工具调用来体现。
204
- 5. **等待结果**: 在继续下一步之前,必须等待当前工具的执行结果。
205
- 6. **持续推进**: 除非任务完成,否则必须生成可操作的下一步。
206
- 7. **记录沉淀**: 如果解决方案有普适价值,应记录为方法论。
207
- 8. **用户语言**: 始终使用用户的语言进行交流。
208
- </rules>
209
-
210
- <workflow>
211
- # 🔄 工作流程
212
- 1. **分析**: 理解和分析问题,定义清晰的目标。
213
- 2. **设计**: 设计解决方案并制定详细的行动计划。
214
- 3. **执行**: 按照计划,一次一个步骤地执行。
215
- 4. **完成**: 验证任务是否达成目标,并进行总结。
216
- </workflow>
217
-
218
- <sub_agents_guide>
219
- # 子任务工具使用建议
220
- - 使用 sub_code_agent(代码子Agent)当:
221
- - 需要在当前任务下并行推进较大且相对独立的代码改造
222
- - 涉及多文件/多模块的大范围变更,或需要较长的工具调用链
223
- - 需要隔离上下文以避免污染当前对话(如探索性改动、PoC)
224
- - 需要专注于单一代码子问题,阶段性产出可复用的结果
225
- - 使用 sub_agent(通用子Agent)当:
226
- - 子任务不是以代码改造为主(如调研、方案撰写、评审总结、用例设计、文档生成等)
227
- - 只是需要短期分流一个轻量的辅助性子任务
228
- 说明:
229
- - 两者仅需参数 task(可选 background 提供上下文),完成后返回结果给父Agent
230
- - 子Agent将自动完成并生成总结,请在上层根据返回结果继续编排
231
- </sub_agents_guide>
202
+ ## 核心模式
203
+ 每个响应必须以[MODE: MODE_NAME]开头:
204
+ - **INTENT**: 理解用户需求
205
+ - **RESEARCH**: 收集信息
206
+ - **INNOVATE**: 探索方案
207
+ - **PLAN**: 制定计划(复杂任务用task_list_manager)
208
+ - **EXECUTE**: 执行操作
209
+ - **REVIEW**: 验证结果
210
+
211
+ ### IIRIPER 工作流强制约束
212
+ - 整体工作流必须严格按照 **INTENT → RESEARCH → INNOVATE → PLAN → EXECUTE → REVIEW** 的顺序推进。
213
+ - **禁止跳步或乱序**:例如,不能在未经过 PLAN 就直接进入 EXECUTE,也不能从 INTENT 直接跳到 REVIEW。
214
+ - 如因用户以非常明确的指令要求跳过某阶段,必须在当前回复中:
215
+ - 明确指出被跳过的阶段;
216
+ - 解释为什么认为可以跳过;
217
+ - 简要提示可能的风险。
218
+
219
+ ## 执行规则
220
+ 1. **单次操作**: 每个响应只含一个工具调用
221
+ 2. **禁止虚构**: 必须基于实际结果,禁止假设
222
+ 3. **任务列表**: 复杂任务用task_list_manager,简单任务直接执行
223
+ 4. **必须验证**: 代码需编译通过、功能验证
224
+ 5. **模式转换**: 需明确信号"ENTER [MODE]"
225
+
226
+ ## 工具使用
227
+ - 优先用task_list_manager执行复杂任务
228
+ - execute_task必须提供additional_info参数
229
+ - 禁止同时调用多个工具
232
230
 
233
231
  <system_info>
234
- # 系统信息
235
- - OS: {platform.platform()} {platform.version()}
236
- - Time: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
232
+ OS: {platform.platform()} {platform.version()}
233
+ Time: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
237
234
  </system_info>
238
235
  """
239
236
 
@@ -259,12 +256,18 @@ class Agent:
259
256
  Clears the current conversation history by delegating to the session manager.
260
257
  直接调用关键流程函数,事件总线仅用于非关键流程(如日志、监控等)。
261
258
  """
259
+ # 获取当前会话文件路径用于提示
260
+ from jarvis.jarvis_utils.dialogue_recorder import get_global_recorder
261
+
262
+ recorder = get_global_recorder()
263
+ session_file_path = recorder.get_session_file_path()
264
+
262
265
  # 关键流程:直接调用 memory_manager 确保记忆提示
263
266
  try:
264
267
  self.memory_manager._ensure_memory_prompt(agent=self)
265
268
  except Exception:
266
269
  pass
267
-
270
+
268
271
  # 非关键流程:广播清理历史前事件(用于日志、监控等)
269
272
  try:
270
273
  self.event_bus.emit(BEFORE_HISTORY_CLEAR, agent=self)
@@ -278,6 +281,11 @@ class Agent:
278
281
  # 重置没有工具调用的计数器
279
282
  self._no_tool_call_count = 0
280
283
 
284
+ # 提示用户会话文件位置
285
+ if Path(session_file_path).exists():
286
+ PrettyOutput.auto_print(f"💾 当前会话记录已保存到: {session_file_path}")
287
+ PrettyOutput.auto_print("🤖 大模型可以读取此文件了解完整对话历史")
288
+
281
289
  # 重置后重新设置系统提示词,确保系统约束仍然生效
282
290
  try:
283
291
  self._setup_system_prompt()
@@ -292,16 +300,11 @@ class Agent:
292
300
 
293
301
  def __del__(self):
294
302
  # 只有在记录启动时才停止记录
295
- try:
296
- name = getattr(self, "name", None)
297
- if name:
298
- delete_agent(name)
299
- except Exception:
300
- pass
303
+ pass
301
304
 
302
305
  def get_tool_usage_prompt(self) -> str:
303
306
  """获取工具使用提示"""
304
- return build_action_prompt(self.output_handler) # type: ignore
307
+ return build_action_prompt(self.output_handler)
305
308
 
306
309
  def __new__(cls, *args, **kwargs):
307
310
  if kwargs.get("agent_type") == "code":
@@ -325,7 +328,7 @@ class Agent:
325
328
  description: str = "",
326
329
  model_group: Optional[str] = None,
327
330
  summary_prompt: Optional[str] = None,
328
- auto_complete: bool = False,
331
+ auto_complete: bool = True,
329
332
  output_handler: Optional[List[OutputHandlerProtocol]] = None,
330
333
  use_tools: Optional[List[str]] = None,
331
334
  execute_tool_confirm: Optional[bool] = None,
@@ -336,7 +339,7 @@ class Agent:
336
339
  force_save_memory: Optional[bool] = None,
337
340
  files: Optional[List[str]] = None,
338
341
  confirm_callback: Optional[Callable[[str, bool], bool]] = None,
339
- non_interactive: Optional[bool] = None,
342
+ non_interactive: Optional[bool] = True,
340
343
  in_multi_agent: Optional[bool] = None,
341
344
  agent_type: str = "normal",
342
345
  **kwargs,
@@ -383,17 +386,18 @@ class Agent:
383
386
  self.first = True
384
387
  self.run_input_handlers_next_turn = False
385
388
  self.user_data: Dict[str, Any] = {}
389
+ # 记录固定的内容
390
+ self.pin_content: str = ""
386
391
  # 记录连续未添加 addon_prompt 的轮数
387
- self._addon_prompt_skip_rounds: int = 0
392
+ self._addon_prompt_skip_rounds = 0
388
393
  # 记录连续没有工具调用的次数(用于非交互模式下的工具使用提示)
389
- self._no_tool_call_count: int = 0
390
-
391
- self._agent_type = "normal"
394
+ self._no_tool_call_count = 0
392
395
 
396
+ self._agent_type = "normal"
393
397
 
394
398
  # 用户确认回调:默认使用 CLI 的 user_confirm,可由外部注入以支持 TUI/GUI
395
399
  self.confirm_callback: Callable[[str, bool], bool] = (
396
- confirm_callback or user_confirm # type: ignore[assignment]
400
+ confirm_callback or user_confirm
397
401
  )
398
402
 
399
403
  # 初始化模型和会话
@@ -407,57 +411,78 @@ class Agent:
407
411
  use_tools or [],
408
412
  )
409
413
  # 初始化用户交互封装,保持向后兼容
410
- self.user_interaction = UserInteractionHandler(self.multiline_inputer, self.confirm_callback)
414
+ self.user_interaction = UserInteractionHandler(
415
+ self.multiline_inputer, self.confirm_callback
416
+ )
411
417
  # 将确认函数指向封装后的 confirm,保持既有调用不变
412
- self.confirm_callback = self.user_interaction.confirm # type: ignore[assignment]
418
+ self.confirm_callback = self.user_interaction.confirm
413
419
  # 非交互模式参数支持:允许通过构造参数显式控制,便于其他Agent调用时设置
420
+ # 仅作为 Agent 实例属性,不写入环境变量或全局配置,避免跨 Agent 污染
414
421
  try:
415
- # 优先使用构造参数,其次回退到环境变量
422
+ # 优先使用构造参数,若未提供则默认为 False
416
423
  self.non_interactive = (
417
- bool(non_interactive)
418
- if non_interactive is not None
419
- else str(os.environ.get("JARVIS_NON_INTERACTIVE", "")).lower() in ("1", "true", "yes")
424
+ bool(non_interactive) if non_interactive is not None else False
420
425
  )
421
- # 如果构造参数显式提供,则同步到环境变量与全局配置,供下游组件读取
422
- if non_interactive is not None:
423
- os.environ["JARVIS_NON_INTERACTIVE"] = "true" if self.non_interactive else "false"
424
-
425
426
  except Exception:
426
427
  # 防御式回退
427
428
  self.non_interactive = False
428
429
 
429
430
  # 初始化配置(直接解析,不再依赖 _init_config)
430
431
  try:
431
- resolved_use_methodology = bool(use_methodology if use_methodology is not None else is_use_methodology())
432
+ resolved_use_methodology = bool(
433
+ use_methodology if use_methodology is not None else is_use_methodology()
434
+ )
432
435
  except Exception:
433
- resolved_use_methodology = bool(use_methodology) if use_methodology is not None else True
436
+ resolved_use_methodology = (
437
+ bool(use_methodology) if use_methodology is not None else True
438
+ )
434
439
 
435
440
  try:
436
- resolved_use_analysis = bool(use_analysis if use_analysis is not None else is_use_analysis())
441
+ resolved_use_analysis = bool(
442
+ use_analysis if use_analysis is not None else is_use_analysis()
443
+ )
437
444
  except Exception:
438
- resolved_use_analysis = bool(use_analysis) if use_analysis is not None else True
445
+ resolved_use_analysis = (
446
+ bool(use_analysis) if use_analysis is not None else True
447
+ )
439
448
 
440
449
  try:
441
- resolved_execute_tool_confirm = bool(execute_tool_confirm if execute_tool_confirm is not None else is_execute_tool_confirm())
450
+ resolved_execute_tool_confirm = bool(
451
+ execute_tool_confirm
452
+ if execute_tool_confirm is not None
453
+ else is_execute_tool_confirm()
454
+ )
442
455
  except Exception:
443
- resolved_execute_tool_confirm = bool(execute_tool_confirm) if execute_tool_confirm is not None else False
456
+ resolved_execute_tool_confirm = (
457
+ bool(execute_tool_confirm)
458
+ if execute_tool_confirm is not None
459
+ else False
460
+ )
444
461
 
445
462
  try:
446
- resolved_force_save_memory = bool(force_save_memory if force_save_memory is not None else is_force_save_memory())
463
+ resolved_force_save_memory = bool(
464
+ force_save_memory
465
+ if force_save_memory is not None
466
+ else is_force_save_memory()
467
+ )
447
468
  except Exception:
448
- resolved_force_save_memory = bool(force_save_memory) if force_save_memory is not None else False
469
+ resolved_force_save_memory = (
470
+ bool(force_save_memory) if force_save_memory is not None else False
471
+ )
449
472
 
450
473
  self.use_methodology = resolved_use_methodology
451
474
  self.use_analysis = resolved_use_analysis
452
475
  self.execute_tool_confirm = resolved_execute_tool_confirm
453
- self.summary_prompt = (summary_prompt or DEFAULT_SUMMARY_PROMPT)
476
+ self.summary_prompt = summary_prompt or DEFAULT_SUMMARY_PROMPT
454
477
  self.force_save_memory = resolved_force_save_memory
455
478
  # 多智能体模式下,默认不自动完成(即使是非交互),仅在明确传入 auto_complete=True 时开启
456
479
  if self.in_multi_agent:
457
480
  self.auto_complete = bool(self.auto_complete)
458
481
  else:
459
482
  # 非交互模式下默认自动完成;否则保持传入的 auto_complete 值
460
- self.auto_complete = bool(self.auto_complete or (self.non_interactive or False))
483
+ self.auto_complete = bool(
484
+ self.auto_complete or (self.non_interactive or False)
485
+ )
461
486
 
462
487
  # 初始化事件总线需先于管理器,以便管理器在构造中安全订阅事件
463
488
  self.event_bus = EventBus()
@@ -466,6 +491,9 @@ class Agent:
466
491
  self.task_analyzer = TaskAnalyzer(self)
467
492
  self.file_methodology_manager = FileMethodologyManager(self)
468
493
  self.prompt_manager = PromptManager(self)
494
+ # 初始化任务列表管理器(使用当前工作目录作为 root_dir,如果子类已设置 root_dir 则使用子类的)
495
+ root_dir = getattr(self, "root_dir", None) or os.getcwd()
496
+ self.task_list_manager = TaskListManager(root_dir)
469
497
 
470
498
  # 如果配置了强制保存记忆,确保 save_memory 工具可用
471
499
  if self.force_save_memory:
@@ -482,10 +510,10 @@ class Agent:
482
510
  show_agent_startup_stats(
483
511
  name,
484
512
  self.model.name(),
485
- self.get_tool_registry(), # type: ignore
486
- platform_name=self.model.platform_name(), # type: ignore
513
+ self.get_tool_registry(),
514
+ platform_name=self.model.platform_name(),
487
515
  )
488
-
516
+
489
517
  # 动态加载工具调用后回调
490
518
  self._load_after_tool_callbacks()
491
519
 
@@ -496,7 +524,7 @@ class Agent:
496
524
 
497
525
  maybe_model = PlatformRegistry().create_platform(platform_name)
498
526
  if maybe_model is None:
499
- print(f"⚠️ 平台 {platform_name} 不存在,将使用普通模型")
527
+ PrettyOutput.auto_print(f"⚠️ 平台 {platform_name} 不存在,将使用普通模型")
500
528
  maybe_model = PlatformRegistry().get_normal_platform()
501
529
 
502
530
  # 在此处收敛为非可选类型,确保后续赋值满足类型检查
@@ -508,9 +536,12 @@ class Agent:
508
536
  self.model.set_model_group(model_group)
509
537
  self.model.set_suppress_output(False)
510
538
 
539
+ # 设置全局模型组,供工具和其他组件使用
540
+ set_global_model_group(model_group)
541
+
511
542
  def _init_session(self):
512
543
  """初始化会话管理器"""
513
- self.session = SessionManager(model=self.model, agent_name=self.name) # type: ignore
544
+ self.session = SessionManager(model=self.model, agent_name=self.name)
514
545
 
515
546
  def _init_handlers(
516
547
  self,
@@ -534,15 +565,20 @@ class Agent:
534
565
  """设置系统提示词"""
535
566
  try:
536
567
  prompt_text = self.prompt_manager.build_system_prompt()
537
- self.model.set_system_prompt(prompt_text) # type: ignore
568
+ self.model.set_system_prompt(prompt_text)
538
569
  except Exception:
539
570
  # 回退到原始行为,确保兼容性
540
571
  action_prompt = self.get_tool_usage_prompt()
541
- self.model.set_system_prompt( # type: ignore
572
+ rules_prompt = self.rules_manager.load_all_rules(
573
+ ",".join(self.loaded_rule_names)
574
+ )
575
+ self.model.set_system_prompt(
542
576
  f"""
543
577
  {self.system_prompt}
544
578
 
545
579
  {action_prompt}
580
+
581
+ {rules_prompt}
546
582
  """
547
583
  )
548
584
 
@@ -556,7 +592,7 @@ class Agent:
556
592
 
557
593
  def get_remaining_token_count(self) -> int:
558
594
  """获取剩余可用的token数量
559
-
595
+
560
596
  返回:
561
597
  int: 剩余可用的token数量,如果无法获取则返回0
562
598
  """
@@ -596,14 +632,16 @@ class Agent:
596
632
  pass
597
633
  try:
598
634
  # Try to pass the keyword for enhanced input handler
599
- return self.multiline_inputer(tip, print_on_empty=print_on_empty) # type: ignore
635
+ return self.multiline_inputer(
636
+ tip,
637
+ )
600
638
  except TypeError:
601
639
  # Fallback for custom handlers that only accept one argument
602
- return self.multiline_inputer(tip) # type: ignore
640
+ return self.multiline_inputer(tip)
603
641
 
604
642
  def _load_after_tool_callbacks(self) -> None:
605
643
  """
606
- 扫描 JARVIS_AFTER_TOOL_CALL_CB_DIRS 中的 Python 文件并动态注册回调。
644
+ 扫描 after_tool_call_cb_dirs 中的 Python 文件并动态注册回调。
607
645
  约定优先级(任一命中即注册):
608
646
  - 模块级可调用对象: after_tool_call_cb
609
647
  - 工厂方法返回单个或多个可调用对象: get_after_tool_call_cb(), register_after_tool_call_cb()
@@ -634,7 +672,7 @@ class Agent:
634
672
  if hasattr(module, "after_tool_call_cb"):
635
673
  obj = getattr(module, "after_tool_call_cb")
636
674
  if callable(obj):
637
- candidates.append(obj) # type: ignore[arg-type]
675
+ candidates.append(obj)
638
676
 
639
677
  # 2) 工厂方法:get_after_tool_call_cb()
640
678
  if hasattr(module, "get_after_tool_call_cb"):
@@ -668,6 +706,7 @@ class Agent:
668
706
 
669
707
  for cb in candidates:
670
708
  try:
709
+
671
710
  def _make_wrapper(callback):
672
711
  def _wrapper(**kwargs: Any) -> None:
673
712
  try:
@@ -675,13 +714,17 @@ class Agent:
675
714
  callback(agent)
676
715
  except Exception:
677
716
  pass
717
+
678
718
  return _wrapper
679
- self.event_bus.subscribe(AFTER_TOOL_CALL, _make_wrapper(cb))
719
+
720
+ self.event_bus.subscribe(
721
+ AFTER_TOOL_CALL, _make_wrapper(cb)
722
+ )
680
723
  except Exception:
681
724
  pass
682
725
 
683
726
  except Exception as e:
684
- print(f"⚠️ 从 {file_path} 加载回调失败: {e}")
727
+ PrettyOutput.auto_print(f"⚠️ 从 {file_path} 加载回调失败: {e}")
685
728
  finally:
686
729
  if added_path:
687
730
  try:
@@ -689,7 +732,7 @@ class Agent:
689
732
  except ValueError:
690
733
  pass
691
734
  except Exception as e:
692
- print(f"⚠️ 加载回调目录时发生错误: {e}")
735
+ PrettyOutput.auto_print(f"⚠️ 加载回调目录时发生错误: {e}")
693
736
 
694
737
  def save_session(self) -> bool:
695
738
  """Saves the current session state by delegating to the session manager."""
@@ -813,7 +856,7 @@ class Agent:
813
856
 
814
857
  def _add_addon_prompt(self, message: str, need_complete: bool) -> str:
815
858
  """添加附加提示到消息
816
-
859
+
817
860
  规则:
818
861
  1. 如果 session.addon_prompt 存在,优先使用它
819
862
  2. 如果消息长度超过阈值,添加默认 addon_prompt
@@ -833,7 +876,7 @@ class Agent:
833
876
 
834
877
  addon_text = ""
835
878
  should_add = False
836
-
879
+
837
880
  if self.session.addon_prompt:
838
881
  # 优先使用 session 中设置的 addon_prompt
839
882
  addon_text = self.session.addon_prompt
@@ -852,7 +895,7 @@ class Agent:
852
895
  addon_text = self.make_default_addon_prompt(need_complete)
853
896
  message = join_prompts([message, addon_text])
854
897
  should_add = True
855
-
898
+
856
899
  # 更新计数器:如果添加了 addon_prompt,重置计数器;否则递增
857
900
  if should_add:
858
901
  self._addon_prompt_skip_rounds = 0
@@ -876,7 +919,6 @@ class Agent:
876
919
  """管理对话长度计数;摘要触发由剩余token数量在 AgentRunLoop 中统一处理(剩余token低于20%时触发)。"""
877
920
  self.session.conversation_length += get_context_token_count(message)
878
921
 
879
-
880
922
  return message
881
923
 
882
924
  def _invoke_model(self, message: str) -> str:
@@ -894,15 +936,15 @@ class Agent:
894
936
  except Exception:
895
937
  pass
896
938
 
897
- response = self.model.chat_until_success(message) # type: ignore
939
+ response = self.model.chat_until_success(message)
898
940
  # 防御: 模型可能返回空响应(None或空字符串),统一为空字符串并告警
899
941
  if not response:
900
942
  try:
901
- print("⚠️ 模型返回空响应,已使用空字符串回退。")
943
+ PrettyOutput.auto_print("⚠️ 模型返回空响应,已使用空字符串回退。")
902
944
  except Exception:
903
945
  pass
904
946
  response = ""
905
-
947
+
906
948
  # 事件:模型调用后
907
949
  try:
908
950
  self.event_bus.emit(
@@ -935,31 +977,36 @@ class Agent:
935
977
  try:
936
978
  if not self.model:
937
979
  raise RuntimeError("Model not initialized")
938
-
939
- print("🔍 开始生成对话历史摘要...")
940
-
980
+
981
+ PrettyOutput.auto_print("🔍 开始生成对话历史摘要...")
982
+
941
983
  if for_token_limit:
942
984
  # token限制触发的summary:使用SUMMARY_REQUEST_PROMPT进行上下文压缩
943
985
  prompt_to_use = self.session.prompt + "\n" + SUMMARY_REQUEST_PROMPT
944
986
  else:
945
987
  # 任务完成时的summary:使用用户传入的summary_prompt或DEFAULT_SUMMARY_PROMPT
946
988
  safe_summary_prompt = self.summary_prompt or ""
947
- if isinstance(safe_summary_prompt, str) and safe_summary_prompt.strip() != "":
989
+ if (
990
+ isinstance(safe_summary_prompt, str)
991
+ and safe_summary_prompt.strip() != ""
992
+ ):
948
993
  prompt_to_use = safe_summary_prompt
949
994
  else:
950
995
  prompt_to_use = DEFAULT_SUMMARY_PROMPT
951
996
 
952
- summary = self.model.chat_until_success(prompt_to_use) # type: ignore
997
+ summary = self.model.chat_until_success(prompt_to_use)
953
998
  # 防御: 可能返回空响应(None或空字符串),统一为空字符串并告警
954
999
  if not summary:
955
1000
  try:
956
- print("⚠️ 总结模型返回空响应,已使用空字符串回退。")
1001
+ PrettyOutput.auto_print(
1002
+ "⚠️ 总结模型返回空响应,已使用空字符串回退。"
1003
+ )
957
1004
  except Exception:
958
1005
  pass
959
1006
  summary = ""
960
1007
  return summary
961
1008
  except Exception:
962
- print("❌ 总结对话历史失败")
1009
+ PrettyOutput.auto_print("❌ 总结对话历史失败")
963
1010
  return ""
964
1011
 
965
1012
  def _summarize_and_clear_history(self) -> str:
@@ -994,18 +1041,62 @@ class Agent:
994
1041
  # token限制触发的summary,使用SUMMARY_REQUEST_PROMPT
995
1042
  summary = self.generate_summary(for_token_limit=True)
996
1043
 
1044
+ # 获取git diff信息
1045
+ git_diff_info = ""
1046
+ try:
1047
+ # 尝试从 AgentRunLoop 获取已缓存的 git diff
1048
+ from jarvis.jarvis_agent.run_loop import AgentRunLoop
1049
+
1050
+ if hasattr(self, "_agent_run_loop") and isinstance(
1051
+ self._agent_run_loop, AgentRunLoop
1052
+ ):
1053
+ agent_run_loop = self._agent_run_loop
1054
+ else:
1055
+ # 创建临时 AgentRunLoop 实例来获取 git diff
1056
+ agent_run_loop = AgentRunLoop(self)
1057
+
1058
+ if agent_run_loop.has_git_diff():
1059
+ cached_diff = agent_run_loop.get_cached_git_diff()
1060
+ git_diff_info = cached_diff or ""
1061
+ else:
1062
+ # 如果还没有缓存,直接获取
1063
+ git_diff_info = agent_run_loop.get_git_diff()
1064
+ except Exception as e:
1065
+ git_diff_info = f"获取git diff失败: {str(e)}"
1066
+
997
1067
  # 先获取格式化的摘要消息
998
1068
  formatted_summary = ""
999
1069
  if summary:
1000
1070
  formatted_summary = self._format_summary_message(summary)
1001
1071
 
1072
+ # 添加git diff信息到摘要中 - 只显示有效的代码变更
1073
+ is_valid_git_diff = (
1074
+ git_diff_info
1075
+ and git_diff_info.strip()
1076
+ and
1077
+ # 过滤错误信息(获取失败等)
1078
+ not git_diff_info.startswith("获取git diff失败")
1079
+ and not git_diff_info.startswith("Failed to get git diff")
1080
+ and
1081
+ # 过滤无变更提示
1082
+ "没有检测到代码变更" not in git_diff_info
1083
+ and "No code changes detected" not in git_diff_info
1084
+ and
1085
+ # 确保包含实际代码变更(diff格式)
1086
+ "diff --git" in git_diff_info
1087
+ )
1088
+
1089
+ if is_valid_git_diff:
1090
+ diff_section = f"\n\n## 代码变更摘要\n```\n{git_diff_info}\n```"
1091
+ formatted_summary += diff_section
1092
+
1002
1093
  # 关键流程:直接调用 memory_manager 确保记忆提示
1003
1094
  try:
1004
1095
  self.memory_manager._ensure_memory_prompt(agent=self)
1005
1096
  except Exception:
1006
1097
  pass
1007
-
1008
- # 非关键流程:广播清理历史前事件(用于日志、监控等)
1098
+
1099
+ # 非关键流程:广播清理历史前事件(用于日志、监控等)
1009
1100
  try:
1010
1101
  self.event_bus.emit(BEFORE_HISTORY_CLEAR, agent=self)
1011
1102
  except Exception:
@@ -1022,13 +1113,54 @@ class Agent:
1022
1113
  self._addon_prompt_skip_rounds = 0
1023
1114
  # 重置没有工具调用的计数器
1024
1115
  self._no_tool_call_count = 0
1025
-
1116
+
1117
+ # 获取任务列表信息(用于历史记录)
1118
+ task_list_info = ""
1119
+ try:
1120
+ # 获取所有任务列表的摘要信息
1121
+ task_lists_summary: List[Dict[str, Any]] = []
1122
+ for task_list_id, task_list in self.task_list_manager.task_lists.items():
1123
+ summary_dict = self.task_list_manager.get_task_list_summary(
1124
+ task_list_id
1125
+ )
1126
+ if summary_dict and isinstance(summary_dict, dict):
1127
+ task_lists_summary.append(summary_dict)
1128
+
1129
+ if task_lists_summary:
1130
+ task_list_info = "\\n\\n## 任务列表状态\\n"
1131
+ for summary_dict in task_lists_summary:
1132
+ task_list_info += (
1133
+ f"\\n- 目标: {summary_dict.get('main_goal', '未知')}"
1134
+ )
1135
+ task_list_info += (
1136
+ f"\\n- 总任务数: {summary_dict.get('total_tasks', 0)}"
1137
+ )
1138
+ task_list_info += f"\\n- 待执行: {summary_dict.get('pending', 0)}"
1139
+ task_list_info += f"\\n- 执行中: {summary_dict.get('running', 0)}"
1140
+ task_list_info += f"\\n- 已完成: {summary_dict.get('completed', 0)}"
1141
+ task_list_info += f"\\n- 失败: {summary_dict.get('failed', 0)}"
1142
+ task_list_info += (
1143
+ f"\\n- 已放弃: {summary_dict.get('abandoned', 0)}\\n"
1144
+ )
1145
+ except Exception:
1146
+ # 非关键流程,失败时不影响主要功能
1147
+ pass
1148
+
1026
1149
  # 非关键流程:广播清理历史后的事件(用于日志、监控等)
1027
1150
  try:
1028
1151
  self.event_bus.emit(AFTER_HISTORY_CLEAR, agent=self)
1029
1152
  except Exception:
1030
1153
  pass
1031
1154
 
1155
+ # 将任务列表信息添加到摘要中
1156
+ if task_list_info:
1157
+ formatted_summary += task_list_info
1158
+
1159
+ # 添加用户固定的重要内容
1160
+ if self.pin_content.strip():
1161
+ pin_section = f"\n\n## 用户的原始需求和要求\n{self.pin_content.strip()}"
1162
+ formatted_summary += pin_section
1163
+
1032
1164
  return formatted_summary
1033
1165
 
1034
1166
  def _handle_history_with_file_upload(self) -> str:
@@ -1038,19 +1170,43 @@ class Agent:
1038
1170
  self.memory_manager._ensure_memory_prompt(agent=self)
1039
1171
  except Exception:
1040
1172
  pass
1041
-
1173
+
1042
1174
  # 非关键流程:广播清理历史前事件(用于日志、监控等)
1043
1175
  try:
1044
1176
  self.event_bus.emit(BEFORE_HISTORY_CLEAR, agent=self)
1045
1177
  except Exception:
1046
1178
  pass
1047
-
1179
+
1048
1180
  result = self.file_methodology_manager.handle_history_with_file_upload()
1049
1181
  # 重置 addon_prompt 跳过轮数计数器
1050
1182
  self._addon_prompt_skip_rounds = 0
1051
1183
  # 重置没有工具调用的计数器
1052
1184
  self._no_tool_call_count = 0
1053
-
1185
+
1186
+ # 添加系统约束提醒
1187
+ if result:
1188
+ constraint_reminder = """
1189
+
1190
+ **⚠️ 重要系统约束提醒(总结后必须严格遵守):**
1191
+ 1. **每次只能执行一个工具调用**:每个响应必须包含且仅包含一个工具调用(任务完成时除外)。同时调用多个工具会导致错误。
1192
+ 2. **禁止虚构结果**:所有操作必须基于实际执行结果,禁止推测、假设或虚构任何执行结果。必须等待工具执行完成并获得实际结果后再进行下一步。
1193
+ 3. **等待工具结果**:在继续下一步之前,必须等待当前工具的执行结果,不能假设工具执行的结果。
1194
+ 4. **基于实际验证**:所有结论必须基于实际执行结果和验证证据,禁止基于推测或假设。
1195
+ 5. **代码任务完成标准(严格执行)**:
1196
+ - **编译/构建必须通过**:代码必须能够成功编译/构建,无编译错误、无语法错误、无链接错误
1197
+ - **功能必须验证**:功能必须经过实际运行验证,不能仅凭代码存在就认为完成
1198
+ - **错误必须修复**:如果存在编译错误、运行时错误、测试失败,任务必须标记为"部分完成"或"进行中",不能标记为"已完成"
1199
+ - **不能因为"代码已编写"就认为任务完成**:必须验证编译通过、功能正常运行、测试通过
1200
+ """
1201
+ result += constraint_reminder
1202
+
1203
+ # 添加用户固定的重要内容
1204
+ if self.pin_content.strip():
1205
+ pin_section = (
1206
+ f"\n\n## 用户强调的任务目标和关键信息\n{self.pin_content.strip()}"
1207
+ )
1208
+ result += pin_section
1209
+
1054
1210
  # 非关键流程:广播清理历史后的事件(用于日志、监控等)
1055
1211
  try:
1056
1212
  self.event_bus.emit(AFTER_HISTORY_CLEAR, agent=self)
@@ -1060,15 +1216,107 @@ class Agent:
1060
1216
 
1061
1217
  def _format_summary_message(self, summary: str) -> str:
1062
1218
  """格式化摘要消息"""
1063
- return f"""
1219
+ # 获取任务列表信息
1220
+ task_list_info = self._get_task_list_info()
1221
+
1222
+ # 获取会话文件路径信息
1223
+ session_file_info = ""
1224
+ try:
1225
+ from jarvis.jarvis_utils.dialogue_recorder import get_global_recorder
1226
+ from pathlib import Path
1227
+
1228
+ recorder = get_global_recorder()
1229
+ session_file_path = recorder.get_session_file_path()
1230
+ if Path(session_file_path).exists():
1231
+ session_file_info = f"\n\n**📁 完整对话历史文件**:\n完整的对话历史已自动保存到以下文件,如果需要查看详细的历史信息,可以读取此文件:\n`{session_file_path}`\n\n此文件包含之前所有对话的完整记录(JSONL格式),每行一个消息记录,包括时间戳、角色和内容。"
1232
+ except Exception:
1233
+ # 非关键流程,失败时不影响主要功能
1234
+ pass
1235
+
1236
+ # 获取初始 commit 信息(仅对 CodeAgent)
1237
+ initial_commit_info = ""
1238
+ try:
1239
+ if hasattr(self, "start_commit") and self.start_commit:
1240
+ initial_commit_info = f"\n\n**🔖 初始 Git Commit(安全回退点)**:\n本次任务开始时的初始 commit 是:`{self.start_commit}`\n\n**⚠️ 重要提示**:如果文件被破坏得很严重无法恢复,可以使用以下命令重置到这个初始 commit:\n```bash\ngit reset --hard {self.start_commit}\n```\n这将丢弃所有未提交的更改,将工作区恢复到任务开始时的状态。请谨慎使用此命令,确保这是你真正想要的操作。"
1241
+ except Exception:
1242
+ # 非关键流程,失败时不影响主要功能
1243
+ pass
1244
+
1245
+ formatted_message = f"""
1064
1246
  以下是之前对话的关键信息总结:
1065
1247
 
1066
1248
  <content>
1067
1249
  {summary}
1068
1250
  </content>
1069
1251
 
1070
- 请基于以上信息继续完成任务。请注意,这是之前对话的摘要,上下文长度已超过限制而被重置。请直接继续任务,无需重复已完成的步骤。如有需要,可以询问用户以获取更多信息。
1252
+ **⚠️ 重要系统约束提醒(总结后必须严格遵守):**
1253
+ 1. **每次只能执行一个工具调用**:每个响应必须包含且仅包含一个工具调用(任务完成时除外)。同时调用多个工具会导致错误。
1254
+ 2. **禁止虚构结果**:所有操作必须基于实际执行结果,禁止推测、假设或虚构任何执行结果。必须等待工具执行完成并获得实际结果后再进行下一步。
1255
+ 3. **等待工具结果**:在继续下一步之前,必须等待当前工具的执行结果,不能假设工具执行的结果。
1256
+ 4. **基于实际验证**:所有结论必须基于实际执行结果和验证证据,禁止基于推测或假设。
1257
+ 5. **代码任务完成标准(严格执行)**:
1258
+ - **编译/构建必须通过**:代码必须能够成功编译/构建,无编译错误、无语法错误、无链接错误
1259
+ - **功能必须验证**:功能必须经过实际运行验证,不能仅凭代码存在就认为完成
1260
+ - **错误必须修复**:如果存在编译错误、运行时错误、测试失败,任务必须标记为"部分完成"或"进行中",不能标记为"已完成"
1261
+ - **不能因为"代码已编写"就认为任务完成**:必须验证编译通过、功能正常运行、测试通过
1262
+
1263
+ 请基于以上信息继续完成任务。请注意,这是之前对话的摘要,上下文长度已超过限制而被重置。请直接继续任务,无需重复已完成的步骤。如有需要,可以询问用户以获取更多信息。{session_file_info}{initial_commit_info}
1264
+ """
1265
+
1266
+ # 如果有任务列表信息,添加到消息后面
1267
+ if task_list_info:
1268
+ formatted_message += f"\n\n{task_list_info}"
1269
+
1270
+ return formatted_message
1271
+
1272
+ def _get_task_list_info(self) -> str:
1273
+ """获取并格式化当前任务列表信息
1274
+
1275
+ 返回:
1276
+ str: 格式化的任务列表信息,如果没有任务列表则返回空字符串
1071
1277
  """
1278
+ try:
1279
+ # 使用当前Agent的任务列表管理器获取所有任务列表信息
1280
+ if (
1281
+ not hasattr(self, "task_list_manager")
1282
+ or not self.task_list_manager.task_lists
1283
+ ):
1284
+ return ""
1285
+
1286
+ all_task_lists_info = []
1287
+
1288
+ # 遍历所有任务列表
1289
+ for task_list_id, task_list in self.task_list_manager.task_lists.items():
1290
+ summary = self.task_list_manager.get_task_list_summary(task_list_id)
1291
+ if not summary:
1292
+ continue
1293
+
1294
+ # 构建任务列表摘要信息
1295
+ info_parts = []
1296
+ info_parts.append(f"📋 任务列表: {summary['main_goal']}")
1297
+ info_parts.append(
1298
+ f" 总任务: {summary['total_tasks']} | 待执行: {summary['pending']} | 执行中: {summary['running']} | 已完成: {summary['completed']}"
1299
+ )
1300
+
1301
+ # 如果有失败或放弃的任务,也显示
1302
+ if summary["failed"] > 0 or summary["abandoned"] > 0:
1303
+ status_parts = []
1304
+ if summary["failed"] > 0:
1305
+ status_parts.append(f"失败: {summary['failed']}")
1306
+ if summary["abandoned"] > 0:
1307
+ status_parts.append(f"放弃: {summary['abandoned']}")
1308
+ info_parts[-1] += f" | {' | '.join(status_parts)}"
1309
+
1310
+ all_task_lists_info.append("\n".join(info_parts))
1311
+
1312
+ if not all_task_lists_info:
1313
+ return ""
1314
+
1315
+ return "\n\n".join(all_task_lists_info)
1316
+
1317
+ except Exception:
1318
+ # 静默失败,不干扰主流程
1319
+ return ""
1072
1320
 
1073
1321
  def _call_tools(self, response: str) -> Tuple[bool, Any]:
1074
1322
  """
@@ -1098,13 +1346,15 @@ class Agent:
1098
1346
  result = "任务完成"
1099
1347
 
1100
1348
  if self.need_summary:
1101
-
1102
1349
  # 确保总结提示词非空:若为None或仅空白,则回退到默认提示词
1103
1350
  safe_summary_prompt = self.summary_prompt or ""
1104
- if isinstance(safe_summary_prompt, str) and safe_summary_prompt.strip() == "":
1351
+ if (
1352
+ isinstance(safe_summary_prompt, str)
1353
+ and safe_summary_prompt.strip() == ""
1354
+ ):
1105
1355
  safe_summary_prompt = DEFAULT_SUMMARY_PROMPT
1106
1356
  # 注意:不要写回 session.prompt,避免回调修改/清空后导致使用空prompt
1107
-
1357
+
1108
1358
  # 关键流程:直接调用 task_analyzer 执行任务分析
1109
1359
  try:
1110
1360
  self.task_analyzer._on_before_summary(
@@ -1115,7 +1365,7 @@ class Agent:
1115
1365
  )
1116
1366
  except Exception:
1117
1367
  pass
1118
-
1368
+
1119
1369
  # 非关键流程:广播将要生成总结事件(用于日志、监控等)
1120
1370
  try:
1121
1371
  self.event_bus.emit(
@@ -1131,16 +1381,39 @@ class Agent:
1131
1381
  if not self.model:
1132
1382
  raise RuntimeError("Model not initialized")
1133
1383
  # 直接使用本地变量,避免受事件回调影响
1134
- ret = self.model.chat_until_success(safe_summary_prompt) # type: ignore
1384
+ ret = self.model.chat_until_success(safe_summary_prompt)
1135
1385
  # 防御: 总结阶段模型可能返回空响应(None或空字符串),统一为空字符串并告警
1136
1386
  if not ret:
1137
1387
  try:
1138
- print("⚠️ 总结阶段模型返回空响应,已使用空字符串回退。")
1388
+ PrettyOutput.auto_print(
1389
+ "⚠️ 总结阶段模型返回空响应,已使用空字符串回退。"
1390
+ )
1139
1391
  except Exception:
1140
1392
  pass
1141
1393
  ret = ""
1142
1394
  result = ret
1143
1395
 
1396
+ # 打印任务总结内容给用户查看
1397
+ if ret and ret.strip():
1398
+ try:
1399
+ import jarvis.jarvis_utils.globals as G
1400
+ from jarvis.jarvis_utils.globals import console
1401
+ from rich.panel import Panel
1402
+ from rich import box
1403
+
1404
+ agent_name = self.name if hasattr(self, "name") else None
1405
+ panel = Panel(
1406
+ ret,
1407
+ title=f"[bold cyan]{(G.get_current_agent_name() + ' · ') if G.get_current_agent_name() else ''}{agent_name or 'LLM'} 任务总结[/bold cyan]",
1408
+ border_style="bright_green",
1409
+ box=box.ROUNDED,
1410
+ expand=True,
1411
+ )
1412
+ console.print(panel)
1413
+ except Exception:
1414
+ # 如果格式化输出失败,回退到简单打印
1415
+ PrettyOutput.auto_print(f"📋 任务总结:\n{ret}")
1416
+
1144
1417
  # 非关键流程:广播完成总结事件(用于日志、监控等)
1145
1418
  try:
1146
1419
  self.event_bus.emit(
@@ -1160,7 +1433,7 @@ class Agent:
1160
1433
  )
1161
1434
  except Exception:
1162
1435
  pass
1163
-
1436
+
1164
1437
  try:
1165
1438
  self.memory_manager._ensure_memory_prompt(
1166
1439
  agent=self,
@@ -1169,7 +1442,7 @@ class Agent:
1169
1442
  )
1170
1443
  except Exception:
1171
1444
  pass
1172
-
1445
+
1173
1446
  # 非关键流程:广播任务完成事件(用于日志、监控等)
1174
1447
  try:
1175
1448
  self.event_bus.emit(
@@ -1201,7 +1474,7 @@ class Agent:
1201
1474
 
1202
1475
  # 任务完成提示
1203
1476
  complete_prompt = (
1204
- f"- 输出{ot('!!!COMPLETE!!!')}"
1477
+ f"- 如果任务已完成,只输出 {ot('!!!COMPLETE!!!')},不要输出其他任何内容。任务总结将会在后面的交互中被询问。"
1205
1478
  if need_complete and self.auto_complete
1206
1479
  else ""
1207
1480
  )
@@ -1215,15 +1488,15 @@ class Agent:
1215
1488
  addon_prompt = f"""
1216
1489
  <system_prompt>
1217
1490
  请判断是否已经完成任务,如果已经完成:
1218
- - 直接输出完成原因,不需要再有新的操作,不要输出{ot("TOOL_CALL")}标签
1219
- {complete_prompt}
1491
+ {complete_prompt if complete_prompt else f"- 直接输出完成原因,不需要再有新的操作,不要输出{ot('TOOL_CALL')}标签"}
1220
1492
  如果没有完成,请进行下一步操作:
1221
1493
  - 仅包含一个操作
1222
1494
  - 如果信息不明确,请请求用户补充
1223
1495
  - 如果执行过程中连续失败5次,请请求用户操作
1496
+ - 工具调用必须使用{ot("TOOL_CALL")}和{ct("TOOL_CALL")}标签
1224
1497
  - 操作列表:{action_handlers}{memory_prompts}
1225
1498
 
1226
- 注意:如果当前部分任务已完成,之前的上下文价值不大,可以输出<!!!SUMMARY!!!>标记来触发总结并清空历史,以便开始新的任务阶段。
1499
+ 注意:如果当前部分任务已完成,之前的上下文价值不大,可以输出{ot("!!!SUMMARY!!!")}标记来触发总结并清空历史,以便开始新的任务阶段。
1227
1500
  </system_prompt>
1228
1501
 
1229
1502
  请继续。
@@ -1246,10 +1519,31 @@ class Agent:
1246
1519
  3. 包含错误处理和恢复逻辑
1247
1520
  4. 自动加载相关方法论(如果是首次运行)
1248
1521
  """
1249
- self.session.prompt = f"{user_input}"
1522
+ # 根据当前模式生成额外说明,供 LLM 感知执行策略
1250
1523
  try:
1251
- set_agent(self.name, self)
1252
-
1524
+ # 延迟导入CodeAgent以避免循环依赖
1525
+ from jarvis.jarvis_code_agent.code_agent import CodeAgent
1526
+
1527
+ # 如果是CodeAgent实例,则跳过注册,由CodeAgent.run自行管理
1528
+ if not isinstance(self, CodeAgent):
1529
+ set_current_agent(self.name, self) # 标记agent开始运行
1530
+ non_interactive_note = ""
1531
+ if getattr(self, "non_interactive", False):
1532
+ non_interactive_note = (
1533
+ "\n\n[系统说明]\n"
1534
+ "本次会话处于**非交互模式**:\n"
1535
+ "- 在 PLAN 模式中给出清晰、可执行的详细计划后,应**自动进入 EXECUTE 模式执行计划**,不要等待用户额外确认;\n"
1536
+ "- 在 EXECUTE 模式中,保持一步一步的小步提交和可回退策略,但不需要向用户反复询问“是否继续”;\n"
1537
+ "- 如遇信息严重不足,可以在 RESEARCH 模式中自行补充必要分析,而不是卡在等待用户输入。\n"
1538
+ )
1539
+
1540
+ # 如果是非交互模式,可以假设用户输入的是完整的需求
1541
+ self.pin_content = user_input
1542
+
1543
+ # 将非交互模式说明添加到用户输入中
1544
+ enhanced_input = user_input + non_interactive_note
1545
+ self.session.prompt = enhanced_input
1546
+
1253
1547
  # 关键流程:直接调用 memory_manager 重置任务状态
1254
1548
  try:
1255
1549
  self.memory_manager._on_task_started(
@@ -1260,7 +1554,7 @@ class Agent:
1260
1554
  )
1261
1555
  except Exception:
1262
1556
  pass
1263
-
1557
+
1264
1558
  # 非关键流程:广播任务开始事件(用于日志、监控等)
1265
1559
  try:
1266
1560
  self.event_bus.emit(
@@ -1272,18 +1566,48 @@ class Agent:
1272
1566
  )
1273
1567
  except Exception:
1274
1568
  pass
1569
+
1275
1570
  return self._main_loop()
1276
- except Exception as e:
1277
- print(f"❌ 任务失败: {str(e)}")
1278
- return f"Task failed: {str(e)}"
1571
+
1572
+ finally:
1573
+ if not isinstance(self, CodeAgent):
1574
+ clear_current_agent()
1279
1575
 
1280
1576
  def _main_loop(self) -> Any:
1281
1577
  """主运行循环"""
1282
1578
  # 委派至独立的运行循环类,保持行为一致
1283
1579
  loop = AgentRunLoop(self)
1580
+ self._agent_run_loop = loop # 存储引用以便其他方法访问
1284
1581
  return loop.run()
1285
1582
 
1286
- def _handle_run_interrupt(self, current_response: str) -> Optional[Union[Any, "LoopAction"]]:
1583
+ def set_non_interactive(self, value: bool) -> None:
1584
+ """设置非交互模式并管理自动完成状态。
1585
+
1586
+ 当进入非交互模式时,自动启用自动完成;
1587
+ 当退出非交互模式时,恢复自动完成的原始值。
1588
+
1589
+ 参数:
1590
+ value: 是否启用非交互模式
1591
+ """
1592
+ # 保存auto_complete的原始值(如果是首次设置)
1593
+ if not hasattr(self, "_auto_complete_backup"):
1594
+ self._auto_complete_backup = self.auto_complete
1595
+
1596
+ # 设置非交互模式(仅作为 Agent 实例属性,不写入环境变量或全局配置)
1597
+ self.non_interactive = value
1598
+
1599
+ # 根据non_interactive的值调整auto_complete
1600
+ if value: # 进入非交互模式
1601
+ self.auto_complete = True
1602
+ else: # 退出非交互模式
1603
+ # 恢复auto_complete的原始值
1604
+ self.auto_complete = self._auto_complete_backup
1605
+ # 清理备份,避免状态污染
1606
+ delattr(self, "_auto_complete_backup")
1607
+
1608
+ def _handle_run_interrupt(
1609
+ self, current_response: str
1610
+ ) -> Optional[Union[Any, "LoopAction"]]:
1287
1611
  """处理运行中的中断
1288
1612
 
1289
1613
  返回:
@@ -1295,6 +1619,11 @@ class Agent:
1295
1619
  return None
1296
1620
 
1297
1621
  set_interrupt(False)
1622
+
1623
+ # 被中断时,如果当前是非交互模式,立即切换到交互模式(在获取用户输入前)
1624
+ if self.non_interactive:
1625
+ self.set_non_interactive(False)
1626
+
1298
1627
  user_input = self._multiline_input(
1299
1628
  "模型交互期间被中断,请输入用户干预信息:", False
1300
1629
  )
@@ -1316,17 +1645,21 @@ class Agent:
1316
1645
  return self._complete_task(auto_completed=False)
1317
1646
 
1318
1647
  if any(handler.can_handle(current_response) for handler in self.output_handler):
1319
- if self.confirm_callback("检测到有工具调用,是否继续处理工具调用?", True):
1320
- self.session.prompt = join_prompts([
1321
- f"被用户中断,用户补充信息为:{user_input}",
1322
- "用户同意继续工具调用。"
1323
- ])
1648
+ if self.confirm_callback("检测到有工具调用,是否继续处理工具调用?", False):
1649
+ self.session.prompt = join_prompts(
1650
+ [
1651
+ f"被用户中断,用户补充信息为:{user_input}",
1652
+ "用户同意继续工具调用。",
1653
+ ]
1654
+ )
1324
1655
  return None # 继续执行工具调用
1325
1656
  else:
1326
- self.session.prompt = join_prompts([
1327
- f"被用户中断,用户补充信息为:{user_input}",
1328
- "检测到有工具调用,但被用户拒绝执行。请根据用户的补充信息重新考虑下一步操作。"
1329
- ])
1657
+ self.session.prompt = join_prompts(
1658
+ [
1659
+ f"被用户中断,用户补充信息为:{user_input}",
1660
+ "检测到有工具调用,但被用户拒绝执行。请根据用户的补充信息重新考虑下一步操作。",
1661
+ ]
1662
+ )
1330
1663
  return LoopAction.SKIP_TURN # 请求主循环 continue
1331
1664
  else:
1332
1665
  self.session.prompt = f"被用户中断,用户补充信息为:{user_input}"
@@ -1345,9 +1678,9 @@ class Agent:
1345
1678
  if user_input:
1346
1679
  self.session.prompt = user_input
1347
1680
  # 使用显式动作信号,保留返回类型注释以保持兼容
1348
- return LoopAction.CONTINUE # type: ignore[return-value]
1681
+ return LoopAction.CONTINUE
1349
1682
  else:
1350
- return LoopAction.COMPLETE # type: ignore[return-value]
1683
+ return LoopAction.COMPLETE
1351
1684
 
1352
1685
  def _first_run(self):
1353
1686
  """首次运行初始化"""
@@ -1368,14 +1701,22 @@ class Agent:
1368
1701
  self.first = False
1369
1702
 
1370
1703
  def _create_temp_model(self, system_prompt: str) -> BasePlatform:
1371
- """创建一个用于执行一次性任务的临时模型实例,以避免污染主会话。"""
1372
- temp_model = PlatformRegistry().create_platform(
1373
- self.model.platform_name() # type: ignore
1374
- )
1704
+ """创建一个用于执行一次性任务的临时模型实例,以避免污染主会话。
1705
+
1706
+ 筛选操作使用cheap模型以降低成本。
1707
+ """
1708
+ from jarvis.jarvis_utils.config import get_cheap_model_name
1709
+ from jarvis.jarvis_utils.config import get_cheap_platform_name
1710
+
1711
+ # 筛选操作使用cheap模型
1712
+ platform_name = get_cheap_platform_name(None)
1713
+ model_name = get_cheap_model_name(None)
1714
+
1715
+ temp_model = PlatformRegistry().create_platform(platform_name)
1375
1716
  if not temp_model:
1376
1717
  raise RuntimeError("创建临时模型失败。")
1377
1718
 
1378
- temp_model.set_model_name(self.model.name()) # type: ignore
1719
+ temp_model.set_model_name(model_name)
1379
1720
  temp_model.set_system_prompt(system_prompt)
1380
1721
  return temp_model
1381
1722
 
@@ -1412,7 +1753,7 @@ class Agent:
1412
1753
 
1413
1754
  def _filter_tools_if_needed(self, task: str):
1414
1755
  """如果工具数量超过阈值,使用大模型筛选相关工具
1415
-
1756
+
1416
1757
  注意:仅筛选用户自定义工具,内置工具不参与筛选(始终保留)
1417
1758
  """
1418
1759
  tool_registry = self.get_tool_registry()
@@ -1451,7 +1792,9 @@ class Agent:
1451
1792
  请根据用户任务,从列表中选择最相关的工具。
1452
1793
  请仅返回所选工具的编号,以逗号分隔。例如:1, 5, 12
1453
1794
  """
1454
- print(f"ℹ️ 工具数量超过{threshold}个,正在使用AI筛选相关工具...")
1795
+ PrettyOutput.auto_print(
1796
+ f"ℹ️ 工具数量超过{threshold}个,正在使用AI筛选相关工具..."
1797
+ )
1455
1798
  # 广播工具筛选开始事件
1456
1799
  try:
1457
1800
  self.event_bus.emit(
@@ -1467,18 +1810,14 @@ class Agent:
1467
1810
  # 使用临时模型实例调用模型,以避免污染历史记录
1468
1811
  try:
1469
1812
  temp_model = self._create_temp_model("你是一个帮助筛选工具的助手。")
1470
- selected_tools_str = temp_model.chat_until_success(
1471
- selection_prompt
1472
- ) # type: ignore
1813
+ selected_tools_str = temp_model.chat_until_success(selection_prompt)
1473
1814
 
1474
1815
  # 解析响应并筛选工具
1475
1816
  selected_indices = [
1476
1817
  int(i.strip()) for i in re.findall(r"\d+", selected_tools_str)
1477
1818
  ]
1478
1819
  selected_tool_names = [
1479
- tool_names[i - 1]
1480
- for i in selected_indices
1481
- if 0 < i <= len(tool_names)
1820
+ tool_names[i - 1] for i in selected_indices if 0 < i <= len(tool_names)
1482
1821
  ]
1483
1822
 
1484
1823
  if selected_tool_names:
@@ -1486,11 +1825,15 @@ class Agent:
1486
1825
  selected_tool_names = sorted(list(set(selected_tool_names)))
1487
1826
  # 合并内置工具名称和筛选出的用户自定义工具名称
1488
1827
  builtin_names = list(tool_registry._builtin_tool_names)
1489
- final_tool_names = sorted(list(set(builtin_names + selected_tool_names)))
1828
+ final_tool_names = sorted(
1829
+ list(set(builtin_names + selected_tool_names))
1830
+ )
1490
1831
  tool_registry.use_tools(final_tool_names)
1491
1832
  # 使用筛选后的工具列表重新设置系统提示
1492
1833
  self._setup_system_prompt()
1493
- print(f"✅ 已筛选出 {len(selected_tool_names)} 个相关工具: {', '.join(selected_tool_names)}")
1834
+ PrettyOutput.auto_print(
1835
+ f"✅ 已筛选出 {len(selected_tool_names)} 个相关工具: {', '.join(selected_tool_names)}"
1836
+ )
1494
1837
  # 广播工具筛选事件
1495
1838
  try:
1496
1839
  self.event_bus.emit(
@@ -1504,7 +1847,7 @@ class Agent:
1504
1847
  except Exception:
1505
1848
  pass
1506
1849
  else:
1507
- print("⚠️ AI 未能筛选出任何相关工具,将使用所有工具。")
1850
+ PrettyOutput.auto_print("⚠️ AI 未能筛选出任何相关工具,将使用所有工具。")
1508
1851
  # 广播工具筛选事件(无筛选结果)
1509
1852
  try:
1510
1853
  self.event_bus.emit(
@@ -1519,7 +1862,7 @@ class Agent:
1519
1862
  pass
1520
1863
 
1521
1864
  except Exception as e:
1522
- print(f"❌ 工具筛选失败: {e},将使用所有工具。")
1865
+ PrettyOutput.auto_print(f"❌ 工具筛选失败: {e},将使用所有工具。")
1523
1866
 
1524
1867
  def _check_and_organize_memory(self):
1525
1868
  """
@@ -1536,7 +1879,7 @@ class Agent:
1536
1879
  "global",
1537
1880
  )
1538
1881
  except Exception as e:
1539
- print(f"⚠️ 检查记忆库时发生意外错误: {e}")
1882
+ PrettyOutput.auto_print(f"⚠️ 检查记忆库时发生意外错误: {e}")
1540
1883
 
1541
1884
  def _perform_memory_check(self, memory_type: str, base_path: Path, scope_name: str):
1542
1885
  """执行特定范围的记忆检查和整理"""
@@ -1578,7 +1921,9 @@ class Agent:
1578
1921
  f"是否立即整理记忆库以优化性能和相关性?"
1579
1922
  )
1580
1923
  if self.confirm_callback(prompt, False):
1581
- print(f"ℹ️ 正在开始整理 '{scope_name}' ({memory_type}) 记忆库...")
1924
+ PrettyOutput.auto_print(
1925
+ f"ℹ️ 正在开始整理 '{scope_name}' ({memory_type}) 记忆库..."
1926
+ )
1582
1927
  organizer.organize_memories(memory_type, min_overlap=3)
1583
1928
  else:
1584
- print(f"ℹ️ 已取消 '{scope_name}' 记忆库整理。")
1929
+ PrettyOutput.auto_print(f"ℹ️ 已取消 '{scope_name}' 记忆库整理。")