jarvis-ai-assistant 0.1.32__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. jarvis/__init__.py +3 -0
  2. jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
  3. jarvis/__pycache__/agent.cpython-313.pyc +0 -0
  4. jarvis/__pycache__/main.cpython-313.pyc +0 -0
  5. jarvis/__pycache__/models.cpython-313.pyc +0 -0
  6. jarvis/__pycache__/tools.cpython-313.pyc +0 -0
  7. jarvis/__pycache__/utils.cpython-313.pyc +0 -0
  8. jarvis/__pycache__/zte_llm.cpython-313.pyc +0 -0
  9. jarvis/agent.py +289 -0
  10. jarvis/main.py +148 -0
  11. jarvis/models/__init__.py +3 -0
  12. jarvis/models/__pycache__/__init__.cpython-313.pyc +0 -0
  13. jarvis/models/__pycache__/base.cpython-313.pyc +0 -0
  14. jarvis/models/__pycache__/kimi.cpython-313.pyc +0 -0
  15. jarvis/models/__pycache__/openai.cpython-313.pyc +0 -0
  16. jarvis/models/__pycache__/oyi.cpython-313.pyc +0 -0
  17. jarvis/models/__pycache__/registry.cpython-313.pyc +0 -0
  18. jarvis/models/base.py +39 -0
  19. jarvis/models/kimi.py +389 -0
  20. jarvis/models/openai.py +96 -0
  21. jarvis/models/oyi.py +271 -0
  22. jarvis/models/registry.py +199 -0
  23. jarvis/tools/__init__.py +5 -0
  24. jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  25. jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
  26. jarvis/tools/__pycache__/bing_search.cpython-313.pyc +0 -0
  27. jarvis/tools/__pycache__/calculator.cpython-313.pyc +0 -0
  28. jarvis/tools/__pycache__/calculator_tool.cpython-313.pyc +0 -0
  29. jarvis/tools/__pycache__/file_ops.cpython-313.pyc +0 -0
  30. jarvis/tools/__pycache__/generator.cpython-313.pyc +0 -0
  31. jarvis/tools/__pycache__/methodology.cpython-313.pyc +0 -0
  32. jarvis/tools/__pycache__/python_script.cpython-313.pyc +0 -0
  33. jarvis/tools/__pycache__/rag.cpython-313.pyc +0 -0
  34. jarvis/tools/__pycache__/registry.cpython-313.pyc +0 -0
  35. jarvis/tools/__pycache__/search.cpython-313.pyc +0 -0
  36. jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
  37. jarvis/tools/__pycache__/sub_agent.cpython-313.pyc +0 -0
  38. jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc +0 -0
  39. jarvis/tools/__pycache__/user_input.cpython-313.pyc +0 -0
  40. jarvis/tools/__pycache__/user_interaction.cpython-313.pyc +0 -0
  41. jarvis/tools/__pycache__/webpage.cpython-313.pyc +0 -0
  42. jarvis/tools/base.py +23 -0
  43. jarvis/tools/file_ops.py +110 -0
  44. jarvis/tools/generator.py +172 -0
  45. jarvis/tools/methodology.py +145 -0
  46. jarvis/tools/registry.py +183 -0
  47. jarvis/tools/shell.py +78 -0
  48. jarvis/tools/sub_agent.py +82 -0
  49. jarvis/utils.py +202 -0
  50. jarvis_ai_assistant-0.1.32.dist-info/LICENSE +21 -0
  51. jarvis_ai_assistant-0.1.32.dist-info/METADATA +345 -0
  52. jarvis_ai_assistant-0.1.32.dist-info/RECORD +55 -0
  53. jarvis_ai_assistant-0.1.32.dist-info/WHEEL +5 -0
  54. jarvis_ai_assistant-0.1.32.dist-info/entry_points.txt +2 -0
  55. jarvis_ai_assistant-0.1.32.dist-info/top_level.txt +1 -0
