jarvis-ai-assistant 0.3.20__py3-none-any.whl → 0.3.21__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 (57) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +24 -3
  3. jarvis/jarvis_agent/config_editor.py +5 -1
  4. jarvis/jarvis_agent/edit_file_handler.py +15 -9
  5. jarvis/jarvis_agent/jarvis.py +99 -3
  6. jarvis/jarvis_agent/memory_manager.py +3 -3
  7. jarvis/jarvis_agent/share_manager.py +3 -1
  8. jarvis/jarvis_agent/task_analyzer.py +0 -1
  9. jarvis/jarvis_agent/task_manager.py +15 -5
  10. jarvis/jarvis_agent/tool_executor.py +2 -2
  11. jarvis/jarvis_code_agent/code_agent.py +39 -16
  12. jarvis/jarvis_git_utils/git_commiter.py +3 -6
  13. jarvis/jarvis_mcp/sse_mcp_client.py +9 -3
  14. jarvis/jarvis_mcp/streamable_mcp_client.py +15 -5
  15. jarvis/jarvis_memory_organizer/memory_organizer.py +1 -1
  16. jarvis/jarvis_methodology/main.py +4 -4
  17. jarvis/jarvis_multi_agent/__init__.py +3 -3
  18. jarvis/jarvis_platform/base.py +10 -5
  19. jarvis/jarvis_platform/kimi.py +18 -6
  20. jarvis/jarvis_platform/tongyi.py +18 -5
  21. jarvis/jarvis_platform/yuanbao.py +10 -3
  22. jarvis/jarvis_platform_manager/main.py +21 -7
  23. jarvis/jarvis_platform_manager/service.py +4 -3
  24. jarvis/jarvis_rag/cli.py +61 -22
  25. jarvis/jarvis_rag/embedding_manager.py +10 -3
  26. jarvis/jarvis_rag/llm_interface.py +4 -1
  27. jarvis/jarvis_rag/query_rewriter.py +3 -1
  28. jarvis/jarvis_rag/rag_pipeline.py +11 -3
  29. jarvis/jarvis_rag/retriever.py +151 -2
  30. jarvis/jarvis_smart_shell/main.py +59 -18
  31. jarvis/jarvis_stats/cli.py +11 -9
  32. jarvis/jarvis_stats/stats.py +14 -8
  33. jarvis/jarvis_stats/storage.py +23 -6
  34. jarvis/jarvis_tools/cli/main.py +63 -29
  35. jarvis/jarvis_tools/edit_file.py +3 -4
  36. jarvis/jarvis_tools/file_analyzer.py +0 -1
  37. jarvis/jarvis_tools/generate_new_tool.py +3 -3
  38. jarvis/jarvis_tools/read_code.py +0 -1
  39. jarvis/jarvis_tools/read_webpage.py +14 -4
  40. jarvis/jarvis_tools/registry.py +0 -3
  41. jarvis/jarvis_tools/retrieve_memory.py +0 -1
  42. jarvis/jarvis_tools/save_memory.py +0 -1
  43. jarvis/jarvis_tools/search_web.py +0 -2
  44. jarvis/jarvis_tools/sub_agent.py +197 -0
  45. jarvis/jarvis_tools/sub_code_agent.py +194 -0
  46. jarvis/jarvis_tools/virtual_tty.py +21 -13
  47. jarvis/jarvis_utils/config.py +35 -5
  48. jarvis/jarvis_utils/input.py +297 -56
  49. jarvis/jarvis_utils/methodology.py +3 -1
  50. jarvis/jarvis_utils/output.py +5 -2
  51. jarvis/jarvis_utils/utils.py +480 -170
  52. {jarvis_ai_assistant-0.3.20.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/METADATA +10 -2
  53. {jarvis_ai_assistant-0.3.20.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/RECORD +57 -55
  54. {jarvis_ai_assistant-0.3.20.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/WHEEL +0 -0
  55. {jarvis_ai_assistant-0.3.20.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/entry_points.txt +0 -0
  56. {jarvis_ai_assistant-0.3.20.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/licenses/LICENSE +0 -0
  57. {jarvis_ai_assistant-0.3.20.dist-info → jarvis_ai_assistant-0.3.21.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,194 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ sub_code_agent 工具
4
+ 将子任务交给 CodeAgent 执行,并返回执行结果。
5
+
6
+ 约定:
7
+ - 仅接收一个参数:task
8
+ - 不依赖父 Agent,所有配置使用系统默认与全局变量
9
+ - 子Agent必须自动完成(auto_complete=True)且需要summary(need_summary=True)
10
+ """
11
+ from typing import Any, Dict, Optional
12
+ import json
13
+
14
+ from jarvis.jarvis_code_agent.code_agent import CodeAgent
15
+ from jarvis.jarvis_utils.globals import delete_agent
16
+ from jarvis.jarvis_code_agent import code_agent as code_agent_module
17
+
18
+
19
+ class SubCodeAgentTool:
20
+ """
21
+ 使用 CodeAgent 托管执行子任务,执行完立即清理内部 Agent。
22
+ - 不注册至全局
23
+ - 使用系统默认/全局配置
24
+ - 启用自动完成与总结
25
+ """
26
+
27
+ # 必须与文件名一致,供 ToolRegistry 自动注册
28
+ name = "sub_code_agent"
29
+ description = "将子任务交给 CodeAgent 执行,并返回执行结果(使用系统默认配置,自动完成并生成总结)。"
30
+ parameters = {
31
+ "type": "object",
32
+ "properties": {
33
+ "task": {
34
+ "type": "string",
35
+ "description": "要执行的子任务内容(必填)",
36
+ },
37
+ "background": {
38
+ "type": "string",
39
+ "description": "任务背景与已知信息(可选,将与任务一并提供给子Agent)",
40
+ },
41
+ },
42
+ "required": ["task"],
43
+ }
44
+
45
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
46
+ """
47
+ 执行代码子任务并返回结果(由 CodeAgent 托管执行)。
48
+ 返回:
49
+ - success: 是否成功
50
+ - stdout: CodeAgent 执行结果(字符串;若为 None 则返回“任务执行完成”)
51
+ - stderr: 错误信息(如有)
52
+ """
53
+ try:
54
+ task: str = str(args.get("task", "")).strip()
55
+ if not task:
56
+ return {
57
+ "success": False,
58
+ "stdout": "",
59
+ "stderr": "task 不能为空",
60
+ }
61
+
62
+ # 在模块级别打补丁,仅自动确认交互(允许用户输入)
63
+ def _auto_confirm(tip: str, default: bool = True) -> bool:
64
+ return default
65
+
66
+ code_agent_module.user_confirm = _auto_confirm
67
+
68
+ # 读取背景信息并组合任务
69
+ background: str = str(args.get("background", "")).strip()
70
+ enhanced_task = (
71
+ f"背景信息:\n{background}\n\n任务:\n{task}" if background else task
72
+ )
73
+
74
+ # 继承父Agent的模型组与工具使用集(用于覆盖默认值)
75
+ parent_agent = args.get("agent")
76
+ # 如未注入父Agent,尝试从全局获取当前或任一已注册Agent
77
+ if parent_agent is None:
78
+ try:
79
+ from jarvis.jarvis_utils import globals as G # 延迟导入避免循环
80
+
81
+ curr = getattr(G, "current_agent_name", "")
82
+ if curr:
83
+ parent_agent = getattr(G, "global_agents", {}).get(curr)
84
+ if parent_agent is None and getattr(G, "global_agents", {}):
85
+ try:
86
+ parent_agent = next(iter(G.global_agents.values()))
87
+ except Exception:
88
+ parent_agent = None
89
+ except Exception:
90
+ parent_agent = None
91
+ model_group = None
92
+ use_tools: list[str] = []
93
+ try:
94
+ if parent_agent is not None:
95
+ if getattr(parent_agent, "model", None):
96
+ model_group = getattr(parent_agent.model, "model_group", None)
97
+ parent_registry = parent_agent.get_tool_registry()
98
+ if parent_registry:
99
+ for t in parent_registry.get_all_tools():
100
+ if isinstance(t, dict) and t.get("name"):
101
+ use_tools.append(str(t["name"]))
102
+ except Exception:
103
+ pass
104
+
105
+ # 创建 CodeAgent:参数优先使用父Agent的配置(若可获取),否则使用默认
106
+ # 推断/继承 llm_type、need_summary、tool_group
107
+ llm_type = "normal"
108
+ tool_group = None
109
+ try:
110
+ if parent_agent is not None:
111
+ llm_type = getattr(parent_agent, "llm_type", llm_type)
112
+ tool_group = getattr(parent_agent, "tool_group", tool_group)
113
+ except Exception:
114
+ pass
115
+
116
+ # 依据父Agent已启用工具集,推导 append_tools(作为在 CodeAgent 基础工具上的增量)
117
+ append_tools = None
118
+ try:
119
+ base_tools = [
120
+ "execute_script",
121
+ "search_web",
122
+ "ask_user",
123
+ "read_code",
124
+ "rewrite_file",
125
+ "save_memory",
126
+ "retrieve_memory",
127
+ "clear_memory",
128
+ "sub_code_agent",
129
+ ]
130
+ if use_tools:
131
+ extras = [t for t in use_tools if t not in base_tools]
132
+ append_tools = ",".join(extras) if extras else None
133
+ except Exception:
134
+ append_tools = None
135
+
136
+ try:
137
+ code_agent = CodeAgent(
138
+ llm_type=llm_type,
139
+ model_group=model_group,
140
+ need_summary=True,
141
+ append_tools=append_tools,
142
+ tool_group=tool_group,
143
+ )
144
+ except SystemExit as se:
145
+ # 将底层 sys.exit 转换为工具错误,避免终止进程
146
+ return {
147
+ "success": False,
148
+ "stdout": "",
149
+ "stderr": f"初始化 CodeAgent 失败(可能未配置 git 或当前非 git 仓库): {se}",
150
+ }
151
+
152
+ # 子Agent需要自动完成
153
+ try:
154
+ code_agent.agent.auto_complete = True
155
+ # 同步父Agent工具使用集(如可用)
156
+ if use_tools:
157
+ code_agent.agent.set_use_tools(use_tools)
158
+ # 同步父Agent的模型名称(如可用),以尽量保持平台与模型一致
159
+ if (
160
+ parent_agent is not None
161
+ and getattr(parent_agent, "model", None)
162
+ and getattr(code_agent.agent, "model", None)
163
+ ):
164
+ try:
165
+ parent_model_name = parent_agent.model.name() # type: ignore[attr-defined]
166
+ if parent_model_name:
167
+ code_agent.agent.model.set_model_name(parent_model_name) # type: ignore[attr-defined]
168
+ except Exception:
169
+ pass
170
+ except Exception:
171
+ pass
172
+
173
+ # 执行子任务(无提交信息前后缀)
174
+ ret = code_agent.run(enhanced_task, prefix="", suffix="")
175
+ stdout = ret if isinstance(ret, str) and ret else "任务执行完成"
176
+
177
+ # 主动清理内部 Agent,避免污染父Agent的全局状态
178
+ try:
179
+ inner_agent = code_agent.agent
180
+ delete_agent(inner_agent.name)
181
+ except Exception:
182
+ pass
183
+
184
+ return {
185
+ "success": True,
186
+ "stdout": json.dumps({"result": stdout}, ensure_ascii=False, indent=2),
187
+ "stderr": "",
188
+ }
189
+ except Exception as e:
190
+ return {
191
+ "success": False,
192
+ "stdout": "",
193
+ "stderr": f"执行子任务失败: {str(e)}",
194
+ }
@@ -127,7 +127,9 @@ class VirtualTTYTool:
127
127
  try:
128
128
  if action == "launch":
129
129
  if args.get("keys", "") != "":
130
- PrettyOutput.print("启动虚拟终端时,不能同时指定 keys 参数", OutputType.ERROR)
130
+ PrettyOutput.print(
131
+ "启动虚拟终端时,不能同时指定 keys 参数", OutputType.ERROR
132
+ )
131
133
  return {
132
134
  "success": False,
133
135
  "stdout": "",
@@ -136,7 +138,9 @@ class VirtualTTYTool:
136
138
 
137
139
  result = self._launch_tty(agent, tty_id)
138
140
  if not result["success"]:
139
- PrettyOutput.print(f"启动虚拟终端 [{tty_id}] 失败", OutputType.ERROR)
141
+ PrettyOutput.print(
142
+ f"启动虚拟终端 [{tty_id}] 失败", OutputType.ERROR
143
+ )
140
144
  return result
141
145
  elif action == "send_keys":
142
146
  keys = args.get("keys", "").strip()
@@ -145,26 +149,34 @@ class VirtualTTYTool:
145
149
 
146
150
  result = self._input_command(agent, tty_id, keys, timeout, add_enter)
147
151
  if not result["success"]:
148
- PrettyOutput.print(f"发送按键序列到终端 [{tty_id}] 失败", OutputType.ERROR)
152
+ PrettyOutput.print(
153
+ f"发送按键序列到终端 [{tty_id}] 失败", OutputType.ERROR
154
+ )
149
155
  return result
150
156
  elif action == "output":
151
157
  timeout = args.get("timeout", 5.0) # 默认5秒超时
152
158
 
153
159
  result = self._get_output(agent, tty_id, timeout)
154
160
  if not result["success"]:
155
- PrettyOutput.print(f"获取终端 [{tty_id}] 输出失败", OutputType.ERROR)
161
+ PrettyOutput.print(
162
+ f"获取终端 [{tty_id}] 输出失败", OutputType.ERROR
163
+ )
156
164
  return result
157
165
  elif action == "close":
158
166
 
159
167
  result = self._close_tty(agent, tty_id)
160
168
  if not result["success"]:
161
- PrettyOutput.print(f"关闭虚拟终端 [{tty_id}] 失败", OutputType.ERROR)
169
+ PrettyOutput.print(
170
+ f"关闭虚拟终端 [{tty_id}] 失败", OutputType.ERROR
171
+ )
162
172
  return result
163
173
  elif action == "get_screen":
164
174
 
165
175
  result = self._get_screen(agent, tty_id)
166
176
  if not result["success"]:
167
- PrettyOutput.print(f"获取终端 [{tty_id}] 屏幕内容失败", OutputType.ERROR)
177
+ PrettyOutput.print(
178
+ f"获取终端 [{tty_id}] 屏幕内容失败", OutputType.ERROR
179
+ )
168
180
  return result
169
181
  elif action == "list":
170
182
 
@@ -230,8 +242,6 @@ class VirtualTTYTool:
230
242
  except BlockingIOError:
231
243
  continue
232
244
 
233
-
234
-
235
245
  return {"success": True, "stdout": output, "stderr": ""}
236
246
 
237
247
  except Exception as e:
@@ -297,8 +307,6 @@ class VirtualTTYTool:
297
307
  except _queue.Empty:
298
308
  continue
299
309
 
300
-
301
-
302
310
  return {"success": True, "stdout": output, "stderr": ""}
303
311
 
304
312
  except Exception as e:
@@ -668,9 +676,9 @@ class VirtualTTYTool:
668
676
  {
669
677
  "id": tty_id,
670
678
  "status": status,
671
- "pid": tty_data["process"].pid
672
- if tty_data["process"]
673
- else None,
679
+ "pid": (
680
+ tty_data["process"].pid if tty_data["process"] else None
681
+ ),
674
682
  "shell": tty_data["shell"],
675
683
  }
676
684
  )
@@ -296,7 +296,11 @@ def get_tool_load_dirs() -> List[str]:
296
296
  返回:
297
297
  List[str]: 工具加载目录列表
298
298
  """
299
- return GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_LOAD_DIRS", [])
299
+ return [
300
+ os.path.expanduser(os.path.expandvars(str(p)))
301
+ for p in GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_LOAD_DIRS", [])
302
+ if p
303
+ ]
300
304
 
301
305
 
302
306
  def get_methodology_dirs() -> List[str]:
@@ -306,7 +310,11 @@ def get_methodology_dirs() -> List[str]:
306
310
  返回:
307
311
  List[str]: 方法论加载目录列表
308
312
  """
309
- return GLOBAL_CONFIG_DATA.get("JARVIS_METHODOLOGY_DIRS", [])
313
+ return [
314
+ os.path.expanduser(os.path.expandvars(str(p)))
315
+ for p in GLOBAL_CONFIG_DATA.get("JARVIS_METHODOLOGY_DIRS", [])
316
+ if p
317
+ ]
310
318
 
311
319
 
312
320
  def get_agent_definition_dirs() -> List[str]:
@@ -316,7 +324,11 @@ def get_agent_definition_dirs() -> List[str]:
316
324
  返回:
317
325
  List[str]: agent 定义加载目录列表
318
326
  """
319
- return GLOBAL_CONFIG_DATA.get("JARVIS_AGENT_DEFINITION_DIRS", [])
327
+ return [
328
+ os.path.expanduser(os.path.expandvars(str(p)))
329
+ for p in GLOBAL_CONFIG_DATA.get("JARVIS_AGENT_DEFINITION_DIRS", [])
330
+ if p
331
+ ]
320
332
 
321
333
 
322
334
  def get_multi_agent_dirs() -> List[str]:
@@ -326,7 +338,11 @@ def get_multi_agent_dirs() -> List[str]:
326
338
  返回:
327
339
  List[str]: multi_agent 加载目录列表
328
340
  """
329
- return GLOBAL_CONFIG_DATA.get("JARVIS_MULTI_AGENT_DIRS", [])
341
+ return [
342
+ os.path.expanduser(os.path.expandvars(str(p)))
343
+ for p in GLOBAL_CONFIG_DATA.get("JARVIS_MULTI_AGENT_DIRS", [])
344
+ if p
345
+ ]
330
346
 
331
347
 
332
348
  def get_roles_dirs() -> List[str]:
@@ -336,7 +352,11 @@ def get_roles_dirs() -> List[str]:
336
352
  返回:
337
353
  List[str]: roles 加载目录列表
338
354
  """
339
- return GLOBAL_CONFIG_DATA.get("JARVIS_ROLES_DIRS", [])
355
+ return [
356
+ os.path.expanduser(os.path.expandvars(str(p)))
357
+ for p in GLOBAL_CONFIG_DATA.get("JARVIS_ROLES_DIRS", [])
358
+ if p
359
+ ]
340
360
 
341
361
 
342
362
  def get_central_methodology_repo() -> str:
@@ -369,6 +389,16 @@ def is_print_prompt() -> bool:
369
389
  return GLOBAL_CONFIG_DATA.get("JARVIS_PRINT_PROMPT", False) == True
370
390
 
371
391
 
392
+ def is_print_error_traceback() -> bool:
393
+ """
394
+ 获取是否在错误输出时打印回溯调用链。
395
+
396
+ 返回:
397
+ bool: 如果打印回溯则返回True,默认为False(不打印)
398
+ """
399
+ return GLOBAL_CONFIG_DATA.get("JARVIS_PRINT_ERROR_TRACEBACK", False) is True
400
+
401
+
372
402
  def is_force_save_memory() -> bool:
373
403
  """
374
404
  获取是否强制保存记忆。