diff --git a/packages/page-agent/package.json b/packages/page-agent/package.json new file mode 100644 index 0000000..b0224a0 --- /dev/null +++ b/packages/page-agent/package.json @@ -0,0 +1,53 @@ +{ + "name": "page-agent", + "private": false, + "version": "0.2.5", + "type": "module", + "main": "./dist/esm/page-agent.js", + "module": "./dist/esm/page-agent.js", + "types": "./dist/esm/PageAgent.d.ts", + "exports": { + ".": { + "types": "./dist/esm/PageAgent.d.ts", + "import": "./dist/esm/page-agent.js", + "default": "./dist/esm/page-agent.js" + } + }, + "files": [ + "dist/" + ], + "description": "GUI agent for web applications - add intelligent automation to any webpage with a single script", + "keywords": [ + "ai", + "automation", + "ui-agent", + "GUI-agent", + "browser-automation", + "web-agent", + "llm", + "dom-interaction", + "web-automation", + "GUI-simulation" + ], + "author": "Simon", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/alibaba/page-agent.git" + }, + "homepage": "https://alibaba.github.io/page-agent/", + "scripts": { + "build": "vite build", + "dev:iife": "concurrently \"vite build --config vite.iife.config.js --watch\" \"npx serve dist/iife -p 5174\"", + "prepublishOnly": "node -e \"const fs=require('fs');['README.md','LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"", + "postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\"" + }, + "dependencies": { + "chalk": "^5.6.2", + "zod": "^4.3.5", + "@page-agent/llms": "0.2.5", + "@page-agent/page-controller": "0.2.5", + "@page-agent/core": "0.2.5", + "@page-agent/ui": "0.2.5" + } +} diff --git a/packages/page-agent/src/PageAgent.ts b/packages/page-agent/src/PageAgent.ts new file mode 100644 index 0000000..31ef902 --- /dev/null +++ b/packages/page-agent/src/PageAgent.ts @@ -0,0 +1,19 @@ +/** + * Copyright (C) 2025 Alibaba Group Holding Limited + * All rights reserved. + */ +import { type PageAgentConfig, PageAgentCore } from '@page-agent/core' +import { Panel } from '@page-agent/ui' + +export type { PageAgentConfig } + +export class PageAgent extends PageAgentCore { + panel: Panel + + constructor(config: PageAgentConfig) { + super(config) + this.panel = new Panel(this, { + language: config.language, + }) + } +} diff --git a/packages/page-agent/src/env.d.ts b/packages/page-agent/src/env.d.ts new file mode 100644 index 0000000..21d2cd5 --- /dev/null +++ b/packages/page-agent/src/env.d.ts @@ -0,0 +1,9 @@ +/// +import type { PageAgent } from './PageAgent' + +declare global { + interface Window { + pageAgent?: PageAgent + PageAgent: typeof PageAgent + } +} diff --git a/packages/page-agent/src/iife.ts b/packages/page-agent/src/iife.ts new file mode 100644 index 0000000..81830ed --- /dev/null +++ b/packages/page-agent/src/iife.ts @@ -0,0 +1,52 @@ +/** + * Auto-run entry for page-agent.js. Insert this script into your page to get page-agent functionality. + */ +import { Panel } from '@page-agent/ui' + +import { PageAgent, type PageAgentConfig } from './PageAgent' + +// Clean up existing instances to prevent multiple injections from bookmarklet +if (window.pageAgent) { + window.pageAgent.dispose() +} + +// Mount to global window object +window.PageAgent = PageAgent + +// Export for ES module usage +// export { PageAgent } + +console.log('🚀 page-agent.js loaded!') + +const DEMO_MODEL = 'PAGE-AGENT-FREE-TESTING-RANDOM' +const DEMO_BASE_URL = 'https://hwcxiuzfylggtcktqgij.supabase.co/functions/v1/llm-testing-proxy' +const DEMO_API_KEY = 'PAGE-AGENT-FREE-TESTING-RANDOM' + +// in case document.x is not ready yet +// @todo give a switch to disable auto-init +setTimeout(() => { + const currentScript = document.currentScript as HTMLScriptElement | null + let config: PageAgentConfig + + if (currentScript) { + console.log('🚀 page-agent.js detected current script:', currentScript.src) + const url = new URL(currentScript.src) + const model = url.searchParams.get('model') || DEMO_MODEL + const baseURL = url.searchParams.get('baseURL') || DEMO_BASE_URL + const apiKey = url.searchParams.get('apiKey') || DEMO_API_KEY + const language = (url.searchParams.get('lang') as 'zh-CN' | 'en-US') || 'zh-CN' + config = { model, baseURL, apiKey, language } + } else { + console.log('🚀 page-agent.js no current script detected, using default demo config') + config = { + model: import.meta.env.LLM_MODEL_NAME ? import.meta.env.LLM_MODEL_NAME : DEMO_MODEL, + baseURL: import.meta.env.LLM_BASE_URL ? import.meta.env.LLM_BASE_URL : DEMO_BASE_URL, + apiKey: import.meta.env.LLM_API_KEY ? import.meta.env.LLM_API_KEY : DEMO_API_KEY, + } + } + + // Create agent + window.pageAgent = new PageAgent(config) + + console.log('🚀 page-agent.js initialized with config:', window.pageAgent.config) +}) diff --git a/packages/page-agent/tsconfig.dts.json b/packages/page-agent/tsconfig.dts.json new file mode 100644 index 0000000..70eceb9 --- /dev/null +++ b/packages/page-agent/tsconfig.dts.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + // @workaround DTS bug + // dts do not work with monorepo path mapping + // disable path mapping for it + "paths": {} + } +} diff --git a/packages/page-agent/tsconfig.json b/packages/page-agent/tsconfig.json new file mode 100644 index 0000000..8f1362c --- /dev/null +++ b/packages/page-agent/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", + "noEmit": false, + "allowImportingTsExtensions": false, + "baseUrl": ".", + "outDir": "dist", + "paths": { + // + "@page-agent/llms": ["../llms/src/index.ts"], + "@page-agent/page-controller": ["../page-controller/src/PageController.ts"], + "@page-agent/core": ["../core/src/PageAgentCore.ts"], + "@page-agent/ui": ["../ui/src/index.ts"] + } + }, + "include": ["**/*.ts"], + "exclude": ["dist", "node_modules"], + "references": [ + // + { "path": "../llms" }, + { "path": "../page-controller" }, + { "path": "../core" }, + { "path": "../ui" } + ] +} diff --git a/packages/page-agent/vite.config.js b/packages/page-agent/vite.config.js new file mode 100644 index 0000000..bc210ec --- /dev/null +++ b/packages/page-agent/vite.config.js @@ -0,0 +1,44 @@ +// @ts-check +import { dirname, resolve } from 'path' +import dts from 'unplugin-dts/vite' +import { fileURLToPath } from 'url' +import { defineConfig } from 'vite' +import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js' + +const __dirname = dirname(fileURLToPath(import.meta.url)) + +// ES Module for NPM Package +export default defineConfig({ + clearScreen: false, + plugins: [ + dts({ tsconfigPath: './tsconfig.dts.json', bundleTypes: true }), + cssInjectedByJsPlugin({ relativeCSSInjection: true }), + ], + publicDir: false, + esbuild: { + keepNames: true, + }, + build: { + lib: { + entry: resolve(__dirname, 'src/PageAgent.ts'), + name: 'PageAgent', + fileName: 'page-agent', + formats: ['es'], + }, + outDir: resolve(__dirname, 'dist', 'esm'), + rollupOptions: { + external: [ + 'chalk', + 'zod', + // all the internal packages + /^@page-agent\//, + ], + }, + minify: false, + sourcemap: true, + cssCodeSplit: true, + }, + define: { + 'process.env.NODE_ENV': '"production"', + }, +}) diff --git a/packages/page-agent/vite.iife.config.js b/packages/page-agent/vite.iife.config.js new file mode 100644 index 0000000..cf53902 --- /dev/null +++ b/packages/page-agent/vite.iife.config.js @@ -0,0 +1,57 @@ +// @ts-check +import { config as dotenvConfig } from 'dotenv' +import { dirname, resolve } from 'path' +import { fileURLToPath } from 'url' +import { defineConfig } from 'vite' +import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js' + +const __dirname = dirname(fileURLToPath(import.meta.url)) + +// Load .env from repo root +dotenvConfig({ path: resolve(__dirname, '../../.env') }) + +// UMD Bundle for CDN +// - alias all local packages so that they can be build in +// - no external +// - no d.ts. dts does not work with monorepo aliasing +export default defineConfig(({ mode }) => ({ + plugins: [cssInjectedByJsPlugin({ relativeCSSInjection: true })], + publicDir: false, + esbuild: { + keepNames: true, + }, + resolve: { + alias: { + '@page-agent/page-controller': resolve(__dirname, '../page-controller/src/PageController.ts'), + '@page-agent/llms': resolve(__dirname, '../llms/src/index.ts'), + '@page-agent/core': resolve(__dirname, '../core/src/PageAgentCore.ts'), + '@page-agent/ui': resolve(__dirname, '../ui/src/index.ts'), + }, + }, + build: { + lib: { + entry: resolve(__dirname, 'src/iife.ts'), + name: 'PageAgent', + fileName: 'page-agent', + formats: ['iife'], + }, + outDir: resolve(__dirname, 'dist', 'iife'), + cssCodeSplit: true, + minify: false, + rollupOptions: { + output: { + // force use .js as extension + entryFileNames: 'page-agent.js', + }, + onwarn: function (message, handler) { + if (message.code === 'EVAL') return + handler(message) + }, + }, + }, + define: { + 'import.meta.env.LLM_MODEL_NAME': JSON.stringify(process.env.LLM_MODEL_NAME), + 'import.meta.env.LLM_API_KEY': JSON.stringify(process.env.LLM_API_KEY), + 'import.meta.env.LLM_BASE_URL': JSON.stringify(process.env.LLM_BASE_URL), + }, +})) diff --git a/packages/website/src/pages/Home.tsx b/packages/website/src/pages/Home.tsx index 9955387..ba2c37a 100644 --- a/packages/website/src/pages/Home.tsx +++ b/packages/website/src/pages/Home.tsx @@ -1,5 +1,4 @@ /* eslint-disable react-dom/no-dangerously-set-innerhtml */ -import { Panel } from '@page-agent/ui' import { Bot, Box, MessageSquare, PlayCircle, Shield, Sparkles, Users, Zap } from 'lucide-react' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -95,10 +94,6 @@ export default function HomePage() { // promptForNextTask: false, // enablePanel: false, }) - - // Create and bind Panel - const panel = new Panel(win.pageAgent, { language: i18n.language as any }) - panel.show() } const result = await win.pageAgent.execute(task) diff --git a/packages/website/tsconfig.json b/packages/website/tsconfig.json index 33a054a..9e1dda9 100644 --- a/packages/website/tsconfig.json +++ b/packages/website/tsconfig.json @@ -10,11 +10,12 @@ // Self root "@/*": ["src/*"], - // Simplified monorepo solution (raw npm workspace with hoisting) - "page-agent": ["../page-agent/src/PageAgent.ts"], "@page-agent/llms": ["../llms/src/index.ts"], "@page-agent/page-controller": ["../page-controller/src/PageController.ts"], - "@page-agent/ui": ["../ui/src/index.ts"] + "@page-agent/core": ["../core/src/PageAgentCore.ts"], + "@page-agent/ui": ["../ui/src/index.ts"], + + "page-agent": ["../page-agent/src/PageAgent.ts"] } }, "include": ["**/*.ts", "**/*.tsx"], @@ -22,8 +23,10 @@ "references": [ // { "path": "../llms" }, - { "path": "../page-agent" }, { "path": "../page-controller" }, - { "path": "../ui" } + { "path": "../core" }, + { "path": "../ui" }, + + { "path": "../page-agent" } ] } diff --git a/packages/website/vite.config.js b/packages/website/vite.config.js index fcc24a5..df7e831 100644 --- a/packages/website/vite.config.js +++ b/packages/website/vite.config.js @@ -36,9 +36,11 @@ export default defineConfig(({ mode }) => ({ '@': resolve(__dirname, 'src'), // Monorepo packages (always bundle local code instead of npm versions) - '@page-agent/llms': resolve(__dirname, '../llms/src/index.ts'), '@page-agent/page-controller': resolve(__dirname, '../page-controller/src/PageController.ts'), + '@page-agent/llms': resolve(__dirname, '../llms/src/index.ts'), + '@page-agent/core': resolve(__dirname, '../core/src/PageAgentCore.ts'), '@page-agent/ui': resolve(__dirname, '../ui/src/index.ts'), + 'page-agent': resolve(__dirname, '../page-agent/src/PageAgent.ts'), }, },