jarvis-ai-assistant 0.3.30__py3-none-any.whl → 0.7.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +458 -152
  3. jarvis/jarvis_agent/agent_manager.py +17 -13
  4. jarvis/jarvis_agent/builtin_input_handler.py +2 -6
  5. jarvis/jarvis_agent/config_editor.py +2 -7
  6. jarvis/jarvis_agent/event_bus.py +82 -12
  7. jarvis/jarvis_agent/file_context_handler.py +329 -0
  8. jarvis/jarvis_agent/file_methodology_manager.py +3 -4
  9. jarvis/jarvis_agent/jarvis.py +628 -55
  10. jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
  11. jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
  12. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
  13. jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
  14. jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
  15. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
  16. jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
  17. jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
  18. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
  19. jarvis/jarvis_agent/language_support_info.py +486 -0
  20. jarvis/jarvis_agent/main.py +34 -10
  21. jarvis/jarvis_agent/memory_manager.py +7 -16
  22. jarvis/jarvis_agent/methodology_share_manager.py +10 -16
  23. jarvis/jarvis_agent/prompt_manager.py +1 -1
  24. jarvis/jarvis_agent/prompts.py +193 -171
  25. jarvis/jarvis_agent/protocols.py +8 -12
  26. jarvis/jarvis_agent/run_loop.py +105 -9
  27. jarvis/jarvis_agent/session_manager.py +2 -3
  28. jarvis/jarvis_agent/share_manager.py +20 -22
  29. jarvis/jarvis_agent/shell_input_handler.py +1 -2
  30. jarvis/jarvis_agent/stdio_redirect.py +295 -0
  31. jarvis/jarvis_agent/task_analyzer.py +31 -6
  32. jarvis/jarvis_agent/task_manager.py +11 -27
  33. jarvis/jarvis_agent/tool_executor.py +2 -3
  34. jarvis/jarvis_agent/tool_share_manager.py +12 -24
  35. jarvis/jarvis_agent/utils.py +5 -1
  36. jarvis/jarvis_agent/web_bridge.py +189 -0
  37. jarvis/jarvis_agent/web_output_sink.py +53 -0
  38. jarvis/jarvis_agent/web_server.py +786 -0
  39. jarvis/jarvis_c2rust/__init__.py +26 -0
  40. jarvis/jarvis_c2rust/cli.py +575 -0
  41. jarvis/jarvis_c2rust/collector.py +250 -0
  42. jarvis/jarvis_c2rust/constants.py +26 -0
  43. jarvis/jarvis_c2rust/library_replacer.py +1254 -0
  44. jarvis/jarvis_c2rust/llm_module_agent.py +1272 -0
  45. jarvis/jarvis_c2rust/loaders.py +207 -0
  46. jarvis/jarvis_c2rust/models.py +28 -0
  47. jarvis/jarvis_c2rust/optimizer.py +2157 -0
  48. jarvis/jarvis_c2rust/scanner.py +1681 -0
  49. jarvis/jarvis_c2rust/transpiler.py +2983 -0
  50. jarvis/jarvis_c2rust/utils.py +385 -0
  51. jarvis/jarvis_code_agent/build_validation_config.py +132 -0
  52. jarvis/jarvis_code_agent/code_agent.py +1371 -220
  53. jarvis/jarvis_code_agent/code_analyzer/__init__.py +65 -0
  54. jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +106 -0
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +74 -0
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +72 -0
  60. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +70 -0
  61. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +53 -0
  62. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +47 -0
  63. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +61 -0
  64. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +110 -0
  65. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +154 -0
  66. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +110 -0
  67. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +153 -0
  68. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
  69. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +648 -0
  70. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
  71. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
  72. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
  73. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
  74. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
  75. jarvis/jarvis_code_agent/code_analyzer/language_support.py +110 -0
  76. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +49 -0
  77. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +299 -0
  78. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +215 -0
  79. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
  80. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
  81. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +269 -0
  82. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +281 -0
  83. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
  84. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +605 -0
  85. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
  86. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +252 -0
  87. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +58 -0
  88. jarvis/jarvis_code_agent/lint.py +501 -8
  89. jarvis/jarvis_code_agent/utils.py +141 -0
  90. jarvis/jarvis_code_analysis/code_review.py +493 -584
  91. jarvis/jarvis_data/config_schema.json +128 -12
  92. jarvis/jarvis_git_squash/main.py +4 -5
  93. jarvis/jarvis_git_utils/git_commiter.py +82 -75
  94. jarvis/jarvis_mcp/sse_mcp_client.py +22 -29
  95. jarvis/jarvis_mcp/stdio_mcp_client.py +12 -13
  96. jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
  97. jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
  98. jarvis/jarvis_methodology/main.py +32 -48
  99. jarvis/jarvis_multi_agent/__init__.py +287 -55
  100. jarvis/jarvis_multi_agent/main.py +36 -4
  101. jarvis/jarvis_platform/base.py +524 -202
  102. jarvis/jarvis_platform/human.py +7 -8
  103. jarvis/jarvis_platform/kimi.py +30 -36
  104. jarvis/jarvis_platform/openai.py +88 -25
  105. jarvis/jarvis_platform/registry.py +26 -10
  106. jarvis/jarvis_platform/tongyi.py +24 -25
  107. jarvis/jarvis_platform/yuanbao.py +32 -43
  108. jarvis/jarvis_platform_manager/main.py +66 -77
  109. jarvis/jarvis_platform_manager/service.py +8 -13
  110. jarvis/jarvis_rag/cli.py +53 -55
  111. jarvis/jarvis_rag/embedding_manager.py +13 -18
  112. jarvis/jarvis_rag/llm_interface.py +8 -9
  113. jarvis/jarvis_rag/query_rewriter.py +10 -21
  114. jarvis/jarvis_rag/rag_pipeline.py +24 -27
  115. jarvis/jarvis_rag/reranker.py +4 -5
  116. jarvis/jarvis_rag/retriever.py +28 -30
  117. jarvis/jarvis_sec/__init__.py +305 -0
  118. jarvis/jarvis_sec/agents.py +143 -0
  119. jarvis/jarvis_sec/analysis.py +276 -0
  120. jarvis/jarvis_sec/checkers/__init__.py +32 -0
  121. jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
  122. jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
  123. jarvis/jarvis_sec/cli.py +139 -0
  124. jarvis/jarvis_sec/clustering.py +1439 -0
  125. jarvis/jarvis_sec/file_manager.py +427 -0
  126. jarvis/jarvis_sec/parsers.py +73 -0
  127. jarvis/jarvis_sec/prompts.py +268 -0
  128. jarvis/jarvis_sec/report.py +336 -0
  129. jarvis/jarvis_sec/review.py +453 -0
  130. jarvis/jarvis_sec/status.py +264 -0
  131. jarvis/jarvis_sec/types.py +20 -0
  132. jarvis/jarvis_sec/utils.py +499 -0
  133. jarvis/jarvis_sec/verification.py +848 -0
  134. jarvis/jarvis_sec/workflow.py +226 -0
  135. jarvis/jarvis_smart_shell/main.py +38 -87
  136. jarvis/jarvis_stats/cli.py +2 -2
  137. jarvis/jarvis_stats/stats.py +8 -8
  138. jarvis/jarvis_stats/storage.py +15 -21
  139. jarvis/jarvis_stats/visualizer.py +1 -1
  140. jarvis/jarvis_tools/clear_memory.py +3 -20
  141. jarvis/jarvis_tools/cli/main.py +21 -23
  142. jarvis/jarvis_tools/edit_file.py +1019 -132
  143. jarvis/jarvis_tools/execute_script.py +83 -25
  144. jarvis/jarvis_tools/file_analyzer.py +6 -9
  145. jarvis/jarvis_tools/generate_new_tool.py +14 -21
  146. jarvis/jarvis_tools/lsp_client.py +1552 -0
  147. jarvis/jarvis_tools/methodology.py +2 -3
  148. jarvis/jarvis_tools/read_code.py +1736 -35
  149. jarvis/jarvis_tools/read_symbols.py +140 -0
  150. jarvis/jarvis_tools/read_webpage.py +12 -13
  151. jarvis/jarvis_tools/registry.py +427 -200
  152. jarvis/jarvis_tools/retrieve_memory.py +20 -19
  153. jarvis/jarvis_tools/rewrite_file.py +72 -158
  154. jarvis/jarvis_tools/save_memory.py +3 -15
  155. jarvis/jarvis_tools/search_web.py +18 -18
  156. jarvis/jarvis_tools/sub_agent.py +36 -43
  157. jarvis/jarvis_tools/sub_code_agent.py +25 -26
  158. jarvis/jarvis_tools/virtual_tty.py +55 -33
  159. jarvis/jarvis_utils/clipboard.py +7 -10
  160. jarvis/jarvis_utils/config.py +232 -45
  161. jarvis/jarvis_utils/embedding.py +8 -5
  162. jarvis/jarvis_utils/fzf.py +8 -8
  163. jarvis/jarvis_utils/git_utils.py +225 -36
  164. jarvis/jarvis_utils/globals.py +3 -3
  165. jarvis/jarvis_utils/http.py +1 -1
  166. jarvis/jarvis_utils/input.py +99 -48
  167. jarvis/jarvis_utils/jsonnet_compat.py +465 -0
  168. jarvis/jarvis_utils/methodology.py +52 -48
  169. jarvis/jarvis_utils/utils.py +819 -491
  170. jarvis_ai_assistant-0.7.6.dist-info/METADATA +600 -0
  171. jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
  172. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +4 -0
  173. jarvis/jarvis_agent/config.py +0 -92
  174. jarvis/jarvis_agent/edit_file_handler.py +0 -296
  175. jarvis/jarvis_platform/ai8.py +0 -332
  176. jarvis/jarvis_tools/ask_user.py +0 -54
  177. jarvis_ai_assistant-0.3.30.dist-info/METADATA +0 -381
  178. jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
  179. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
  180. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
  181. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,6 @@ from pathlib import Path
