فهرست منبع

refactor: browser use tools

Talegorithm 2 روز پیش
والد
کامیت
f649d162ce

+ 14 - 28
agent/core/runner.py

@@ -179,35 +179,21 @@ BUILTIN_TOOLS = [
     # "knowledge_list",
     # "knowledge_slim",
 
-    # 浏览器工具
-    "browser_get_live_url",
-    "browser_navigate_to_url",
-    "browser_search_web",
-    "browser_go_back",
-    "browser_wait",
-    "browser_click_element",
-    "browser_input_text",
-    "browser_send_keys",
-    "browser_upload_file",
-    "browser_scroll_page",
-    "browser_find_text",
+    # 浏览器工具(14 个语义化入口,重构自 28 个原始工具)
+    "browser_navigate",
+    "browser_search",
+    "browser_back",
+    "browser_interact",
+    "browser_scroll",
     "browser_screenshot",
-    "browser_switch_tab",
-    "browser_close_tab",
-    "browser_get_dropdown_options",
-    "browser_select_dropdown_option",
-    "browser_extract_content",
-    "browser_read_long_content",
-    "browser_download_direct_url",
-    "browser_get_page_html",
-    "browser_get_visual_selector_map",
-    "browser_evaluate",
-    "browser_ensure_login_with_cookies",
-    # 可以暂时由飞书消息替代
-    #"browser_wait_for_user_action",
-    "browser_done",
-    "browser_export_cookies",
-    "browser_load_cookies",
+    "browser_elements",
+    "browser_read",
+    "browser_extract",
+    "browser_tabs",
+    "browser_cookies",
+    "browser_wait",
+    "browser_js",
+    "browser_download",
 
     # 飞书工具
     "feishu_send_message_to_contact",

+ 3 - 2
agent/docs/tools-refactor-plan.md

@@ -1,8 +1,9 @@
 # 工具体系改造方案(Refactor Plan)
 
-> 本文档是**未来规划**,不是现状描述。当前工具体系的状态请看 [`tools.md`](./tools.md)。
+> ✅ **方案一(内容工具族)** 和 **方案二(浏览器工具族)** 已于 2026-04-12 完成落地。
+> 下方保留原始方案文档供参考。沙箱工具已于此前删除。
 >
-> 当方案落地后,记得把本文档对应的章节删除或合并到 `tools.md`
+> 当前工具体系的状态请看 [`tools.md`](./tools.md)
 
 ## 背景
 

+ 29 - 23
agent/skill/skills/browser.md

@@ -9,32 +9,38 @@ description: 浏览器自动化工具使用指南
 
 ### 基本工作流程
 
-1. **页面导航**: 使用 `browser_navigate_to_url` 或 `browser_search_web` 到达目标页面
+1. **页面导航**: 使用 `browser_navigate(url)` 或 `browser_search(query)` 到达目标页面
 2. **等待加载**: 页面跳转后调用 `browser_wait(seconds=2)` 等待内容加载
-3. **获取元素索引**: 调用 `browser_get_visual_selector_map` 获取可交互元素的索引映射和当前界面的截图
-4. **执行交互**: 使用 `browser_click_element`、`browser_input_text` 等工具操作页面
-5. **提取内容**: 使用 `browser_extract_content`, `browser_read_long_content`, `browser_get_page_html` 获取数据
+3. **获取元素索引**: 调用 `browser_screenshot(highlight_elements=True)` 获取带编号标注的截图 + 元素列表
+4. **执行交互**: 使用 `browser_interact(action, index, ...)` 操作页面(click / type / send_keys / upload / dropdown)
+5. **提取内容**: 使用 `browser_extract(query)` 让 LLM 提取结构化数据,或 `browser_read(mode="long")` 分页读取长内容
 
 ### 关键原则
 
 - **禁止模拟结果**:不要输出你认为的搜索结果,而是要调用工具获取真实结果
-- **必须先获取索引**: 所有 `index` 参数都需要先通过 `browser_get_selector_map` 获取
-- **高级工具**:优先使用 `browser_extract_content`, `browser_read_long_content` 等工具获取数据,而不是使用 `browser_get_selector_map` 获取索引后手动解析
-- **操作后等待**: 任何可能触发页面变化的操作(点击、输入、滚动)后都要调用 `browser_wait`
+- **必须先获取索引**: 所有 `index` 参数都需要先通过 `browser_screenshot(highlight_elements=True)` 或 `browser_elements()` 获取
+- **高级工具**:优先使用 `browser_extract` / `browser_read` 获取数据,而不是手动解析元素
+- **操作后等待**: 任何可能触发页面变化的操作后都要调用 `browser_wait`
 - **登录处理**:
-  - **正常登录**:当遇到需要登录的网页时,使用 `browser_load_cookies` 来登录
-  - **首次登录**:当没有该网站的 cookie 时,需要请求人类协助登录:
-    1. 调用 `browser_get_live_url` 获取云浏览器实时画面链接
-    2. 导航到目标网站的登录页面
-    3. 通过 `feishu_send_message_to_contact` 将 live URL 发送给相关人员,请求其在浏览器中完成登录
-    4. 使用 `feishu_get_contact_replies(contact_name="...", wait_time_seconds=300)` 等待对方回复确认登录完成
-    5. 收到回复后使用 `browser_export_cookies` 将登录态保存下来
-- **复杂操作用JS**: 当标准工具无法满足时,使用 `browser_evaluate` 执行 JavaScript 代码
-
-### 工具分类
-
-**导航**: browser_get_live_url, browser_navigate_to_url, browser_search_web, browser_go_back, browser_wait
-**交互**: browser_click_element, browser_input_text, browser_send_keys, browser_upload_file
-**视图**: browser_scroll_page, browser_find_text, browser_screenshot
-**提取**: browser_extract_content, browser_read_long_content, browser_get_page_html, browser_get_selector_map, browser_get_visual_selector_map
-**高级**: browser_evaluate, browser_load_cookies, browser_export_cookies, browser_wait_for_user_action, browser_download_direct_url
+  - **正常登录**:使用 `browser_cookies(action="load", url=...)` 注入已保存的 cookie
+  - **首次登录**:需要人类协助——导航到登录页,通过飞书发送链接,等待确认后 `browser_cookies(action="export")` 保存
+- **复杂操作用JS**: 当标准工具无法满足时,使用 `browser_js(code)` 执行 JavaScript
+
+### 工具一览
+
+| 工具 | 功能 |
+|------|------|
+| `browser_navigate(url)` | 导航到 URL |
+| `browser_search(query, engine)` | 搜索引擎搜索 |
+| `browser_back()` | 返回上一页 |
+| `browser_interact(action, ...)` | 元素交互(click/type/send_keys/upload/dropdown) |
+| `browser_scroll(down, pages)` | 滚动页面 |
+| `browser_screenshot(highlight)` | 截图(highlight=True 带元素编号标注) |
+| `browser_elements()` | 获取可交互元素列表(纯文本) |
+| `browser_read(mode)` | 读取页面(html/find/long) |
+| `browser_extract(query)` | LLM 驱动的结构化数据提取 |
+| `browser_tabs(action, tab_id)` | 标签页管理(switch/close) |
+| `browser_cookies(action, ...)` | Cookie/登录态管理(load/export/ensure_login) |
+| `browser_wait(seconds/user_message)` | 等待(定时 or 等用户操作) |
+| `browser_js(code)` | 执行 JavaScript |
+| `browser_download(url)` | 下载文件 |

+ 121 - 0
agent/skill/skills/core.md

@@ -0,0 +1,121 @@
+---
+name: core
+type: core
+description: 核心系统能力,自动加载到 System Prompt
+---
+
+## 计划与执行
+
+使用 `goal` 工具管理执行计划。目标树是你的工作记忆——系统会定期将当前计划注入给你,帮助你追踪进度和关键结论。
+
+### 核心原则
+
+- **先明确目标再行动**:开始执行前,用 `goal` 明确当前要做什么
+- **灵活运用,不受约束**:
+  - 可以先做全局规划再行动:`goal(add="调研方案, 实现方案, 测试验证")`
+  - 可以走一步看一步,每次只规划下一个目标
+  - 行动中可以动态放弃并调整:`goal(abandon="方案不可行")`
+  - 规划本身可以作为一个目标(如 "调研并确定技术方案")
+- **简单任务只需一个目标**:`goal(add="将CSV转换为JSON")` 即可,不需要强制拆分
+
+### 使用方式
+
+创建目标:
+
+```
+goal(add="调研并确定方案, 执行方案, 评估结果")
+```
+
+聚焦并开始执行(使用计划视图中的 ID,如 "1", "2.1"):
+
+```
+goal(focus="1")
+```
+
+完成目标,记录**关键结论**(不是过程描述):
+
+```
+goal(done="最佳方案是openpose,精度高且支持多人检测")
+```
+
+完成并切换到下一个:
+
+```
+goal(done="openpose方案确认可行", focus="2")
+```
+
+添加子目标或同级目标:
+
+```
+goal(add="设计接口, 实现代码", under="2")
+goal(add="编写文档", after="2")
+```
+
+放弃不可行的目标:
+
+```
+goal(abandon="方案A需要Redis,环境没有")
+```
+
+### 使用规范
+
+1. **聚焦到具体目标**:始终将焦点放在你正在执行的最具体的子目标上,而不是父目标。创建子目标后立即 `focus` 到第一个要执行的子目标。完成后用 `done` + `focus` 切换到下一个。
+2. **同时只有一个目标处于执行中**:完成当前目标后再切换
+3. **summary 记录结论**:记录关键发现,而非 "已完成调研" 这样无信息量的描述
+4. **计划可调整**:根据执行情况随时追加、跳过或放弃目标
+5. **使用 ID 定位**:focus、after、under 参数使用目标的 ID(如 "1", "2.1")
+
+### 知识复用
+
+在**启动新任务**、**拆分复杂目标**或**遇到执行障碍**时,应主动调用 `knowledge_search` 获取相关的历史经验或避坑指南。
+**使用示例:**
+`knowledge_search(query="如何处理浏览器点击不生效的问题", types=["strategy", "tool"])`
+
+## 信息调研
+
+你可以通过 `content_search(platform, keyword)` 搜索来自 GitHub、小红书、微信公众号、知乎、YouTube、X 等平台的信息,再用 `content_detail(platform, index)` 查看完整内容。不确定平台参数时先调 `content_platforms()` 查看。
+对于需要深度交互的网页内容,使用浏览器工具进行操作。
+
+调研过程可能需要多次搜索,比如基于搜索结果中获得的启发或信息启动新的搜索,直到得到令人满意的答案。你可以使用`goal`工具管理搜索的过程,或者使用文档记录搜索的中间或最终结果。
+
+## 浏览器工具使用指南
+
+所有浏览器工具都以 `browser_` 为前缀。浏览器会话会持久化,无需每次重新启动。
+
+### 基本工作流程
+
+1. **页面导航**: 使用 `browser_navigate(url)` 或 `browser_search(query)` 到达目标页面
+2. **等待加载**: 页面跳转后调用 `browser_wait(seconds=2)` 等待内容加载
+3. **获取元素索引**: 调用 `browser_screenshot(highlight_elements=True)` 获取带编号标注的截图 + 元素列表
+4. **执行交互**: 使用 `browser_interact(action, index, ...)` 操作页面(click / type / send_keys / upload / dropdown)
+5. **提取内容**: 使用 `browser_extract(query)` 让 LLM 提取结构化数据,或 `browser_read(mode="long")` 分页读取长内容
+
+### 关键原则
+
+- **禁止模拟结果**:不要输出你认为的搜索结果,而是要调用工具获取真实结果
+- **必须先获取索引**: 所有 `index` 参数都需要先通过 `browser_screenshot(highlight_elements=True)` 或 `browser_elements()` 获取
+- **高级工具**:优先使用 `browser_extract` / `browser_read` 获取数据,而不是手动解析元素
+- **操作后等待**: 任何可能触发页面变化的操作后都要调用 `browser_wait`
+- **登录处理**:
+  - **正常登录**:使用 `browser_cookies(action="load", url=...)` 注入已保存的 cookie
+  - **首次登录**:需要人类协助——导航到登录页,通过飞书发送链接,等待确认后 `browser_cookies(action="export")` 保存
+- **复杂操作用JS**: 当标准工具无法满足时,使用 `browser_js(code)` 执行 JavaScript
+
+### 工具一览
+
+| 工具 | 功能 |
+|------|------|
+| `browser_navigate(url)` | 导航到 URL |
+| `browser_search(query, engine)` | 搜索引擎搜索 |
+| `browser_back()` | 返回上一页 |
+| `browser_interact(action, ...)` | 元素交互(click/type/send_keys/upload/dropdown) |
+| `browser_scroll(down, pages)` | 滚动页面 |
+| `browser_screenshot(highlight)` | 截图(highlight=True 带元素编号标注) |
+| `browser_elements()` | 获取可交互元素列表(纯文本) |
+| `browser_read(mode)` | 读取页面(html/find/long) |
+| `browser_extract(query)` | LLM 驱动的结构化数据提取 |
+| `browser_tabs(action, tab_id)` | 标签页管理(switch/close) |
+| `browser_cookies(action, ...)` | Cookie/登录态管理(load/export/ensure_login) |
+| `browser_wait(seconds/user_message)` | 等待(定时 or 等用户操作) |
+| `browser_js(code)` | 执行 JavaScript |
+| `browser_download(url)` | 下载文件 |

+ 30 - 93
agent/tools/builtin/browser/__init__.py

@@ -2,63 +2,32 @@
 浏览器工具 - Browser-Use 原生工具适配器
 
 基于 browser-use 实现的浏览器自动化工具集。
+28 个原始工具已合并为 14 个语义化入口(2026-04 重构)。
 """
 
 from agent.tools.builtin.browser.baseClass import (
-    # 会话管理
+    # 会话管理(非 @tool,供框架内部调用)
     init_browser_session,
     get_browser_session,
     get_browser_live_url,
     cleanup_browser_session,
     kill_browser_session,
 
-    # 导航类工具
-    browser_get_live_url,
-    browser_navigate_to_url,
-    browser_search_web,
-    browser_go_back,
-    browser_wait,
-
-    # 元素交互工具
-    browser_click_element,
-    browser_input_text,
-    browser_send_keys,
-    browser_upload_file,
-
-    # 滚动和视图工具
-    browser_scroll_page,
-    browser_find_text,
+    # 14 个 @tool 入口
+    browser_navigate,
+    browser_search,
+    browser_back,
+    browser_interact,
+    browser_scroll,
     browser_screenshot,
-
-    # 标签页管理工具
-    browser_switch_tab,
-    browser_close_tab,
-
-    # 下拉框工具
-    browser_get_dropdown_options,
-    browser_select_dropdown_option,
-
-    # 内容提取工具
-    browser_extract_content,
-    browser_read_long_content,
-    browser_get_page_html,
-    browser_download_direct_url,
-    browser_get_selector_map,
-    browser_get_visual_selector_map,
-
-    # JavaScript 执行工具
-    browser_evaluate,
-    browser_ensure_login_with_cookies,
-
-    # 等待用户操作
-    browser_wait_for_user_action,
-
-    # 任务完成
-    browser_done,
-
-    # Cookie 持久化
-    browser_export_cookies,
-    browser_load_cookies,
+    browser_elements,
+    browser_read,
+    browser_extract,
+    browser_tabs,
+    browser_cookies,
+    browser_wait,
+    browser_js,
+    browser_download,
 )
 
 __all__ = [
@@ -69,51 +38,19 @@ __all__ = [
     'cleanup_browser_session',
     'kill_browser_session',
 
-    # 导航类工具
-    'browser_get_live_url',
-    'browser_navigate_to_url',
-    'browser_search_web',
-    'browser_go_back',
-    'browser_wait',
-
-    # 元素交互工具
-    'browser_click_element',
-    'browser_input_text',
-    'browser_send_keys',
-    'browser_upload_file',
-
-    # 滚动和视图工具
-    'browser_scroll_page',
-    'browser_find_text',
+    # @tool 入口
+    'browser_navigate',
+    'browser_search',
+    'browser_back',
+    'browser_interact',
+    'browser_scroll',
     'browser_screenshot',
-
-    # 标签页管理工具
-    'browser_switch_tab',
-    'browser_close_tab',
-
-    # 下拉框工具
-    'browser_get_dropdown_options',
-    'browser_select_dropdown_option',
-
-    # 内容提取工具
-    'browser_extract_content',
-    'browser_read_long_content',
-    'browser_download_direct_url',
-    'browser_get_page_html',
-    'browser_get_selector_map',
-    'browser_get_visual_selector_map',
-
-    # JavaScript 执行工具
-    'browser_evaluate',
-    'browser_ensure_login_with_cookies',
-
-    # 等待用户操作
-    'browser_wait_for_user_action',
-
-    # 任务完成
-    'browser_done',
-
-    # Cookie 持久化
-    'browser_export_cookies',
-    'browser_load_cookies',
+    'browser_elements',
+    'browser_read',
+    'browser_extract',
+    'browser_tabs',
+    'browser_cookies',
+    'browser_wait',
+    'browser_js',
+    'browser_download',
 ]

+ 334 - 77
agent/tools/builtin/browser/baseClass.py

@@ -52,7 +52,7 @@ import aiohttp
 import re
 import base64
 from urllib.parse import urlparse, parse_qs, unquote
-from typing import Optional, List, Dict, Any, Tuple, Union
+from typing import Literal, Optional, List, Dict, Any, Tuple, Union
 from pathlib import Path
 from langchain_core.runnables import RunnableLambda
 from argparse import Namespace # 使用 Namespace 快速构造带属性的对象
@@ -548,7 +548,6 @@ def _fetch_profile_id(cookie_type: str) -> Optional[str]:
 # 导航类工具 (Navigation Tools)
 # ============================================================
 
-@tool()
 async def browser_get_live_url() -> ToolResult:
     """
     获取云浏览器的实时画面链接(Live URL),可用于在本地浏览器中查看或分享给他人操作。
@@ -567,7 +566,6 @@ async def browser_get_live_url() -> ToolResult:
     )
 
 
