Compare commits

...

10 Commits

Author SHA1 Message Date
Simon 3d014f15e7 chore(version): bump version to 1.5.8 2026-03-16 22:52:32 +08:00
Simon ce8f0fdbd8 Merge pull request #273 from alibaba/feat/extension-control-curr-tab-group
feat(ext): initial controlled group
2026-03-16 22:51:51 +08:00
Simon 48fede38fd feat(ext): initialTab should be in controlled group; rm windowId; rm gray color 2026-03-16 20:51:32 +08:00
Simon f303ed5fc5 Merge branch 'main' of https://github.com/alibaba/page-agent 2026-03-16 19:45:29 +08:00
Simon 6dbc33efd9 docs: limitation; readme; attribution 2026-03-16 19:45:14 +08:00
Simon 53628532df Merge pull request #251 from linked-danis/pr5-scrollintoview 2026-03-16 18:45:19 +08:00
Simon 2aae34d74a Merge pull request #250 from linked-danis/pr2-step-delay 2026-03-16 17:50:50 +08:00
Simon e27d1fb57f fix(style): Tailwind important flag 2026-03-16 17:35:32 +08:00
linked-danis 89546887bd fix: type-safe scrollIntoViewIfNeeded
Add proper interface for WebKit extension method.

Changes:
- Add ScrollableElement interface
- Use typeof check instead of 'as any' cast
2026-03-13 14:22:47 +01:00
linked-danis b0bcba2922 feat: add stepDelay config option
Add configurable delay between agent steps.
Previously hardcoded to 0.4s.

