Compare commits

...

2 Commits

Author SHA1 Message Date
Simon 7a97de2a37 feat(ext): expose more config 2026-03-05 20:34:55 +08:00
Simon 19b03b83ea chore(version): bump version to 1.5.1 2026-03-05 19:28:19 +08:00
15 changed files with 171 additions and 76 deletions
+2 -2
View File
@@ -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.1/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.1/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).
+2 -2
View File
@@ -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.1/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.1/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)。
+18 -18
View File
@@ -1,12 +1,12 @@
{ {
"name": "root", "name": "root",
"version": "1.4.4", "version": "1.5.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "root", "name": "root",
"version": "1.4.4", "version": "1.5.1",
"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.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/llms": "1.4.4", "@page-agent/llms": "1.5.1",
"@page-agent/page-controller": "1.4.4", "@page-agent/page-controller": "1.5.1",
"chalk": "^5.6.2" "chalk": "^5.6.2"
}, },
"devDependencies": { "devDependencies": {
@@ -11132,10 +11132,10 @@
"version": "0.1.8", "version": "0.1.8",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@page-agent/core": "1.4.4", "@page-agent/core": "1.5.1",
"@page-agent/llms": "1.4.4", "@page-agent/llms": "1.5.1",
"@page-agent/page-controller": "1.4.4", "@page-agent/page-controller": "1.5.1",
"@page-agent/ui": "1.4.4", "@page-agent/ui": "1.5.1",
"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.1",
"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.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/core": "1.4.4", "@page-agent/core": "1.5.1",
"@page-agent/llms": "1.4.4", "@page-agent/llms": "1.5.1",
"@page-agent/page-controller": "1.4.4", "@page-agent/page-controller": "1.5.1",
"@page-agent/ui": "1.4.4", "@page-agent/ui": "1.5.1",
"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.1",
"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.1",
"license": "MIT" "license": "MIT"
}, },
"packages/website": { "packages/website": {
"name": "@page-agent/website", "name": "@page-agent/website",
"version": "1.4.4", "version": "1.5.1",
"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.4.4", "version": "1.5.1",
"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.4.4", "version": "1.5.1",
"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.1",
"@page-agent/page-controller": "1.4.4" "@page-agent/page-controller": "1.5.1"
}, },
"peerDependencies": { "peerDependencies": {
"zod": "^3.25.0 || ^4.0.0" "zod": "^3.25.0 || ^4.0.0"
+1 -1
View File
@@ -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)
+4 -4
View File
@@ -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.1",
"@page-agent/llms": "1.4.4", "@page-agent/llms": "1.5.1",
"@page-agent/page-controller": "1.4.4", "@page-agent/page-controller": "1.5.1",
"@page-agent/ui": "1.4.4", "@page-agent/ui": "1.5.1",
"ai-motion": "^0.4.8", "ai-motion": "^0.4.8",
"chalk": "^5.6.2" "chalk": "^5.6.2"
}, },
+35 -13
View File
@@ -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 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "1.4.4", "version": "1.5.1",
"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.4.4", "version": "1.5.1",
"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.1",
"@page-agent/llms": "1.4.4", "@page-agent/llms": "1.5.1",
"@page-agent/page-controller": "1.4.4", "@page-agent/page-controller": "1.5.1",
"@page-agent/ui": "1.4.4", "@page-agent/ui": "1.5.1",
"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.4.4", "version": "1.5.1",
"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",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "1.4.4", "version": "1.5.1",
"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.4.4", "version": "1.5.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 0.0.0.0", "dev": "vite --host 0.0.0.0",
+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.4.4/dist/iife/page-agent.demo.js' 'https://cdn.jsdelivr.net/npm/page-agent@1.5.1/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.1/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'