From fe82b11285593df08c6449fe3cdd8f9aac212706 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Thu, 19 Mar 2026 19:50:05 +0800 Subject: [PATCH] feat: AK optional --- docs/CHANGELOG.md | 36 ----------------- packages/extension/docs/extension_api.md | 4 +- packages/extension/src/agent/constants.ts | 4 +- .../extension/src/components/ConfigPanel.tsx | 10 ++--- .../extension/src/entrypoints/main-world.ts | 5 +-- packages/llms/src/OpenAIClient.ts | 2 +- packages/llms/src/index.ts | 6 +-- packages/llms/src/types.ts | 2 +- packages/mcp/src/index.js | 2 +- packages/website/src/constants.ts | 2 +- .../docs/advanced/page-agent-core/page.tsx | 12 +++--- .../docs/features/chrome-extension/page.tsx | 39 ++----------------- .../src/pages/docs/features/models/page.tsx | 4 +- .../website/src/pages/home/HeroSection.tsx | 4 +- 14 files changed, 30 insertions(+), 102 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c48457f..ec28538 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -153,42 +153,6 @@ PageAgent is now ready for production use. The API is stable and breaking change - **Ask User Tool** - Agent can ask users for clarification - **i18n Support** - English and Chinese localization -### Configuration - -```typescript -// Version 1.0.0 -interface PageAgentConfig { - // LLM Configuration (required) - baseURL: string - apiKey: string - model: string - temperature?: number - maxRetries?: number - customFetch?: typeof fetch - - // Agent Configuration - language?: 'en-US' | 'zh-CN' - maxSteps?: number // default: 20 - customTools?: Record // experimental - instructions?: InstructionsConfig - transformPageContent?: (content: string) => string | Promise - experimentalScriptExecutionTool?: boolean // default: false - - // Lifecycle Hooks (experimental) - onBeforeTask?: (agent, result) => void - onAfterTask?: (agent, result) => void - onBeforeStep?: (agent, stepCount) => void - onAfterStep?: (agent, history) => void - onDispose?: (agent, reason?) => void - - // Page Controller Configuration - enableMask?: boolean // default: true - viewportExpansion?: number - interactiveBlacklist?: Element[] - interactiveWhitelist?: Element[] -} -``` - ### Packages | Package | Description | diff --git a/packages/extension/docs/extension_api.md b/packages/extension/docs/extension_api.md index c4671f3..d49272d 100644 --- a/packages/extension/docs/extension_api.md +++ b/packages/extension/docs/extension_api.md @@ -115,8 +115,8 @@ import type { export interface ExecuteConfig { baseURL: string - apiKey: string model: string + apiKey?: string // Include the initial tab where page JS starts. Default: true. includeInitialTab?: boolean @@ -205,8 +205,8 @@ import type { interface ExecuteConfig { baseURL: string - apiKey: string model: string + apiKey?: string includeInitialTab?: boolean onStatusChange?: (status: AgentStatus) => void onActivity?: (activity: AgentActivity) => void diff --git a/packages/extension/src/agent/constants.ts b/packages/extension/src/agent/constants.ts index 0b90164..7ddaa1a 100644 --- a/packages/extension/src/agent/constants.ts +++ b/packages/extension/src/agent/constants.ts @@ -3,12 +3,12 @@ import type { LLMConfig } from '@page-agent/llms' // Demo LLM for testing export const DEMO_MODEL = 'qwen3.5-plus' export const DEMO_BASE_URL = 'https://page-ag-testing-ohftxirgbn.cn-shanghai.fcapp.run' -export const DEMO_API_KEY = 'NA' +// export const DEMO_API_KEY = 'NA' export const DEMO_CONFIG: LLMConfig = { - apiKey: DEMO_API_KEY, baseURL: DEMO_BASE_URL, model: DEMO_MODEL, + // apiKey: DEMO_API_KEY, } /** Legacy testing endpoints that should be auto-migrated to DEMO_BASE_URL */ diff --git a/packages/extension/src/components/ConfigPanel.tsx b/packages/extension/src/components/ConfigPanel.tsx index 60b6cbb..1e6f1ed 100644 --- a/packages/extension/src/components/ConfigPanel.tsx +++ b/packages/extension/src/components/ConfigPanel.tsx @@ -14,7 +14,7 @@ import { import { useEffect, useState } from 'react' import { siGithub } from 'simple-icons' -import { DEMO_API_KEY, DEMO_BASE_URL, DEMO_MODEL, isTestingEndpoint } from '@/agent/constants' +import { DEMO_BASE_URL, DEMO_MODEL, isTestingEndpoint } from '@/agent/constants' import type { ExtConfig, LanguagePreference } from '@/agent/useAgent' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' @@ -27,9 +27,9 @@ interface ConfigPanelProps { } export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { - const [apiKey, setApiKey] = useState(config?.apiKey || DEMO_API_KEY) const [baseURL, setBaseURL] = useState(config?.baseURL || DEMO_BASE_URL) const [model, setModel] = useState(config?.model || DEMO_MODEL) + const [apiKey, setApiKey] = useState(config?.apiKey) const [language, setLanguage] = useState(config?.language) const [maxSteps, setMaxSteps] = useState(config?.maxSteps) const [systemInstruction, setSystemInstruction] = useState(config?.systemInstruction ?? '') @@ -44,9 +44,9 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { const [showApiKey, setShowApiKey] = useState(false) useEffect(() => { - setApiKey(config?.apiKey || DEMO_API_KEY) setBaseURL(config?.baseURL || DEMO_BASE_URL) setModel(config?.model || DEMO_MODEL) + setApiKey(config?.apiKey) setLanguage(config?.language) setMaxSteps(config?.maxSteps) setSystemInstruction(config?.systemInstruction ?? '') @@ -194,7 +194,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
setModel(e.target.value)} className="text-xs h-8" @@ -206,7 +206,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
setApiKey(e.target.value)} className="text-xs h-8" diff --git a/packages/extension/src/entrypoints/main-world.ts b/packages/extension/src/entrypoints/main-world.ts index 8433faa..fd93e68 100644 --- a/packages/extension/src/entrypoints/main-world.ts +++ b/packages/extension/src/entrypoints/main-world.ts @@ -4,8 +4,8 @@ export type Execute = (task: string, config: ExecuteConfig) => Promise { if (task.trim().length === 0) throw new Error('Task cannot be empty') if (!config) throw new Error('Config is required') if (!config.baseURL) throw new Error('Config must have a baseURL') - if (!config.apiKey) throw new Error('Config must have an apiKey') if (!config.model) throw new Error('Config must have a model') const id = getId() @@ -85,8 +84,8 @@ export default defineUnlistedScript(() => { task, config: { baseURL: config.baseURL, - apiKey: config.apiKey, model: config.model, + apiKey: config.apiKey, includeInitialTab: config.includeInitialTab, }, }, diff --git a/packages/llms/src/OpenAIClient.ts b/packages/llms/src/OpenAIClient.ts index b78ba44..3009aca 100644 --- a/packages/llms/src/OpenAIClient.ts +++ b/packages/llms/src/OpenAIClient.ts @@ -50,7 +50,7 @@ export class OpenAIClient implements LLMClient { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${this.config.apiKey}`, + ...(this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }), }, body: JSON.stringify(requestBody), signal: abortSignal, diff --git a/packages/llms/src/index.ts b/packages/llms/src/index.ts index 0a1cad3..242389f 100644 --- a/packages/llms/src/index.ts +++ b/packages/llms/src/index.ts @@ -8,17 +8,17 @@ export type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool } export function parseLLMConfig(config: LLMConfig): Required { // Runtime validation as defensive programming (types already guarantee these) - if (!config.baseURL || !config.apiKey || !config.model) { + if (!config.baseURL || !config.model) { throw new Error( - '[PageAgent] LLM configuration required. Please provide: baseURL, apiKey, model. ' + + '[PageAgent] LLM configuration required. Please provide: baseURL, model. ' + 'See: https://alibaba.github.io/page-agent/docs/features/models' ) } return { baseURL: config.baseURL, - apiKey: config.apiKey, model: config.model, + apiKey: config.apiKey || '', temperature: config.temperature ?? DEFAULT_TEMPERATURE, maxRetries: config.maxRetries ?? LLM_MAX_RETRIES, customFetch: (config.customFetch ?? fetch).bind(globalThis), // fetch will be illegal unless bound diff --git a/packages/llms/src/types.ts b/packages/llms/src/types.ts index 857375a..df609fa 100644 --- a/packages/llms/src/types.ts +++ b/packages/llms/src/types.ts @@ -89,8 +89,8 @@ export interface InvokeResult { */ export interface LLMConfig { baseURL: string - apiKey: string model: string + apiKey?: string temperature?: number maxRetries?: number diff --git a/packages/mcp/src/index.js b/packages/mcp/src/index.js index f0bfb94..d88211e 100755 --- a/packages/mcp/src/index.js +++ b/packages/mcp/src/index.js @@ -12,9 +12,9 @@ const port = parseInt(env.PORT || '38401') /** @type {Record} */ const llmConfig = {} -if (env.LLM_API_KEY) llmConfig.apiKey = env.LLM_API_KEY if (env.LLM_BASE_URL) llmConfig.baseURL = env.LLM_BASE_URL if (env.LLM_MODEL_NAME) llmConfig.model = env.LLM_MODEL_NAME +if (env.LLM_API_KEY) llmConfig.apiKey = env.LLM_API_KEY // --- Hub bridge (HTTP + WebSocket) --- diff --git a/packages/website/src/constants.ts b/packages/website/src/constants.ts index 6186ce1..29a82f8 100644 --- a/packages/website/src/constants.ts +++ b/packages/website/src/constants.ts @@ -7,4 +7,4 @@ export const CDN_DEMO_CN_URL = // Demo LLM for website testing (homepage quick trial uses flash) export const DEMO_MODEL = 'qwen3.5-flash' export const DEMO_BASE_URL = 'https://page-ag-testing-ohftxirgbn.cn-shanghai.fcapp.run' -export const DEMO_API_KEY = 'NA' +// export const DEMO_API_KEY = '' diff --git a/packages/website/src/pages/docs/advanced/page-agent-core/page.tsx b/packages/website/src/pages/docs/advanced/page-agent-core/page.tsx index fe6da03..3930227 100644 --- a/packages/website/src/pages/docs/advanced/page-agent-core/page.tsx +++ b/packages/website/src/pages/docs/advanced/page-agent-core/page.tsx @@ -129,12 +129,6 @@ const result = await agent.execute('Fill in the form with test data')`} ? 'LLM API 的基础 URL(如 https://api.openai.com/v1)' : 'Base URL of the LLM API (e.g., https://api.openai.com/v1)', }, - { - name: 'apiKey', - type: 'string', - required: true, - description: isZh ? 'API 密钥' : 'API key for authentication', - }, { name: 'model', type: 'string', @@ -143,6 +137,12 @@ const result = await agent.execute('Fill in the form with test data')`} ? '模型名称(如 gpt-5.2, anthropic/claude-4.5-haiku)' : 'Model name (e.g., gpt-5.2, anthropic/claude-4.5-haiku)', }, + { + name: 'apiKey', + type: 'string', + required: false, + description: 'LLM AK', + }, { name: 'temperature', type: 'number', diff --git a/packages/website/src/pages/docs/features/chrome-extension/page.tsx b/packages/website/src/pages/docs/features/chrome-extension/page.tsx index cb39f7f..b97f9d7 100644 --- a/packages/website/src/pages/docs/features/chrome-extension/page.tsx +++ b/packages/website/src/pages/docs/features/chrome-extension/page.tsx @@ -187,39 +187,7 @@ localStorage.setItem('PageAgentExtUserAuthToken', '')

void - onActivity?: (activity: AgentActivity) => void - onHistoryUpdate?: (history: HistoricalEvent[]) => void -} - -type Execute = (task: string, config: ExecuteConfig) => Promise - -declare global { - interface Window { - PAGE_AGENT_EXT_VERSION?: string - PAGE_AGENT_EXT?: { - version: string - execute: Execute - stop: () => void - } - } -}` - : `import type { + code={`import type { AgentActivity, AgentStatus, ExecutionResult, @@ -228,8 +196,8 @@ declare global { interface ExecuteConfig { baseURL: string // LLM API endpoint - apiKey: string // API key model: string // Model name + apiKey?: string // LLM AK includeInitialTab?: boolean onStatusChange?: (status: AgentStatus) => void @@ -248,8 +216,7 @@ declare global { stop: () => void } } -}` - } +}`} language="typescript" /> diff --git a/packages/website/src/pages/docs/features/models/page.tsx b/packages/website/src/pages/docs/features/models/page.tsx index d3dd6b3..2dc0c37 100644 --- a/packages/website/src/pages/docs/features/models/page.tsx +++ b/packages/website/src/pages/docs/features/models/page.tsx @@ -129,10 +129,9 @@ const pageAgent = new PageAgent({ model: 'MiniMax-M2.7' }); -// Self-hosted models (e.g., Ollama) +// Self-hosted models (e.g., Ollama) — no apiKey needed const pageAgent = new PageAgent({ baseURL: 'http://localhost:11434/v1', - apiKey: 'NA', model: 'qwen3:14b' }); @@ -280,7 +279,6 @@ LLM_MODEL_NAME="qwen3:14b"`} fetch(url, { ...init, credentials: 'include' }), diff --git a/packages/website/src/pages/home/HeroSection.tsx b/packages/website/src/pages/home/HeroSection.tsx index cb565e9..a671800 100644 --- a/packages/website/src/pages/home/HeroSection.tsx +++ b/packages/website/src/pages/home/HeroSection.tsx @@ -10,7 +10,7 @@ import { Particles } from '../../components/ui/particles' import { CDN_DEMO_CN_URL, CDN_DEMO_URL, - DEMO_API_KEY, + // DEMO_API_KEY, DEMO_BASE_URL, DEMO_MODEL, } from '../../constants' @@ -94,7 +94,7 @@ export default function HeroSection() { apiKey: import.meta.env.DEV && import.meta.env.LLM_API_KEY ? import.meta.env.LLM_API_KEY - : DEMO_API_KEY, + : undefined, }) }