jarvis-ai-assistant 0.7.8__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.8.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.8.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1811 @@
1
+ """任务列表管理工具。
2
+
3
+ 该工具允许 LLM 管理任务列表,包括创建任务列表、添加任务、更新任务状态等。
4
+ """
5
+
6
+ import json
7
+ from typing import Any
8
+
9
+ from jarvis.jarvis_utils.output import PrettyOutput
10
+
11
+ # -*- coding: utf-8 -*-
12
+ from typing import Dict
13
+ from typing import List
14
+ from typing import Optional
15
+
16
+ from jarvis.jarvis_agent.task_list import TaskStatus
17
+ from jarvis.jarvis_utils.config import get_max_input_token_count
18
+ from jarvis.jarvis_utils.globals import get_global_model_group
19
+ from jarvis.jarvis_utils.tag import ot, ct
20
+
21
+
22
+ class DependencyValidationError(Exception):
23
+ """依赖验证错误的基类"""
24
+
25
+ pass
26
+
27
+
28
+ class DependencyNotFoundError(DependencyValidationError):
29
+ """依赖任务不存在错误"""
30
+
31
+ pass
32
+
33
+
34
+ class DependencyNotCompletedError(DependencyValidationError):
35
+ """依赖任务未完成错误"""
36
+
37
+ pass
38
+
39
+
40
+ class DependencyFailedError(DependencyValidationError):
41
+ """依赖任务失败错误"""
42
+
43
+ pass
44
+
45
+
46
+ # 任务输出长度限制常量
47
+ DEFAULT_MAX_TASK_OUTPUT_LENGTH = 10000 # 默认最大任务输出长度(字符数)
48
+
49
+
50
+ class task_list_manager:
51
+ """任务列表管理工具,供 LLM 调用"""
52
+
53
+ name = "task_list_manager"
54
+
55
+ def _get_max_output_length(self, agent: Any = None) -> int:
56
+ """获取基于剩余token数量的最大输出长度(字符数)
57
+
58
+ 参数:
59
+ agent: Agent实例,用于获取模型和剩余token数量
60
+
61
+ 返回:
62
+ int: 允许的最大字符数(基于剩余token计算,保留安全余量)
63
+ """
64
+ try:
65
+ # 优先使用剩余token数量
66
+ if agent and hasattr(agent, "model"):
67
+ try:
68
+ remaining_tokens = agent.model.get_remaining_token_count()
69
+ # 使用剩余token的2/3作为限制,保留1/3作为安全余量
70
+ # 粗略估算:1个token约等于4个字符(中文可能更少,但保守估计)
71
+ limit_tokens = int(remaining_tokens * 2 / 3)
72
+ # 转换为字符数(保守估计:1 token = 4 字符)
73
+ limit_chars = limit_tokens * 4
74
+ # 确保至少返回一个合理的值
75
+ if limit_chars > 0:
76
+ return limit_chars
77
+ except Exception:
78
+ pass
79
+
80
+ # 回退方案:使用输入窗口的2/3
81
+ # 使用全局模型组(不再从 agent 继承)
82
+ model_group = get_global_model_group()
83
+
84
+ max_input_tokens = get_max_input_token_count(model_group)
85
+ # 计算2/3限制的token数,然后转换为字符数
86
+ limit_tokens = int(max_input_tokens * 2 / 3)
87
+ limit_chars = limit_tokens * 4
88
+ return limit_chars
89
+ except Exception:
90
+ # 如果获取失败,使用默认值
91
+ return DEFAULT_MAX_TASK_OUTPUT_LENGTH
92
+
93
+ def _get_truncate_lengths(self, max_length: int) -> tuple[int, int]:
94
+ """根据最大长度计算截断时的前缀和后缀长度
95
+
96
+ 参数:
97
+ max_length: 最大长度(字符数)
98
+
99
+ 返回:
100
+ tuple[int, int]: (前缀长度, 后缀长度)
101
+ """
102
+ # 前缀占80%,后缀占20%
103
+ prefix_length = int(max_length * 0.8)
104
+ suffix_length = int(max_length * 0.2)
105
+ return prefix_length, suffix_length
106
+
107
+ def _get_task_list_id(self, agent: Any) -> Optional[str]:
108
+ """从 Agent 的 user_data 中获取 task_list_id
109
+
110
+ 参数:
111
+ agent: Agent 实例
112
+
113
+ 返回:
114
+ Optional[str]: task_list_id,如果不存在则返回 None
115
+ """
116
+ if not agent:
117
+ return None
118
+ try:
119
+ result = agent.get_user_data("__task_list_id__")
120
+ return str(result) if result is not None else None
121
+ except Exception:
122
+ return None
123
+
124
+ def _set_task_list_id(self, agent: Any, task_list_id: str) -> None:
125
+ """将 task_list_id 保存到 Agent 的 user_data 中
126
+
127
+ 参数:
128
+ agent: Agent 实例
129
+ task_list_id: 任务列表 ID
130
+ """
131
+ if not agent:
132
+ return
133
+ try:
134
+ agent.set_user_data("__task_list_id__", task_list_id)
135
+ except Exception:
136
+ pass
137
+
138
+ def _determine_agent_type(
139
+ self, agent: Any, task: Any, task_content: str, background: str
140
+ ) -> bool:
141
+ """直接根据agent实例判断是否为代码相关任务
142
+
143
+ 参数:
144
+ agent: 当前执行的agent实例
145
+ task: 任务对象
146
+ task_content: 任务内容
147
+ background: 背景信息
148
+
149
+ 返回:
150
+ bool: True 表示代码相关任务,False 表示通用任务
151
+ """
152
+ try:
153
+ # 直接根据agent实例类型判断
154
+ from jarvis.jarvis_code_agent.code_agent import CodeAgent
155
+
156
+ return isinstance(agent, CodeAgent)
157
+ except ImportError:
158
+ # 如果导入失败,回退到通用Agent
159
+ return False
160
+
161
+ def _create_verification_agent(
162
+ self, task: Any, parent_agent: Any, verification_iteration: int = 1
163
+ ) -> Any:
164
+ """创建验证 Agent,只能使用 read_code 和 execute_script 工具
165
+
166
+ 参数:
167
+ task: 任务对象
168
+ parent_agent: 父 Agent 实例
169
+ verification_iteration: 验证迭代次数
170
+
171
+ 返回:
172
+ Agent: 验证 Agent 实例
173
+ """
174
+ from jarvis.jarvis_agent import Agent
175
+ from jarvis.jarvis_utils.globals import get_global_model_group
176
+
177
+ # 构建验证任务的系统提示词
178
+ verification_system_prompt = f"""你是一个任务验证专家。你的任务是验证任务是否真正完成,仅验证任务预期输出和产物。
179
+
180
+ **任务信息:**
181
+ - 任务名称:{task.task_name}
182
+ - 任务描述:{task.task_desc}
183
+ - 预期输出(建议为分条列出的结构化条目,例如 1)、2)、3) 或 markdown 列表 - item):{task.expected_output}
184
+
185
+ **验证要求:**
186
+ 1. 将预期输出解析为一组**逐条的预期结果条目**(例如按换行、编号 1)、2)、3) 或 markdown 列表 - item 进行切分)
187
+ 2. 对**每一条预期结果条目**分别进行验证:检查对应的代码、文件或其他产物是否真实存在且满足该条要求
188
+ 3. 使用 read_code 工具验证任务产生的代码或文件是否符合对应条目的要求
189
+ 4. 仅检查任务明确要求的产物是否存在且正确
190
+ 5. 不要验证与任务预期输出无关的项目(如整体项目编译、无关测试等)
191
+ 6. 关注任务描述中明确提到的具体交付物
192
+
193
+ **验证标准:**
194
+ - 每一条预期输出条目是否都已实际生成对应产物
195
+ - 每一条条目对应的产物是否符合任务描述中的具体要求
196
+ - 不验证无关的编译状态、测试覆盖率或代码风格
197
+
198
+ **重要:**
199
+ - 只能使用 read_code 和 execute_script 工具
200
+ - 必须基于实际验证结果,不能推测或假设
201
+ - 仅验证任务预期输出和直接相关的产物
202
+ - 如果验证通过,直接输出 {ot("!!!COMPLETE!!!")},不要输出其他任何内容。
203
+ - **严禁尝试修复问题**:只能报告发现的问题,严禁提供修复建议或尝试任何修复操作
204
+ """
205
+
206
+ # 构建验证任务的总结提示词(结构化格式要求)
207
+ verification_summary_prompt = f"""请以结构化的格式总结任务验证结果。必须严格按照以下格式输出:
208
+
209
+ ## 任务验证结果
210
+
211
+ **任务名称**:{task.task_name}
212
+
213
+ **验证状态**:[PASSED/FAILED]
214
+
215
+ **最终结论**:[VERIFICATION_PASSED 或 VERIFICATION_FAILED]
216
+
217
+ **逐条验证结果**:
218
+ - 逐条列出每一个预期输出条目及其验证结果,格式示例:
219
+ - 条目1:[PASSED/FAILED] 说明...
220
+ - 条目2:[PASSED/FAILED] 说明...
221
+ - 条目3:[PASSED/FAILED] 说明...
222
+
223
+ **说明**:
224
+ - 如果验证通过:输出 "所有预期输出条目均已验证完成"
225
+ - 如果验证失败:详细说明不通过的原因,包括:
226
+ * 哪些预期输出条目未找到或不完整
227
+ * 实际输出与各条目预期不符的具体差异
228
+ * 需要补充或修正的部分
229
+
230
+ **重要**:
231
+ - 必须严格按照上述格式输出
232
+ - 验证状态必须是 PASSED 或 FAILED
233
+ - 最终结论必须是 "VERIFICATION_PASSED" 或 "VERIFICATION_FAILED"
234
+ - 仅基于任务预期输出进行验证,不涉及无关检查
235
+ """
236
+
237
+ # 获取父 Agent 的模型组
238
+ model_group = get_global_model_group()
239
+ try:
240
+ if parent_agent is not None:
241
+ model_group = getattr(parent_agent, "model_group", model_group)
242
+ except Exception:
243
+ pass
244
+
245
+ # 创建验证 Agent,只使用 read_code 和 execute_script 工具
246
+ # 获取父代理所有规则内容并添加到系统提示词
247
+ rules_content, _ = parent_agent.rules_manager.load_all_rules(
248
+ ",".join(parent_agent.loaded_rule_names)
249
+ )
250
+
251
+ enhanced_system_prompt = verification_system_prompt + rules_content
252
+
253
+ verification_agent = Agent(
254
+ system_prompt=enhanced_system_prompt,
255
+ name=f"verification_agent_{task.task_id}_{verification_iteration}",
256
+ description="Task verification agent",
257
+ model_group=model_group,
258
+ summary_prompt=verification_summary_prompt,
259
+ auto_complete=True,
260
+ need_summary=True,
261
+ use_tools=["read_code", "execute_script"], # 只使用这两个工具
262
+ non_interactive=True,
263
+ )
264
+
265
+ return verification_agent
266
+
267
+ def _verify_task_completion(
268
+ self,
269
+ task: Any,
270
+ task_content: str,
271
+ background: str,
272
+ parent_agent: Any,
273
+ verification_iteration: int = 1,
274
+ ) -> tuple[bool, str]:
275
+ """验证任务是否真正完成
276
+
277
+ 参数:
278
+ task: 任务对象
279
+ task_content: 任务内容
280
+ background: 背景信息
281
+ parent_agent: 父 Agent 实例
282
+ verification_iteration: 验证迭代次数
283
+
284
+ 返回:
285
+ tuple[bool, str]: (是否完成, 验证结果或失败原因)
286
+ """
287
+ try:
288
+ from jarvis.jarvis_utils.output import PrettyOutput
289
+
290
+ # 创建验证 Agent
291
+ verification_agent = self._create_verification_agent(
292
+ task, parent_agent, verification_iteration
293
+ )
294
+
295
+ # 构建验证任务
296
+ verification_task = f"""请验证以下任务是否真正完成,并且**对预期输出中的每一条条目分别进行验证**:
297
+
298
+ {task_content}
299
+
300
+ 背景信息:
301
+ {background}
302
+
303
+ 请使用 read_code 和 execute_script 工具进行验证,重点检查:
304
+ 1. 将预期输出解析为多条具体条目(按换行 / 编号 1)、2)、3) / markdown 列表 - item 等方式拆分)
305
+ 2. 对每一条预期输出条目,检查是否有对应的代码、文件或其他实际产物支撑
306
+ 3. 如果某条条目无法找到对应产物、产物不完整或与描述不符,需单独标记为 FAILED,并说明原因
307
+ 4. 仅在**所有预期输出条目**都验证通过时,才可以整体判定为 PASSED
308
+
309
+ 如果存在编译错误、运行时错误、测试失败,或任意一条预期输出条目未满足要求,必须明确标记整体为未完成,并详细说明原因。
310
+ """
311
+
312
+ PrettyOutput.auto_print(
313
+ f"🔍 开始验证任务 [{task.task_name}] (第 {verification_iteration} 次验证)..."
314
+ )
315
+
316
+ # 执行验证
317
+ verification_result = verification_agent.run(verification_task)
318
+
319
+ # 解析验证结果(从结构化的 summary 中提取)
320
+ if verification_result:
321
+ verification_result_str = str(verification_result)
322
+
323
+ # 尝试从结构化格式中提取验证状态
324
+ verification_status = None
325
+ final_conclusion = None
326
+ detailed_explanation = None
327
+
328
+ # 查找验证状态
329
+ import re
330
+
331
+ status_match = re.search(
332
+ r"\*\*验证状态\*\*:\s*\[(PASSED|FAILED)\]", verification_result_str
333
+ )
334
+ if status_match:
335
+ verification_status = status_match.group(1)
336
+
337
+ # 查找最终结论
338
+ conclusion_match = re.search(
339
+ r"\*\*最终结论\*\*:\s*\[(VERIFICATION_PASSED|VERIFICATION_FAILED)\]",
340
+ verification_result_str,
341
+ )
342
+ if conclusion_match:
343
+ final_conclusion = conclusion_match.group(1)
344
+
345
+ # 提取说明(可能是"详细说明"或"说明")
346
+ explanation_match = re.search(
347
+ r"\*\*说明\*\*:\s*\n(.*?)(?=\n\n|\*\*|$)",
348
+ verification_result_str,
349
+ re.DOTALL,
350
+ )
351
+ if explanation_match:
352
+ detailed_explanation = explanation_match.group(1).strip()
353
+ else:
354
+ # 尝试查找"详细说明"
355
+ explanation_match = re.search(
356
+ r"\*\*详细说明\*\*:\s*\n(.*?)(?=\n\n|\*\*|$)",
357
+ verification_result_str,
358
+ re.DOTALL,
359
+ )
360
+ if explanation_match:
361
+ detailed_explanation = explanation_match.group(1).strip()
362
+
363
+ # 判断验证是否通过
364
+ is_passed = False
365
+ if (
366
+ verification_status == "PASSED"
367
+ or final_conclusion == "VERIFICATION_PASSED"
368
+ ):
369
+ is_passed = True
370
+ elif (
371
+ verification_status == "FAILED"
372
+ or final_conclusion == "VERIFICATION_FAILED"
373
+ ):
374
+ is_passed = False
375
+ elif "VERIFICATION_PASSED" in verification_result_str.upper():
376
+ is_passed = True
377
+ elif "VERIFICATION_FAILED" in verification_result_str.upper():
378
+ is_passed = False
379
+ else:
380
+ # 如果无法从结构化格式中提取,尝试查找关键词
381
+ if (
382
+ "验证通过" in verification_result_str
383
+ or "所有验证通过" in verification_result_str
384
+ ):
385
+ is_passed = True
386
+ elif (
387
+ "验证失败" in verification_result_str
388
+ or "验证未通过" in verification_result_str
389
+ ):
390
+ is_passed = False
391
+ else:
392
+ # 默认认为未通过
393
+ is_passed = False
394
+
395
+ if is_passed:
396
+ PrettyOutput.auto_print(f"✅ 任务 [{task.task_name}] 验证通过")
397
+ return True, verification_result_str
398
+ else:
399
+ # 使用详细说明作为失败原因,如果没有则使用整个结果
400
+ failure_reason = (
401
+ detailed_explanation
402
+ if detailed_explanation
403
+ else verification_result_str
404
+ )
405
+ PrettyOutput.auto_print(
406
+ f"❌ 任务 [{task.task_name}] 验证未通过:{failure_reason[:200]}..."
407
+ )
408
+ return False, failure_reason
409
+ else:
410
+ PrettyOutput.auto_print(
411
+ f"⚠️ 任务 [{task.task_name}] 验证无结果,默认认为未完成"
412
+ )
413
+ return False, "验证无结果"
414
+
415
+ except Exception as e:
416
+ PrettyOutput.auto_print(
417
+ f"⚠️ 验证任务 [{task.task_name}] 时发生异常: {str(e)}"
418
+ )
419
+ return False, f"验证异常: {str(e)}"
420
+
421
+ def _print_task_list_status(
422
+ self, task_list_manager: Any, task_list_id: Optional[str] = None
423
+ ):
424
+ """打印任务列表状态
425
+
426
+ 参数:
427
+ task_list_manager: 任务列表管理器实例
428
+ task_list_id: 任务列表ID(如果为None,则不打印)
429
+ """
430
+ try:
431
+ from rich.console import Console
432
+ from rich.table import Table
433
+
434
+ console = Console()
435
+
436
+ # 确定要打印的任务列表
437
+ task_lists_to_print = {}
438
+ if task_list_id:
439
+ task_list = task_list_manager.get_task_list(task_list_id)
440
+ if task_list:
441
+ task_lists_to_print[task_list_id] = task_list
442
+
443
+ if not task_lists_to_print:
444
+ return
445
+
446
+ for tlist_id, task_list in task_lists_to_print.items():
447
+ tasks = list(task_list.tasks.values())
448
+ if not tasks:
449
+ continue
450
+
451
+ # 创建表格
452
+ table = Table(
453
+ title=f"任务列表状态: {tlist_id}",
454
+ show_header=True,
455
+ header_style="bold magenta",
456
+ title_style="bold cyan",
457
+ )
458
+ table.add_column("任务ID", style="cyan", width=12)
459
+ table.add_column("任务名称", style="yellow", width=30)
460
+ table.add_column("状态", style="bold", width=12)
461
+ table.add_column("优先级", justify="center", width=8)
462
+ table.add_column("Agent类型", width=10)
463
+ table.add_column("依赖", width=12)
464
+
465
+ # 按优先级和创建时间排序
466
+ sorted_tasks = sorted(tasks, key=lambda t: (-t.priority, t.create_time))
467
+
468
+ # 状态颜色映射
469
+ status_colors = {
470
+ TaskStatus.PENDING: "yellow",
471
+ TaskStatus.RUNNING: "blue",
472
+ TaskStatus.COMPLETED: "green",
473
+ TaskStatus.FAILED: "red",
474
+ TaskStatus.ABANDONED: "dim",
475
+ }
476
+
477
+ for task in sorted_tasks:
478
+ status_color = status_colors.get(task.status, "white")
479
+ status_text = (
480
+ f"[{status_color}]{task.status.value}[/{status_color}]"
481
+ )
482
+
483
+ # 格式化依赖
484
+ deps_text = ", ".join(task.dependencies[:3])
485
+ if len(task.dependencies) > 3:
486
+ deps_text += f" (+{len(task.dependencies) - 3})"
487
+
488
+ table.add_row(
489
+ task.task_id,
490
+ task.task_name[:28] + "..."
491
+ if len(task.task_name) > 30
492
+ else task.task_name,
493
+ status_text,
494
+ str(task.priority),
495
+ task.agent_type.value,
496
+ deps_text if task.dependencies else "-",
497
+ )
498
+
499
+ console.print(table)
500
+
501
+ # 打印统计信息
502
+ summary = task_list_manager.get_task_list_summary(tlist_id)
503
+ if summary:
504
+ stats_text = (
505
+ f"📊 总计: {summary['total_tasks']} | "
506
+ f"⏳ 待执行: {summary['pending']} | "
507
+ f"🔄 执行中: {summary['running']} | "
508
+ f"✅ 已完成: {summary['completed']} | "
509
+ f"❌ 失败: {summary['failed']} | "
510
+ f"🚫 已放弃: {summary['abandoned']}"
511
+ )
512
+ console.print(f"[dim]{stats_text}[/dim]")
513
+ console.print() # 空行
514
+
515
+ except Exception as e:
516
+ # 打印详细错误信息,帮助调试
517
+ import traceback
518
+
519
+ PrettyOutput.auto_print(f"⚠️ 打印任务状态失败: {e}")
520
+ PrettyOutput.auto_print(f" 错误详情: {traceback.format_exc()}")
521
+
522
+ description = f"""任务列表管理工具,供LLM管理复杂任务拆分和执行。
523
+
524
+ **核心功能:**
525
+ - `add_tasks`: 批量添加任务(推荐PLAN阶段使用)
526
+ - `execute_task`: 执行任务(自动创建子Agent)
527
+ - `get_task_list_summary`: 查看任务状态
528
+
529
+ **任务类型选择:**
530
+ - `main`: 简单任务(1-3步、单文件)由主Agent直接执行
531
+ - `sub`: 复杂任务(多步骤、多文件)自动创建子Agent
532
+
533
+ **强制要求:**
534
+ - execute_task必须提供non-empty additional_info参数
535
+ - 禁止过度拆分简单任务
536
+ - 每个Agent只能有一个任务列表
537
+
538
+ **使用场景:**
539
+ - PLAN阶段:一次性添加所有子任务
540
+ - 数据切分:按目录/文件/模块分批处理
541
+ - 依赖管理:自动验证任务依赖关系
542
+
543
+ **关键原则:**
544
+ 简单任务用main,复杂任务用sub,避免过度拆分。
545
+
546
+ **使用示例**
547
+ 创建任务列表:
548
+ ```
549
+ {ot("TOOL_CALL")}
550
+ {{
551
+ "name": "task_list_manager",
552
+ "arguments": {{
553
+ "action": "add_tasks",
554
+ "main_goal": "创建任务列表",
555
+ "background": "背景信息",
556
+ "tasks_info": [
557
+ {{
558
+ "task_name": "任务1",
559
+ "task_desc": "任务1描述",
560
+ "priority": 1,
561
+ "expected_output": "任务1预期输出",
562
+ "agent_type": "main",
563
+ "dependencies": []
564
+ }}
565
+ {{
566
+ "task_name": "任务2",
567
+ "task_desc": "任务2描述",
568
+ "priority": 2,
569
+ "expected_output": "任务2预期输出",
570
+ "agent_type": "sub",
571
+ "dependencies": ["任务1"]
572
+ }}
573
+ ]
574
+ }}
575
+ }}
576
+ {ct("TOOL_CALL")}
577
+ ```
578
+
579
+ 执行任务:
580
+ ```
581
+ {ot("TOOL_CALL")}
582
+ {{
583
+ "name": "task_list_manager",
584
+ "arguments": {{
585
+ "action": "execute_task",
586
+ "task_id": "任务ID",
587
+ "additional_info": "任务详细信息"
588
+ }}
589
+ }}
590
+ {ct("TOOL_CALL")}
591
+ ```
592
+
593
+ 更新任务状态:
594
+ ```
595
+ {ot("TOOL_CALL")}
596
+ {{
597
+ "name": "task_list_manager",
598
+ "arguments": {{
599
+ "action": "update_task",
600
+ "task_id": "任务ID",
601
+ "task_update_info": {{
602
+ "status": "completed",
603
+ "actual_output": "任务实际输出"
604
+ }}
605
+ }}
606
+ }}
607
+ {ct("TOOL_CALL")}
608
+ ```
609
+
610
+
611
+ """
612
+
613
+ parameters = {
614
+ "type": "object",
615
+ "properties": {
616
+ "action": {
617
+ "type": "string",
618
+ "enum": [
619
+ "add_tasks",
620
+ "get_task_detail",
621
+ "get_task_list_summary",
622
+ "execute_task",
623
+ "update_task",
624
+ ],
625
+ "description": "要执行的操作",
626
+ },
627
+ "main_goal": {
628
+ "type": "string",
629
+ "description": "任务列表的核心目标(必填,仅在首次创建任务列表时使用)。创建新任务列表时必须提供此参数。",
630
+ },
631
+ "background": {
632
+ "type": "string",
633
+ "description": "所有子任务的公共背景信息,将自动添加到每个子任务的描述中。**必须包含以下信息**:1) **全局约束条件**:所有子任务必须遵循的技术约束、环境限制、性能要求等;2) **必须要求**:所有子任务必须完成的要求、必须遵循的规范、必须实现的功能等;3) **禁止事项**:所有子任务执行中禁止的操作、禁止使用的技术、禁止修改的内容等;4) **验证标准**:所有子任务的统一验证方式、验收标准、测试要求等。可用于提供全局上下文、统一规范等公共信息。",
634
+ },
635
+ "tasks_info": {
636
+ "type": "array",
637
+ "description": "任务信息列表(add_tasks 需要,如果任务列表不存在会自动创建)",
638
+ "items": {
639
+ "type": "object",
640
+ "properties": {
641
+ "task_name": {"type": "string", "description": "任务名称"},
642
+ "task_desc": {
643
+ "type": "string",
644
+ "description": "任务描述。**必须包含以下信息**:1) **约束条件**:明确任务执行的技术约束、环境限制、性能要求等;2) **必须要求**:明确任务必须完成的具体要求、必须遵循的规范、必须实现的功能等;3) **禁止事项**:明确任务执行中禁止的操作、禁止使用的技术、禁止修改的内容等;4) **验证标准**:明确任务完成的验证方式、验收标准、测试要求等。任务描述应该清晰、具体、可执行。",
645
+ },
646
+ "priority": {
647
+ "type": "integer",
648
+ "description": "优先级(1-5,5为最高)",
649
+ },
650
+ "expected_output": {
651
+ "type": "string",
652
+ "description": "预期输出。**必须使用分条列出的结构化格式**,例如:1) xxx;2) yyy;3) zzz,或使用 markdown 列表 - xxx、- yyy、- zzz。后续验证 Agent 会对每一条预期输出条目分别进行验证。",
653
+ },
654
+ "agent_type": {
655
+ "type": "string",
656
+ "enum": ["main", "sub"],
657
+ "description": "Agent类型:**简单任务必须使用 `main`**(由主Agent直接执行,不要拆分为子任务);**复杂任务使用 `sub`**(系统智能处理复杂任务)",
658
+ },
659
+ "dependencies": {
660
+ "type": "array",
661
+ "items": {"type": "string"},
662
+ "description": "依赖的任务名称或任务ID列表(可选,可以引用本次批次中的任务名称)",
663
+ },
664
+ },
665
+ "required": [
666
+ "task_name",
667
+ "task_desc",
668
+ "priority",
669
+ "expected_output",
670
+ "agent_type",
671
+ ],
672
+ },
673
+ },
674
+ "task_id": {
675
+ "type": "string",
676
+ "description": "任务ID(execute_task/update_task/get_task_detail 需要)",
677
+ },
678
+ "additional_info": {
679
+ "type": "string",
680
+ "description": "附加信息(**仅在 execute_task 时必填**)。必须提供任务的详细上下文信息,包括任务背景、关键信息、约束条件、预期结果等。不能为空字符串或None。",
681
+ },
682
+ "task_update_info": {
683
+ "type": "object",
684
+ "description": "任务更新信息(update_task 需要)",
685
+ "properties": {
686
+ "task_name": {
687
+ "type": "string",
688
+ "description": "更新后的任务名称(可选)",
689
+ },
690
+ "task_desc": {
691
+ "type": "string",
692
+ "description": "更新后的任务描述(可选)。**必须包含以下信息**:1) **约束条件**:明确任务执行的技术约束、环境限制、性能要求等;2) **必须要求**:明确任务必须完成的具体要求、必须遵循的规范、必须实现的功能等;3) **禁止事项**:明确任务执行中禁止的操作、禁止使用的技术、禁止修改的内容等;4) **验证标准**:明确任务完成的验证方式、验收标准、测试要求等。任务描述应该清晰、具体、可执行。",
693
+ },
694
+ "priority": {
695
+ "type": "integer",
696
+ "description": "更新后的优先级(可选,1-5)",
697
+ },
698
+ "expected_output": {
699
+ "type": "string",
700
+ "description": "更新后的预期输出(可选)",
701
+ },
702
+ "dependencies": {
703
+ "type": "array",
704
+ "items": {"type": "string"},
705
+ "description": "更新后的依赖任务ID列表(可选)",
706
+ },
707
+ "status": {
708
+ "type": "string",
709
+ "enum": [
710
+ "pending",
711
+ "running",
712
+ "completed",
713
+ "failed",
714
+ "abandoned",
715
+ ],
716
+ "description": "更新后的任务状态(可选,通常不需要手动调用)",
717
+ },
718
+ "actual_output": {
719
+ "type": "string",
720
+ "description": "更新后的实际输出(可选,通常不需要手动调用)",
721
+ },
722
+ },
723
+ },
724
+ },
725
+ "required": ["action"],
726
+ }
727
+
728
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
729
+ """执行任务列表管理操作"""
730
+ try:
731
+ agent = args.get("agent")
732
+ if not agent:
733
+ return {
734
+ "success": False,
735
+ "stdout": "",
736
+ "stderr": "无法获取 Agent 实例",
737
+ }
738
+
739
+ # 获取任务列表管理器
740
+ task_list_manager = getattr(agent, "task_list_manager", None)
741
+ if not task_list_manager:
742
+ return {
743
+ "success": False,
744
+ "stdout": "",
745
+ "stderr": "任务列表管理器未初始化",
746
+ }
747
+
748
+ # 获取 Agent ID(使用 Agent 名称作为 ID)
749
+ agent_id = getattr(agent, "name", "main_agent")
750
+ is_main_agent = True # CodeAgent 默认是主 Agent
751
+
752
+ action = args.get("action")
753
+ if not action:
754
+ return {
755
+ "success": False,
756
+ "stdout": "",
757
+ "stderr": "缺少 action 参数",
758
+ }
759
+
760
+ # 根据 action 执行相应操作
761
+ result = None
762
+ task_list_id_for_status = None
763
+
764
+ if action == "add_tasks":
765
+ result = self._handle_add_tasks(
766
+ args, task_list_manager, agent_id, agent
767
+ )
768
+ task_list_id_for_status = self._get_task_list_id(agent)
769
+
770
+ elif action == "get_task_detail":
771
+ result = self._handle_get_task_detail(
772
+ args, task_list_manager, agent_id, is_main_agent, agent
773
+ )
774
+ task_list_id_for_status = self._get_task_list_id(agent)
775
+
776
+ elif action == "get_task_list_summary":
777
+ result = self._handle_get_task_list_summary(
778
+ args, task_list_manager, agent
779
+ )
780
+ task_list_id_for_status = self._get_task_list_id(agent)
781
+
782
+ elif action == "execute_task":
783
+ result = self._handle_execute_task(
784
+ args, task_list_manager, agent_id, is_main_agent, agent
785
+ )
786
+ task_list_id_for_status = self._get_task_list_id(agent)
787
+
788
+ elif action == "update_task":
789
+ result = self._handle_update_task(
790
+ args, task_list_manager, agent_id, is_main_agent, agent
791
+ )
792
+ task_list_id_for_status = self._get_task_list_id(agent)
793
+
794
+ else:
795
+ result = {
796
+ "success": False,
797
+ "stdout": "",
798
+ "stderr": f"未知的操作: {action}",
799
+ }
800
+
801
+ # 打印任务状态(如果操作成功)
802
+ if result and result.get("success"):
803
+ # 如果有 task_list_id,只打印该任务列表;否则打印所有任务列表
804
+ self._print_task_list_status(task_list_manager, task_list_id_for_status)
805
+
806
+ return result
807
+
808
+ except Exception as e:
809
+ return {
810
+ "success": False,
811
+ "stdout": "",
812
+ "stderr": f"执行任务列表操作失败: {str(e)}",
813
+ }
814
+
815
+ def _handle_add_tasks(
816
+ self, args: Dict, task_list_manager: Any, agent_id: str, agent: Any
817
+ ) -> Dict[str, Any]:
818
+ """处理批量添加任务(支持通过任务名称匹配依赖关系)"""
819
+ task_list_id = self._get_task_list_id(agent)
820
+ tasks_info = args.get("tasks_info")
821
+
822
+ if not task_list_id:
823
+ # 验证:如果没有task_list且只有一个任务且agent不是main,则拒绝
824
+ if tasks_info and isinstance(tasks_info, list) and len(tasks_info) == 1:
825
+ # 获取第一个任务的agent_type
826
+ first_task = tasks_info[0]
827
+ agent_type = first_task.get("agent_type")
828
+ if agent_type != "main":
829
+ return {
830
+ "success": False,
831
+ "stdout": "",
832
+ "stderr": "拒绝添加单个非main类型任务:对于简单任务,agent_type应为main,由主Agent直接执行。如需创建复杂任务,请添加多个任务或修改agent_type为main。",
833
+ }
834
+
835
+ # 自动创建任务列表
836
+ if not tasks_info:
837
+ return {
838
+ "success": False,
839
+ "stdout": "",
840
+ "stderr": "缺少 tasks_info 参数",
841
+ }
842
+
843
+ # 验证 main_goal 是否为必填参数
844
+ main_goal = args.get("main_goal")
845
+ if not main_goal:
846
+ return {
847
+ "success": False,
848
+ "stdout": "",
849
+ "stderr": "缺少 main_goal 参数:创建任务列表时必须提供 main_goal",
850
+ }
851
+
852
+ # 检查是否已有任务列表
853
+ existing_task_list_id = self._get_task_list_id(agent)
854
+ if existing_task_list_id:
855
+ # 检查任务列表是否还存在
856
+ existing_task_list = task_list_manager.get_task_list(
857
+ existing_task_list_id
858
+ )
859
+ if existing_task_list:
860
+ return {
861
+ "success": False,
862
+ "stdout": "",
863
+ "stderr": f"Agent 已存在任务列表(ID: {existing_task_list_id}),每个 Agent 只能有一个任务列表。如需创建新列表,请先完成或放弃当前任务列表。",
864
+ }
865
+
866
+ # 创建任务列表
867
+ task_list_id, success, error_msg = task_list_manager.create_task_list(
868
+ main_goal=main_goal, agent_id=agent_id
869
+ )
870
+
871
+ if not success:
872
+ return {
873
+ "success": False,
874
+ "stdout": "",
875
+ "stderr": f"自动创建任务列表失败: {error_msg}",
876
+ }
877
+
878
+ # 保存 task_list_id 到 Agent 的 user_data
879
+ self._set_task_list_id(agent, task_list_id)
880
+
881
+ tasks_info = args.get("tasks_info")
882
+ if not tasks_info:
883
+ return {
884
+ "success": False,
885
+ "stdout": "",
886
+ "stderr": "缺少 tasks_info 参数",
887
+ }
888
+
889
+ if not isinstance(tasks_info, list):
890
+ return {
891
+ "success": False,
892
+ "stdout": "",
893
+ "stderr": "tasks_info 必须是数组",
894
+ }
895
+
896
+ # 获取background参数并处理
897
+ background = args.get("background", "")
898
+ if background and str(background).strip():
899
+ # 将background信息附加到每个子任务的描述中
900
+ processed_tasks_info = []
901
+ for task_info in tasks_info:
902
+ if isinstance(task_info, dict) and "task_desc" in task_info:
903
+ # 创建新的task_info字典,避免修改原始数据
904
+ new_task_info = task_info.copy()
905
+
906
+ # 构建新的任务描述,包含background信息
907
+ original_desc = task_info["task_desc"]
908
+ separator = "\n" + "=" * 50 + "\n"
909
+ new_task_info["task_desc"] = (
910
+ f"{original_desc}{separator}公共背景信息:\n{background}"
911
+ )
912
+ processed_tasks_info.append(new_task_info)
913
+ else:
914
+ processed_tasks_info.append(task_info)
915
+ tasks_info = processed_tasks_info
916
+
917
+ # add_tasks 方法已经支持通过任务名称匹配依赖关系
918
+ task_ids, success, error_msg = task_list_manager.add_tasks(
919
+ task_list_id=task_list_id, tasks_info=tasks_info, agent_id=agent_id
920
+ )
921
+
922
+ if success:
923
+ result = {
924
+ "task_ids": task_ids,
925
+ "task_count": len(task_ids),
926
+ "task_list_id": task_list_id,
927
+ "message": f"成功批量添加 {len(task_ids)} 个任务",
928
+ }
929
+ return {
930
+ "success": True,
931
+ "stdout": json.dumps(result, ensure_ascii=False, indent=2),
932
+ "stderr": "",
933
+ }
934
+ else:
935
+ return {
936
+ "success": False,
937
+ "stdout": "",
938
+ "stderr": f"批量添加任务失败: {error_msg}",
939
+ }
940
+
941
+ def _handle_get_task_detail(
942
+ self,
943
+ args: Dict,
944
+ task_list_manager: Any,
945
+ agent_id: str,
946
+ is_main_agent: bool,
947
+ agent: Any,
948
+ ) -> Dict[str, Any]:
949
+ """处理获取任务详情"""
950
+ task_list_id = self._get_task_list_id(agent)
951
+ if not task_list_id:
952
+ return {
953
+ "success": False,
954
+ "stdout": "",
955
+ "stderr": "Agent 还没有任务列表,请先使用 add_tasks 添加任务(会自动创建任务列表)",
956
+ }
957
+ task_id = args.get("task_id")
958
+
959
+ if not task_id:
960
+ return {
961
+ "success": False,
962
+ "stdout": "",
963
+ "stderr": "缺少 task_id 参数",
964
+ }
965
+
966
+ task, success, error_msg = task_list_manager.get_task_detail(
967
+ task_list_id=task_list_id,
968
+ task_id=task_id,
969
+ agent_id=agent_id,
970
+ is_main_agent=is_main_agent,
971
+ )
972
+
973
+ if success and task:
974
+ result = {
975
+ "task": task.to_dict(),
976
+ "message": "获取任务详情成功",
977
+ }
978
+ return {
979
+ "success": True,
980
+ "stdout": json.dumps(result, ensure_ascii=False, indent=2),
981
+ "stderr": "",
982
+ }
983
+ else:
984
+ return {
985
+ "success": False,
986
+ "stdout": "",
987
+ "stderr": error_msg or "获取任务详情失败",
988
+ }
989
+
990
+ def _handle_get_task_list_summary(
991
+ self, args: Dict, task_list_manager: Any, agent: Any
992
+ ) -> Dict[str, Any]:
993
+ """处理获取任务列表摘要"""
994
+ task_list_id = self._get_task_list_id(agent)
995
+ if not task_list_id:
996
+ return {
997
+ "success": False,
998
+ "stdout": "",
999
+ "stderr": "Agent 还没有任务列表,请先使用 add_tasks 添加任务(会自动创建任务列表)",
1000
+ }
1001
+
1002
+ summary = task_list_manager.get_task_list_summary(task_list_id=task_list_id)
1003
+
1004
+ if summary:
1005
+ return {
1006
+ "success": True,
1007
+ "stdout": json.dumps(summary, ensure_ascii=False, indent=2),
1008
+ "stderr": "",
1009
+ }
1010
+ else:
1011
+ return {
1012
+ "success": False,
1013
+ "stdout": "",
1014
+ "stderr": "任务列表不存在",
1015
+ }
1016
+
1017
+ def _validate_dependencies_status(
1018
+ self,
1019
+ task_list_manager: Any,
1020
+ task_list_id: str,
1021
+ task: Any,
1022
+ agent_id: str,
1023
+ is_main_agent: bool,
1024
+ ) -> None:
1025
+ """验证任务的所有依赖是否都已completed
1026
+
1027
+ 参数:
1028
+ task_list_manager: 任务列表管理器
1029
+ task_list_id: 任务列表ID
1030
+ task: 要验证的任务对象
1031
+ agent_id: Agent ID
1032
+ is_main_agent: 是否为主 Agent
1033
+
1034
+ 抛出:
1035
+ DependencyNotFoundError: 依赖任务不存在
1036
+ DependencyNotCompletedError: 依赖任务未完成
1037
+ DependencyFailedError: 依赖任务失败
1038
+ """
1039
+ if not task.dependencies:
1040
+ return # 无依赖,直接返回
1041
+
1042
+ for dep_id in task.dependencies:
1043
+ dep_task, success, error_msg = task_list_manager.get_task_detail(
1044
+ task_list_id=task_list_id,
1045
+ task_id=dep_id,
1046
+ agent_id=agent_id,
1047
+ is_main_agent=is_main_agent,
1048
+ )
1049
+
1050
+ if not success:
1051
+ raise DependencyNotFoundError(f"依赖任务 '{dep_id}' 不存在")
1052
+
1053
+ if dep_task.status == TaskStatus.FAILED:
1054
+ raise DependencyFailedError(
1055
+ f"依赖任务 '{dep_id}' 执行失败,无法执行当前任务"
1056
+ )
1057
+
1058
+ if dep_task.status == TaskStatus.ABANDONED:
1059
+ raise DependencyFailedError(
1060
+ f"依赖任务 '{dep_id}' 已被放弃,无法执行当前任务"
1061
+ )
1062
+
1063
+ if dep_task.status == TaskStatus.PENDING:
1064
+ raise DependencyNotCompletedError(
1065
+ f"依赖任务 '{dep_id}' 尚未开始执行,无法执行当前任务"
1066
+ )
1067
+
1068
+ if dep_task.status == TaskStatus.RUNNING:
1069
+ raise DependencyNotCompletedError(
1070
+ f"依赖任务 '{dep_id}' 正在执行中,无法执行当前任务"
1071
+ )
1072
+
1073
+ if dep_task.status != TaskStatus.COMPLETED:
1074
+ raise DependencyNotCompletedError(
1075
+ f"依赖任务 '{dep_id}' 状态为 '{dep_task.status.value}',不满足执行条件"
1076
+ )
1077
+
1078
+ def _handle_execute_task(
1079
+ self,
1080
+ args: Dict,
1081
+ task_list_manager: Any,
1082
+ agent_id: str,
1083
+ is_main_agent: bool,
1084
+ parent_agent: Any,
1085
+ ) -> Dict[str, Any]:
1086
+ """处理执行任务(自动创建子 Agent 执行)
1087
+
1088
+ 重要提醒:执行一个任务前,系统会自动验证其所有依赖任务是否已完成(completed状态)。
1089
+ 如果有任何依赖任务未完成或失败,任务执行将被拒绝并返回相应的错误信息。"""
1090
+ task_list_id = self._get_task_list_id(parent_agent)
1091
+ if not task_list_id:
1092
+ return {
1093
+ "success": False,
1094
+ "stdout": "",
1095
+ "stderr": "Agent 还没有任务列表,请先使用 add_tasks 添加任务(会自动创建任务列表)",
1096
+ }
1097
+ task_id = args.get("task_id")
1098
+ additional_info = args.get("additional_info")
1099
+
1100
+ if not task_id:
1101
+ return {
1102
+ "success": False,
1103
+ "stdout": "",
1104
+ "stderr": "缺少 task_id 参数",
1105
+ }
1106
+
1107
+ if additional_info is None:
1108
+ return {
1109
+ "success": False,
1110
+ "stdout": "",
1111
+ "stderr": "缺少 additional_info 参数",
1112
+ }
1113
+
1114
+ if not additional_info or not str(additional_info).strip():
1115
+ return {
1116
+ "success": False,
1117
+ "stdout": "",
1118
+ "stderr": "additional_info 参数不能为空",
1119
+ }
1120
+
1121
+ # 获取任务详情
1122
+ task, success, error_msg = task_list_manager.get_task_detail(
1123
+ task_list_id=task_list_id,
1124
+ task_id=task_id,
1125
+ agent_id=agent_id,
1126
+ is_main_agent=is_main_agent,
1127
+ )
1128
+
1129
+ if not success or not task:
1130
+ return {
1131
+ "success": False,
1132
+ "stdout": "",
1133
+ "stderr": error_msg or "获取任务详情失败",
1134
+ }
1135
+
1136
+ # 验证依赖状态
1137
+ try:
1138
+ self._validate_dependencies_status(
1139
+ task_list_manager=task_list_manager,
1140
+ task_list_id=task_list_id,
1141
+ task=task,
1142
+ agent_id=agent_id,
1143
+ is_main_agent=is_main_agent,
1144
+ )
1145
+ except DependencyValidationError as e:
1146
+ return {
1147
+ "success": False,
1148
+ "stdout": "",
1149
+ "stderr": str(e),
1150
+ }
1151
+
1152
+ # 检查任务状态
1153
+ if task.status.value != "pending":
1154
+ return {
1155
+ "success": False,
1156
+ "stdout": "",
1157
+ "stderr": f"任务状态为 {task.status.value},无法执行(只有 pending 状态的任务可以执行)",
1158
+ }
1159
+
1160
+ # 更新任务状态为 running
1161
+ update_success, update_msg = task_list_manager.update_task_status(
1162
+ task_list_id=task_list_id,
1163
+ task_id=task_id,
1164
+ status="running",
1165
+ agent_id=agent_id,
1166
+ is_main_agent=is_main_agent,
1167
+ )
1168
+
1169
+ if not update_success:
1170
+ return {
1171
+ "success": False,
1172
+ "stdout": "",
1173
+ "stderr": f"更新任务状态失败: {update_msg}",
1174
+ }
1175
+
1176
+ try:
1177
+ # 合并任务描述和附加信息
1178
+ merged_description = task.task_desc
1179
+ if additional_info and str(additional_info).strip():
1180
+ # 使用清晰的分隔符合并原有描述和附加信息
1181
+ separator = "\n" + "=" * 50 + "\n"
1182
+ merged_description = (
1183
+ f"{task.task_desc}{separator}附加信息:\n{additional_info}"
1184
+ )
1185
+
1186
+ # 实际更新任务的desc字段,使打印时可见
1187
+ task.task_desc = merged_description
1188
+
1189
+ # 构建任务执行内容
1190
+ task_content = f"""任务名称: {task.task_name}
1191
+
1192
+ 任务描述:
1193
+ {merged_description}
1194
+
1195
+ 预期输出:
1196
+ {task.expected_output}"""
1197
+
1198
+ # 构建背景信息
1199
+ background_parts = []
1200
+
1201
+ # 获取额外的背景信息(如果提供)
1202
+ additional_background = args.get("additional_background")
1203
+ if additional_background:
1204
+ background_parts.append(f"额外背景信息: {additional_background}")
1205
+
1206
+ # 1. 获取任务列表的 main_goal 作为全局上下文
1207
+ task_list = task_list_manager.get_task_list(task_list_id)
1208
+ if task_list:
1209
+ background_parts.append(f"全局目标: {task_list.main_goal}")
1210
+
1211
+ # 2. 获取依赖任务的输出作为背景信息
1212
+ if task.dependencies:
1213
+ dep_outputs = []
1214
+ for dep_id in task.dependencies:
1215
+ dep_task, dep_success, _ = task_list_manager.get_task_detail(
1216
+ task_list_id=task_list_id,
1217
+ task_id=dep_id,
1218
+ agent_id=agent_id,
1219
+ is_main_agent=is_main_agent,
1220
+ )
1221
+ if dep_success and dep_task:
1222
+ if dep_task.actual_output:
1223
+ dep_outputs.append(
1224
+ f"依赖任务 [{dep_task.task_name}] 的输出:\n{dep_task.actual_output}"
1225
+ )
1226
+ elif dep_task.status == TaskStatus.COMPLETED:
1227
+ # 即使没有输出,也说明依赖任务已完成
1228
+ dep_outputs.append(
1229
+ f"依赖任务 [{dep_task.task_name}] 已完成(状态: {dep_task.status.value})"
1230
+ )
1231
+
1232
+ if dep_outputs:
1233
+ background_parts.append(
1234
+ "依赖任务信息:\n" + "\n\n".join(dep_outputs)
1235
+ )
1236
+
1237
+ # 3. 获取其他已完成任务的摘要信息(作为额外上下文,帮助理解整体进度)
1238
+ if task_list:
1239
+ completed_tasks = [
1240
+ t
1241
+ for t in task_list.tasks.values()
1242
+ if t.status == TaskStatus.COMPLETED
1243
+ and t.task_id != task_id
1244
+ and t.task_id not in (task.dependencies or [])
1245
+ ]
1246
+ if completed_tasks:
1247
+ # 只包含前3个已完成任务的简要信息,避免上下文过长
1248
+ completed_summary = []
1249
+ for completed_task in completed_tasks[:3]:
1250
+ summary = f"- [{completed_task.task_name}]: {completed_task.task_desc}"
1251
+ if completed_task.actual_output:
1252
+ # 只取输出的前200字符作为摘要
1253
+ output_preview = completed_task.actual_output[:200]
1254
+ if len(completed_task.actual_output) > 200:
1255
+ output_preview += "..."
1256
+ summary += f"\n 输出摘要: {output_preview}"
1257
+ completed_summary.append(summary)
1258
+
1259
+ if completed_summary:
1260
+ background_parts.append(
1261
+ "其他已完成任务(参考信息):\n"
1262
+ + "\n".join(completed_summary)
1263
+ )
1264
+
1265
+ background = "\n\n".join(background_parts) if background_parts else ""
1266
+
1267
+ # 根据 agent_type 创建相应的子 Agent 执行任务
1268
+ execution_result = None
1269
+ if task.agent_type.value == "main":
1270
+ # 主 Agent 执行:直接在当前 Agent 中执行(不创建子 Agent)
1271
+ # 注意:主 Agent 类型的任务需要主 Agent 自行执行,执行完成后需要手动调用 update_task_status 更新状态
1272
+ result = {
1273
+ "task_id": task_id,
1274
+ "task_name": task.task_name,
1275
+ "task_desc": task.task_desc,
1276
+ "expected_output": task.expected_output,
1277
+ "background": background,
1278
+ "message": "任务已标记为 running,请主 Agent 自行执行",
1279
+ "note": "主 Agent 类型的任务应由当前 Agent 直接执行,执行完成后请调用 update_task 更新任务状态为 completed 或 failed",
1280
+ "warning": "请务必在执行完成后更新任务状态,否则任务将一直保持 running 状态",
1281
+ }
1282
+ return {
1283
+ "success": True,
1284
+ "stdout": json.dumps(result, ensure_ascii=False, indent=2),
1285
+ "stderr": "",
1286
+ }
1287
+
1288
+ elif task.agent_type.value == "sub":
1289
+ # 子 Agent 执行:自动识别使用合适的子 Agent 工具
1290
+ # 执行后需要验证任务是否真正完成,如果未完成则继续迭代执行
1291
+ # 初始化变量,确保在 try-except 外部可以访问
1292
+ final_verification_passed = False
1293
+ execution_result = None
1294
+
1295
+ try:
1296
+ # 直接根据agent实例类型判断任务类型
1297
+ is_code_task = self._determine_agent_type(
1298
+ parent_agent, task, task_content, background
1299
+ )
1300
+
1301
+ # 迭代执行和验证,直到任务真正完成(无限迭代,直到验证通过)
1302
+ iteration = 0
1303
+ verification_passed = False
1304
+ all_execution_results = [] # 记录所有执行结果
1305
+ all_verification_results: List[str] = [] # 记录所有验证结果
1306
+
1307
+ while not verification_passed:
1308
+ iteration += 1
1309
+ from jarvis.jarvis_utils.output import PrettyOutput
1310
+
1311
+ PrettyOutput.auto_print(
1312
+ f"🔄 执行任务 [{task.task_name}] (第 {iteration} 次迭代)..."
1313
+ )
1314
+
1315
+ if is_code_task:
1316
+ # 代码相关任务:使用 sub_code_agent 工具
1317
+ from jarvis.jarvis_tools.sub_code_agent import (
1318
+ SubCodeAgentTool,
1319
+ )
1320
+
1321
+ sub_code_agent_tool = SubCodeAgentTool()
1322
+
1323
+ # 构建子Agent名称:使用任务名称和ID,便于识别
1324
+ agent_name = f"{task.task_name} (task_{task_id})"
1325
+
1326
+ # 如果是第二次及以后的迭代,添加验证反馈信息
1327
+ enhanced_task_content = task_content
1328
+ if iteration > 1 and all_verification_results:
1329
+ last_verification = all_verification_results[-1]
1330
+ enhanced_task_content = f"""{task_content}
1331
+
1332
+ **之前的验证反馈(需要修复的问题):**
1333
+ {last_verification}
1334
+
1335
+ 请根据以上验证反馈修复问题,确保任务真正完成。
1336
+ """
1337
+
1338
+ # 调用 sub_code_agent 执行任务
1339
+ tool_result = sub_code_agent_tool.execute(
1340
+ {
1341
+ "task": enhanced_task_content,
1342
+ "background": background,
1343
+ "name": agent_name,
1344
+ "agent": parent_agent,
1345
+ }
1346
+ )
1347
+ else:
1348
+ # 通用任务:使用 sub_agent 工具
1349
+ from jarvis.jarvis_tools.sub_agent import SubAgentTool
1350
+
1351
+ sub_general_agent_tool = SubAgentTool()
1352
+
1353
+ # 构建系统提示词和总结提示词
1354
+ system_prompt = f"""你是一个专业的任务执行助手。
1355
+
1356
+ 当前任务: {task.task_name}
1357
+
1358
+ 任务描述: {task.task_desc}
1359
+
1360
+ 预期输出: {task.expected_output}
1361
+
1362
+ 请专注于完成这个任务,完成后提供清晰的输出结果。
1363
+ """
1364
+ summary_prompt = f"总结任务 [{task.task_name}] 的执行结果,包括完成的工作和输出内容。"
1365
+
1366
+ # 构建子Agent名称:使用任务名称和ID,便于识别
1367
+ agent_name = f"{task.task_name} (task_{task_id})"
1368
+
1369
+ # 如果是第二次及以后的迭代,添加验证反馈信息
1370
+ enhanced_task_content = task_content
1371
+ if iteration > 1 and all_verification_results:
1372
+ last_verification = all_verification_results[-1]
1373
+ enhanced_task_content = f"""{task_content}
1374
+
1375
+ **之前的验证反馈(需要修复的问题):**
1376
+ {last_verification}
1377
+
1378
+ 请根据以上验证反馈修复问题,确保任务真正完成。
1379
+ """
1380
+
1381
+ # 调用 sub_agent 执行任务
1382
+ tool_result = sub_general_agent_tool.execute(
1383
+ {
1384
+ "task": enhanced_task_content,
1385
+ "background": background,
1386
+ "name": agent_name,
1387
+ "system_prompt": system_prompt,
1388
+ "summary_prompt": summary_prompt,
1389
+ "agent": parent_agent,
1390
+ }
1391
+ )
1392
+
1393
+ execution_result = tool_result.get("stdout", "")
1394
+ execution_success = tool_result.get("success", False)
1395
+
1396
+ if not execution_success:
1397
+ # 执行失败,更新任务状态为 failed
1398
+ task_list_manager.update_task_status(
1399
+ task_list_id=task_list_id,
1400
+ task_id=task_id,
1401
+ status="failed",
1402
+ agent_id=agent_id,
1403
+ is_main_agent=is_main_agent,
1404
+ actual_output=f"执行失败: {tool_result.get('stderr', '未知错误')}",
1405
+ )
1406
+ return {
1407
+ "success": False,
1408
+ "stdout": "",
1409
+ "stderr": f"子 Agent 执行失败: {tool_result.get('stderr', '未知错误')}",
1410
+ }
1411
+
1412
+ # 记录执行结果
1413
+ all_execution_results.append(execution_result)
1414
+
1415
+ # 验证任务是否真正完成
1416
+ verification_passed, verification_result = (
1417
+ self._verify_task_completion(
1418
+ task,
1419
+ task_content,
1420
+ background,
1421
+ parent_agent,
1422
+ verification_iteration=iteration,
1423
+ )
1424
+ )
1425
+
1426
+ # 记录验证结果
1427
+ all_verification_results.append(verification_result)
1428
+
1429
+ if not verification_passed:
1430
+ PrettyOutput.auto_print(
1431
+ f"⚠️ 任务 [{task.task_name}] 验证未通过,将继续迭代修复 (第 {iteration} 次迭代)"
1432
+ )
1433
+ else:
1434
+ PrettyOutput.auto_print(
1435
+ f"✅ 任务 [{task.task_name}] 验证通过,任务真正完成 (共执行 {iteration} 次迭代)"
1436
+ )
1437
+ final_verification_passed = True
1438
+
1439
+ # 保存最终验证状态(循环退出时 verification_passed 应该为 True)
1440
+ final_verification_passed = verification_passed
1441
+
1442
+ # 使用最后一次的执行结果
1443
+ execution_result = (
1444
+ all_execution_results[-1]
1445
+ if all_execution_results
1446
+ else "任务执行完成"
1447
+ )
1448
+ except Exception as e:
1449
+ # 执行异常,更新任务状态为 failed
1450
+ task_list_manager.update_task_status(
1451
+ task_list_id=task_list_id,
1452
+ task_id=task_id,
1453
+ status="failed",
1454
+ agent_id=agent_id,
1455
+ is_main_agent=is_main_agent,
1456
+ actual_output=f"执行异常: {str(e)}",
1457
+ )
1458
+ return {
1459
+ "success": False,
1460
+ "stdout": "",
1461
+ "stderr": f"创建子 Agent 执行任务失败: {str(e)}",
1462
+ }
1463
+
1464
+ # 确保 execution_result 有值
1465
+ if execution_result is None:
1466
+ execution_result = "任务执行完成"
1467
+
1468
+ # 处理执行结果:如果结果太长,进行截断并添加提示
1469
+ processed_result = execution_result or "任务执行完成"
1470
+
1471
+ # 基于剩余token动态计算最大输出长度
1472
+ max_output_length = self._get_max_output_length(parent_agent)
1473
+
1474
+ if len(processed_result) > max_output_length:
1475
+ # 根据最大长度计算截断时的前缀和后缀长度
1476
+ prefix_length, suffix_length = self._get_truncate_lengths(
1477
+ max_output_length
1478
+ )
1479
+
1480
+ # 保留前缀和后缀,中间用省略号连接
1481
+ truncated_result = (
1482
+ processed_result[:prefix_length]
1483
+ + "\n\n... [输出内容过长,已截断中间部分] ...\n\n"
1484
+ + processed_result[-suffix_length:]
1485
+ )
1486
+ processed_result = truncated_result
1487
+ execution_result_len = (
1488
+ len(execution_result) if execution_result is not None else 0
1489
+ )
1490
+ PrettyOutput.auto_print(
1491
+ f"⚠️ 任务 {task_id} 的执行结果过长({execution_result_len} 字符),"
1492
+ f"已截断为 {len(truncated_result)} 字符(基于剩余token限制:{max_output_length} 字符)"
1493
+ )
1494
+
1495
+ # 对于 sub agent 类型的任务,只有在验证通过后才更新为 completed
1496
+ # 如果验证未通过但达到最大迭代次数,标记为 failed
1497
+ if task.agent_type.value == "sub":
1498
+ # 检查最终验证状态
1499
+ if final_verification_passed:
1500
+ # 验证通过,更新任务状态为 completed
1501
+ task_list_manager.update_task_status(
1502
+ task_list_id=task_list_id,
1503
+ task_id=task_id,
1504
+ status="completed",
1505
+ agent_id=agent_id,
1506
+ is_main_agent=is_main_agent,
1507
+ actual_output=processed_result,
1508
+ )
1509
+ else:
1510
+ # 验证未通过,标记为 failed
1511
+ task_list_manager.update_task_status(
1512
+ task_list_id=task_list_id,
1513
+ task_id=task_id,
1514
+ status="failed",
1515
+ agent_id=agent_id,
1516
+ is_main_agent=is_main_agent,
1517
+ actual_output=processed_result,
1518
+ )
1519
+ else:
1520
+ # 对于 main agent 类型的任务,直接更新为 completed(由主 Agent 自行管理状态)
1521
+ # 这里不更新状态,由主 Agent 自行调用 update_task 更新
1522
+ pass
1523
+
1524
+ # 构建格式化的任务完成通知
1525
+ import datetime
1526
+
1527
+ # 获取当前时间作为完成时间
1528
+ completion_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
1529
+
1530
+ # 预览长度:基于最大输出长度的50%
1531
+ preview_length = int(max_output_length * 0.5)
1532
+
1533
+ # 创建格式化的完成通知
1534
+ formatted_notification = f"""
1535
+ ✅ **任务完成通知**
1536
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1537
+
1538
+ 🎯 **任务信息**
1539
+ 任务ID: {task_id}
1540
+ 任务名称: {task.task_name}
1541
+ 优先级: {task.priority}/5
1542
+ 完成时间: {completion_time}
1543
+
1544
+ 📊 **执行结果**
1545
+ 状态: ✅ 已完成
1546
+ 输出长度: {len(processed_result)} 字符
1547
+
1548
+ 📝 **执行摘要**
1549
+ {processed_result[:preview_length]}{"..." if len(processed_result) > preview_length else ""}
1550
+
1551
+ 📋 **后续操作**
1552
+ • 完整结果已保存到任务的 actual_output 字段
1553
+ • 可通过 get_task_detail 获取完整详情
1554
+ • 依赖此任务的其他任务现在可以开始执行
1555
+
1556
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1557
+ 任务 [{task.task_name}] 已成功完成!
1558
+ """
1559
+
1560
+ # 直接返回格式化的任务完成通知
1561
+ return {
1562
+ "success": True,
1563
+ "stdout": formatted_notification.strip(),
1564
+ "stderr": "",
1565
+ }
1566
+
1567
+ except Exception as e:
1568
+ # 发生异常,更新任务状态为 failed
1569
+ try:
1570
+ task_list_manager.update_task_status(
1571
+ task_list_id=task_list_id,
1572
+ task_id=task_id,
1573
+ status="failed",
1574
+ agent_id=agent_id,
1575
+ is_main_agent=is_main_agent,
1576
+ actual_output=f"执行异常: {str(e)}",
1577
+ )
1578
+ except Exception:
1579
+ pass
1580
+
1581
+ return {
1582
+ "success": False,
1583
+ "stdout": "",
1584
+ "stderr": f"执行任务失败: {str(e)}",
1585
+ }
1586
+
1587
+ def _check_dependencies_completed(
1588
+ self,
1589
+ task_list_manager: Any,
1590
+ task_list_id: str,
1591
+ dependencies: List[str],
1592
+ agent_id: str,
1593
+ is_main_agent: bool,
1594
+ ) -> Dict[str, Any]:
1595
+ """验证依赖任务状态。
1596
+
1597
+ 参数:
1598
+ task_list_manager: 任务列表管理器
1599
+ task_list_id: 任务列表 ID
1600
+ dependencies: 依赖任务 ID 列表
1601
+ agent_id: Agent ID
1602
+ is_main_agent: 是否为主 Agent
1603
+
1604
+ 返回:
1605
+ Dict: 验证结果,包含 success 状态和错误信息
1606
+ """
1607
+ if not dependencies:
1608
+ return {"success": True, "stdout": "", "stderr": ""}
1609
+
1610
+ incomplete_deps = []
1611
+ failed_deps = []
1612
+ not_found_deps = []
1613
+
1614
+ for dep_id in dependencies:
1615
+ dep_task, dep_success, error_msg = task_list_manager.get_task_detail(
1616
+ task_list_id=task_list_id,
1617
+ task_id=dep_id,
1618
+ agent_id=agent_id,
1619
+ is_main_agent=is_main_agent,
1620
+ )
1621
+
1622
+ if not dep_success or not dep_task:
1623
+ not_found_deps.append(dep_id)
1624
+ continue
1625
+
1626
+ if dep_task.status == TaskStatus.COMPLETED:
1627
+ continue # 依赖已完成,继续检查下一个
1628
+ elif dep_task.status in (TaskStatus.FAILED, TaskStatus.ABANDONED):
1629
+ failed_deps.append((dep_id, dep_task.task_name, dep_task.status.value))
1630
+ else: # PENDING 或 RUNNING
1631
+ incomplete_deps.append(
1632
+ (dep_id, dep_task.task_name, dep_task.status.value)
1633
+ )
1634
+
1635
+ # 构建错误信息
1636
+ error_messages = []
1637
+
1638
+ if not_found_deps:
1639
+ error_messages.append(f"依赖任务不存在: {', '.join(not_found_deps)}")
1640
+
1641
+ if failed_deps:
1642
+ for dep_id, task_name, status in failed_deps:
1643
+ error_messages.append(
1644
+ f"依赖任务 [{task_name}] 状态为 {status},无法执行"
1645
+ )
1646
+
1647
+ if incomplete_deps:
1648
+ for dep_id, task_name, status in incomplete_deps:
1649
+ error_messages.append(
1650
+ f"依赖任务 [{task_name}] 状态为 {status},需要为 completed"
1651
+ )
1652
+
1653
+ if error_messages:
1654
+ return {
1655
+ "success": False,
1656
+ "stdout": "",
1657
+ "stderr": "任务执行失败:依赖验证未通过\n"
1658
+ + "\n".join(f"- {msg}" for msg in error_messages),
1659
+ }
1660
+
1661
+ return {"success": True, "stdout": "", "stderr": ""}
1662
+
1663
+ def _handle_update_task(
1664
+ self,
1665
+ args: Dict,
1666
+ task_list_manager: Any,
1667
+ agent_id: str,
1668
+ is_main_agent: bool,
1669
+ agent: Any,
1670
+ ) -> Dict[str, Any]:
1671
+ """处理更新任务属性"""
1672
+ task_list_id = self._get_task_list_id(agent)
1673
+ if not task_list_id:
1674
+ return {
1675
+ "success": False,
1676
+ "stdout": "",
1677
+ "stderr": "Agent 还没有任务列表,请先使用 add_tasks 添加任务(会自动创建任务列表)",
1678
+ }
1679
+ task_id = args.get("task_id")
1680
+ task_update_info = args.get("task_update_info", {})
1681
+
1682
+ if not task_id:
1683
+ return {
1684
+ "success": False,
1685
+ "stdout": "",
1686
+ "stderr": "缺少 task_id 参数",
1687
+ }
1688
+
1689
+ if not task_update_info:
1690
+ return {
1691
+ "success": False,
1692
+ "stdout": "",
1693
+ "stderr": "缺少 task_update_info 参数",
1694
+ }
1695
+
1696
+ try:
1697
+ # 权限检查
1698
+ if not task_list_manager._check_agent_permission(
1699
+ agent_id, task_id, is_main_agent
1700
+ ):
1701
+ return {
1702
+ "success": False,
1703
+ "stdout": "",
1704
+ "stderr": "权限不足:无法访问该任务",
1705
+ }
1706
+
1707
+ # 获取任务列表
1708
+ task_list = task_list_manager.get_task_list(task_list_id)
1709
+ if not task_list:
1710
+ return {
1711
+ "success": False,
1712
+ "stdout": "",
1713
+ "stderr": "任务列表不存在",
1714
+ }
1715
+
1716
+ # 获取任务
1717
+ task = task_list.get_task(task_id)
1718
+ if not task:
1719
+ return {
1720
+ "success": False,
1721
+ "stdout": "",
1722
+ "stderr": "任务不存在",
1723
+ }
1724
+
1725
+ # 验证并更新任务属性
1726
+ update_kwargs = {}
1727
+
1728
+ if "task_name" in task_update_info:
1729
+ new_name = task_update_info["task_name"]
1730
+ update_kwargs["task_name"] = new_name
1731
+
1732
+ if "task_desc" in task_update_info:
1733
+ new_desc = task_update_info["task_desc"]
1734
+ update_kwargs["task_desc"] = new_desc
1735
+
1736
+ if "priority" in task_update_info:
1737
+ new_priority = task_update_info["priority"]
1738
+ if not (1 <= new_priority <= 5):
1739
+ return {
1740
+ "success": False,
1741
+ "stdout": "",
1742
+ "stderr": "priority 必须在 1-5 之间",
1743
+ }
1744
+ update_kwargs["priority"] = new_priority
1745
+
1746
+ if "expected_output" in task_update_info:
1747
+ update_kwargs["expected_output"] = task_update_info["expected_output"]
1748
+
1749
+ if "dependencies" in task_update_info:
1750
+ # 验证依赖关系
1751
+ new_deps = task_update_info["dependencies"]
1752
+ for dep_id in new_deps:
1753
+ if dep_id not in task_list.tasks:
1754
+ return {
1755
+ "success": False,
1756
+ "stdout": "",
1757
+ "stderr": f"依赖任务 {dep_id} 不存在",
1758
+ }
1759
+ update_kwargs["dependencies"] = new_deps
1760
+
1761
+ # 处理状态更新(如果提供)
1762
+ status = task_update_info.get("status")
1763
+ actual_output = task_update_info.get("actual_output")
1764
+
1765
+ if status is not None:
1766
+ # 使用 update_task_status 方法更新状态
1767
+ status_success, status_msg = task_list_manager.update_task_status(
1768
+ task_list_id=task_list_id,
1769
+ task_id=task_id,
1770
+ status=status,
1771
+ agent_id=agent_id,
1772
+ is_main_agent=is_main_agent,
1773
+ actual_output=actual_output,
1774
+ )
1775
+ if not status_success:
1776
+ return {
1777
+ "success": False,
1778
+ "stdout": "",
1779
+ "stderr": f"更新任务状态失败: {status_msg}",
1780
+ }
1781
+
1782
+ # 执行其他属性更新(如果有)
1783
+ if update_kwargs:
1784
+ if not task_list.update_task(task_id, **update_kwargs):
1785
+ return {
1786
+ "success": False,
1787
+ "stdout": "",
1788
+ "stderr": "更新任务属性失败",
1789
+ }
1790
+
1791
+ # 保存快照
1792
+ task_list_manager._save_snapshot(task_list_id, task_list)
1793
+
1794
+ # 获取更新后的任务信息
1795
+ updated_task = task_list.get_task(task_id)
1796
+ result = {
1797
+ "task_id": task_id,
1798
+ "task": updated_task.to_dict() if updated_task else None,
1799
+ "message": "任务更新成功",
1800
+ }
1801
+ return {
1802
+ "success": True,
1803
+ "stdout": json.dumps(result, ensure_ascii=False, indent=2),
1804
+ "stderr": "",
1805
+ }
1806
+ except Exception as e:
1807
+ return {
1808
+ "success": False,
1809
+ "stdout": "",
1810
+ "stderr": f"更新任务失败: {str(e)}",
1811
+ }