jarvis-ai-assistant 0.4.0__py3-none-any.whl → 0.4.1__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.
@@ -56,9 +56,11 @@ class CodeAgent:
56
56
  need_summary: bool = True,
57
57
  append_tools: Optional[str] = None,
58
58
  tool_group: Optional[str] = None,
59
+ non_interactive: Optional[bool] = None,
59
60
  ):
60
61
  self.root_dir = os.getcwd()
61
62
  self.tool_group = tool_group
63
+ self.non_interactive = non_interactive
62
64
 
63
65
  # 检测 git username 和 email 是否已设置
64
66
  self._check_git_config()
@@ -68,7 +70,6 @@ class CodeAgent:
68
70
  "search_web",
69
71
  "ask_user",
70
72
  "read_code",
71
- "rewrite_file",
72
73
  "save_memory",
73
74
  "retrieve_memory",
74
75
  "clear_memory",
@@ -89,11 +90,11 @@ class CodeAgent:
89
90
  system_prompt=code_system_prompt,
90
91
  name="CodeAgent",
91
92
  auto_complete=False,
92
- output_handler=[tool_registry, EditFileHandler()], # type: ignore
93
93
  model_group=model_group,
94
94
  need_summary=need_summary,
95
95
  use_methodology=False, # 禁用方法论
96
96
  use_analysis=False, # 禁用分析
97
+ non_interactive=self.non_interactive,
97
98
  )
98
99
 
99
100
  self.agent.event_bus.subscribe(AFTER_TOOL_CALL, self._on_after_tool_call)
@@ -137,7 +138,7 @@ class CodeAgent:
137
138
 
138
139
  ## 文件编辑工具使用规范
139
140
  - 对于部分文件内容修改,使用edit_file工具
140
- - 对于需要重写整个文件内容,使用rewrite_file工具
141
+ - 对于需要重写整个文件内容,使用 REWRITE 操作
141
142
  - 对于简单的修改,可以使用execute_script工具执行shell命令完成
142
143
 
143
144
  ## 子任务与子CodeAgent
@@ -567,8 +568,8 @@ class CodeAgent:
567
568
  1. 每次响应仅执行一步操作,先分析再修改,避免一步多改。
568
569
  2. 充分利用工具理解用户需求和现有代码,禁止凭空假设。
569
570
  3. 如果不清楚要修改的文件,必须先分析并找出需要修改的文件,明确目标后再进行编辑。
570
- 4. 代码编辑任务优先使用 edit_file 工具,确保搜索文本在目标文件中有且仅有一次精确匹配,保证修改的准确性和安全性。
571
- 5. 如需大范围重写,才可使用 rewrite_file 工具。
571
+ 4. 代码编辑任务优先使用 PATCH 操作,确保搜索文本在目标文件中有且仅有一次精确匹配,保证修改的准确性和安全性。
572
+ 5. 如需大范围重写,才可使用 REWRITE 操作。
572
573
  6. 如遇信息不明,优先调用工具补充分析,不要主观臆断。
573
574
  """
574
575
 
@@ -851,9 +852,10 @@ def cli(
851
852
  PrettyOutput.print(
852
853
  f"警告:当前目录 '{curr_dir_path}' 不是一个git仓库。", OutputType.WARNING
853
854
  )
854
- if user_confirm(
855
+ init_git = True if non_interactive else user_confirm(
855
856
  f"是否要在 '{curr_dir_path}' 中初始化一个新的git仓库?", default=True
856
- ):
857
+ )
858
+ if init_git:
857
859
  try:
858
860
  subprocess.run(
859
861
  ["git", "init"],
@@ -881,6 +883,7 @@ def cli(
881
883
  need_summary=False,
882
884
  append_tools=append_tools,
883
885
  tool_group=tool_group,
886
+ non_interactive=non_interactive,
884
887
  )
885
888
 
886
889
  # 尝试恢复会话
@@ -689,7 +689,6 @@ class CodeReviewTool:
689
689
  {ot("REPORT")}
690
690
  [在此处插入完整MARKDOWN格式的审查报告]
691
691
  {ct("REPORT")}""",
