Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ab713f3d3a | |||
| 05cc4f36c8 | |||
| 54e9bdad7d | |||
| 0fc88c0080 | |||
| 02f97ef2fa | |||
| 0853ffbbc6 | |||
| 60ac6da09f | |||
| 11a9fb1181 | |||
| 3762d0f1e0 | |||
| ebbe92f7ca | |||
| 9f239b2de3 | |||
| 2410c27b55 | |||
| 6d6c82648c | |||
| f41119c1ad | |||
| 9e6e1b996c | |||
| 1ab23e181f | |||
| a1b485691f | |||
| 694e05b800 | |||
| b761795c1a | |||
| 8cc54983aa | |||
| 59a599285e | |||
| 2f8c2b395c | |||
| 28f836674c | |||
| 6f01632231 | |||
| 41123ac561 | |||
| c8bf0dd20f | |||
| ec2b744bab | |||
| eab9cf64e8 | |||
| 42130d6f1d |
@@ -58,4 +58,4 @@ body:
|
||||
- label: I have read the Code of Conduct. / 我已阅读行为准则。
|
||||
required: true
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
|
||||
@@ -44,4 +44,4 @@ body:
|
||||
- label: I have read the CODE_OF_CONDUCT.md and CONTRIBUTING.md. / 我已阅读行为准则。
|
||||
required: true
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
id-token: write # Required for OIDC
|
||||
id-token: write # Required for OIDC
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
# Ensure npm 11.5.1 or later is installed
|
||||
- name: Update npm
|
||||
run: npm install -g npm@latest
|
||||
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
@@ -32,4 +32,4 @@ jobs:
|
||||
run: npm run build:libs
|
||||
|
||||
- name: Publish all public packages
|
||||
run: npm publish --workspaces --access public
|
||||
run: npm publish --workspaces --access public
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "prettier.prettier-vscode"]
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "prettier.prettier-vscode"]
|
||||
}
|
||||
|
||||
Vendored
+27
-26
@@ -1,28 +1,29 @@
|
||||
{
|
||||
"editor.fontLigatures": true,
|
||||
"cSpell.words": [
|
||||
"deepseek",
|
||||
"HITL",
|
||||
"innerhtml",
|
||||
"llms",
|
||||
"opensource",
|
||||
"qwen",
|
||||
"retryable",
|
||||
"shadcn",
|
||||
"wouter"
|
||||
],
|
||||
"markdownlint.config": {
|
||||
// "comment": "Relaxed rules",
|
||||
"default": true,
|
||||
"whitespace": false,
|
||||
"line_length": false,
|
||||
"ul-indent": false,
|
||||
"no-inline-html": false,
|
||||
"no-bare-urls": false,
|
||||
"fenced-code-language": false,
|
||||
"first-line-h1": false,
|
||||
"block-spacing": false,
|
||||
"blanks-around-lists": false,
|
||||
"ol-prefix": false
|
||||
}
|
||||
"editor.fontLigatures": true,
|
||||
"cSpell.words": [
|
||||
"deepseek",
|
||||
"HITL",
|
||||
"innerhtml",
|
||||
"llms",
|
||||
"onwarn",
|
||||
"opensource",
|
||||
"qwen",
|
||||
"retryable",
|
||||
"shadcn",
|
||||
"wouter"
|
||||
],
|
||||
"markdownlint.config": {
|
||||
// "comment": "Relaxed rules",
|
||||
"default": true,
|
||||
"whitespace": false,
|
||||
"line_length": false,
|
||||
"ul-indent": false,
|
||||
"no-inline-html": false,
|
||||
"no-bare-urls": false,
|
||||
"fenced-code-language": false,
|
||||
"first-line-h1": false,
|
||||
"block-spacing": false,
|
||||
"blanks-around-lists": false,
|
||||
"ol-prefix": false
|
||||
}
|
||||
}
|
||||
|
||||
+61
-51
@@ -7,16 +7,16 @@ Thank you for your interest in contributing to Page-Agent! We welcome contributi
|
||||
### Development Setup
|
||||
|
||||
1. **Prerequisites**
|
||||
- `node.js >= 20` with `npm >= 10`
|
||||
- An editor that supports `ts/eslint/prettier`
|
||||
- Make sure `eslint`, `prettier` and `commitlint` work well
|
||||
- `node.js >= 20` with `npm >= 10`
|
||||
- An editor that supports `ts/eslint/prettier`
|
||||
- Make sure `eslint`, `prettier` and `commitlint` work well
|
||||
|
||||
2. **Setup**
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm start # Start demo and documentation site
|
||||
```
|
||||
```bash
|
||||
npm ci
|
||||
npm start # Start demo and documentation site
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
|
||||
@@ -25,11 +25,11 @@ This is a **monorepo** with npm workspaces containing **two main packages**:
|
||||
1. **Core Library** (`packages/page-agent/`) - Pure JavaScript/TypeScript AI agent library for browser DOM automation, published as `page-agent` on npm
|
||||
2. **Website** (`packages/website/`) - React documentation and landing page. Also as demo and test page for the core lib. private package `@page-agent/website`
|
||||
|
||||
We use a simplified monorepo solution with `native npm-workspace + ts reference + vite alias`. No fancy tooling. Hoisting is required.
|
||||
We use a simplified monorepo solution with `native npm-workspace + ts reference + vite alias`. No fancy tooling. Hoisting is required.
|
||||
|
||||
- When developing. Use alias so that we don't have to pre-build.
|
||||
- When bundling. Use external and disable ts `paths` alias to leave deps out.
|
||||
- When bundling `UMD` and `Website`. Bundle everything including local packages.
|
||||
- When bundling `IIFE` and `Website`. Bundle everything including local packages.
|
||||
|
||||
## 🤝 How to Contribute
|
||||
|
||||
@@ -44,40 +44,39 @@ We use a simplified monorepo solution with `native npm-workspace + ts reference
|
||||
|
||||
1. **Fork and Clone**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-username/page-agent.git
|
||||
cd page-agent
|
||||
```
|
||||
```bash
|
||||
git clone https://github.com/your-username/page-agent.git
|
||||
cd page-agent
|
||||
```
|
||||
|
||||
2. **Create Feature Branch**
|
||||
|
||||
```bash
|
||||
git checkout -b feat/your-feature-name
|
||||
```
|
||||
```bash
|
||||
git checkout -b feat/your-feature-name
|
||||
```
|
||||
|
||||
3. **Make Changes**
|
||||
- Follow existing code style and patterns
|
||||
- Add tests for new functionality
|
||||
- Update documentation as needed
|
||||
- Follow existing code style and patterns
|
||||
- Add tests for new functionality
|
||||
- Update documentation as needed
|
||||
|
||||
4. **Test Your Changes**
|
||||
|
||||
```bash
|
||||
# TODO
|
||||
```
|
||||
- Test in our demo website
|
||||
- Test it on other websites if applicable
|
||||
- `@TODO: test suite`
|
||||
|
||||
5. **Commit and Push**
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: add awesome feature"
|
||||
git push origin feat/your-feature-name
|
||||
```
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: add awesome feature"
|
||||
git push origin feat/your-feature-name
|
||||
```
|
||||
|
||||
6. **Create Pull Request**
|
||||
- Provide clear description of changes
|
||||
- Link related issues
|
||||
- Include screenshots for UI changes
|
||||
- Provide clear description of changes
|
||||
- Link related issues
|
||||
- Include screenshots for UI changes
|
||||
|
||||
## 📝 Code Style
|
||||
|
||||
@@ -94,41 +93,52 @@ We use a simplified monorepo solution with `native npm-workspace + ts reference
|
||||
- It's **recommended** to heavily rely on AI (aka "vibe coding") when maintaining **demo pages and tests**.
|
||||
- BUT **NOT the core lib!!!** Be very careful if AI ever touched the core lib!!!
|
||||
- Review anything AI wrote before make a commit. You are the author of anything you commit. NOT AI.
|
||||
- Update the AI instructions when structure changed.
|
||||
- Cursor and Cline: `./.cursor/rules`
|
||||
- Github Copilot: `./.github/copilot-instructions.md`
|
||||
- Claude Code: `./CLAUDE.md`
|
||||
- Update the [AI instructions](AGENTS.md) when structure changed.
|
||||
|
||||
## 🔧 Development Workflows
|
||||
|
||||
### Test With Your Own LLM API
|
||||
|
||||
- Create a `.env` file in the repo root with your LLM API config
|
||||
|
||||
```env
|
||||
LLM_MODEL_NAME=gpt-5.2
|
||||
LLM_API_KEY=your-api-key
|
||||
LLM_BASE_URL=https://api.your-llm-provider.com/v1
|
||||
```
|
||||
|
||||
- Restart the dev server to load new env vars
|
||||
- If not provided, the demo will the free testing proxy by default
|
||||
|
||||
### Website Development
|
||||
|
||||
```bash
|
||||
npm start # React development server
|
||||
npm start
|
||||
```
|
||||
|
||||
### Core Lib Development and Testing
|
||||
### Testing on Other Websites
|
||||
|
||||
> @TODO this part is outdated. Update this.
|
||||
- Start and serve a local `iife` script
|
||||
|
||||
- Config your LLM API
|
||||
- Start and serve a local umd script
|
||||
```bash
|
||||
npm run dev:iife # Serving IIFE with auto rebuild at http://localhost:5174/page-agent.js
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run dev:umd # Serving UMD with auto rebuild at http://localhost:5173/page-agent.umd.cjs
|
||||
```
|
||||
- Add a new bookmark
|
||||
|
||||
- Add a new bookmark enable it on other website
|
||||
```javascript
|
||||
javascript:(function(){var s=document.createElement('script');s.src=`http://localhost:5174/page-agent.js?t=${Math.random()}`;s.onload=()=>console.log(%27PageAgent ready!%27);document.head.appendChild(s);})();
|
||||
```
|
||||
|
||||
```
|
||||
javascript:(function(){var s=document.createElement('script');s.src=`http://localhost:5173/page-agent.umd.cjs?t=${Math.random()}`;s.onload=()=>console.log(%27PageAgent ready!%27);document.head.appendChild(s);})();
|
||||
```
|
||||
- Click the bookmark on any page to load Page-Agent
|
||||
|
||||
> Warning: AK in your local `.env` will be inlined in the iife script.
|
||||
|
||||
### Adding Documentation
|
||||
|
||||
1. Create `website/src/docs/section/page-name/page.tsx`
|
||||
2. Add route to `website/src/router.tsx`
|
||||
3. Add navigation link to `website/src/components/DocsLayout.tsx`
|
||||
Ask an AI to help you add documentation to the `website/` package. Follow the existing style.
|
||||
|
||||
> Our AGENTS.md file and guardrails are designed for this purpose. But please be careful and review anything AI generated.
|
||||
|
||||
## 🎯 Contribution Areas
|
||||
|
||||
@@ -143,7 +153,7 @@ We especially welcome contributions in:
|
||||
|
||||
## 🚫 What We Don't Accept
|
||||
|
||||
- Changes that break existing API compatibility
|
||||
- Changes that break existing API compatibility (Discuss first)
|
||||
- Heavy dependencies to core library
|
||||
- Contributions without proper testing
|
||||
- Code that doesn't follow project conventions
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Alibaba
|
||||
Copyright (c) 2026 Alibaba
|
||||
Copyright (c) 2026 Simon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+32
-50
@@ -1,8 +1,11 @@
|
||||
# PageAgent 🤖🪄
|
||||
|
||||

|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://img.alicdn.com/imgextra/i4/O1CN01qKig1P1FnhpFKNdi6_!!6000000000532-2-tps-1280-256.png">
|
||||
<img alt="Page Agent Banner" src="https://img.alicdn.com/imgextra/i1/O1CN01NCMKXj1Gn4tkFTsxf_!!6000000000666-2-tps-1280-256.png">
|
||||
</picture>
|
||||
|
||||
[](https://badge.fury.io/js/page-agent) [](https://opensource.org/licenses/MIT) [](http://www.typescriptlang.org/) [](https://www.npmjs.com/package/page-agent) [](https://bundlephobia.com/package/page-agent) [](https://github.com/alibaba/page-agent)
|
||||
[](https://opensource.org/licenses/MIT) [](http://www.typescriptlang.org/) [](https://www.npmjs.com/package/page-agent) [](https://bundlephobia.com/package/page-agent) [](https://github.com/alibaba/page-agent)
|
||||
|
||||
纯 JS 实现的 GUI agent。使用自然语言操作你的 Web 应用。无须后端、客户端、浏览器插件。
|
||||
|
||||
@@ -10,7 +13,7 @@
|
||||
|
||||
👉 <a href="https://alibaba.github.io/page-agent/" target="_blank"><b>🚀 Demo</b></a> | <a href="https://alibaba.github.io/page-agent/#/docs/introduction/overview" target="_blank"><b>📖 Documentation</b></a>
|
||||
|
||||
<video id="demo-video" src="https://github.com/user-attachments/assets/141bbb01-8022-4d1f-919d-9efc9a1dc1cf" width="640" crossorigin muted autoplay loop></video>
|
||||
<video id="demo-video" src="https://github.com/user-attachments/assets/34d8444d-cbfb-44a3-a24e-fd5c167bb0bf" controls crossorigin muted></video>
|
||||
|
||||
---
|
||||
|
||||
@@ -28,22 +31,25 @@
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 快速体验 (Demo CDN)
|
||||
### 快速体验 (With Testing LLM)
|
||||
|
||||
最快的体验方式:
|
||||
|
||||
```html
|
||||
<script src="https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js" crossorigin="true"></script>
|
||||
<script
|
||||
src="https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js"
|
||||
crossorigin="true"
|
||||
></script>
|
||||
```
|
||||
|
||||
> ⚠️ **仅用于技术评估。** Demo 模型有速率限制和使用限制,生产环境请使用 NPM 方式。
|
||||
|
||||
| 位置 | URL |
|
||||
| ------ | --------------------------------------------------------------------------------------- |
|
||||
| 全球 | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js |
|
||||
| 中国 | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js |
|
||||
| Mirrors | URL |
|
||||
| ------- | ----------------------------------------------------------------------------------- |
|
||||
| Global | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js |
|
||||
| China | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js |
|
||||
|
||||
### NPM 安装(推荐)
|
||||
### NPM 安装
|
||||
|
||||
```bash
|
||||
npm install page-agent
|
||||
@@ -53,35 +59,16 @@ npm install page-agent
|
||||
import { PageAgent } from 'page-agent'
|
||||
|
||||
const agent = new PageAgent({
|
||||
model: 'deepseek-chat',
|
||||
baseURL: 'https://api.deepseek.com',
|
||||
apiKey: 'YOUR_API_KEY',
|
||||
language: 'zh-CN',
|
||||
model: 'deepseek-chat',
|
||||
baseURL: 'https://api.deepseek.com',
|
||||
apiKey: 'YOUR_API_KEY',
|
||||
language: 'zh-CN',
|
||||
})
|
||||
|
||||
await agent.execute('点击登录按钮')
|
||||
```
|
||||
|
||||
### CDN 引入
|
||||
|
||||
适用于无法使用 NPM 的环境,用法与 NPM 一致:
|
||||
|
||||
```html
|
||||
<script src="https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.js" crossorigin="true"></script>
|
||||
<script>
|
||||
const agent = new PageAgent({
|
||||
model: 'deepseek-chat',
|
||||
baseURL: 'https://api.deepseek.com',
|
||||
apiKey: 'YOUR_API_KEY',
|
||||
})
|
||||
await agent.execute('点击登录按钮')
|
||||
</script>
|
||||
```
|
||||
|
||||
| 位置 | URL |
|
||||
| ------ | ----------------------------------------------------------------------------------- |
|
||||
| 全球 | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.js |
|
||||
| 中国 | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.js |
|
||||
适用于无法使用 NPM 的环境,我们也提供了 IIFE 构建的 CDN 方式。[@see CDN Usage](https://alibaba.github.io/page-agent/#/docs/integration/cdn-setup)
|
||||
|
||||
## 🏗️ 架构设计
|
||||
|
||||
@@ -101,28 +88,19 @@ packages/
|
||||
|
||||
欢迎社区贡献!以下是参与方式:
|
||||
|
||||
### 开发环境
|
||||
1. Fork 并 clone。`git clone https://github.com/alibaba/page-agent.git && cd page-agent`
|
||||
2. 安装依赖: `npm install`
|
||||
3. 启动开发: `npm start`
|
||||
|
||||
1. Fork 项目仓库
|
||||
2. Clone or fork: `git clone https://github.com/alibaba/page-agent.git && cd page-agent`
|
||||
3. 安装依赖: `npm install`
|
||||
4. 启动开发: `npm start`
|
||||
更多详情请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
|
||||
|
||||
### 贡献指南
|
||||
|
||||
请在贡献前阅读我们的[行为准则](CODE_OF_CONDUCT.md)和[贡献指南](CONTRIBUTING.md)。
|
||||
请在贡献前阅读我们的[行为准则](CODE_OF_CONDUCT.md)。
|
||||
|
||||
## 👏 致谢
|
||||
|
||||
本项目基于以下优秀项目构建:
|
||||
本项目基于 **[`browser-use`](https://github.com/browser-use/browser-use)** 的优秀工作构建。
|
||||
|
||||
- **[browser-use](https://github.com/browser-use/browser-use)**
|
||||
|
||||
PageAgent 专为**客户端网页增强**设计,不是服务端自动化工具。
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。
|
||||
`PageAgent` 专为**客户端网页增强**设计,不是服务端自动化工具。
|
||||
|
||||
```
|
||||
DOM processing components and prompt are derived from browser-use:
|
||||
@@ -141,6 +119,10 @@ Third-party dependencies and their licenses can be found in the package.json
|
||||
file and in the node_modules directory after installation.
|
||||
```
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
[MIT License](LICENSE)
|
||||
|
||||
---
|
||||
|
||||
**⭐ 如果觉得 PageAgent 有用或有趣,请给项目点个星!**
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# PageAgent 🤖🪄
|
||||
|
||||

|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://img.alicdn.com/imgextra/i4/O1CN01qKig1P1FnhpFKNdi6_!!6000000000532-2-tps-1280-256.png">
|
||||
<img alt="Page Agent Banner" src="https://img.alicdn.com/imgextra/i1/O1CN01NCMKXj1Gn4tkFTsxf_!!6000000000666-2-tps-1280-256.png">
|
||||
</picture>
|
||||
|
||||
[](https://badge.fury.io/js/page-agent) [](https://opensource.org/licenses/MIT) [](http://www.typescriptlang.org/) [](https://www.npmjs.com/package/page-agent) [](https://bundlephobia.com/package/page-agent) [](https://github.com/alibaba/page-agent)
|
||||
[](https://opensource.org/licenses/MIT) [](http://www.typescriptlang.org/) [](https://www.npmjs.com/package/page-agent) [](https://bundlephobia.com/package/page-agent) [](https://github.com/alibaba/page-agent)
|
||||
|
||||
The GUI Agent Living in Your Webpage. Control web interfaces with natural language.
|
||||
|
||||
@@ -10,7 +13,7 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua
|
||||
|
||||
👉 <a href="https://alibaba.github.io/page-agent/" target="_blank"><b>🚀 Demo</b></a> | <a href="https://alibaba.github.io/page-agent/#/docs/introduction/overview" target="_blank"><b>📖 Documentation</b></a>
|
||||
|
||||
<video id="demo-video" src="https://github.com/user-attachments/assets/de8d1964-8bde-494f-a52f-2975469557a5" width="640" crossorigin muted autoplay loop></video>
|
||||
<video id="demo-video" src="https://github.com/user-attachments/assets/34d8444d-cbfb-44a3-a24e-fd5c167bb0bf" controls crossorigin muted></video>
|
||||
|
||||
---
|
||||
|
||||
@@ -28,22 +31,25 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Quick Try (Demo CDN)
|
||||
### Quick Try (With Testing LLM)
|
||||
|
||||
Fastest way to try PageAgent:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js" crossorigin="true"></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js"
|
||||
crossorigin="true"
|
||||
></script>
|
||||
```
|
||||
|
||||
> ⚠️ **For technical evaluation only.** Demo model has rate limits and usage restrictions. Use NPM for production.
|
||||
|
||||
| Location | URL |
|
||||
| -------- | --------------------------------------------------------------------------------------- |
|
||||
| Global | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js |
|
||||
| China | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js |
|
||||
| Mirrors | URL |
|
||||
| ------- | ----------------------------------------------------------------------------------- |
|
||||
| Global | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js |
|
||||
| China | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js |
|
||||
|
||||
### NPM Installation (Recommended)
|
||||
### NPM Installation
|
||||
|
||||
```bash
|
||||
npm install page-agent
|
||||
@@ -53,35 +59,16 @@ npm install page-agent
|
||||
import { PageAgent } from 'page-agent'
|
||||
|
||||
const agent = new PageAgent({
|
||||
model: 'deepseek-chat',
|
||||
baseURL: 'https://api.deepseek.com',
|
||||
apiKey: 'YOUR_API_KEY',
|
||||
language: 'en-US',
|
||||
model: 'deepseek-chat',
|
||||
baseURL: 'https://api.deepseek.com',
|
||||
apiKey: 'YOUR_API_KEY',
|
||||
language: 'en-US',
|
||||
})
|
||||
|
||||
await agent.execute('Click the login button')
|
||||
```
|
||||
|
||||
### CDN Build
|
||||
|
||||
For environments where NPM is not available. Usage is identical to NPM:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.js" crossorigin="true"></script>
|
||||
<script>
|
||||
const agent = new PageAgent({
|
||||
model: 'deepseek-chat',
|
||||
baseURL: 'https://api.deepseek.com',
|
||||
apiKey: 'YOUR_API_KEY',
|
||||
})
|
||||
await agent.execute('Click the login button')
|
||||
</script>
|
||||
```
|
||||
|
||||
| Location | URL |
|
||||
| -------- | ----------------------------------------------------------------------------------- |
|
||||
| Global | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.js |
|
||||
| China | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.js |
|
||||
For environments where NPM is not available. We do offer a IIFE build via CDN. [@see CDN Usage](https://alibaba.github.io/page-agent/#/docs/integration/cdn-setup)
|
||||
|
||||
## 🏗️ Structure
|
||||
|
||||
@@ -101,28 +88,19 @@ packages/
|
||||
|
||||
We welcome contributions from the community! Here's how to get started:
|
||||
|
||||
### Setup
|
||||
1. Fork and clone. `git clone https://github.com/alibaba/page-agent.git && cd page-agent`
|
||||
2. Install dependencies: `npm install`
|
||||
3. Start development: `npm start`
|
||||
|
||||
1. Fork the repository
|
||||
2. Clone your fork: `git clone https://github.com/alibaba/page-agent.git && cd page-agent`
|
||||
3. Install dependencies: `npm install`
|
||||
4. Start development: `npm start`
|
||||
More details in [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
### Contributing Guidelines
|
||||
|
||||
Please read our [Code of Conduct](CODE_OF_CONDUCT.md) and [Contributing Guide](CONTRIBUTING.md) before contributing.
|
||||
Please read our [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.
|
||||
|
||||
## 👏 Acknowledgments
|
||||
|
||||
This project builds upon the excellent work of:
|
||||
This project builds upon the excellent work of **[`browser-use`](https://github.com/browser-use/browser-use)**.
|
||||
|
||||
- **[browser-use](https://github.com/browser-use/browser-use)**
|
||||
|
||||
PageAgent is designed for **client-side web enhancement**, not server-side automation.
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
`PageAgent` is designed for **client-side web enhancement**, not server-side automation.
|
||||
|
||||
```
|
||||
DOM processing components and prompt are derived from browser-use:
|
||||
@@ -141,6 +119,10 @@ Third-party dependencies and their licenses can be found in the package.json
|
||||
file and in the node_modules directory after installation.
|
||||
```
|
||||
|
||||
## 📄 License
|
||||
|
||||
[MIT License](LICENSE)
|
||||
|
||||
---
|
||||
|
||||
**⭐ Star this repo if you find PageAgent helpful!**
|
||||
|
||||
Generated
+15
-29
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "root",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "root",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"packages/page-controller",
|
||||
@@ -1540,20 +1540,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/api-extractor/node_modules/typescript": {
|
||||
"version": "5.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
|
||||
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/api-extractor/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
@@ -4627,9 +4613,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz",
|
||||
"integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==",
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz",
|
||||
"integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
@@ -8147,15 +8133,15 @@
|
||||
},
|
||||
"packages/cdn": {
|
||||
"name": "@page-agent/cdn",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"page-agent": "0.2.0"
|
||||
"page-agent": "0.2.4"
|
||||
}
|
||||
},
|
||||
"packages/llms": {
|
||||
"name": "@page-agent/llms",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^5.6.2",
|
||||
@@ -8163,19 +8149,19 @@
|
||||
}
|
||||
},
|
||||
"packages/page-agent": {
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@page-agent/llms": "0.2.0",
|
||||
"@page-agent/page-controller": "0.2.0",
|
||||
"@page-agent/ui": "0.2.0",
|
||||
"@page-agent/llms": "0.2.4",
|
||||
"@page-agent/page-controller": "0.2.4",
|
||||
"@page-agent/ui": "0.2.4",
|
||||
"chalk": "^5.6.2",
|
||||
"zod": "^4.3.5"
|
||||
}
|
||||
},
|
||||
"packages/page-controller": {
|
||||
"name": "@page-agent/page-controller",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ai-motion": "^0.4.8"
|
||||
@@ -8183,12 +8169,12 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@page-agent/ui",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"license": "MIT"
|
||||
},
|
||||
"packages/website": {
|
||||
"name": "@page-agent/website",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
|
||||
+22
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "root",
|
||||
"private": true,
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"packages/page-controller",
|
||||
@@ -29,7 +29,7 @@
|
||||
"build:website": "npm run build:website --workspace=@page-agent/website",
|
||||
"build:libs": "npm run build --workspaces --if-present",
|
||||
"build": "npm run build:libs && npm run build:website",
|
||||
"dev:umd": "npm run dev:umd --workspace=page-agent",
|
||||
"dev:iife": "npm run dev:iife --workspace=page-agent",
|
||||
"version": "node scripts/sync-version.js",
|
||||
"lint": "eslint .",
|
||||
"prepare": "husky"
|
||||
@@ -59,6 +59,9 @@
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-css-injected-by-js": "^3.5.2"
|
||||
},
|
||||
"overrides": {
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts,cjs,cts,mjs,mts}": [
|
||||
"npx prettier --write --ignore-unknown",
|
||||
@@ -99,6 +102,22 @@
|
||||
".css$"
|
||||
],
|
||||
"importOrderSeparation": true,
|
||||
"importOrderSortSpecifiers": true
|
||||
"importOrderSortSpecifiers": true,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.md",
|
||||
"options": {
|
||||
"useTabs": false,
|
||||
"tabWidth": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.json",
|
||||
"options": {
|
||||
"useTabs": false,
|
||||
"tabWidth": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@page-agent/cdn",
|
||||
"private": false,
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"dist/"
|
||||
@@ -18,6 +18,6 @@
|
||||
"build": "vite build && vite build --mode demo"
|
||||
},
|
||||
"dependencies": {
|
||||
"page-agent": "0.2.0"
|
||||
"page-agent": "0.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,13 @@ export default defineConfig(({ mode }) => {
|
||||
outDir: resolve(__dirname, 'dist'),
|
||||
emptyOutDir: !isDemo, // only empty on first build (full)
|
||||
minify: false,
|
||||
cssCodeSplit: true,
|
||||
rollupOptions: {
|
||||
onwarn: function (message, handler) {
|
||||
if (message.code === 'EVAL') return
|
||||
handler(message)
|
||||
},
|
||||
},
|
||||
},
|
||||
define: {
|
||||
'process.env.NODE_ENV': '"production"',
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# @page-agent/llms
|
||||
|
||||
LLM client with a **reflection-before-action** mental model for page-agent.
|
||||
|
||||
## Why This Package Exists
|
||||
|
||||
The LLM module and the agent logic are inherently coupled. This package exists not to decouple them, but to **define the interface contract** between the LLM and the agent.
|
||||
|
||||
The core abstraction is the `MacroToolInput` — a structured output format that **forces the model to reflect before acting**.
|
||||
|
||||
## The Reflection-Before-Action Model
|
||||
|
||||
Every tool call must first output its reasoning state before the actual action:
|
||||
|
||||
```typescript
|
||||
interface MacroToolInput {
|
||||
// Reflection (mandatory before any action)
|
||||
evaluation_previous_goal?: string // How well did the previous action work?
|
||||
memory?: string // Key information to remember
|
||||
next_goal?: string // What to accomplish next
|
||||
|
||||
// Action (the actual operation)
|
||||
action: Record<string, any>
|
||||
}
|
||||
```
|
||||
|
||||
This design ensures that:
|
||||
|
||||
1. **The model evaluates its previous action** before deciding the next step
|
||||
2. **Working memory is explicitly maintained** across conversation turns
|
||||
3. **Goals are clearly stated**, making the agent's reasoning transparent and debuggable
|
||||
|
||||
## Key Components
|
||||
|
||||
| Export | Description |
|
||||
|--------|-------------|
|
||||
| `LLM` | Main LLM client class with retry logic |
|
||||
| `MacroToolInput` | The reflection-before-action input schema |
|
||||
| `AgentBrain` | Agent's thinking state (eval, memory, goal) |
|
||||
| `LLMConfig` | Configuration for LLM connection |
|
||||
| `parseLLMConfig` | Parse and apply defaults to config |
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@page-agent/llms",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"type": "module",
|
||||
"main": "./dist/lib/page-agent-llms.js",
|
||||
"module": "./dist/lib/page-agent-llms.js",
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// @workaround DTS bug
|
||||
// dts do not work with monorepo path mapping
|
||||
// disable path mapping for it
|
||||
"paths": {}
|
||||
}
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// @workaround DTS bug
|
||||
// dts do not work with monorepo path mapping
|
||||
// disable path mapping for it
|
||||
"paths": {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-11
@@ -1,13 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
||||
|
||||
@@ -34,4 +34,3 @@ export default defineConfig({
|
||||
'process.env.NODE_ENV': '"production"',
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "page-agent",
|
||||
"private": false,
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"type": "module",
|
||||
"main": "./dist/esm/page-agent.js",
|
||||
"module": "./dist/esm/page-agent.js",
|
||||
@@ -37,17 +37,16 @@
|
||||
},
|
||||
"homepage": "https://alibaba.github.io/page-agent/",
|
||||
"scripts": {
|
||||
"build": "vite build && vite build --config vite.umd.config.js",
|
||||
"serve": "npx serve dist/umd -p 5173",
|
||||
"dev:umd": "concurrently \"vite build --config vite.umd.config.js --watch\" \"npm run serve\"",
|
||||
"build": "vite build",
|
||||
"dev:iife": "concurrently \"vite build --config vite.iife.config.js --watch\" \"npx serve dist/iife -p 5174\"",
|
||||
"prepublishOnly": "node -e \"const fs=require('fs');['README.md','LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
||||
"postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^5.6.2",
|
||||
"zod": "^4.3.5",
|
||||
"@page-agent/llms": "0.2.0",
|
||||
"@page-agent/page-controller": "0.2.0",
|
||||
"@page-agent/ui": "0.2.0"
|
||||
"@page-agent/llms": "0.2.4",
|
||||
"@page-agent/page-controller": "0.2.4",
|
||||
"@page-agent/ui": "0.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { PageAgentConfig } from './config'
|
||||
import { MAX_STEPS } from './config/constants'
|
||||
import SYSTEM_PROMPT from './prompts/system_prompt.md?raw'
|
||||
import { tools } from './tools'
|
||||
import { normalizeResponse, trimLines, uid, waitUntil } from './utils'
|
||||
import { normalizeResponse, trimLines, uid } from './utils'
|
||||
import { assert } from './utils/assert'
|
||||
|
||||
/**
|
||||
@@ -90,9 +90,6 @@ export interface UserTakeoverEvent {
|
||||
*/
|
||||
export type HistoryEvent = AgentStep | ObservationEvent | UserTakeoverEvent
|
||||
|
||||
/** @deprecated Use AgentStep instead */
|
||||
export type AgentHistory = AgentStep
|
||||
|
||||
export interface ExecutionResult {
|
||||
success: boolean
|
||||
data: string
|
||||
@@ -104,7 +101,6 @@ export class PageAgent extends EventTarget {
|
||||
id = uid()
|
||||
panel: Panel
|
||||
tools: typeof tools
|
||||
paused = false
|
||||
disposed = false
|
||||
task = ''
|
||||
taskId = ''
|
||||
@@ -138,11 +134,6 @@ export class PageAgent extends EventTarget {
|
||||
language: this.config.language,
|
||||
onExecuteTask: (task) => this.execute(task),
|
||||
onStop: () => this.dispose(),
|
||||
onPauseToggle: () => {
|
||||
this.paused = !this.paused
|
||||
return this.paused
|
||||
},
|
||||
getPaused: () => this.paused,
|
||||
})
|
||||
this.tools = new Map(tools)
|
||||
|
||||
@@ -190,6 +181,7 @@ export class PageAgent extends EventTarget {
|
||||
*/
|
||||
pushObservation(content: string): void {
|
||||
this.history.push({ type: 'observation', content })
|
||||
this.panel.update({ type: 'observation', content })
|
||||
}
|
||||
|
||||
async execute(task: string): Promise<ExecutionResult> {
|
||||
@@ -237,8 +229,6 @@ export class PageAgent extends EventTarget {
|
||||
|
||||
// abort
|
||||
if (this.#abortController.signal.aborted) throw new Error('AbortError')
|
||||
// pause
|
||||
await waitUntil(() => !this.paused)
|
||||
|
||||
// Update status to thinking
|
||||
console.log(chalk.blue('Thinking...'))
|
||||
@@ -362,8 +352,6 @@ export class PageAgent extends EventTarget {
|
||||
execute: async (input: MacroToolInput): Promise<MacroToolResult> => {
|
||||
// abort
|
||||
if (this.#abortController.signal.aborted) throw new Error('AbortError')
|
||||
// pause
|
||||
await waitUntil(() => !this.paused)
|
||||
|
||||
console.log(chalk.blue.bold('MacroTool execute'), input)
|
||||
const action = input.action
|
||||
|
||||
@@ -108,14 +108,14 @@ export interface AgentConfig {
|
||||
* @note PageAgent will try to detect new pages and decide if it's caused by an action. But not very reliable.
|
||||
* @todo remove `this` binding, pass agent as explicit parameter instead
|
||||
*/
|
||||
onNewPageOpen?: (this: PageAgent, url: string) => Promise<void> | void
|
||||
// onNewPageOpen?: (this: PageAgent, url: string) => Promise<void> | void
|
||||
|
||||
/**
|
||||
* TODO: @unimplemented
|
||||
* try to navigate to a new page instead of opening a new tab/window.
|
||||
* @note will unload the current page when a action tries to open a new page. so that things keep in the same tab/window.
|
||||
*/
|
||||
experimentalPreventNewPage?: boolean
|
||||
// experimentalPreventNewPage?: boolean
|
||||
}
|
||||
|
||||
export type PageAgentConfig = LLMConfig & AgentConfig & PageControllerConfig
|
||||
|
||||
@@ -36,9 +36,13 @@ setTimeout(() => {
|
||||
} else {
|
||||
console.log('🚀 page-agent.js no current script detected, using default demo config')
|
||||
const config: PageAgentConfig = {
|
||||
model: DEMO_MODEL,
|
||||
baseURL: DEMO_BASE_URL,
|
||||
apiKey: DEMO_API_KEY,
|
||||
// model: DEMO_MODEL,
|
||||
// baseURL: DEMO_BASE_URL,
|
||||
// apiKey: DEMO_API_KEY,
|
||||
|
||||
model: import.meta.env.LLM_MODEL_NAME ? import.meta.env.LLM_MODEL_NAME : DEMO_MODEL,
|
||||
baseURL: import.meta.env.LLM_BASE_URL ? import.meta.env.LLM_BASE_URL : DEMO_BASE_URL,
|
||||
apiKey: import.meta.env.LLM_API_KEY ? import.meta.env.LLM_API_KEY : DEMO_API_KEY,
|
||||
}
|
||||
window.pageAgent = new PageAgent(config)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
system_prompt.md
|
||||
@@ -6,8 +6,6 @@ export interface PageAgentEventMap {
|
||||
// PageAgent status events
|
||||
// 'agent:execute': { params: { task: string } }
|
||||
// 'agent:done': { params: { text: string; success: boolean } }
|
||||
// 'agent:paused': { params: undefined }
|
||||
// 'agent:resumed': { params: undefined }
|
||||
// 'agent:disposed': { params: undefined }
|
||||
// 'agent:error': { params: { error: string | Error } }
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// @workaround DTS bug
|
||||
// dts do not work with monorepo path mapping
|
||||
// disable path mapping for it
|
||||
"paths": {}
|
||||
}
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// @workaround DTS bug
|
||||
// dts do not work with monorepo path mapping
|
||||
// disable path mapping for it
|
||||
"paths": {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
"paths": {
|
||||
//
|
||||
"@page-agent/llms": ["../llms/src/index.ts"],
|
||||
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
|
||||
"@page-agent/ui": ["../ui/src/index.ts"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["dist", "node_modules"],
|
||||
"references": [
|
||||
//
|
||||
{ "path": "../llms" },
|
||||
{ "path": "../page-controller" },
|
||||
{ "path": "../ui" }
|
||||
]
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
"paths": {
|
||||
//
|
||||
"@page-agent/llms": ["../llms/src/index.ts"],
|
||||
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
|
||||
"@page-agent/ui": ["../ui/src/index.ts"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["dist", "node_modules"],
|
||||
"references": [
|
||||
//
|
||||
{ "path": "../llms" },
|
||||
{ "path": "../page-controller" },
|
||||
{ "path": "../ui" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// @ts-check
|
||||
import { config as dotenvConfig } from 'dotenv'
|
||||
import { dirname, resolve } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { defineConfig } from 'vite'
|
||||
@@ -6,11 +7,14 @@ import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
// Load .env from repo root
|
||||
dotenvConfig({ path: resolve(__dirname, '../../.env') })
|
||||
|
||||
// UMD Bundle for CDN
|
||||
// - alias all local packages so that they can be build in
|
||||
// - no external
|
||||
// - no d.ts. dts does not work with monorepo aliasing
|
||||
export default defineConfig({
|
||||
export default defineConfig(({ mode }) => ({
|
||||
plugins: [cssInjectedByJsPlugin({ relativeCSSInjection: true })],
|
||||
publicDir: false,
|
||||
esbuild: {
|
||||
@@ -25,21 +29,28 @@ export default defineConfig({
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'src/umd.ts'),
|
||||
entry: resolve(__dirname, 'src/iife.ts'),
|
||||
name: 'PageAgent',
|
||||
fileName: 'page-agent',
|
||||
formats: ['umd'],
|
||||
formats: ['iife'],
|
||||
},
|
||||
outDir: resolve(__dirname, 'dist', 'umd'),
|
||||
outDir: resolve(__dirname, 'dist', 'iife'),
|
||||
cssCodeSplit: true,
|
||||
minify: false,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
// force use .js as extension
|
||||
entryFileNames: 'page-agent.js',
|
||||
},
|
||||
onwarn: function (message, handler) {
|
||||
if (message.code === 'EVAL') return
|
||||
handler(message)
|
||||
},
|
||||
},
|
||||
cssCodeSplit: true,
|
||||
},
|
||||
define: {
|
||||
'process.env.NODE_ENV': '"production"',
|
||||
'import.meta.env.LLM_MODEL_NAME': JSON.stringify(process.env.LLM_MODEL_NAME),
|
||||
'import.meta.env.LLM_API_KEY': JSON.stringify(process.env.LLM_API_KEY),
|
||||
'import.meta.env.LLM_BASE_URL': JSON.stringify(process.env.LLM_BASE_URL),
|
||||
},
|
||||
})
|
||||
}))
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@page-agent/page-controller",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"type": "module",
|
||||
"main": "./dist/lib/page-controller.js",
|
||||
"module": "./dist/lib/page-controller.js",
|
||||
|
||||
@@ -287,12 +287,52 @@ export async function scrollVertically(
|
||||
(document.documentElement as HTMLElement)
|
||||
|
||||
if (el === document.scrollingElement || el === document.documentElement || el === document.body) {
|
||||
// Page-level scroll
|
||||
const scrollBefore = window.scrollY
|
||||
const scrollMax = document.documentElement.scrollHeight - window.innerHeight
|
||||
|
||||
window.scrollBy(0, dy)
|
||||
return `✅ Scrolled page by ${dy}px.`
|
||||
|
||||
const scrollAfter = window.scrollY
|
||||
const scrolled = scrollAfter - scrollBefore
|
||||
|
||||
if (Math.abs(scrolled) < 1) {
|
||||
return dy > 0
|
||||
? `⚠️ Already at the bottom of the page, cannot scroll down further.`
|
||||
: `⚠️ Already at the top of the page, cannot scroll up further.`
|
||||
}
|
||||
|
||||
const reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1
|
||||
const reachedTop = dy < 0 && scrollAfter <= 1
|
||||
|
||||
if (reachedBottom) return `✅ Scrolled page by ${scrolled}px. Reached the bottom of the page.`
|
||||
if (reachedTop) return `✅ Scrolled page by ${scrolled}px. Reached the top of the page.`
|
||||
return `✅ Scrolled page by ${scrolled}px.`
|
||||
} else {
|
||||
// Container scroll
|
||||
const scrollBefore = el!.scrollTop
|
||||
const scrollMax = el!.scrollHeight - el!.clientHeight
|
||||
|
||||
el!.scrollBy({ top: dy, behavior: 'smooth' })
|
||||
await waitFor(0.1) // Animation playback
|
||||
return `✅ Scrolled container (${el!.tagName}) by ${dy}px.`
|
||||
await waitFor(0.1)
|
||||
|
||||
const scrollAfter = el!.scrollTop
|
||||
const scrolled = scrollAfter - scrollBefore
|
||||
|
||||
if (Math.abs(scrolled) < 1) {
|
||||
return dy > 0
|
||||
? `⚠️ Already at the bottom of container (${el!.tagName}), cannot scroll down further.`
|
||||
: `⚠️ Already at the top of container (${el!.tagName}), cannot scroll up further.`
|
||||
}
|
||||
|
||||
const reachedBottom = dy > 0 && scrollAfter >= scrollMax - 1
|
||||
const reachedTop = dy < 0 && scrollAfter <= 1
|
||||
|
||||
if (reachedBottom)
|
||||
return `✅ Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the bottom.`
|
||||
if (reachedTop)
|
||||
return `✅ Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the top.`
|
||||
return `✅ Scrolled container (${el!.tagName}) by ${scrolled}px.`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,11 +450,52 @@ export async function scrollHorizontally(
|
||||
(document.documentElement as HTMLElement)
|
||||
|
||||
if (el === document.scrollingElement || el === document.documentElement || el === document.body) {
|
||||
// Page-level scroll
|
||||
const scrollBefore = window.scrollX
|
||||
const scrollMax = document.documentElement.scrollWidth - window.innerWidth
|
||||
|
||||
window.scrollBy(dx, 0)
|
||||
return `✅ Scrolled page horizontally by ${dx}px`
|
||||
|
||||
const scrollAfter = window.scrollX
|
||||
const scrolled = scrollAfter - scrollBefore
|
||||
|
||||
if (Math.abs(scrolled) < 1) {
|
||||
return dx > 0
|
||||
? `⚠️ Already at the right edge of the page, cannot scroll right further.`
|
||||
: `⚠️ Already at the left edge of the page, cannot scroll left further.`
|
||||
}
|
||||
|
||||
const reachedRight = dx > 0 && scrollAfter >= scrollMax - 1
|
||||
const reachedLeft = dx < 0 && scrollAfter <= 1
|
||||
|
||||
if (reachedRight)
|
||||
return `✅ Scrolled page by ${scrolled}px. Reached the right edge of the page.`
|
||||
if (reachedLeft) return `✅ Scrolled page by ${scrolled}px. Reached the left edge of the page.`
|
||||
return `✅ Scrolled page horizontally by ${scrolled}px.`
|
||||
} else {
|
||||
// Container scroll
|
||||
const scrollBefore = el!.scrollLeft
|
||||
const scrollMax = el!.scrollWidth - el!.clientWidth
|
||||
|
||||
el!.scrollBy({ left: dx, behavior: 'smooth' })
|
||||
await waitFor(0.1) // Animation playback
|
||||
return `✅ Scrolled container (${el!.tagName}) horizontally by ${dx}px`
|
||||
await waitFor(0.1)
|
||||
|
||||
const scrollAfter = el!.scrollLeft
|
||||
const scrolled = scrollAfter - scrollBefore
|
||||
|
||||
if (Math.abs(scrolled) < 1) {
|
||||
return dx > 0
|
||||
? `⚠️ Already at the right edge of container (${el!.tagName}), cannot scroll right further.`
|
||||
: `⚠️ Already at the left edge of container (${el!.tagName}), cannot scroll left further.`
|
||||
}
|
||||
|
||||
const reachedRight = dx > 0 && scrollAfter >= scrollMax - 1
|
||||
const reachedLeft = dx < 0 && scrollAfter <= 1
|
||||
|
||||
if (reachedRight)
|
||||
return `✅ Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the right edge.`
|
||||
if (reachedLeft)
|
||||
return `✅ Scrolled container (${el!.tagName}) by ${scrolled}px. Reached the left edge.`
|
||||
return `✅ Scrolled container (${el!.tagName}) horizontally by ${scrolled}px.`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// @workaround DTS bug
|
||||
// dts do not work with monorepo path mapping
|
||||
// disable path mapping for it
|
||||
"paths": {}
|
||||
}
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// @workaround DTS bug
|
||||
// dts do not work with monorepo path mapping
|
||||
// disable path mapping for it
|
||||
"paths": {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.js"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.js"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ export default defineConfig({
|
||||
outDir: resolve(__dirname, 'dist', 'lib'),
|
||||
rollupOptions: {
|
||||
external: ['@page-agent/*', 'ai-motion'],
|
||||
onwarn: function (message, handler) {
|
||||
if (message.code === 'EVAL') return
|
||||
handler(message)
|
||||
},
|
||||
},
|
||||
minify: false,
|
||||
sourcemap: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@page-agent/ui",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"type": "module",
|
||||
"main": "./dist/lib/page-agent-ui.js",
|
||||
"module": "./dist/lib/page-agent-ui.js",
|
||||
|
||||
@@ -209,18 +209,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.pauseButton {
|
||||
font-weight: 600;
|
||||
&.paused {
|
||||
background: rgba(34, 197, 94, 0.2); /* 绿色背景表示可以继续 */
|
||||
color: rgb(34, 197, 94);
|
||||
|
||||
&:hover {
|
||||
background: rgba(34, 197, 94, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stopButton {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
color: rgb(255, 41, 41);
|
||||
@@ -364,6 +352,11 @@
|
||||
background: linear-gradient(135deg, rgba(255, 214, 0, 0.1), rgba(255, 214, 0, 0.05));
|
||||
}
|
||||
|
||||
&.observation {
|
||||
border-left-color: rgb(147, 51, 234);
|
||||
background: linear-gradient(135deg, rgba(147, 51, 234, 0.1), rgba(147, 51, 234, 0.05));
|
||||
}
|
||||
|
||||
/* 突出显示 done 成功结果 */
|
||||
&.doneSuccess {
|
||||
background: linear-gradient(
|
||||
|
||||
+10
-55
@@ -11,8 +11,6 @@ export interface PanelConfig {
|
||||
language?: SupportedLanguage
|
||||
onExecuteTask: (task: string) => void
|
||||
onStop: () => void
|
||||
onPauseToggle: () => boolean // returns new paused state
|
||||
getPaused: () => boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,6 +27,7 @@ export type PanelUpdate =
|
||||
| { type: 'completed' }
|
||||
| { type: 'toolExecuting'; toolName: string; args: any }
|
||||
| { type: 'toolCompleted'; toolName: string; args: any; result?: string; duration?: number }
|
||||
| { type: 'observation'; content: string }
|
||||
|
||||
/**
|
||||
* Agent control panel
|
||||
@@ -39,7 +38,6 @@ export class Panel {
|
||||
#statusText: HTMLElement
|
||||
#historySection: HTMLElement
|
||||
#expandButton: HTMLElement
|
||||
#pauseButton: HTMLElement
|
||||
#stopButton: HTMLElement
|
||||
#inputSection: HTMLElement
|
||||
#taskInput: HTMLInputElement
|
||||
@@ -66,7 +64,6 @@ export class Panel {
|
||||
this.#statusText = this.#wrapper.querySelector(`.${styles.statusText}`)!
|
||||
this.#historySection = this.#wrapper.querySelector(`.${styles.historySection}`)!
|
||||
this.#expandButton = this.#wrapper.querySelector(`.${styles.expandButton}`)!
|
||||
this.#pauseButton = this.#wrapper.querySelector(`.${styles.pauseButton}`)!
|
||||
this.#stopButton = this.#wrapper.querySelector(`.${styles.stopButton}`)!
|
||||
this.#inputSection = this.#wrapper.querySelector(`.${styles.inputSectionWrapper}`)!
|
||||
this.#taskInput = this.#wrapper.querySelector(`.${styles.taskInput}`)!
|
||||
@@ -75,6 +72,8 @@ export class Panel {
|
||||
this.#startHeaderUpdateLoop()
|
||||
|
||||
this.#showInputArea()
|
||||
|
||||
this.hide() // Start hidden
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,11 +119,6 @@ export class Panel {
|
||||
this.#updateStatusIndicator('thinking')
|
||||
this.#updateHistory()
|
||||
this.#collapse()
|
||||
// Reset pause state via callback
|
||||
if (this.#config.getPaused()) {
|
||||
this.#config.onPauseToggle()
|
||||
}
|
||||
this.#updatePauseButton()
|
||||
// Reset user input state
|
||||
this.#isWaitingForUserAnswer = false
|
||||
this.#userAnswerResolver = null
|
||||
@@ -205,6 +199,8 @@ export class Panel {
|
||||
duration: data.duration,
|
||||
}
|
||||
}
|
||||
case 'observation':
|
||||
return { type: 'observation', displayText: data.content }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,39 +273,6 @@ export class Panel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle pause state
|
||||
*/
|
||||
#togglePause(): void {
|
||||
const paused = this.#config.onPauseToggle()
|
||||
this.#updatePauseButton()
|
||||
|
||||
// Update status display
|
||||
if (paused) {
|
||||
this.#statusText.textContent = this.#i18n.t('ui.panel.paused')
|
||||
this.#updateStatusIndicator('thinking')
|
||||
} else {
|
||||
this.#statusText.textContent = this.#i18n.t('ui.panel.continueExecution')
|
||||
this.#updateStatusIndicator('tool_executing')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update pause button state
|
||||
*/
|
||||
#updatePauseButton(): void {
|
||||
const paused = this.#config.getPaused()
|
||||
if (paused) {
|
||||
this.#pauseButton.textContent = '▶'
|
||||
this.#pauseButton.title = this.#i18n.t('ui.panel.continue')
|
||||
this.#pauseButton.classList.add(styles.paused)
|
||||
} else {
|
||||
this.#pauseButton.textContent = '⏸︎'
|
||||
this.#pauseButton.title = this.#i18n.t('ui.panel.pause')
|
||||
this.#pauseButton.classList.remove(styles.paused)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop Agent
|
||||
*/
|
||||
@@ -401,7 +364,7 @@ export class Panel {
|
||||
#createWrapper(): HTMLElement {
|
||||
const wrapper = document.createElement('div')
|
||||
wrapper.id = 'page-agent-runtime_agent-panel'
|
||||
wrapper.className = `${styles.wrapper} ${styles.collapsed}`
|
||||
wrapper.className = styles.wrapper
|
||||
wrapper.setAttribute('data-browser-use-ignore', 'true')
|
||||
|
||||
wrapper.innerHTML = `
|
||||
@@ -426,9 +389,6 @@ export class Panel {
|
||||
<button class="${styles.controlButton} ${styles.expandButton}" title="${this.#i18n.t('ui.panel.expand')}">
|
||||
▼
|
||||
</button>
|
||||
<button class="${styles.controlButton} ${styles.pauseButton}" title="${this.#i18n.t('ui.panel.pause')}">
|
||||
⏸︎
|
||||
</button>
|
||||
<button class="${styles.controlButton} ${styles.stopButton}" title="${this.#i18n.t('ui.panel.stop')}">
|
||||
X
|
||||
</button>
|
||||
@@ -466,12 +426,6 @@ export class Panel {
|
||||
this.#toggle()
|
||||
})
|
||||
|
||||
// Pause/continue button
|
||||
this.#pauseButton.addEventListener('click', (e) => {
|
||||
e.stopPropagation()
|
||||
this.#togglePause()
|
||||
})
|
||||
|
||||
// Stop button
|
||||
this.#stopButton.addEventListener('click', (e) => {
|
||||
e.stopPropagation()
|
||||
@@ -503,7 +457,6 @@ export class Panel {
|
||||
|
||||
#expand(): void {
|
||||
this.#isExpanded = true
|
||||
this.wrapper.classList.remove(styles.collapsed)
|
||||
this.wrapper.classList.add(styles.expanded)
|
||||
this.#expandButton.textContent = '▲'
|
||||
}
|
||||
@@ -511,7 +464,6 @@ export class Panel {
|
||||
#collapse(): void {
|
||||
this.#isExpanded = false
|
||||
this.wrapper.classList.remove(styles.expanded)
|
||||
this.wrapper.classList.add(styles.collapsed)
|
||||
this.#expandButton.textContent = '▼'
|
||||
}
|
||||
|
||||
@@ -632,7 +584,7 @@ export class Panel {
|
||||
typeClass = styles.error
|
||||
statusIcon = '❌'
|
||||
} else if (step.type === 'tool_executing') {
|
||||
statusIcon = '⚙️'
|
||||
statusIcon = '🔨'
|
||||
} else if (step.type === 'output') {
|
||||
typeClass = styles.output
|
||||
statusIcon = '🤖'
|
||||
@@ -642,6 +594,9 @@ export class Panel {
|
||||
} else if (step.type === 'retry') {
|
||||
typeClass = styles.retry
|
||||
statusIcon = '🔄'
|
||||
} else if (step.type === 'observation') {
|
||||
typeClass = styles.observation
|
||||
statusIcon = '👁️'
|
||||
} else {
|
||||
statusIcon = '🧠'
|
||||
}
|
||||
|
||||
@@ -6,7 +6,15 @@ export interface Step {
|
||||
id: string
|
||||
stepNumber: number
|
||||
timestamp: Date
|
||||
type: 'thinking' | 'tool_executing' | 'completed' | 'error' | 'output' | 'input' | 'retry'
|
||||
type:
|
||||
| 'thinking'
|
||||
| 'tool_executing'
|
||||
| 'completed'
|
||||
| 'error'
|
||||
| 'output'
|
||||
| 'input'
|
||||
| 'retry'
|
||||
| 'observation'
|
||||
|
||||
// Tool execution related
|
||||
toolName?: string
|
||||
@@ -18,7 +26,7 @@ export interface Step {
|
||||
duration?: number
|
||||
}
|
||||
|
||||
export type AgentStatus = 'idle' | 'running' | 'paused' | 'completed' | 'error'
|
||||
export type AgentStatus = 'idle' | 'running' | 'completed' | 'error'
|
||||
|
||||
export class UIState {
|
||||
private steps: Step[] = []
|
||||
|
||||
@@ -4,17 +4,13 @@ const enUS = {
|
||||
panel: {
|
||||
ready: 'Ready',
|
||||
thinking: 'Thinking...',
|
||||
paused: 'Paused',
|
||||
taskInput: 'Enter new task, describe steps in detail, press Enter to submit',
|
||||
userAnswerPrompt: 'Please answer the question above, press Enter to submit',
|
||||
taskTerminated: 'Task terminated',
|
||||
taskCompleted: 'Task completed',
|
||||
continueExecution: 'Continue execution',
|
||||
userAnswer: 'User answer: {{input}}',
|
||||
question: 'Question: {{question}}',
|
||||
waitingPlaceholder: 'Waiting for task to start...',
|
||||
pause: 'Pause',
|
||||
continue: 'Continue',
|
||||
stop: 'Stop',
|
||||
expand: 'Expand history',
|
||||
collapse: 'Collapse history',
|
||||
@@ -54,17 +50,13 @@ const zhCN = {
|
||||
panel: {
|
||||
ready: '准备就绪',
|
||||
thinking: '正在思考...',
|
||||
paused: '暂停中,稍后',
|
||||
taskInput: '输入新任务,详细描述步骤,回车提交',
|
||||
userAnswerPrompt: '请回答上面问题,回车提交',
|
||||
taskTerminated: '任务已终止',
|
||||
taskCompleted: '任务结束',
|
||||
continueExecution: '继续执行',
|
||||
userAnswer: '用户回答: {{input}}',
|
||||
question: '询问: {{question}}',
|
||||
waitingPlaceholder: '等待任务开始...',
|
||||
pause: '暂停',
|
||||
continue: '继续',
|
||||
stop: '终止',
|
||||
expand: '展开历史',
|
||||
collapse: '收起历史',
|
||||
|
||||
@@ -2,4 +2,4 @@ This is the CSS implementation of ai-motion.
|
||||
|
||||
Easy to use but Terrible performance. Causing full screen glitching in some browsers.
|
||||
|
||||
Use it only in a small area.
|
||||
Use it only in a small area.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// @workaround DTS bug
|
||||
// dts do not work with monorepo path mapping
|
||||
// disable path mapping for it
|
||||
"paths": {}
|
||||
}
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// @workaround DTS bug
|
||||
// dts do not work with monorepo path mapping
|
||||
// disable path mapping for it
|
||||
"paths": {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-11
@@ -1,13 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.js"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.js"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# Landing Page & Docs
|
||||
@@ -1,24 +1,24 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"registries": {
|
||||
"@magicui": "https://magicui.design/r/{name}.json"
|
||||
}
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"registries": {
|
||||
"@magicui": "https://magicui.design/r/{name}.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@page-agent/website",
|
||||
"private": true,
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host 0.0.0.0",
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function Header() {
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
{/* Logo */}
|
||||
<Link
|
||||
href="/"
|
||||
href="~/"
|
||||
className="flex items-center gap-2 sm:gap-3 group shrink-0"
|
||||
aria-label={t('header.logo_alt')}
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
@@ -55,7 +55,7 @@ export default function Header() {
|
||||
aria-label="Mobile navigation"
|
||||
>
|
||||
<Link
|
||||
href="/docs/introduction/overview"
|
||||
href="~/docs/introduction/overview"
|
||||
className="p-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200 shrink-0"
|
||||
aria-label={t('header.nav_docs')}
|
||||
>
|
||||
@@ -89,7 +89,7 @@ export default function Header() {
|
||||
{import.meta.env.VERSION}
|
||||
</span>
|
||||
<Link
|
||||
href="/docs/introduction/overview"
|
||||
href="~/docs/introduction/overview"
|
||||
className="flex items-center gap-1.5 text-gray-600 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200"
|
||||
>
|
||||
<BookOpen className="w-4 h-4" />
|
||||
@@ -137,7 +137,7 @@ export default function Header() {
|
||||
role="navigation"
|
||||
>
|
||||
<Link
|
||||
href="/docs/introduction/overview"
|
||||
href="~/docs/introduction/overview"
|
||||
className="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
|
||||
@@ -28,9 +28,9 @@ pages/i18n/
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
function MyComponent() {
|
||||
const { t } = useTranslation('common') // 指定命名空间
|
||||
|
||||
return <h1>{t('header.nav_docs')}</h1>
|
||||
const { t } = useTranslation('common') // 指定命名空间
|
||||
|
||||
return <h1>{t('header.nav_docs')}</h1>
|
||||
}
|
||||
```
|
||||
|
||||
@@ -71,4 +71,3 @@ t('common:header.nav_docs')
|
||||
- [ ] 文档页翻译(`docs.json`)
|
||||
- [ ] DocsLayout 导航结构国际化
|
||||
- [ ] 404 页面国际化
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable react-dom/no-dangerously-set-innerhtml */
|
||||
import { Bot, Box, MessageSquare, PlayCircle, Shield, Sparkles, Users, Zap } from 'lucide-react'
|
||||
import { PageAgent } from 'page-agent'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Link, useSearchParams } from 'wouter'
|
||||
@@ -59,13 +58,12 @@ export default function HomePage() {
|
||||
const handleExecute = async () => {
|
||||
if (!task.trim()) return
|
||||
|
||||
let pageAgent: PageAgent
|
||||
const win = window as any
|
||||
|
||||
if (win.pageAgent && !win.pageAgent.disposed) {
|
||||
pageAgent = win.pageAgent
|
||||
} else {
|
||||
pageAgent = new PageAgent({
|
||||
// Lazy load PageAgent only when user clicks execute
|
||||
if (!win.pageAgent || win.pageAgent.disposed) {
|
||||
const { PageAgent } = await import('page-agent')
|
||||
win.pageAgent = new PageAgent({
|
||||
// 把 react 根元素排除掉,挂了很多冒泡时间导致假阳
|
||||
interactiveBlacklist: [document.getElementById('root')!],
|
||||
language: i18n.language as any,
|
||||
@@ -92,11 +90,9 @@ export default function HomePage() {
|
||||
? import.meta.env.LLM_API_KEY
|
||||
: DEMO_API_KEY,
|
||||
})
|
||||
win.pageAgent = pageAgent
|
||||
}
|
||||
|
||||
const result = await pageAgent.execute(task)
|
||||
|
||||
const result = await win.pageAgent.execute(task)
|
||||
console.log(result)
|
||||
}
|
||||
|
||||
@@ -107,7 +103,7 @@ export default function HomePage() {
|
||||
{/* Hero Section */}
|
||||
<main id="main-content">
|
||||
<section
|
||||
className="relative px-6 py-22 lg:py-28 overflow-hidden"
|
||||
className="relative px-6 py-22 pb-18 lg:py-28 overflow-hidden"
|
||||
aria-labelledby="hero-heading"
|
||||
>
|
||||
<div className="max-w-7xl mx-auto text-center">
|
||||
|
||||
@@ -24,38 +24,38 @@ export default function DocsLayout({ children }: DocsLayoutProps) {
|
||||
{
|
||||
title: t('nav.introduction'),
|
||||
items: [
|
||||
{ title: t('nav.overview'), path: '/docs/introduction/overview' },
|
||||
{ title: t('nav.quick_start'), path: '/docs/introduction/quick-start' },
|
||||
{ title: t('nav.limitations'), path: '/docs/introduction/limitations' },
|
||||
{ title: t('nav.overview'), path: '/introduction/overview' },
|
||||
{ title: t('nav.quick_start'), path: '/introduction/quick-start' },
|
||||
{ title: t('nav.limitations'), path: '/introduction/limitations' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('nav.features'),
|
||||
items: [
|
||||
{ title: t('nav.models'), path: '/docs/features/models' },
|
||||
{ title: t('nav.custom_tools'), path: '/docs/features/custom-tools' },
|
||||
{ title: t('nav.knowledge_injection'), path: '/docs/features/custom-instructions' },
|
||||
{ title: t('nav.data_masking'), path: '/docs/features/data-masking' },
|
||||
{ title: t('nav.models'), path: '/features/models' },
|
||||
{ title: t('nav.custom_tools'), path: '/features/custom-tools' },
|
||||
{ title: t('nav.knowledge_injection'), path: '/features/custom-instructions' },
|
||||
{ title: t('nav.data_masking'), path: '/features/data-masking' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('nav.integration'),
|
||||
items: [
|
||||
{ title: t('nav.configuration'), path: '/docs/integration/configuration' },
|
||||
{ title: t('nav.third_party_agent'), path: '/docs/integration/third-party-agent' },
|
||||
{ title: t('nav.cdn_setup'), path: '/docs/integration/cdn-setup' },
|
||||
{ title: t('nav.configuration'), path: '/integration/configuration' },
|
||||
{ title: t('nav.third_party_agent'), path: '/integration/third-party-agent' },
|
||||
{ title: t('nav.cdn_setup'), path: '/integration/cdn-setup' },
|
||||
{
|
||||
title: '🚧 ' + t('nav.security_permissions'),
|
||||
path: '/docs/integration/security-permissions',
|
||||
path: '/integration/security-permissions',
|
||||
},
|
||||
{ title: '🚧 ' + t('nav.best_practices'), path: '/docs/integration/best-practices' },
|
||||
{ title: '🚧 ' + t('nav.best_practices'), path: '/integration/best-practices' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto px-6 py-8 overflow-x-auto">
|
||||
<div className="flex gap-8 min-w-[900px]">
|
||||
<div className="flex gap-8 min-w-225">
|
||||
{/* Sidebar */}
|
||||
<aside className="w-64 shrink-0" role="complementary" aria-label="文档导航">
|
||||
<div className="sticky">
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import { Suspense } from 'react'
|
||||
import { Route, Switch } from 'wouter'
|
||||
|
||||
import Header from '../../components/Header'
|
||||
import DocsLayout from './Layout'
|
||||
import Instructions from './features/custom-instructions/page'
|
||||
// Features
|
||||
import CustomTools from './features/custom-tools/page'
|
||||
import DataMasking from './features/data-masking/page'
|
||||
import Models from './features/models/page'
|
||||
import BestPractices from './integration/best-practices/page'
|
||||
// Integration
|
||||
import CdnSetup from './integration/cdn-setup/page'
|
||||
import Configuration from './integration/configuration/page'
|
||||
import SecurityPermissions from './integration/security-permissions/page'
|
||||
import ThirdPartyAgent from './integration/third-party-agent/page'
|
||||
import Limitations from './introduction/limitations/page'
|
||||
// Introduction
|
||||
import Overview from './introduction/overview/page'
|
||||
import QuickStart from './introduction/quick-start/page'
|
||||
|
||||
function DocsPage({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<Suspense>{children}</Suspense>
|
||||
</DocsLayout>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function DocsRouter() {
|
||||
return (
|
||||
<Switch>
|
||||
{/* Introduction */}
|
||||
<Route path="/introduction/overview">
|
||||
<DocsPage>
|
||||
<Overview />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/introduction/quick-start">
|
||||
<DocsPage>
|
||||
<QuickStart />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/introduction/limitations">
|
||||
<DocsPage>
|
||||
<Limitations />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
|
||||
{/* Features */}
|
||||
<Route path="/features/custom-tools">
|
||||
<DocsPage>
|
||||
<CustomTools />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/features/data-masking">
|
||||
<DocsPage>
|
||||
<DataMasking />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/features/custom-instructions">
|
||||
<DocsPage>
|
||||
<Instructions />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/features/models">
|
||||
<DocsPage>
|
||||
<Models />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
|
||||
{/* Integration */}
|
||||
<Route path="/integration/cdn-setup">
|
||||
<DocsPage>
|
||||
<CdnSetup />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/integration/security-permissions">
|
||||
<DocsPage>
|
||||
<SecurityPermissions />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/integration/configuration">
|
||||
<DocsPage>
|
||||
<Configuration />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/integration/best-practices">
|
||||
<DocsPage>
|
||||
<BestPractices />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
<Route path="/integration/third-party-agent">
|
||||
<DocsPage>
|
||||
<ThirdPartyAgent />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
|
||||
{/* Default redirect or 404 */}
|
||||
<Route path="/docs">
|
||||
<DocsPage>
|
||||
<Overview />
|
||||
</DocsPage>
|
||||
</Route>
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
@@ -28,15 +28,17 @@ export default function Configuration() {
|
||||
className="mb-4"
|
||||
language="typescript"
|
||||
code={`interface LLMConfig {
|
||||
baseURL?: string
|
||||
apiKey?: string
|
||||
model?: string
|
||||
baseURL: string
|
||||
apiKey: string
|
||||
model: string
|
||||
|
||||
temperature?: number
|
||||
maxRetries?: number
|
||||
|
||||
/**
|
||||
* Custom fetch function for LLM API requests.
|
||||
* Use this to customize headers, credentials, proxy, etc.
|
||||
* The response should follow OpenAI API format.
|
||||
*/
|
||||
customFetch?: typeof globalThis.fetch
|
||||
}`}
|
||||
@@ -71,12 +73,12 @@ export default function Configuration() {
|
||||
getPageInstructions?: (url: string) => string | undefined | null
|
||||
}
|
||||
|
||||
// Lifecycle hooks
|
||||
onBeforeStep?: (stepCnt: number) => Promise<void> | void
|
||||
onAfterStep?: (stepCnt: number, history: AgentHistory[]) => Promise<void> | void
|
||||
onBeforeTask?: () => Promise<void> | void
|
||||
onAfterTask?: (result: ExecutionResult) => Promise<void> | void
|
||||
onDispose?: (reason?: string) => void
|
||||
// Lifecycle hooks (with \`this\` bound to PageAgent instance)
|
||||
onBeforeStep?: (this: PageAgent, stepCnt: number) => Promise<void> | void
|
||||
onAfterStep?: (this: PageAgent, stepCnt: number, history: HistoryEvent[]) => Promise<void> | void
|
||||
onBeforeTask?: (this: PageAgent) => Promise<void> | void
|
||||
onAfterTask?: (this: PageAgent, result: ExecutionResult) => Promise<void> | void
|
||||
onDispose?: (this: PageAgent, reason?: string) => void
|
||||
|
||||
/**
|
||||
* Transform page content before sending to LLM.
|
||||
@@ -103,7 +105,7 @@ export default function Configuration() {
|
||||
<CodeEditor
|
||||
className="mb-4"
|
||||
language="typescript"
|
||||
code={`interface PageControllerConfig {
|
||||
code={`interface DomConfig {
|
||||
/** Elements to exclude from interaction */
|
||||
interactiveBlacklist?: (Element | (() => Element))[]
|
||||
|
||||
@@ -118,15 +120,13 @@ export default function Configuration() {
|
||||
|
||||
/** Highlight label opacity (0-1) */
|
||||
highlightLabelOpacity?: number
|
||||
}
|
||||
|
||||
/** Viewport expansion in pixels (-1 for full page) */
|
||||
interface PageControllerConfig extends DomConfig {
|
||||
/** Viewport expansion in pixels */
|
||||
viewportExpansion?: number
|
||||
|
||||
/**
|
||||
* Enable visual mask overlay during automation.
|
||||
* Blocks user interaction while agent is running.
|
||||
* Default: false for PageController, true for PageAgent.
|
||||
*/
|
||||
/** Enable visual mask overlay during operations (default: false) */
|
||||
enableMask?: boolean
|
||||
}`}
|
||||
/>
|
||||
|
||||
@@ -22,13 +22,6 @@ export default function Overview() {
|
||||
|
||||
{/* Status Badges */}
|
||||
<div className="flex flex-wrap gap-2 items-center">
|
||||
<a
|
||||
href="https://www.npmjs.com/package/page-agent"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<img src="https://badge.fury.io/js/page-agent.svg" alt="npm version" />
|
||||
</a>
|
||||
<a href="https://opensource.org/licenses/MIT" target="_blank" rel="noopener noreferrer">
|
||||
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="MIT License" />
|
||||
</a>
|
||||
|
||||
+24
-138
@@ -1,148 +1,34 @@
|
||||
import { Suspense, lazy } from 'react'
|
||||
import { Route, Switch } from 'wouter'
|
||||
|
||||
import Header from './components/Header'
|
||||
import HomePage from './pages/Home'
|
||||
import DocsLayout from './pages/docs/Layout'
|
||||
// Features pages
|
||||
import Instructions from './pages/docs/features/custom-instructions/page'
|
||||
import CustomTools from './pages/docs/features/custom-tools/page'
|
||||
import DataMasking from './pages/docs/features/data-masking/page'
|
||||
import Models from './pages/docs/features/models/page'
|
||||
// Integration pages
|
||||
import BestPractices from './pages/docs/integration/best-practices/page'
|
||||
import CdnSetup from './pages/docs/integration/cdn-setup/page'
|
||||
import Configuration from './pages/docs/integration/configuration/page'
|
||||
import SecurityPermissions from './pages/docs/integration/security-permissions/page'
|
||||
import ThirdPartyAgent from './pages/docs/integration/third-party-agent/page'
|
||||
// Introduction pages
|
||||
import Limitations from './pages/docs/introduction/limitations/page'
|
||||
import Overview from './pages/docs/introduction/overview/page'
|
||||
import QuickStart from './pages/docs/introduction/quick-start/page'
|
||||
// Lazy load pages
|
||||
const HomePage = lazy(() => import('./pages/Home'))
|
||||
const DocsPages = lazy(() => import('./pages/docs/index'))
|
||||
|
||||
export default function Router() {
|
||||
return (
|
||||
<Switch>
|
||||
{/* Home page */}
|
||||
<Route path="/" component={HomePage} />
|
||||
<Suspense>
|
||||
<Switch>
|
||||
{/* Home page */}
|
||||
<Route path="/">
|
||||
<HomePage />
|
||||
</Route>
|
||||
|
||||
{/* Documentation pages with layout */}
|
||||
<Route path="/docs/introduction/overview">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<Overview />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
{/* All docs pages */}
|
||||
<Route path="/docs" nest>
|
||||
<DocsPages />
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/introduction/quick-start">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<QuickStart />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/introduction/limitations">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<Limitations />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/features/custom-tools">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<CustomTools />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/features/data-masking">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<DataMasking />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/features/custom-instructions">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<Instructions />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/features/models">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<Models />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/integration/cdn-setup">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<CdnSetup />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/integration/security-permissions">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<SecurityPermissions />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/integration/configuration">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<Configuration />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/integration/best-practices">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<BestPractices />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route path="/docs/integration/third-party-agent">
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||
<Header />
|
||||
<DocsLayout>
|
||||
<ThirdPartyAgent />
|
||||
</DocsLayout>
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
{/* 404 page */}
|
||||
<Route>
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<h1 className="text-4xl font-bold mb-4 text-gray-900 dark:text-white">404</h1>
|
||||
<p className="text-xl text-gray-600 dark:text-gray-300">页面未找到</p>
|
||||
{/* 404 */}
|
||||
<Route>
|
||||
<div className="min-h-screen bg-white dark:bg-gray-900 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<h1 className="text-4xl font-bold mb-4 text-gray-900 dark:text-white">404</h1>
|
||||
<p className="text-xl text-gray-600 dark:text-gray-300">页面未找到</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Route>
|
||||
</Switch>
|
||||
</Route>
|
||||
</Switch>
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
"paths": {
|
||||
// Self root
|
||||
"@/*": ["src/*"],
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
"paths": {
|
||||
// Self root
|
||||
"@/*": ["src/*"],
|
||||
|
||||
// Simplified monorepo solution (raw npm workspace with hoisting)
|
||||
"page-agent": ["../page-agent/src/PageAgent.ts"],
|
||||
"@page-agent/llms": ["../llms/src/index.ts"],
|
||||
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
|
||||
"@page-agent/ui": ["../ui/src/index.ts"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["dist", "node_modules"],
|
||||
"references": [
|
||||
//
|
||||
{ "path": "../llms" },
|
||||
{ "path": "../page-agent" },
|
||||
{ "path": "../page-controller" },
|
||||
{ "path": "../ui" }
|
||||
]
|
||||
// Simplified monorepo solution (raw npm workspace with hoisting)
|
||||
"page-agent": ["../page-agent/src/PageAgent.ts"],
|
||||
"@page-agent/llms": ["../llms/src/index.ts"],
|
||||
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
|
||||
"@page-agent/ui": ["../ui/src/index.ts"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["dist", "node_modules"],
|
||||
"references": [
|
||||
//
|
||||
{ "path": "../llms" },
|
||||
{ "path": "../page-agent" },
|
||||
{ "path": "../page-controller" },
|
||||
{ "path": "../ui" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -16,10 +16,20 @@ const pageAgentPkg = JSON.parse(
|
||||
dotenvConfig({ path: resolve(__dirname, '../../.env') })
|
||||
|
||||
// Website Config (React Documentation Site)
|
||||
export default defineConfig({
|
||||
export default defineConfig(({ mode }) => ({
|
||||
base: './',
|
||||
clearScreen: false,
|
||||
plugins: [react(), tailwindcss()],
|
||||
build: {
|
||||
chunkSizeWarningLimit: 2000,
|
||||
cssCodeSplit: true,
|
||||
rollupOptions: {
|
||||
onwarn: function (message, handler) {
|
||||
if (message.code === 'EVAL') return
|
||||
handler(message)
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
// Self root
|
||||
@@ -33,9 +43,11 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
define: {
|
||||
'import.meta.env.LLM_MODEL_NAME': JSON.stringify(process.env.LLM_MODEL_NAME),
|
||||
'import.meta.env.LLM_API_KEY': JSON.stringify(process.env.LLM_API_KEY),
|
||||
'import.meta.env.LLM_BASE_URL': JSON.stringify(process.env.LLM_BASE_URL),
|
||||
...(mode === 'development' && {
|
||||
'import.meta.env.LLM_MODEL_NAME': JSON.stringify(process.env.LLM_MODEL_NAME),
|
||||
'import.meta.env.LLM_API_KEY': JSON.stringify(process.env.LLM_API_KEY),
|
||||
'import.meta.env.LLM_BASE_URL': JSON.stringify(process.env.LLM_BASE_URL),
|
||||
}),
|
||||
'import.meta.env.VERSION': JSON.stringify(pageAgentPkg.version),
|
||||
},
|
||||
})
|
||||
}))
|
||||
|
||||
+41
-41
@@ -1,47 +1,47 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "ES2024",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2024", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "ES2024",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2024", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
|
||||
// "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
// "baseUrl": "src",
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
// "incremental": true,
|
||||
// "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
|
||||
// "baseUrl": "src",
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
// "incremental": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"verbatimModuleSyntax": false,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"allowImportingTsExtensions": true,
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"verbatimModuleSyntax": false,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"allowImportingTsExtensions": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
|
||||
// "paths": {
|
||||
// // Simplified monorepo solution (raw npm workspace with hoisting)
|
||||
// "@page-agent/page-controller": ["./packages/page-controller/src/PageController.ts"],
|
||||
// "page-agent": ["./packages/page-agent/src/PageAgent.ts"]
|
||||
// }
|
||||
}
|
||||
// "references": [
|
||||
// { "path": "./packages/page-controller" },
|
||||
// { "path": "./packages/page-agent" },
|
||||
// { "path": "./packages/website" }
|
||||
// ],
|
||||
// "include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"],
|
||||
// "exclude": ["node_modules", "dist", "packages/*/dist"]
|
||||
// "files": ["env.d.ts"]
|
||||
// "files": []
|
||||
// "paths": {
|
||||
// // Simplified monorepo solution (raw npm workspace with hoisting)
|
||||
// "@page-agent/page-controller": ["./packages/page-controller/src/PageController.ts"],
|
||||
// "page-agent": ["./packages/page-agent/src/PageAgent.ts"]
|
||||
// }
|
||||
}
|
||||
// "references": [
|
||||
// { "path": "./packages/page-controller" },
|
||||
// { "path": "./packages/page-agent" },
|
||||
// { "path": "./packages/website" }
|
||||
// ],
|
||||
// "include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"],
|
||||
// "exclude": ["node_modules", "dist", "packages/*/dist"]
|
||||
// "files": ["env.d.ts"]
|
||||
// "files": []
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"extends": "./tsconfig.base.json",
|
||||
"references": [
|
||||
{ "path": "./packages/page-controller" },
|
||||
{ "path": "./packages/ui" },
|
||||
{ "path": "./packages/llms" },
|
||||
{ "path": "./packages/page-agent" },
|
||||
{ "path": "./packages/website" }
|
||||
],
|
||||
"include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "dist", "packages/*/dist"]
|
||||
"extends": "./tsconfig.base.json",
|
||||
"references": [
|
||||
{ "path": "./packages/page-controller" },
|
||||
{ "path": "./packages/ui" },
|
||||
{ "path": "./packages/llms" },
|
||||
{ "path": "./packages/page-agent" },
|
||||
{ "path": "./packages/website" }
|
||||
],
|
||||
"include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "dist", "packages/*/dist"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user