4
4
  from typing import Any, Dict, List, Optional
5
5
 
6
6
  from jarvis.jarvis_utils.config import get_data_dir, get_max_input_token_count
7
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
8
7
  from jarvis.jarvis_utils.globals import get_short_term_memories
9
8
  from jarvis.jarvis_utils.embedding import get_context_token_count
10
9
 
@@ -13,17 +12,7 @@ class RetrieveMemoryTool:
13
12
  """检索记忆工具,用于从长短期记忆系统中检索信息"""
14
13
 
15
14
  name = "retrieve_memory"
16
- description = """从长短期记忆系统中检索信息。
17
-
18
- 支持的记忆类型:
19
- - project_long_term: 项目长期记忆(与当前项目相关的信息)
20
- - global_long_term: 全局长期记忆(通用的信息、用户喜好、知识、方法等)
21
- - short_term: 短期记忆(当前任务相关的信息)
22
- - all: 从所有类型中检索
23
-
24
- 可以通过标签过滤检索结果,支持多个标签(满足任一标签即可)
25
- 注意:标签数量建议不要超过10个,以保证检索效率
26
- """
15
+ description = "从长短期记忆系统中检索信息。支持按类型(project_long_term/global_long_term/short_term/all)和标签过滤,标签建议不超过10个。"
27
16
 