-@tool()
 async def browser_navigate_to_url(url: str, new_tab: bool = False) -> ToolResult:
     """
     导航到指定的 URL
@@ -607,7 +605,6 @@ async def browser_navigate_to_url(url: str, new_tab: bool = False) -> ToolResult
         )
 
 
-@tool()
 async def browser_search_web(query: str, engine: str = "bing") -> ToolResult:
     """
     使用搜索引擎搜索
@@ -644,7 +641,6 @@ async def browser_search_web(query: str, engine: str = "bing") -> ToolResult:
         )
 
 
-@tool()
 async def browser_go_back() -> ToolResult:
     """
     返回到上一个页面
@@ -671,10 +667,9 @@ async def browser_go_back() -> ToolResult:
         )
 
 
-@tool()
-async def browser_wait(seconds: int = 3) -> ToolResult:
+async def browser_wait_impl(seconds: int = 3) -> ToolResult:
     """
-    等待指定的秒数
+    等待指定的秒数(内部实现)
     Wait for a specified number of seconds
 
     用于等待页面加载、动画完成或其他异步操作。
@@ -732,7 +727,6 @@ class DownloadLinkCaptureHandler(logging.Handler):
                     self.captured_url = url
                     # print(f"🎯 成功锁定完整直链: {url[:50]}...") # 调试用
 
