Compare commits

...

12 Commits

Author SHA1 Message Date
Zou-Seay
9f22a730df fix(extension): resolve race condition in hub config and fix tab initialization crash
Some checks failed
CI / test (24) (push) Has been cancelled
Deploy Demo / deploy (push) Has been cancelled
add: erp scrape python demo
2026-06-25 15:31:41 +08:00
Zou-Seay
e26589bc54 feat: 增加 ERP 订单自动化抓取自定义工具及相关开发文档
Some checks failed
CI / test (24) (push) Has been cancelled
Deploy Demo / deploy (push) Has been cancelled
2026-06-24 16:02:08 +08:00
Simon
fb4b8fd067 Merge pull request #565 from alibaba/dependabot/github_actions/github-actions-640176b5ab
Some checks failed
CI / test (24) (push) Has been cancelled
Deploy Demo / deploy (push) Has been cancelled
chore(deps): bump actions/checkout from 6 to 7 in the github-actions group
2026-06-23 14:24:52 +08:00
Simon
2bed20cd85 Merge pull request #566 from alibaba/dependabot/npm_and_yarn/development-dependencies-1075e1fe2e
chore(deps-dev): bump the development-dependencies group with 8 updates
2026-06-23 14:24:36 +08:00
Simon
c48c7c524e Merge pull request #567 from alibaba/dependabot/npm_and_yarn/development-major-3bc154b33b
chore(deps-dev): bump @types/node from 25.9.3 to 26.0.0 in the development-major group
2026-06-23 14:24:20 +08:00
dependabot[bot]
32f27e73e3 chore(deps-dev): bump @types/node in the development-major group
Bumps the development-major group with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).


