Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15d609aebc | |||
| d66bf8f3cf | |||
| d3b42036af | |||
| e448a43769 | |||
| 349de7bf48 | |||
| eec601e6b2 | |||
| 5b280a4a67 | |||
| 46deaf373f | |||
| e098d5701f | |||
| 21d4be0020 | |||
| 3f6a1856ac | |||
| 816e24a102 | |||
| 80e2a93a8c | |||
| 2f8096883f | |||
| 088f002583 | |||
| 27e9e78636 | |||
| a0c979602e | |||
| 3dc9edb8b5 | |||
| 32b68ab7c8 | |||
| 75a61c05c1 | |||
| bdfa98358b | |||
| dc8b38ccb9 | |||
| e1c288aaeb | |||
| 7a97de2a37 | |||
| 19b03b83ea |
+27
-22
@@ -1,6 +1,6 @@
|
|||||||
# Contributing to Page-Agent
|
# Contributing to PageAgent
|
||||||
|
|
||||||
Thank you for your interest in contributing to Page-Agent! We welcome contributions from everyone.
|
Thank you for your interest in contributing to PageAgent! We welcome contributions from everyone.
|
||||||
|
|
||||||
## 🚀 Quick Start
|
## 🚀 Quick Start
|
||||||
|
|
||||||
@@ -27,11 +27,11 @@ This is a **monorepo** with npm workspaces containing **4 main packages**:
|
|||||||
- **Extension** (`packages/extension/`) - Chrome extension for multi-page tasks and browser-level automation
|
- **Extension** (`packages/extension/`) - Chrome extension for multi-page tasks and browser-level automation
|
||||||
- **Website** (`packages/website/`) - React documentation and landing page. Also as demo and test page for the core lib. private package `@page-agent/website`
|
- **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 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. Use external and disable ts `paths` alias to leave deps out.
|
||||||
- When bundling `IIFE` and `Website`. Bundle everything including local packages.
|
> - When bundling `IIFE` and `Website`. Bundle everything including local packages.
|
||||||
|
|
||||||
## 🤝 How to Contribute
|
## 🤝 How to Contribute
|
||||||
|
|
||||||
@@ -90,14 +90,17 @@ We use a simplified monorepo solution with `native npm-workspace + ts reference
|
|||||||
- Keep functions small and focused
|
- Keep functions small and focused
|
||||||
- Add JSDoc for public APIs
|
- Add JSDoc for public APIs
|
||||||
|
|
||||||
### Vibe coding with AI
|
### Vibe Coding with AI
|
||||||
|
|
||||||
- It's **recommended** to heavily rely on AI (aka "vibe coding") when maintaining **demo pages and tests**.
|
> [Vibe coding](https://en.wikipedia.org/wiki/Vibe_coding) = describe what you want in natural language, let AI write the code, and you review the result.
|
||||||
- Be very careful if AI ever touched the core lib!!!
|
|
||||||
|
- Vibe coding is **RECOMMENDED** when maintaining **the demo, the website, the UI and tests**.
|
||||||
|
- We have a [website/AGENTS.md](packages/website/AGENTS.md) for that.
|
||||||
|
- Vibe coding is **NOT** allowed for the core lib!!!
|
||||||
|
- NEVER try to vibe coding the MV3 extension!!! It is HELL.
|
||||||
- Review anything AI wrote before make a commit. You are the author of anything you commit. NOT AI.
|
- Review anything AI wrote before make a commit. You are the author of anything you commit. NOT AI.
|
||||||
- Update the [AI instructions](AGENTS.md) when structure changed.
|
|
||||||
|
|
||||||
If your lame AI assistant does not support [AGENTS.md](https://agents.md/). Add an alias for it:
|
If your AI assistant does not support [AGENTS.md](https://agents.md/). Add an alias for it:
|
||||||
|
|
||||||
- claude-code (`CLAUDE.md`)
|
- claude-code (`CLAUDE.md`)
|
||||||
|
|
||||||
@@ -135,10 +138,10 @@ If your lame AI assistant does not support [AGENTS.md](https://agents.md/). Add
|
|||||||
LLM_MODEL_NAME="qwen3:14b"
|
LLM_MODEL_NAME="qwen3:14b"
|
||||||
```
|
```
|
||||||
|
|
||||||
> ⚠️ Add `*` to `OLLAMA_ORIGINS` (403). Models < 10B unlikely strong enough. Requires tool_call support. Set context length > 15k (default 4k will NOT work): `$env:OLLAMA_CONTEXT_LENGTH=64000; ollama serve`
|
> @see https://alibaba.github.io/page-agent/docs/features/models#ollama for configuration
|
||||||
|
|
||||||
- Restart the dev server to load new env vars
|
- **Restart the dev server** to load new env vars
|
||||||
- If not provided, the demo will the free testing proxy by default
|
- If not provided, the demo will use the free testing proxy by default. By using it, you agree to its [terms](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md).
|
||||||
|
|
||||||
### Website Development
|
### Website Development
|
||||||
|
|
||||||
@@ -149,12 +152,13 @@ npm start
|
|||||||
### Extension Development
|
### Extension Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# make sure you ran `npm run build:libs` first
|
||||||
|
# and every time you changed the core libs
|
||||||
npm run dev -w @page-agent/ext
|
npm run dev -w @page-agent/ext
|
||||||
npm run zip -w @page-agent/ext
|
npm run zip -w @page-agent/ext
|
||||||
```
|
```
|
||||||
|
|
||||||
- Load extension in Chrome via `chrome://extensions` -> **Load unpacked**
|
- Update `packages/extension/docs/extension_api.md` for API integration details
|
||||||
- Use `packages/extension/docs/extension_api.md` (EN) or `packages/extension/docs/extension_api_zh.md` (ZH) for API integration details
|
|
||||||
|
|
||||||
### Testing on Other Websites
|
### Testing on Other Websites
|
||||||
|
|
||||||
@@ -172,7 +176,7 @@ npm run zip -w @page-agent/ext
|
|||||||
|
|
||||||
- Click the bookmark on any page to load Page-Agent
|
- Click the bookmark on any page to load Page-Agent
|
||||||
|
|
||||||
> Warning: AK in your local `.env` will be inlined in the iife script.
|
> Warning: AK in your local `.env` will be inlined in the iife script. Be very careful when you distribute the script.
|
||||||
|
|
||||||
### Adding Documentation
|
### Adding Documentation
|
||||||
|
|
||||||
@@ -193,16 +197,17 @@ We especially welcome contributions in:
|
|||||||
|
|
||||||
## 🚫 What We Don't Accept
|
## 🚫 What We Don't Accept
|
||||||
|
|
||||||
- Changes that break existing API compatibility (Discuss first)
|
- Breaking changes and large PRs without prior discussion
|
||||||
- Heavy dependencies to core library
|
- Heavy dependencies to core libs
|
||||||
- Contributions without proper testing
|
- Contributions without proper testing
|
||||||
- Code that doesn't follow project conventions
|
- Code that doesn't follow project conventions
|
||||||
|
- Dependencies or code with licenses incompatible with MIT
|
||||||
|
|
||||||
## 📄 Legal
|
## 📄 Legal
|
||||||
|
|
||||||
By contributing to this project, you agree that your contributions will be licensed under the MIT License.
|
By contributing to this project, you agree that your contributions will be licensed under the MIT License.
|
||||||
|
|
||||||
> You may need to sign a github CLA before you create a PR.
|
> You need to sign a github CLA when you create a PR.
|
||||||
|
|
||||||
## 💬 Questions?
|
## 💬 Questions?
|
||||||
|
|
||||||
@@ -210,4 +215,4 @@ By contributing to this project, you agree that your contributions will be licen
|
|||||||
- Check existing documentation and issues first
|
- Check existing documentation and issues first
|
||||||
- Be respectful and constructive in discussions
|
- Be respectful and constructive in discussions
|
||||||
|
|
||||||
Thank you for helping make Page-Agent better! 🎉
|
Thank you for helping make PageAgent better! 🎉
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua
|
|||||||
|
|
||||||
🌐 **English** | [中文](./docs/README-zh.md)
|
🌐 **English** | [中文](./docs/README-zh.md)
|
||||||
|
|
||||||
👉 <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>
|
👉 <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> | <a href="https://news.ycombinator.com/item?id=47264138" target="_blank">📢 Join HN Discussion</a>
|
||||||
|
|
||||||
<video id="demo-video" src="https://github.com/user-attachments/assets/11aed429-b69c-49d5-8982-fa99b4a0e9a8" controls crossorigin muted></video>
|
<video id="demo-video" src="https://github.com/user-attachments/assets/a1f2eae2-13fb-4aae-98cf-a3fc1620a6c2" controls crossorigin muted></video>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -49,8 +49,8 @@ Fastest way to try PageAgent with our free Demo LLM:
|
|||||||
|
|
||||||
| Mirrors | URL |
|
| Mirrors | URL |
|
||||||
| ------- | ---------------------------------------------------------------------------------- |
|
| ------- | ---------------------------------------------------------------------------------- |
|
||||||
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.4.4/dist/iife/page-agent.demo.js |
|
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.5.3/dist/iife/page-agent.demo.js |
|
||||||
| China | https://registry.npmmirror.com/page-agent/1.4.4/files/dist/iife/page-agent.demo.js |
|
| China | https://registry.npmmirror.com/page-agent/1.5.3/files/dist/iife/page-agent.demo.js |
|
||||||
|
|
||||||
> **⚠️ For technical evaluation only.** This demo CDN uses our free [testing LLM API](https://alibaba.github.io/page-agent/docs/features/models#free-testing-api). By using it, you agree to its [terms](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md).
|
> **⚠️ For technical evaluation only.** This demo CDN uses our free [testing LLM API](https://alibaba.github.io/page-agent/docs/features/models#free-testing-api). By using it, you agree to its [terms](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md).
|
||||||
|
|
||||||
@@ -111,3 +111,11 @@ file and in the node_modules directory after installation.
|
|||||||
---
|
---
|
||||||
|
|
||||||
**⭐ Star this repo if you find PageAgent helpful!**
|
**⭐ Star this repo if you find PageAgent helpful!**
|
||||||
|
|
||||||
|
<a href="https://www.star-history.com/?repos=alibaba%2Fpage-agent&type=date">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&theme=dark" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date" />
|
||||||
|
<img alt="Star History Chart" src="https://api.star-history.com/image?repos=alibaba/page-agent&type=date" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
|||||||
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.5.1] - 2026-03-05
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- **`data-browser-use-ignore` → `data-page-agent-ignore`** - DOM ignore attribute renamed to match the project identity
|
||||||
|
- **Config types restructured** - `PageAgentConfig` split into `AgentConfig` + `PageAgentCoreConfig`; config definitions moved from `config/index.ts` to `types.ts`
|
||||||
|
- **Zod v3/v4 dual support** - Libraries now accept both `zod@^3.25` and `zod@^4.0` as peer dependencies
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- **Experimental `llms.txt` support** - Agent can fetch and include a site's `llms.txt` in context. Enable via `experimentalLlmsTxt: true`
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
- Default `maxSteps` changed from 20 to 40 for better for complex tasks out of the box
|
||||||
|
- Added 400ms wait between agent steps for page reactions
|
||||||
|
- Increased click wait time (100ms → 200ms) for more reliable interactions
|
||||||
|
- Removed debug `console.log` statements from scroll actions
|
||||||
|
- Reset observations on new task start
|
||||||
|
- Improved logging across packages
|
||||||
|
|
||||||
|
### Extension v0.1.9
|
||||||
|
|
||||||
|
> PageAgent 1.5.1
|
||||||
|
|
||||||
|
- **Advanced config panel** - New collapsible section exposing Max Steps, System Instruction, and experimental `llms.txt` toggle
|
||||||
|
- Streamlined User Auth Token description
|
||||||
|
- Moved testing API notice below auth token section
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [1.4.0] - 2026-02-27
|
## [1.4.0] - 2026-02-27
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
+3
-3
@@ -13,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>
|
👉 <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/11aed429-b69c-49d5-8982-fa99b4a0e9a8" controls crossorigin muted></video>
|
<video id="demo-video" src="https://github.com/user-attachments/assets/a1f2eae2-13fb-4aae-98cf-a3fc1620a6c2" controls crossorigin muted></video>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -49,8 +49,8 @@
|
|||||||
|
|
||||||
| Mirrors | URL |
|
| Mirrors | URL |
|
||||||
| ------- | ---------------------------------------------------------------------------------- |
|
| ------- | ---------------------------------------------------------------------------------- |
|
||||||
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.4.4/dist/iife/page-agent.demo.js |
|
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.5.3/dist/iife/page-agent.demo.js |
|
||||||
| China | https://registry.npmmirror.com/page-agent/1.4.4/files/dist/iife/page-agent.demo.js |
|
| China | https://registry.npmmirror.com/page-agent/1.5.3/files/dist/iife/page-agent.demo.js |
|
||||||
|
|
||||||
> **⚠️ 仅用于技术评估。** 该 Demo CDN 使用了免费的[测试 LLM API](https://alibaba.github.io/page-agent/docs/features/models#free-testing-api),使用即表示您同意其[条款](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md)。
|
> **⚠️ 仅用于技术评估。** 该 Demo CDN 使用了免费的[测试 LLM API](https://alibaba.github.io/page-agent/docs/features/models#free-testing-api),使用即表示您同意其[条款](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md)。
|
||||||
|
|
||||||
|
|||||||
+19
-17
@@ -1,20 +1,20 @@
|
|||||||
# Terms of Use & Privacy
|
# Terms of Use & Privacy
|
||||||
|
|
||||||
**Last updated:** February 2026
|
**Last updated:** March 2026
|
||||||
|
|
||||||
"We" in this document refers to the maintainers of the open-source Page Agent project (https://github.com/alibaba/page-agent). This document covers the Page Agent software itself and the testing services we provide — **not** any third-party product or service built with it.
|
"We" in this document refers to the maintainers of the open-source Page Agent project (https://github.com/alibaba/page-agent). "The software" refers to PageAgent.js (the JavaScript library) and Page Agent Ext (the browser extension). This document covers the software itself and the testing API we provide — **not** any third-party product or service built with it.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Open Source Software Privacy
|
## 1. Open Source Software Privacy
|
||||||
|
|
||||||
Page Agent (PageAgent.js and Page Agent Extension) is a **client-side only** tool with a "Bring Your Own Key" (BYOK) architecture. The software itself does **not** include any backend service. The software does **not** collect or transmit any user data on its own, and the maintainers do **not** have access to your browsing activity, page content, or task instructions through the software.
|
The software is a **client-side only** tool with a "Bring Your Own Key" (BYOK) architecture. The software itself does **not** include any backend service. The software does **not** collect or transmit any user data on its own, and we do **not** have access to your browsing activity, page content, or task instructions through the software.
|
||||||
|
|
||||||
All data transmission occurs **only** between your browser and the LLM provider you configure. You are in full control of which provider receives your data.
|
All data transmission occurs **only** between your browser and the LLM provider you configure. You are in full control of which provider receives your data.
|
||||||
|
|
||||||
- You choose which LLM provider to use
|
- You choose which LLM provider to use
|
||||||
- You may configure your own API endpoint at any time
|
- You may configure your own API endpoint at any time
|
||||||
- The project is open source and can be audited: https://github.com/alibaba/page-agent
|
- The project is open source under the [MIT License](https://github.com/alibaba/page-agent/blob/main/LICENSE) and can be audited at: https://github.com/alibaba/page-agent
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -22,21 +22,23 @@ All data transmission occurs **only** between your browser and the LLM provider
|
|||||||
|
|
||||||
To facilitate easy testing and technical evaluation, we provide a free testing LLM API. This API is used in the project homepage's live demo, the pre-built demo CDN bundles, and the browser extension's default configuration. Users may also use it independently for their own technical evaluation of page-agent.
|
To facilitate easy testing and technical evaluation, we provide a free testing LLM API. This API is used in the project homepage's live demo, the pre-built demo CDN bundles, and the browser extension's default configuration. Users may also use it independently for their own technical evaluation of page-agent.
|
||||||
|
|
||||||
This free testing API is provided **strictly for technical evaluation and R&D purposes only**. It must not be used in any production environment. By using this service, you agree to the following terms:
|
This free testing API is provided **strictly for technical evaluation and R&D purposes only**. It must not be used in any production environment. By using this API, you agree to the following terms:
|
||||||
|
|
||||||
**No Sensitive Data**: You are strictly prohibited from inputting any Personal Identifiable Information (PII), confidential business data, financial/medical records, or using this agent on web pages containing such sensitive information.
|
- **No Sensitive Data**: You are strictly prohibited from inputting any Personal Identifiable Information (PII), confidential business data, financial/medical records, or using this agent on web pages containing such sensitive information.
|
||||||
|
|
||||||
**Zero Data Retention**: We do not store, log, or use your prompts or webpage data (DOM) for model training. All data is processed in-transit and immediately discarded. However, we do temporarily process necessary, identity-agnostic network data (such as IP addresses) solely for rate-limiting and anti-abuse purposes.
|
- **Data Processing**: We do not store or log your prompts, webpage data (HTML), or any submitted content, nor do we use such data for model training. All data is processed in-transit and immediately discarded. We perform in-memory request validation to prevent abuse of the testing API, and temporarily process IP addresses for rate-limiting purposes. No data from these processes is retained. Data is processed through Alibaba Cloud infrastructure, which is subject to its own privacy policy.
|
||||||
|
|
||||||
**Independent Infrastructure**: The `page-agent` open-source software is completely frontend-based with a "Bring Your Own Key" (BYOK) architecture and no built-in backend. To facilitate easy testing, the maintainers have independently purchased public cloud services from Alibaba Cloud China ([aliyun.com](https://www.aliyun.com) FC and BaiLian Qwen models). This project is not affiliated with, nor endorsed by, Alibaba Cloud.
|
- **Independent Infrastructure**: The software is completely frontend-based with a "Bring Your Own Key" (BYOK) architecture and **no built-in backend**. To facilitate easy testing, the maintainers have purchased public cloud services from Alibaba Cloud China ([aliyun.com](https://www.aliyun.com) Function Compute and BaiLian Qwen models). This project is not a product of, nor endorsed by, Alibaba Cloud.
|
||||||
|
|
||||||
**No Guaranteed Availability**: This testing API may be rate-limited, degraded, or discontinued at any time without prior notice.
|
- **No Guaranteed Availability**: This testing API may be rate-limited, degraded, or discontinued at any time without prior notice.
|
||||||
|
|
||||||
**"AS IS" & Limitation of Liability**: This service is provided strictly on an "AS IS" and "AS AVAILABLE" basis, without any warranties. The maintainers bear no liability for any data loss, service interruption, or legal consequences arising from your use of this demo.
|
- **"AS IS" & Limitation of Liability**: This service is provided strictly on an "AS IS" and "AS AVAILABLE" basis, without any warranties. The maintainers bear no liability for any data loss, service interruption, or legal consequences arising from your use of this service.
|
||||||
|
|
||||||
**Recommendation for Real Usage**: For secure and continuous usage, we strongly advise using the default BYOK mode with your own legally compliant commercial LLM API keys, or connecting to local, offline models (e.g., Ollama).
|
- **Recommendation for Real Usage**: For secure and continuous usage, we strongly advise using the BYOK mode with your own legally compliant commercial LLM API keys, or connecting to local, offline models (e.g., Ollama).
|
||||||
|
|
||||||
**Note**: This service processes data via servers located in Mainland China. If you are located in a region with strict data localization laws (such as the EU/EEA), please do not use this demo.
|
**Note**: This free testing LLM API processes data via servers located in Mainland China. If you are located in a region with strict data localization laws (such as the EU/EEA), please do not use this API.
|
||||||
|
|
||||||
|
**Age Requirement**: The software and testing API are not intended for use by individuals under the age of 13 (or the minimum age of digital consent in your jurisdiction).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -49,19 +51,19 @@ The extension performs DOM analysis and automation actions **locally in your bro
|
|||||||
Data is transmitted to external servers **only when you initiate an automation task**. When this occurs:
|
Data is transmitted to external servers **only when you initiate an automation task**. When this occurs:
|
||||||
|
|
||||||
- Your task instructions (natural language commands)
|
- Your task instructions (natural language commands)
|
||||||
- Simplified page structure (cleaned DOM) of all pages under the extension's control
|
- Simplified page structure (cleaned HTML) of all pages under the extension's control
|
||||||
|
|
||||||
are sent to the LLM API endpoint configured in **your settings**.
|
are sent to the LLM API endpoint configured in **your settings**.
|
||||||
|
|
||||||
> **Note:** The DOM cleaning process simplifies page structure for AI readability but **does not guarantee removal of sensitive information** (e.g., visible text, form values, or personal data on the page). Please be mindful of the page content when initiating tasks.
|
> **Note:** The HTML cleaning process simplifies page structure for AI readability but **does not guarantee removal of sensitive information** (e.g., visible text, form values, or personal data on the page). Please be mindful of the page content when initiating tasks.
|
||||||
|
|
||||||
**If you configure a third-party LLM provider** (e.g., OpenAI, Anthropic, or others), data is sent directly to that provider. Their privacy policies apply.
|
**If you configure a third-party LLM provider** (e.g., OpenAI, Anthropic, or others), data is sent directly to that provider. Their privacy policies apply.
|
||||||
|
|
||||||
**If you use the built-in testing API**, the terms in [Section 2](#2-testing-api-and-demo-disclaimer--terms-of-use) apply. By using the extension with the default testing API, you agree to those terms.
|
**If you use the testing API**, the terms in [Section 2](#2-testing-api-and-demo-disclaimer--terms-of-use) apply. By using the extension with the default testing API, you agree to those terms.
|
||||||
|
|
||||||
### Data Storage
|
### Data Storage
|
||||||
|
|
||||||
- **Local storage only**: Your configuration (API endpoint, API key, model selection) is stored in your browser via `chrome.storage.local`
|
- **Local storage only**: Your configuration (API endpoint, API key, model selection) is stored in your browser via `chrome.storage.local` (or equivalent browser storage APIs)
|
||||||
- **No cloud sync**: Configuration is not synced to any external server
|
- **No cloud sync**: Configuration is not synced to any external server
|
||||||
- **No analytics**: The extension does not include any analytics or tracking code
|
- **No analytics**: The extension does not include any analytics or tracking code
|
||||||
|
|
||||||
@@ -76,7 +78,7 @@ are sent to the LLM API endpoint configured in **your settings**.
|
|||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
We may update these terms as the project evolves.
|
We may update these terms at our discretion.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
|
|||||||
Generated
+19
-19
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "root",
|
"name": "root",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "root",
|
"name": "root",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/page-controller",
|
"packages/page-controller",
|
||||||
@@ -11113,11 +11113,11 @@
|
|||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@page-agent/core",
|
"name": "@page-agent/core",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/llms": "1.4.4",
|
"@page-agent/llms": "1.5.3",
|
||||||
"@page-agent/page-controller": "1.4.4",
|
"@page-agent/page-controller": "1.5.3",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -11129,13 +11129,13 @@
|
|||||||
},
|
},
|
||||||
"packages/extension": {
|
"packages/extension": {
|
||||||
"name": "@page-agent/ext",
|
"name": "@page-agent/ext",
|
||||||
"version": "0.1.8",
|
"version": "0.1.15",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/core": "1.4.4",
|
"@page-agent/core": "1.5.3",
|
||||||
"@page-agent/llms": "1.4.4",
|
"@page-agent/llms": "1.5.3",
|
||||||
"@page-agent/page-controller": "1.4.4",
|
"@page-agent/page-controller": "1.5.3",
|
||||||
"@page-agent/ui": "1.4.4",
|
"@page-agent/ui": "1.5.3",
|
||||||
"ai-motion": "^0.4.8",
|
"ai-motion": "^0.4.8",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
@@ -11173,7 +11173,7 @@
|
|||||||
},
|
},
|
||||||
"packages/llms": {
|
"packages/llms": {
|
||||||
"name": "@page-agent/llms",
|
"name": "@page-agent/llms",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
@@ -11186,13 +11186,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/page-agent": {
|
"packages/page-agent": {
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/core": "1.4.4",
|
"@page-agent/core": "1.5.3",
|
||||||
"@page-agent/llms": "1.4.4",
|
"@page-agent/llms": "1.5.3",
|
||||||
"@page-agent/page-controller": "1.4.4",
|
"@page-agent/page-controller": "1.5.3",
|
||||||
"@page-agent/ui": "1.4.4",
|
"@page-agent/ui": "1.5.3",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -11204,7 +11204,7 @@
|
|||||||
},
|
},
|
||||||
"packages/page-controller": {
|
"packages/page-controller": {
|
||||||
"name": "@page-agent/page-controller",
|
"name": "@page-agent/page-controller",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ai-motion": "^0.4.8"
|
"ai-motion": "^0.4.8"
|
||||||
@@ -11212,12 +11212,12 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@page-agent/ui",
|
"name": "@page-agent/ui",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"packages/website": {
|
"packages/website": {
|
||||||
"name": "@page-agent/website",
|
"name": "@page-agent/website",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "root",
|
"name": "root",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/page-controller",
|
"packages/page-controller",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/core",
|
"name": "@page-agent/core",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/esm/page-agent-core.js",
|
"main": "./dist/esm/page-agent-core.js",
|
||||||
"module": "./dist/esm/page-agent-core.js",
|
"module": "./dist/esm/page-agent-core.js",
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"@page-agent/llms": "1.4.4",
|
"@page-agent/llms": "1.5.3",
|
||||||
"@page-agent/page-controller": "1.4.4"
|
"@page-agent/page-controller": "1.5.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"zod": "^3.25.0 || ^4.0.0"
|
"zod": "^3.25.0 || ^4.0.0"
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export class PageAgentCore extends EventTarget {
|
|||||||
constructor(config: PageAgentCoreConfig) {
|
constructor(config: PageAgentCoreConfig) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this.config = { ...config, maxSteps: config.maxSteps || 40 }
|
this.config = { ...config, maxSteps: config.maxSteps ?? 40 }
|
||||||
|
|
||||||
this.#llm = new LLM(this.config)
|
this.#llm = new LLM(this.config)
|
||||||
this.tools = new Map(tools)
|
this.tools = new Map(tools)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/ext",
|
"name": "@page-agent/ext",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.8",
|
"version": "0.1.15",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "wxt",
|
"dev": "wxt",
|
||||||
@@ -38,10 +38,10 @@
|
|||||||
"wxt": "^0.20.18"
|
"wxt": "^0.20.18"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/core": "1.4.4",
|
"@page-agent/core": "1.5.3",
|
||||||
"@page-agent/llms": "1.4.4",
|
"@page-agent/llms": "1.5.3",
|
||||||
"@page-agent/page-controller": "1.4.4",
|
"@page-agent/page-controller": "1.5.3",
|
||||||
"@page-agent/ui": "1.4.4",
|
"@page-agent/ui": "1.5.3",
|
||||||
"ai-motion": "^0.4.8",
|
"ai-motion": "^0.4.8",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type PageAgentConfig, PageAgentCore } from '@page-agent/core'
|
import { type AgentConfig, PageAgentCore } from '@page-agent/core'
|
||||||
|
|
||||||
import { RemotePageController } from './RemotePageController'
|
import { RemotePageController } from './RemotePageController'
|
||||||
import { TabsController } from './TabsController'
|
import { TabsController } from './TabsController'
|
||||||
@@ -17,7 +17,7 @@ function detectLanguage(): 'en-US' | 'zh-CN' {
|
|||||||
* - can be used from a side panel or a content script
|
* - can be used from a side panel or a content script
|
||||||
*/
|
*/
|
||||||
export class MultiPageAgent extends PageAgentCore {
|
export class MultiPageAgent extends PageAgentCore {
|
||||||
constructor(config: Omit<PageAgentConfig, 'pageController'> & { includeInitialTab?: boolean }) {
|
constructor(config: AgentConfig & { includeInitialTab?: boolean }) {
|
||||||
// multi page controller
|
// multi page controller
|
||||||
const tabsController = new TabsController()
|
const tabsController = new TabsController()
|
||||||
const pageController = new RemotePageController(tabsController)
|
const pageController = new RemotePageController(tabsController)
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ import { DEMO_CONFIG, migrateLegacyEndpoint } from './constants'
|
|||||||
/** Language preference: undefined means follow system */
|
/** Language preference: undefined means follow system */
|
||||||
export type LanguagePreference = SupportedLanguage | undefined
|
export type LanguagePreference = SupportedLanguage | undefined
|
||||||
|
|
||||||
export interface ExtConfig extends LLMConfig {
|
export interface AdvancedConfig {
|
||||||
|
maxSteps?: number
|
||||||
|
systemInstruction?: string
|
||||||
|
experimentalLlmsTxt?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExtConfig extends LLMConfig, AdvancedConfig {
|
||||||
language?: LanguagePreference
|
language?: LanguagePreference
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,9 +46,10 @@ export function useAgent(): UseAgentResult {
|
|||||||
const [config, setConfig] = useState<ExtConfig | null>(null)
|
const [config, setConfig] = useState<ExtConfig | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
chrome.storage.local.get(['llmConfig', 'language']).then((result) => {
|
chrome.storage.local.get(['llmConfig', 'language', 'advancedConfig']).then((result) => {
|
||||||
let llmConfig = (result.llmConfig as LLMConfig) ?? DEMO_CONFIG
|
let llmConfig = (result.llmConfig as LLMConfig) ?? DEMO_CONFIG
|
||||||
const language = (result.language as SupportedLanguage) || undefined
|
const language = (result.language as SupportedLanguage) || undefined
|
||||||
|
const advancedConfig = (result.advancedConfig as AdvancedConfig) ?? {}
|
||||||
|
|
||||||
// Auto-migrate legacy testing endpoints
|
// Auto-migrate legacy testing endpoints
|
||||||
const migrated = migrateLegacyEndpoint(llmConfig)
|
const migrated = migrateLegacyEndpoint(llmConfig)
|
||||||
@@ -53,14 +60,18 @@ export function useAgent(): UseAgentResult {
|
|||||||
chrome.storage.local.set({ llmConfig: DEMO_CONFIG })
|
chrome.storage.local.set({ llmConfig: DEMO_CONFIG })
|
||||||
}
|
}
|
||||||
|
|
||||||
setConfig({ ...llmConfig, language })
|
setConfig({ ...llmConfig, ...advancedConfig, language })
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!config) return
|
if (!config) return
|
||||||
|
|
||||||
const agent = new MultiPageAgent(config)
|
const { systemInstruction, ...agentConfig } = config
|
||||||
|
const agent = new MultiPageAgent({
|
||||||
|
...agentConfig,
|
||||||
|
instructions: systemInstruction ? { system: systemInstruction } : undefined,
|
||||||
|
})
|
||||||
agentRef.current = agent
|
agentRef.current = agent
|
||||||
|
|
||||||
const handleStatusChange = (e: Event) => {
|
const handleStatusChange = (e: Event) => {
|
||||||
@@ -106,15 +117,26 @@ export function useAgent(): UseAgentResult {
|
|||||||
agentRef.current?.stop()
|
agentRef.current?.stop()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const configure = useCallback(async ({ language, ...llmConfig }: ExtConfig) => {
|
const configure = useCallback(
|
||||||
await chrome.storage.local.set({ llmConfig })
|
async ({
|
||||||
if (language) {
|
language,
|
||||||
await chrome.storage.local.set({ language })
|
maxSteps,
|
||||||
} else {
|
systemInstruction,
|
||||||
await chrome.storage.local.remove('language')
|
experimentalLlmsTxt,
|
||||||
}
|
...llmConfig
|
||||||
setConfig({ ...llmConfig, language })
|
}: ExtConfig) => {
|
||||||
}, [])
|
await chrome.storage.local.set({ llmConfig })
|
||||||
|
if (language) {
|
||||||
|
await chrome.storage.local.set({ language })
|
||||||
|
} else {
|
||||||
|
await chrome.storage.local.remove('language')
|
||||||
|
}
|
||||||
|
const advancedConfig: AdvancedConfig = { maxSteps, systemInstruction, experimentalLlmsTxt }
|
||||||
|
await chrome.storage.local.set({ advancedConfig })
|
||||||
|
setConfig({ ...llmConfig, ...advancedConfig, language })
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status,
|
status,
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
import { Copy, CornerUpLeft, Eye, EyeOff, HatGlasses, Home, Loader2, Scale } from 'lucide-react'
|
import {
|
||||||
|
ChevronDown,
|
||||||
|
Copy,
|
||||||
|
CornerUpLeft,
|
||||||
|
Eye,
|
||||||
|
EyeOff,
|
||||||
|
HatGlasses,
|
||||||
|
Home,
|
||||||
|
Loader2,
|
||||||
|
Scale,
|
||||||
|
} from 'lucide-react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { siGithub } from 'simple-icons'
|
import { siGithub } from 'simple-icons'
|
||||||
|
|
||||||
@@ -6,6 +16,7 @@ import { DEMO_API_KEY, DEMO_BASE_URL, DEMO_MODEL, isTestingEndpoint } from '@/ag
|
|||||||
import type { ExtConfig, LanguagePreference } from '@/agent/useAgent'
|
import type { ExtConfig, LanguagePreference } from '@/agent/useAgent'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
|
import { Switch } from '@/components/ui/switch'
|
||||||
|
|
||||||
interface ConfigPanelProps {
|
interface ConfigPanelProps {
|
||||||
config: ExtConfig | null
|
config: ExtConfig | null
|
||||||
@@ -18,18 +29,26 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
const [baseURL, setBaseURL] = useState(config?.baseURL || DEMO_BASE_URL)
|
const [baseURL, setBaseURL] = useState(config?.baseURL || DEMO_BASE_URL)
|
||||||
const [model, setModel] = useState(config?.model || DEMO_MODEL)
|
const [model, setModel] = useState(config?.model || DEMO_MODEL)
|
||||||
const [language, setLanguage] = useState<LanguagePreference>(config?.language)
|
const [language, setLanguage] = useState<LanguagePreference>(config?.language)
|
||||||
|
const [maxSteps, setMaxSteps] = useState<number | undefined>(config?.maxSteps)
|
||||||
|
const [systemInstruction, setSystemInstruction] = useState(config?.systemInstruction ?? '')
|
||||||
|
const [experimentalLlmsTxt, setExperimentalLlmsTxt] = useState(
|
||||||
|
config?.experimentalLlmsTxt ?? false
|
||||||
|
)
|
||||||
|
const [advancedOpen, setAdvancedOpen] = useState(false)
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const [userAuthToken, setUserAuthToken] = useState<string>('')
|
const [userAuthToken, setUserAuthToken] = useState<string>('')
|
||||||
const [copied, setCopied] = useState(false)
|
const [copied, setCopied] = useState(false)
|
||||||
const [showToken, setShowToken] = useState(false)
|
const [showToken, setShowToken] = useState(false)
|
||||||
const [showApiKey, setShowApiKey] = useState(false)
|
const [showApiKey, setShowApiKey] = useState(false)
|
||||||
|
|
||||||
// Update local state when config prop changes
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setApiKey(config?.apiKey || DEMO_API_KEY)
|
setApiKey(config?.apiKey || DEMO_API_KEY)
|
||||||
setBaseURL(config?.baseURL || DEMO_BASE_URL)
|
setBaseURL(config?.baseURL || DEMO_BASE_URL)
|
||||||
setModel(config?.model || DEMO_MODEL)
|
setModel(config?.model || DEMO_MODEL)
|
||||||
setLanguage(config?.language)
|
setLanguage(config?.language)
|
||||||
|
setMaxSteps(config?.maxSteps)
|
||||||
|
setSystemInstruction(config?.systemInstruction ?? '')
|
||||||
|
setExperimentalLlmsTxt(config?.experimentalLlmsTxt ?? false)
|
||||||
}, [config])
|
}, [config])
|
||||||
|
|
||||||
// Poll for user auth token every second until found
|
// Poll for user auth token every second until found
|
||||||
@@ -67,7 +86,15 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
try {
|
try {
|
||||||
await onSave({ apiKey, baseURL, model, language })
|
await onSave({
|
||||||
|
apiKey,
|
||||||
|
baseURL,
|
||||||
|
model,
|
||||||
|
language,
|
||||||
|
maxSteps: maxSteps || undefined,
|
||||||
|
systemInstruction: systemInstruction || undefined,
|
||||||
|
experimentalLlmsTxt,
|
||||||
|
})
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
}
|
}
|
||||||
@@ -87,28 +114,11 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Testing API notice */}
|
|
||||||
{isTestingEndpoint(baseURL) && (
|
|
||||||
<div className="p-2.5 rounded-md border border-amber-500/30 bg-amber-500/5 text-[10px] text-muted-foreground leading-relaxed">
|
|
||||||
<Scale className="size-3 inline-block mr-1 -mt-0.5 text-amber-600" />
|
|
||||||
You are using the free testing API. By using this service you agree to the{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="underline hover:text-foreground"
|
|
||||||
>
|
|
||||||
Terms of Use & Privacy Policy
|
|
||||||
</a>
|
|
||||||
. No sensitive data. No guaranteed availability.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* User Auth Token Section */}
|
{/* User Auth Token Section */}
|
||||||
<div className="flex flex-col gap-1.5 p-3 bg-muted/50 rounded-md border">
|
<div className="flex flex-col gap-1.5 p-3 bg-muted/50 rounded-md border">
|
||||||
<label className="text-xs font-medium text-muted-foreground">User Auth Token</label>
|
<label className="text-xs font-medium text-muted-foreground">User Auth Token</label>
|
||||||
<p className="text-[10px] text-muted-foreground mb-1">
|
<p className="text-[10px] text-muted-foreground mb-1">
|
||||||
Add this token to a website's localStorage to give it authorization to call this extension
|
Give a website the ability to call this extension.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<Input
|
<Input
|
||||||
@@ -153,6 +163,23 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Testing API notice */}
|
||||||
|
{isTestingEndpoint(baseURL) && (
|
||||||
|
<div className="p-2.5 rounded-md border border-amber-500/30 bg-amber-500/5 text-[11px] text-muted-foreground leading-relaxed">
|
||||||
|
<Scale className="size-3 inline-block mr-1 -mt-0.5 text-amber-600" />
|
||||||
|
You are using the free testing API. By using this service you agree to the{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="underline hover:text-foreground"
|
||||||
|
>
|
||||||
|
Terms of Use & Privacy Policy
|
||||||
|
</a>
|
||||||
|
. No sensitive data. No guaranteed availability.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<label className="text-xs text-muted-foreground">Model</label>
|
<label className="text-xs text-muted-foreground">Model</label>
|
||||||
<Input
|
<Input
|
||||||
@@ -197,6 +224,52 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Advanced Config */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setAdvancedOpen(!advancedOpen)}
|
||||||
|
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground cursor-pointer mt-1 font-bold"
|
||||||
|
>
|
||||||
|
Advanced
|
||||||
|
<ChevronDown
|
||||||
|
className="size-3 transition-transform"
|
||||||
|
style={{ transform: advancedOpen ? 'rotate(0deg)' : 'rotate(90deg)' }}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{advancedOpen && (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col gap-1.5">
|
||||||
|
<label className="text-xs text-muted-foreground">Max Steps</label>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
placeholder="40"
|
||||||
|
min={1}
|
||||||
|
max={200}
|
||||||
|
value={maxSteps ?? ''}
|
||||||
|
onChange={(e) => setMaxSteps(e.target.value ? Number(e.target.value) : undefined)}
|
||||||
|
className="text-xs h-8 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [-moz-appearance:textfield]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-1.5">
|
||||||
|
<label className="text-xs text-muted-foreground">System Instruction</label>
|
||||||
|
<textarea
|
||||||
|
placeholder="Additional instructions for the agent..."
|
||||||
|
value={systemInstruction}
|
||||||
|
onChange={(e) => setSystemInstruction(e.target.value)}
|
||||||
|
rows={3}
|
||||||
|
className="text-xs rounded-md border border-input bg-background px-3 py-2 resize-y min-h-[60px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label className="flex items-center justify-between cursor-pointer">
|
||||||
|
<span className="text-xs text-muted-foreground">Experimental llms.txt support</span>
|
||||||
|
<Switch checked={experimentalLlmsTxt} onCheckedChange={setExperimentalLlmsTxt} />
|
||||||
|
</label>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex gap-2 mt-2">
|
<div className="flex gap-2 mt-2">
|
||||||
<Button variant="outline" onClick={onClose} className="flex-1 h-8 text-xs cursor-pointer">
|
<Button variant="outline" onClick={onClose} className="flex-1 h-8 text-xs cursor-pointer">
|
||||||
Cancel
|
Cancel
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AlertTriangle, RotateCcw } from 'lucide-react'
|
import { AlertTriangle, Eraser, RotateCcw } from 'lucide-react'
|
||||||
import { Component, type ErrorInfo, type ReactNode } from 'react'
|
import { Component, type ErrorInfo, type ReactNode } from 'react'
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
@@ -27,6 +27,11 @@ export class ErrorBoundary extends Component<Props, State> {
|
|||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleResetConfig = async () => {
|
||||||
|
await chrome.storage.local.remove(['llmConfig', 'language', 'advancedConfig'])
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.state.hasError) {
|
if (!this.state.hasError) {
|
||||||
return this.props.children
|
return this.props.children
|
||||||
@@ -39,10 +44,16 @@ export class ErrorBoundary extends Component<Props, State> {
|
|||||||
<p className="text-sm text-muted-foreground mb-4 max-w-xs">
|
<p className="text-sm text-muted-foreground mb-4 max-w-xs">
|
||||||
{this.state.error?.message || 'An unexpected error occurred'}
|
{this.state.error?.message || 'An unexpected error occurred'}
|
||||||
</p>
|
</p>
|
||||||
<Button variant="outline" size="sm" onClick={this.handleReload}>
|
<div className="flex gap-2">
|
||||||
<RotateCcw className="size-3.5 mr-2" />
|
<Button variant="outline" size="sm" onClick={this.handleResetConfig}>
|
||||||
Reload Panel
|
<Eraser className="size-3.5 mr-2" />
|
||||||
</Button>
|
Reset Config
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" size="sm" onClick={this.handleReload}>
|
||||||
|
<RotateCcw className="size-3.5 mr-2" />
|
||||||
|
Reload Panel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,20 +43,24 @@ export function MotionOverlay({ active }: { active: boolean }) {
|
|||||||
const motionRef = useRef<Motion | null>(null)
|
const motionRef = useRef<Motion | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const mode = document.documentElement.classList.contains('dark') ? 'dark' : 'light'
|
try {
|
||||||
const motion = new Motion({
|
const mode = document.documentElement.classList.contains('dark') ? 'dark' : 'light'
|
||||||
mode,
|
const motion = new Motion({
|
||||||
borderWidth: 4,
|
mode,
|
||||||
borderRadius: 14,
|
borderWidth: 4,
|
||||||
glowWidth: mode === 'dark' ? 120 : 60,
|
borderRadius: 14,
|
||||||
styles: { position: 'absolute', inset: '0' },
|
glowWidth: mode === 'dark' ? 120 : 60,
|
||||||
})
|
styles: { position: 'absolute', inset: '0' },
|
||||||
motionRef.current = motion
|
})
|
||||||
containerRef.current!.appendChild(motion.element)
|
motionRef.current = motion
|
||||||
motion.autoResize(containerRef.current!)
|
containerRef.current!.appendChild(motion.element)
|
||||||
|
motion.autoResize(containerRef.current!)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[MotionOverlay] Motion unavailable:', e)
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
motion.dispose()
|
motionRef.current?.dispose()
|
||||||
motionRef.current = null
|
motionRef.current = null
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
zip: {
|
||||||
|
artifactTemplate: 'page-agent-ext-{{version}}-{{browser}}.zip',
|
||||||
|
},
|
||||||
manifest: {
|
manifest: {
|
||||||
default_locale: 'en',
|
default_locale: 'en',
|
||||||
name: '__MSG_extName__',
|
name: '__MSG_extName__',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/llms",
|
"name": "@page-agent/llms",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/lib/page-agent-llms.js",
|
"main": "./dist/lib/page-agent-llms.js",
|
||||||
"module": "./dist/lib/page-agent-llms.js",
|
"module": "./dist/lib/page-agent-llms.js",
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ export function modelPatch(body: Record<string, any>) {
|
|||||||
} else if (modelName.startsWith('gpt-51')) {
|
} else if (modelName.startsWith('gpt-51')) {
|
||||||
debug('Applying GPT-51 patch: disable reasoning')
|
debug('Applying GPT-51 patch: disable reasoning')
|
||||||
body.reasoning_effort = 'none'
|
body.reasoning_effort = 'none'
|
||||||
|
} else if (modelName.startsWith('gpt-54')) {
|
||||||
|
debug(
|
||||||
|
'Applying GPT-5.4 patch: skip reasoning_effort because chat/completions rejects it with function tools'
|
||||||
|
)
|
||||||
|
delete body.reasoning_effort
|
||||||
} else if (modelName.startsWith('gpt-5-mini')) {
|
} else if (modelName.startsWith('gpt-5-mini')) {
|
||||||
debug('Applying GPT-5-mini patch: set reasoning effort to low, temperature to 1')
|
debug('Applying GPT-5-mini patch: set reasoning effort to low, temperature to 1')
|
||||||
body.reasoning_effort = 'low'
|
body.reasoning_effort = 'low'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "page-agent",
|
"name": "page-agent",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/esm/page-agent.js",
|
"main": "./dist/esm/page-agent.js",
|
||||||
"module": "./dist/esm/page-agent.js",
|
"module": "./dist/esm/page-agent.js",
|
||||||
@@ -44,10 +44,10 @@
|
|||||||
"postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
"postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/core": "1.4.4",
|
"@page-agent/core": "1.5.3",
|
||||||
"@page-agent/llms": "1.4.4",
|
"@page-agent/llms": "1.5.3",
|
||||||
"@page-agent/page-controller": "1.4.4",
|
"@page-agent/page-controller": "1.5.3",
|
||||||
"@page-agent/ui": "1.4.4",
|
"@page-agent/ui": "1.5.3",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/page-controller",
|
"name": "@page-agent/page-controller",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/lib/page-controller.js",
|
"main": "./dist/lib/page-controller.js",
|
||||||
"module": "./dist/lib/page-controller.js",
|
"module": "./dist/lib/page-controller.js",
|
||||||
|
|||||||
@@ -8,13 +8,7 @@ import cursorStyles from './cursor.module.css'
|
|||||||
export class SimulatorMask {
|
export class SimulatorMask {
|
||||||
shown: boolean = false
|
shown: boolean = false
|
||||||
wrapper = document.createElement('div')
|
wrapper = document.createElement('div')
|
||||||
motion = new Motion({
|
motion: Motion | null = null
|
||||||
mode: isPageDark() ? 'dark' : 'light',
|
|
||||||
styles: {
|
|
||||||
position: 'absolute',
|
|
||||||
inset: '0',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
#cursor = document.createElement('div')
|
#cursor = document.createElement('div')
|
||||||
|
|
||||||
@@ -30,8 +24,17 @@ export class SimulatorMask {
|
|||||||
this.wrapper.setAttribute('data-browser-use-ignore', 'true')
|
this.wrapper.setAttribute('data-browser-use-ignore', 'true')
|
||||||
this.wrapper.setAttribute('data-page-agent-ignore', 'true')
|
this.wrapper.setAttribute('data-page-agent-ignore', 'true')
|
||||||
|
|
||||||
this.wrapper.appendChild(this.motion.element)
|
try {
|
||||||
this.motion.autoResize(this.wrapper)
|
const motion = new Motion({
|
||||||
|
mode: isPageDark() ? 'dark' : 'light',
|
||||||
|
styles: { position: 'absolute', inset: '0' },
|
||||||
|
})
|
||||||
|
this.motion = motion
|
||||||
|
this.wrapper.appendChild(motion.element)
|
||||||
|
motion.autoResize(this.wrapper)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[SimulatorMask] Motion overlay unavailable:', e)
|
||||||
|
}
|
||||||
|
|
||||||
// Capture all mouse, keyboard, and wheel events
|
// Capture all mouse, keyboard, and wheel events
|
||||||
this.wrapper.addEventListener('click', (e) => {
|
this.wrapper.addEventListener('click', (e) => {
|
||||||
@@ -145,8 +148,8 @@ export class SimulatorMask {
|
|||||||
if (this.shown) return
|
if (this.shown) return
|
||||||
|
|
||||||
this.shown = true
|
this.shown = true
|
||||||
this.motion.start()
|
this.motion?.start()
|
||||||
this.motion.fadeIn()
|
this.motion?.fadeIn()
|
||||||
|
|
||||||
this.wrapper.style.display = 'block'
|
this.wrapper.style.display = 'block'
|
||||||
|
|
||||||
@@ -163,8 +166,8 @@ export class SimulatorMask {
|
|||||||
if (!this.shown) return
|
if (!this.shown) return
|
||||||
|
|
||||||
this.shown = false
|
this.shown = false
|
||||||
this.motion.fadeOut()
|
this.motion?.fadeOut()
|
||||||
this.motion.pause()
|
this.motion?.pause()
|
||||||
|
|
||||||
this.#cursor.classList.remove(cursorStyles.clicking)
|
this.#cursor.classList.remove(cursorStyles.clicking)
|
||||||
|
|
||||||
@@ -174,7 +177,7 @@ export class SimulatorMask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this.motion.dispose()
|
this.motion?.dispose()
|
||||||
this.wrapper.remove()
|
this.wrapper.remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/ui",
|
"name": "@page-agent/ui",
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/lib/page-agent-ui.js",
|
"main": "./dist/lib/page-agent-ui.js",
|
||||||
"module": "./dist/lib/page-agent-ui.js",
|
"module": "./dist/lib/page-agent-ui.js",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/website",
|
"name": "@page-agent/website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.4.4",
|
"version": "1.5.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// Demo build (auto-init with demo LLM, for quick testing)
|
// Demo build (auto-init with demo LLM, for quick testing)
|
||||||
export const CDN_DEMO_URL =
|
export const CDN_DEMO_URL =
|
||||||
'https://cdn.jsdelivr.net/npm/page-agent@1.4.4/dist/iife/page-agent.demo.js'
|
'https://cdn.jsdelivr.net/npm/page-agent@1.5.3/dist/iife/page-agent.demo.js'
|
||||||
export const CDN_DEMO_CN_URL =
|
export const CDN_DEMO_CN_URL =
|
||||||
'https://registry.npmmirror.com/page-agent/1.4.4/files/dist/iife/page-agent.demo.js'
|
'https://registry.npmmirror.com/page-agent/1.5.3/files/dist/iife/page-agent.demo.js'
|
||||||
|
|
||||||
// Demo LLM for website testing (homepage quick trial uses flash)
|
// Demo LLM for website testing (homepage quick trial uses flash)
|
||||||
export const DEMO_MODEL = 'qwen3.5-flash'
|
export const DEMO_MODEL = 'qwen3.5-flash'
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ function ScrollToTop() {
|
|||||||
|
|
||||||
export default function Router() {
|
export default function Router() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const id = requestIdleCallback(() => docsImport())
|
const schedule = globalThis.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1))
|
||||||
return () => cancelIdleCallback(id)
|
const cancel = globalThis.cancelIdleCallback ?? clearTimeout
|
||||||
|
const id = schedule(() => docsImport())
|
||||||
|
return () => cancel(id)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user