diff --git a/package-lock.json b/package-lock.json index 0261c3a..da2eedf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11074,7 +11074,7 @@ }, "packages/extension": { "name": "@page-agent/ext", - "version": "0.1.6", + "version": "0.1.7", "hasInstallScript": true, "dependencies": { "@page-agent/core": "1.3.0", diff --git a/packages/core/src/PageAgentCore.ts b/packages/core/src/PageAgentCore.ts index 69d66eb..0a9c63c 100644 --- a/packages/core/src/PageAgentCore.ts +++ b/packages/core/src/PageAgentCore.ts @@ -7,7 +7,7 @@ import type { BrowserState, PageController } from '@page-agent/page-controller' import chalk from 'chalk' import * as zod from 'zod' -import { type PageAgentConfig } from './config' +import { type PageAgentConfig, type SupportedLanguage } from './config' import { DEFAULT_MAX_STEPS } from './config/constants' import SYSTEM_PROMPT from './prompts/system_prompt.md?raw' import { tools } from './tools' @@ -24,6 +24,7 @@ import type { import { assert, normalizeResponse, uid, waitFor } from './utils' export { type PageAgentConfig } +export type { SupportedLanguage } export { tool, type PageAgentTool } from './tools' export type * from './types' diff --git a/packages/extension/package.json b/packages/extension/package.json index 88213ae..4f5e8da 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/ext", "private": true, - "version": "0.1.6", + "version": "0.1.7", "type": "module", "scripts": { "dev": "wxt", diff --git a/packages/extension/src/agent/useAgent.ts b/packages/extension/src/agent/useAgent.ts index c734110..6b28c49 100644 --- a/packages/extension/src/agent/useAgent.ts +++ b/packages/extension/src/agent/useAgent.ts @@ -1,22 +1,34 @@ /** * React hook for using AgentController */ -import type { AgentActivity, AgentStatus, HistoricalEvent } from '@page-agent/core' +import type { + AgentActivity, + AgentStatus, + HistoricalEvent, + SupportedLanguage, +} from '@page-agent/core' import type { LLMConfig } from '@page-agent/llms' import { useCallback, useEffect, useRef, useState } from 'react' import { MultiPageAgent } from './MultiPageAgent' import { DEMO_CONFIG } from './constants' +/** Language preference: undefined means follow system */ +export type LanguagePreference = SupportedLanguage | undefined + +export interface ExtConfig extends LLMConfig { + language?: LanguagePreference +} + export interface UseAgentResult { status: AgentStatus history: HistoricalEvent[] activity: AgentActivity | null currentTask: string - config: LLMConfig | null + config: ExtConfig | null execute: (task: string) => Promise stop: () => void - configure: (config: LLMConfig) => Promise + configure: (config: ExtConfig) => Promise } export function useAgent(): UseAgentResult { @@ -25,16 +37,17 @@ export function useAgent(): UseAgentResult { const [history, setHistory] = useState([]) const [activity, setActivity] = useState(null) const [currentTask, setCurrentTask] = useState('') - const [config, setConfig] = useState(null) + const [config, setConfig] = useState(null) useEffect(() => { - chrome.storage.local.get('llmConfig').then((result) => { - if (result.llmConfig) { - setConfig(result.llmConfig as LLMConfig) - } else { + chrome.storage.local.get(['llmConfig', 'language']).then((result) => { + const llmConfig = (result.llmConfig as LLMConfig) ?? DEMO_CONFIG + const language = (result.language as SupportedLanguage) || undefined + const full = { ...llmConfig, language } + if (!result.llmConfig) { chrome.storage.local.set({ llmConfig: DEMO_CONFIG }) - setConfig(DEMO_CONFIG) } + setConfig(full) }) }, []) @@ -87,9 +100,14 @@ export function useAgent(): UseAgentResult { agentRef.current?.stop() }, []) - const configure = useCallback(async (newConfig: LLMConfig) => { - await chrome.storage.local.set({ llmConfig: newConfig }) - setConfig(newConfig) + const configure = useCallback(async ({ language, ...llmConfig }: ExtConfig) => { + await chrome.storage.local.set({ llmConfig }) + if (language) { + await chrome.storage.local.set({ language }) + } else { + await chrome.storage.local.remove('language') + } + setConfig({ ...llmConfig, language }) }, []) return { diff --git a/packages/extension/src/entrypoints/sidepanel/components/ConfigPanel.tsx b/packages/extension/src/entrypoints/sidepanel/components/ConfigPanel.tsx index 20bed01..968d833 100644 --- a/packages/extension/src/entrypoints/sidepanel/components/ConfigPanel.tsx +++ b/packages/extension/src/entrypoints/sidepanel/components/ConfigPanel.tsx @@ -1,15 +1,15 @@ -import type { LLMConfig } from '@page-agent/llms' import { Copy, CornerUpLeft, Eye, EyeOff, HatGlasses, Home, Loader2, Scale } from 'lucide-react' import { useEffect, useState } from 'react' import { siGithub } from 'simple-icons' import { DEMO_API_KEY, DEMO_BASE_URL, DEMO_MODEL } from '@/agent/constants' +import type { ExtConfig, LanguagePreference } from '@/agent/useAgent' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' interface ConfigPanelProps { - config: LLMConfig | null - onSave: (config: LLMConfig) => Promise + config: ExtConfig | null + onSave: (config: ExtConfig) => Promise onClose: () => void } @@ -17,6 +17,7 @@ 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 [language, setLanguage] = useState(config?.language) const [saving, setSaving] = useState(false) const [userAuthToken, setUserAuthToken] = useState('') const [copied, setCopied] = useState(false) @@ -28,6 +29,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { setApiKey(config?.apiKey || DEMO_API_KEY) setBaseURL(config?.baseURL || DEMO_BASE_URL) setModel(config?.model || DEMO_MODEL) + setLanguage(config?.language) }, [config]) // Poll for user auth token every second until found @@ -65,7 +67,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { const handleSave = async () => { setSaving(true) try { - await onSave({ apiKey, baseURL, model }) + await onSave({ apiKey, baseURL, model, language }) } finally { setSaving(false) } @@ -165,6 +167,19 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { +
+ + +
+