Updates `@types/node` from 25.9.3 to 26.0.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: development-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-23 00:30:20 +00:00
dependabot[bot]
71738f1966 chore(deps-dev): bump the development-dependencies group with 8 updates
Bumps the development-dependencies group with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [@eslint-react/eslint-plugin](https://github.com/Rel1cx/eslint-react/tree/HEAD/plugins/eslint-plugin) | `5.9.0` | `5.9.2` |
| [globals](https://github.com/sindresorhus/globals) | `17.6.0` | `17.7.0` |
| [happy-dom](https://github.com/capricorn86/happy-dom) | `20.10.4` | `20.10.6` |
| [lint-staged](https://github.com/lint-staged/lint-staged) | `17.0.7` | `17.0.8` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.61.1` | `8.62.0` |
| [@types/chrome](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/chrome) | `0.1.43` | `0.2.0` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.18.0` | `1.21.0` |
| [simple-icons](https://github.com/simple-icons/simple-icons) | `16.23.0` | `16.24.0` |


Updates `@eslint-react/eslint-plugin` from 5.9.0 to 5.9.2
- [Release notes](https://github.com/Rel1cx/eslint-react/releases)
- [Changelog](https://github.com/Rel1cx/eslint-react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Rel1cx/eslint-react/commits/v5.9.2/plugins/eslint-plugin)

Updates `globals` from 17.6.0 to 17.7.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0)

Updates `happy-dom` from 20.10.4 to 20.10.6
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v20.10.4...v20.10.6)

Updates `lint-staged` from 17.0.7 to 17.0.8
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v17.0.7...v17.0.8)

Updates `typescript-eslint` from 8.61.1 to 8.62.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.62.0/packages/typescript-eslint)

Updates `@types/chrome` from 0.1.43 to 0.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/chrome)

Updates `lucide-react` from 1.18.0 to 1.21.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.21.0/packages/lucide-react)

Updates `simple-icons` from 16.23.0 to 16.24.0
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/compare/16.23.0...16.24.0)

---
updated-dependencies:
- dependency-name: "@eslint-react/eslint-plugin"
  dependency-version: 5.9.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: globals
  dependency-version: 17.7.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: happy-dom
  dependency-version: 20.10.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: lint-staged
  dependency-version: 17.0.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.62.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: "@types/chrome"
  dependency-version: 0.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: lucide-react
  dependency-version: 1.21.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: simple-icons
  dependency-version: 16.24.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-23 00:29:32 +00:00
dependabot[bot]
e44455ba80 chore(deps): bump actions/checkout in the github-actions group
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 6 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-23 00:27:34 +00:00
Simon
d2ee260d82 Merge pull request #560 from alibaba/dependabot/npm_and_yarn/development-dependencies-d854c95bb8
chore(deps-dev): bump the development-dependencies group across 1 directory with 17 updates
2026-06-17 20:53:39 +08:00
dependabot[bot]
1f738bc41c chore(deps-dev): bump the development-dependencies group across 1 directory with 17 updates
Bumps the development-dependencies group with 16 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@eslint-react/eslint-plugin](https://github.com/Rel1cx/eslint-react/tree/HEAD/plugins/eslint-plugin) | `5.8.16` | `5.9.0` |
| [@microsoft/api-extractor](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-extractor) | `7.58.8` | `7.58.9` |
| [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.3.0` | `4.3.1` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.9.2` | `25.9.3` |
| [eslint](https://github.com/eslint/eslint) | `10.4.1` | `10.5.0` |
| [happy-dom](https://github.com/capricorn86/happy-dom) | `20.10.2` | `20.10.4` |
| [prettier](https://github.com/prettier/prettier) | `3.8.3` | `3.8.4` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.61.0` | `8.61.1` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.8` | `4.1.9` |
| [@radix-ui/react-hover-card](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/hover-card) | `1.1.16` | `1.1.17` |
| [@radix-ui/react-label](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/label) | `2.1.9` | `2.1.10` |
| [@radix-ui/react-separator](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/separator) | `1.1.9` | `1.1.10` |
| [@radix-ui/react-slot](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/slot) | `1.2.5` | `1.3.0` |
| [@radix-ui/react-switch](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/switch) | `1.3.0` | `1.3.1` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.17.0` | `1.18.0` |
| [@radix-ui/react-tooltip](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tooltip) | `1.2.9` | `1.2.10` |



Updates `@eslint-react/eslint-plugin` from 5.8.16 to 5.9.0
- [Release notes](https://github.com/Rel1cx/eslint-react/releases)
- [Changelog](https://github.com/Rel1cx/eslint-react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Rel1cx/eslint-react/commits/v5.9.0/plugins/eslint-plugin)

Updates `@microsoft/api-extractor` from 7.58.8 to 7.58.9
- [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/api-extractor/CHANGELOG.md)
- [Commits](https://github.com/microsoft/rushstack/commits/@microsoft/api-extractor_v7.58.9/apps/api-extractor)

Updates `@tailwindcss/vite` from 4.3.0 to 4.3.1
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/@tailwindcss-vite)

Updates `@types/node` from 25.9.2 to 25.9.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint` from 10.4.1 to 10.5.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.4.1...v10.5.0)

Updates `happy-dom` from 20.10.2 to 20.10.4
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v20.10.2...v20.10.4)

Updates `prettier` from 3.8.3 to 3.8.4
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.8.3...3.8.4)

Updates `typescript-eslint` from 8.61.0 to 8.61.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.61.1/packages/typescript-eslint)

Updates `vitest` from 4.1.8 to 4.1.9
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/HEAD/packages/vitest)

Updates `@radix-ui/react-hover-card` from 1.1.16 to 1.1.17
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/hover-card/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/hover-card)

Updates `@radix-ui/react-label` from 2.1.9 to 2.1.10
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/label/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/label)

Updates `@radix-ui/react-separator` from 1.1.9 to 1.1.10
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/separator/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/separator)

Updates `@radix-ui/react-slot` from 1.2.5 to 1.3.0
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/slot/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/slot)

Updates `@radix-ui/react-switch` from 1.3.0 to 1.3.1
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/switch/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/switch)

Updates `lucide-react` from 1.17.0 to 1.18.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.18.0/packages/lucide-react)

Updates `tailwindcss` from 4.3.0 to 4.3.1
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/tailwindcss)

Updates `@radix-ui/react-tooltip` from 1.2.9 to 1.2.10
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tooltip/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tooltip)

---
updated-dependencies:
- dependency-name: "@eslint-react/eslint-plugin"
  dependency-version: 5.9.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: "@microsoft/api-extractor"
  dependency-version: 7.58.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@types/node"
  dependency-version: 25.9.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: eslint
  dependency-version: 10.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: happy-dom
  dependency-version: 20.10.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: prettier
  dependency-version: 3.8.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.61.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: vitest
  dependency-version: 4.1.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@radix-ui/react-hover-card"
  dependency-version: 1.1.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@radix-ui/react-label"
  dependency-version: 2.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@radix-ui/react-separator"
  dependency-version: 1.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@radix-ui/react-slot"
  dependency-version: 1.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: "@radix-ui/react-switch"
  dependency-version: 1.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: lucide-react
  dependency-version: 1.18.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: tailwindcss
  dependency-version: 4.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@radix-ui/react-tooltip"
  dependency-version: 1.2.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-16 05:00:12 +00:00
Simon
2802ab3dea Merge pull request #559 from alibaba/fix/hoist-happy-dom
fix(deps): hoist happy-dom to root devDependencies
2026-06-16 12:33:51 +08:00
Simon
e6a2e07640 fix(deps): hoist happy-dom to root devDependencies 2026-06-16 12:30:55 +08:00
15 changed files with 781 additions and 903 deletions

View File

@@ -16,7 +16,7 @@ jobs:
node-version: [24] node-version: [24]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -13,7 +13,7 @@ jobs:
id-token: write id-token: write
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v6

View File

@@ -13,7 +13,7 @@ jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v6

58
demo_erp_scrape.py Normal file
View File

@@ -0,0 +1,58 @@
import asyncio
import os
from dotenv import load_dotenv
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
# 加载当前目录下的 .env 文件
load_dotenv()
async def run_browser_automation():
print("⏳ 正在启动 Page Agent MCP 服务器...")
print("👉 如果你没有打开浏览器,系统会自动帮你唤起默认浏览器!\n")
# 1. 配置 MCP 服务端
# 它会自动读取当前系统的 PATH调用 npx 启动 @page-agent/mcp
server_params = StdioServerParameters(
command="npx",
args=["-y", "@page-agent/mcp"],
env={
**os.environ,
"LLM_BASE_URL": os.getenv("LLM_BASE_URL", ""),
"LLM_API_KEY": os.getenv("LLM_API_KEY", ""),
"LLM_MODEL_NAME": os.getenv("LLM_MODEL_NAME", "qwen-plus")
}
)
# 2. 通过标准输入输出Stdio连接到插件的 MCP 服务
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# 初始化握手
await session.initialize()
print("✅ 成功连接到了 MCP 服务端!正在等待浏览器插件握手...")
# 轮询等待浏览器插件连上来
for _ in range(15):
status_res = await session.call_tool("get_status", {})
if '"connected": true' in status_res.content[0].text:
break
await asyncio.sleep(1)
else:
print("❌ 浏览器插件连接超时!请确保 Chrome 浏览器正常运行,并启用了 Page Agent 插件。")
return
task_prompt = "请你先导航到 https://preview.pro.ant.design/list/table-list/ 页面,然后使用自定义工具 scrapeErpOrdersTool 来抓取当前页面的所有分页表格数据。抓取完成后,请告诉我一共抓取到了多少条数据,并列出前三条作为示例。"
print(f"🤖 派发自然语言任务: 【{task_prompt}\n")
print("👁️‍🗨️ 正在观测浏览器执行... (你可以切回浏览器看着它自动操作,大概需要几十秒)")
# 调用 MCP 的 execute_task 工具
result = await session.call_tool("execute_task", {
"task": task_prompt
})
print("\n🎉 浏览器任务执行完毕,大模型返回的最终结果是:")
print(result.content[0].text)
if __name__ == "__main__":
asyncio.run(run_browser_automation())

113
docs/custom-tools-guide.md Normal file
View File

@@ -0,0 +1,113 @@
# Page Agent 自定义工具注册指南
在 Page Agent 体系中你可以通过注册自定义工具Custom Tools让大模型能够执行你编写的特定 JavaScript 代码(如:复杂的批量爬虫、与系统底层的原生交互等)。
## 核心架构原理
Page Agent 的 Extension 版本使用了 `MultiPageAgent` 类来初始化。大模型与浏览器的交互是通过 `PageController` 实现的。
要增加新的工具,我们只需两步:**编写工具逻辑** -> **在实例化时注入配置**
## 步骤一:创建你的自定义工具
`packages/extension/src/agent/` 目录下(或者你自己的工具管理目录),创建一个新的工具文件,例如 `customTools.ts`
你需要引入 `@page-agent/core` 中的 `tool` 辅助函数,以及 `zod` 来定义参数格式:
```typescript
// 文件路径packages/extension/src/agent/customTools.ts
import { tool } from '@page-agent/core'
import * as z from 'zod/v4'
export const myCustomTool = tool({
// 【必填】Description: 给大模型看的自然语言说明书。写得越清楚,大模型调用的时机越准确。
description: '当需要执行特定的复杂业务逻辑(如静默抓取数据)时,调用此工具。',
// 【必填】InputSchema: 如果工具需要参数(比如你要抓取的目标页数),在这里定义。不需要参数写 z.object({})
inputSchema: z.object({
targetCount: z.number().optional().describe("目标抓取数量")
}),
// 【必填】Execute: 工具被大模型触发时执行的后台代码
execute: async function (input, { signal }) {
// 由于这段代码跑在 Chrome Extension 的 Background Worker 中,不能直接操纵网页 DOM。
// 同时出于安全限制,插件环境禁用了底层的 executeJavascript 方法。
// 我们必须使用 Chrome 原生的 chrome.scripting API 来向目标网页注入脚本。
// 1. 获取当前大模型正在操作的页面 Tab ID
const tabId = (this.pageController as any).currentTabId;
if (!tabId) return "报错:未找到激活的页面";
// 2. 将代码注入目标网页执行
const results = await chrome.scripting.executeScript({
target: { tabId: tabId },
func: async () => {
// ... 这段代码将直接跑在网页(如金蝶 ERP的控制台内部
return new Promise((resolve) => {
const data = "抓取完成的数据";
resolve(data); // 务必把数据 resolve 回后台
});
}
});
// 3. 取出网页传回来的数据
const resultData = results[0]?.result;
// 4. 将数据发送给后端的数据库 API (边抓边存,或最后存)
// await fetch('https://api.yourdomain.com/save', { method: 'POST', body: JSON.stringify(resultData) });
// 5. 返回给大模型汇报工作
return \`工具执行成功,已处理数据:\${resultData}\`;
}
});
```
> **🚨 极其关键的安全权限配置:**
> 使用 `chrome.scripting` API 前,你**必须**在插件配置文件 `packages/extension/wxt.config.js` 的 `permissions` 数组中添加 `'scripting'` 权限,否则会一直报错!
>
> ```javascript
> // wxt.config.js
> permissions: ['tabs', 'tabGroups', 'sidePanel', 'storage', 'scripting'],
> ```
## 步骤二:将工具注册到 Agent 实例中
编写完工具后,你必须告诉 Page Agent 存在这个工具。
打开 `packages/extension/src/agent/MultiPageAgent.ts`(或者你实例化 `PageAgent` 的地方)。在 `customTools` 属性中注册你的工具。
```typescript
// 文件路径packages/extension/src/agent/MultiPageAgent.ts
import { createTabTools } from './tabTools'
import { myCustomTool } from './customTools' // 1. 引入你的工具
export class MultiPageAgent extends PageAgentCore {
constructor(config: MultiPageAgentConfig) {
// ... (原有的 controller 初始化代码)
// 2. 将你的工具合并到 customTools 对象中
const customTools = {
...createTabTools(tabsController), // 保留原有的内置 Tab 切换工具
my_custom_tool: myCustomTool, // 注册你的新工具,键名 (my_custom_tool) 就是工具对外的 ID
}
super({
// ... (原有的其他配置)
customTools: customTools, // 3. 将工具对象传递给底层配置
});
// ...
}
}
```
## 步骤三:编译与发布插件
代码修改完毕后,你需要重新构建浏览器插件:
在项目的根目录(`/Users/seay/Documents/code/page-agent`)执行以下命令:
```bash
npm run build:ext
```
- 该命令会自动编译压缩代码,并在 `packages/extension/.output/` 目录下生成打包好的 `.zip` 文件(例如 `.output/page-agent-ext-1.10.0-chrome.zip`)。
- **更新插件:** 将此 `.zip` 文件发给客户解压。在浏览器的 `chrome://extensions/` 界面中覆盖加载该文件夹,并点击“刷新”图标即可生效。大模型立刻就能使用你的新工具了。

1359
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -45,27 +45,28 @@
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^21.0.1", "@commitlint/cli": "^21.0.1",
"@commitlint/config-conventional": "^21.0.1", "@commitlint/config-conventional": "^21.0.1",
"@eslint-react/eslint-plugin": "^5.8.16", "@eslint-react/eslint-plugin": "^5.9.2",
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@microsoft/api-extractor": "^7.58.8", "@microsoft/api-extractor": "^7.58.9",
"@tailwindcss/vite": "^4.3.0", "@tailwindcss/vite": "^4.3.1",
"@trivago/prettier-plugin-sort-imports": "^6.0.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^25.9.2", "@types/node": "^26.0.0",
"@vitejs/plugin-react": "^6.0.2", "@vitejs/plugin-react": "^6.0.2",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"concurrently": "^10.0.3", "concurrently": "^10.0.3",
"dotenv": "^17.4.2", "dotenv": "^17.4.2",
"eslint": "^10.4.0", "eslint": "^10.5.0",
"globals": "^17.6.0", "globals": "^17.7.0",
"happy-dom": "^20.10.6",
"husky": "^9.1.7", "husky": "^9.1.7",
"lint-staged": "^17.0.5", "lint-staged": "^17.0.8",
"prettier": "^3.8.3", "prettier": "^3.8.4",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.61.0", "typescript-eslint": "^8.62.0",
"unplugin-dts": "^1.0.1", "unplugin-dts": "^1.0.1",
"vite": "^8.0.14", "vite": "^8.0.14",
"vite-plugin-css-injected-by-js": "^5.0.1", "vite-plugin-css-injected-by-js": "^5.0.1",
"vitest": "^4.1.8" "vitest": "^4.1.9"
}, },
"overrides": { "overrides": {
"typescript": "^6.0.3", "typescript": "^6.0.3",

View File

@@ -10,27 +10,27 @@
"postinstall": "wxt prepare" "postinstall": "wxt prepare"
}, },
"devDependencies": { "devDependencies": {
"@radix-ui/react-hover-card": "^1.1.16", "@radix-ui/react-hover-card": "^1.1.17",
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.9", "@radix-ui/react-label": "^2.1.10",
"@radix-ui/react-separator": "^1.1.9", "@radix-ui/react-separator": "^1.1.10",
"@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-slot": "^1.3.0",
"@radix-ui/react-switch": "^1.3.0", "@radix-ui/react-switch": "^1.3.1",
"@tailwindcss/vite": "^4.3.0", "@tailwindcss/vite": "^4.3.1",
"@types/chrome": "^0.1.43", "@types/chrome": "^0.2.0",
"@types/react": "^19.2.17", "@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@wxt-dev/module-react": "^1.2.2", "@wxt-dev/module-react": "^1.2.2",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"idb": "^8.0.3", "idb": "^8.0.3",
"lucide-react": "^1.16.0", "lucide-react": "^1.21.0",
"motion": "^12.40.0", "motion": "^12.40.0",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"react": "^19.2.6", "react": "^19.2.6",
"react-dom": "^19.2.6", "react-dom": "^19.2.6",
"rough-notation": "^0.5.1", "rough-notation": "^0.5.1",
"simple-icons": "^16.23.0", "simple-icons": "^16.24.0",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"tailwind-merge": "^3.6.0", "tailwind-merge": "^3.6.0",
"tailwindcss": "^4.3.0", "tailwindcss": "^4.3.0",

View File

@@ -2,6 +2,7 @@ import { type AgentConfig, PageAgentCore } from '@page-agent/core'
import { RemotePageController } from './RemotePageController' import { RemotePageController } from './RemotePageController'
import { TabsController } from './TabsController' import { TabsController } from './TabsController'
import { scrapeErpOrdersTool } from './customTools'
import SYSTEM_PROMPT from './system_prompt.md?raw' import SYSTEM_PROMPT from './system_prompt.md?raw'
import { createTabTools } from './tabTools' import { createTabTools } from './tabTools'
@@ -26,7 +27,12 @@ export class MultiPageAgent extends PageAgentCore {
// multi page controller // multi page controller
const tabsController = new TabsController() const tabsController = new TabsController()
const pageController = new RemotePageController(tabsController) const pageController = new RemotePageController(tabsController)
const customTools = createTabTools(tabsController)
// 注册内置工具以及我们自定义的 ERP 抓取工具
const customTools = {
...createTabTools(tabsController),
scrape_erp_orders: scrapeErpOrdersTool,
}
// system prompt - auto-detect language if not specified // system prompt - auto-detect language if not specified
const language = config.language ?? detectLanguage() const language = config.language ?? detectLanguage()

View File

@@ -47,7 +47,7 @@ export class RemotePageController {
} }
async getLastUpdateTime(): Promise<number> { async getLastUpdateTime(): Promise<number> {
if (!this.currentTabId) throw new Error('tabsController not initialized.') if (!this.currentTabId) return Date.now()
return sendMessage({ return sendMessage({
type: 'PAGE_CONTROL', type: 'PAGE_CONTROL',
action: 'get_last_update_time', action: 'get_last_update_time',

View File

@@ -0,0 +1,64 @@
import { tool } from '@page-agent/core'
import * as z from 'zod/v4'
export const scrapeErpOrdersTool = tool({
description:
'当到达 ERP 订单列表或查询列表的第一页时,调用此工具。该工具会自动接管浏览器,静默抓取所有分页表格数据。',
inputSchema: z.object({}),
execute: async function (input, { signal }) {
console.log('🚀 大模型已切断,原生爬虫代码接管...')
// 获取当前正在被 Agent 控制的标签页 ID
const tabId = (this.pageController as any).currentTabId
if (!tabId) {
return '❌ 错误:没有找到激活的标签页,无法执行抓取。'
}
try {
// 在 Chrome 插件中,不能使用 executeJavascript必须使用 Chrome 原生的 scripting API 注入代码
const results = await chrome.scripting.executeScript({
target: { tabId: tabId },
func: async () => {
// --- 以下代码将原封不动地在金蝶/AntDesign的网页环境内部执行 ---
let allData: any[] = []
let pageCount = 1
while (true) {
const rows = document.querySelectorAll('tr.ant-table-row')
const pageData = Array.from(rows).map((row) => {
const cells = row.querySelectorAll('td')
return {
ruleName: cells[1] ? (cells[1] as HTMLElement).innerText.trim() : '',
desc: cells[2] ? (cells[2] as HTMLElement).innerText.trim() : '',
}
})
allData = allData.concat(pageData)
const nextLi = document.querySelector('li.ant-pagination-next')
if (!nextLi || nextLi.classList.contains('ant-pagination-disabled')) {
return allData // 把数据回传
}
const nextBtn = nextLi.querySelector('button')
if (nextBtn) nextBtn.click()
else (nextLi as HTMLElement).click()
pageCount++
await new Promise((r) => setTimeout(r, 1500))
}
// --- 网页内部代码结束 ---
},
})
// 提取网页返回的数据
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const extractedOrders = (results && results[0] ? results[0].result : []) as any
console.log('✅ 成功拿到了网页返回的全部数据:', extractedOrders)
return `成功抓取了所有 ${extractedOrders?.length || 0} 条订单数据,并已打印到后台控制台日志中。`
} catch (error) {
console.error('执行脚本失败:', error)
return `❌ 抓取失败: ${error}`
}
},
})

View File

@@ -218,9 +218,23 @@ export function useHubWs(
Number(wsPort), Number(wsPort),
{ {
onExecute: async (task, incomingConfig) => { onExecute: async (task, incomingConfig) => {
const { execute, configure, config } = latestRef.current let { execute } = latestRef.current
const { configure, config } = latestRef.current
if (incomingConfig) { if (incomingConfig) {
let changed = false
for (const key of Object.keys(incomingConfig)) {
if (incomingConfig[key] !== (config as any)?.[key]) {
changed = true
break
}
}
if (changed) {
await configure({ ...config, ...incomingConfig } as ExtConfig) await configure({ ...config, ...incomingConfig } as ExtConfig)
// Wait a bit for React to re-render and instantiate the new MultiPageAgent
await new Promise((resolve) => setTimeout(resolve, 500))
// Re-fetch the newly generated execute function after re-render
execute = latestRef.current.execute
}
} }
const result = await execute(task) const result = await execute(task)
return { success: result.success, data: result.data } return { success: result.success, data: result.data }

View File

@@ -45,7 +45,7 @@ export default defineConfig({
name: '__MSG_extName__', name: '__MSG_extName__',
description: '__MSG_extDescription__', description: '__MSG_extDescription__',
homepage_url: 'https://alibaba.github.io/page-agent/', homepage_url: 'https://alibaba.github.io/page-agent/',
permissions: ['tabs', 'tabGroups', 'sidePanel', 'storage'], permissions: ['tabs', 'tabGroups', 'sidePanel', 'storage', 'scripting'],
host_permissions: ['<all_urls>'], host_permissions: ['<all_urls>'],
icons: { icons: {
64: 'assets/page-agent-64.png', 64: 'assets/page-agent-64.png',

View File

@@ -48,8 +48,5 @@
}, },
"dependencies": { "dependencies": {
"ai-motion": "^0.4.8" "ai-motion": "^0.4.8"
},
"devDependencies": {
"happy-dom": "^20.10.2"
} }
} }

View File

@@ -10,21 +10,21 @@
}, },
"devDependencies": { "devDependencies": {
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-separator": "^1.1.9", "@radix-ui/react-separator": "^1.1.10",
"@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-slot": "^1.3.0",
"@radix-ui/react-switch": "^1.3.0", "@radix-ui/react-switch": "^1.3.1",
"@radix-ui/react-tooltip": "^1.2.9", "@radix-ui/react-tooltip": "^1.2.10",
"@types/react": "^19.2.17", "@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"lucide-react": "^1.16.0", "lucide-react": "^1.21.0",
"motion": "^12.40.0", "motion": "^12.40.0",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"react": "^19.2.6", "react": "^19.2.6",
"react-dom": "^19.2.6", "react-dom": "^19.2.6",
"rough-notation": "^0.5.1", "rough-notation": "^0.5.1",
"simple-icons": "^16.23.0", "simple-icons": "^16.24.0",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"tailwind-merge": "^3.6.0", "tailwind-merge": "^3.6.0",
"tailwindcss": "^4.3.0", "tailwindcss": "^4.3.0",