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.

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
- tools = [web_tool, refuse_tool]
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
- desc = result.get("summary", "")
738
- if desc:
739
- search_descriptions.append(desc)
740
-
741
- stages.append({
742
- "name": "Search",
743
- "model": "",
744
- "provider": "Web",
745
- "description": " → ".join(search_descriptions) if search_descriptions else "Web Search",
746
- "time": session.search_time,
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