jarvis-ai-assistant 0.1.111__py3-none-any.whl → 0.1.112__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.
Potentially problematic release.
This version of jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/agent.py +40 -34
- jarvis/jarvis_code_agent/code_agent.py +23 -5
- jarvis/jarvis_code_agent/file_select.py +16 -16
- jarvis/jarvis_code_agent/patch.py +17 -11
- jarvis/jarvis_code_agent/relevant_files.py +33 -40
- jarvis/jarvis_codebase/main.py +57 -48
- jarvis/jarvis_lsp/cpp.py +1 -1
- jarvis/jarvis_lsp/go.py +1 -1
- jarvis/jarvis_lsp/python.py +0 -2
- jarvis/jarvis_lsp/registry.py +13 -13
- jarvis/jarvis_lsp/rust.py +1 -1
- jarvis/jarvis_platform/ai8.py +14 -14
- jarvis/jarvis_platform/base.py +1 -1
- jarvis/jarvis_platform/kimi.py +17 -17
- jarvis/jarvis_platform/ollama.py +14 -14
- jarvis/jarvis_platform/openai.py +8 -8
- jarvis/jarvis_platform/oyi.py +19 -19
- jarvis/jarvis_platform/registry.py +6 -6
- jarvis/jarvis_platform_manager/main.py +17 -17
- jarvis/jarvis_rag/main.py +25 -25
- jarvis/jarvis_smart_shell/main.py +6 -6
- jarvis/jarvis_tools/ask_codebase.py +3 -3
- jarvis/jarvis_tools/ask_user.py +2 -2
- jarvis/jarvis_tools/create_code_agent.py +8 -8
- jarvis/jarvis_tools/create_sub_agent.py +2 -2
- jarvis/jarvis_tools/execute_shell.py +2 -2
- jarvis/jarvis_tools/file_operation.py +1 -1
- jarvis/jarvis_tools/git_commiter.py +4 -4
- jarvis/jarvis_tools/methodology.py +3 -3
- jarvis/jarvis_tools/rag.py +3 -3
- jarvis/jarvis_tools/read_code.py +1 -1
- jarvis/jarvis_tools/read_webpage.py +19 -6
- jarvis/jarvis_tools/registry.py +11 -11
- jarvis/jarvis_tools/search.py +88 -27
- jarvis/jarvis_tools/select_code_files.py +1 -1
- jarvis/jarvis_tools/tool_generator.py +182 -0
- jarvis/utils.py +18 -20
- jarvis_ai_assistant-0.1.112.dist-info/METADATA +460 -0
- jarvis_ai_assistant-0.1.112.dist-info/RECORD +64 -0
- jarvis_ai_assistant-0.1.111.dist-info/METADATA +0 -461
- jarvis_ai_assistant-0.1.111.dist-info/RECORD +0 -63
- {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/top_level.txt +0 -0
|
@@ -13,7 +13,7 @@ from jarvis.utils import PrettyOutput, OutputType, get_shell_name, init_env
|
|
|
13
13
|
def execute_command(command: str) -> None:
|
|
14
14
|
"""Show command and allow user to edit, then execute, Ctrl+C to cancel"""
|
|
15
15
|
try:
|
|
16
|
-
print("
|
|
16
|
+
print("生成的命令 (可以编辑, 按回车执行, Ctrl+C 取消):")
|
|
17
17
|
# Pre-fill input line
|
|
18
18
|
readline.set_startup_hook(lambda: readline.insert_text(command))
|
|
19
19
|
try:
|
|
@@ -21,11 +21,11 @@ def execute_command(command: str) -> None:
|
|
|
21
21
|
if edited_command.strip(): # Ensure command is not empty
|
|
22
22
|
os.system(edited_command)
|
|
23
23
|
except KeyboardInterrupt:
|
|
24
|
-
print("
|
|
24
|
+
PrettyOutput.print("执行取消", OutputType.INFO)
|
|
25
25
|
finally:
|
|
26
26
|
readline.set_startup_hook() # Clear pre-filled
|
|
27
27
|
except Exception as e:
|
|
28
|
-
PrettyOutput.print(f"
|
|
28
|
+
PrettyOutput.print(f"执行命令失败: {str(e)}", OutputType.WARNING)
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def process_request(request: str) -> Optional[str]:
|
|
@@ -85,14 +85,14 @@ Remember: Only return the command itself, without any additional content.
|
|
|
85
85
|
return None
|
|
86
86
|
|
|
87
87
|
except Exception as e:
|
|
88
|
-
PrettyOutput.print(f"
|
|
88
|
+
PrettyOutput.print(f"处理请求失败: {str(e)}", OutputType.WARNING)
|
|
89
89
|
return None
|
|
90
90
|
|
|
91
91
|
def main():
|
|
92
92
|
# 创建参数解析器
|
|
93
93
|
init_env()
|
|
94
94
|
parser = argparse.ArgumentParser(
|
|
95
|
-
description="
|
|
95
|
+
description="将自然语言要求转换为shell命令",
|
|
96
96
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
97
97
|
epilog="""
|
|
98
98
|
Example:
|
|
@@ -104,7 +104,7 @@ Example:
|
|
|
104
104
|
# 添加参数
|
|
105
105
|
parser.add_argument(
|
|
106
106
|
"request",
|
|
107
|
-
help="
|
|
107
|
+
help="描述您想要执行的操作, 用自然语言描述"
|
|
108
108
|
)
|
|
109
109
|
|
|
110
110
|
# 解析参数
|
|
@@ -45,7 +45,7 @@ class AskCodebaseTool:
|
|
|
45
45
|
question = args["question"]
|
|
46
46
|
top_k = args.get("top_k", 20)
|
|
47
47
|
|
|
48
|
-
PrettyOutput.print(f"
|
|
48
|
+
PrettyOutput.print(f"正在分析代码库以回答问题: {question}", OutputType.INFO)
|
|
49
49
|
|
|
50
50
|
# Create new CodeBase instance
|
|
51
51
|
git_root = find_git_root()
|
|
@@ -61,8 +61,8 @@ class AskCodebaseTool:
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
except Exception as e:
|
|
64
|
-
error_msg = f"
|
|
65
|
-
PrettyOutput.print(error_msg, OutputType.
|
|
64
|
+
error_msg = f"分析代码库失败: {str(e)}"
|
|
65
|
+
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
66
66
|
return {
|
|
67
67
|
"success": False,
|
|
68
68
|
"stdout": "",
|
jarvis/jarvis_tools/ask_user.py
CHANGED
|
@@ -30,10 +30,10 @@ class AskUserTool:
|
|
|
30
30
|
question = args["question"]
|
|
31
31
|
|
|
32
32
|
# Display the question
|
|
33
|
-
PrettyOutput.print(f"
|
|
33
|
+
PrettyOutput.print(f"问题: {question}", OutputType.SYSTEM)
|
|
34
34
|
|
|
35
35
|
# Get user input
|
|
36
|
-
user_response = get_multiline_input("
|
|
36
|
+
user_response = get_multiline_input("请输入您的答案 (输入空行结束)")
|
|
37
37
|
|
|
38
38
|
return {
|
|
39
39
|
"success": True,
|
|
@@ -31,7 +31,7 @@ class CreateCodeAgentTool:
|
|
|
31
31
|
# Step 1: Handle uncommitted changes
|
|
32
32
|
start_commit = None
|
|
33
33
|
if has_uncommitted_changes():
|
|
34
|
-
PrettyOutput.print("
|
|
34
|
+
PrettyOutput.print("发现未提交的更改,正在提交...", OutputType.INFO)
|
|
35
35
|
git_commiter = GitCommitTool()
|
|
36
36
|
result = git_commiter.execute({})
|
|
37
37
|
if not result["success"]:
|
|
@@ -45,7 +45,7 @@ class CreateCodeAgentTool:
|
|
|
45
45
|
start_commit = self._get_current_commit()
|
|
46
46
|
|
|
47
47
|
# Step 2: Development
|
|
48
|
-
PrettyOutput.print("
|
|
48
|
+
PrettyOutput.print("开始开发...", OutputType.INFO)
|
|
49
49
|
agent = CodeAgent()
|
|
50
50
|
agent.run(requirement)
|
|
51
51
|
|
|
@@ -53,7 +53,7 @@ class CreateCodeAgentTool:
|
|
|
53
53
|
end_commit = self._get_current_commit()
|
|
54
54
|
|
|
55
55
|
# Step 3: Code Review
|
|
56
|
-
PrettyOutput.print("
|
|
56
|
+
PrettyOutput.print("开始代码审查...", OutputType.INFO)
|
|
57
57
|
reviewer = CodeReviewTool()
|
|
58
58
|
review_result = reviewer.execute({
|
|
59
59
|
"review_type": "range",
|
|
@@ -69,15 +69,15 @@ class CreateCodeAgentTool:
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
# Step 4: Generate Summary
|
|
72
|
-
summary = f"""
|
|
72
|
+
summary = f"""开发总结:
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
开始提交: {start_commit}
|
|
75
|
+
结束提交: {end_commit}
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
需求:
|
|
78
78
|
{requirement}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
代码审查结果:
|
|
81
81
|
{extract_code_report(review_result["stdout"])}
|
|
82
82
|
"""
|
|
83
83
|
|
|
@@ -50,7 +50,7 @@ class SubAgentTool:
|
|
|
50
50
|
goal = args.get("goal", "")
|
|
51
51
|
files = args.get("files", [])
|
|
52
52
|
|
|
53
|
-
PrettyOutput.print(f"
|
|
53
|
+
PrettyOutput.print(f"创建子代理: {agent_name}", OutputType.INFO)
|
|
54
54
|
|
|
55
55
|
# Build task description
|
|
56
56
|
task_description = task
|
|
@@ -68,7 +68,7 @@ class SubAgentTool:
|
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
# Run sub-agent, pass file list
|
|
71
|
-
PrettyOutput.print("
|
|
71
|
+
PrettyOutput.print("子代理开始执行任务...", OutputType.INFO)
|
|
72
72
|
result = sub_agent.run(task_description, file_list=files)
|
|
73
73
|
|
|
74
74
|
return {
|
|
@@ -40,7 +40,7 @@ class ShellTool:
|
|
|
40
40
|
# Modify command to use script
|
|
41
41
|
tee_command = f"script -q -c '{escaped_command}' {output_file}"
|
|
42
42
|
|
|
43
|
-
PrettyOutput.print(f"
|
|
43
|
+
PrettyOutput.print(f"执行命令: {command}", OutputType.INFO)
|
|
44
44
|
|
|
45
45
|
# Execute command
|
|
46
46
|
return_code = os.system(tee_command)
|
|
@@ -55,7 +55,7 @@ class ShellTool:
|
|
|
55
55
|
if len(lines) > 2:
|
|
56
56
|
output = "\n".join(lines[1:-1])
|
|
57
57
|
except Exception as e:
|
|
58
|
-
output = f"
|
|
58
|
+
output = f"读取输出文件失败: {str(e)}"
|
|
59
59
|
finally:
|
|
60
60
|
# Clean up temporary file
|
|
61
61
|
Path(output_file).unlink(missing_ok=True)
|
|
@@ -43,7 +43,7 @@ class FileOperationTool:
|
|
|
43
43
|
|
|
44
44
|
# Record the operation and the full path
|
|
45
45
|
abs_path = os.path.abspath(filepath)
|
|
46
|
-
PrettyOutput.print(f"
|
|
46
|
+
PrettyOutput.print(f"文件操作: {operation} - {abs_path}", OutputType.INFO)
|
|
47
47
|
|
|
48
48
|
if operation == "exists":
|
|
49
49
|
exists = os.path.exists(filepath)
|
|
@@ -25,7 +25,7 @@ class GitCommitTool:
|
|
|
25
25
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
26
26
|
"""Execute automatic commit process"""
|
|
27
27
|
try:
|
|
28
|
-
PrettyOutput.print("
|
|
28
|
+
PrettyOutput.print("准备添加文件到提交...", OutputType.SYSTEM)
|
|
29
29
|
os.system("git add .")
|
|
30
30
|
PrettyOutput.print("Get diff...", OutputType.SYSTEM)
|
|
31
31
|
diff = os.popen("git diff --cached --exit-code").read()
|
|
@@ -40,17 +40,17 @@ class GitCommitTool:
|
|
|
40
40
|
|
|
41
41
|
{diff}
|
|
42
42
|
'''
|
|
43
|
-
PrettyOutput.print("
|
|
43
|
+
PrettyOutput.print("生成提交消息...", OutputType.SYSTEM)
|
|
44
44
|
platform = PlatformRegistry().get_codegen_platform()
|
|
45
45
|
platform.set_suppress_output(True)
|
|
46
46
|
commit_message = platform.chat_until_success(prompt)
|
|
47
47
|
commit_message = self._extract_commit_message(commit_message)
|
|
48
|
-
PrettyOutput.print("
|
|
48
|
+
PrettyOutput.print("提交...", OutputType.INFO)
|
|
49
49
|
os.popen(f"git commit -m '{commit_message}'")
|
|
50
50
|
|
|
51
51
|
commit_hash = self._get_last_commit_hash()
|
|
52
52
|
|
|
53
|
-
PrettyOutput.section(f"
|
|
53
|
+
PrettyOutput.section(f"提交哈希: {commit_hash}\n提交消息: {commit_message}", OutputType.SUCCESS)
|
|
54
54
|
|
|
55
55
|
return {"success": True, "stdout": yaml.safe_dump({"commit_hash": commit_hash, "commit_message": commit_message}), "stderr": ""}
|
|
56
56
|
|
|
@@ -47,7 +47,7 @@ class MethodologyTool:
|
|
|
47
47
|
with open(self.methodology_file, 'w', encoding='utf-8') as f:
|
|
48
48
|
yaml.safe_dump({}, f, allow_unicode=True)
|
|
49
49
|
except Exception as e:
|
|
50
|
-
PrettyOutput.print(f"
|
|
50
|
+
PrettyOutput.print(f"创建方法论文件失败:{str(e)}", OutputType.ERROR)
|
|
51
51
|
|
|
52
52
|
def _load_methodologies(self) -> Dict:
|
|
53
53
|
"""Load all methodologies"""
|
|
@@ -55,7 +55,7 @@ class MethodologyTool:
|
|
|
55
55
|
with open(self.methodology_file, 'r', encoding='utf-8') as f:
|
|
56
56
|
return yaml.safe_load(f) or {}
|
|
57
57
|
except Exception as e:
|
|
58
|
-
PrettyOutput.print(f"
|
|
58
|
+
PrettyOutput.print(f"加载方法论失败: {str(e)}", OutputType.ERROR)
|
|
59
59
|
return {}
|
|
60
60
|
|
|
61
61
|
def _save_methodologies(self, methodologies: Dict):
|
|
@@ -64,7 +64,7 @@ class MethodologyTool:
|
|
|
64
64
|
with open(self.methodology_file, 'w', encoding='utf-8') as f:
|
|
65
65
|
yaml.safe_dump(methodologies, f, allow_unicode=True)
|
|
66
66
|
except Exception as e:
|
|
67
|
-
PrettyOutput.print(f"
|
|
67
|
+
PrettyOutput.print(f"保存方法论失败: {str(e)}", OutputType.ERROR)
|
|
68
68
|
|
|
69
69
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
70
70
|
"""Execute the operation of managing methodologies
|
jarvis/jarvis_tools/rag.py
CHANGED
|
@@ -87,11 +87,11 @@ class RAGTool:
|
|
|
87
87
|
|
|
88
88
|
# If you need to rebuild the index or the index does not exist
|
|
89
89
|
if rebuild_index or not rag.is_index_built():
|
|
90
|
-
PrettyOutput.print("
|
|
90
|
+
PrettyOutput.print("正在构建文档索引...", OutputType.INFO)
|
|
91
91
|
rag.build_index(dir_path)
|
|
92
92
|
|
|
93
93
|
# Execute question and answer
|
|
94
|
-
PrettyOutput.print(f"
|
|
94
|
+
PrettyOutput.print(f"问题: {question}", OutputType.INFO)
|
|
95
95
|
response = rag.ask(question)
|
|
96
96
|
|
|
97
97
|
if response is None:
|
|
@@ -108,7 +108,7 @@ class RAGTool:
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
except Exception as e:
|
|
111
|
-
PrettyOutput.print(f"
|
|
111
|
+
PrettyOutput.print(f"文档问答失败:{str(e)}", OutputType.ERROR)
|
|
112
112
|
return {
|
|
113
113
|
"success": False,
|
|
114
114
|
"stdout": "",
|
jarvis/jarvis_tools/read_code.py
CHANGED
|
@@ -51,7 +51,7 @@ class ReadCodeTool:
|
|
|
51
51
|
|
|
52
52
|
# Record the operation and the full path
|
|
53
53
|
abs_path = os.path.abspath(filepath)
|
|
54
|
-
PrettyOutput.print(f"
|
|
54
|
+
PrettyOutput.print(f"正在读取代码文件:{abs_path}", OutputType.INFO)
|
|
55
55
|
|
|
56
56
|
# Check if file exists
|
|
57
57
|
if not os.path.exists(filepath):
|
|
@@ -5,7 +5,7 @@ from jarvis.utils import PrettyOutput, OutputType
|
|
|
5
5
|
|
|
6
6
|
class WebpageTool:
|
|
7
7
|
name = "read_webpage"
|
|
8
|
-
description = "Read webpage content, extract title and
|
|
8
|
+
description = "Read webpage content, extract title, text and hyperlinks"
|
|
9
9
|
parameters = {
|
|
10
10
|
"type": "object",
|
|
11
11
|
"properties": {
|
|
@@ -28,7 +28,7 @@ class WebpageTool:
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
# Send request
|
|
31
|
-
PrettyOutput.print(f"
|
|
31
|
+
PrettyOutput.print(f"正在读取网页:{url}", OutputType.INFO)
|
|
32
32
|
response = requests.get(url, headers=headers, timeout=10)
|
|
33
33
|
response.raise_for_status()
|
|
34
34
|
|
|
@@ -46,16 +46,29 @@ class WebpageTool:
|
|
|
46
46
|
title = soup.title.string if soup.title else ""
|
|
47
47
|
title = title.strip() if title else "No title"
|
|
48
48
|
|
|
49
|
-
# Extract text
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
# Extract text and links
|
|
50
|
+
text_parts = []
|
|
51
|
+
links = []
|
|
52
|
+
|
|
53
|
+
# Process content and collect links
|
|
54
|
+
for element in soup.descendants:
|
|
55
|
+
if element.name == 'a' and element.get('href'): # type: ignore
|
|
56
|
+
href = element.get('href') # type: ignore
|
|
57
|
+
text = element.get_text(strip=True)
|
|
58
|
+
if text and href:
|
|
59
|
+
links.append(f"[{text}]({href})")
|
|
60
|
+
elif isinstance(element, str) and element.strip():
|
|
61
|
+
text_parts.append(element.strip())
|
|
52
62
|
|
|
53
63
|
# Build output
|
|
54
64
|
output = [
|
|
55
65
|
f"Title: {title}",
|
|
56
66
|
"",
|
|
57
67
|
"Text content:",
|
|
58
|
-
"\n".join(
|
|
68
|
+
"\n".join(text_parts),
|
|
69
|
+
"",
|
|
70
|
+
"Links found:",
|
|
71
|
+
"\n".join(links) if links else "No links found"
|
|
59
72
|
]
|
|
60
73
|
|
|
61
74
|
return {
|
jarvis/jarvis_tools/registry.py
CHANGED
|
@@ -71,7 +71,7 @@ class ToolRegistry:
|
|
|
71
71
|
"""Use specified tools"""
|
|
72
72
|
missing_tools = [tool_name for tool_name in name if tool_name not in self.tools]
|
|
73
73
|
if missing_tools:
|
|
74
|
-
PrettyOutput.print(f"
|
|
74
|
+
PrettyOutput.print(f"工具 {missing_tools} 不存在,可用的工具有: {', '.join(self.tools.keys())}", OutputType.WARNING)
|
|
75
75
|
self.tools = {tool_name: self.tools[tool_name] for tool_name in name}
|
|
76
76
|
|
|
77
77
|
def dont_use_tools(self, names: List[str]):
|
|
@@ -116,7 +116,7 @@ class ToolRegistry:
|
|
|
116
116
|
try:
|
|
117
117
|
p_file_path = Path(file_path).resolve() # Get the absolute path
|
|
118
118
|
if not p_file_path.exists() or not p_file_path.is_file():
|
|
119
|
-
PrettyOutput.print(f"
|
|
119
|
+
PrettyOutput.print(f"文件不存在: {p_file_path}", OutputType.ERROR)
|
|
120
120
|
return False
|
|
121
121
|
|
|
122
122
|
# Add the parent directory to sys.path temporarily
|
|
@@ -167,7 +167,7 @@ class ToolRegistry:
|
|
|
167
167
|
sys.path.remove(parent_dir)
|
|
168
168
|
|
|
169
169
|
except Exception as e:
|
|
170
|
-
PrettyOutput.print(f"
|
|
170
|
+
PrettyOutput.print(f"从 {Path(file_path).name} 加载工具失败: {str(e)}", OutputType.ERROR)
|
|
171
171
|
return False
|
|
172
172
|
|
|
173
173
|
def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
|
|
@@ -215,12 +215,12 @@ arguments:
|
|
|
215
215
|
try:
|
|
216
216
|
args = json.loads(args)
|
|
217
217
|
except json.JSONDecodeError:
|
|
218
|
-
PrettyOutput.print(f"
|
|
218
|
+
PrettyOutput.print(f"工具参数格式无效: {name} {tool_call_help}", OutputType.ERROR)
|
|
219
219
|
return ""
|
|
220
220
|
|
|
221
221
|
# Display tool call information
|
|
222
|
-
PrettyOutput.section(f"
|
|
223
|
-
params = "
|
|
222
|
+
PrettyOutput.section(f"执行工具: {name}", OutputType.TOOL)
|
|
223
|
+
params = "参数:\n"
|
|
224
224
|
if isinstance(args, dict):
|
|
225
225
|
for key, value in args.items():
|
|
226
226
|
params += f"{key} = {value}\n"
|
|
@@ -245,12 +245,12 @@ arguments:
|
|
|
245
245
|
# Process the result
|
|
246
246
|
if result["success"]:
|
|
247
247
|
|
|
248
|
-
PrettyOutput.section("
|
|
248
|
+
PrettyOutput.section("执行成功", OutputType.SUCCESS)
|
|
249
249
|
|
|
250
250
|
# If the output exceeds 4k characters, use a large model to summarize
|
|
251
251
|
if get_context_token_count(output) > self.max_token_count:
|
|
252
252
|
try:
|
|
253
|
-
PrettyOutput.print("
|
|
253
|
+
PrettyOutput.print("输出过长,正在总结...", OutputType.PROGRESS)
|
|
254
254
|
model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
255
255
|
|
|
256
256
|
# If the output exceeds the maximum context length, only take the last part
|
|
@@ -282,11 +282,11 @@ Please provide a summary:"""
|
|
|
282
282
|
--- Summary ends ---"""
|
|
283
283
|
|
|
284
284
|
except Exception as e:
|
|
285
|
-
PrettyOutput.print(f"
|
|
285
|
+
PrettyOutput.print(f"总结失败: {str(e)}", OutputType.ERROR)
|
|
286
286
|
output = f"Output is too long ({len(output)} characters), it is recommended to view the original output.\nPreview of the first 300 characters:\n{output[:300]}..."
|
|
287
287
|
|
|
288
288
|
else:
|
|
289
|
-
PrettyOutput.section("
|
|
289
|
+
PrettyOutput.section("执行失败", OutputType.WARNING)
|
|
290
290
|
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
|
291
291
|
|
|
292
292
|
if len(tool_calls) > 1:
|
|
@@ -294,5 +294,5 @@ Please provide a summary:"""
|
|
|
294
294
|
return output
|
|
295
295
|
|
|
296
296
|
except Exception as e:
|
|
297
|
-
PrettyOutput.print(f"
|
|
297
|
+
PrettyOutput.print(f"工具执行失败:{str(e)}", OutputType.ERROR)
|
|
298
298
|
return f"Tool call failed: {str(e)}"
|
jarvis/jarvis_tools/search.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Dict, Any, List
|
|
2
2
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
3
|
-
from jarvis.utils import PrettyOutput, OutputType
|
|
3
|
+
from jarvis.utils import PrettyOutput, OutputType, get_context_token_count, get_max_token_count
|
|
4
4
|
from jarvis.jarvis_tools.read_webpage import WebpageTool
|
|
5
5
|
from playwright.sync_api import sync_playwright
|
|
6
6
|
from urllib.parse import quote
|
|
@@ -58,7 +58,7 @@ def bing_search(query):
|
|
|
58
58
|
return summaries
|
|
59
59
|
|
|
60
60
|
except Exception as error:
|
|
61
|
-
PrettyOutput.print(f"
|
|
61
|
+
PrettyOutput.print(f"搜索错误:{str(error)}", OutputType.ERROR)
|
|
62
62
|
return None
|
|
63
63
|
|
|
64
64
|
class SearchTool:
|
|
@@ -106,28 +106,89 @@ class SearchTool:
|
|
|
106
106
|
})
|
|
107
107
|
return formatted_results
|
|
108
108
|
except Exception as e:
|
|
109
|
-
PrettyOutput.print(f"
|
|
109
|
+
PrettyOutput.print(f"搜索请求失败:{str(e)}", OutputType.ERROR)
|
|
110
110
|
return []
|
|
111
111
|
|
|
112
112
|
def _extract_info(self, contents: List[str], question: str) -> str:
|
|
113
113
|
"""Use language model to extract key information from web content"""
|
|
114
|
-
|
|
114
|
+
try:
|
|
115
|
+
# Reserve tokens for prompt and response
|
|
116
|
+
max_tokens = get_max_token_count()
|
|
117
|
+
reserved_tokens = 2000 # Reserve tokens for prompt template and response
|
|
118
|
+
available_tokens = max_tokens - reserved_tokens
|
|
119
|
+
|
|
120
|
+
# Split contents into batches
|
|
121
|
+
batches = []
|
|
122
|
+
current_batch = []
|
|
123
|
+
current_tokens = 0
|
|
124
|
+
|
|
125
|
+
for content in contents:
|
|
126
|
+
content_tokens = get_context_token_count(content)
|
|
127
|
+
|
|
128
|
+
# If adding this content would exceed limit, start new batch
|
|
129
|
+
if current_tokens + content_tokens > available_tokens:
|
|
130
|
+
if current_batch:
|
|
131
|
+
batches.append(current_batch)
|
|
132
|
+
current_batch = [content]
|
|
133
|
+
current_tokens = content_tokens
|
|
134
|
+
else:
|
|
135
|
+
current_batch.append(content)
|
|
136
|
+
current_tokens += content_tokens
|
|
137
|
+
|
|
138
|
+
# Add final batch
|
|
139
|
+
if current_batch:
|
|
140
|
+
batches.append(current_batch)
|
|
115
141
|
|
|
116
|
-
|
|
142
|
+
# Process each batch
|
|
143
|
+
batch_results = []
|
|
144
|
+
for i, batch in enumerate(batches, 1):
|
|
145
|
+
PrettyOutput.print(f"正在处理批次 {i}/{len(batches)}...", OutputType.PROGRESS)
|
|
146
|
+
|
|
147
|
+
prompt = f"""Please analyze these search results to answer the question: {question}
|
|
148
|
+
|
|
149
|
+
Search results content (Batch {i}/{len(batches)}):
|
|
117
150
|
{'-' * 40}
|
|
118
|
-
{''.join(
|
|
151
|
+
{''.join(batch)}
|
|
119
152
|
{'-' * 40}
|
|
120
153
|
|
|
121
|
-
Please
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
154
|
+
Please extract key information related to the question. Focus on:
|
|
155
|
+
1. Relevant facts and details
|
|
156
|
+
2. Maintaining objectivity
|
|
157
|
+
3. Citing sources when appropriate
|
|
158
|
+
4. Noting any uncertainties
|
|
159
|
+
|
|
160
|
+
Format your response as a clear summary of findings from this batch."""
|
|
161
|
+
|
|
162
|
+
response = self.model.chat_until_success(prompt)
|
|
163
|
+
batch_results.append(response)
|
|
164
|
+
|
|
165
|
+
# If only one batch, return its result directly
|
|
166
|
+
if len(batch_results) == 1:
|
|
167
|
+
return batch_results[0]
|
|
168
|
+
|
|
169
|
+
# Synthesize results from all batches
|
|
170
|
+
batch_findings = '\n\n'.join(f'Batch {i+1}:\n{result}' for i, result in enumerate(batch_results))
|
|
171
|
+
separator = '-' * 40
|
|
172
|
+
|
|
173
|
+
synthesis_prompt = f"""Please provide a comprehensive answer to the original question by synthesizing the findings from multiple batches of search results.
|
|
174
|
+
|
|
175
|
+
Original Question: {question}
|
|
176
|
+
|
|
177
|
+
Findings from each batch:
|
|
178
|
+
{separator}
|
|
179
|
+
{batch_findings}
|
|
180
|
+
{separator}
|
|
181
|
+
|
|
182
|
+
Please synthesize a final answer that:
|
|
183
|
+
1. Combines key insights from all batches
|
|
184
|
+
2. Resolves any contradictions between sources
|
|
185
|
+
3. Maintains clear source attribution
|
|
186
|
+
4. Acknowledges any remaining uncertainties
|
|
187
|
+
5. Provides a coherent and complete response to the original question"""
|
|
188
|
+
|
|
189
|
+
final_response = self.model.chat_until_success(synthesis_prompt)
|
|
190
|
+
return final_response
|
|
127
191
|
|
|
128
|
-
try:
|
|
129
|
-
response = self.model.chat_until_success(prompt)
|
|
130
|
-
return response
|
|
131
192
|
except Exception as e:
|
|
132
193
|
return f"Information extraction failed: {str(e)}"
|
|
133
194
|
|
|
@@ -139,8 +200,8 @@ When answering, pay attention to:
|
|
|
139
200
|
max_results = args.get("max_results", 3)
|
|
140
201
|
|
|
141
202
|
# Print search information
|
|
142
|
-
PrettyOutput.print(f"
|
|
143
|
-
PrettyOutput.print(f"
|
|
203
|
+
PrettyOutput.print(f"搜索关键词: {query}", OutputType.INFO)
|
|
204
|
+
PrettyOutput.print(f"相关问题: {question}", OutputType.INFO)
|
|
144
205
|
|
|
145
206
|
# Get search results
|
|
146
207
|
results = self._search(query, max_results)
|
|
@@ -155,13 +216,13 @@ When answering, pay attention to:
|
|
|
155
216
|
contents = []
|
|
156
217
|
for i, result in enumerate(results, 1):
|
|
157
218
|
try:
|
|
158
|
-
PrettyOutput.print(f"
|
|
219
|
+
PrettyOutput.print(f"正在读取结果 {i}/{len(results)}... {result['title']} - {result['href']}", OutputType.PROGRESS)
|
|
159
220
|
webpage_result = self.webpage_tool.execute({"url": result["href"]})
|
|
160
221
|
if webpage_result["success"]:
|
|
161
222
|
contents.append(f"\nSource {i}: {result['href']}\n")
|
|
162
223
|
contents.append(webpage_result["stdout"])
|
|
163
224
|
except Exception as e:
|
|
164
|
-
PrettyOutput.print(f"
|
|
225
|
+
PrettyOutput.print(f"读取结果失败 {i}: {str(e)}", OutputType.WARNING)
|
|
165
226
|
continue
|
|
166
227
|
|
|
167
228
|
if not contents:
|
|
@@ -172,7 +233,7 @@ When answering, pay attention to:
|
|
|
172
233
|
}
|
|
173
234
|
|
|
174
235
|
# Extract information
|
|
175
|
-
PrettyOutput.print("
|
|
236
|
+
PrettyOutput.print("正在分析搜索结果...", OutputType.PROGRESS)
|
|
176
237
|
analysis = self._extract_info(contents, question)
|
|
177
238
|
|
|
178
239
|
return {
|
|
@@ -200,15 +261,15 @@ def main():
|
|
|
200
261
|
args = parser.parse_args()
|
|
201
262
|
|
|
202
263
|
try:
|
|
203
|
-
PrettyOutput.print(f"
|
|
264
|
+
PrettyOutput.print(f"搜索: {args.query}", OutputType.INFO)
|
|
204
265
|
|
|
205
266
|
results = bing_search(args.query)
|
|
206
267
|
|
|
207
268
|
if not results:
|
|
208
|
-
PrettyOutput.print("
|
|
269
|
+
PrettyOutput.print("未找到搜索结果", OutputType.WARNING)
|
|
209
270
|
sys.exit(1)
|
|
210
271
|
|
|
211
|
-
PrettyOutput.print(f"\
|
|
272
|
+
PrettyOutput.print(f"\n找到 {len(results)} 个结果:", OutputType.INFO)
|
|
212
273
|
|
|
213
274
|
for i, result in enumerate(results[:args.max], 1):
|
|
214
275
|
output = []
|
|
@@ -217,16 +278,16 @@ def main():
|
|
|
217
278
|
output.append(f"{i}. {result['href']}")
|
|
218
279
|
else:
|
|
219
280
|
output.append(f"{i}. {result['title']}")
|
|
220
|
-
output.append(f"
|
|
281
|
+
output.append(f"链接: {result['href']}")
|
|
221
282
|
if result['abstract']:
|
|
222
|
-
output.append(f"
|
|
283
|
+
output.append(f"摘要: {result['abstract']}")
|
|
223
284
|
PrettyOutput.print("\n".join(output), OutputType.INFO)
|
|
224
285
|
|
|
225
286
|
except KeyboardInterrupt:
|
|
226
|
-
PrettyOutput.print("
|
|
287
|
+
PrettyOutput.print("搜索已取消", OutputType.WARNING)
|
|
227
288
|
sys.exit(1)
|
|
228
289
|
except Exception as e:
|
|
229
|
-
PrettyOutput.print(f"
|
|
290
|
+
PrettyOutput.print(f"执行错误: {str(e)}", OutputType.ERROR)
|
|
230
291
|
sys.exit(1)
|
|
231
292
|
|
|
232
293
|
if __name__ == "__main__":
|
|
@@ -33,7 +33,7 @@ class CodeFileSelecterTool:
|
|
|
33
33
|
related_files = args.get("related_files", [])
|
|
34
34
|
root_dir = args.get("root_dir", ".").strip()
|
|
35
35
|
|
|
36
|
-
PrettyOutput.print("
|
|
36
|
+
PrettyOutput.print("开始交互式文件选择...", OutputType.INFO)
|
|
37
37
|
|
|
38
38
|
# Use file_select module to handle file selection
|
|
39
39
|
selected_files = select_files(
|