Compare commits

...

10 Commits

Author SHA1 Message Date
Simon af36f43104 chore(version): bump version to 0.2.5 2026-01-17 17:47:50 +08:00
Simon b5f260207c chore: wording 2026-01-17 17:47:04 +08:00
Simon 9075204c29 Merge pull request #118 from alibaba/feat/make-panel-optional
feat: make all ui optional
2026-01-17 17:43:40 +08:00
Simon ce3a80bc53 docs: typo 2026-01-17 17:30:16 +08:00
Simon 64c36f67bb docs: update config; instructions for programmatic usage 2026-01-17 17:28:28 +08:00
Simon 78d4919289 feat: make panel optional 2026-01-17 17:24:17 +08:00
Simon 1af2607cca feat: remove ask_user tool from sys_prompt 2026-01-17 17:18:31 +08:00
Simon ab713f3d3a chore(version): bump version to 0.2.4 2026-01-17 16:22:45 +08:00
Simon 05cc4f36c8 chore: add .prettierignore for system_prompt.md 2026-01-17 16:22:28 +08:00
Simon 54e9bdad7d chore: prettier json and markdowns 2026-01-17 16:15:36 +08:00
39 changed files with 437 additions and 321 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ on:
- 'v*' - 'v*'
permissions: permissions:
id-token: write # Required for OIDC id-token: write # Required for OIDC
contents: read contents: read
jobs: jobs:
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"recommendations": ["dbaeumer.vscode-eslint", "prettier.prettier-vscode"] "recommendations": ["dbaeumer.vscode-eslint", "prettier.prettier-vscode"]
} }
+27 -27
View File
@@ -1,29 +1,29 @@
{ {
"editor.fontLigatures": true, "editor.fontLigatures": true,
"cSpell.words": [ "cSpell.words": [
"deepseek", "deepseek",
"HITL", "HITL",
"innerhtml", "innerhtml",
"llms", "llms",
"onwarn", "onwarn",
"opensource", "opensource",
"qwen", "qwen",
"retryable", "retryable",
"shadcn", "shadcn",
"wouter" "wouter"
], ],
"markdownlint.config": { "markdownlint.config": {
// "comment": "Relaxed rules", // "comment": "Relaxed rules",
"default": true, "default": true,
"whitespace": false, "whitespace": false,
"line_length": false, "line_length": false,
"ul-indent": false, "ul-indent": false,
"no-inline-html": false, "no-inline-html": false,
"no-bare-urls": false, "no-bare-urls": false,
"fenced-code-language": false, "fenced-code-language": false,
"first-line-h1": false, "first-line-h1": false,
"block-spacing": false, "block-spacing": false,
"blanks-around-lists": false, "blanks-around-lists": false,
"ol-prefix": false "ol-prefix": false
} }
} }
+39 -39
View File
@@ -7,16 +7,16 @@ Thank you for your interest in contributing to Page-Agent! We welcome contributi
### Development Setup ### Development Setup
1. **Prerequisites** 1. **Prerequisites**
- `node.js >= 20` with `npm >= 10` - `node.js >= 20` with `npm >= 10`
- An editor that supports `ts/eslint/prettier` - An editor that supports `ts/eslint/prettier`
- Make sure `eslint`, `prettier` and `commitlint` work well - Make sure `eslint`, `prettier` and `commitlint` work well
2. **Setup** 2. **Setup**
```bash ```bash
npm ci npm ci
npm start # Start demo and documentation site npm start # Start demo and documentation site
``` ```
### Project Structure ### Project Structure
@@ -44,39 +44,39 @@ We use a simplified monorepo solution with `native npm-workspace + ts reference
1. **Fork and Clone** 1. **Fork and Clone**
```bash ```bash
git clone https://github.com/your-username/page-agent.git git clone https://github.com/your-username/page-agent.git
cd page-agent cd page-agent
``` ```
2. **Create Feature Branch** 2. **Create Feature Branch**
```bash ```bash
git checkout -b feat/your-feature-name git checkout -b feat/your-feature-name
``` ```
3. **Make Changes** 3. **Make Changes**
- Follow existing code style and patterns - Follow existing code style and patterns
- Add tests for new functionality - Add tests for new functionality
- Update documentation as needed - Update documentation as needed
4. **Test Your Changes** 4. **Test Your Changes**
- Test in our demo website - Test in our demo website
- Test it on other websites if applicable - Test it on other websites if applicable
- `@TODO: test suite` - `@TODO: test suite`
5. **Commit and Push** 5. **Commit and Push**
```bash ```bash
git add . git add .
git commit -m "feat: add awesome feature" git commit -m "feat: add awesome feature"
git push origin feat/your-feature-name git push origin feat/your-feature-name
``` ```
6. **Create Pull Request** 6. **Create Pull Request**
- Provide clear description of changes - Provide clear description of changes
- Link related issues - Link related issues
- Include screenshots for UI changes - Include screenshots for UI changes
## 📝 Code Style ## 📝 Code Style
@@ -101,11 +101,11 @@ We use a simplified monorepo solution with `native npm-workspace + ts reference
- Create a `.env` file in the repo root with your LLM API config - Create a `.env` file in the repo root with your LLM API config
```env ```env
LLM_MODEL_NAME=gpt-5.2 LLM_MODEL_NAME=gpt-5.2
LLM_API_KEY=your-api-key LLM_API_KEY=your-api-key
LLM_BASE_URL=https://api.your-llm-provider.com/v1 LLM_BASE_URL=https://api.your-llm-provider.com/v1
``` ```
- 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 the free testing proxy by default
@@ -120,15 +120,15 @@ npm start
- Start and serve a local `iife` script - Start and serve a local `iife` script
```bash ```bash
npm run dev:iife # Serving IIFE with auto rebuild at http://localhost:5174/page-agent.js npm run dev:iife # Serving IIFE with auto rebuild at http://localhost:5174/page-agent.js
``` ```
- Add a new bookmark - Add a new bookmark
```javascript ```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:5174/page-agent.js?t=${Math.random()}`;s.onload=()=>console.log(%27PageAgent ready!%27);document.head.appendChild(s);})();
``` ```
- Click the bookmark on any page to load Page-Agent - Click the bookmark on any page to load Page-Agent
+6 -6
View File
@@ -37,8 +37,8 @@
```html ```html
<script <script
src="https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js" src="https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js"
crossorigin="true" crossorigin="true"
></script> ></script>
``` ```
@@ -59,10 +59,10 @@ npm install page-agent
import { PageAgent } from 'page-agent' import { PageAgent } from 'page-agent'
const agent = new PageAgent({ const agent = new PageAgent({
model: 'deepseek-chat', model: 'deepseek-chat',
baseURL: 'https://api.deepseek.com', baseURL: 'https://api.deepseek.com',
apiKey: 'YOUR_API_KEY', apiKey: 'YOUR_API_KEY',
language: 'zh-CN', language: 'zh-CN',
}) })
await agent.execute('点击登录按钮') await agent.execute('点击登录按钮')
+6 -6
View File
@@ -37,8 +37,8 @@ Fastest way to try PageAgent:
```html ```html
<script <script
src="https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js" src="https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js"
crossorigin="true" crossorigin="true"
></script> ></script>
``` ```
@@ -59,10 +59,10 @@ npm install page-agent
import { PageAgent } from 'page-agent' import { PageAgent } from 'page-agent'
const agent = new PageAgent({ const agent = new PageAgent({
model: 'deepseek-chat', model: 'deepseek-chat',
baseURL: 'https://api.deepseek.com', baseURL: 'https://api.deepseek.com',
apiKey: 'YOUR_API_KEY', apiKey: 'YOUR_API_KEY',
language: 'en-US', language: 'en-US',
}) })
await agent.execute('Click the login button') await agent.execute('Click the login button')
+12 -12
View File
@@ -1,12 +1,12 @@
{ {
"name": "root", "name": "root",
"version": "0.2.3", "version": "0.2.5",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "root", "name": "root",
"version": "0.2.3", "version": "0.2.5",
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
@@ -8133,15 +8133,15 @@
}, },
"packages/cdn": { "packages/cdn": {
"name": "@page-agent/cdn", "name": "@page-agent/cdn",
"version": "0.2.3", "version": "0.2.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"page-agent": "0.2.3" "page-agent": "0.2.5"
} }
}, },
"packages/llms": { "packages/llms": {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "0.2.3", "version": "0.2.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chalk": "^5.6.2", "chalk": "^5.6.2",
@@ -8149,19 +8149,19 @@
} }
}, },
"packages/page-agent": { "packages/page-agent": {
"version": "0.2.3", "version": "0.2.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/llms": "0.2.3", "@page-agent/llms": "0.2.5",
"@page-agent/page-controller": "0.2.3", "@page-agent/page-controller": "0.2.5",
"@page-agent/ui": "0.2.3", "@page-agent/ui": "0.2.5",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5" "zod": "^4.3.5"
} }
}, },
"packages/page-controller": { "packages/page-controller": {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "0.2.3", "version": "0.2.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ai-motion": "^0.4.8" "ai-motion": "^0.4.8"
@@ -8169,12 +8169,12 @@
}, },
"packages/ui": { "packages/ui": {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "0.2.3", "version": "0.2.5",
"license": "MIT" "license": "MIT"
}, },
"packages/website": { "packages/website": {
"name": "@page-agent/website", "name": "@page-agent/website",
"version": "0.2.3", "version": "0.2.5",
"dependencies": { "dependencies": {
"@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",
+18 -2
View File
@@ -1,7 +1,7 @@
{ {
"name": "root", "name": "root",
"private": true, "private": true,
"version": "0.2.3", "version": "0.2.5",
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
@@ -102,6 +102,22 @@
".css$" ".css$"
], ],
"importOrderSeparation": true, "importOrderSeparation": true,
"importOrderSortSpecifiers": true "importOrderSortSpecifiers": true,
"overrides": [
{
"files": "*.md",
"options": {
"useTabs": false,
"tabWidth": 4
}
},
{
"files": "*.json",
"options": {
"useTabs": false,
"tabWidth": 4
}
}
]
} }
} }
+2 -2
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/cdn", "name": "@page-agent/cdn",
"private": false, "private": false,
"version": "0.2.3", "version": "0.2.5",
"type": "module", "type": "module",
"files": [ "files": [
"dist/" "dist/"
@@ -18,6 +18,6 @@
"build": "vite build && vite build --mode demo" "build": "vite build && vite build --mode demo"
}, },
"dependencies": { "dependencies": {
"page-agent": "0.2.3" "page-agent": "0.2.5"
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "0.2.3", "version": "0.2.5",
"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",
+7 -8
View File
@@ -1,10 +1,9 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
// @workaround DTS bug // @workaround DTS bug
// dts do not work with monorepo path mapping // dts do not work with monorepo path mapping
// disable path mapping for it // disable path mapping for it
"paths": {} "paths": {}
} }
} }
+10 -11
View File
@@ -1,13 +1,12 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false, "noEmit": false,
"allowImportingTsExtensions": false, "allowImportingTsExtensions": false,
"baseUrl": ".", "baseUrl": ".",
"outDir": "dist" "outDir": "dist"
}, },
"include": ["**/*.ts"], "include": ["**/*.ts"],
"exclude": ["dist", "node_modules"] "exclude": ["dist", "node_modules"]
} }
+4 -4
View File
@@ -1,7 +1,7 @@
{ {
"name": "page-agent", "name": "page-agent",
"private": false, "private": false,
"version": "0.2.3", "version": "0.2.5",
"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",
@@ -45,8 +45,8 @@
"dependencies": { "dependencies": {
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5", "zod": "^4.3.5",
"@page-agent/llms": "0.2.3", "@page-agent/llms": "0.2.5",
"@page-agent/page-controller": "0.2.3", "@page-agent/page-controller": "0.2.5",
"@page-agent/ui": "0.2.3" "@page-agent/ui": "0.2.5"
} }
} }
+32 -21
View File
@@ -99,7 +99,7 @@ export interface ExecutionResult {
export class PageAgent extends EventTarget { export class PageAgent extends EventTarget {
config: PageAgentConfig config: PageAgentConfig
id = uid() id = uid()
panel: Panel panel: Panel | null = null
tools: typeof tools tools: typeof tools
disposed = false disposed = false
task = '' task = ''
@@ -122,7 +122,7 @@ export class PageAgent extends EventTarget {
lastURL: '', lastURL: '',
} }
/** History event stream */ /** History events */
history: HistoryEvent[] = [] history: HistoryEvent[] = []
constructor(config: PageAgentConfig) { constructor(config: PageAgentConfig) {
@@ -130,11 +130,17 @@ export class PageAgent extends EventTarget {
this.config = config this.config = config
this.#llm = new LLM(this.config) this.#llm = new LLM(this.config)
this.panel = new Panel({
language: this.config.language, // Conditionally initialize Panel
onExecuteTask: (task) => this.execute(task), if (this.config.enablePanel !== false) {
onStop: () => this.dispose(), this.panel = new Panel({
}) language: this.config.language,
onExecuteTask: (task) => this.execute(task),
onStop: () => this.dispose(),
promptForNextTask: this.config.promptForNextTask,
})
}
this.tools = new Map(tools) this.tools = new Map(tools)
// Initialize PageController with config (mask enabled by default) // Initialize PageController with config (mask enabled by default)
@@ -146,11 +152,11 @@ export class PageAgent extends EventTarget {
// Listen to LLM events // Listen to LLM events
this.#llmRetryListener = (e) => { this.#llmRetryListener = (e) => {
const { current, max } = (e as CustomEvent).detail const { current, max } = (e as CustomEvent).detail
this.panel.update({ type: 'retry', current, max }) this.panel?.update({ type: 'retry', current, max })
} }
this.#llmErrorListener = (e) => { this.#llmErrorListener = (e) => {
const { error } = (e as CustomEvent).detail const { error } = (e as CustomEvent).detail
this.panel.update({ type: 'error', message: `step failed: ${error.message}` }) this.panel?.update({ type: 'error', message: `step failed: ${error.message}` })
} }
this.#llm.addEventListener('retry', this.#llmRetryListener) this.#llm.addEventListener('retry', this.#llmRetryListener)
this.#llm.addEventListener('error', this.#llmErrorListener) this.#llm.addEventListener('error', this.#llmErrorListener)
@@ -169,6 +175,11 @@ export class PageAgent extends EventTarget {
this.tools.delete('execute_javascript') this.tools.delete('execute_javascript')
} }
// Disable ask_user tool if enableAskUser is false or if panel is disabled
if (this.config.enableAskUser === false || this.config.enablePanel === false) {
this.tools.delete('ask_user')
}
this.#beforeUnloadListener = (e) => { this.#beforeUnloadListener = (e) => {
if (!this.disposed) this.dispose('PAGE_UNLOADING') if (!this.disposed) this.dispose('PAGE_UNLOADING')
} }
@@ -181,7 +192,7 @@ export class PageAgent extends EventTarget {
*/ */
pushObservation(content: string): void { pushObservation(content: string): void {
this.history.push({ type: 'observation', content }) this.history.push({ type: 'observation', content })
this.panel.update({ type: 'observation', content }) this.panel?.update({ type: 'observation', content })
} }
async execute(task: string): Promise<ExecutionResult> { async execute(task: string): Promise<ExecutionResult> {
@@ -199,10 +210,10 @@ export class PageAgent extends EventTarget {
// Show mask and panel // Show mask and panel
this.pageController.showMask() this.pageController.showMask()
this.panel.show() this.panel?.show()
this.panel.reset() this.panel?.reset()
this.panel.update({ type: 'input', task: this.task }) this.panel?.update({ type: 'input', task: this.task })
if (this.#abortController) { if (this.#abortController) {
this.#abortController.abort() this.#abortController.abort()
@@ -232,7 +243,7 @@ export class PageAgent extends EventTarget {
// Update status to thinking // Update status to thinking
console.log(chalk.blue('Thinking...')) console.log(chalk.blue('Thinking...'))
this.panel.update({ type: 'thinking' }) this.panel?.update({ type: 'thinking' })
const result = await this.#llm.invoke( const result = await this.#llm.invoke(
[ [
@@ -370,7 +381,7 @@ export class PageAgent extends EventTarget {
if (reflectionText) { if (reflectionText) {
console.log(reflectionText) console.log(reflectionText)
this.panel.update({ type: 'thinking', text: reflectionText }) this.panel?.update({ type: 'thinking', text: reflectionText })
} }
// Find the corresponding tool // Find the corresponding tool
@@ -378,7 +389,7 @@ export class PageAgent extends EventTarget {
assert(tool, `Tool ${toolName} not found. (@note should have been caught before this!!!)`) assert(tool, `Tool ${toolName} not found. (@note should have been caught before this!!!)`)
console.log(chalk.blue.bold(`Executing tool: ${toolName}`), toolInput) console.log(chalk.blue.bold(`Executing tool: ${toolName}`), toolInput)
this.panel.update({ type: 'toolExecuting', toolName, args: toolInput }) this.panel?.update({ type: 'toolExecuting', toolName, args: toolInput })
const startTime = Date.now() const startTime = Date.now()
@@ -394,7 +405,7 @@ export class PageAgent extends EventTarget {
} }
// Briefly display execution result // Briefly display execution result
this.panel.update({ this.panel?.update({
type: 'toolCompleted', type: 'toolCompleted',
toolName, toolName,
args: toolInput, args: toolInput,
@@ -557,13 +568,13 @@ export class PageAgent extends EventTarget {
// Update panel status // Update panel status
if (success) { if (success) {
this.panel.update({ type: 'output', text }) this.panel?.update({ type: 'output', text })
} else { } else {
this.panel.update({ type: 'error', message: text }) this.panel?.update({ type: 'error', message: text })
} }
// Task completed // Task completed
this.panel.update({ type: 'completed' }) this.panel?.update({ type: 'completed' })
this.pageController.hideMask() this.pageController.hideMask()
@@ -593,7 +604,7 @@ export class PageAgent extends EventTarget {
console.log('Disposing PageAgent...') console.log('Disposing PageAgent...')
this.disposed = true this.disposed = true
this.pageController.dispose() this.pageController.dispose()
this.panel.dispose() this.panel?.dispose()
this.history = [] this.history = []
this.#abortController.abort(reason ?? 'PageAgent disposed') this.#abortController.abort(reason ?? 'PageAgent disposed')
+21
View File
@@ -11,6 +11,27 @@ export interface AgentConfig {
// theme?: 'light' | 'dark' // theme?: 'light' | 'dark'
language?: SupportedLanguage language?: SupportedLanguage
/**
* Whether to prompt for next task after task completion
* @default true
*/
promptForNextTask?: boolean
/**
* Enable the UI panel for visual feedback and user interaction
* When disabled, the panel will not be created and all UI operations will be skipped.
* Useful for automated testing or when integrating PageAgent as a library.
* @default true
*/
enablePanel?: boolean
/**
* Enable the ask_user tool for agent to ask questions
* When disabled, the agent cannot ask user questions during execution.
* @default true
*/
enableAskUser?: boolean
/** /**
* Custom tools to extend PageAgent capabilities * Custom tools to extend PageAgent capabilities
* @experimental * @experimental
@@ -0,0 +1 @@
system_prompt.md
@@ -92,7 +92,6 @@ Strictly follow these rules while using the browser and navigating the web:
- User can be wrong. If the request of user is not achievable, inappropriate or you do not have enough information or tools to achieve it. Tell user to make a better request. - User can be wrong. If the request of user is not achievable, inappropriate or you do not have enough information or tools to achieve it. Tell user to make a better request.
- Webpage can be broken. All webpages or apps have bugs. Some bug will make it hard for your job. It's encouraged to tell user the problem of current page. Your feedbacks (including failing) are valuable for user. - Webpage can be broken. All webpages or apps have bugs. Some bug will make it hard for your job. It's encouraged to tell user the problem of current page. Your feedbacks (including failing) are valuable for user.
- Trying to hard can be harmful. Repeating some action back and forth or pushing for a complex procedure with little knowledge can cause unwanted result and harmful side-effects. User would rather you to complete the task with a fail. - Trying to hard can be harmful. Repeating some action back and forth or pushing for a complex procedure with little knowledge can cause unwanted result and harmful side-effects. User would rather you to complete the task with a fail.
- If you are not clear about the request or steps. `ask_user` to clarify it.
- If you do not have knowledge for the current webpage or task. You must require user to give specific instructions and detailed steps. - If you do not have knowledge for the current webpage or task. You must require user to give specific instructions and detailed steps.
</capability> </capability>
@@ -120,7 +119,7 @@ Exhibit the following reasoning patterns to successfully achieve the <user_reque
- Analyze all relevant items in <agent_history> and <browser_state> to understand your state. - Analyze all relevant items in <agent_history> and <browser_state> to understand your state.
- Explicitly judge success/failure/uncertainty of the last action. Never assume an action succeeded just because it appears to be executed in your last step in <agent_history>. If the expected change is missing, mark the last action as failed (or uncertain) and plan a recovery. - Explicitly judge success/failure/uncertainty of the last action. Never assume an action succeeded just because it appears to be executed in your last step in <agent_history>. If the expected change is missing, mark the last action as failed (or uncertain) and plan a recovery.
- Analyze whether you are stuck, e.g. when you repeat the same actions multiple times without any progress. Then consider alternative approaches e.g. scrolling for more context or ask user for help. - Analyze whether you are stuck, e.g. when you repeat the same actions multiple times without any progress. Then consider alternative approaches e.g. scrolling for more context or ask user for help.
- `ask_user` for help if you have any difficulty. Users want to be kept in the loop. - Ask user for help if you have any difficulty. Keep user in the loop.
- If you see information relevant to <user_request>, plan saving the information to memory. - If you see information relevant to <user_request>, plan saving the information to memory.
- Always reason about the <user_request>. Make sure to carefully analyze the specific steps and information required. E.g. specific filters, specific form fields, specific information to search. Make sure to always compare the current trajectory with the user request and think carefully if thats how the user requested it. - Always reason about the <user_request>. Make sure to carefully analyze the specific steps and information required. E.g. specific filters, specific form fields, specific information to search. Make sure to always compare the current trajectory with the user request and think carefully if thats how the user requested it.
</reasoning_rules> </reasoning_rules>
+3
View File
@@ -80,6 +80,9 @@ tools.set(
question: zod.string(), question: zod.string(),
}), }),
execute: async function (this: PageAgent, input) { execute: async function (this: PageAgent, input) {
if (!this.panel) {
throw new Error('ask_user tool requires panel to be enabled')
}
const answer = await this.panel.askUser(input.question) const answer = await this.panel.askUser(input.question)
return `✅ Received user answer: ${answer}` return `✅ Received user answer: ${answer}`
}, },
+7 -7
View File
@@ -1,9 +1,9 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
// @workaround DTS bug // @workaround DTS bug
// dts do not work with monorepo path mapping // dts do not work with monorepo path mapping
// disable path mapping for it // disable path mapping for it
"paths": {} "paths": {}
} }
} }
+22 -22
View File
@@ -1,24 +1,24 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false, "noEmit": false,
"allowImportingTsExtensions": false, "allowImportingTsExtensions": false,
"baseUrl": ".", "baseUrl": ".",
"outDir": "dist", "outDir": "dist",
"paths": { "paths": {
// //
"@page-agent/llms": ["../llms/src/index.ts"], "@page-agent/llms": ["../llms/src/index.ts"],
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"], "@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
"@page-agent/ui": ["../ui/src/index.ts"] "@page-agent/ui": ["../ui/src/index.ts"]
} }
}, },
"include": ["**/*.ts"], "include": ["**/*.ts"],
"exclude": ["dist", "node_modules"], "exclude": ["dist", "node_modules"],
"references": [ "references": [
// //
{ "path": "../llms" }, { "path": "../llms" },
{ "path": "../page-controller" }, { "path": "../page-controller" },
{ "path": "../ui" } { "path": "../ui" }
] ]
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "0.2.3", "version": "0.2.5",
"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",
+7 -7
View File
@@ -1,9 +1,9 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
// @workaround DTS bug // @workaround DTS bug
// dts do not work with monorepo path mapping // dts do not work with monorepo path mapping
// disable path mapping for it // disable path mapping for it
"paths": {} "paths": {}
} }
} }
+10 -10
View File
@@ -1,12 +1,12 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false, "noEmit": false,
"allowImportingTsExtensions": false, "allowImportingTsExtensions": false,
"baseUrl": ".", "baseUrl": ".",
"outDir": "dist" "outDir": "dist"
}, },
"include": ["**/*.ts", "**/*.js"], "include": ["**/*.ts", "**/*.js"],
"exclude": ["dist", "node_modules"] "exclude": ["dist", "node_modules"]
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "0.2.3", "version": "0.2.5",
"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",
+13 -1
View File
@@ -11,6 +11,11 @@ export interface PanelConfig {
language?: SupportedLanguage language?: SupportedLanguage
onExecuteTask: (task: string) => void onExecuteTask: (task: string) => void
onStop: () => void onStop: () => void
/**
* Whether to prompt for next task after task completion
* @default true
*/
promptForNextTask?: boolean
} }
/** /**
@@ -358,7 +363,14 @@ export class Panel {
} }
const lastStep = steps[steps.length - 1] const lastStep = steps[steps.length - 1]
return lastStep.type === 'completed' || lastStep.type === 'error' const isTaskEnded = lastStep.type === 'completed' || lastStep.type === 'error'
// Only show input area after task completion if configured to do so
if (isTaskEnded) {
return this.#config.promptForNextTask ?? true
}
return false
} }
#createWrapper(): HTMLElement { #createWrapper(): HTMLElement {
+7 -8
View File
@@ -1,10 +1,9 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
// @workaround DTS bug // @workaround DTS bug
// dts do not work with monorepo path mapping // dts do not work with monorepo path mapping
// disable path mapping for it // disable path mapping for it
"paths": {} "paths": {}
} }
} }
+10 -11
View File
@@ -1,13 +1,12 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false, "noEmit": false,
"allowImportingTsExtensions": false, "allowImportingTsExtensions": false,
"baseUrl": ".", "baseUrl": ".",
"outDir": "dist" "outDir": "dist"
}, },
"include": ["**/*.ts", "**/*.js"], "include": ["**/*.ts", "**/*.js"],
"exclude": ["dist", "node_modules"] "exclude": ["dist", "node_modules"]
} }
+22 -22
View File
@@ -1,24 +1,24 @@
{ {
"$schema": "https://ui.shadcn.com/schema.json", "$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york", "style": "new-york",
"rsc": false, "rsc": false,
"tsx": true, "tsx": true,
"tailwind": { "tailwind": {
"config": "", "config": "",
"css": "src/index.css", "css": "src/index.css",
"baseColor": "neutral", "baseColor": "neutral",
"cssVariables": true, "cssVariables": true,
"prefix": "" "prefix": ""
}, },
"iconLibrary": "lucide", "iconLibrary": "lucide",
"aliases": { "aliases": {
"components": "@/components", "components": "@/components",
"utils": "@/lib/utils", "utils": "@/lib/utils",
"ui": "@/components/ui", "ui": "@/components/ui",
"lib": "@/lib", "lib": "@/lib",
"hooks": "@/hooks" "hooks": "@/hooks"
}, },
"registries": { "registries": {
"@magicui": "https://magicui.design/r/{name}.json" "@magicui": "https://magicui.design/r/{name}.json"
} }
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/website", "name": "@page-agent/website",
"private": true, "private": true,
"version": "0.2.3", "version": "0.2.5",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 0.0.0.0", "dev": "vite --host 0.0.0.0",
+2 -3
View File
@@ -28,9 +28,9 @@ pages/i18n/
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
function MyComponent() { function MyComponent() {
const { t } = useTranslation('common') // 指定命名空间 const { t } = useTranslation('common') // 指定命名空间
return <h1>{t('header.nav_docs')}</h1> return <h1>{t('header.nav_docs')}</h1>
} }
``` ```
@@ -71,4 +71,3 @@ t('common:header.nav_docs')
- [ ] 文档页翻译(`docs.json` - [ ] 文档页翻译(`docs.json`
- [ ] DocsLayout 导航结构国际化 - [ ] DocsLayout 导航结构国际化
- [ ] 404 页面国际化 - [ ] 404 页面国际化
+4
View File
@@ -89,6 +89,10 @@ export default function HomePage() {
import.meta.env.DEV && import.meta.env.LLM_API_KEY import.meta.env.DEV && import.meta.env.LLM_API_KEY
? import.meta.env.LLM_API_KEY ? import.meta.env.LLM_API_KEY
: DEMO_API_KEY, : DEMO_API_KEY,
// enableAskUser: false,
// promptForNextTask: false,
// enablePanel: false,
}) })
} }
@@ -61,6 +61,27 @@ export default function Configuration() {
code={`interface AgentConfig { code={`interface AgentConfig {
language?: 'en-US' | 'zh-CN' language?: 'en-US' | 'zh-CN'
/**
* Whether to prompt for next task after task completion
* @default true
*/
promptForNextTask?: boolean
/**
* Enable the UI panel for visual feedback and user interaction
* When disabled, the panel will not be created and all UI operations will be skipped.
* Useful for automated testing or when integrating PageAgent as a library.
* @default true
*/
enablePanel?: boolean
/**
* Enable the ask_user tool for agent to ask questions
* When disabled, the agent cannot ask user questions during execution.
* @default true
*/
enableAskUser?: boolean
/** Custom tools to extend or override built-in tools */ /** Custom tools to extend or override built-in tools */
customTools?: Record<string, PageAgentTool | null> customTools?: Record<string, PageAgentTool | null>
@@ -140,6 +161,39 @@ interface PageControllerConfig extends DomConfig {
code={`type PageAgentConfig = LLMConfig & AgentConfig & PageControllerConfig`} code={`type PageAgentConfig = LLMConfig & AgentConfig & PageControllerConfig`}
/> />
</section> </section>
{/* Programmatic Usage Example */}
<section className="mb-10">
<h2 className="text-2xl font-semibold mb-4">
{isZh ? '程序化使用配置' : 'Programmatic Usage'}
</h2>
<p className="text-gray-600 dark:text-gray-400 mb-4">
{isZh
? '对于程序化集成场景,可以禁用 UI。'
: 'For programmatic integration, you can disable UI.'}
</p>
<CodeEditor
language="typescript"
code={`const agent = new PageAgent({
baseURL: 'https://api.openai.com/v1',
apiKey: 'your-api-key',
model: 'your-model-name',
// Disable all UI features for pure programmatic usage
enablePanel: false, // Don't create Panel UI
enableMask: false, // Don't show visual overlay (mask and pointer)
// enableAskUser is automatically disabled when enablePanel is false
// Or keep Panel but disable post-task prompts
// enablePanel: true,
// promptForNextTask: false,
})
// Pure programmatic execution
const result = await agent.execute('search for TypeScript documentation')
console.log(result.success, result.data, result.history)`}
/>
</section>
</div> </div>
) )
} }
@@ -36,7 +36,7 @@ const pageAgentTool = {
}, },
execute: async (params) => { execute: async (params) => {
const result = await pageAgent.execute(params.instruction) const result = await pageAgent.execute(params.instruction)
return { success: result.success, message: result.message } return { success: result.success, message: result.data }
} }
} }
+26 -26
View File
@@ -1,29 +1,29 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false, "noEmit": false,
"allowImportingTsExtensions": false, "allowImportingTsExtensions": false,
"baseUrl": ".", "baseUrl": ".",
"outDir": "dist", "outDir": "dist",
"paths": { "paths": {
// Self root // Self root
"@/*": ["src/*"], "@/*": ["src/*"],
// Simplified monorepo solution (raw npm workspace with hoisting) // Simplified monorepo solution (raw npm workspace with hoisting)
"page-agent": ["../page-agent/src/PageAgent.ts"], "page-agent": ["../page-agent/src/PageAgent.ts"],
"@page-agent/llms": ["../llms/src/index.ts"], "@page-agent/llms": ["../llms/src/index.ts"],
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"], "@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
"@page-agent/ui": ["../ui/src/index.ts"] "@page-agent/ui": ["../ui/src/index.ts"]
} }
}, },
"include": ["**/*.ts", "**/*.tsx"], "include": ["**/*.ts", "**/*.tsx"],
"exclude": ["dist", "node_modules"], "exclude": ["dist", "node_modules"],
"references": [ "references": [
// //
{ "path": "../llms" }, { "path": "../llms" },
{ "path": "../page-agent" }, { "path": "../page-agent" },
{ "path": "../page-controller" }, { "path": "../page-controller" },
{ "path": "../ui" } { "path": "../ui" }
] ]
} }
+41 -41
View File
@@ -1,47 +1,47 @@
{ {
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"target": "ES2024", "target": "ES2024",
"useDefineForClassFields": true, "useDefineForClassFields": true,
"lib": ["ES2024", "DOM", "DOM.Iterable"], "lib": ["ES2024", "DOM", "DOM.Iterable"],
"module": "ESNext", "module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
"allowJs": true, "allowJs": true,
// "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", // "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
// "baseUrl": "src", // "baseUrl": "src",
"baseUrl": ".", "baseUrl": ".",
"outDir": "dist", "outDir": "dist",
// "incremental": true, // "incremental": true,
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
"verbatimModuleSyntax": false, "verbatimModuleSyntax": false,
"noEmit": true, "noEmit": true,
"jsx": "react-jsx", "jsx": "react-jsx",
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
/* Linting */ /* Linting */
"strict": true, "strict": true,
"noUnusedLocals": false, "noUnusedLocals": false,
"noUnusedParameters": false, "noUnusedParameters": false,
"erasableSyntaxOnly": true, "erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true "noUncheckedSideEffectImports": true
// "paths": { // "paths": {
// // Simplified monorepo solution (raw npm workspace with hoisting) // // Simplified monorepo solution (raw npm workspace with hoisting)
// "@page-agent/page-controller": ["./packages/page-controller/src/PageController.ts"], // "@page-agent/page-controller": ["./packages/page-controller/src/PageController.ts"],
// "page-agent": ["./packages/page-agent/src/PageAgent.ts"] // "page-agent": ["./packages/page-agent/src/PageAgent.ts"]
// } // }
} }
// "references": [ // "references": [
// { "path": "./packages/page-controller" }, // { "path": "./packages/page-controller" },
// { "path": "./packages/page-agent" }, // { "path": "./packages/page-agent" },
// { "path": "./packages/website" } // { "path": "./packages/website" }
// ], // ],
// "include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"], // "include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"],
// "exclude": ["node_modules", "dist", "packages/*/dist"] // "exclude": ["node_modules", "dist", "packages/*/dist"]
// "files": ["env.d.ts"] // "files": ["env.d.ts"]
// "files": [] // "files": []
} }
+10 -10
View File
@@ -1,12 +1,12 @@
{ {
"extends": "./tsconfig.base.json", "extends": "./tsconfig.base.json",
"references": [ "references": [
{ "path": "./packages/page-controller" }, { "path": "./packages/page-controller" },
{ "path": "./packages/ui" }, { "path": "./packages/ui" },
{ "path": "./packages/llms" }, { "path": "./packages/llms" },
{ "path": "./packages/page-agent" }, { "path": "./packages/page-agent" },
{ "path": "./packages/website" } { "path": "./packages/website" }
], ],
"include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"], "include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"],
"exclude": ["node_modules", "dist", "packages/*/dist"] "exclude": ["node_modules", "dist", "packages/*/dist"]
} }