jarvis-ai-assistant 0.3.30__py3-none-any.whl → 0.7.0__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 (115) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +289 -87
  3. jarvis/jarvis_agent/agent_manager.py +17 -8
  4. jarvis/jarvis_agent/edit_file_handler.py +374 -86
  5. jarvis/jarvis_agent/event_bus.py +1 -1
  6. jarvis/jarvis_agent/file_context_handler.py +79 -0
  7. jarvis/jarvis_agent/jarvis.py +601 -43
  8. jarvis/jarvis_agent/main.py +32 -2
  9. jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
  10. jarvis/jarvis_agent/run_loop.py +38 -5
  11. jarvis/jarvis_agent/share_manager.py +8 -1
  12. jarvis/jarvis_agent/stdio_redirect.py +295 -0
  13. jarvis/jarvis_agent/task_analyzer.py +5 -2
  14. jarvis/jarvis_agent/task_planner.py +496 -0
  15. jarvis/jarvis_agent/utils.py +5 -1
  16. jarvis/jarvis_agent/web_bridge.py +189 -0
  17. jarvis/jarvis_agent/web_output_sink.py +53 -0
  18. jarvis/jarvis_agent/web_server.py +751 -0
  19. jarvis/jarvis_c2rust/__init__.py +26 -0
  20. jarvis/jarvis_c2rust/cli.py +613 -0
  21. jarvis/jarvis_c2rust/collector.py +258 -0
  22. jarvis/jarvis_c2rust/library_replacer.py +1122 -0
  23. jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
  24. jarvis/jarvis_c2rust/optimizer.py +960 -0
  25. jarvis/jarvis_c2rust/scanner.py +1681 -0
  26. jarvis/jarvis_c2rust/transpiler.py +2325 -0
  27. jarvis/jarvis_code_agent/build_validation_config.py +133 -0
  28. jarvis/jarvis_code_agent/code_agent.py +1171 -94
  29. jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
  30. jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
  31. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
  32. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
  33. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
  34. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
  35. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
  36. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
  37. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
  38. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
  39. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
  40. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
  41. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
  42. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
  43. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
  44. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
  45. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
  46. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
  47. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
  48. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
  49. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
  50. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
  51. jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
  52. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
  53. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
  54. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
  55. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
  56. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
  57. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
  58. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
  59. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
  60. jarvis/jarvis_code_agent/lint.py +270 -8
  61. jarvis/jarvis_code_agent/utils.py +142 -0
  62. jarvis/jarvis_code_analysis/code_review.py +483 -569
  63. jarvis/jarvis_data/config_schema.json +97 -8
  64. jarvis/jarvis_git_utils/git_commiter.py +38 -26
  65. jarvis/jarvis_mcp/sse_mcp_client.py +2 -2
  66. jarvis/jarvis_mcp/stdio_mcp_client.py +1 -1
  67. jarvis/jarvis_memory_organizer/memory_organizer.py +1 -1
  68. jarvis/jarvis_multi_agent/__init__.py +239 -25
  69. jarvis/jarvis_multi_agent/main.py +37 -1
  70. jarvis/jarvis_platform/base.py +103 -51
  71. jarvis/jarvis_platform/openai.py +26 -1
  72. jarvis/jarvis_platform/yuanbao.py +1 -1
  73. jarvis/jarvis_platform_manager/service.py +2 -2
  74. jarvis/jarvis_rag/cli.py +4 -4
  75. jarvis/jarvis_sec/__init__.py +3605 -0
  76. jarvis/jarvis_sec/checkers/__init__.py +32 -0
  77. jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
  78. jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
  79. jarvis/jarvis_sec/cli.py +116 -0
  80. jarvis/jarvis_sec/report.py +257 -0
  81. jarvis/jarvis_sec/status.py +264 -0
  82. jarvis/jarvis_sec/types.py +20 -0
  83. jarvis/jarvis_sec/workflow.py +219 -0
  84. jarvis/jarvis_stats/cli.py +1 -1
  85. jarvis/jarvis_stats/stats.py +1 -1
  86. jarvis/jarvis_stats/visualizer.py +1 -1
  87. jarvis/jarvis_tools/cli/main.py +1 -0
  88. jarvis/jarvis_tools/execute_script.py +46 -9
  89. jarvis/jarvis_tools/generate_new_tool.py +3 -1
  90. jarvis/jarvis_tools/read_code.py +275 -12
  91. jarvis/jarvis_tools/read_symbols.py +141 -0
  92. jarvis/jarvis_tools/read_webpage.py +5 -3
  93. jarvis/jarvis_tools/registry.py +73 -35
  94. jarvis/jarvis_tools/search_web.py +15 -11
  95. jarvis/jarvis_tools/sub_agent.py +24 -42
  96. jarvis/jarvis_tools/sub_code_agent.py +14 -13
  97. jarvis/jarvis_tools/virtual_tty.py +1 -1
  98. jarvis/jarvis_utils/config.py +187 -35
  99. jarvis/jarvis_utils/embedding.py +3 -0
  100. jarvis/jarvis_utils/git_utils.py +181 -6
  101. jarvis/jarvis_utils/globals.py +3 -3
  102. jarvis/jarvis_utils/http.py +1 -1
  103. jarvis/jarvis_utils/input.py +78 -2
  104. jarvis/jarvis_utils/methodology.py +25 -19
  105. jarvis/jarvis_utils/utils.py +644 -359
  106. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/METADATA +85 -1
  107. jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
  108. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +4 -0
  109. jarvis/jarvis_agent/config.py +0 -92
  110. jarvis/jarvis_tools/edit_file.py +0 -179
  111. jarvis/jarvis_tools/rewrite_file.py +0 -191
  112. jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
  113. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
  114. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
  115. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
