jarvis-ai-assistant 0.1.46__py3-none-any.whl → 0.1.48__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- jarvis/__init__.py +1 -1
- jarvis/agent.py +32 -47
- jarvis/main.py +35 -51
- jarvis/models/__init__.py +1 -1
- jarvis/models/ai8.py +58 -88
- jarvis/models/base.py +6 -6
- jarvis/models/kimi.py +80 -171
- jarvis/models/openai.py +23 -43
- jarvis/models/oyi.py +91 -113
- jarvis/models/registry.py +44 -63
- jarvis/tools/__init__.py +1 -1
- jarvis/tools/base.py +2 -2
- jarvis/tools/file_ops.py +15 -19
- jarvis/tools/generator.py +12 -15
- jarvis/tools/methodology.py +20 -20
- jarvis/tools/registry.py +30 -44
- jarvis/tools/shell.py +11 -12
- jarvis/tools/sub_agent.py +2 -1
- jarvis/utils.py +27 -47
- {jarvis_ai_assistant-0.1.46.dist-info → jarvis_ai_assistant-0.1.48.dist-info}/METADATA +1 -1
- jarvis_ai_assistant-0.1.48.dist-info/RECORD +25 -0
- jarvis_ai_assistant-0.1.46.dist-info/RECORD +0 -25
- {jarvis_ai_assistant-0.1.46.dist-info → jarvis_ai_assistant-0.1.48.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.46.dist-info → jarvis_ai_assistant-0.1.48.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.46.dist-info → jarvis_ai_assistant-0.1.48.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.46.dist-info → jarvis_ai_assistant-0.1.48.dist-info}/top_level.txt +0 -0
jarvis/tools/__init__.py
CHANGED
jarvis/tools/base.py
CHANGED
@@ -2,9 +2,9 @@ from typing import Dict, Any, Callable
|
|
2
2
|
import json
|
3
3
|
|
4
4
|
|
5
|
+
|
5
6
|
class Tool:
|
6
|
-
def __init__(self, name: str, description: str,
|
7
|
-
parameters: Dict, func: Callable):
|
7
|
+
def __init__(self, name: str, description: str, parameters: Dict, func: Callable):
|
8
8
|
self.name = name
|
9
9
|
self.description = description
|
10
10
|
self.parameters = parameters
|
jarvis/tools/file_ops.py
CHANGED
@@ -34,19 +34,18 @@ class FileOperationTool:
|
|
34
34
|
"required": ["operation", "filepath"]
|
35
35
|
}
|
36
36
|
|
37
|
+
|
37
38
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
38
39
|
"""执行文件操作"""
|
39
40
|
try:
|
40
41
|
operation = args["operation"]
|
41
42
|
filepath = args["filepath"]
|
42
43
|
encoding = args.get("encoding", "utf-8")
|
43
|
-
|
44
|
+
|
44
45
|
# 记录操作和完整路径
|
45
46
|
abs_path = os.path.abspath(filepath)
|
46
|
-
PrettyOutput.print(
|
47
|
-
|
48
|
-
OutputType.INFO)
|
49
|
-
|
47
|
+
PrettyOutput.print(f"文件操作: {operation} - {abs_path}", OutputType.INFO)
|
48
|
+
|
50
49
|
if operation == "exists":
|
51
50
|
exists = os.path.exists(filepath)
|
52
51
|
return {
|
@@ -54,21 +53,21 @@ class FileOperationTool:
|
|
54
53
|
"stdout": str(exists),
|
55
54
|
"stderr": ""
|
56
55
|
}
|
57
|
-
|
56
|
+
|
58
57
|
elif operation == "read":
|
59
58
|
if not os.path.exists(filepath):
|
60
59
|
return {
|
61
60
|
"success": False,
|
62
61
|
"error": f"文件不存在: {filepath}"
|
63
62
|
}
|
64
|
-
|
63
|
+
|
65
64
|
# 检查文件大小
|
66
65
|
if os.path.getsize(filepath) > 10 * 1024 * 1024: # 10MB
|
67
66
|
return {
|
68
67
|
"success": False,
|
69
68
|
"error": "文件过大 (>10MB)"
|
70
69
|
}
|
71
|
-
|
70
|
+
|
72
71
|
with open(filepath, 'r', encoding=encoding) as f:
|
73
72
|
content = f.read()
|
74
73
|
return {
|
@@ -76,39 +75,36 @@ class FileOperationTool:
|
|
76
75
|
"stdout": content,
|
77
76
|
"stderr": ""
|
78
77
|
}
|
79
|
-
|
78
|
+
|
80
79
|
elif operation in ["write", "append"]:
|
81
80
|
if not args.get("content"):
|
82
81
|
return {
|
83
82
|
"success": False,
|
84
83
|
"error": "写入/追加操作需要提供content参数"
|
85
84
|
}
|
86
|
-
|
85
|
+
|
87
86
|
# 创建目录(如果不存在)
|
88
|
-
os.makedirs(
|
89
|
-
|
90
|
-
os.path.abspath(filepath)),
|
91
|
-
exist_ok=True)
|
92
|
-
|
87
|
+
os.makedirs(os.path.dirname(os.path.abspath(filepath)), exist_ok=True)
|
88
|
+
|
93
89
|
mode = 'a' if operation == "append" else 'w'
|
94
90
|
with open(filepath, mode, encoding=encoding) as f:
|
95
91
|
f.write(args["content"])
|
96
|
-
|
92
|
+
|
97
93
|
return {
|
98
94
|
"success": True,
|
99
95
|
"stdout": f"成功{operation}内容到 {filepath}",
|
100
96
|
"stderr": ""
|
101
97
|
}
|
102
|
-
|
98
|
+
|
103
99
|
else:
|
104
100
|
return {
|
105
101
|
"success": False,
|
106
102
|
"error": f"未知操作: {operation}"
|
107
103
|
}
|
108
|
-
|
104
|
+
|
109
105
|
except Exception as e:
|
110
106
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
111
107
|
return {
|
112
108
|
"success": False,
|
113
109
|
"error": f"文件操作失败: {str(e)}"
|
114
|
-
}
|
110
|
+
}
|
jarvis/tools/generator.py
CHANGED
@@ -5,7 +5,6 @@ from jarvis.models.registry import PlatformRegistry
|
|
5
5
|
from jarvis.tools.registry import ToolRegistry
|
6
6
|
from jarvis.utils import OutputType, PrettyOutput
|
7
7
|
|
8
|
-
|
9
8
|
class ToolGeneratorTool:
|
10
9
|
name = "generate_tool"
|
11
10
|
description = "生成新的工具代码并自动注册到Jarvis,自动扩充Jarvis的能力"
|
@@ -37,15 +36,13 @@ class ToolGeneratorTool:
|
|
37
36
|
"""
|
38
37
|
# 设置工具目录
|
39
38
|
self.tools_dir = Path.home() / '.jarvis_tools'
|
40
|
-
|
39
|
+
|
41
40
|
# 确保工具目录存在
|
42
41
|
self.tools_dir.mkdir(parents=True, exist_ok=True)
|
43
42
|
|
44
|
-
def _generate_tool_code(self, tool_name: str, class_name: str,
|
45
|
-
description: str, parameters: Dict) -> str:
|
43
|
+
def _generate_tool_code(self, tool_name: str, class_name: str, description: str, parameters: Dict) -> str:
|
46
44
|
"""使用大模型生成工具代码"""
|
47
|
-
platform_name = os.getenv(
|
48
|
-
"JARVIS_CODEGEN_PLATFORM") or PlatformRegistry.get_global_platform_name()
|
45
|
+
platform_name = os.getenv("JARVIS_CODEGEN_PLATFORM") or PlatformRegistry.get_global_platform_name()
|
49
46
|
model = PlatformRegistry.create_platform(platform_name)
|
50
47
|
model_name = os.getenv("JARVIS_CODEGEN_MODEL")
|
51
48
|
if model_name:
|
@@ -84,16 +81,16 @@ class ExampleTool:
|
|
84
81
|
# 验证参数示例
|
85
82
|
if "param1" not in args:
|
86
83
|
return {{"success": False, "error": "缺少必需参数: param1"}}
|
87
|
-
|
84
|
+
|
88
85
|
# 记录操作示例
|
89
86
|
PrettyOutput.print(f"处理参数: {{args['param1']}}", OutputType.INFO)
|
90
87
|
|
91
88
|
# 使用大模型示例
|
92
89
|
response = self.model.chat("prompt")
|
93
|
-
|
90
|
+
|
94
91
|
# 实现具体功能
|
95
92
|
result = "处理结果"
|
96
|
-
|
93
|
+
|
97
94
|
return {{
|
98
95
|
"success": True,
|
99
96
|
"stdout": result,
|
@@ -114,11 +111,11 @@ class ExampleTool:
|
|
114
111
|
# 提取代码块
|
115
112
|
code_start = response.find("```python")
|
116
113
|
code_end = response.find("```", code_start + 9)
|
117
|
-
|
114
|
+
|
118
115
|
if code_start == -1 or code_end == -1:
|
119
116
|
# 如果没有找到代码块标记,假设整个响应都是代码
|
120
117
|
return response
|
121
|
-
|
118
|
+
|
122
119
|
# 提取代码块内容(去掉```python和```标记)
|
123
120
|
code = response[code_start + 9:code_end].strip()
|
124
121
|
return code
|
@@ -165,10 +162,10 @@ class ExampleTool:
|
|
165
162
|
return {
|
166
163
|
"success": True,
|
167
164
|
"stdout": f"工具已生成并注册到Jarvis\n"
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
165
|
+
f"工具目录: {self.tools_dir}\n"
|
166
|
+
f"工具名称: {tool_name}\n"
|
167
|
+
f"工具描述: {description}\n"
|
168
|
+
f"工具参数: {parameters}",
|
172
169
|
"stderr": ""
|
173
170
|
}
|
174
171
|
|
jarvis/tools/methodology.py
CHANGED
@@ -6,7 +6,7 @@ from jarvis.utils import OutputType, PrettyOutput
|
|
6
6
|
|
7
7
|
class MethodologyTool:
|
8
8
|
"""经验管理工具"""
|
9
|
-
|
9
|
+
|
10
10
|
name = "methodology"
|
11
11
|
description = "管理问题处理经验总结,支持添加、更新、删除操作"
|
12
12
|
parameters = {
|
@@ -29,12 +29,12 @@ class MethodologyTool:
|
|
29
29
|
},
|
30
30
|
"required": ["operation", "problem_type"]
|
31
31
|
}
|
32
|
-
|
32
|
+
|
33
33
|
def __init__(self):
|
34
34
|
"""初始化经验管理工具"""
|
35
35
|
self.methodology_file = os.path.expanduser("~/.jarvis_methodology")
|
36
36
|
self._ensure_file_exists()
|
37
|
-
|
37
|
+
|
38
38
|
def _ensure_file_exists(self):
|
39
39
|
"""确保经验总结文件存在"""
|
40
40
|
if not os.path.exists(self.methodology_file):
|
@@ -43,7 +43,7 @@ class MethodologyTool:
|
|
43
43
|
yaml.safe_dump({}, f, allow_unicode=True)
|
44
44
|
except Exception as e:
|
45
45
|
PrettyOutput.print(f"创建经验总结文件失败: {str(e)}", OutputType.ERROR)
|
46
|
-
|
46
|
+
|
47
47
|
def _load_methodologies(self) -> Dict:
|
48
48
|
"""加载所有经验总结"""
|
49
49
|
try:
|
@@ -52,7 +52,7 @@ class MethodologyTool:
|
|
52
52
|
except Exception as e:
|
53
53
|
PrettyOutput.print(f"加载经验总结失败: {str(e)}", OutputType.ERROR)
|
54
54
|
return {}
|
55
|
-
|
55
|
+
|
56
56
|
def _save_methodologies(self, methodologies: Dict):
|
57
57
|
"""保存所有经验总结"""
|
58
58
|
try:
|
@@ -60,31 +60,31 @@ class MethodologyTool:
|
|
60
60
|
yaml.safe_dump(methodologies, f, allow_unicode=True)
|
61
61
|
except Exception as e:
|
62
62
|
PrettyOutput.print(f"保存经验总结失败: {str(e)}", OutputType.ERROR)
|
63
|
-
|
63
|
+
|
64
64
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
65
65
|
"""执行经验总结管理操作
|
66
|
-
|
66
|
+
|
67
67
|
Args:
|
68
68
|
args: 包含操作参数的字典
|
69
69
|
- operation: 操作类型 (delete/update/add)
|
70
70
|
- problem_type: 问题类型
|
71
71
|
- content: 经验总结内容 (update/add 时必需)
|
72
|
-
|
72
|
+
|
73
73
|
Returns:
|
74
74
|
Dict[str, Any]: 包含执行结果的字典
|
75
75
|
"""
|
76
76
|
operation = args.get("operation")
|
77
77
|
problem_type = args.get("problem_type")
|
78
78
|
content = args.get("content")
|
79
|
-
|
79
|
+
|
80
80
|
if not operation or not problem_type:
|
81
81
|
return {
|
82
82
|
"success": False,
|
83
83
|
"error": "缺少必要参数: operation 和 problem_type"
|
84
84
|
}
|
85
|
-
|
85
|
+
|
86
86
|
methodologies = self._load_methodologies()
|
87
|
-
|
87
|
+
|
88
88
|
try:
|
89
89
|
if operation == "delete":
|
90
90
|
if problem_type in methodologies:
|
@@ -99,43 +99,43 @@ class MethodologyTool:
|
|
99
99
|
"success": False,
|
100
100
|
"error": f"未找到问题类型 '{problem_type}' 的经验总结"
|
101
101
|
}
|
102
|
-
|
102
|
+
|
103
103
|
elif operation in ["update", "add"]:
|
104
104
|
if not content:
|
105
105
|
return {
|
106
106
|
"success": False,
|
107
107
|
"error": "需要提供经验总结内容"
|
108
108
|
}
|
109
|
-
|
109
|
+
|
110
110
|
methodologies[problem_type] = content
|
111
111
|
self._save_methodologies(methodologies)
|
112
|
-
|
112
|
+
|
113
113
|
action = "更新" if problem_type in methodologies else "添加"
|
114
114
|
return {
|
115
115
|
"success": True,
|
116
116
|
"stdout": f"已{action}问题类型 '{problem_type}' 的经验总结"
|
117
117
|
}
|
118
|
-
|
118
|
+
|
119
119
|
else:
|
120
120
|
return {
|
121
121
|
"success": False,
|
122
122
|
"error": f"不支持的操作类型: {operation}"
|
123
123
|
}
|
124
|
-
|
124
|
+
|
125
125
|
except Exception as e:
|
126
126
|
return {
|
127
127
|
"success": False,
|
128
128
|
"error": f"执行失败: {str(e)}"
|
129
129
|
}
|
130
|
-
|
130
|
+
|
131
131
|
def get_methodology(self, problem_type: str) -> Optional[str]:
|
132
132
|
"""获取指定问题类型的经验总结
|
133
|
-
|
133
|
+
|
134
134
|
Args:
|
135
135
|
problem_type: 问题类型
|
136
|
-
|
136
|
+
|
137
137
|
Returns:
|
138
138
|
Optional[str]: 经验总结内容,如果不存在则返回 None
|
139
139
|
"""
|
140
140
|
methodologies = self._load_methodologies()
|
141
|
-
return methodologies.get(problem_type)
|
141
|
+
return methodologies.get(problem_type)
|
jarvis/tools/registry.py
CHANGED
@@ -11,8 +11,7 @@ from jarvis.utils import OutputType, PrettyOutput
|
|
11
11
|
|
12
12
|
|
13
13
|
class ToolRegistry:
|
14
|
-
global_tool_registry = None
|
15
|
-
|
14
|
+
global_tool_registry = None # type: ignore
|
16
15
|
def __init__(self):
|
17
16
|
"""初始化工具注册器
|
18
17
|
"""
|
@@ -31,13 +30,13 @@ class ToolRegistry:
|
|
31
30
|
def _load_builtin_tools(self):
|
32
31
|
"""从内置tools目录加载工具"""
|
33
32
|
tools_dir = Path(__file__).parent
|
34
|
-
|
33
|
+
|
35
34
|
# 遍历目录下的所有.py文件
|
36
35
|
for file_path in tools_dir.glob("*.py"):
|
37
36
|
# 跳过基础文件和__init__.py
|
38
37
|
if file_path.name in ["base.py", "__init__.py", "registry.py"]:
|
39
38
|
continue
|
40
|
-
|
39
|
+
|
41
40
|
self.register_tool_by_file(file_path)
|
42
41
|
|
43
42
|
def _load_external_tools(self):
|
@@ -45,21 +44,21 @@ class ToolRegistry:
|
|
45
44
|
external_tools_dir = Path.home() / '.jarvis_tools'
|
46
45
|
if not external_tools_dir.exists():
|
47
46
|
return
|
48
|
-
|
47
|
+
|
49
48
|
# 遍历目录下的所有.py文件
|
50
49
|
for file_path in external_tools_dir.glob("*.py"):
|
51
50
|
# 跳过__init__.py
|
52
51
|
if file_path.name == "__init__.py":
|
53
52
|
continue
|
54
|
-
|
53
|
+
|
55
54
|
self.register_tool_by_file(file_path)
|
56
55
|
|
57
56
|
def register_tool_by_file(self, file_path: str):
|
58
57
|
"""从指定文件加载并注册工具
|
59
|
-
|
58
|
+
|
60
59
|
Args:
|
61
60
|
file_path: 工具文件的路径
|
62
|
-
|
61
|
+
|
63
62
|
Returns:
|
64
63
|
bool: 是否成功加载工具
|
65
64
|
"""
|
@@ -68,32 +67,31 @@ class ToolRegistry:
|
|
68
67
|
if not file_path.exists() or not file_path.is_file():
|
69
68
|
PrettyOutput.print(f"文件不存在: {file_path}", OutputType.ERROR)
|
70
69
|
return False
|
71
|
-
|
70
|
+
|
72
71
|
# 动态导入模块
|
73
72
|
module_name = file_path.stem
|
74
|
-
spec = importlib.util.spec_from_file_location(
|
75
|
-
module_name, file_path)
|
73
|
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
76
74
|
if not spec or not spec.loader:
|
77
75
|
PrettyOutput.print(f"无法加载模块: {file_path}", OutputType.ERROR)
|
78
76
|
return False
|
79
|
-
|
77
|
+
|
80
78
|
module = importlib.util.module_from_spec(spec)
|
81
79
|
sys.modules[module_name] = module # 添加到 sys.modules 以支持相对导入
|
82
80
|
spec.loader.exec_module(module)
|
83
|
-
|
81
|
+
|
84
82
|
# 查找模块中的工具类
|
85
83
|
tool_found = False
|
86
84
|
for item_name in dir(module):
|
87
85
|
item = getattr(module, item_name)
|
88
86
|
# 检查是否是类,并且有必要的属性
|
89
|
-
if (isinstance(item, type) and
|
90
|
-
hasattr(item, 'name') and
|
91
|
-
hasattr(item, 'description') and
|
92
|
-
|
93
|
-
|
87
|
+
if (isinstance(item, type) and
|
88
|
+
hasattr(item, 'name') and
|
89
|
+
hasattr(item, 'description') and
|
90
|
+
hasattr(item, 'parameters')):
|
91
|
+
|
94
92
|
# 实例化工具类,传入模型和输出处理器
|
95
93
|
tool_instance = item()
|
96
|
-
|
94
|
+
|
97
95
|
# 注册工具
|
98
96
|
self.register_tool(
|
99
97
|
name=tool_instance.name,
|
@@ -101,31 +99,20 @@ class ToolRegistry:
|
|
101
99
|
parameters=tool_instance.parameters,
|
102
100
|
func=tool_instance.execute
|
103
101
|
)
|
104
|
-
PrettyOutput.print(
|
105
|
-
f"从 {file_path} 加载工具: {
|
106
|
-
tool_instance.name}: {
|
107
|
-
tool_instance.description}",
|
108
|
-
OutputType.INFO)
|
102
|
+
PrettyOutput.print(f"从 {file_path} 加载工具: {tool_instance.name}: {tool_instance.description}", OutputType.INFO)
|
109
103
|
tool_found = True
|
110
|
-
|
104
|
+
|
111
105
|
if not tool_found:
|
112
|
-
PrettyOutput.print(
|
113
|
-
f"文件中未找到有效的工具类: {file_path}",
|
114
|
-
OutputType.WARNING)
|
106
|
+
PrettyOutput.print(f"文件中未找到有效的工具类: {file_path}", OutputType.WARNING)
|
115
107
|
return False
|
116
|
-
|
108
|
+
|
117
109
|
return True
|
118
|
-
|
110
|
+
|
119
111
|
except Exception as e:
|
120
|
-
PrettyOutput.print(
|
121
|
-
f"加载工具失败 {
|
122
|
-
file_path.name}: {
|
123
|
-
str(e)}",
|
124
|
-
OutputType.ERROR)
|
112
|
+
PrettyOutput.print(f"加载工具失败 {file_path.name}: {str(e)}", OutputType.ERROR)
|
125
113
|
return False
|
126
114
|
|
127
|
-
def register_tool(self, name: str, description: str,
|
128
|
-
parameters: Dict, func: Callable):
|
115
|
+
def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
|
129
116
|
"""注册新工具"""
|
130
117
|
self.tools[name] = Tool(name, description, parameters, func)
|
131
118
|
|
@@ -149,12 +136,12 @@ class ToolRegistry:
|
|
149
136
|
try:
|
150
137
|
if not tool_calls:
|
151
138
|
return ""
|
152
|
-
|
139
|
+
|
153
140
|
# 只处理第一个工具调用
|
154
141
|
tool_call = tool_calls[0]
|
155
142
|
name = tool_call["name"]
|
156
143
|
args = tool_call["arguments"]
|
157
|
-
|
144
|
+
|
158
145
|
if isinstance(args, str):
|
159
146
|
try:
|
160
147
|
args = json.loads(args)
|
@@ -166,14 +153,13 @@ class ToolRegistry:
|
|
166
153
|
PrettyOutput.section(f"执行工具: {name}", OutputType.TOOL)
|
167
154
|
if isinstance(args, dict):
|
168
155
|
for key, value in args.items():
|
169
|
-
PrettyOutput.print(
|
170
|
-
f"参数: {key} = {value}", OutputType.DEBUG)
|
156
|
+
PrettyOutput.print(f"参数: {key} = {value}", OutputType.DEBUG)
|
171
157
|
else:
|
172
158
|
PrettyOutput.print(f"参数: {args}", OutputType.DEBUG)
|
173
|
-
|
159
|
+
|
174
160
|
# 执行工具调用
|
175
161
|
result = self.execute_tool(name, args)
|
176
|
-
|
162
|
+
|
177
163
|
# 处理结果
|
178
164
|
if result["success"]:
|
179
165
|
stdout = result["stdout"]
|
@@ -190,7 +176,7 @@ class ToolRegistry:
|
|
190
176
|
error_msg = result["error"]
|
191
177
|
output = f"执行失败: {error_msg}"
|
192
178
|
PrettyOutput.section("执行失败", OutputType.ERROR)
|
193
|
-
|
179
|
+
|
194
180
|
return output
|
195
181
|
except Exception as e:
|
196
182
|
PrettyOutput.print(f"执行工具失败: {str(e)}", OutputType.ERROR)
|
jarvis/tools/shell.py
CHANGED
@@ -21,6 +21,7 @@ class ShellTool:
|
|
21
21
|
"required": ["command"]
|
22
22
|
}
|
23
23
|
|
24
|
+
|
24
25
|
def _escape_command(self, cmd: str) -> str:
|
25
26
|
"""转义命令中的特殊字符"""
|
26
27
|
return cmd.replace("'", "'\"'\"'")
|
@@ -29,23 +30,21 @@ class ShellTool:
|
|
29
30
|
"""执行shell命令"""
|
30
31
|
try:
|
31
32
|
command = args["command"]
|
32
|
-
|
33
|
+
|
33
34
|
# 生成临时文件名
|
34
|
-
output_file = os.path.join(
|
35
|
-
|
36
|
-
os.getpid()}.log")
|
37
|
-
|
35
|
+
output_file = os.path.join(tempfile.gettempdir(), f"jarvis_shell_{os.getpid()}.log")
|
36
|
+
|
38
37
|
# 转义命令中的特殊字符
|
39
38
|
escaped_command = self._escape_command(command)
|
40
|
-
|
39
|
+
|
41
40
|
# 修改命令以使用script
|
42
41
|
tee_command = f"script -q -c '{escaped_command}' {output_file}"
|
43
|
-
|
42
|
+
|
44
43
|
PrettyOutput.print(f"执行命令: {command}", OutputType.INFO)
|
45
|
-
|
44
|
+
|
46
45
|
# 执行命令
|
47
46
|
return_code = os.system(tee_command)
|
48
|
-
|
47
|
+
|
49
48
|
# 读取输出文件
|
50
49
|
try:
|
51
50
|
with open(output_file, 'r', encoding='utf-8', errors='replace') as f:
|
@@ -60,14 +59,14 @@ class ShellTool:
|
|
60
59
|
finally:
|
61
60
|
# 清理临时文件
|
62
61
|
Path(output_file).unlink(missing_ok=True)
|
63
|
-
|
62
|
+
|
64
63
|
return {
|
65
64
|
"success": return_code == 0,
|
66
65
|
"stdout": output,
|
67
66
|
"stderr": "",
|
68
67
|
"return_code": return_code
|
69
68
|
}
|
70
|
-
|
69
|
+
|
71
70
|
except Exception as e:
|
72
71
|
# 确保清理临时文件
|
73
72
|
if 'output_file' in locals():
|
@@ -76,4 +75,4 @@ class ShellTool:
|
|
76
75
|
return {
|
77
76
|
"success": False,
|
78
77
|
"error": str(e)
|
79
|
-
}
|
78
|
+
}
|
jarvis/tools/sub_agent.py
CHANGED
@@ -39,6 +39,7 @@ class SubAgentTool:
|
|
39
39
|
"required": ["agent_name", "task", "context", "goal"]
|
40
40
|
}
|
41
41
|
|
42
|
+
|
42
43
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
43
44
|
"""创建并运行子代理"""
|
44
45
|
try:
|
@@ -78,4 +79,4 @@ class SubAgentTool:
|
|
78
79
|
return {
|
79
80
|
"success": False,
|
80
81
|
"error": f"子代理执行失败: {str(e)}"
|
81
|
-
}
|
82
|
+
}
|