692
- output_handler=[tool_registry], # type: ignore
693
692
  auto_complete=False,
694
693
  )
695
694
 
@@ -322,6 +322,11 @@
322
322
  "description": "是否保存会话记录",
323
323
  "default": false
324
324
  },
325
+ "JARVIS_SKIP_PREDEFINED_TASKS": {
326
+ "type": "boolean",
327
+ "description": "是否跳过预定义任务加载(不读取 pre-command 列表)",
328
+ "default": false
329
+ },
325
330
  "JARVIS_GIT_CHECK_MODE": {
326
331
  "type": "string",
327
332
  "enum": ["strict", "warn"],
@@ -7,17 +7,20 @@ import yaml
7
7
  from jarvis.jarvis_agent import Agent
8
8
  from jarvis.jarvis_agent.output_handler import OutputHandler
9
9
  from jarvis.jarvis_tools.registry import ToolRegistry
10
+ from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
11
+ from jarvis.jarvis_agent.rewrite_file_handler import RewriteFileHandler
10
12
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
11
13
  from jarvis.jarvis_utils.tag import ct, ot
12
14
 
13
15
 
14
16
  class MultiAgent(OutputHandler):
15
- def __init__(self, agents_config: List[Dict], main_agent_name: str):
17
+ def __init__(self, agents_config: List[Dict], main_agent_name: str, common_system_prompt: str = ""):
16
18
  self.agents_config = agents_config
17
19
  self.agents_config_map = {c["name"]: c for c in agents_config}
18
20
  self.agents: Dict[str, Agent] = {}
19
21
  self.main_agent_name = main_agent_name
20
22
  self.original_question: Optional[str] = None
23
+ self.common_system_prompt: str = common_system_prompt
21
24
 
22
25
  def prompt(self) -> str:
23
26
  return f"""
@@ -66,18 +69,168 @@ content: |2
66
69
  """
67
70
 
68
71
  def can_handle(self, response: str) -> bool:
69
- return len(self._extract_send_msg(response)) > 0
72
+ # 只要检测到 SEND_MESSAGE 起始标签即认为可处理,
73
+ # 即便内容有误也由 handle 返回明确错误与修复指导
74
+ return ot("SEND_MESSAGE") in response
70
75
 
71
76
  def handle(self, response: str, agent: Any) -> Tuple[bool, Any]:
72
- send_messages = self._extract_send_msg(response)
73
- if len(send_messages) > 1:
77
+ """
78
+ 处理 SEND_MESSAGE。若存在格式/解析/字段/目标等问题,返回明确错误原因与修复指导。
79
+ """
80
+ # 优先使用解析器获取“正确路径”结果
81
+ parsed = self._extract_send_msg(response)
82
+ if len(parsed) == 1:
83
+ msg = parsed[0]
84
+ # 字段校验
85
+ to_val = msg.get("to")
86
+ content_val = msg.get("content")
87
+ missing = []
88
+ if not to_val:
89
+ missing.append("to")
90
+ if content_val is None or (isinstance(content_val, str) and content_val.strip() == ""):
91
+ # 允许空格/空行被视为缺失
92
+ missing.append("content")
93
+ if missing:
94
+ guidance = (
95
+ "SEND_MESSAGE 字段缺失或为空:"
96
+ + ", ".join(missing)
97
+ + "\n修复建议:\n"
98
+ "- 必须包含 to 和 content 字段\n"
99
+ "- to: 目标智能体名称(字符串)\n"
100
+ "- content: 发送内容,建议使用多行块 |2 保持格式\n"
101
+ "示例:\n"
102
+ f"{ot('SEND_MESSAGE')}\n"
103
+ "to: 目标Agent名称\n"
104
+ "content: |2\n"
105
+ " 这里填写要发送的消息内容\n"
106
+ f"{ct('SEND_MESSAGE')}"
107
+ )
108
+ return False, guidance
109
+ # 类型校验
110
+ if not isinstance(to_val, str):
111
+ return False, "SEND_MESSAGE 字段类型错误:to 必须为字符串。修复建议:将 to 改为字符串,如 to: ChapterPolisher"
112
+ if not isinstance(content_val, str):
113
+ return False, "SEND_MESSAGE 字段类型错误:content 必须为字符串。修复建议:将 content 改为字符串或使用多行块 content: |2"
114
+ # 目标校验
115
+ if to_val not in self.agents_config_map:
116
+ available = ", ".join(self.agents_config_map.keys())
117
+ return (
118
+ False,
119
+ f"目标智能体不存在:'{to_val}' 不在可用列表中。\n"
120
+ f"可用智能体:[{available}]\n"
121
+ "修复建议:\n"
122
+ "- 将 to 修改为上述可用智能体之一\n"
123
+ "- 或检查配置中是否遗漏了该智能体的定义"
124
+ )
125
+ # 通过校验,交给上层发送
126
+ return True, {"to": to_val, "content": content_val}
127
+ elif len(parsed) > 1:
128
+ return (
129
+ False,
130
+ "检测到多个 SEND_MESSAGE 块。一次只能发送一个消息。\n修复建议:合并消息或分多轮发送,每轮仅保留一个 SEND_MESSAGE 块。"
131
+ )
132
+ # 未成功解析,进行诊断并返回可操作指导
133
+ try:
134
+ normalized = response.replace("\r\n", "\n").replace("\r", "\n")
135
+ except Exception:
136
+ normalized = response
137
+ ot_tag = ot("SEND_MESSAGE")
138
+ ct_tag = ct("SEND_MESSAGE")
139
+ has_open = ot_tag in normalized
140
+ has_close = ct_tag in normalized
141
+ if has_open and not has_close:
74
142
  return (
75
143
  False,
76
- "Send multiple messages, please only send one message at a time.",
144
+ f"检测到 {ot_tag} 但缺少结束标签 {ct_tag}。\n"
145
+ "修复建议:在消息末尾补充结束标签,并确认标签各自独占一行。\n"
146
+ "示例:\n"
147
+ f"{ot_tag}\n"
148
+ "to: 目标Agent名称\n"
149
+ "content: |2\n"
150
+ " 这里填写要发送的消息内容\n"
151
+ f"{ct_tag}"
152
+ )
153
+ # 尝试提取原始块并指出 YAML 问题
154
+ import re as _re
155
+ pattern = _re.compile(
156
+ rf"{_re.escape(ot_tag)}[ \t]*\n(.*?)(?:\n)?[ \t]*{_re.escape(ct_tag)}",
157
+ _re.DOTALL,
158
+ )
159
+ blocks = pattern.findall(normalized)
160
+ if not blocks:
161
+ alt_pattern = _re.compile(
162
+ rf"{_re.escape(ot_tag)}[ \t]*(.*?)[ \t]*{_re.escape(ct_tag)}",
163
+ _re.DOTALL,
164
+ )
165
+ blocks = alt_pattern.findall(normalized)
166
+ if not blocks:
167
+ return (
168
+ False,
169
+ "SEND_MESSAGE 格式错误:未能识别完整的消息块。\n"
170
+ "修复建议:确保起止标签在单独行上,且中间内容为合法的 YAML,包含 to 与 content 字段。"
171
+ )
172
+ raw = blocks[0]
173
+ try:
174
+ msg_obj = yaml.safe_load(raw)
175
+ if not isinstance(msg_obj, dict):
176
+ return (
177
+ False,
178
+ "SEND_MESSAGE 内容必须为 YAML 对象(键值对)。\n"
179
+ "修复建议:使用 to 与 content 字段构成的对象。\n"
180
+ "示例:\n"
181
+ f"{ot('SEND_MESSAGE')}\n"
182
+ "to: 目标Agent名称\n"
183
+ "content: |2\n"
184
+ " 这里填写要发送的消息内容\n"
185
+ f"{ct('SEND_MESSAGE')}"
186
+ )
187
+ missing_keys = [k for k in ("to", "content") if k not in msg_obj]
188
+ if missing_keys:
189
+ return (
190
+ False,
191
+ "SEND_MESSAGE 缺少必要字段:" + ", ".join(missing_keys) + "\n"
192
+ "修复建议:补充缺失字段。\n"
193
+ "示例:\n"
194
+ f"{ot('SEND_MESSAGE')}\n"
195
+ "to: 目标Agent名称\n"
196
+ "content: |2\n"
197
+ " 这里填写要发送的消息内容\n"
198
+ f"{ct('SEND_MESSAGE')}"
199
+ )
200
+ # 针对值类型的提示(更细)
201
+ if not isinstance(msg_obj.get("to"), str):
202
+ return False, "SEND_MESSAGE 字段类型错误:to 必须为字符串。"
203
+ if not isinstance(msg_obj.get("content"), str):
204
+ return False, "SEND_MESSAGE 字段类型错误:content 必须为字符串,建议使用多行块 |2。"
205
+ # 若到此仍未返回,说明结构基本正确,但 _extract_send_msg 未命中,给出泛化建议
206
+ return (
207
+ False,
208
+ "SEND_MESSAGE 格式可能存在缩进或空白字符问题,导致未被系统识别。\n"
209
+ "修复建议:\n"
210
+ "- 确保起止标签各占一行\n"
211
+ "- 标签与内容之间保留换行\n"
212
+ "- 使用 content: |2 并保证 YAML 缩进一致\n"
213
+ "示例:\n"
214
+ f"{ot('SEND_MESSAGE')}\n"
215
+ "to: 目标Agent名称\n"
216
+ "content: |2\n"
217
+ " 这里填写要发送的消息内容\n"
218
+ f"{ct('SEND_MESSAGE')}"
219
+ )
220
+ except Exception as e:
221
+ return (
222
+ False,
223
+ f"SEND_MESSAGE YAML 解析失败:{str(e)}\n"
224
+ "修复建议:\n"
225
+ "- 检查冒号、缩进与引号是否正确\n"
226
+ "- 使用 content: |2 多行块以避免缩进歧义\n"
227
+ "示例:\n"
228
+ f"{ot('SEND_MESSAGE')}\n"
229
+ "to: 目标Agent名称\n"
230
+ "content: |2\n"
231
+ " 这里填写要发送的消息内容\n"
232
+ f"{ct('SEND_MESSAGE')}"
77
233
  )
78
- if len(send_messages) == 0:
79
- return False, ""
80
- return True, send_messages[0]
81
234
 
82
235
  def name(self) -> str:
83
236
  return "SEND_MESSAGE"
@@ -89,16 +242,38 @@ content: |2
89
242
  Args:
90
243
  content: The content containing send message
91
244
  """
92
- if ot("SEND_MESSAGE") in content and ct("SEND_MESSAGE") not in content:
93
- content += "\n" + ct("SEND_MESSAGE")
94
- data = re.findall(
95
- ot("SEND_MESSAGE") + r"\n(.*?)\n" + ct("SEND_MESSAGE"), content, re.DOTALL
245
+ # Normalize line endings to handle CRLF/CR cases to ensure robust matching
246
+ try:
247
+ normalized = content.replace("\r\n", "\n").replace("\r", "\n")
248
+ except Exception:
249
+ normalized = content
250
+
251
+ ot_tag = ot("SEND_MESSAGE")
252
+ ct_tag = ct("SEND_MESSAGE")
253
+
254
+ # Auto-append closing tag if missing
255
+ if ot_tag in normalized and ct_tag not in normalized:
256
+ normalized += "\n" + ct_tag
257
+
258
+ # Use robust regex with DOTALL; escape tags to avoid regex meta issues
259
+ pattern = re.compile(
260
+ rf"{re.escape(ot_tag)}[ \t]*\n(.*?)(?:\n)?[ \t]*{re.escape(ct_tag)}",
261
+ re.DOTALL,
96
262
  )
263
+ data = pattern.findall(normalized)
264
+ # Fallback: handle cases without explicit newlines around closing tag
265
+ if not data:
266
+ alt_pattern = re.compile(
267
+ rf"{re.escape(ot_tag)}[ \t]*(.*?)[ \t]*{re.escape(ct_tag)}",
268
+ re.DOTALL,
269
+ )
270
+ data = alt_pattern.findall(normalized)
271
+
97
272
  ret = []
98
273
  for item in data:
99
274
  try:
100
275
  msg = yaml.safe_load(item)
101
- if "to" in msg and "content" in msg:
276
+ if isinstance(msg, dict) and "to" in msg and "content" in msg:
102
277
  ret.append(msg)
103
278
  except Exception:
104
279
  continue
@@ -113,24 +288,22 @@ content: |2
113
288
 
114
289
  config = self.agents_config_map[name].copy()
115
290
 
291
+ # Prepend common system prompt if configured
292
+ common_sp = getattr(self, "common_system_prompt", "")
293
+ if common_sp:
294
+ existing_sp = config.get("system_prompt", "")
295
+ if existing_sp:
296
+ config["system_prompt"] = f"{common_sp}\n\n{existing_sp}"
297
+ else:
298
+ config["system_prompt"] = common_sp
299
+
116
300
  if name != self.main_agent_name and self.original_question:
117
301
  system_prompt = config.get("system_prompt", "")
118
302
  config["system_prompt"] = (
119
303
  f"{system_prompt}\n\n# 原始问题\n{self.original_question}"
120
304
  )
121
305
 
122
- output_handler = config.get("output_handler", [])
123
- if len(output_handler) == 0:
124
- output_handler = [
125
- ToolRegistry(),
126
- self,
127
- ]
128
- else:
129
- if not any(isinstance(h, MultiAgent) for h in output_handler):
130
- output_handler.append(self)
131
- config["output_handler"] = output_handler
132
-
133
- agent = Agent(**config)
306
+ agent = Agent(output_handler=[ToolRegistry(), EditFileHandler(), RewriteFileHandler(), self],**config)
134
307
  self.agents[name] = agent
135
308
  return agent
136
309
 
@@ -204,6 +377,13 @@ content: {msg['content']}
204
377
  if not agent:
205
378
  return f"智能体 {to_agent_name} 未找到"
206
379
 
380
+ # Check if the sending agent should be cleared
381
+ sender_config = self.agents_config_map.get(last_agent_name, {})
382
+ if sender_config.get("clear_after_send_message"):
383
+ if agent:
384
+ PrettyOutput.print(f"清除智能体 {last_agent_name} 在发送消息后的历史记录...", OutputType.INFO)
385
+ agent.clear_history()
386
+
207
387
  last_agent_name = agent.name
208
388
  msg = agent.run(prompt)
209
389
  return ""
@@ -20,6 +20,9 @@ def cli(
20
20
  user_input: Optional[str] = typer.Option(
21
21
  None, "--input", "-i", help="用户输入(可选)"
22
22
  ),
23
+ model_group: Optional[str] = typer.Option(
24
+ None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
25
+ ),
23
26
  non_interactive: bool = typer.Option(
24
27
  False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
25
28
  ),
@@ -45,6 +48,8 @@ def cli(
45
48
  try:
46
49
  if non_interactive:
47
50
  set_config("JARVIS_NON_INTERACTIVE", True)
51
+ if model_group:
52
+ set_config("JARVIS_LLM_GROUP", str(model_group))
48
53
  except Exception:
49
54
  # 静默忽略同步异常,不影响主流程
50
55
  pass
@@ -61,7 +66,11 @@ def cli(
61
66
  raise ValueError("必须指定main_agent作为主智能体")
62
67
 
63
68
  # 创建并运行多智能体系统
64
- multi_agent = MultiAgent(agents_config, main_agent_name)
69
+ multi_agent = MultiAgent(
70
+ agents_config,
71
+ main_agent_name,
72
+ common_system_prompt=str(config_data.get("common_system_prompt", "") or "")
73
+ )
65
74
  final_input = (
66
75
  user_input
67
76
  if user_input is not None
@@ -24,6 +24,7 @@ from jarvis.jarvis_utils.config import (
24
24
  )
25
25
  from jarvis.jarvis_utils.embedding import split_text_into_chunks
26
26
  from jarvis.jarvis_utils.globals import set_in_chat, get_interrupt, console
27
+ import jarvis.jarvis_utils.globals as G
27
28
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
28
29
  from jarvis.jarvis_utils.tag import ct, ot
29
30
  from jarvis.jarvis_utils.utils import get_context_token_count, while_success, while_true
@@ -83,6 +84,11 @@ class BasePlatform(ABC):
83
84
 
84
85
  start_time = time.time()
85
86
 
87
+ # 当输入为空白字符串时,打印警告并直接返回空字符串
88
+ if message.strip() == "":
89
+ PrettyOutput.print("输入为空白字符串,已忽略本次请求", OutputType.WARNING)
90
+ return ""
91
+
86
92
  input_token_count = get_context_token_count(message)
87
93
 
88
94
  if input_token_count > get_max_input_token_count(self.model_group):
@@ -133,7 +139,9 @@ class BasePlatform(ABC):
133
139
  first_chunk = None
134
140
 
135
141
  with Status(
136
- f"🤔 {self.name()} 正在思考中...", spinner="dots", console=console
142
+ f"🤔 {(G.current_agent_name + ' · ') if G.current_agent_name else ''}{self.name()} 正在思考中...",
143
+ spinner="dots",
144
+ console=console,
137
145
  ):
138
146
  try:
139
147
  while True:
@@ -147,7 +155,7 @@ class BasePlatform(ABC):
147
155
  text_content = Text(overflow="fold")
148
156
  panel = Panel(
149
157
  text_content,
150
- title=f"[bold cyan]{self.name()}[/bold cyan]",
158
+ title=f"[bold cyan]{(G.current_agent_name + ' · ') if G.current_agent_name else ''}{self.name()}[/bold cyan]",
151
159
  subtitle="[yellow]正在回答... (按 Ctrl+C 中断)[/yellow]",
152
160
  border_style="bright_blue",
153
161
  box=box.ROUNDED,
@@ -227,7 +235,7 @@ class BasePlatform(ABC):
227
235
  else:
228
236
  # Print a clear prefix line before streaming model output (non-pretty mode)
229
237
  console.print(
230
- f"🤖 模型输出 - {self.name()} (按 Ctrl+C 中断)",
238
+ f"🤖 模型输出 - {(G.current_agent_name + ' · ') if G.current_agent_name else ''}{self.name()} (按 Ctrl+C 中断)",
231
239
  soft_wrap=False,
232
240
  )
233
241
  for s in self.chat(message):
@@ -369,9 +377,10 @@ class BasePlatform(ABC):
369
377
  return
370
378
 
371
379
  if self._session_history_file is None:
372
- # Ensure data directory exists
380
+ # Ensure session history directory exists under data directory
373
381
  data_dir = get_data_dir()
374
- os.makedirs(data_dir, exist_ok=True)
382
+ session_dir = os.path.join(data_dir, "session_history")
383
+ os.makedirs(session_dir, exist_ok=True)
375
384
 
376
385
  # Build a safe filename including platform, model and timestamp
377
386
  try:
@@ -389,7 +398,7 @@ class BasePlatform(ABC):
389
398
  ts = datetime.now().strftime("%Y%m%d_%H%M%S")
390
399
 
391
400
  self._session_history_file = os.path.join(
392
- data_dir, f"session_history_{safe_platform}_{safe_model}_{ts}.log"
401
+ session_dir, f"session_history_{safe_platform}_{safe_model}_{ts}.log"
393
402
  )
394
403
 
395
404
  # Append record
@@ -5,7 +5,7 @@ sub_agent 工具
5
5
 
6
6
  约定:
7
7
  - 必填参数:task, name, background, system_prompt, summary_prompt, use_tools
8
- - 继承父 Agent 的部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer;其他参数需显式提供
8
+ - 继承父 Agent 的部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer、non_interactive、use_methodology、use_analysis;其他参数需显式提供
9
9
  - 子Agent必须自动完成(auto_complete=True)且需要summary(need_summary=True)
10
10
  """
11
11
  from typing import Any, Dict, List
@@ -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部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer、non_interactive、use_methodology、use_analysis;其他参数需显式提供,自动完成并生成总结)。"
31
31
  parameters = {
32
32
  "type": "object",
33
33
  "properties": {
@@ -51,17 +51,6 @@ 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
- ),
64
- },
65
54
  },
