jarvis-ai-assistant 0.2.1__py3-none-any.whl → 0.2.3__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/jarvis_agent/jarvis.py +61 -59
- jarvis/jarvis_agent/main.py +42 -40
- jarvis/jarvis_agent/prompts.py +26 -4
- jarvis/jarvis_code_agent/code_agent.py +35 -31
- jarvis/jarvis_code_analysis/code_review.py +73 -39
- jarvis/jarvis_data/config_schema.json +67 -12
- jarvis/jarvis_git_squash/main.py +16 -12
- jarvis/jarvis_git_utils/git_commiter.py +25 -20
- jarvis/jarvis_methodology/main.py +34 -49
- jarvis/jarvis_multi_agent/main.py +28 -23
- jarvis/jarvis_platform/ai8.py +31 -22
- jarvis/jarvis_platform/kimi.py +31 -61
- jarvis/jarvis_platform/tongyi.py +71 -85
- jarvis/jarvis_platform/yuanbao.py +44 -50
- jarvis/jarvis_platform_manager/main.py +55 -90
- jarvis/jarvis_rag/cli.py +79 -23
- jarvis/jarvis_rag/query_rewriter.py +61 -12
- jarvis/jarvis_rag/rag_pipeline.py +143 -34
- jarvis/jarvis_rag/retriever.py +5 -5
- jarvis/jarvis_smart_shell/main.py +58 -87
- jarvis/jarvis_tools/cli/main.py +120 -153
- jarvis/jarvis_tools/generate_new_tool.py +22 -1
- jarvis/jarvis_tools/registry.py +1 -7
- jarvis/jarvis_tools/search_web.py +12 -10
- jarvis/jarvis_utils/config.py +92 -11
- jarvis/jarvis_utils/globals.py +29 -8
- jarvis/jarvis_utils/http.py +58 -79
- jarvis/jarvis_utils/input.py +114 -121
- jarvis/jarvis_utils/output.py +1 -1
- jarvis/jarvis_utils/utils.py +3 -0
- jarvis_ai_assistant-0.2.3.dist-info/METADATA +301 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/RECORD +37 -40
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/entry_points.txt +0 -2
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +0 -265
- jarvis/jarvis_platform/oyi.py +0 -357
- jarvis_ai_assistant-0.2.1.dist-info/METADATA +0 -845
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/top_level.txt +0 -0
@@ -1,15 +1,25 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
# -*- coding: utf-8 -*-
|
3
|
-
import argparse
|
4
3
|
import os
|
5
4
|
import sys
|
6
5
|
from typing import Optional, Tuple
|
7
6
|
|
7
|
+
import typer
|
8
|
+
|
8
9
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
9
10
|
from jarvis.jarvis_utils.config import get_shell_name, set_config
|
10
11
|
from jarvis.jarvis_utils.input import get_multiline_input
|
11
12
|
from jarvis.jarvis_utils.utils import init_env
|
12
13
|
|
14
|
+
app = typer.Typer(
|
15
|
+
help="将自然语言要求转换为shell命令",
|
16
|
+
epilog="""
|
17
|
+
Example:
|
18
|
+
jss request "Find all Python files in the current directory"
|
19
|
+
jss install
|
20
|
+
""",
|
21
|
+
)
|
22
|
+
|
13
23
|
|
14
24
|
def execute_command(command: str, should_run: bool) -> None:
|
15
25
|
"""Print command without execution"""
|
@@ -48,15 +58,18 @@ def _get_markers() -> Tuple[str, str]:
|
|
48
58
|
)
|
49
59
|
|
50
60
|
|
51
|
-
|
52
|
-
|
61
|
+
@app.command("install")
|
62
|
+
def install_jss_completion(
|
63
|
+
shell: str = typer.Option("fish", help="指定shell类型(仅支持fish)"),
|
64
|
+
) -> None:
|
65
|
+
"""为fish shell安装'命令未找到'处理器,实现自然语言命令执行"""
|
66
|
+
if shell != "fish":
|
67
|
+
print(f"错误: 不支持的shell类型: {shell}, 仅支持fish")
|
68
|
+
raise typer.Exit(code=1)
|
53
69
|
|
54
|
-
Returns:
|
55
|
-
int: 0 if success, 1 if failed
|
56
|
-
"""
|
57
70
|
if not _check_fish_shell():
|
58
71
|
print("当前不是fish shell,无需安装")
|
59
|
-
return
|
72
|
+
return
|
60
73
|
|
61
74
|
config_file = _get_config_file()
|
62
75
|
start_marker, end_marker = _get_markers()
|
@@ -64,13 +77,15 @@ def install_jss_completion() -> int:
|
|
64
77
|
if not os.path.exists(config_file):
|
65
78
|
print("未找到config.fish文件,将创建新文件")
|
66
79
|
os.makedirs(os.path.dirname(config_file), exist_ok=True)
|
80
|
+
with open(config_file, "w") as f:
|
81
|
+
f.write("")
|
67
82
|
|
68
83
|
with open(config_file, "r") as f:
|
69
84
|
content = f.read()
|
70
85
|
|
71
86
|
if start_marker in content:
|
72
87
|
print("JSS fish completion已安装,请执行: source ~/.config/fish/config.fish")
|
73
|
-
return
|
88
|
+
return
|
74
89
|
|
75
90
|
with open(config_file, "a") as f:
|
76
91
|
f.write(
|
@@ -90,32 +105,34 @@ end
|
|
90
105
|
"""
|
91
106
|
)
|
92
107
|
print("JSS fish completion已安装,请执行: source ~/.config/fish/config.fish")
|
93
|
-
return 0
|
94
108
|
|
95
109
|
|
96
|
-
|
97
|
-
|
110
|
+
@app.command("uninstall")
|
111
|
+
def uninstall_jss_completion(
|
112
|
+
shell: str = typer.Option("fish", help="指定shell类型(仅支持fish)"),
|
113
|
+
) -> None:
|
114
|
+
"""卸载JSS fish shell'命令未找到'处理器"""
|
115
|
+
if shell != "fish":
|
116
|
+
print(f"错误: 不支持的shell类型: {shell}, 仅支持fish")
|
117
|
+
raise typer.Exit(code=1)
|
98
118
|
|
99
|
-
Returns:
|
100
|
-
int: 0 if success, 1 if failed
|
101
|
-
"""
|
102
119
|
if not _check_fish_shell():
|
103
120
|
print("当前不是fish shell,无需卸载")
|
104
|
-
return
|
121
|
+
return
|
105
122
|
|
106
123
|
config_file = _get_config_file()
|
107
124
|
start_marker, end_marker = _get_markers()
|
108
125
|
|
109
126
|
if not os.path.exists(config_file):
|
110
127
|
print("未找到JSS fish completion配置,无需卸载")
|
111
|
-
return
|
128
|
+
return
|
112
129
|
|
113
130
|
with open(config_file, "r") as f:
|
114
131
|
content = f.read()
|
115
132
|
|
116
133
|
if start_marker not in content:
|
117
134
|
print("未找到JSS fish completion配置,无需卸载")
|
118
|
-
return
|
135
|
+
return
|
119
136
|
|
120
137
|
new_content = content.split(start_marker)[0] + content.split(end_marker)[-1]
|
121
138
|
|
@@ -123,7 +140,6 @@ def uninstall_jss_completion() -> int:
|
|
123
140
|
f.write(new_content)
|
124
141
|
|
125
142
|
print("JSS fish completion已卸载,请执行: source ~/.config/fish/config.fish")
|
126
|
-
return 0
|
127
143
|
|
128
144
|
|
129
145
|
def process_request(request: str) -> Optional[str]:
|
@@ -175,85 +191,40 @@ def process_request(request: str) -> Optional[str]:
|
|
175
191
|
return None
|
176
192
|
|
177
193
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
set_config("JARVIS_PRINT_PROMPT", "false")
|
183
|
-
|
184
|
-
parser = argparse.ArgumentParser(
|
185
|
-
description="将自然语言要求转换为shell命令",
|
186
|
-
formatter_class=argparse.RawDescriptionHelpFormatter,
|
187
|
-
epilog="""
|
188
|
-
Example:
|
189
|
-
%(prog)s request "Find all Python files in the current directory"
|
190
|
-
%(prog)s install
|
191
|
-
""",
|
194
|
+
@app.command("request")
|
195
|
+
def request_command(
|
196
|
+
request: Optional[str] = typer.Argument(
|
197
|
+
None, help="描述您想要执行的操作(用自然语言描述),如果未提供则从标准输入读取"
|
192
198
|
)
|
193
|
-
|
194
|
-
|
195
|
-
subparsers = parser.add_subparsers(dest="command", required=True)
|
196
|
-
|
197
|
-
# request子命令
|
198
|
-
request_parser = subparsers.add_parser(
|
199
|
-
"request", help="描述您想要执行的操作(用自然语言描述)"
|
200
|
-
)
|
201
|
-
request_parser.add_argument(
|
202
|
-
"request",
|
203
|
-
nargs="?", # 设置为可选参数
|
204
|
-
help="描述您想要执行的操作(用自然语言描述),如果未提供则从标准输入读取",
|
205
|
-
)
|
206
|
-
|
207
|
-
# install子命令
|
208
|
-
install_parser = subparsers.add_parser(
|
209
|
-
"install", help="安装JSS fish shell命令补全功能"
|
210
|
-
)
|
211
|
-
install_parser.add_argument(
|
212
|
-
"--shell", choices=["fish"], default="fish", help="指定shell类型(仅支持fish)"
|
213
|
-
)
|
214
|
-
|
215
|
-
# 添加uninstall子命令
|
216
|
-
uninstall_parser = subparsers.add_parser(
|
217
|
-
"uninstall", help="卸载JSS fish shell命令补全功能"
|
218
|
-
)
|
219
|
-
uninstall_parser.add_argument(
|
220
|
-
"--shell", choices=["fish"], default="fish", help="指定shell类型(仅支持fish)"
|
221
|
-
)
|
222
|
-
|
223
|
-
# 解析参数
|
224
|
-
args = parser.parse_args()
|
225
|
-
|
199
|
+
):
|
200
|
+
"""描述您想要执行的操作(用自然语言描述)"""
|
226
201
|
should_run = False
|
227
|
-
|
228
|
-
# 处理install命令
|
229
|
-
if args.command == "install":
|
230
|
-
if args.shell != "fish":
|
231
|
-
print(f"错误: 不支持的shell类型: {args.shell}, 仅支持fish")
|
232
|
-
return 1
|
233
|
-
return install_jss_completion()
|
234
|
-
|
235
|
-
# 处理uninstall命令
|
236
|
-
if args.command == "uninstall":
|
237
|
-
if args.shell != "fish":
|
238
|
-
print(f"错误: 不支持的shell类型: {args.shell}, 仅支持fish")
|
239
|
-
return 1
|
240
|
-
return uninstall_jss_completion()
|
241
|
-
|
242
|
-
# 处理request命令
|
243
|
-
if not args.request:
|
202
|
+
if not request:
|
244
203
|
# 检查是否在交互式终端中运行
|
245
|
-
|
204
|
+
request = get_multiline_input(tip="请输入您要执行的功能:")
|
246
205
|
should_run = True
|
206
|
+
|
247
207
|
# 处理请求
|
248
|
-
command = process_request(
|
208
|
+
command = process_request(request)
|
249
209
|
|
250
210
|
# 输出结果
|
251
211
|
if command:
|
252
212
|
execute_command(command, should_run) # 显示并执行命令
|
253
|
-
return 0
|
254
213
|
else:
|
255
|
-
|
214
|
+
raise typer.Exit(code=1)
|
215
|
+
|
216
|
+
|
217
|
+
def cli():
|
218
|
+
"""Typer application entry point"""
|
219
|
+
init_env("")
|
220
|
+
set_config("JARVIS_PRINT_PROMPT", "false")
|
221
|
+
app()
|
222
|
+
|
223
|
+
|
224
|
+
def main():
|
225
|
+
"""Main entry point for the script"""
|
226
|
+
cli()
|
256
227
|
|
257
228
|
|
258
229
|
if __name__ == "__main__":
|
259
|
-
|
230
|
+
main()
|
jarvis/jarvis_tools/cli/main.py
CHANGED
@@ -1,178 +1,145 @@
|
|
1
1
|
import sys
|
2
|
+
import json
|
3
|
+
from typing import Optional
|
4
|
+
|
5
|
+
import typer
|
6
|
+
from tabulate import tabulate
|
2
7
|
|
3
8
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
4
9
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
5
10
|
from jarvis.jarvis_utils.utils import init_env
|
6
11
|
|
12
|
+
app = typer.Typer(help="Jarvis 工具系统命令行界面")
|
7
13
|
|
8
|
-
def main() -> int:
|
9
|
-
"""
|
10
|
-
命令行工具入口,提供工具列表查看和工具调用功能
|
11
|
-
|
12
|
-
功能:
|
13
|
-
1. 列出所有可用工具 (list命令)
|
14
|
-
2. 调用指定工具 (call命令)
|
15
|
-
|
16
|
-
参数:
|
17
|
-
通过命令行参数传递,包括:
|
18
|
-
- list: 列出工具
|
19
|
-
--json: 以JSON格式输出
|
20
|
-
--detailed: 显示详细信息
|
21
|
-
- call: 调用工具
|
22
|
-
tool_name: 工具名称
|
23
|
-
--args: 工具参数(JSON格式)
|
24
|
-
--args-file: 从文件加载工具参数
|
25
|
-
|
26
|
-
返回值:
|
27
|
-
int: 0表示成功,非0表示错误
|
28
|
-
"""
|
29
|
-
import argparse
|
30
|
-
import json
|
31
|
-
|
32
|
-
init_env("欢迎使用 Jarvis-Tools,您的工具系统已准备就绪!")
|
33
|
-
|
34
|
-
parser = argparse.ArgumentParser(description="Jarvis 工具系统命令行界面")
|
35
|
-
subparsers = parser.add_subparsers(dest="command", help="命令")
|
36
14
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
call_parser = subparsers.add_parser("call", help="调用指定工具")
|
44
|
-
call_parser.add_argument("tool_name", help="要调用的工具名称")
|
45
|
-
call_parser.add_argument("--args", type=str, help="工具参数 (JSON格式)")
|
46
|
-
call_parser.add_argument(
|
47
|
-
"--args-file", type=str, help="从文件加载工具参数 (JSON格式)"
|
48
|
-
)
|
49
|
-
|
50
|
-
# 统计子命令
|
51
|
-
stat_parser = subparsers.add_parser("stat", help="显示工具调用统计信息")
|
52
|
-
stat_parser.add_argument("--json", action="store_true", help="以JSON格式输出")
|
53
|
-
|
54
|
-
args = parser.parse_args()
|
55
|
-
|
56
|
-
# 初始化工具注册表
|
15
|
+
@app.command("list")
|
16
|
+
def list_tools(
|
17
|
+
as_json: bool = typer.Option(False, "--json", help="以JSON格式输出"),
|
18
|
+
detailed: bool = typer.Option(False, "--detailed", help="显示详细信息"),
|
19
|
+
):
|
20
|
+
"""列出所有可用工具"""
|
57
21
|
registry = ToolRegistry()
|
22
|
+
tools = registry.get_all_tools()
|
58
23
|
|
59
|
-
if
|
60
|
-
|
61
|
-
|
62
|
-
if args.json:
|
63
|
-
if args.detailed:
|
64
|
-
print(
|
65
|
-
json.dumps(tools, indent=2, ensure_ascii=False)
|
66
|
-
) # 输出完整JSON格式
|
67
|
-
else:
|
68
|
-
simple_tools = [
|
69
|
-
{"name": t["name"], "description": t["description"]} for t in tools
|
70
|
-
] # 简化工具信息
|
71
|
-
print(json.dumps(simple_tools, indent=2, ensure_ascii=False))
|
24
|
+
if as_json:
|
25
|
+
if detailed:
|
26
|
+
print(json.dumps(tools, indent=2, ensure_ascii=False))
|
72
27
|
else:
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
print(tool["parameters"]) # 显示详细参数信息
|
80
|
-
|
81
|
-
elif args.command == "stat":
|
82
|
-
from tabulate import tabulate
|
83
|
-
|
84
|
-
stats = registry._get_tool_stats()
|
85
|
-
tools = registry.get_all_tools()
|
86
|
-
|
87
|
-
# 构建统计表格数据
|
88
|
-
table_data = []
|
28
|
+
simple_tools = [
|
29
|
+
{"name": t["name"], "description": t["description"]} for t in tools
|
30
|
+
]
|
31
|
+
print(json.dumps(simple_tools, indent=2, ensure_ascii=False))
|
32
|
+
else:
|
33
|
+
PrettyOutput.section("可用工具列表", OutputType.SYSTEM)
|
89
34
|
for tool in tools:
|
90
|
-
|
91
|
-
|
92
|
-
|
35
|
+
print(f"\n✅ {tool['name']}")
|
36
|
+
print(f" 描述: {tool['description']}")
|
37
|
+
if detailed:
|
38
|
+
print(" 参数:")
|
39
|
+
print(tool["parameters"])
|
93
40
|
|
94
|
-
# 按调用次数降序排序
|
95
|
-
table_data.sort(key=lambda x: x[1], reverse=True)
|
96
41
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
42
|
+
@app.command("stat")
|
43
|
+
def stat_tools(as_json: bool = typer.Option(False, "--json", help="以JSON格式输出")):
|
44
|
+
"""显示工具调用统计信息"""
|
45
|
+
registry = ToolRegistry()
|
46
|
+
stats = registry._get_tool_stats()
|
47
|
+
tools = registry.get_all_tools()
|
48
|
+
|
49
|
+
table_data = []
|
50
|
+
for tool in tools:
|
51
|
+
name = tool["name"]
|
52
|
+
count = stats.get(name, 0)
|
53
|
+
table_data.append([name, count])
|
104
54
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
55
|
+
table_data.sort(key=lambda x: x[1], reverse=True)
|
56
|
+
|
57
|
+
if as_json:
|
58
|
+
print(json.dumps(dict(table_data), indent=2))
|
59
|
+
else:
|
60
|
+
PrettyOutput.section("工具调用统计", OutputType.SYSTEM)
|
61
|
+
print(tabulate(table_data, headers=["工具名称", "调用次数"], tablefmt="grid"))
|
62
|
+
|
63
|
+
|
64
|
+
@app.command("call")
|
65
|
+
def call_tool(
|
66
|
+
tool_name: str = typer.Argument(..., help="要调用的工具名称"),
|
67
|
+
args: Optional[str] = typer.Option(None, "--args", help="工具参数 (JSON格式)"),
|
68
|
+
args_file: Optional[str] = typer.Option(
|
69
|
+
None, "--args-file", help="从文件加载工具参数 (JSON格式)"
|
70
|
+
),
|
71
|
+
):
|
72
|
+
"""调用指定工具"""
|
73
|
+
registry = ToolRegistry()
|
74
|
+
tool_obj = registry.get_tool(tool_name)
|
75
|
+
|
76
|
+
if not tool_obj:
|
77
|
+
PrettyOutput.print(f"错误: 工具 '{tool_name}' 不存在", OutputType.ERROR)
|
78
|
+
available_tools = ", ".join([t["name"] for t in registry.get_all_tools()])
|
79
|
+
print(f"可用工具: {available_tools}")
|
80
|
+
raise typer.Exit(code=1)
|
81
|
+
|
82
|
+
tool_args = {}
|
83
|
+
if args:
|
84
|
+
try:
|
85
|
+
tool_args = json.loads(args)
|
86
|
+
except json.JSONDecodeError:
|
87
|
+
PrettyOutput.print("错误: 参数必须是有效的JSON格式", OutputType.ERROR)
|
88
|
+
raise typer.Exit(code=1)
|
89
|
+
elif args_file:
|
90
|
+
try:
|
91
|
+
with open(args_file, "r", encoding="utf-8") as f:
|
92
|
+
tool_args = json.load(f)
|
93
|
+
except (json.JSONDecodeError, FileNotFoundError) as e:
|
141
94
|
PrettyOutput.print(
|
142
|
-
f"错误:
|
95
|
+
f"错误: 无法从文件加载参数: {str(e)}", OutputType.ERROR
|
143
96
|
)
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
97
|
+
raise typer.Exit(code=1)
|
98
|
+
|
99
|
+
required_params = tool_obj.parameters.get("required", [])
|
100
|
+
missing_params = [p for p in required_params if p not in tool_args]
|
101
|
+
|
102
|
+
if missing_params:
|
103
|
+
PrettyOutput.print(
|
104
|
+
f"错误: 缺少必需参数: {', '.join(missing_params)}", OutputType.ERROR
|
105
|
+
)
|
106
|
+
print("\n参数说明:")
|
107
|
+
params = tool_obj.parameters.get("properties", {})
|
108
|
+
for param_name in required_params:
|
109
|
+
param_info = params.get(param_name, {})
|
110
|
+
desc = param_info.get("description", "无描述")
|
111
|
+
print(f" - {param_name}: {desc}")
|
112
|
+
raise typer.Exit(code=1)
|
113
|
+
|
114
|
+
result = registry.execute_tool(tool_name, tool_args)
|
115
|
+
|
116
|
+
if result["success"]:
|
117
|
+
PrettyOutput.section(f"工具 {tool_name} 执行成功", OutputType.SUCCESS)
|
118
|
+
else:
|
119
|
+
PrettyOutput.section(f"工具 {tool_name} 执行失败", OutputType.ERROR)
|
160
120
|
|
161
|
-
|
162
|
-
|
163
|
-
|
121
|
+
if result.get("stdout"):
|
122
|
+
print("\n输出:")
|
123
|
+
print(result["stdout"])
|
164
124
|
|
165
|
-
|
166
|
-
|
167
|
-
|
125
|
+
if result.get("stderr"):
|
126
|
+
PrettyOutput.print("\n错误:", OutputType.ERROR)
|
127
|
+
print(result["stderr"])
|
168
128
|
|
169
|
-
|
129
|
+
if not result["success"]:
|
130
|
+
raise typer.Exit(code=1)
|
131
|
+
|
132
|
+
|
133
|
+
def cli():
|
134
|
+
"""Typer application entry point"""
|
135
|
+
init_env("欢迎使用 Jarvis-Tools,您的工具系统已准备就绪!")
|
136
|
+
app()
|
170
137
|
|
171
|
-
else:
|
172
|
-
parser.print_help()
|
173
138
|
|
174
|
-
|
139
|
+
def main():
|
140
|
+
"""Main entry point for the script"""
|
141
|
+
cli()
|
175
142
|
|
176
143
|
|
177
144
|
if __name__ == "__main__":
|
178
|
-
|
145
|
+
main()
|
@@ -12,7 +12,9 @@ class generate_new_tool:
|
|
12
12
|
生成并注册新的Jarvis工具。该工具会在用户数据目录下创建新的工具文件,
|
13
13
|
并自动注册到当前的工具注册表中。适用场景:1. 需要创建新的自定义工具;
|
14
14
|
2. 扩展Jarvis功能;3. 自动化重复性操作;4. 封装特定领域的功能。
|
15
|
-
|
15
|
+
重要提示:
|
16
|
+
1. `tool_name` 参数必须与 `tool_code` 中定义的 `name` 属性完全一致。
|
17
|
+
2. 在编写工具代码时,应尽量将工具执行的过程和结果打印出来,方便追踪工具的执行状态。
|
16
18
|
"""
|
17
19
|
|
18
20
|
parameters = {
|
@@ -75,6 +77,25 @@ class generate_new_tool:
|
|
75
77
|
"stderr": f"工具名称 '{tool_name}' 不是有效的Python标识符",
|
76
78
|
}
|
77
79
|
|
80
|
+
# 验证工具代码中的名称是否与tool_name一致
|
81
|
+
import re
|
82
|
+
|
83
|
+
match = re.search(r"^\s*name\s*=\s*[\"'](.+?)[\"']", tool_code, re.MULTILINE)
|
84
|
+
if not match:
|
85
|
+
return {
|
86
|
+
"success": False,
|
87
|
+
"stdout": "",
|
88
|
+
"stderr": "无法在工具代码中找到 'name' 属性。请确保工具类中包含 'name = \"your_tool_name\"'。",
|
89
|
+
}
|
90
|
+
|
91
|
+
code_name = match.group(1)
|
92
|
+
if tool_name != code_name:
|
93
|
+
return {
|
94
|
+
"success": False,
|
95
|
+
"stdout": "",
|
96
|
+
"stderr": f"工具名称不一致:参数 'tool_name' ('{tool_name}') 与代码中的 'name' 属性 ('{code_name}') 必须相同。",
|
97
|
+
}
|
98
|
+
|
78
99
|
# 准备工具目录
|
79
100
|
tools_dir = Path(get_data_dir()) / "tools"
|
80
101
|
tools_dir.mkdir(parents=True, exist_ok=True)
|
jarvis/jarvis_tools/registry.py
CHANGED
@@ -594,13 +594,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
594
594
|
OutputType.INFO,
|
595
595
|
)
|
596
596
|
PrettyOutput.print(fixed_content, OutputType.TOOL)
|
597
|
-
|
598
|
-
data = temp_data
|
599
|
-
else:
|
600
|
-
return (
|
601
|
-
{},
|
602
|
-
f"只有{ot('TOOL_CALL')}标签,未找到{ct('TOOL_CALL')}标签,调用格式错误,请检查工具调用格式。\n{tool_call_help}",
|
603
|
-
)
|
597
|
+
data = temp_data
|
604
598
|
except (yaml.YAMLError, EOFError, KeyboardInterrupt):
|
605
599
|
# Even after fixing, it's not valid YAML, or user cancelled.
|
606
600
|
# Fall through to the original error.
|
@@ -2,9 +2,13 @@
|
|
2
2
|
"""A tool for searching the web."""
|
3
3
|
from typing import Any, Dict
|
4
4
|
|
5
|
-
import
|
6
|
-
from markdownify import markdownify as md
|
7
|
-
|
5
|
+
import requests
|
6
|
+
from markdownify import markdownify as md # type: ignore
|
7
|
+
|
8
|
+
# pylint: disable=import-error,missing-module-docstring
|
9
|
+
# fmt: off
|
10
|
+
from ddgs import DDGS # type: ignore[import-not-found]
|
11
|
+
# fmt: on
|
8
12
|
|
9
13
|
from jarvis.jarvis_agent import Agent
|
10
14
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
@@ -53,18 +57,18 @@ class SearchWebTool:
|
|
53
57
|
f"📄 ({visited_count + 1}/10) 正在抓取: {title} ({url})",
|
54
58
|
OutputType.INFO,
|
55
59
|
)
|
56
|
-
response = http_get(url, timeout=10.0,
|
57
|
-
content = md(response.text, strip=[
|
60
|
+
response = http_get(url, timeout=10.0, allow_redirects=True)
|
61
|
+
content = md(response.text, strip=["script", "style"])
|
58
62
|
if content:
|
59
63
|
full_content += content + "\n\n"
|
60
64
|
visited_urls.append(url)
|
61
65
|
visited_count += 1
|
62
|
-
except
|
66
|
+
except requests.exceptions.HTTPError as e:
|
63
67
|
PrettyOutput.print(
|
64
68
|
f"⚠️ HTTP错误 {e.response.status_code} 访问 {url}",
|
65
69
|
OutputType.WARNING,
|
66
70
|
)
|
67
|
-
except
|
71
|
+
except requests.exceptions.RequestException as e:
|
68
72
|
PrettyOutput.print(f"⚠️ 请求错误: {e}", OutputType.WARNING)
|
69
73
|
|
70
74
|
if not full_content.strip():
|
@@ -75,9 +79,7 @@ class SearchWebTool:
|
|
75
79
|
}
|
76
80
|
|
77
81
|
url_list_str = "\n".join(f" - {u}" for u in visited_urls)
|
78
|
-
PrettyOutput.print(
|
79
|
-
f"🔍 已成功访问并处理以下URL:\n{url_list_str}", OutputType.INFO
|
80
|
-
)
|
82
|
+
PrettyOutput.print(f"🔍 已成功访问并处理以下URL:\n{url_list_str}", OutputType.INFO)
|
81
83
|
|
82
84
|
PrettyOutput.print("🧠 正在总结内容...", OutputType.INFO)
|
83
85
|
summary_prompt = f"请为查询“{query}”总结以下内容:\n\n{full_content}"
|