jarvis-ai-assistant 0.1.132__py3-none-any.whl → 0.1.138__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/jarvis_agent/__init__.py +330 -347
- jarvis/jarvis_agent/builtin_input_handler.py +16 -6
- jarvis/jarvis_agent/file_input_handler.py +9 -9
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +12 -13
- jarvis/jarvis_agent/output_handler.py +3 -3
- jarvis/jarvis_agent/patch.py +92 -64
- jarvis/jarvis_agent/shell_input_handler.py +5 -3
- jarvis/jarvis_code_agent/code_agent.py +263 -177
- jarvis/jarvis_code_agent/file_select.py +24 -24
- jarvis/jarvis_dev/main.py +45 -59
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +179 -0
- jarvis/jarvis_git_squash/main.py +7 -7
- jarvis/jarvis_lsp/base.py +11 -53
- jarvis/jarvis_lsp/cpp.py +13 -28
- jarvis/jarvis_lsp/go.py +13 -28
- jarvis/jarvis_lsp/python.py +8 -27
- jarvis/jarvis_lsp/registry.py +21 -83
- jarvis/jarvis_lsp/rust.py +15 -30
- jarvis/jarvis_methodology/main.py +101 -0
- jarvis/jarvis_multi_agent/__init__.py +10 -51
- jarvis/jarvis_multi_agent/main.py +43 -0
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/ai8.py +67 -89
- jarvis/jarvis_platform/base.py +14 -13
- jarvis/jarvis_platform/kimi.py +25 -28
- jarvis/jarvis_platform/ollama.py +24 -26
- jarvis/jarvis_platform/openai.py +15 -19
- jarvis/jarvis_platform/oyi.py +48 -50
- jarvis/jarvis_platform/registry.py +29 -44
- jarvis/jarvis_platform/yuanbao.py +39 -43
- jarvis/jarvis_platform_manager/main.py +81 -81
- jarvis/jarvis_platform_manager/openai_test.py +21 -21
- jarvis/jarvis_rag/file_processors.py +18 -18
- jarvis/jarvis_rag/main.py +262 -278
- jarvis/jarvis_smart_shell/main.py +12 -12
- jarvis/jarvis_tools/ask_codebase.py +85 -78
- jarvis/jarvis_tools/ask_user.py +8 -8
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +9 -9
- jarvis/jarvis_tools/code_review.py +40 -21
- jarvis/jarvis_tools/create_code_agent.py +15 -15
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- jarvis/jarvis_tools/execute_python_script.py +3 -3
- jarvis/jarvis_tools/execute_shell.py +11 -11
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_analyzer.py +116 -105
- jarvis/jarvis_tools/file_operation.py +22 -20
- jarvis/jarvis_tools/find_caller.py +105 -40
- jarvis/jarvis_tools/find_methodolopy.py +65 -0
- jarvis/jarvis_tools/find_symbol.py +123 -39
- jarvis/jarvis_tools/function_analyzer.py +140 -57
- jarvis/jarvis_tools/git_commiter.py +10 -10
- jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
- jarvis/jarvis_tools/methodology.py +22 -67
- jarvis/jarvis_tools/project_analyzer.py +137 -53
- jarvis/jarvis_tools/rag.py +15 -20
- jarvis/jarvis_tools/read_code.py +25 -23
- jarvis/jarvis_tools/read_webpage.py +31 -31
- jarvis/jarvis_tools/registry.py +72 -52
- jarvis/jarvis_tools/search_web.py +23 -353
- jarvis/jarvis_tools/tool_generator.py +19 -19
- jarvis/jarvis_utils/config.py +36 -96
- jarvis/jarvis_utils/embedding.py +83 -83
- jarvis/jarvis_utils/git_utils.py +20 -20
- jarvis/jarvis_utils/globals.py +18 -6
- jarvis/jarvis_utils/input.py +10 -9
- jarvis/jarvis_utils/methodology.py +141 -140
- jarvis/jarvis_utils/output.py +13 -13
- jarvis/jarvis_utils/utils.py +23 -71
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +6 -15
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +4 -3
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- jarvis/jarvis_tools/select_code_files.py +0 -62
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +0 -82
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
|
@@ -1,364 +1,34 @@
|
|
|
1
|
-
from typing import Dict, Any, List
|
|
2
|
-
import concurrent.futures
|
|
3
|
-
from regex import W
|
|
4
|
-
from yaspin import yaspin
|
|
5
|
-
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
6
|
-
from jarvis.jarvis_tools.read_webpage import WebpageTool
|
|
7
|
-
from playwright.sync_api import sync_playwright
|
|
8
|
-
from urllib.parse import quote
|
|
9
1
|
|
|
10
|
-
from jarvis.jarvis_utils.config import get_max_token_count, get_thread_count
|
|
11
|
-
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
12
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
13
2
|
|
|
14
|
-
def bing_search(query):
|
|
15
|
-
try:
|
|
16
|
-
with sync_playwright() as p:
|
|
17
|
-
# Set parameters when starting the browser
|
|
18
|
-
with yaspin(text="正在启动浏览器...", color="cyan") as spinner:
|
|
19
|
-
browser = p.chromium.launch(
|
|
20
|
-
headless=True, # Headless mode
|
|
21
|
-
args=['--disable-gpu', '--no-sandbox', '--disable-dev-shm-usage']
|
|
22
|
-
)
|
|
23
|
-
spinner.text = "浏览器启动完成"
|
|
24
|
-
spinner.ok("✅")
|
|
25
|
-
|
|
26
|
-
# Create a new page and set timeout
|
|
27
|
-
with yaspin(text="正在创建新页面...", color="cyan") as spinner:
|
|
28
|
-
page = browser.new_page(
|
|
29
|
-
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
30
|
-
viewport={'width': 1920, 'height': 1080}
|
|
31
|
-
)
|
|
32
|
-
spinner.text = "新页面创建完成"
|
|
33
|
-
spinner.ok("✅")
|
|
34
|
-
|
|
35
|
-
# Set page timeout
|
|
36
|
-
with yaspin(text="正在设置页面超时...", color="cyan") as spinner:
|
|
37
|
-
page.set_default_timeout(60000)
|
|
38
|
-
spinner.text = "页面超时设置完成"
|
|
39
|
-
spinner.ok("✅")
|
|
40
|
-
|
|
41
|
-
# Visit search page
|
|
42
|
-
with yaspin(text=f"正在搜索 {query}...", color="cyan") as spinner:
|
|
43
|
-
url = f"https://www.bing.com/search?q={quote(query)}&form=QBLH&sp=-1"
|
|
44
|
-
page.goto(url, wait_until="networkidle")
|
|
45
|
-
spinner.text = "搜索完成"
|
|
46
|
-
spinner.ok("✅")
|
|
47
|
-
|
|
48
|
-
# Wait for search results to load
|
|
49
|
-
with yaspin(text="正在等待搜索结果加载...", color="cyan") as spinner:
|
|
50
|
-
page.wait_for_selector("#b_results", state="visible", timeout=30000)
|
|
51
|
-
# Wait for a moment to ensure the results are fully loaded
|
|
52
|
-
page.wait_for_timeout(1000)
|
|
53
|
-
spinner.text = "搜索结果加载完成"
|
|
54
|
-
spinner.ok("✅")
|
|
55
|
-
|
|
56
|
-
# Extract search results
|
|
57
|
-
with yaspin(text="正在提取搜索结果...", color="cyan") as spinner:
|
|
58
|
-
summaries = page.evaluate("""() => {
|
|
59
|
-
const results = [];
|
|
60
|
-
const elements = document.querySelectorAll("#b_results > .b_algo");
|
|
61
|
-
|
|
62
|
-
for (const el of elements) {
|
|
63
|
-
const titleEl = el.querySelector("h2");
|
|
64
|
-
const linkEl = titleEl ? titleEl.querySelector("a") : null;
|
|
65
|
-
const abstractEl = el.querySelector(".b_caption p");
|
|
66
|
-
|
|
67
|
-
if (linkEl) {
|
|
68
|
-
results.push({
|
|
69
|
-
title: titleEl.innerText.trim(),
|
|
70
|
-
href: linkEl.href,
|
|
71
|
-
abstract: abstractEl ? abstractEl.innerText.trim() : ""
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return results;
|
|
76
|
-
}""")
|
|
77
|
-
spinner.text = "搜索结果提取完成"
|
|
78
|
-
spinner.ok("✅")
|
|
79
3
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
except Exception as error:
|
|
87
|
-
PrettyOutput.print(f"搜索错误:{str(error)}", OutputType.ERROR)
|
|
88
|
-
return None
|
|
4
|
+
import os
|
|
5
|
+
import statistics
|
|
6
|
+
from typing import Any, Dict
|
|
7
|
+
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
8
|
+
|
|
89
9
|
|
|
90
|
-
class
|
|
10
|
+
class SearchWebTool:
|
|
91
11
|
name = "search_web"
|
|
92
|
-
description = "
|
|
12
|
+
description = "搜索互联网上的信息"
|
|
93
13
|
parameters = {
|
|
94
14
|
"type": "object",
|
|
95
15
|
"properties": {
|
|
96
|
-
"query": {
|
|
97
|
-
|
|
98
|
-
"description": "搜索关键词"
|
|
99
|
-
},
|
|
100
|
-
"question": {
|
|
101
|
-
"type": "string",
|
|
102
|
-
"description": "要回答的具体问题,用于从搜索结果中提取相关信息"
|
|
103
|
-
},
|
|
104
|
-
"max_results": {
|
|
105
|
-
"type": "integer",
|
|
106
|
-
"description": "最大搜索结果数量",
|
|
107
|
-
"default": 10
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
"required": ["query", "question"]
|
|
16
|
+
"query": {"type": "string", "description": "具体的问题"}
|
|
17
|
+
}
|
|
111
18
|
}
|
|
112
19
|
|
|
113
|
-
def __init__(self):
|
|
114
|
-
"""Initialize the search tool, need to pass in the language model for information extraction"""
|
|
115
|
-
self.model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
116
|
-
self.webpage_tool = WebpageTool()
|
|
117
|
-
|
|
118
|
-
def _search(self, query: str, max_results: int) -> List[Dict]:
|
|
119
|
-
"""Execute search request"""
|
|
120
|
-
try:
|
|
121
|
-
results = bing_search(query)
|
|
122
|
-
if not results:
|
|
123
|
-
return []
|
|
124
|
-
|
|
125
|
-
# Format search results
|
|
126
|
-
formatted_results = []
|
|
127
|
-
for result in results[:max_results]:
|
|
128
|
-
formatted_results.append({
|
|
129
|
-
"title": result.get("title", ""),
|
|
130
|
-
"href": result.get("href", ""),
|
|
131
|
-
"body": result.get("abstract", "")
|
|
132
|
-
})
|
|
133
|
-
return formatted_results
|
|
134
|
-
except Exception as e:
|
|
135
|
-
PrettyOutput.print(f"搜索请求失败:{str(e)}", OutputType.ERROR)
|
|
136
|
-
return []
|
|
137
|
-
|
|
138
|
-
def _extract_info(self, contents: List[str], question: str) -> str:
|
|
139
|
-
"""Use language model to extract key information from web content"""
|
|
140
|
-
try:
|
|
141
|
-
# Reserve tokens for prompt and response
|
|
142
|
-
max_tokens = get_max_token_count()
|
|
143
|
-
reserved_tokens = 2000 # Reserve tokens for prompt template and response
|
|
144
|
-
available_tokens = max_tokens - reserved_tokens
|
|
145
|
-
|
|
146
|
-
# Split contents into batches
|
|
147
|
-
batches = []
|
|
148
|
-
current_batch = []
|
|
149
|
-
current_tokens = 0
|
|
150
|
-
|
|
151
|
-
for content in contents:
|
|
152
|
-
content_tokens = get_context_token_count(content)
|
|
153
|
-
|
|
154
|
-
# If adding this content would exceed limit, start new batch
|
|
155
|
-
if current_tokens + content_tokens > available_tokens:
|
|
156
|
-
if current_batch:
|
|
157
|
-
batches.append(current_batch)
|
|
158
|
-
current_batch = [content]
|
|
159
|
-
current_tokens = content_tokens
|
|
160
|
-
else:
|
|
161
|
-
current_batch.append(content)
|
|
162
|
-
current_tokens += content_tokens
|
|
163
|
-
|
|
164
|
-
# Add final batch
|
|
165
|
-
if current_batch:
|
|
166
|
-
batches.append(current_batch)
|
|
167
|
-
|
|
168
|
-
# Process each batch
|
|
169
|
-
batch_results = []
|
|
170
|
-
for i, batch in enumerate(batches, 1):
|
|
171
|
-
prompt = f"""请根据以下搜索结果回答以下问题:{question}
|
|
172
|
-
|
|
173
|
-
搜索结果内容 (第 {i} 批/{len(batches)}):
|
|
174
|
-
{'-' * 40}
|
|
175
|
-
{''.join(batch)}
|
|
176
|
-
{'-' * 40}
|
|
177
|
-
|
|
178
|
-
请提取与问题相关的关键信息。重点关注:
|
|
179
|
-
1. 相关事实和细节
|
|
180
|
-
2. 保持客观性
|
|
181
|
-
3. 在适当的时候引用来源
|
|
182
|
-
4. 注明任何不确定性
|
|
183
|
-
|
|
184
|
-
请将您的回答格式化为对本批次搜索结果的清晰总结。"""
|
|
185
|
-
|
|
186
|
-
response = self.model.chat_until_success(prompt)
|
|
187
|
-
batch_results.append(response)
|
|
188
|
-
|
|
189
|
-
# If only one batch, return its result directly
|
|
190
|
-
if len(batch_results) == 1:
|
|
191
|
-
return batch_results[0]
|
|
192
|
-
|
|
193
|
-
# Synthesize results from all batches
|
|
194
|
-
batch_findings = '\n\n'.join(f'Batch {i+1}:\n{result}' for i, result in enumerate(batch_results))
|
|
195
|
-
separator = '-' * 40
|
|
196
|
-
|
|
197
|
-
synthesis_prompt = f"""请通过综合多个批次的搜索结果,为原始问题提供一个全面的回答。
|
|
198
|
-
|
|
199
|
-
原始问题: {question}
|
|
200
|
-
|
|
201
|
-
各批次的发现:
|
|
202
|
-
{separator}
|
|
203
|
-
{batch_findings}
|
|
204
|
-
{separator}
|
|
205
|
-
|
|
206
|
-
请综合出一个最终答案,要求:
|
|
207
|
-
1. 整合所有批次的关键见解
|
|
208
|
-
2. 解决不同来源之间的矛盾
|
|
209
|
-
3. 保持清晰的来源归属
|
|
210
|
-
4. 承认任何剩余的不确定性
|
|
211
|
-
5. 提供对原始问题的连贯完整的回答"""
|
|
212
|
-
|
|
213
|
-
final_response = self.model.chat_until_success(synthesis_prompt)
|
|
214
|
-
return final_response
|
|
215
|
-
|
|
216
|
-
except Exception as e:
|
|
217
|
-
return f"信息提取失败:{str(e)}"
|
|
218
|
-
|
|
219
|
-
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
220
|
-
"""Execute search and extract information"""
|
|
221
|
-
try:
|
|
222
|
-
query = args["query"]
|
|
223
|
-
question = args["question"]
|
|
224
|
-
max_results = args.get("max_results", 3)
|
|
225
|
-
|
|
226
|
-
# Print search information
|
|
227
|
-
PrettyOutput.print(f"搜索关键词: {query}", OutputType.INFO)
|
|
228
|
-
PrettyOutput.print(f"相关问题: {question}", OutputType.INFO)
|
|
229
|
-
|
|
230
|
-
# Get search results
|
|
231
|
-
results = self._search(query, max_results)
|
|
232
|
-
if not results:
|
|
233
|
-
return {
|
|
234
|
-
"success": False,
|
|
235
|
-
"stdout": "",
|
|
236
|
-
"stderr": "No search results found"
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
# Read webpages in parallel using ThreadPoolExecutor
|
|
240
|
-
contents = []
|
|
241
|
-
|
|
242
|
-
# Print starting message
|
|
243
|
-
PrettyOutput.print(f"开始并行读取 {len(results)} 个网页结果...", OutputType.INFO)
|
|
244
|
-
|
|
245
|
-
def fetch_webpage(result_info):
|
|
246
|
-
"""Function to fetch a single webpage in a separate thread"""
|
|
247
|
-
idx, result = result_info
|
|
248
|
-
try:
|
|
249
|
-
# Removed progress print here to avoid mixed output
|
|
250
|
-
webpage_result = self.webpage_tool.execute({"url": result["href"]})
|
|
251
|
-
if webpage_result["success"]:
|
|
252
|
-
return idx, result, webpage_result["stdout"], True
|
|
253
|
-
return idx, result, None, False
|
|
254
|
-
except Exception as e:
|
|
255
|
-
return idx, result, str(e), False
|
|
256
|
-
|
|
257
|
-
# Use ThreadPoolExecutor for parallel processing
|
|
258
|
-
processed_results = []
|
|
259
|
-
with yaspin(text="正在并行读取网页内容...", color="cyan") as spinner:
|
|
260
|
-
with concurrent.futures.ThreadPoolExecutor(max_workers=get_thread_count()) as executor:
|
|
261
|
-
# Submit all webpage fetch tasks
|
|
262
|
-
future_to_result = {
|
|
263
|
-
executor.submit(fetch_webpage, (i, result)): i
|
|
264
|
-
for i, result in enumerate(results)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
# Collect results as they complete
|
|
268
|
-
for future in concurrent.futures.as_completed(future_to_result):
|
|
269
|
-
processed_results.append(future.result())
|
|
270
|
-
# Update spinner with current progress
|
|
271
|
-
spinner.text = f"正在并行读取网页内容... ({len(processed_results)}/{len(results)})"
|
|
272
|
-
|
|
273
|
-
spinner.text = "网页内容读取完成"
|
|
274
|
-
spinner.ok("✅")
|
|
275
|
-
|
|
276
|
-
# Sort results by original index to maintain ordering
|
|
277
|
-
processed_results.sort(key=lambda x: x[0])
|
|
278
|
-
|
|
279
|
-
# Print results in order and add to contents
|
|
280
|
-
PrettyOutput.section("搜索结果概览", OutputType.INFO)
|
|
281
|
-
|
|
282
|
-
output = []
|
|
283
|
-
for idx, result, content, success in processed_results:
|
|
284
|
-
if success:
|
|
285
|
-
output.append(f"✅ 读取结果 {idx+1}/{len(results)} 完成: {result['title']} - {result['href']}")
|
|
286
|
-
contents.append(f"\nSource {idx+1}: {result['href']}\n")
|
|
287
|
-
contents.append(content)
|
|
288
|
-
else:
|
|
289
|
-
output.append(f"❌ 读取结果 {idx+1}/{len(results)} 失败: {result['title']} - {result['href']}")
|
|
290
|
-
|
|
291
|
-
PrettyOutput.print("\n".join(output), OutputType.INFO)
|
|
292
|
-
|
|
293
|
-
if not contents:
|
|
294
|
-
return {
|
|
295
|
-
"success": False,
|
|
296
|
-
"stdout": "",
|
|
297
|
-
"stderr": "No valid search results found"
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
# Extract information
|
|
301
|
-
with yaspin(text="正在提取信息...", color="cyan") as spinner:
|
|
302
|
-
analysis = self._extract_info(contents, question)
|
|
303
|
-
spinner.text = "信息提取完成"
|
|
304
|
-
spinner.ok("✅")
|
|
305
|
-
|
|
306
|
-
output = f"分析结果:\n\n{analysis}"
|
|
307
|
-
PrettyOutput.print(output, OutputType.SUCCESS)
|
|
308
|
-
|
|
309
|
-
return {
|
|
310
|
-
"success": True,
|
|
311
|
-
"stdout": output,
|
|
312
|
-
"stderr": ""
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
except Exception as e:
|
|
316
|
-
return {
|
|
317
|
-
"success": False,
|
|
318
|
-
"stdout": "",
|
|
319
|
-
"stderr": f"Search failed: {str(e)}"
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
def main():
|
|
323
|
-
"""Command line directly run search tool"""
|
|
324
|
-
import argparse
|
|
325
|
-
import sys
|
|
326
|
-
|
|
327
|
-
parser = argparse.ArgumentParser(description='Bing search tool')
|
|
328
|
-
parser.add_argument('query', help='Search keywords')
|
|
329
|
-
parser.add_argument('--max', type=int, default=5, help='Maximum number of results (default 5)')
|
|
330
|
-
parser.add_argument('--url-only', action='store_true', help='Only display URL')
|
|
331
|
-
args = parser.parse_args()
|
|
332
|
-
|
|
333
|
-
try:
|
|
334
|
-
PrettyOutput.print(f"搜索: {args.query}", OutputType.INFO)
|
|
335
|
-
|
|
336
|
-
results = bing_search(args.query)
|
|
337
|
-
|
|
338
|
-
if not results:
|
|
339
|
-
PrettyOutput.print("未找到搜索结果", OutputType.WARNING)
|
|
340
|
-
sys.exit(1)
|
|
341
|
-
|
|
342
|
-
PrettyOutput.print(f"\n找到 {len(results)} 个结果:", OutputType.INFO)
|
|
343
|
-
|
|
344
|
-
for i, result in enumerate(results[:args.max], 1):
|
|
345
|
-
output = []
|
|
346
|
-
output.append(f"\n{'-'*50}")
|
|
347
|
-
if args.url_only:
|
|
348
|
-
output.append(f"{i}. {result['href']}")
|
|
349
|
-
else:
|
|
350
|
-
output.append(f"{i}. {result['title']}")
|
|
351
|
-
output.append(f"链接: {result['href']}")
|
|
352
|
-
if result['abstract']:
|
|
353
|
-
output.append(f"摘要: {result['abstract']}")
|
|
354
|
-
PrettyOutput.print("\n".join(output), OutputType.INFO)
|
|
355
|
-
|
|
356
|
-
except KeyboardInterrupt:
|
|
357
|
-
PrettyOutput.print("搜索已取消", OutputType.WARNING)
|
|
358
|
-
sys.exit(1)
|
|
359
|
-
except Exception as e:
|
|
360
|
-
PrettyOutput.print(f"执行错误: {str(e)}", OutputType.ERROR)
|
|
361
|
-
sys.exit(1)
|
|
362
20
|
|
|
363
|
-
|
|
364
|
-
|
|
21
|
+
@staticmethod
|
|
22
|
+
def check() -> bool:
|
|
23
|
+
return os.getenv("YUANBAO_COOKIES", "") != "" and os.getenv("YUANBAO_AGENT_ID", "") != ""
|
|
24
|
+
|
|
25
|
+
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]: # type: ignore
|
|
26
|
+
query = args.get("query")
|
|
27
|
+
model = PlatformRegistry().create_platform("yuanbao")
|
|
28
|
+
model.set_suppress_output(False) # type: ignore
|
|
29
|
+
model.set_model_name("deep_seek") # type: ignore
|
|
30
|
+
return {
|
|
31
|
+
"stdout": model.chat_until_success(query), # type: ignore
|
|
32
|
+
"stderr": "",
|
|
33
|
+
"success": True,
|
|
34
|
+
}
|
|
@@ -11,7 +11,7 @@ from jarvis.jarvis_utils.utils import ct, ot
|
|
|
11
11
|
|
|
12
12
|
class ToolGenerator:
|
|
13
13
|
"""工具生成器类,用于自动创建与Jarvis系统集成的新工具"""
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
name = "tool_generator"
|
|
16
16
|
description = "使用LLM自动生成与系统集成的新工具"
|
|
17
17
|
parameters = {
|
|
@@ -22,7 +22,7 @@ class ToolGenerator:
|
|
|
22
22
|
"description": "新工具的名称"
|
|
23
23
|
},
|
|
24
24
|
"description": {
|
|
25
|
-
"type": "string",
|
|
25
|
+
"type": "string",
|
|
26
26
|
"description": "工具用途描述"
|
|
27
27
|
},
|
|
28
28
|
"input_spec": {
|
|
@@ -32,7 +32,7 @@ class ToolGenerator:
|
|
|
32
32
|
},
|
|
33
33
|
"required": ["tool_name", "description", "input_spec"]
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
def execute(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
37
37
|
"""
|
|
38
38
|
执行工具生成过程
|
|
@@ -42,20 +42,20 @@ class ToolGenerator:
|
|
|
42
42
|
包含执行结果的字典,包含success、stdout和stderr字段
|
|
43
43
|
"""
|
|
44
44
|
# 获取代码生成平台实例
|
|
45
|
-
model = PlatformRegistry.get_global_platform_registry().
|
|
46
|
-
|
|
45
|
+
model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
46
|
+
|
|
47
47
|
try:
|
|
48
48
|
tool_name = arguments["tool_name"]
|
|
49
49
|
description = arguments["description"]
|
|
50
50
|
input_spec = arguments["input_spec"]
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# 使用LLM生成工具实现代码
|
|
53
53
|
with yaspin(text="正在生成工具...", color="cyan") as spinner:
|
|
54
54
|
prompt = self._create_prompt(tool_name, description, input_spec)
|
|
55
55
|
llm_response = model.chat_until_success(prompt)
|
|
56
56
|
spinner.text = "工具生成完成"
|
|
57
57
|
spinner.ok("✅")
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
# 从LLM响应中提取实现代码
|
|
60
60
|
with yaspin(text="正在提取工具实现...", color="cyan") as spinner:
|
|
61
61
|
implementation = self._extract_code(llm_response)
|
|
@@ -67,7 +67,7 @@ class ToolGenerator:
|
|
|
67
67
|
}
|
|
68
68
|
spinner.text = "工具实现提取完成"
|
|
69
69
|
spinner.ok("✅")
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
# 验证生成的工具代码是否符合返回值格式要求
|
|
72
72
|
with yaspin(text="正在验证工具返回值格式...", color="cyan") as spinner:
|
|
73
73
|
if not self._validate_return_value_format(implementation):
|
|
@@ -78,31 +78,31 @@ class ToolGenerator:
|
|
|
78
78
|
}
|
|
79
79
|
spinner.text = "工具返回值格式验证完成"
|
|
80
80
|
spinner.ok("✅")
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
# 保存生成的新工具
|
|
83
83
|
with yaspin(text="正在保存工具...", color="cyan") as spinner:
|
|
84
84
|
tools_dir = Path.home() / ".jarvis" / "tools"
|
|
85
85
|
tools_dir.mkdir(parents=True, exist_ok=True)
|
|
86
86
|
tool_file = tools_dir / f"{tool_name}.py"
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
with open(tool_file, "w", errors="ignore") as f:
|
|
89
89
|
f.write(implementation)
|
|
90
90
|
spinner.text = "工具保存完成"
|
|
91
91
|
spinner.ok("✅")
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
return {
|
|
94
94
|
"success": True,
|
|
95
95
|
"stdout": f"工具成功生成于: {tool_file}",
|
|
96
96
|
"stderr": ""
|
|
97
97
|
}
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
except Exception as e:
|
|
100
100
|
return {
|
|
101
101
|
"success": False,
|
|
102
102
|
"stdout": "",
|
|
103
103
|
"stderr": f"工具生成失败: {str(e)}"
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
def _create_prompt(self, tool_name: str, description: str, input_spec: str) -> str:
|
|
107
107
|
"""
|
|
108
108
|
创建用于工具生成的LLM提示
|
|
@@ -134,10 +134,10 @@ class CustomTool:
|
|
|
134
134
|
|
|
135
135
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
136
136
|
"""执行工具功能
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
Args:
|
|
139
139
|
args: 传递给工具的参数
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
Returns:
|
|
142
142
|
{
|
|
143
143
|
"success": bool,
|
|
@@ -148,7 +148,7 @@ class CustomTool:
|
|
|
148
148
|
try:
|
|
149
149
|
# 在此实现工具逻辑
|
|
150
150
|
# 使用LLM
|
|
151
|
-
# model = PlatformRegistry.get_global_platform_registry().
|
|
151
|
+
# model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
152
152
|
# result = model.chat_until_success(prompt)
|
|
153
153
|
|
|
154
154
|
result = "工具执行结果"
|
|
@@ -189,7 +189,7 @@ class CustomTool:
|
|
|
189
189
|
示例:
|
|
190
190
|
{example_code}
|
|
191
191
|
'''
|
|
192
|
-
|
|
192
|
+
|
|
193
193
|
def _extract_code(self, response: str) -> str:
|
|
194
194
|
"""
|
|
195
195
|
从LLM响应中提取Python代码
|
|
@@ -202,7 +202,7 @@ class CustomTool:
|
|
|
202
202
|
if sm:
|
|
203
203
|
return sm.group(1)
|
|
204
204
|
return ""
|
|
205
|
-
|
|
205
|
+
|
|
206
206
|
def _validate_return_value_format(self, code: str) -> bool:
|
|
207
207
|
"""
|
|
208
208
|
验证execute方法的返回值格式是否正确
|
|
@@ -216,6 +216,6 @@ class CustomTool:
|
|
|
216
216
|
if "def execute(self, args: Dict) -> Dict:" not in code and \
|
|
217
217
|
"def execute(self, args: Dict) -> Dict[str, Any]:" not in code:
|
|
218
218
|
return False
|
|
219
|
-
|
|
219
|
+
|
|
220
220
|
# 检查返回值中是否包含所有必需字段
|
|
221
221
|
return all(field in code for field in required_fields)
|