@@ -51,6 +51,7 @@ arguments:
51
51
  - 完全按照上述格式
52
52
  - 使用正确的YAML格式,2个空格作为缩进
53
53
  - 包含所有必需参数
54
+ - {ot("TOOL_CALL")} 和 {ct("TOOL_CALL")} 必须出现在行首
54
55
  </rule>
55
56
 
56
57
  <rule>
@@ -101,6 +102,7 @@ arguments:
101
102
  - 创建虚构对话
102
103
  - 在没有所需信息的情况下继续
103
104
  - yaml 格式错误
105
+ - {ot("TOOL_CALL")} 和 {ct("TOOL_CALL")} 没有出现在行首
104
106
  </common_errors>
105
107
  </tool_system_guide>
106
108
  """
@@ -121,7 +123,8 @@ class ToolRegistry(OutputHandlerProtocol):
121
123
  return "TOOL_CALL"
122
124
 
123
125
  def can_handle(self, response: str) -> bool:
124
- return ot("TOOL_CALL") in response
126
+ # 仅当 {ot("TOOL_CALL")} 出现在行首时才认为可以处理
127
+ return re.search(rf'(?m){re.escape(ot("TOOL_CALL"))}', response) is not None
125
128
 
126
129
  def prompt(self) -> str:
127
130
  """加载工具"""
@@ -172,7 +175,15 @@ class ToolRegistry(OutputHandlerProtocol):
172
175
  try:
173
176
  tool_call, err_msg, auto_completed = self._extract_tool_calls(response)
174
177
  if err_msg:
175
- return False, err_msg
178
+ # 只要工具解析错误,追加工具使用帮助信息(相当于一次 <ToolUsage>)
179
+ try:
180
+ from jarvis.jarvis_agent import Agent
181
+ agent: Agent = agent_
182
+ tool_usage = agent.get_tool_usage_prompt()
183
+ return False, f"{err_msg}\n\n{tool_usage}"
184
+ except Exception:
185
+ # 兼容处理:无法获取Agent或ToolUsage时,至少返回工具系统帮助信息
186
+ return False, f"{err_msg}\n\n{tool_call_help}"
176
187
  result = self.handle_tool_calls(tool_call, agent_)
177
188
  if auto_completed:
178
189
  # 如果自动补全了结束标签,在结果中添加说明信息
@@ -347,22 +358,28 @@ class ToolRegistry(OutputHandlerProtocol):
347
358
  # 如果配置了中心工具仓库,将其添加到加载路径
348
359
  central_repo = get_central_tool_repo()
349
360
  if central_repo:
350
- # 中心工具仓库存储在数据目录下的特定位置
351
- central_repo_path = os.path.join(get_data_dir(), "central_tool_repo")
352
- tool_dirs.append(central_repo_path)
361
+ # 支持本地目录路径或Git仓库URL
362
+ expanded = os.path.expanduser(os.path.expandvars(central_repo))
363
+ if os.path.isdir(expanded):
364
+ # 直接使用本地目录(支持Git仓库的子目录)
365
+ tool_dirs.append(expanded)
366
+ else:
367
+ # 中心工具仓库存储在数据目录下的特定位置
368
+ central_repo_path = os.path.join(get_data_dir(), "central_tool_repo")
369
+ tool_dirs.append(central_repo_path)
353
370
 
354
- # 确保中心工具仓库被克隆/更新
355
- if not os.path.exists(central_repo_path):
356
- try:
357
- import subprocess
371
+ # 确保中心工具仓库被克隆/更新
372
+ if not os.path.exists(central_repo_path):
373
+ try:
374
+ import subprocess
358
375
 
359
- subprocess.run(
360
- ["git", "clone", central_repo, central_repo_path], check=True
361
- )
362
- except Exception as e:
363
- PrettyOutput.print(
364
- f"克隆中心工具仓库失败: {str(e)}", OutputType.ERROR
365
- )
376
+ subprocess.run(
377
+ ["git", "clone", central_repo, central_repo_path], check=True
378
+ )
379
+ except Exception as e:
380
+ PrettyOutput.print(
381
+ f"克隆中心工具仓库失败: {str(e)}", OutputType.ERROR
382
+ )
366
383
 
367
384
  # --- 全局每日更新检查 ---
368
385
  daily_check_git_updates(tool_dirs, "tools")
@@ -608,11 +625,9 @@ class ToolRegistry(OutputHandlerProtocol):
608
625
 
609
626
  @staticmethod
610
627
  def _has_tool_calls_block(content: str) -> bool:
611
- """从内容中提取工具调用块"""
612
- return (
613
- re.search(ot("TOOL_CALL") + r"(.*?)" + ct("TOOL_CALL"), content, re.DOTALL)
614
- is not None
615
- )
628
+ """从内容中提取工具调用块(仅匹配行首标签)"""
629
+ pattern = rf'(?ms){re.escape(ot("TOOL_CALL"))}(.*?)^{re.escape(ct("TOOL_CALL"))}'
630
+ return re.search(pattern, content) is not None
616
631
 
617
632
  @staticmethod
618
633
  def _extract_tool_calls(
@@ -632,23 +647,29 @@ class ToolRegistry(OutputHandlerProtocol):
632
647
  异常:
633
648
  Exception: 如果工具调用缺少必要字段
634
649
  """