-@tool()
 async def browser_download_direct_url(url: str, save_name: str = "book.epub") -> ToolResult:
     save_dir = Path.cwd() / ".cache/.browser_use_files"
     save_dir.mkdir(parents=True, exist_ok=True)
@@ -797,7 +791,6 @@ async def browser_download_direct_url(url: str, save_name: str = "book.epub") ->
             long_term_memory=f"下载任务由于异常中断: {str(e)}"
         )
     
-@tool()
 async def browser_click_element(index: int) -> ToolResult:
     """
     点击页面元素,并自动通过拦截内部日志获取下载直链。
@@ -847,7 +840,6 @@ async def browser_click_element(index: int) -> ToolResult:
         logger.removeHandler(capture_handler)
 
 
-@tool()
 async def browser_input_text(index: int, text: str, clear: bool = True) -> ToolResult:
     """
     在指定元素中输入文本
@@ -885,7 +877,6 @@ async def browser_input_text(index: int, text: str, clear: bool = True) -> ToolR
         )
 
 
-@tool()
 async def browser_send_keys(keys: str) -> ToolResult:
     """
     发送键盘按键或快捷键
@@ -925,7 +916,6 @@ async def browser_send_keys(keys: str) -> ToolResult:
         )
 
 
-@tool()
 async def browser_upload_file(index: int, path: str) -> ToolResult:
     """
     上传文件到文件输入元素