Changes:
- Add stepDelay?: number to AgentConfig
- Use config value with 0.4s default
2026-03-13 14:22:37 +01:00
21 changed files with 127 additions and 111 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
MIT License MIT License
Copyright (c) 2026 Alibaba Copyright (c) 2026 SimonLuvRamen
Copyright (c) 2026 Simon Copyright (c) 2026 Alibaba Group Holding Limited
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+7 -7
View File
@@ -5,13 +5,13 @@
<img alt="Page Agent Banner" src="https://img.alicdn.com/imgextra/i1/O1CN01NCMKXj1Gn4tkFTsxf_!!6000000000666-2-tps-1280-256.png"> <img alt="Page Agent Banner" src="https://img.alicdn.com/imgextra/i1/O1CN01NCMKXj1Gn4tkFTsxf_!!6000000000666-2-tps-1280-256.png">
</picture> </picture>
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) [![Downloads](https://img.shields.io/npm/dt/page-agent.svg)](https://www.npmjs.com/package/page-agent) [![Bundle Size](https://img.shields.io/bundlephobia/minzip/page-agent)](https://bundlephobia.com/package/page-agent) [![GitHub stars](https://img.shields.io/github/stars/alibaba/page-agent.svg)](https://github.com/alibaba/page-agent) [![License: MIT](https://img.shields.io/badge/License-MIT-auto.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) [![Bundle Size](https://img.shields.io/bundlephobia/minzip/page-agent)](https://bundlephobia.com/package/page-agent) [![Downloads](https://img.shields.io/npm/dt/page-agent.svg)](https://www.npmjs.com/package/page-agent) [![GitHub stars](https://img.shields.io/github/stars/alibaba/page-agent.svg)](https://github.com/alibaba/page-agent)
The GUI Agent Living in Your Webpage. Control web interfaces with natural language. The GUI Agent Living in Your Webpage. Control web interfaces with natural language.
🌐 **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://news.ycombinator.com/item?id=47264138" target="_blank"><b>📢 Join HN Discussion</b></a> | <a href="https://x.com/simonluvramen" target="_blank"><b>𝕏 Follow on X</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>📖 Docs</b></a> | <a href="https://news.ycombinator.com/item?id=47264138" target="_blank"><b>📢 HN Discussion</b></a> | <a href="https://x.com/simonluvramen" target="_blank"><b>𝕏 Follow on X</b></a>
<video id="demo-video" src="https://github.com/user-attachments/assets/a1f2eae2-13fb-4aae-98cf-a3fc1620a6c2" 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.5.7/dist/iife/page-agent.demo.js | | Global | https://cdn.jsdelivr.net/npm/page-agent@1.5.8/dist/iife/page-agent.demo.js |
| China | https://registry.npmmirror.com/page-agent/1.5.7/files/dist/iife/page-agent.demo.js | | China | https://registry.npmmirror.com/page-agent/1.5.8/files/dist/iife/page-agent.demo.js |
### NPM Installation ### NPM Installation
@@ -112,8 +112,8 @@ file and in the node_modules directory after installation.
<a href="https://www.star-history.com/?repos=alibaba%2Fpage-agent&type=date"> <a href="https://www.star-history.com/?repos=alibaba%2Fpage-agent&type=date">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&theme=dark&legend=top-left&v=6" /> <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&theme=dark&legend=top-left&v=7" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&legend=top-left&v=6" /> <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&legend=top-left&v=7" />
<img alt="Star History Chart" src="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&legend=top-left&v=6" /> <img alt="Star History Chart" src="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&legend=top-left&v=7" />
</picture> </picture>
</a> </a>
+7 -7
View File
@@ -5,13 +5,13 @@
<img alt="Page Agent Banner" src="https://img.alicdn.com/imgextra/i1/O1CN01NCMKXj1Gn4tkFTsxf_!!6000000000666-2-tps-1280-256.png"> <img alt="Page Agent Banner" src="https://img.alicdn.com/imgextra/i1/O1CN01NCMKXj1Gn4tkFTsxf_!!6000000000666-2-tps-1280-256.png">
</picture> </picture>
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) [![Downloads](https://img.shields.io/npm/dt/page-agent.svg)](https://www.npmjs.com/package/page-agent) [![Bundle Size](https://img.shields.io/bundlephobia/minzip/page-agent)](https://bundlephobia.com/package/page-agent) [![GitHub stars](https://img.shields.io/github/stars/alibaba/page-agent.svg)](https://github.com/alibaba/page-agent) [![License: MIT](https://img.shields.io/badge/License-MIT-auto.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) [![Bundle Size](https://img.shields.io/bundlephobia/minzip/page-agent)](https://bundlephobia.com/package/page-agent) [![Downloads](https://img.shields.io/npm/dt/page-agent.svg)](https://www.npmjs.com/package/page-agent) [![GitHub stars](https://img.shields.io/github/stars/alibaba/page-agent.svg)](https://github.com/alibaba/page-agent)
纯 JS 实现的 GUI agent。使用自然语言操作你的 Web 应用。无须后端、客户端、浏览器插件。 纯 JS 实现的 GUI agent。使用自然语言操作你的 Web 应用。无须后端、客户端、浏览器插件。
🌐 [English](../README.md) | **中文** 🌐 [English](../README.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://news.ycombinator.com/item?id=47264138" target="_blank"><b>📢 Join HN Discussion</b></a> | <a href="https://x.com/simonluvramen" target="_blank"><b>𝕏 Follow on X</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>📖 Docs</b></a> | <a href="https://news.ycombinator.com/item?id=47264138" target="_blank"><b>📢 HN Discussion</b></a> | <a href="https://x.com/simonluvramen" target="_blank"><b>𝕏 Follow on X</b></a>
<video id="demo-video" src="https://github.com/user-attachments/assets/a1f2eae2-13fb-4aae-98cf-a3fc1620a6c2" 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.5.7/dist/iife/page-agent.demo.js | | Global | https://cdn.jsdelivr.net/npm/page-agent@1.5.8/dist/iife/page-agent.demo.js |
| China | https://registry.npmmirror.com/page-agent/1.5.7/files/dist/iife/page-agent.demo.js | | China | https://registry.npmmirror.com/page-agent/1.5.8/files/dist/iife/page-agent.demo.js |
### NPM 安装 ### NPM 安装
@@ -110,8 +110,8 @@ file and in the node_modules directory after installation.
<a href="https://www.star-history.com/?repos=alibaba%2Fpage-agent&type=date"> <a href="https://www.star-history.com/?repos=alibaba%2Fpage-agent&type=date">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&theme=dark&legend=top-left&vv=6" /> <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&theme=dark&legend=top-left&v=7" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&legend=top-left&vv=6" /> <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&legend=top-left&v=7" />
<img alt="Star History Chart" src="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&legend=top-left&vv=6" /> <img alt="Star History Chart" src="https://api.star-history.com/image?repos=alibaba/page-agent&type=date&legend=top-left&v=7" />
</picture> </picture>
</a> </a>
+19 -19
View File
@@ -1,12 +1,12 @@
{ {
"name": "root", "name": "root",
"version": "1.5.7", "version": "1.5.8",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "root", "name": "root",
"version": "1.5.7", "version": "1.5.8",
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
@@ -11090,11 +11090,11 @@
}, },
"packages/core": { "packages/core": {
"name": "@page-agent/core", "name": "@page-agent/core",
"version": "1.5.7", "version": "1.5.8",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/llms": "1.5.7", "@page-agent/llms": "1.5.8",
"@page-agent/page-controller": "1.5.7", "@page-agent/page-controller": "1.5.8",
"chalk": "^5.6.2" "chalk": "^5.6.2"
}, },
"devDependencies": { "devDependencies": {
@@ -11106,13 +11106,13 @@
}, },
"packages/extension": { "packages/extension": {
"name": "@page-agent/ext", "name": "@page-agent/ext",
"version": "1.5.7", "version": "1.5.8",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@page-agent/core": "1.5.7", "@page-agent/core": "1.5.8",
"@page-agent/llms": "1.5.7", "@page-agent/llms": "1.5.8",
"@page-agent/page-controller": "1.5.7", "@page-agent/page-controller": "1.5.8",
"@page-agent/ui": "1.5.7", "@page-agent/ui": "1.5.8",
"ai-motion": "^0.4.8", "ai-motion": "^0.4.8",
"chalk": "^5.6.2" "chalk": "^5.6.2"
}, },
@@ -11150,7 +11150,7 @@
}, },
"packages/llms": { "packages/llms": {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "1.5.7", "version": "1.5.8",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chalk": "^5.6.2" "chalk": "^5.6.2"
@@ -11163,13 +11163,13 @@
} }
}, },
"packages/page-agent": { "packages/page-agent": {
"version": "1.5.7", "version": "1.5.8",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/core": "1.5.7", "@page-agent/core": "1.5.8",
"@page-agent/llms": "1.5.7", "@page-agent/llms": "1.5.8",
"@page-agent/page-controller": "1.5.7", "@page-agent/page-controller": "1.5.8",
"@page-agent/ui": "1.5.7", "@page-agent/ui": "1.5.8",
"chalk": "^5.6.2" "chalk": "^5.6.2"
}, },
"devDependencies": { "devDependencies": {
@@ -11181,7 +11181,7 @@
}, },
"packages/page-controller": { "packages/page-controller": {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "1.5.7", "version": "1.5.8",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ai-motion": "^0.4.8" "ai-motion": "^0.4.8"
@@ -11189,12 +11189,12 @@
}, },
"packages/ui": { "packages/ui": {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "1.5.7", "version": "1.5.8",
"license": "MIT" "license": "MIT"
}, },
"packages/website": { "packages/website": {
"name": "@page-agent/website", "name": "@page-agent/website",
"version": "1.5.7", "version": "1.5.8",
"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
View File
@@ -1,7 +1,7 @@
{ {
"name": "root", "name": "root",
"private": true, "private": true,
"version": "1.5.7", "version": "1.5.8",
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
+3 -3
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/core", "name": "@page-agent/core",
"private": false, "private": false,
"version": "1.5.7", "version": "1.5.8",
"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.5.7", "@page-agent/llms": "1.5.8",
"@page-agent/page-controller": "1.5.7" "@page-agent/page-controller": "1.5.8"
}, },
"peerDependencies": { "peerDependencies": {
"zod": "^3.25.0 || ^4.0.0" "zod": "^3.25.0 || ^4.0.0"
+6 -3
View File
@@ -1,5 +1,6 @@
/** /**
* Copyright (C) 2025 Alibaba Group Holding Limited * Copyright (C) 2025 Alibaba Group Holding Limited
* Copyright (C) 2026 SimonLuvRamen
* All rights reserved. * All rights reserved.
*/ */
import { InvokeError, LLM, type Tool } from '@page-agent/llms' import { InvokeError, LLM, type Tool } from '@page-agent/llms'
@@ -343,7 +344,7 @@ export class PageAgentCore extends EventTarget {
return result return result
} }
await waitFor(0.4) // @TODO: configurable await waitFor(this.config.stepDelay ?? 0.4)
} }
} }
@@ -511,7 +512,8 @@ export class PageAgentCore extends EventTarget {
// Accumulated wait time warning // Accumulated wait time warning
if (this.#states.totalWaitTime >= 3) { if (this.#states.totalWaitTime >= 3) {
this.pushObservation( this.pushObservation(
`You have waited ${this.#states.totalWaitTime} seconds accumulatively. DO NOT wait any longer unless you have a good reason.` `You have waited ${this.#states.totalWaitTime} seconds accumulatively. ` +
`DO NOT wait any longer unless you have a good reason.`
) )
} }
@@ -527,7 +529,8 @@ export class PageAgentCore extends EventTarget {
const remaining = this.config.maxSteps - step const remaining = this.config.maxSteps - step
if (remaining === 5) { if (remaining === 5) {
this.pushObservation( this.pushObservation(
`⚠️ Only ${remaining} steps remaining. Consider wrapping up or calling done with partial results.` `⚠️ Only ${remaining} steps remaining. ` +
`Consider wrapping up or calling done with partial results.`
) )
} else if (remaining === 2) { } else if (remaining === 2) {
this.pushObservation( this.pushObservation(
+6
View File
@@ -152,6 +152,12 @@ export interface AgentConfig extends LLMConfig {
* @experimental Use with caution - incorrect prompts may break agent behavior. * @experimental Use with caution - incorrect prompts may break agent behavior.
*/ */
customSystemPrompt?: string customSystemPrompt?: string
/**
* Delay between steps in seconds.
* @default 0.4
*/
stepDelay?: number
} }
/** /**
+5 -5
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/ext", "name": "@page-agent/ext",
"private": true, "private": true,
"version": "1.5.7", "version": "1.5.8",
"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.5.7", "@page-agent/core": "1.5.8",
"@page-agent/llms": "1.5.7", "@page-agent/llms": "1.5.8",
"@page-agent/page-controller": "1.5.7", "@page-agent/page-controller": "1.5.8",
"@page-agent/ui": "1.5.7", "@page-agent/ui": "1.5.8",
"ai-motion": "^0.4.8", "ai-motion": "^0.4.8",
"chalk": "^5.6.2" "chalk": "^5.6.2"
}, },
@@ -52,7 +52,7 @@ export function handleTabControlMessage(
.create({ url: payload.url, active: false }) .create({ url: payload.url, active: false })
.then((newTab) => { .then((newTab) => {
debug('open_new_tab: success', newTab) debug('open_new_tab: success', newTab)
sendResponse({ success: true, tabId: newTab.id, windowId: newTab.windowId }) sendResponse({ success: true, tabId: newTab.id })
}) })
.catch((error) => { .catch((error) => {
sendResponse({ error: error instanceof Error ? error.message : String(error) }) sendResponse({ error: error instanceof Error ? error.message : String(error) })
@@ -63,7 +63,7 @@ export function handleTabControlMessage(
case 'create_tab_group': { case 'create_tab_group': {
debug('create_tab_group', payload) debug('create_tab_group', payload)
chrome.tabs chrome.tabs
.group({ tabIds: payload.tabIds, createProperties: { windowId: payload.windowId } }) .group({ tabIds: payload.tabIds })
.then((groupId) => { .then((groupId) => {
debug('create_tab_group: success', groupId) debug('create_tab_group: success', groupId)
sendResponse({ success: true, groupId }) sendResponse({ success: true, groupId })
+31 -42
View File
@@ -27,7 +27,6 @@ export class TabsController extends EventTarget {
private initialTabId: number | null = null private initialTabId: number | null = null
private tabGroupId: number | null = null private tabGroupId: number | null = null
private task: string = '' private task: string = ''
private windowId: number | null = null
async init(task: string, includeInitialTab: boolean = true) { async init(task: string, includeInitialTab: boolean = true) {
debug('init', task, includeInitialTab) debug('init', task, includeInitialTab)
@@ -37,7 +36,6 @@ export class TabsController extends EventTarget {
this.currentTabId = null this.currentTabId = null
this.tabGroupId = null this.tabGroupId = null
this.initialTabId = null this.initialTabId = null
this.windowId = null
const result = await sendMessage({ const result = await sendMessage({
type: 'TAB_CONTROL', type: 'TAB_CONTROL',
@@ -53,7 +51,6 @@ export class TabsController extends EventTarget {
if (includeInitialTab) { if (includeInitialTab) {
this.currentTabId = this.initialTabId this.currentTabId = this.initialTabId
// update tab status immediately
const info = await sendMessage({ const info = await sendMessage({
type: 'TAB_CONTROL', type: 'TAB_CONTROL',
action: 'get_tab_info', action: 'get_tab_info',
@@ -67,6 +64,8 @@ export class TabsController extends EventTarget {
title: info.title, title: info.title,
status: info.status, status: info.status,
}) })
await this.createTabGroup([this.initialTabId])
} }
await this.updateCurrentTabId(this.currentTabId) await this.updateCurrentTabId(this.currentTabId)
@@ -132,9 +131,6 @@ export class TabsController extends EventTarget {
} }
const tabId = result.tabId as number const tabId = result.tabId as number
const windowId = result.windowId as number
this.windowId = windowId
this.tabs.push({ this.tabs.push({
id: tabId, id: tabId,
@@ -144,32 +140,7 @@ export class TabsController extends EventTarget {
await this.switchToTab(tabId) await this.switchToTab(tabId)
if (!this.tabGroupId) { if (!this.tabGroupId) {
const result = await sendMessage({ await this.createTabGroup([tabId])
type: 'TAB_CONTROL',
action: 'create_tab_group',
payload: { tabIds: [tabId], windowId: this.windowId },
})
if (!result.success) {
throw new Error(`Failed to create tab group: ${result.error}`)
}
const groupId = result.groupId as number
this.tabGroupId = groupId
await sendMessage({
type: 'TAB_CONTROL',
action: 'update_tab_group',
payload: {
groupId: this.tabGroupId,
properties: {
title: `PageAgent(${this.task})`,
color: randomColor(),
collapsed: false,
},
},
})
} else { } else {
await sendMessage({ await sendMessage({
type: 'TAB_CONTROL', type: 'TAB_CONTROL',
@@ -230,6 +201,33 @@ export class TabsController extends EventTarget {
} }
} }
private async createTabGroup(tabIds: number[]) {
const result = await sendMessage({
type: 'TAB_CONTROL',
action: 'create_tab_group',
payload: { tabIds },
})
if (!result?.success) {
throw new Error(`Failed to create tab group: ${result?.error}`)
}
this.tabGroupId = result.groupId as number
await sendMessage({
type: 'TAB_CONTROL',
action: 'update_tab_group',
payload: {
groupId: this.tabGroupId,
properties: {
title: `PageAgent(${this.task})`,
color: randomColor(),
collapsed: false,
},
},
})
}
async updateCurrentTabId(tabId: number | null) { async updateCurrentTabId(tabId: number | null) {
debug('updateCurrentTabId', tabId) debug('updateCurrentTabId', tabId)
@@ -309,16 +307,7 @@ interface TabMeta {
status?: 'loading' | 'unloaded' | 'complete' status?: 'loading' | 'unloaded' | 'complete'
} }
const TAB_GROUP_COLORS = [ const TAB_GROUP_COLORS = ['blue', 'red', 'yellow', 'green', 'pink', 'purple', 'cyan'] as const
'grey',
'blue',
'red',
'yellow',
'green',
'pink',
'purple',
'cyan',
] as const
type TabGroupColor = (typeof TAB_GROUP_COLORS)[number] type TabGroupColor = (typeof TAB_GROUP_COLORS)[number]
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "1.5.7", "version": "1.5.8",
"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",
+5 -5
View File
@@ -1,7 +1,7 @@
{ {
"name": "page-agent", "name": "page-agent",
"private": false, "private": false,
"version": "1.5.7", "version": "1.5.8",
"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.5.7", "@page-agent/core": "1.5.8",
"@page-agent/llms": "1.5.7", "@page-agent/llms": "1.5.8",
"@page-agent/page-controller": "1.5.7", "@page-agent/page-controller": "1.5.8",
"@page-agent/ui": "1.5.7", "@page-agent/ui": "1.5.8",
"chalk": "^5.6.2" "chalk": "^5.6.2"
}, },
"peerDependencies": { "peerDependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "1.5.7", "version": "1.5.8",
"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 -3
View File
@@ -213,14 +213,18 @@ export async function selectOptionElement(selectElement: HTMLSelectElement, opti
await waitFor(0.1) // Wait to ensure change event processing completes await waitFor(0.1) // Wait to ensure change event processing completes
} }
interface ScrollableElement extends HTMLElement {
scrollIntoViewIfNeeded?: (centerIfNeeded?: boolean) => void
}
export async function scrollIntoViewIfNeeded(element: HTMLElement) { export async function scrollIntoViewIfNeeded(element: HTMLElement) {
const el = element as any const el = element as ScrollableElement
if (el.scrollIntoViewIfNeeded) { if (typeof el.scrollIntoViewIfNeeded === 'function') {
el.scrollIntoViewIfNeeded() el.scrollIntoViewIfNeeded()
// await waitFor(0.5) // Animation playback // await waitFor(0.5) // Animation playback
} else { } else {
// @todo visibility check // @todo visibility check
el.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' }) element.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' })
// await waitFor(0.5) // Animation playback // await waitFor(0.5) // Animation playback
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "1.5.7", "version": "1.5.8",
"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 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/website", "name": "@page-agent/website",
"private": true, "private": true,
"version": "1.5.7", "version": "1.5.8",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 0.0.0.0", "dev": "vite --host 0.0.0.0",
+14 -3
View File
@@ -12,9 +12,20 @@ export default function Footer() {
> >
<div className="max-w-7xl mx-auto px-6 py-6"> <div className="max-w-7xl mx-auto px-6 py-6">
<div className="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0"> <div className="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0">
<p className="text-gray-600 dark:text-gray-300 text-sm"> <div className="text-gray-600 dark:text-gray-300 text-sm text-center md:text-left">
© 2026 page-agent. All rights reserved. <p>© 2026 page-agent. All rights reserved.</p>
</p> <p>
Built with by{' '}
<a
href="https://x.com/simonluvramen"
target="_blank"
rel="noopener noreferrer"
className="hover:text-gray-900 dark:hover:text-white transition-colors duration-200"
>
Simon
</a>
</p>
</div>
<div className="flex items-center space-x-6"> <div className="flex items-center space-x-6">
<a <a
+2 -2
View File
@@ -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.5.7/dist/iife/page-agent.demo.js' 'https://cdn.jsdelivr.net/npm/page-agent@1.5.8/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.5.7/files/dist/iife/page-agent.demo.js' 'https://registry.npmmirror.com/page-agent/1.5.8/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'
+1 -1
View File
@@ -1,4 +1,4 @@
@import 'tailwindcss'; @import 'tailwindcss' important;
@import 'tw-animate-css'; @import 'tw-animate-css';
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@@ -116,6 +116,9 @@ export default function LimitationsPage() {
isZh ? '键盘快捷键' : 'Keyboard shortcuts', isZh ? '键盘快捷键' : 'Keyboard shortcuts',
isZh ? '坐标定位操作' : 'Position-based control', isZh ? '坐标定位操作' : 'Position-based control',
isZh ? '绘图操作' : 'Drawing', isZh ? '绘图操作' : 'Drawing',
isZh
? 'Monaco、CodeMirror 等需要通过 JS 实例控制的编辑器'
: 'Monaco, CodeMirror and other editors that require JS instance access',
].map((text) => ( ].map((text) => (
<li key={text} className="flex items-center text-gray-700 dark:text-gray-300"> <li key={text} className="flex items-center text-gray-700 dark:text-gray-300">
<span className="mr-2 text-red-600 dark:text-red-400"></span> <span className="mr-2 text-red-600 dark:text-red-400"></span>
@@ -128,8 +131,8 @@ export default function LimitationsPage() {
</div> </div>
{/* Understanding Limitations */} {/* Understanding Limitations */}
<Heading id="understanding" className="text-2xl font-bold mb-3 mt-6"> <Heading id="text-based-approach" className="text-2xl font-bold mb-3 mt-6">
{isZh ? '理解能力' : 'Understanding'} {isZh ? '基于文本的方案' : 'Text-Based Approach'}
</Heading> </Heading>
<p className="mb-2 font-medium"> <p className="mb-2 font-medium">