650
+ # 如果</TOOL_CALL>出现在响应的末尾,但是前面没有换行符,自动插入一个换行符进行修复
651
+ if content.rstrip().endswith(ct("TOOL_CALL")):
652
+ pos = content.rfind(ct("TOOL_CALL"))
653
+ if pos > 0 and content[pos - 1] not in ("\n", "\r"):
654
+ content = content[:pos] + "\n" + content[pos:]
655
+
635
656
  # 将内容拆分为行
636
- data = re.findall(
637
- ot("TOOL_CALL") + r"(.*?)" + ct("TOOL_CALL"), content, re.DOTALL
638
- )
657
+ pattern = rf'(?ms){re.escape(ot("TOOL_CALL"))}(.*?)^{re.escape(ct("TOOL_CALL"))}'
658
+ data = re.findall(pattern, content)
639
659
  auto_completed = False
640
660
  if not data:
641
- # can_handle 确保 ot("TOOL_CALL") 在内容中。
642
- # 如果数据为空,则表示 ct("TOOL_CALL") 可能丢失。
643
- if ot("TOOL_CALL") in content and ct("TOOL_CALL") not in content:
644
- # 尝试通过附加结束标签来修复它
661
+ # can_handle 确保 ot("TOOL_CALL") 在内容中(行首)。
662
+ # 如果数据为空,则表示行首的 ct("TOOL_CALL") 可能丢失。
663
+ has_open_at_bol = re.search(rf'(?m){re.escape(ot("TOOL_CALL"))}', content) is not None
664
+ has_close_at_bol = re.search(rf'(?m)^{re.escape(ct("TOOL_CALL"))}', content) is not None
665
+ if has_open_at_bol and not has_close_at_bol:
666
+ # 尝试通过附加结束标签来修复它(确保结束标签位于行首)
645
667
  fixed_content = content.strip() + f"\n{ct('TOOL_CALL')}"