66
55
  "required": [
67
56
  "task",
@@ -69,7 +58,6 @@ class SubAgentTool:
69
58
  "background",
70
59
  "system_prompt",
71
60
  "summary_prompt",
72
- "use_tools",
73
61
  ],
74
62
  }
75
63
 
@@ -105,16 +93,6 @@ class SubAgentTool:
105
93
  summary_prompt = str(args.get("summary_prompt", "")).strip()
106
94
  agent_name = str(args.get("name", "")).strip()
107
95
 
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
96
  errors = []
119
97
  if not system_prompt:
120
98
  errors.append("system_prompt 不能为空")
@@ -122,8 +100,6 @@ class SubAgentTool:
122
100
  errors.append("summary_prompt 不能为空")
123
101
  if not agent_name:
124
102
  errors.append("name 不能为空")
125
- if not use_tools:
126
- errors.append("use_tools 不能为空")
127
103
  if not background:
128
104
  errors.append("background 不能为空")
129
105
 
@@ -139,12 +115,18 @@ class SubAgentTool:
139
115
  parent_model_group = None
140
116
  parent_execute_tool_confirm = None
141
117
  parent_multiline_inputer = None
118
+ parent_non_interactive = None
119
+ parent_use_methodology = None
120
+ parent_use_analysis = None
142
121
  try:
