entari-plugin-hyw 4.0.0rc14__py3-none-any.whl → 4.0.0rc15__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/__init__.py +149 -367
- {entari_plugin_hyw-4.0.0rc14.dist-info → entari_plugin_hyw-4.0.0rc15.dist-info}/METADATA +1 -1
- {entari_plugin_hyw-4.0.0rc14.dist-info → entari_plugin_hyw-4.0.0rc15.dist-info}/RECORD +11 -12
- {entari_plugin_hyw-4.0.0rc14.dist-info → entari_plugin_hyw-4.0.0rc15.dist-info}/WHEEL +1 -1
- hyw_core/agent.py +115 -18
- hyw_core/browser_control/assets/card-dist/index.html +35 -31
- hyw_core/browser_control/service.py +43 -0
- hyw_core/definitions.py +57 -12
- hyw_core/search.py +4 -6
- hyw_core/stages/summary.py +45 -18
- entari_plugin_hyw/Untitled-1 +0 -1865
- {entari_plugin_hyw-4.0.0rc14.dist-info → entari_plugin_hyw-4.0.0rc15.dist-info}/top_level.txt +0 -0
hyw_core/agent.py
CHANGED
|
@@ -15,7 +15,7 @@ from typing import Any, Callable, Awaitable, Dict, List, Optional
|
|
|
15
15
|
from loguru import logger
|
|
16
16
|
from openai import AsyncOpenAI
|
|
17
17
|
|
|
18
|
-
from .definitions import get_web_tool, get_refuse_answer_tool, AGENT_SYSTEM_PROMPT
|
|
18
|
+
from .definitions import get_web_tool, get_refuse_answer_tool, get_js_tool, AGENT_SYSTEM_PROMPT
|
|
19
19
|
from .stages.base import StageContext, StageResult
|
|
20
20
|
from .search import SearchService
|
|
21
21
|
|
|
@@ -209,8 +209,19 @@ class AgentPipeline:
|
|
|
209
209
|
|
|
210
210
|
session.messages = [
|
|
211
211
|
{"role": "system", "content": system_prompt},
|
|
212
|
-
{"role": "user", "content": user_content}
|
|
213
212
|
]
|
|
213
|
+
|
|
214
|
+
# Add conversation history (previous turns) before current user message
|
|
215
|
+
# This enables continuous conversation context
|
|
216
|
+
if conversation_history:
|
|
217
|
+
for msg in conversation_history:
|
|
218
|
+
role = msg.get("role", "")
|
|
219
|
+
content = msg.get("content", "")
|
|
220
|
+
if role in ("user", "assistant") and content:
|
|
221
|
+
session.messages.append({"role": role, "content": content})
|
|
222
|
+
|
|
223
|
+
# Add current user message
|
|
224
|
+
session.messages.append({"role": "user", "content": user_content})
|
|
214
225
|
|
|
215
226
|
# Add image source hint for user images
|
|
216
227
|
if user_image_count > 0:
|
|
@@ -223,8 +234,9 @@ class AgentPipeline:
|
|
|
223
234
|
# Tool definitions
|
|
224
235
|
web_tool = get_web_tool()
|
|
225
236
|
refuse_tool = get_refuse_answer_tool()
|
|
226
|
-
|
|
227
|
-
|
|
237
|
+
js_tool = get_js_tool()
|
|
238
|
+
tools = [web_tool, refuse_tool, js_tool]
|
|
239
|
+
|
|
228
240
|
usage_totals = {"input_tokens": 0, "output_tokens": 0}
|
|
229
241
|
final_content = ""
|
|
230
242
|
|
|
@@ -429,7 +441,10 @@ class AgentPipeline:
|
|
|
429
441
|
if func_name == "web_tool":
|
|
430
442
|
tasks_to_run.append(self._execute_web_tool(tool_call_args_list[idx], context))
|
|
431
443
|
task_indices.append(idx)
|
|
432
|
-
|
|
444
|
+
elif func_name == "js_executor":
|
|
445
|
+
tasks_to_run.append(self._execute_js_tool(tool_call_args_list[idx], context))
|
|
446
|
+
task_indices.append(idx)
|
|
447
|
+
|
|
433
448
|
# Run all web_tool calls in parallel
|
|
434
449
|
if tasks_to_run:
|
|
435
450
|
results = await asyncio.gather(*tasks_to_run, return_exceptions=True)
|
|
@@ -647,6 +662,59 @@ class AgentPipeline:
|
|
|
647
662
|
"screenshot_count": 0
|
|
648
663
|
}
|
|
649
664
|
|
|
665
|
+
async def _execute_js_tool(self, args: Dict, context: StageContext) -> Dict[str, Any]:
|
|
666
|
+
"""执行 JS 代码工具"""
|
|
667
|
+
script = args.get("script", "")
|
|
668
|
+
if not script:
|
|
669
|
+
return {"summary": "JS执行失败: 代码为空", "results": []}
|
|
670
|
+
|
|
671
|
+
if self.send_func:
|
|
672
|
+
try:
|
|
673
|
+
await self.send_func("💻 正在执行JavaScript代码...")
|
|
674
|
+
except: pass
|
|
675
|
+
|
|
676
|
+
logger.info(f"AgentPipeline: Executing JS script: {script[:50]}...")
|
|
677
|
+
result = await self.search_service.execute_script(script)
|
|
678
|
+
|
|
679
|
+
# 格式化结果
|
|
680
|
+
success = result.get("success", False)
|
|
681
|
+
output = result.get("result", None)
|
|
682
|
+
error = result.get("error", None)
|
|
683
|
+
url = result.get("url", "")
|
|
684
|
+
title = result.get("title", "")
|
|
685
|
+
|
|
686
|
+
# Add to context
|
|
687
|
+
context.web_results.append({
|
|
688
|
+
"_id": context.next_id(),
|
|
689
|
+
"_type": "js_result",
|
|
690
|
+
"url": url,
|
|
691
|
+
"title": title or "JS Execution",
|
|
692
|
+
"script": script,
|
|
693
|
+
"output": str(output) if success else str(error),
|
|
694
|
+
"success": success,
|
|
695
|
+
"content": f"Script: {script}\n\nOutput: {output}" if success else f"Error: {error}"
|
|
696
|
+
})
|
|
697
|
+
|
|
698
|
+
if success:
|
|
699
|
+
summary = f"JS执行成功 (返回: {str(output)[:50]}...)"
|
|
700
|
+
return {
|
|
701
|
+
"summary": summary,
|
|
702
|
+
"results": [{"_type": "js_result", "url": url}],
|
|
703
|
+
"screenshot_count": 0,
|
|
704
|
+
"full_output": str(output), # Return full output for LLM
|
|
705
|
+
"success": True
|
|
706
|
+
}
|
|
707
|
+
else:
|
|
708
|
+
return {
|
|
709
|
+
"summary": f"JS执行失败: {str(error)[:50]}",
|
|
710
|
+
"results": [],
|
|
711
|
+
"screenshot_count": 0,
|
|
712
|
+
"full_output": f"JS Execution Failed: {error}",
|
|
713
|
+
"success": False,
|
|
714
|
+
"error": str(error)
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
|
|
650
718
|
def _collect_filter_urls(self, filters: List, visible: List[Dict]) -> List[str]:
|
|
651
719
|
"""Collect URLs based on filter specifications."""
|
|
652
720
|
urls = []
|
|
@@ -729,22 +797,51 @@ class AgentPipeline:
|
|
|
729
797
|
"cost": instruct_cost,
|
|
730
798
|
})
|
|
731
799
|
|
|
732
|
-
# 2. Search Stage (搜索)
|
|
800
|
+
# 2. Search Stage (搜索) / Browser JS Stage
|
|
733
801
|
if session.tool_calls:
|
|
734
|
-
# Collect all search descriptions
|
|
802
|
+
# Collect all search descriptions and check for JS executor calls
|
|
735
803
|
search_descriptions = []
|
|
804
|
+
js_calls = []
|
|
805
|
+
|
|
736
806
|
for tc, result in zip(session.tool_calls, session.tool_results):
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
807
|
+
if tc.get("name") == "js_executor":
|
|
808
|
+
# Collect JS execution info
|
|
809
|
+
js_calls.append({
|
|
810
|
+
"script": tc.get("args", {}).get("script", ""),
|
|
811
|
+
"output": result.get("full_output", result.get("summary", "")),
|
|
812
|
+
"url": result.get("results", [{}])[0].get("url", "") if result.get("results") else "",
|
|
813
|
+
"success": result.get("success", True), # Default to True if not present
|
|
814
|
+
"error": result.get("error", "")
|
|
815
|
+
})
|
|
816
|
+
else:
|
|
817
|
+
desc = result.get("summary", "")
|
|
818
|
+
if desc:
|
|
819
|
+
search_descriptions.append(desc)
|
|
820
|
+
|
|
821
|
+
# Add Search stage if there are search calls
|
|
822
|
+
if search_descriptions:
|
|
823
|
+
stages.append({
|
|
824
|
+
"name": "Search",
|
|
825
|
+
"model": "",
|
|
826
|
+
"provider": "Web",
|
|
827
|
+
"description": " → ".join(search_descriptions),
|
|
828
|
+
"time": session.search_time,
|
|
829
|
+
})
|
|
830
|
+
|
|
831
|
+
# Add Browser JS stage for each JS call
|
|
832
|
+
for js_call in js_calls:
|
|
833
|
+
stages.append({
|
|
834
|
+
"name": "browser_js",
|
|
835
|
+
"model": "",
|
|
836
|
+
"provider": "Browser",
|
|
837
|
+
"description": "JavaScript Execution",
|
|
838
|
+
"script": js_call["script"],
|
|
839
|
+
"output": js_call["output"],
|
|
840
|
+
"url": js_call["url"],
|
|
841
|
+
"success": js_call.get("success"),
|
|
842
|
+
"error": js_call.get("error"),
|
|
843
|
+
"time": 0, # JS execution time is included in search_time
|
|
844
|
+
})
|
|
748
845
|
|
|
749
846
|
# 3. Summary Stage (总结)
|
|
750
847
|
# Calculate remaining tokens after instruct
|