646
668
 
647
669
  # 再次提取,并检查YAML是否有效
648
670
  temp_data = re.findall(
649
- ot("TOOL_CALL") + r"(.*?)" + ct("TOOL_CALL"),
671
+ pattern,
650
672
  fixed_content,
651
- re.DOTALL,
652
673
  )
653
674
 
654
675
  if temp_data:
@@ -830,10 +851,12 @@ class ToolRegistry(OutputHandlerProtocol):
830
851
  try:
831
852
  args = json.loads(args)
832
853
  except json.JSONDecodeError:
833
- PrettyOutput.print(
834
- f"工具参数格式无效: {name} {tool_call_help}", OutputType.ERROR
835
- )
836
- return ""
854
+ # 返回错误并附带完整的工具使用提示,指导下一次正确调用
855
+ try:
856
+ usage_prompt = agent_instance.get_tool_usage_prompt()
857
+ except Exception:
858
+ usage_prompt = tool_call_help
859
+ return f"工具参数格式无效: {name}。arguments 应为可解析的 JSON 或对象,请按工具调用格式提供。\n\n{usage_prompt}"
837
860
 
838
861
  # 执行工具调用(根据工具实现的协议版本,由系统在内部决定agent的传递方式)
839
862
  result = self.execute_tool(name, args, agent)
@@ -853,6 +876,15 @@ class ToolRegistry(OutputHandlerProtocol):
853
876
  except Exception:
854
877
  pass
855
878
 
879
+ # 如果执行失败,附带工具使用提示返回
880
+ if not result.get("success", False):
881
+ try:
882
+ usage_prompt = agent_instance.get_tool_usage_prompt()
883
+ except Exception:
884
+ usage_prompt = tool_call_help
885
+ err_output = self._format_tool_output(result.get("stdout", ""), result.get("stderr", ""))
886
+ return f"{err_output}\n\n{usage_prompt}"
887
+
856
888
  # 格式化输出