143
122
  if parent_agent is not None:
144
123
  if getattr(parent_agent, "model", None):
145
124
  parent_model_group = getattr(parent_agent.model, "model_group", None)
146
125
  parent_execute_tool_confirm = getattr(parent_agent, "execute_tool_confirm", None)
147
126
  parent_multiline_inputer = getattr(parent_agent, "multiline_inputer", None)
127
+ parent_non_interactive = getattr(parent_agent, "non_interactive", None)
128
+ parent_use_methodology = getattr(parent_agent, "use_methodology", None)
129
+ parent_use_analysis = getattr(parent_agent, "use_analysis", None)
148
130
  except Exception:
149
131
  # 安全兜底:无法从父Agent获取配置则保持为None,使用系统默认
150
132
  pass
@@ -156,23 +138,17 @@ class SubAgentTool:
156
138
  model_group=parent_model_group,
157
139
  summary_prompt=summary_prompt,
158
140
  auto_complete=auto_complete,
159
- output_handler=None,
160
141
  use_tools=None,
161
142
  execute_tool_confirm=parent_execute_tool_confirm,
162
143
  need_summary=need_summary,
163
144
  multiline_inputer=parent_multiline_inputer,
164
- use_methodology=None,
165
- use_analysis=None,
145
+ use_methodology=parent_use_methodology,
146
+ use_analysis=parent_use_analysis,
166
147
  force_save_memory=None,
167
148
  files=None,
149
+ non_interactive=parent_non_interactive,
168
150
  )
169
151
 
170
- # 设置可用工具列表
171
- try:
172
- agent.set_use_tools(use_tools)
173
- except Exception:
174
- pass
175
-
176
152
  # 校验子Agent所用模型是否有效,必要时回退到平台可用模型
177
153
  try:
178
154
  platform = getattr(agent, "model", None)
@@ -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 转换为工具错误,避免终止进程
@@ -779,3 +779,13 @@ def is_non_interactive() -> bool:
779
779
  # 忽略环境变量解析异常,回退到配置
780
780
  pass
781
781
  return GLOBAL_CONFIG_DATA.get("JARVIS_NON_INTERACTIVE", False) is True
782
+
783
+
784
+ def is_skip_predefined_tasks() -> bool:
785
+ """
786
+ 是否跳过预定义任务加载。
787
+
788
+ 返回:
789
+ bool: 如果跳过预定义任务加载则返回True,默认为False
790
+ """
791
+ return GLOBAL_CONFIG_DATA.get("JARVIS_SKIP_PREDEFINED_TASKS", False) is True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire