jarvis-ai-assistant 0.1.46__py3-none-any.whl → 0.1.48__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.
- 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
|
+
}
|