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