entari-plugin-hyw 4.0.0rc12__py3-none-any.whl → 4.0.0rc13__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 entari-plugin-hyw might be problematic. Click here for more details.
- {entari_plugin_hyw-4.0.0rc12.dist-info → entari_plugin_hyw-4.0.0rc13.dist-info}/METADATA +1 -1
- {entari_plugin_hyw-4.0.0rc12.dist-info → entari_plugin_hyw-4.0.0rc13.dist-info}/RECORD +6 -6
- hyw_core/agent.py +87 -30
- hyw_core/definitions.py +4 -1
- {entari_plugin_hyw-4.0.0rc12.dist-info → entari_plugin_hyw-4.0.0rc13.dist-info}/WHEEL +0 -0
- {entari_plugin_hyw-4.0.0rc12.dist-info → entari_plugin_hyw-4.0.0rc13.dist-info}/top_level.txt +0 -0
|
@@ -5,10 +5,10 @@ entari_plugin_hyw/history.py,sha256=0XJwbfvXH5T1EPt4G1J5wWMJsKi0FfmajY5cvw8CQWE,
|
|
|
5
5
|
entari_plugin_hyw/misc.py,sha256=5IqF5Z2C_6Ufy5TI89uX5hX5fVYcXOTZIQUIu_tvf54,6855
|
|
6
6
|
entari_plugin_hyw/search_cache.py,sha256=7MIhTm5_YnZjc0aBaX7AE4AJp0VT8eU6ObR6mTkoerc,4285
|
|
7
7
|
hyw_core/__init__.py,sha256=Jlr9Ic-BLOPTnff6OctUCdjDMdK4nssTF_vHie4QKTo,1958
|
|
8
|
-
hyw_core/agent.py,sha256=
|
|
8
|
+
hyw_core/agent.py,sha256=xKvO9CIo0MX7mBQ6DuLDaDLvREyRIZMNXKk4tpOMi1U,29496
|
|
9
9
|
hyw_core/config.py,sha256=DHxwToUVLm1nT88gG05e3hVzSLxXMk9BjgjAnhGCADk,4918
|
|
10
10
|
hyw_core/core.py,sha256=_jN4831OeHQ_aM7sIlzcwYb5_Lp82kp2XmqpJD_tsLA,16097
|
|
11
|
-
hyw_core/definitions.py,sha256=
|
|
11
|
+
hyw_core/definitions.py,sha256=pH46L-N25pSuPaIiN7l7yfoD6oHK6BLHigE0eYLFmJQ,4270
|
|
12
12
|
hyw_core/image_cache.py,sha256=t8pr1kgH2ngK9IhrBAhzUqhBWERNztUywMzgCFZEtQk,9899
|
|
13
13
|
hyw_core/pipeline.py,sha256=ZWwF0DHa29-65lUMU1_Fem3xQmxl7X_vgeni0ErOb8Q,22826
|
|
14
14
|
hyw_core/search.py,sha256=VvfNSb9Hf7ZQWlNtnZfYe2eO9qPjYtwJxVlud6OdeCQ,7787
|
|
@@ -66,7 +66,7 @@ hyw_core/crawling/models.py,sha256=pCKe0k9xT3taSAlTlh0PazcLV0xYsm8p3XIkLHGf-LM,2
|
|
|
66
66
|
hyw_core/stages/__init__.py,sha256=W89cWpq-HBLi2FprtJQSjQNLzpbhM8ZCkqPG61D_imE,521
|
|
67
67
|
hyw_core/stages/base.py,sha256=EfnTkISXbBNxjARykqIhmMrVqw2tqZl7ozJbJEbRnhI,2806
|
|
68
68
|
hyw_core/stages/summary.py,sha256=sgHCm_Leq_pkJ4YcgQuf8croiOP1oKz171TnzJwRwVs,7080
|
|
69
|
-
entari_plugin_hyw-4.0.
|
|
70
|
-
entari_plugin_hyw-4.0.
|
|
71
|
-
entari_plugin_hyw-4.0.
|
|
72
|
-
entari_plugin_hyw-4.0.
|
|
69
|
+
entari_plugin_hyw-4.0.0rc13.dist-info/METADATA,sha256=NhbBeH0svhxJ6MvHl6vKF-BCzg-jRczAhlg_3fXD_lM,3845
|
|
70
|
+
entari_plugin_hyw-4.0.0rc13.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
71
|
+
entari_plugin_hyw-4.0.0rc13.dist-info/top_level.txt,sha256=ah76OrufRX0okOl4Fv8MO6PXiT0IaZ1oG0eDrdAPoNo,27
|
|
72
|
+
entari_plugin_hyw-4.0.0rc13.dist-info/RECORD,,
|
hyw_core/agent.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Agent Pipeline
|
|
3
3
|
|
|
4
4
|
Tool-calling agent that can autonomously use web_tool to search/screenshot.
|
|
5
|
-
Maximum 2 tool calls,
|
|
5
|
+
Maximum 2 rounds of tool calls, up to 3 parallel calls per round.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import asyncio
|
|
@@ -31,6 +31,9 @@ class AgentSession:
|
|
|
31
31
|
messages: List[Dict] = field(default_factory=list) # LLM conversation
|
|
32
32
|
created_at: float = field(default_factory=time.time)
|
|
33
33
|
|
|
34
|
+
# Round tracking (each round can have up to 3 parallel tool calls)
|
|
35
|
+
round_count: int = 0
|
|
36
|
+
|
|
34
37
|
# Image tracking
|
|
35
38
|
user_image_count: int = 0 # Number of images from user input
|
|
36
39
|
total_image_count: int = 0 # Total images including web screenshots
|
|
@@ -45,12 +48,13 @@ class AgentSession:
|
|
|
45
48
|
|
|
46
49
|
@property
|
|
47
50
|
def call_count(self) -> int:
|
|
51
|
+
"""Total number of individual tool calls."""
|
|
48
52
|
return len(self.tool_calls)
|
|
49
53
|
|
|
50
54
|
@property
|
|
51
55
|
def should_force_summary(self) -> bool:
|
|
52
|
-
"""
|
|
53
|
-
return self.
|
|
56
|
+
"""Force summary after 2 rounds of tool calls."""
|
|
57
|
+
return self.round_count >= 2
|
|
54
58
|
|
|
55
59
|
|
|
56
60
|
def parse_filter_syntax(query: str, max_count: int = 3):
|
|
@@ -130,12 +134,13 @@ class AgentPipeline:
|
|
|
130
134
|
|
|
131
135
|
Flow:
|
|
132
136
|
1. 用户输入 → LLM (with tools)
|
|
133
|
-
2. If tool_call: execute
|
|
134
|
-
3. If call_count >= 2: force summary on next call
|
|
137
|
+
2. If tool_call: execute all tools in parallel → notify user with batched message → loop
|
|
138
|
+
3. If call_count >= 2 rounds: force summary on next call
|
|
135
139
|
4. Return final content
|
|
136
140
|
"""
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
MAX_TOOL_ROUNDS = 2 # Maximum rounds of tool calls
|
|
143
|
+
MAX_PARALLEL_TOOLS = 3 # Maximum parallel tool calls per round
|
|
139
144
|
|
|
140
145
|
def __init__(
|
|
141
146
|
self,
|
|
@@ -183,7 +188,9 @@ class AgentPipeline:
|
|
|
183
188
|
|
|
184
189
|
# Build initial messages
|
|
185
190
|
language = getattr(self.config, "language", "Simplified Chinese")
|
|
186
|
-
|
|
191
|
+
from datetime import datetime
|
|
192
|
+
current_time = datetime.now().strftime("%Y-%m-%d %H:%M")
|
|
193
|
+
system_prompt = AGENT_SYSTEM_PROMPT + f"\n\n用户要求的语言: {language}\n当前时间: {current_time}"
|
|
187
194
|
|
|
188
195
|
# Build user content with images if provided
|
|
189
196
|
user_image_count = len(images) if images else 0
|
|
@@ -230,7 +237,7 @@ class AgentPipeline:
|
|
|
230
237
|
while True:
|
|
231
238
|
# Check if we need to force summary (no tools)
|
|
232
239
|
if session.should_force_summary:
|
|
233
|
-
logger.info(f"AgentPipeline: Max tool
|
|
240
|
+
logger.info(f"AgentPipeline: Max tool rounds ({self.MAX_TOOL_ROUNDS}) reached, forcing summary")
|
|
234
241
|
# Add context message about collected info
|
|
235
242
|
if context.web_results:
|
|
236
243
|
context_msg = self._format_web_context(context)
|
|
@@ -307,7 +314,12 @@ class AgentPipeline:
|
|
|
307
314
|
]
|
|
308
315
|
})
|
|
309
316
|
|
|
310
|
-
# Execute tool calls
|
|
317
|
+
# Execute all tool calls in parallel
|
|
318
|
+
tool_tasks = []
|
|
319
|
+
tool_call_ids = []
|
|
320
|
+
tool_call_names = []
|
|
321
|
+
tool_call_args_list = []
|
|
322
|
+
|
|
311
323
|
for tool_call in message.tool_calls:
|
|
312
324
|
tc_id = tool_call.id
|
|
313
325
|
func_name = tool_call.function.name
|
|
@@ -317,17 +329,22 @@ class AgentPipeline:
|
|
|
317
329
|
except json.JSONDecodeError:
|
|
318
330
|
args = {}
|
|
319
331
|
|
|
320
|
-
|
|
321
|
-
|
|
332
|
+
tool_call_ids.append(tc_id)
|
|
333
|
+
tool_call_names.append(func_name)
|
|
334
|
+
tool_call_args_list.append(args)
|
|
335
|
+
logger.info(f"AgentPipeline: Queueing tool '{func_name}' with args: {args}")
|
|
336
|
+
|
|
337
|
+
# Check for refuse_answer first (handle immediately)
|
|
338
|
+
for idx, func_name in enumerate(tool_call_names):
|
|
322
339
|
if func_name == "refuse_answer":
|
|
323
|
-
|
|
340
|
+
args = tool_call_args_list[idx]
|
|
324
341
|
reason = args.get("reason", "Refused")
|
|
325
342
|
context.should_refuse = True
|
|
326
343
|
context.refuse_reason = reason
|
|
327
344
|
|
|
328
345
|
session.messages.append({
|
|
329
346
|
"role": "tool",
|
|
330
|
-
"tool_call_id":
|
|
347
|
+
"tool_call_id": tool_call_ids[idx],
|
|
331
348
|
"content": f"已拒绝回答: {reason}"
|
|
332
349
|
})
|
|
333
350
|
|
|
@@ -339,23 +356,50 @@ class AgentPipeline:
|
|
|
339
356
|
"stats": {"total_time": time.time() - start_time},
|
|
340
357
|
"usage": usage_totals,
|
|
341
358
|
}
|
|
359
|
+
|
|
360
|
+
# Execute web_tool calls in parallel
|
|
361
|
+
search_start = time.time()
|
|
362
|
+
tasks_to_run = []
|
|
363
|
+
task_indices = []
|
|
364
|
+
|
|
365
|
+
for idx, func_name in enumerate(tool_call_names):
|
|
366
|
+
if func_name == "web_tool":
|
|
367
|
+
tasks_to_run.append(self._execute_web_tool(tool_call_args_list[idx], context))
|
|
368
|
+
task_indices.append(idx)
|
|
369
|
+
|
|
370
|
+
# Run all web_tool calls in parallel
|
|
371
|
+
if tasks_to_run:
|
|
372
|
+
results = await asyncio.gather(*tasks_to_run, return_exceptions=True)
|
|
373
|
+
else:
|
|
374
|
+
results = []
|
|
375
|
+
|
|
376
|
+
session.search_time += time.time() - search_start
|
|
377
|
+
|
|
378
|
+
# Process results and collect notifications
|
|
379
|
+
notifications = []
|
|
380
|
+
result_map = {} # Map task index to result
|
|
381
|
+
|
|
382
|
+
for i, result in enumerate(results):
|
|
383
|
+
task_idx = task_indices[i]
|
|
384
|
+
if isinstance(result, Exception):
|
|
385
|
+
result_map[task_idx] = {"summary": f"执行失败: {result}", "results": []}
|
|
386
|
+
else:
|
|
387
|
+
result_map[task_idx] = result
|
|
388
|
+
|
|
389
|
+
# Add all tool results to messages and collect notifications
|
|
390
|
+
for idx, func_name in enumerate(tool_call_names):
|
|
391
|
+
tc_id = tool_call_ids[idx]
|
|
392
|
+
args = tool_call_args_list[idx]
|
|
342
393
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
search_start = time.time()
|
|
346
|
-
result = await self._execute_web_tool(args, context)
|
|
347
|
-
session.search_time += time.time() - search_start
|
|
394
|
+
if func_name == "web_tool":
|
|
395
|
+
result = result_map.get(idx, {"summary": "未执行", "results": []})
|
|
348
396
|
|
|
349
397
|
# Track tool call
|
|
350
398
|
session.tool_calls.append({"name": func_name, "args": args})
|
|
351
399
|
session.tool_results.append(result)
|
|
352
400
|
|
|
353
|
-
#
|
|
354
|
-
|
|
355
|
-
try:
|
|
356
|
-
await self.send_func(f"🔍 {result['summary']}")
|
|
357
|
-
except Exception as e:
|
|
358
|
-
logger.warning(f"AgentPipeline: Failed to send notification: {e}")
|
|
401
|
+
# Collect notification
|
|
402
|
+
notifications.append(f"🔍 {result['summary']}")
|
|
359
403
|
|
|
360
404
|
# Add tool result to messages
|
|
361
405
|
result_content = f"搜索完成: {result['summary']}\n\n找到 {len(result.get('results', []))} 个结果"
|
|
@@ -368,15 +412,15 @@ class AgentPipeline:
|
|
|
368
412
|
# Add image source hint for web screenshots
|
|
369
413
|
screenshot_count = result.get("screenshot_count", 0)
|
|
370
414
|
if screenshot_count > 0:
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
session.total_image_count =
|
|
415
|
+
start_idx_img = session.total_image_count + 1
|
|
416
|
+
end_idx_img = session.total_image_count + screenshot_count
|
|
417
|
+
session.total_image_count = end_idx_img
|
|
374
418
|
|
|
375
419
|
source_desc = result.get("source_desc", "网页截图")
|
|
376
|
-
if
|
|
377
|
-
hint = f"第{
|
|
420
|
+
if start_idx_img == end_idx_img:
|
|
421
|
+
hint = f"第{start_idx_img}张图片来自{source_desc},作为查询的参考资料"
|
|
378
422
|
else:
|
|
379
|
-
hint = f"第{
|
|
423
|
+
hint = f"第{start_idx_img}-{end_idx_img}张图片来自{source_desc},作为查询的参考资料"
|
|
380
424
|
session.messages.append({"role": "system", "content": hint})
|
|
381
425
|
else:
|
|
382
426
|
# Unknown tool
|
|
@@ -385,6 +429,19 @@ class AgentPipeline:
|
|
|
385
429
|
"tool_call_id": tc_id,
|
|
386
430
|
"content": f"Unknown tool: {func_name}"
|
|
387
431
|
})
|
|
432
|
+
|
|
433
|
+
# Send batched notification (up to 3 lines)
|
|
434
|
+
if self.send_func and notifications:
|
|
435
|
+
try:
|
|
436
|
+
# Join notifications with newlines, max 3 lines
|
|
437
|
+
notification_msg = "\n".join(notifications[:3])
|
|
438
|
+
await self.send_func(notification_msg)
|
|
439
|
+
except Exception as e:
|
|
440
|
+
logger.warning(f"AgentPipeline: Failed to send notification: {e}")
|
|
441
|
+
|
|
442
|
+
# Increment round count after processing all tool calls in this round
|
|
443
|
+
if tasks_to_run:
|
|
444
|
+
session.round_count += 1
|
|
388
445
|
|
|
389
446
|
# Build final response
|
|
390
447
|
total_time = time.time() - start_time
|
hyw_core/definitions.py
CHANGED
|
@@ -46,6 +46,7 @@ def get_web_tool() -> Dict[str, Any]:
|
|
|
46
46
|
"function": {
|
|
47
47
|
"name": "web_tool",
|
|
48
48
|
"description": """搜索网页或截图指定URL。用于获取最新信息、查找资料。
|
|
49
|
+
## 使用方式
|
|
49
50
|
网页搜索(大部分问题优先使用此方法):
|
|
50
51
|
直接传入搜索词如 "python async" 会返回搜索结果列表
|
|
51
52
|
|
|
@@ -84,10 +85,12 @@ AGENT_SYSTEM_PROMPT = """# 你是一个智能助手 (Agent), 你的职责是使
|
|
|
84
85
|
最小限度使用自身知识, 尽可能使用 web_tool 获取信息.
|
|
85
86
|
|
|
86
87
|
## 工具使用指南
|
|
88
|
+
- 并行调用工具
|
|
89
|
+
- 网页搜索: 可以同时调用3次, 其中URL截图消耗较大, 最多同时调用1个
|
|
87
90
|
- 积极使用 web_tool 获取信息
|
|
88
91
|
- 搜索时, 关键词保证简单、指向准确、利于传统搜索引擎.
|
|
89
92
|
- 获取页面截图时, 只使用官方性较强的 wiki、官方网站、资源站等等, 不使用第三方转载新闻网站.
|
|
90
|
-
- 最多可调用2
|
|
93
|
+
- 最多可调用2轮工具, 之后必须给出最终回答
|
|
91
94
|
- 适当时候调用 `refuse_answer`
|
|
92
95
|
- 对于具体任务, 如果是转述、格式化、翻译等, 请直接给出最终回答, 不再调用工具
|
|
93
96
|
|
|
File without changes
|
{entari_plugin_hyw-4.0.0rc12.dist-info → entari_plugin_hyw-4.0.0rc13.dist-info}/top_level.txt
RENAMED
|
File without changes
|