857
889
  output = self._format_tool_output(
858
890
  result["stdout"], result.get("stderr", "")
@@ -913,4 +945,10 @@ class ToolRegistry(OutputHandlerProtocol):
913
945
 
914
946
  except Exception as e:
915
947
  PrettyOutput.print(f"工具执行失败:{str(e)}", OutputType.ERROR)
916
- return f"工具调用失败: {str(e)}"
948
+ try:
949
+ from jarvis.jarvis_agent import Agent # 延迟导入避免循环依赖
950
+ agent_instance_for_prompt: Agent = agent # type: ignore
951
+ usage_prompt = agent_instance_for_prompt.get_tool_usage_prompt()
952
+ except Exception:
953
+ usage_prompt = tool_call_help
954
+ return f"工具调用失败: {str(e)}\n\n{usage_prompt}"
@@ -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
@@ -147,11 +147,13 @@ class SearchWebTool:
147
147
  if model.support_web():
148
148
  model.set_web(True)
149
149
  model.set_suppress_output(False)
150
- return {
151
- "stdout": model.chat_until_success(query),
152
- "stderr": "",
153
- "success": True,
154
- }
150
+ response = model.chat_until_success(query)
151
+ if response and response.strip():
152
+ return {
153
+ "stdout": response,
154
+ "stderr": "",
155
+ "success": True,
156
+ }
155
157
 
156
158
  # 否则使用现有的模型选择流程
157
159
  if agent.model.support_web():
@@ -161,11 +163,13 @@ class SearchWebTool:
161
163
  model.set_model_name(agent.model.name())
162
164
  model.set_web(True)
163
165
  model.set_suppress_output(False)
164
- return {
165
- "stdout": model.chat_until_success(query),
166
- "stderr": "",
167
- "success": True,
168
- }
166
+ response = model.chat_until_success(query)
167
+ if response and response.strip():
168
+ return {
169
+ "stdout": response,
170
+ "stderr": "",
171
+ "success": True,
172
+ }
169
173
 
170
174
  return self._search_with_ddgs(query, agent)
171
175
 
@@ -4,16 +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
18
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
18
19
 
19
20
 
@@ -27,7 +28,7 @@ class SubAgentTool:
27
28
 
28
29
  # 必须与文件名一致,供 ToolRegistry 自动注册
29
30
  name = "sub_agent"
30
- description = "将子任务交给通用 Agent 执行,并返回执行结果(继承父Agent部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer;其他参数需显式提供,自动完成并生成总结)。"
31
+ description = "将子任务交给通用 Agent 执行,并返回执行结果(继承父Agent部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer、non_interactive、use_methodology、use_analysis;其他参数需显式提供,自动完成并生成总结)。"
31
32
  parameters = {
32
33
  "type": "object",
33
34
  "properties": {
@@ -41,7 +42,7 @@ class SubAgentTool:
41
42
  },
42
43
  "background": {
43
44
  "type": "string",
44
- "description": "任务背景与已知信息(必填,将与任务一并提供给子Agent)",
45
+ "description": "任务背景与已知信息(可选,将与任务一并提供给子Agent)",
45
46
  },
46
47
  "system_prompt": {
47
48
  "type": "string",
@@ -51,25 +52,16 @@ class SubAgentTool:
51
52
  "type": "string",
52
53
  "description": "覆盖子Agent的总结提示词(必填)",
53
54
  },
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
- ),
55
+ "non_interactive": {
56
+ "type": "boolean",
57
+ "description": "是否启用无交互模式(可选,默认继承父Agent或系统默认)",
64
58
  },
65
59
  },
66
60
  "required": [
67
61
  "task",
68
62
  "name",
69
- "background",
70
63
  "system_prompt",
71
64
  "summary_prompt",
72
- "use_tools",
73
65
  ],
74
66
  }
75
67
 
@@ -105,16 +97,6 @@ class SubAgentTool:
105
97
  summary_prompt = str(args.get("summary_prompt", "")).strip()
106
98
  agent_name = str(args.get("name", "")).strip()
107
99
 
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
100
  errors = []
119
101
  if not system_prompt:
120
102
  errors.append("system_prompt 不能为空")
@@ -122,8 +104,6 @@ class SubAgentTool:
122
104
  errors.append("summary_prompt 不能为空")
123
105
  if not agent_name:
124
106
  errors.append("name 不能为空")
125
- if not use_tools:
126
- errors.append("use_tools 不能为空")
127
107
  if not background:
128
108
  errors.append("background 不能为空")