28
17
  parameters = {
29
18
  "type": "object",
@@ -99,9 +88,7 @@ class RetrieveMemoryTool:
99
88
 
100
89
  memories.append(memory_data)
101
90
  except Exception as e:
102
- PrettyOutput.print(
103
- f"读取记忆文件 {memory_file} 失败: {str(e)}", OutputType.WARNING
104
- )
91
+ print(f"⚠️ 读取记忆文件 {memory_file} 失败: {str(e)}")
105
92
 
106
93
  return memories
107
94
 
@@ -131,9 +118,23 @@ class RetrieveMemoryTool:
131
118
  # 按创建时间排序(最新的在前)
132
119
  all_memories.sort(key=lambda x: x.get("created_at", ""), reverse=True)
133
120
 
134
- # 获取最大输入token数的2/3作为记忆的token限制
135
- max_input_tokens = get_max_input_token_count()
136
- memory_token_limit = int(max_input_tokens * 2 / 3)
121
+ # 优先使用剩余token数量,回退到输入窗口限制
122
+ memory_token_limit = None
123
+ agent = args.get("agent")
124
+ if agent and hasattr(agent, "model"):
125
+ try:
126
+ remaining_tokens = agent.model.get_remaining_token_count()
127
+ # 使用剩余token的2/3作为限制,保留1/3作为安全余量
128
+ memory_token_limit = int(remaining_tokens * 2 / 3)
129
+ if memory_token_limit <= 0:
130
+ memory_token_limit = None
131
+ except Exception:
132
+ pass
133
+
134
+ # 回退方案:使用输入窗口的2/3
135
+ if memory_token_limit is None:
136
+ max_input_tokens = get_max_input_token_count()
137
+ memory_token_limit = int(max_input_tokens * 2 / 3)
137
138
 
138
139
  # 基于token限制和条数限制筛选记忆
139
140
  filtered_memories: List[Dict[str, Any]] = []
@@ -223,5 +224,5 @@ class RetrieveMemoryTool:
223
224
 
224
225
  except Exception as e:
225
226
  error_msg = f"检索记忆失败: {str(e)}"
226
- PrettyOutput.print(error_msg, OutputType.ERROR)
227
+ print(f"❌ {error_msg}")
227
228
  return {"success": False, "stdout": "", "stderr": error_msg}
@@ -1,191 +1,105 @@
1
1
  # -*- coding: utf-8 -*-
2
- """
3
- 文件重写工具类
4
-
5
- 功能概述:
6
- 1. 提供完整的文件重写功能
7
- 2. 支持创建新文件或完全重写现有文件
8
- 3. 实现原子操作:所有修改要么全部成功,要么全部回滚
9
- 4. 自动创建所需目录结构
10
-
11
- 核心特性:
12
- - 支持不存在的文件和空文件处理
13
- - 自动创建所需目录结构
14
- - 完善的错误处理和回滚机制
15
- - 保持文件格式和编码
16
- """
2
+ import os
17
3
  from typing import Any, Dict
18
4
 
19
5
 
20
- class FileRewriteTool:
6
+
7
+ class RewriteFileTool:
8
+ """文件重写工具,用于完全重写文件内容"""
9
+
21
10
  name = "rewrite_file"
22
- description = """文件重写工具,用于完全重写或创建文件
23
-
24
- # 文件重写规范
25
-
26
- ## 重要提示
27
- 此工具用于完全重写文件内容或创建新文件。与edit_file不同,此工具会替换文件的全部内容。
28
-
29
- ## 基本使用
30
- 1. 指定需要重写的文件路径
31
- 2. 提供新的文件内容
32
- 3. 所有操作要么全部成功,要么全部失败并回滚
33
-
34
- ## 核心原则
35
- 1. **完整重写**:提供完整的文件内容,将替换原文件的所有内容
36
- 2. **格式保持**:
37
- - 保持原始代码的缩进方式(空格或制表符)
38
- - 保持原始代码的空行数量和位置
39
- - 保持原始代码的行尾空格处理方式
40
- - 不改变原始代码的换行风格
41
-
42
- ## 最佳实践
43
- 1. 确保提供格式良好的完整文件内容
44
- 2. 创建新文件时提供完整、格式良好的内容
45
- 3. 不要出现未实现的代码,如:TODO
46
- """
11
+ description = "完全重写文件内容,适用于新增文件或大范围改写。具备失败回滚能力。局部修改请使用 edit_file。\n\n ⚠️ 重要提示:\n - 不要一次重写太多内容,建议分多次进行,避免超过LLM的上下文窗口大小\n - 如果文件内容较长(超过2048字符),建议采用以下策略:\n 1. 第一次调用 rewrite_file 写入部分内容(如文件的前半部分或关键部分)\n 2. 然后多次调用 edit_file 工具,使用 insert_after 操作补充后续内容\n - 这样可以避免单次操作内容过长导致上下文溢出"
12
+
47
13
  parameters = {
48
14
  "type": "object",
49
15
  "properties": {
50
- "file": {"type": "string", "description": "需要重写的文件路径"},
16
+ "file_path": {
17
+ "type": "string",
18
+ "description": "要重写的文件路径(支持绝对路径和相对路径)",
19
+ },
51
20
  "content": {
52
21
  "type": "string",
53
- "description": "新的文件内容,将完全替换原文件内容",
22
+ "description": "新的文件完整内容",
54
23
  },
55
24
  },
56
- "required": ["file", "content"],
25
+ "required": ["file_path", "content"],
57
26
  }
58
27
 
59
28
  def __init__(self):
60
29
  """初始化文件重写工具"""
61
30
  pass
62
31
 
63
- def execute(self, args: Dict) -> Dict[str, Any]:
64
- """
65
- 执行文件重写操作,完全替换文件内容
66
-
67
- 参数:
68
- file (str): 文件路径
69
- content (str): 新的文件内容
70
-
71
- 返回:
72
- dict: 包含执行结果的字典
73
- {
74
- "success": bool, # 是否成功完成重写
75
- "stdout": str, # 标准输出信息
76
- "stderr": str # 错误信息
77
- }
78
- """
79
- import os
80
-
81
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
82
-
83
- stdout_messages = []
84
- stderr_messages = []
85
- success = True
86
-
87
- file_path = args["file"]
88
- new_content = args["content"]
89
- agent = args.get("agent", None)
90
- abs_path = os.path.abspath(file_path)
91
-
92
- # 创建已处理文件变量,用于失败时回滚
93
- original_content = None
94
- processed = False
95
-
32
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
33
+ """执行文件重写操作"""
96
34
  try:
97
- file_exists = os.path.exists(file_path)
35
+ file_path = args.get("file_path")
36
+ content = args.get("content")
37
+
38
+ if not file_path:
39
+ return {
40
+ "success": False,
41
+ "stdout": "",
42
+ "stderr": "缺少必需参数:file_path",
43
+ }
44
+
45
+ if content is None:
46
+ return {
47
+ "success": False,
48
+ "stdout": "",
49
+ "stderr": "缺少必需参数:content",
50
+ }
51
+
52
+ abs_path = os.path.abspath(file_path)
53
+ original_content = None
54
+ processed = False
98
55
 
99
56
  try:
100
- # 如果文件存在,则读取原内容用于回滚
57
+ file_exists = os.path.exists(abs_path)
101
58
  if file_exists:
102
- with open(abs_path, "r", encoding="utf-8") as f:
103
- original_content = f.read()
59
+ with open(abs_path, "r", encoding="utf-8") as rf:
60
+ original_content = rf.read()
104
61
 
105
- # 确保目录存在
106
62
  os.makedirs(os.path.dirname(abs_path), exist_ok=True)
107
-
108
- # 写入新内容
109
- with open(abs_path, "w", encoding="utf-8") as f:
110
- f.write(new_content)
111
-
63
+ with open(abs_path, "w", encoding="utf-8") as wf:
64
+ wf.write(content)
112
65
  processed = True
113
66
 
114
- action = "创建并写入" if not file_exists else "成功重写"
115
- stdout_message = f"文件 {abs_path} {action}"
116
- stdout_messages.append(stdout_message)
67
+ # 记录 REWRITE 操作调用统计
68
+ try:
69
+ from jarvis.jarvis_stats.stats import StatsManager
117
70
 
118
- except Exception as e:
119
- stderr_message = f"处理文件 {file_path} 时出错: {str(e)}"
120
- stderr_messages.append(stderr_message)
121
- PrettyOutput.print(stderr_message, OutputType.WARNING)
122
- success = False
71
+ StatsManager.increment("rewrite_file", group="tool")
72
+ except Exception:
73
+ pass
123
74
 
124
- # 如果操作失败,回滚已修改的文件
125
- if not success and processed:
126
- rollback_message = "操作失败,正在回滚修改..."
127
- stderr_messages.append(rollback_message)
75
+ return {
76
+ "success": True,
77
+ "stdout": f"文件 {abs_path} 重写成功",
78
+ "stderr": "",
79
+ }
128
80
 
81
+ except Exception as e:
82
+ # 回滚已修改内容
129
83
  try:
130
- if original_content is None:
131
- # 如果是新创建的文件,则删除
132
- if os.path.exists(abs_path):
133
- os.remove(abs_path)
134
- rollback_file_message = f"已删除新创建的文件: {abs_path}"
135
- else:
136
- # 如果是修改的文件,则恢复原内容
137
- with open(abs_path, "w", encoding="utf-8") as f:
138
- f.write(original_content)
139
- rollback_file_message = f"已回滚文件: {abs_path}"
140
-
141
- stderr_messages.append(rollback_file_message)
142
- except Exception as e:
143
- rollback_error = f"回滚文件 {file_path} 失败: {str(e)}"
144
- stderr_messages.append(rollback_error)
145
- PrettyOutput.print(rollback_error, OutputType.WARNING)
146
-
147
- # 记录成功处理的文件(使用绝对路径)
148
- if success and agent:
149
- abs_path = os.path.abspath(file_path)
150
- files = agent.get_user_data("files")
151
- if files:
152
- if abs_path not in files:
153
- files.append(abs_path)
154
- else:
155
- files = [abs_path]
156
- agent.set_user_data("files", files)
157
-
158
- return {
159
- "success": success,
160
- "stdout": "\n".join(stdout_messages),
161
- "stderr": "\n".join(stderr_messages),
162
- }
84
+ if processed:
85
+ if original_content is None:
86
+ if os.path.exists(abs_path):
87
+ os.remove(abs_path)
88
+ else:
89
+ with open(abs_path, "w", encoding="utf-8") as wf:
90
+ wf.write(original_content)
91
+ except Exception:
92
+ pass
93
+ error_msg = f"文件重写失败: {str(e)}"
94
+ print(f"❌ {error_msg}")
95
+ return {
96
+ "success": False,
97
+ "stdout": "",
98
+ "stderr": error_msg,
99
+ }
163
100
 
164
101
  except Exception as e:
165
- error_msg = f"文件重写操作失败: {str(e)}"
166
- PrettyOutput.print(error_msg, OutputType.WARNING)
102
+ error_msg = f"文件重写失败: {str(e)}"
103
+ print(f"❌ {error_msg}")
104
+ return {"success": False, "stdout": "", "stderr": error_msg}
167
105
 
168
- # 如果有已修改的文件,尝试回滚
169
- if processed:
170
- rollback_message = "操作失败,正在回滚修改..."
171
- stderr_messages.append(rollback_message)
172
-
173
- try:
174
- if original_content is None:
175
- # 如果是新创建的文件,则删除
176
- if os.path.exists(file_path):
177
- os.remove(file_path)
178
- stderr_messages.append(f"已删除新创建的文件: {file_path}")
179
- else:
180
- # 如果是修改的文件,则恢复原内容
181
- with open(file_path, "w", encoding="utf-8") as f:
182
- f.write(original_content)
183
- stderr_messages.append(f"已回滚文件: {file_path}")
184
- except:
185
- stderr_messages.append(f"回滚文件失败: {file_path}")
186
-
187
- return {
188
- "success": False,
189
- "stdout": "",
190
- "stderr": error_msg + "\n" + "\n".join(stderr_messages),
191
- }
@@ -6,7 +6,6 @@ from pathlib import Path
6
6
  from typing import Any, Dict
7
7
 
8
8
  from jarvis.jarvis_utils.config import get_data_dir
9
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
10
9
  from jarvis.jarvis_utils.globals import add_short_term_memory
11
10
 
12
11
 
@@ -14,18 +13,7 @@ class SaveMemoryTool:
14
13
  """保存记忆工具,用于将信息保存到长短期记忆系统"""
15
14
 
16
15
  name = "save_memory"
17
- description = """保存信息到长短期记忆系统。
18
-
19
- 支持批量保存多条记忆,可以同时保存不同类型的记忆。
20
-
21
- 支持的记忆类型:
22
- - project_long_term: 项目长期记忆(与当前项目相关的信息)
23
- - global_long_term: 全局长期记忆(通用的信息、用户喜好、知识、方法等)
24
- - short_term: 短期记忆(当前任务相关的信息)
25
-
26
- 项目长期记忆存储在当前目录的 .jarvis/memory 下
27
- 全局长期记忆和短期记忆存储在数据目录的 memory 子目录下
28
- """
16
+ description = "保存信息到长短期记忆系统。支持批量保存,记忆类型:project_long_term(项目长期)、global_long_term(全局长期)、short_term(短期)。"
29
17
 
30
18
  parameters = {
31
19
  "type": "object",
@@ -163,7 +151,7 @@ class SaveMemoryTool:
163
151
  except Exception as e:
164
152
  failed_count += 1
165
153
  error_msg = f"保存第 {i+1} 条记忆失败: {str(e)}"
166
- PrettyOutput.print(error_msg, OutputType.ERROR)
154
+ print(f"❌ {error_msg}")
167
155
  results.append(
168
156
  {
169
157
  "error": error_msg,
@@ -190,5 +178,5 @@ class SaveMemoryTool:
190
178
 
191
179
  except Exception as e:
192
180
  error_msg = f"保存记忆失败: {str(e)}"
193
- PrettyOutput.print(error_msg, OutputType.ERROR)
181
+ print(f"❌ {error_msg}")
194
182
  return {"success": False, "stdout": "", "stderr": error_msg}
@@ -2,7 +2,7 @@
2
2
  """网络搜索工具。"""
3
3
  from typing import Any, Dict
4
4
 
5
- import requests
5
+ import requests # type: ignore[import-untyped]
6
6
  from markdownify import markdownify as md # type: ignore
7
7
 
8
8
  # pylint: disable=import-error,missing-module-docstring
@@ -17,7 +17,6 @@ from jarvis.jarvis_utils.config import (
17
17
  get_web_search_model_name,
18
18
  )
19
19
  from jarvis.jarvis_utils.http import get as http_get
20
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
21
20
 
22
21
 
23
22
  class SearchWebTool:
@@ -65,12 +64,9 @@ class SearchWebTool:
65
64
  visited_urls.append(url)
66
65
  visited_count += 1
67
66
  except requests.exceptions.HTTPError as e:
68
- PrettyOutput.print(
69
- f"⚠️ HTTP错误 {e.response.status_code} 访问 {url}",
70
- OutputType.WARNING,
71
- )
67
+ print(f"⚠️ HTTP错误 {e.response.status_code} 访问 {url}")
72
68
  except requests.exceptions.RequestException as e:
73
- PrettyOutput.print(f"⚠️ 请求错误: {e}", OutputType.WARNING)
69
+ print(f"⚠️ 请求错误: {e}")
74
70
 
75
71
  if not full_content.strip():
76
72
  return {
@@ -108,7 +104,7 @@ class SearchWebTool:
108
104
  return {"stdout": summary, "stderr": "", "success": True}
109
105
 
110
106
  except Exception as e:
111
- PrettyOutput.print(f"❌ 网页搜索过程中发生错误: {e}", OutputType.ERROR)
107
+ print(f"❌ 网页搜索过程中发生错误: {e}")
112
108
  return {
113
109
  "stdout": "",
114
110
  "stderr": f"网页搜索过程中发生错误: {e}",
@@ -147,11 +143,13 @@ class SearchWebTool:
147
143
  if model.support_web():
148
144
  model.set_web(True)
149
145
  model.set_suppress_output(False)
150
- return {
151
- "stdout": model.chat_until_success(query),
152
- "stderr": "",
153
- "success": True,
154
- }
146
+ response = model.chat_until_success(query)
147
+ if response and response.strip():
148
+ return {
149
+ "stdout": response,
150
+ "stderr": "",
151
+ "success": True,
152
+ }
155
153
 
156
154
  # 否则使用现有的模型选择流程
157
155
  if agent.model.support_web():
@@ -161,11 +159,13 @@ class SearchWebTool:
161
159
  model.set_model_name(agent.model.name())
162
160
  model.set_web(True)
163
161
  model.set_suppress_output(False)
164
- return {
165
- "stdout": model.chat_until_success(query),
166
- "stderr": "",
167
- "success": True,
168
- }
162
+ response = model.chat_until_success(query)
163
+ if response and response.strip():
164
+ return {
165
+ "stdout": response,
166
+ "stderr": "",
167
+ "success": True,
168
+ }
169
169
 
170
170
  return self._search_with_ddgs(query, agent)
171
171
 
@@ -4,17 +4,17 @@ sub_agent 工具
4
4
  将子任务交给通用 Agent 执行,并返回执行结果。
5
5
 
6
6
  约定:
7
- - 必填参数:task, name, background, system_prompt, summary_prompt, use_tools
8
- - 继承父 Agent 的部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer;其他参数需显式提供
7
+ - 必填参数:task, name, system_prompt, summary_prompt
8
+ - 可选参数:background
9
+ - 工具集:默认使用系统工具集(无需传入 use_tools)
10
+ - 继承父 Agent 的部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer、non_interactive、use_methodology、use_analysis;其他参数需显式提供
9
11
  - 子Agent必须自动完成(auto_complete=True)且需要summary(need_summary=True)
10
12
  """
11
- from typing import Any, Dict, List
13
+ from typing import Any, Dict
12
14
  import json
13
15
 
14
16
  from jarvis.jarvis_agent import Agent
15
17
  from jarvis.jarvis_utils.globals import delete_agent
16
- from jarvis.jarvis_tools.registry import ToolRegistry
17
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
18
18
 
19
19
 
20
20
  class SubAgentTool:
@@ -27,7 +27,7 @@ class SubAgentTool:
27
27
 
28
28
  # 必须与文件名一致,供 ToolRegistry 自动注册
29
29
  name = "sub_agent"
30
- description = "将子任务交给通用 Agent 执行,并返回执行结果(继承父Agent部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer;其他参数需显式提供,自动完成并生成总结)。"
30
+ description = "将子任务交给通用 Agent 执行并返回结果(继承父Agent部分配置,自动完成并生成总结)。"
31
31
  parameters = {
32
32
  "type": "object",
33
33
  "properties": {
@@ -41,7 +41,7 @@ class SubAgentTool:
41
41
  },
42
42
  "background": {
43
43
  "type": "string",
44
- "description": "任务背景与已知信息(必填,将与任务一并提供给子Agent)",
44
+ "description": "任务背景与已知信息(可选,将与任务一并提供给子Agent)",
45
45
  },
46
46
  "system_prompt": {
47
47
  "type": "string",
@@ -51,25 +51,16 @@ class SubAgentTool:
51
51
  "type": "string",
52
52
  "description": "覆盖子Agent的总结提示词(必填)",
53
53
  },
54
- "use_tools": {
55
- "type": "array",
56
- "items": {"type": "string"},
57
- "description": "限制子Agent可用的工具名称列表(必填)。兼容以逗号分隔的字符串输入。可用的工具列表:"
58
- + "\n".join(
59
- [
60
- t["name"] + ": " + t["description"]
61
- for t in ToolRegistry().get_all_tools()
62
- ]
63
- ),
54
+ "non_interactive": {
55
+ "type": "boolean",
56
+ "description": "是否启用无交互模式(可选,默认继承父Agent或系统默认)",
64
57
  },
65
58
  },
66
59
  "required": [
67
60
  "task",
68
61
  "name",
69
- "background",
70
62
  "system_prompt",
71
63
  "summary_prompt",
72
- "use_tools",
73
64
  ],
74
65
  }
75
66
 
@@ -105,16 +96,6 @@ class SubAgentTool:
105
96
  summary_prompt = str(args.get("summary_prompt", "")).strip()
106
97
  agent_name = str(args.get("name", "")).strip()
107
98
 
108
- # 解析可用工具列表(支持数组或以逗号分隔的字符串)
109
- _use_tools = args.get("use_tools", None)
110
- use_tools: List[str] = []
111
- if isinstance(_use_tools, list):
112
- use_tools = [str(x).strip() for x in _use_tools if str(x).strip()]
113
- elif isinstance(_use_tools, str):
114
- use_tools = [s.strip() for s in _use_tools.split(",") if s.strip()]
115
- else:
116
- use_tools = []
117
-
118
99
  errors = []
119
100
  if not system_prompt:
120
101
  errors.append("system_prompt 不能为空")
@@ -122,8 +103,6 @@ class SubAgentTool:
122
103
  errors.append("summary_prompt 不能为空")
123
104
  if not agent_name:
124
105
  errors.append("name 不能为空")
125
- if not use_tools:
126
- errors.append("use_tools 不能为空")
127
106
  if not background:
128
107
  errors.append("background 不能为空")
129
108
 
@@ -137,20 +116,29 @@ class SubAgentTool:
137
116
  # 基于父Agent(如有)继承部分配置后创建子Agent
138
117
  parent_agent = args.get("agent", None)
139
118
  parent_model_group = None
140
- parent_input_handler = None
141
119
  parent_execute_tool_confirm = None
142
120
  parent_multiline_inputer = None
121
+ parent_non_interactive = None
122
+ parent_use_methodology = None
123
+ parent_use_analysis = None
143
124
  try:
144
125
  if parent_agent is not None:
145
126
  if getattr(parent_agent, "model", None):
146
127
  parent_model_group = getattr(parent_agent.model, "model_group", None)
147
- parent_input_handler = getattr(parent_agent, "input_handler", None)
148
128
  parent_execute_tool_confirm = getattr(parent_agent, "execute_tool_confirm", None)
149
129
  parent_multiline_inputer = getattr(parent_agent, "multiline_inputer", None)
130
+ parent_non_interactive = getattr(parent_agent, "non_interactive", None)
131
+ parent_use_methodology = getattr(parent_agent, "use_methodology", None)
132
+ parent_use_analysis = getattr(parent_agent, "use_analysis", None)
150
133
  except Exception:
151
134
  # 安全兜底:无法从父Agent获取配置则保持为None,使用系统默认
152
135
  pass
153
136
 
137
+ # 可选参数:允许显式覆盖无交互模式
138
+ explicit_non_interactive = args.get("non_interactive", None)
139
+ if explicit_non_interactive is not None:
140
+ parent_non_interactive = bool(explicit_non_interactive)
141
+
154
142
  agent = Agent(
155
143
  system_prompt=system_prompt,
156
144
  name=agent_name,
@@ -158,22 +146,30 @@ class SubAgentTool:
158
146
  model_group=parent_model_group,
159
147
  summary_prompt=summary_prompt,
160
148
  auto_complete=auto_complete,
161
- output_handler=None,
162
149
  use_tools=None,
163
- input_handler=parent_input_handler,
164
150
  execute_tool_confirm=parent_execute_tool_confirm,
165
151
  need_summary=need_summary,
166
152
  multiline_inputer=parent_multiline_inputer,
167
- use_methodology=None,
168
- use_analysis=None,
153
+ use_methodology=parent_use_methodology,
154
+ use_analysis=parent_use_analysis,
169
155
  force_save_memory=None,
170
156
  files=None,
157
+ non_interactive=parent_non_interactive,
171
158
  )
172
159
 
173
- # 设置可用工具列表
160
+ # 禁用 sub_agent 和 sub_code_agent,避免无限递归
174
161
  try:
175
- agent.set_use_tools(use_tools)
162
+ # 获取当前启用的工具列表
163
+ tool_registry = agent.get_tool_registry()
164
+ if tool_registry:
165
+ current_tools = [t.get("name") for t in tool_registry.get_all_tools() if isinstance(t, dict) and t.get("name")]
166
+ # 过滤掉禁止的工具
167
+ forbidden_tools = {"sub_agent", "sub_code_agent"}
168
+ filtered_tools = [t for t in current_tools if t not in forbidden_tools]
169
+ if filtered_tools:
170
+ agent.set_use_tools(filtered_tools)
176
171
  except Exception:
172
+ # 如果禁用工具失败,不影响主流程
177
173
  pass
178
174
 
179
175
  # 校验子Agent所用模型是否有效,必要时回退到平台可用模型
@@ -185,10 +181,7 @@ class SubAgentTool:
185
181
  available_names = [m for m, _ in available_models]
186
182
  current_model_name = platform.name()
187
183
  if current_model_name not in available_names:
188
- PrettyOutput.print(
189
- f"检测到子Agent模型 {current_model_name} 不存在于平台 {platform.platform_name()} 的可用模型列表,将回退到 {available_names[0]}",
190
- OutputType.WARNING,
191
- )
184
+ print(f"⚠️ 检测到子Agent模型 {current_model_name} 不存在于平台 {platform.platform_name()} 的可用模型列表,将回退到 {available_names[0]}")
192
185
  platform.set_model_name(available_names[0])
193
186
  except Exception:
194
187
  # 获取模型列表或设置模型失败时,保持原设置并继续,交由底层报错处理