@@ -0,0 +1,172 @@
1
+ from typing import Dict, Any
2
+ from pathlib import Path
3
+ from jarvis.models.registry import ModelRegistry
4
+ from jarvis.tools.registry import ToolRegistry
5
+ from jarvis.utils import OutputType, PrettyOutput
6
+
7
+ class ToolGeneratorTool:
8
+ name = "generate_tool"
9
+ description = "生成新的工具代码并自动注册到Jarvis,自动扩充Jarvis的能力"
10
+ parameters = {
11
+ "type": "object",
12
+ "properties": {
13
+ "tool_name": {
14
+ "type": "string",
15
+ "description": "工具的名称(snake_case格式)"
16
+ },
17
+ "class_name": {
18
+ "type": "string",
19
+ "description": "工具类的名称(PascalCase格式)"
20
+ },
21
+ "description": {
22
+ "type": "string",
23
+ "description": "工具的功能描述"
24
+ },
25
+ "parameters": {
26
+ "type": "object",
27
+ "description": "工具参数的JSON Schema定义"
28
+ }
29
+ },
30
+ "required": ["tool_name", "class_name", "description", "parameters"]
31
+ }
32
+
33
+ def __init__(self):
34
+ """初始化工具生成器
35
+ """
36
+ # 设置工具目录
37
+ self.tools_dir = Path.home() / '.jarvis_tools'
38
+
39
+ # 确保工具目录存在
40
+ self.tools_dir.mkdir(parents=True, exist_ok=True)
41
+
42
+ def _generate_tool_code(self, tool_name: str, class_name: str, description: str, parameters: Dict) -> str:
43
+ """使用大模型生成工具代码"""
44
+ model = ModelRegistry.get_global_model()
45
+
46
+ prompt = f"""请生成一个Python工具类的代码,要求如下,除了代码,不要输出任何内容:
47
+
48
+ 1. 类名: {class_name}
49
+ 2. 工具名称: {tool_name}
50
+ 3. 功能描述: {description}
51
+ 4. 参数定义: {parameters}
52
+
53
+ 严格按照以下格式生成代码(各函数的参数和返回值一定要与示例一致):
54
+
55
+ ```python
56
+ from typing import Dict, Any, Protocol, Optional
57
+ from jarvis.utils import OutputType, PrettyOutput
58
+ from jarvis.models.registry import ModelRegistry
59
+
60
+ class ExampleTool:
61
+ name = "example_tool"
62
+ description = "示例工具"
63
+ parameters = {{
64
+ "type": "object",
65
+ "properties": {{
66
+ "param1": {{"type": "string"}}
67
+ }},
68
+ "required": ["param1"]
69
+ }}
70
+
71
+ def __init__(self):
72
+ self.model = ModelRegistry.get_global_model()
73
+
74
+ def execute(self, args: Dict) -> Dict[str, Any]:
75
+ try:
76
+ # 验证参数示例
77
+ if "param1" not in args:
78
+ return {{"success": False, "error": "缺少必需参数: param1"}}
79
+
80
+ # 记录操作示例
81
+ PrettyOutput.print(f"处理参数: {{args['param1']}}", OutputType.INFO)
82
+
83
+ # 使用大模型示例
84
+ response = self.model.chat("prompt")
85
+
86
+ # 实现具体功能
87
+ result = "处理结果"
88
+
89
+ return {{
90
+ "success": True,
91
+ "stdout": result,
92
+ "stderr": ""
93
+ }}
94
+ except Exception as e:
95
+ PrettyOutput.print(str(e), OutputType.ERROR)
96
+ return {{
97
+ "success": False,
98
+ "error": str(e)
99
+ }}
100
+ ```"""
101
+
102
+ # 调用模型生成代码
103
+ response = model.chat(prompt)
104
+ model.delete_chat()
105
+
106
+ # 提取代码块
107
+ code_start = response.find("```python")
108
+ code_end = response.find("```", code_start + 9)
109
+
110
+ if code_start == -1 or code_end == -1:
111
+ # 如果没有找到代码块标记,假设整个响应都是代码
112
+ return response
113
+
114
+ # 提取代码块内容(去掉```python和```标记)
115
+ code = response[code_start + 9:code_end].strip()
116
+ return code
117
+
118
+ def execute(self, args: Dict) -> Dict[str, Any]:
119
+ """生成工具代码"""
120
+ try:
121
+ tool_name = args["tool_name"]
122
+ class_name = args["class_name"]
123
+ description = args["description"]
124
+ parameters = args["parameters"]
125
+
126
+ PrettyOutput.print(f"开始生成工具: {tool_name}", OutputType.INFO)
127
+
128
+ # 生成工具代码
129
+ tool_code = self._generate_tool_code(
130
+ tool_name,
131
+ class_name,
132
+ description,
133
+ parameters
134
+ )
135
+
136
+ # 获取工具文件路径
137
+ tool_file = self.tools_dir / f"{tool_name}.py"
138
+
139
+ # 写入工具文件
140
+ with open(tool_file, "w", encoding="utf-8") as f:
141
+ f.write(tool_code)
142
+
143
+ # 创建或更新 __init__.py
144
+ init_file = self.tools_dir / "__init__.py"
145
+ if not init_file.exists():
146
+ with open(init_file, "w", encoding="utf-8") as f:
147
+ f.write("# Jarvis Tools\n")
148
+
149
+ # 注册工具
150
+ success = ToolRegistry.get_global_tool_registry().register_tool_by_file(tool_file)
151
+ if not success:
152
+ return {
153
+ "success": False,
154
+ "error": "工具生成成功但注册失败"
155
+ }
156
+
157
+ return {
158
+ "success": True,
159
+ "stdout": f"工具已生成并注册到Jarvis\n"
160
+ f"工具目录: {self.tools_dir}\n"
161
+ f"工具名称: {tool_name}\n"
162
+ f"工具描述: {description}\n"
163
+ f"工具参数: {parameters}",
164
+ "stderr": ""
165
+ }
166
+
167
+ except Exception as e:
168
+ PrettyOutput.print(str(e), OutputType.ERROR)
169
+ return {
170
+ "success": False,
171
+ "error": f"生成工具失败: {str(e)}"
172
+ }
@@ -0,0 +1,145 @@
1
+ import os
2
+ import yaml
3
+ from typing import Dict, Optional, Any
4
+ from jarvis.utils import OutputType, PrettyOutput
5
+
6
+
7
+ class MethodologyTool:
8
+ """经验管理工具"""
9
+
10
+ name = "methodology"
11
+ description = "管理问题处理方法论,支持添加、更新、删除操作"
12
+ parameters = {
13
+ "type": "object",
14
+ "properties": {
15
+ "operation": {
16
+ "type": "string",
17
+ "description": "操作类型 (delete/update/add)",
18
+ "enum": ["delete", "update", "add"]
19
+ },
20
+ "problem_type": {
21
+ "type": "string",
22
+ "description": "问题类型,例如:code_review, bug_fix 等"
23
+ },
24
+ "content": {
25
+ "type": "string",
26
+ "description": "方法论内容 (update/add 时必需)",
27
+ "optional": True
28
+ }
29
+ },
30
+ "required": ["operation", "problem_type"]
31
+ }
32
+
33
+ def __init__(self):
34
+ """初始化经验管理工具"""
35
+ self.methodology_file = os.path.expanduser("~/.jarvis_methodology")
36
+ self._ensure_file_exists()
37
+
38
+ def _ensure_file_exists(self):
39
+ """确保方法论文件存在"""
40
+ if not os.path.exists(self.methodology_file):
41
+ try:
42
+ with open(self.methodology_file, 'w', encoding='utf-8') as f:
43
+ yaml.safe_dump({}, f, allow_unicode=True)
44
+ except Exception as e:
45
+ PrettyOutput.print(f"创建方法论文件失败: {str(e)}", OutputType.ERROR)
46
+
47
+ def _load_methodologies(self) -> Dict:
48
+ """加载所有方法论"""
49
+ try:
50
+ with open(self.methodology_file, 'r', encoding='utf-8') as f:
51
+ return yaml.safe_load(f) or {}
52
+ except Exception as e:
53
+ PrettyOutput.print(f"加载方法论失败: {str(e)}", OutputType.ERROR)
54
+ return {}
55
+
56
+ def _save_methodologies(self, methodologies: Dict):
57
+ """保存所有方法论"""
58
+ try:
59
+ with open(self.methodology_file, 'w', encoding='utf-8') as f:
60
+ yaml.safe_dump(methodologies, f, allow_unicode=True)
61
+ except Exception as e:
62
+ PrettyOutput.print(f"保存方法论失败: {str(e)}", OutputType.ERROR)
63
+
64
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
65
+ """执行方法论管理操作
66
+
67
+ Args:
68
+ args: 包含操作参数的字典
69
+ - operation: 操作类型 (delete/update/add)
70
+ - problem_type: 问题类型
71
+ - content: 方法论内容 (update/add 时必需)
72
+
73
+ Returns:
74
+ Dict[str, Any]: 包含执行结果的字典
75
+ """
76
+ operation = args.get("operation")
77
+ problem_type = args.get("problem_type")
78
+ content = args.get("content")
79
+
80
+ if not operation or not problem_type:
81
+ return {
82
+ "success": False,
83
+ "error": "缺少必要参数: operation 和 problem_type"
84
+ }
85
+
86
+ methodologies = self._load_methodologies()
87
+
88
+ try:
89
+ if operation == "delete":
90
+ if problem_type in methodologies:
91
+ del methodologies[problem_type]
92
+ self._save_methodologies(methodologies)
93
+ return {
94
+ "success": True,
95
+ "stdout": f"已删除问题类型 '{problem_type}' 的方法论"
96
+ }
97
+ else:
98
+ return {
99
+ "success": False,
100
+ "error": f"未找到问题类型 '{problem_type}' 的方法论"
101
+ }
102
+
103
+ elif operation in ["update", "add"]:
104
+ if not content:
105
+ return {
106
+ "success": False,
107
+ "error": f"{operation} 操作需要提供方法论内容"
108
+ }
109
+
110
+ if operation == "update" and problem_type not in methodologies:
111
+ return {
112
+ "success": False,
113
+ "error": f"未找到问题类型 '{problem_type}' 的方法论,无法更新"
114
+ }
115
+
116
+ methodologies[problem_type] = content
117
+ self._save_methodologies(methodologies)
118
+ return {
119
+ "success": True,
120
+ "stdout": f"已{'更新' if operation == 'update' else '添加'}问题类型 '{problem_type}' 的方法论"
121
+ }
122
+
123
+ else:
124
+ return {
125
+ "success": False,
126
+ "error": f"不支持的操作类型: {operation}"
127
+ }
128
+
129
+ except Exception as e:
130
+ return {
131
+ "success": False,
132
+ "error": f"执行失败: {str(e)}"
133
+ }
134
+
135
+ def get_methodology(self, problem_type: str) -> Optional[str]:
136
+ """获取指定问题类型的方法论
137
+
138
+ Args:
139
+ problem_type: 问题类型
140
+
141
+ Returns:
142
+ Optional[str]: 方法论内容,如果不存在则返回 None
143
+ """
144
+ methodologies = self._load_methodologies()
145
+ return methodologies.get(problem_type)
@@ -0,0 +1,183 @@
1
+
2
+ import importlib
3
+ import json
4
+ from pathlib import Path
5
+ import sys
6
+ from typing import Any, Callable, Dict, List, Optional
7
+
8
+ from jarvis.models.registry import ModelRegistry
9
+ from jarvis.tools.base import Tool
10
+ from jarvis.utils import OutputType, PrettyOutput
11
+
12
+
13
+ class ToolRegistry:
14
+ global_tool_registry = None # type: ignore
15
+ def __init__(self):
16
+ """初始化工具注册器
17
+ """
18
+ self.tools: Dict[str, Tool] = {}
19
+ # 加载内置工具和外部工具
20
+ self._load_builtin_tools()
21
+ self._load_external_tools()
22
+
23
+ @staticmethod
24
+ def get_global_tool_registry():
25
+ """获取全局工具注册器"""
26
+ if ToolRegistry.global_tool_registry is None:
27
+ ToolRegistry.global_tool_registry = ToolRegistry()
28
+ return ToolRegistry.global_tool_registry
29
+
30
+ def _load_builtin_tools(self):
31
+ """从内置tools目录加载工具"""
32
+ tools_dir = Path(__file__).parent
33
+
34
+ # 遍历目录下的所有.py文件
35
+ for file_path in tools_dir.glob("*.py"):
36
+ # 跳过基础文件和__init__.py
37
+ if file_path.name in ["base.py", "__init__.py", "registry.py"]:
38
+ continue
39
+
40
+ self.register_tool_by_file(file_path)
41
+
42
+ def _load_external_tools(self):
43
+ """从~/.jarvis_tools加载外部工具"""
44
+ external_tools_dir = Path.home() / '.jarvis_tools'
45
+ if not external_tools_dir.exists():
46
+ return
47
+
48
+ # 遍历目录下的所有.py文件
49
+ for file_path in external_tools_dir.glob("*.py"):
50
+ # 跳过__init__.py
51
+ if file_path.name == "__init__.py":
52
+ continue
53
+
54
+ self.register_tool_by_file(file_path)
55
+
56
+ def register_tool_by_file(self, file_path: str):
57
+ """从指定文件加载并注册工具
58
+
59
+ Args:
60
+ file_path: 工具文件的路径
61
+
62
+ Returns:
63
+ bool: 是否成功加载工具
64
+ """
65
+ try:
66
+ file_path = Path(file_path).resolve() # 获取绝对路径
67
+ if not file_path.exists() or not file_path.is_file():
68
+ PrettyOutput.print(f"文件不存在: {file_path}", OutputType.ERROR)
69
+ return False
70
+
71
+ # 动态导入模块
72
+ module_name = file_path.stem
73
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
74
+ if not spec or not spec.loader:
75
+ PrettyOutput.print(f"无法加载模块: {file_path}", OutputType.ERROR)
76
+ return False
77
+
78
+ module = importlib.util.module_from_spec(spec)
79
+ sys.modules[module_name] = module # 添加到 sys.modules 以支持相对导入
80
+ spec.loader.exec_module(module)
81
+
82
+ # 查找模块中的工具类
83
+ tool_found = False
84
+ for item_name in dir(module):
85
+ item = getattr(module, item_name)
86
+ # 检查是否是类,并且有必要的属性
87
+ if (isinstance(item, type) and
88
+ hasattr(item, 'name') and
89
+ hasattr(item, 'description') and
90
+ hasattr(item, 'parameters')):
91
+
92
+ # 实例化工具类,传入模型和输出处理器
93
+ tool_instance = item()
94
+
95
+ # 注册工具
96
+ self.register_tool(
97
+ name=tool_instance.name,
98
+ description=tool_instance.description,
99
+ parameters=tool_instance.parameters,
100
+ func=tool_instance.execute
101
+ )
102
+ PrettyOutput.print(f"已加载工具: {tool_instance.name}: {tool_instance.description}", OutputType.INFO)
103
+ tool_found = True
104
+
105
+ if not tool_found:
106
+ PrettyOutput.print(f"文件中未找到有效的工具类: {file_path}", OutputType.WARNING)
107
+ return False
108
+
109
+ return True
110
+
111
+ except Exception as e:
112
+ PrettyOutput.print(f"加载工具失败 {file_path.name}: {str(e)}", OutputType.ERROR)
113
+ return False
114
+
115
+ def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
116
+ """注册新工具"""
117
+ self.tools[name] = Tool(name, description, parameters, func)
118
+
119
+ def get_tool(self, name: str) -> Optional[Tool]:
120
+ """获取工具"""
121
+ return self.tools.get(name)
122
+
123
+ def get_all_tools(self) -> List[Dict]:
124
+ """获取所有工具的Ollama格式定义"""
125
+ return [tool.to_dict() for tool in self.tools.values()]
126
+
127
+ def execute_tool(self, name: str, arguments: Dict) -> Dict[str, Any]:
128
+ """执行指定工具"""
129
+ tool = self.get_tool(name)
130
+ if tool is None:
131
+ return {"success": False, "error": f"Tool {name} does not exist"}
132
+ return tool.execute(arguments)
133
+
134
+ def handle_tool_calls(self, tool_calls: List[Dict]) -> str:
135
+ """处理工具调用,只处理第一个工具"""
136
+ try:
137
+ if not tool_calls:
138
+ return ""
139
+
140
+ # 只处理第一个工具调用
141
+ tool_call = tool_calls[0]
142
+ name = tool_call["name"]
143
+ args = tool_call["arguments"]
144
+
145
+ if isinstance(args, str):
146
+ try:
147
+ args = json.loads(args)
148
+ except json.JSONDecodeError:
149
+ PrettyOutput.print(f"工具参数格式无效: {name}", OutputType.ERROR)
150
+ return ""
151
+
152
+ # 显示工具调用信息
153
+ PrettyOutput.section(f"执行工具: {name}", OutputType.TOOL)
154
+ if isinstance(args, dict):
155
+ for key, value in args.items():
156
+ PrettyOutput.print(f"参数: {key} = {value}", OutputType.DEBUG)
157
+ else:
158
+ PrettyOutput.print(f"参数: {args}", OutputType.DEBUG)
159
+
160
+ # 执行工具调用
161
+ result = self.execute_tool(name, args)
162
+
163
+ # 处理结果
164
+ if result["success"]:
165
+ stdout = result["stdout"]
166
+ stderr = result.get("stderr", "")
167
+ output_parts = []
168
+ if stdout:
169
+ output_parts.append(f"输出:\n{stdout}")
170
+ if stderr:
171
+ output_parts.append(f"错误:\n{stderr}")
172
+ output = "\n\n".join(output_parts)
173
+ output = "没有输出和错误" if not output else output
174
+ PrettyOutput.section("执行成功", OutputType.SUCCESS)
175
+ else:
176
+ error_msg = result["error"]
177
+ output = f"执行失败: {error_msg}"
178
+ PrettyOutput.section("执行失败", OutputType.ERROR)
179
+
180
+ return output
181
+ except Exception as e:
182
+ PrettyOutput.print(f"执行工具失败: {str(e)}", OutputType.ERROR)
183
+ return f"Tool call failed: {str(e)}"
jarvis/tools/shell.py ADDED
@@ -0,0 +1,78 @@
1
+ from typing import Dict, Any
2
+ import os
3
+ import tempfile
4
+ from pathlib import Path
5
+
6
+ from jarvis.utils import OutputType, PrettyOutput
7
+
8
+
9
+ class ShellTool:
10
+ name = "execute_shell"
11
+ description = """执行shell命令并返回结果"""
12
+
13
+ parameters = {
14
+ "type": "object",
15
+ "properties": {
16
+ "command": {
17
+ "type": "string",
18
+ "description": "Shell command to execute"
19
+ }
20
+ },
21
+ "required": ["command"]
22
+ }
23
+
24
+
25
+ def _escape_command(self, cmd: str) -> str:
26
+ """转义命令中的特殊字符"""
27
+ return cmd.replace("'", "'\"'\"'")
28
+
29
+ def execute(self, args: Dict) -> Dict[str, Any]:
30
+ """执行shell命令"""
31
+ try:
32
+ command = args["command"]
33
+
34
+ # 生成临时文件名
35
+ output_file = os.path.join(tempfile.gettempdir(), f"jarvis_shell_{os.getpid()}.log")
36
+
37
+ # 转义命令中的特殊字符
38
+ escaped_command = self._escape_command(command)
39
+
40
+ # 修改命令以使用script
41
+ tee_command = f"script -q -c '{escaped_command}' {output_file}"
42
+
43
+ PrettyOutput.print(f"执行命令: {command}", OutputType.INFO)
44
+
45
+ # 执行命令
46
+ return_code = os.system(tee_command)
47
+
48
+ # 读取输出文件
49
+ try:
50
+ with open(output_file, 'r', encoding='utf-8', errors='replace') as f:
51
+ output = f.read()
52
+ # 移除script命令添加的头尾
53
+ if output:
54
+ lines = output.splitlines()
55
+ if len(lines) > 2:
56
+ output = "\n".join(lines[1:-1])
57
+ except Exception as e:
58
+ output = f"读取输出文件失败: {str(e)}"
59
+ finally:
60
+ # 清理临时文件
61
+ Path(output_file).unlink(missing_ok=True)
62
+
63
+ return {
64
+ "success": return_code == 0,
65
+ "stdout": output,
66
+ "stderr": "",
67
+ "return_code": return_code
68
+ }
69
+
70
+ except Exception as e:
71
+ # 确保清理临时文件
72
+ if 'output_file' in locals():
73
+ Path(output_file).unlink(missing_ok=True)
74
+ PrettyOutput.print(str(e), OutputType.ERROR)
75
+ return {
76
+ "success": False,
77
+ "error": str(e)
78
+ }
@@ -0,0 +1,82 @@
1
+ from typing import Dict, Any
2
+
3
+
4
+ from jarvis.agent import Agent
5
+ from jarvis.utils import OutputType, PrettyOutput
6
+
7
+
8
+ class SubAgentTool:
9
+ name = "create_sub_agent"
10
+ description = "创建一个子代理来处理特定任务,子代理会生成任务总结报告"
11
+ parameters = {
12
+ "type": "object",
13
+ "properties": {
14
+ "agent_name": {
15
+ "type": "string",
16
+ "description": "子代理的名称"
17
+ },
18
+ "task": {
19
+ "type": "string",
20
+ "description": "需要完成的具体任务"
21
+ },
22
+ "context": {
23
+ "type": "string",
24
+ "description": "任务相关的上下文信息",
25
+ "default": ""
26
+ },
27
+ "goal": {
28
+ "type": "string",
29
+ "description": "任务的完成目标",
30
+ "default": ""
31
+ },
32
+ "files": {
33
+ "type": "array",
34
+ "items": {"type": "string"},
35
+ "description": "相关文件路径列表,用于文件问答和处理",
36
+ "default": []
37
+ }
38
+ },
39
+ "required": ["agent_name", "task", "context", "goal"]
40
+ }
41
+
42
+
43
+ def execute(self, args: Dict) -> Dict[str, Any]:
44
+ """创建并运行子代理"""
45
+ try:
46
+ agent_name = args["agent_name"]
47
+ task = args["task"]
48
+ context = args.get("context", "")
49
+ goal = args.get("goal", "")
50
+ files = args.get("files", [])
51
+
52
+ PrettyOutput.print(f"创建子代理: {agent_name}", OutputType.INFO)
53
+
54
+ # 构建任务描述
55
+ task_description = task
56
+ if context:
57
+ task_description = f"上下文信息:\n{context}\n\n任务:\n{task}"
58
+ if goal:
59
+ task_description += f"\n\n完成目标:\n{goal}"
60
+
61
+ # 创建子代理
62
+ sub_agent = Agent(
63
+ name=agent_name,
64
+ is_sub_agent=True
65
+ )
66
+
67
+ # 运行子代理,传入文件列表
68
+ PrettyOutput.print("子代理开始执行任务...", OutputType.INFO)
69
+ result = sub_agent.run(task_description, file_list=files)
70
+
71
+ return {
72
+ "success": True,
73
+ "stdout": f"子代理任务完成\n\n{result}",
74
+ "stderr": ""
75
+ }
76
+
77
+ except Exception as e:
78
+ PrettyOutput.print(str(e), OutputType.ERROR)
79
+ return {
80
+ "success": False,
81
+ "error": f"子代理执行失败: {str(e)}"
82
+ }