@@ -968,7 +958,6 @@ async def browser_upload_file(index: int, path: str) -> ToolResult:
 # ============================================================
 # 滚动和视图工具 (Scroll & View Tools)
 # ============================================================
-@tool()
 async def browser_scroll_page(down: bool = True, pages: float = 1.0, index: Optional[int] = None) -> ToolResult:
     try:
         # 限制单次滚动幅度,避免 agent 一次滚 100 页
@@ -1028,7 +1017,6 @@ async def browser_scroll_page(down: bool = True, pages: float = 1.0, index: Opti
 
 
 
-@tool()
 async def browser_find_text(text: str) -> ToolResult:
     """
     查找页面中的文本并滚动到该位置
@@ -1063,7 +1051,6 @@ async def browser_find_text(text: str) -> ToolResult:
             long_term_memory=f"查找文本 '{text}' 失败"
         )
 
-@tool()
 async def browser_get_visual_selector_map() -> ToolResult:
     """
     获取当前页面的视觉快照和交互元素索引映射。
@@ -1160,10 +1147,9 @@ async def browser_get_visual_selector_map() -> ToolResult:
             long_term_memory="获取视觉元素映射失败"
         )
     
-@tool()
-async def browser_screenshot() -> ToolResult:
+async def browser_screenshot_impl() -> ToolResult:
     """
-    请求在下次观察中包含页面截图
+    请求在下次观察中包含页面截图(内部实现)
     Request a screenshot to be included in the next observation
 
     用于视觉检查页面状态,帮助理解页面布局和内容。
@@ -1197,7 +1183,6 @@ async def browser_screenshot() -> ToolResult:
 # 标签页管理工具 (Tab Management Tools)
 # ============================================================
 
-@tool()
 async def browser_switch_tab(tab_id: str) -> ToolResult:
     """
     切换到指定标签页