129
109
 
@@ -137,20 +117,29 @@ class SubAgentTool:
137
117
  # 基于父Agent(如有)继承部分配置后创建子Agent
138
118
  parent_agent = args.get("agent", None)
139
119
  parent_model_group = None
140
- parent_input_handler = None
141
120
  parent_execute_tool_confirm = None
142
121
  parent_multiline_inputer = None
122
+ parent_non_interactive = None
123
+ parent_use_methodology = None
124
+ parent_use_analysis = None
143
125
  try:
144
126
  if parent_agent is not None:
145
127
  if getattr(parent_agent, "model", None):
146
128
  parent_model_group = getattr(parent_agent.model, "model_group", None)
147
- parent_input_handler = getattr(parent_agent, "input_handler", None)
148
129
  parent_execute_tool_confirm = getattr(parent_agent, "execute_tool_confirm", None)
149
130
  parent_multiline_inputer = getattr(parent_agent, "multiline_inputer", None)
131
+ parent_non_interactive = getattr(parent_agent, "non_interactive", None)
132
+ parent_use_methodology = getattr(parent_agent, "use_methodology", None)
133
+ parent_use_analysis = getattr(parent_agent, "use_analysis", None)
150
134
  except Exception:
151
135
  # 安全兜底:无法从父Agent获取配置则保持为None,使用系统默认
152
136
  pass
153
137
 
138
+ # 可选参数:允许显式覆盖无交互模式
139
+ explicit_non_interactive = args.get("non_interactive", None)
140
+ if explicit_non_interactive is not None:
141
+ parent_non_interactive = bool(explicit_non_interactive)
142
+
154
143
  agent = Agent(
155
144
  system_prompt=system_prompt,
156
145
  name=agent_name,
@@ -158,24 +147,17 @@ class SubAgentTool:
158
147
  model_group=parent_model_group,
159
148
  summary_prompt=summary_prompt,
160
149
  auto_complete=auto_complete,
161
- output_handler=None,
162
150
  use_tools=None,
163
- input_handler=parent_input_handler,
164
151
  execute_tool_confirm=parent_execute_tool_confirm,
165
152
  need_summary=need_summary,
166
153
  multiline_inputer=parent_multiline_inputer,
167
- use_methodology=None,
168
- use_analysis=None,
154
+ use_methodology=parent_use_methodology,
155
+ use_analysis=parent_use_analysis,
169
156
  force_save_memory=None,
170
157
  files=None,
158
+ non_interactive=parent_non_interactive,
171
159
  )
172
160
 
173
- # 设置可用工具列表
174
- try:
175
- agent.set_use_tools(use_tools)
176
- except Exception:
177
- pass
178
-
179
161
  # 校验子Agent所用模型是否有效,必要时回退到平台可用模型
180
162
  try:
181
163
  platform = getattr(agent, "model", None)
@@ -4,12 +4,12 @@ sub_code_agent 工具
4
4
  将子任务交给 CodeAgent 执行,并返回执行结果。
5
5
 
6
6
  约定:
7
- - 仅接收一个参数:task
7
+ - 必填参数:task
8
+ - 可选参数:background
8
9
  - 不依赖父 Agent,所有配置使用系统默认与全局变量
9
10
  - 子Agent必须自动完成(auto_complete=True)且需要summary(need_summary=True)
10
11
  """
11
12
  from typing import Any, Dict, List
12
- import json
13
13
 
14
14
  from jarvis.jarvis_code_agent.code_agent import CodeAgent
15
15
  from jarvis.jarvis_utils.globals import delete_agent
@@ -19,7 +19,7 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
19
19
 
20
20
  class SubCodeAgentTool:
21
21
  """
22
- 使用 CodeAgent 托管执行子任务,执行完立即清理内部 Agent。
22
+ 使用 CodeAgent 托管执行子任务,执行完立即清理 CodeAgent 实例。
23
23
  - 不注册至全局