@@ -1232,7 +1217,6 @@ async def browser_switch_tab(tab_id: str) -> ToolResult:
         )
 
 
-@tool()
 async def browser_close_tab(tab_id: str) -> ToolResult:
     """
     关闭指定标签页
@@ -1271,7 +1255,6 @@ async def browser_close_tab(tab_id: str) -> ToolResult:
 # 下拉框工具 (Dropdown Tools)
 # ============================================================
 
-@tool()
 async def browser_get_dropdown_options(index: int) -> ToolResult:
     """
     获取下拉框的所有选项
@@ -1305,7 +1288,6 @@ async def browser_get_dropdown_options(index: int) -> ToolResult:
         )
 
 
-@tool()
 async def browser_select_dropdown_option(index: int, text: str) -> ToolResult:
     """
     选择下拉框选项
@@ -1408,7 +1390,6 @@ async def extraction_adapter(input_data):
     from argparse import Namespace
     return Namespace(completion=content)
 
-@tool()
 async def browser_extract_content(query: str, extract_links: bool = False,
                          start_from_char: int = 0) -> ToolResult:
     """
@@ -1550,7 +1531,6 @@ async def _detect_and_download_pdf_via_cdp(browser) -> Optional[str]:
         return None
 
 
-@tool()
 async def browser_read_long_content(
     goal: Union[str, dict],
     source: str = "page",
@@ -1609,7 +1589,6 @@ async def browser_read_long_content(
             error=f"Read long content failed: {str(e)}",
             long_term_memory="参数解析或校验失败,请检查输入"
         )
-@tool()
 async def browser_get_page_html() -> ToolResult:
     """
     获取当前页面的完整 HTML
@@ -1671,7 +1650,6 @@ async def browser_get_page_html() -> ToolResult:
         )
 
 
-@tool()
 async def browser_get_selector_map() -> ToolResult:
     """
     获取当前页面的元素索引映射
@@ -1743,7 +1721,6 @@ async def browser_get_selector_map() -> ToolResult:
 # JavaScript 执行工具 (JavaScript Tools)
 # ============================================================
 
-@tool()
 async def browser_evaluate(code: str) -> ToolResult:
     """
     在页面中执行 JavaScript 代码
@@ -1785,7 +1762,6 @@ async def browser_evaluate(code: str) -> ToolResult:
         )
 
 
-@tool()
 async def browser_ensure_login_with_cookies(cookie_type: str, url: str = "https://www.xiaohongshu.com") -> ToolResult:
     """
     检查登录状态并在需要时注入 cookies
@@ -1881,7 +1857,6 @@ async def browser_ensure_login_with_cookies(cookie_type: str, url: str = "https:
 # 等待用户操作工具 (Wait for User Action)
 # ============================================================
 
-@tool()
 async def browser_wait_for_user_action(message: str = "Please complete the action in browser",
                                timeout: int = 300) -> ToolResult:
     """
@@ -1953,7 +1928,6 @@ async def browser_wait_for_user_action(message: str = "Please complete the actio
 # 任务完成工具 (Task Completion)
 # ============================================================
 
-@tool()
 async def browser_done(text: str, success: bool = True,
               files_to_display: Optional[List[str]] = None) -> ToolResult:
     """
@@ -1998,7 +1972,6 @@ async def browser_done(text: str, success: bool = True,
 
 _COOKIES_DIR = Path(__file__).parent.parent.parent.parent.parent / ".cache/.cookies"
 
-@tool()
 async def browser_export_cookies(name: str = "", account: str = "") -> ToolResult:
     """
     导出当前浏览器的所有 Cookie 到本地 .cookies/ 目录。
@@ -2042,7 +2015,6 @@ async def browser_export_cookies(name: str = "", account: str = "") -> ToolResul
         return ToolResult(title="Cookie 导出失败", output="", error=str(e), long_term_memory="导出 Cookie 失败")
 
 
-@tool()
 async def browser_load_cookies(url: str, name: str = "", auto_navigate: bool = True) -> ToolResult:
     """
     根据目标 URL 自动查找本地 Cookie 文件,注入浏览器并导航到目标页面恢复登录态。
@@ -2178,60 +2150,345 @@ async def browser_load_cookies(url: str, name: str = "", auto_navigate: bool = T
 
 
 # ============================================================
-# 导出所有工具函数(供外部使用
+# 新版统一入口(13 个 @tool,替代原来 28 个
 # ============================================================
 
-__all__ = [
-    # 会话管理
-    'init_browser_session',
-    'get_browser_session',
-    'cleanup_browser_session',
-    'kill_browser_session',
 
-    # 导航类工具
-    'browser_navigate_to_url',
-    'browser_search_web',
-    'browser_go_back',
-    'browser_wait',
+@tool()
+async def browser_navigate(url: str, new_tab: bool = False) -> ToolResult:
+    """
+    导航到指定 URL。
 
-    # 元素交互工具
-    'browser_click_element',
-    'browser_input_text',
-    'browser_send_keys',
-    'browser_upload_file',
+    Args:
+        url: 目标 URL
+        new_tab: 是否在新标签页打开(默认 False)
+    """
+    return await browser_navigate_to_url(url=url, new_tab=new_tab)
 
-    # 滚动和视图工具
-    'browser_scroll_page',
-    'browser_find_text',
-    'browser_screenshot',
 
-    # 标签页管理工具
-    'browser_switch_tab',
-    'browser_close_tab',
+@tool()
+async def browser_search(query: str, engine: str = "bing") -> ToolResult:
+    """
+    使用搜索引擎搜索。
+
+    Args:
+        query: 搜索关键词
+        engine: 搜索引擎,可选 google / bing / duckduckgo,默认 bing
+    """
+    return await browser_search_web(query=query, engine=engine)
+
+
+@tool()
+async def browser_back() -> ToolResult:
+    """返回上一页。"""
+    return await browser_go_back()
+
+
+@tool()
+async def browser_interact(
+    action: Literal["click", "type", "send_keys", "upload", "dropdown_list", "dropdown_select"],
+    index: Optional[int] = None,
+    text: Optional[str] = None,
+    path: Optional[str] = None,
+    keys: Optional[str] = None,
+    clear: bool = True,
+) -> ToolResult:
+    """
+    与页面元素交互。根据 action 选择具体操作:
+
+    - click: 点击元素。需要 index。
+    - type: 在输入框输入文本。需要 index + text。clear 控制是否先清空。
+    - send_keys: 发送键盘按键(如 Enter、Control+A)。需要 keys,不需要 index。
+    - upload: 上传文件到文件输入框。需要 index + path(绝对路径)。
+    - dropdown_list: 列出下拉框选项。需要 index。
+    - dropdown_select: 选择下拉框选项。需要 index + text(选项文本)。
+
+    Args:
+        action: 交互类型
+        index: 元素索引(从 browser_elements 或 browser_screenshot(highlight=True) 获取)
+        text: 输入文本 / 下拉框选项文本
+        path: 上传文件的绝对路径
+        keys: 键盘按键字符串(如 "Enter"、"Control+A")
+        clear: type 时是否先清空(默认 True)
+    """
+    if action == "click":
+        if index is None:
+            return ToolResult(title="参数错误", output="", error="click 需要 index 参数")
+        return await browser_click_element(index=index)
+
+    elif action == "type":
+        if index is None or text is None:
+            return ToolResult(title="参数错误", output="", error="type 需要 index 和 text 参数")
+        return await browser_input_text(index=index, text=text, clear=clear)
+
+    elif action == "send_keys":
+        if keys is None:
+            return ToolResult(title="参数错误", output="", error="send_keys 需要 keys 参数")
+        return await browser_send_keys(keys=keys)
+
+    elif action == "upload":
+        if index is None or path is None:
+            return ToolResult(title="参数错误", output="", error="upload 需要 index 和 path 参数")
+        return await browser_upload_file(index=index, path=path)
+
+    elif action == "dropdown_list":
+        if index is None:
+            return ToolResult(title="参数错误", output="", error="dropdown_list 需要 index 参数")
+        return await browser_get_dropdown_options(index=index)
+
+    elif action == "dropdown_select":
+        if index is None or text is None:
+            return ToolResult(title="参数错误", output="", error="dropdown_select 需要 index 和 text 参数")
+        return await browser_select_dropdown_option(index=index, text=text)
+
+    else:
+        return ToolResult(title="未知 action", output="", error=f"不支持的 action: {action}")
+
+
+@tool()
+async def browser_scroll(
+    down: bool = True,
+    pages: float = 1.0,
+    into_view_index: Optional[int] = None,
+) -> ToolResult:
+    """
+    滚动页面。
+
+    Args:
+        down: True 向下滚动,False 向上(默认 True)
+        pages: 滚动的页面数(默认 1.0)
+        into_view_index: 传入元素索引则滚动到该元素可见(忽略 down 和 pages)
+    """
+    return await browser_scroll_page(down=down, pages=pages, index=into_view_index)
+
+
+@tool()
+async def browser_screenshot(highlight_elements: bool = False) -> ToolResult:
+    """
+    截取当前页面。
+
+    Args:
+        highlight_elements: False 返回纯截图;True 返回带交互元素编号标注的截图
+                           + 元素列表(原 visual_selector_map 功能)
+    """
+    if highlight_elements:
+        return await browser_get_visual_selector_map()
+    else:
+        return await browser_screenshot_impl()
+
+
+@tool()
+async def browser_elements() -> ToolResult:
+    """
+    获取当前页面的可交互元素列表(纯文本,不截图)。
+    返回的 index 用于 browser_interact / browser_scroll 等操作。
+    """
+    return await browser_get_selector_map()
+
+
+@tool()
+async def browser_read(
+    mode: Literal["html", "find", "long"],
+    query: Optional[str] = None,
+    source: str = "page",
+    context: str = "",
+) -> ToolResult:
+    """
+    读取页面内容,三种模式:
+
+    - html: 获取当前页面的 HTML 源码(大页面会截断到 10000 字符)
+    - find: 在页面中查找文本。需要 query。
+    - long: 智能分页读取长内容(支持自动检测 PDF)。query 描述阅读目标。
 
-    # 下拉框工具
-    'browser_get_dropdown_options',
-    'browser_select_dropdown_option',
+    Args:
+        mode: 读取模式
+        query: find 模式下的查找文本;long 模式下的阅读目标描述
+        source: long 模式的内容来源("page" 或文件路径),默认 "page"
+        context: long 模式的业务背景(可选)
+    """
+    if mode == "html":
+        return await browser_get_page_html()
+
+    elif mode == "find":
+        if not query:
+            return ToolResult(title="参数错误", output="", error="find 模式需要 query 参数")
+        return await browser_find_text(text=query)
+
+    elif mode == "long":
+        return await browser_read_long_content(
+            goal=query or "阅读页面内容",
+            source=source,
+            context=context,
+        )
+
+    else:
+        return ToolResult(title="未知 mode", output="", error=f"不支持的 mode: {mode}")
 
-    # 内容提取工具
-    'browser_extract_content',
-    'browser_get_page_html',
-    'browser_read_long_content',
-    'browser_download_direct_url',
-    'browser_get_selector_map',
-    'browser_get_visual_selector_map',
 
-    # JavaScript 执行工具
-    'browser_evaluate',
-    'browser_ensure_login_with_cookies',
+@tool()
+async def browser_extract(
+    query: str,
+    extract_links: bool = False,
+    start_from_char: int = 0,
+) -> ToolResult:
+    """
+    使用 LLM 从当前页面提取结构化数据。
 
-    # 等待用户操作
-    'browser_wait_for_user_action',
+    与 browser_read 不同,此工具会调用 LLM 分析页面内容并返回结构化结果。
+    适合"提取所有产品价格"、"总结文章要点"等需要理解语义的场景。
 
-    # 任务完成
-    'browser_done',
+    Args:
+        query: 提取指令(如"提取页面上所有产品名称和价格")
+        extract_links: 是否同时提取链接(默认 False)
+        start_from_char: 从第几个字符开始提取(用于分页处理大内容)
+    """
+    return await browser_extract_content(
+        query=query,
+        extract_links=extract_links,
+        start_from_char=start_from_char,
+    )
+
+
+@tool()
+async def browser_tabs(
+    action: Literal["switch", "close"],
+    tab_id: str = "",
+) -> ToolResult:
+    """
+    管理浏览器标签页。
+
+    Args:
+        action: "switch" 切换到指定标签页;"close" 关闭指定标签页
+        tab_id: 标签页 ID(4 字符)
+    """
+    if not tab_id:
+        return ToolResult(title="参数错误", output="", error="需要 tab_id 参数")
+
+    if action == "switch":
+        return await browser_switch_tab(tab_id=tab_id)
+    elif action == "close":
+        return await browser_close_tab(tab_id=tab_id)
+    else:
+        return ToolResult(title="未知 action", output="", error=f"不支持的 action: {action}")
+
+
+@tool()
+async def browser_cookies(
+    action: Literal["load", "export", "ensure_login"],
+    url: str = "",
+    name: str = "",
+    account: str = "",
+    cookie_type: str = "",
+    auto_navigate: bool = True,
+) -> ToolResult:
+    """
+    Cookie / 登录态管理:
+
+    - load: 从本地加载已保存的 cookie 并注入浏览器。需要 url(自动匹配 cookie 文件)。
+    - export: 导出当前浏览器 cookie 到本地。可选 name 和 account 标识。
+    - ensure_login: 检查登录状态,未登录时自动注入 cookie。需要 cookie_type 和 url。
+
+    Args:
+        action: 操作类型
+        url: 目标 URL(load / ensure_login 必填)
+        name: cookie 文件名(可选)
+        account: 账号名(export 时可选)
+        cookie_type: cookie 类型标识(ensure_login 必填)
+        auto_navigate: load 时找不到 cookie 是否自动导航到目标页面(默认 True)
+    """
+    if action == "load":
+        if not url:
+            return ToolResult(title="参数错误", output="", error="load 需要 url 参数")
+        return await browser_load_cookies(url=url, name=name, auto_navigate=auto_navigate)
+
+    elif action == "export":
+        return await browser_export_cookies(name=name, account=account)
+
+    elif action == "ensure_login":
+        if not cookie_type:
+            return ToolResult(title="参数错误", output="", error="ensure_login 需要 cookie_type 参数")
+        return await browser_ensure_login_with_cookies(
+            cookie_type=cookie_type,
+            url=url or "https://www.xiaohongshu.com",
+        )
 
-    # Cookie 持久化
-    'browser_export_cookies',
-    'browser_load_cookies',
+    else:
+        return ToolResult(title="未知 action", output="", error=f"不支持的 action: {action}")
+
+
+@tool()
+async def browser_wait(
+    seconds: Optional[int] = None,
+    user_message: Optional[str] = None,
+    timeout: int = 300,
+) -> ToolResult:
+    """
+    等待。两种模式:
+
+    - 传 seconds: 纯等待指定秒数(默认 3 秒)
+    - 传 user_message: 暂停并提示用户在浏览器中完成操作(如登录、验证码),
+      用户完成后按回车继续。timeout 控制最长等待时间。
+    - 两者都不传: 默认等待 3 秒
+
+    Args:
+        seconds: 等待秒数
+        user_message: 用户操作提示消息
+        timeout: user_message 模式的最长等待(秒),默认 300
+    """
+    if user_message:
+        return await browser_wait_for_user_action(message=user_message, timeout=timeout)
+    else:
+        return await browser_wait_impl(seconds=seconds or 3)
+
+
+@tool()
+async def browser_js(code: str) -> ToolResult:
+    """
+    在当前页面执行 JavaScript 代码。
+
+    Args:
+        code: JavaScript 代码字符串。返回值会被自动序列化。
+    """
+    return await browser_evaluate(code=code)
+
+
+@tool()
+async def browser_download(url: str, save_name: str = "") -> ToolResult:
+    """
+    下载指定 URL 的文件到本地。
+
+    Args:
+        url: 文件 URL
+        save_name: 保存文件名(可选,默认自动推断)
+    """
+    return await browser_download_direct_url(url=url, save_name=save_name or "download")
+
+
+# ============================================================
+# 导出(供外部使用)
+# ============================================================
+
+__all__ = [
+    # 会话管理(非 @tool)
+    'init_browser_session',
+    'get_browser_session',
+    'get_browser_live_url',
+    'cleanup_browser_session',
+    'kill_browser_session',
+
+    # 13 个 @tool 入口
+    'browser_navigate',
+    'browser_search',
+    'browser_back',
+    'browser_interact',
+    'browser_scroll',
+    'browser_screenshot',
+    'browser_elements',
+    'browser_read',
+    'browser_extract',
+    'browser_tabs',
+    'browser_cookies',
+    'browser_wait',
+    'browser_js',
+    'browser_download',
 ]