24
24
  - 使用系统默认/全局配置
25
25
  - 启用自动完成与总结
@@ -84,6 +84,7 @@ class SubCodeAgentTool:
84
84
  parent_agent = None
85
85
  except Exception:
86
86
  parent_agent = None
87
+ parent_non_interactive = getattr(parent_agent, "non_interactive", None) if parent_agent is not None else None
87
88
  model_group = None
88
89
  use_tools: List[str] = []
89
90
  try:
@@ -115,7 +116,7 @@ class SubCodeAgentTool:
115
116
  "search_web",
116
117
  "ask_user",
117
118
  "read_code",
118
- "rewrite_file",
119
+
119
120
  "save_memory",
120
121
  "retrieve_memory",
121
122
  "clear_memory",
@@ -138,6 +139,7 @@ class SubCodeAgentTool:
138
139
  need_summary=True,
139
140
  append_tools=append_tools,
140
141
  tool_group=tool_group,
142
+ non_interactive=parent_non_interactive,
141
143
  )
142
144
  except SystemExit as se:
143
145
  # 将底层 sys.exit 转换为工具错误,避免终止进程
@@ -155,21 +157,21 @@ class SubCodeAgentTool:
155
157
 
156
158
  # 子Agent需要自动完成
157
159
  try:
158
- code_agent.agent.auto_complete = True
160
+ code_agent.auto_complete = True
159
161
  # 同步父Agent工具使用集(如可用)
160
162
  if use_tools:
161
- code_agent.agent.set_use_tools(use_tools)
163
+ code_agent.set_use_tools(use_tools)
162
164
  # 同步父Agent的模型名称(如可用),以尽量保持平台与模型一致
163
165
  if (
164
166
  parent_agent is not None
165
167
  and getattr(parent_agent, "model", None)
166
- and getattr(code_agent.agent, "model", None)
168
+ and getattr(code_agent, "model", None)
167
169
  ):
168
170
  try:
169
171
  parent_model_name = parent_agent.model.name() # type: ignore[attr-defined]
170
172
  if parent_model_name:
171
173
  from typing import Any
172
- model_obj: Any = getattr(code_agent.agent, "model", None)
174
+ model_obj: Any = getattr(code_agent, "model", None)
173
175
  if model_obj is not None:
174
176
  model_obj.set_model_name(parent_model_name)
175
177
  # 模型有效性校验与回退,确保父Agent模型在子Agent平台上可用
@@ -194,18 +196,17 @@ class SubCodeAgentTool:
194
196
 
195
197
  # 执行子任务(无提交信息前后缀)
196
198
  ret = code_agent.run(enhanced_task, prefix="", suffix="")
197
- stdout = ret if isinstance(ret, str) and ret else "任务执行完成"
198
199
 
199
- # 主动清理内部 Agent,避免污染父Agent的全局状态
200
+ # 主动清理 CodeAgent 实例,避免污染父Agent的全局状态
200
201
  try:
201
- inner_agent = code_agent.agent
202
- delete_agent(inner_agent.name)
202
+ # CodeAgent 现在直接继承 Agent,所以直接使用 code_agent
203
+ delete_agent(code_agent.name)
203
204
  except Exception:
204
205
  pass
205
206
 
206
207
  return {
207
208
  "success": True,
208
- "stdout": json.dumps({"result": stdout}, ensure_ascii=False, indent=2),
209
+ "stdout": ret,
209
210
  "stderr": "",
210
211
  }
211
212
  except Exception as e:
@@ -279,7 +279,7 @@ class VirtualTTYTool:
279
279
  line = process.stdout.readline()
280
280
  if line:
281
281
  agent.tty_sessions[tty_id]["output_queue"].put(line)
282
- except:
282
+ except Exception:
283
283
  break
284
284
 
285
285
  output_thread = _threading.Thread(target=read_output, daemon=True)