Files
page-agent/packages/extension/src/agent/useAgent.ts
T

152 lines
4.2 KiB
TypeScript
Raw Normal View History

2026-01-24 19:29:27 +08:00
/**
* React hook for using AgentController
*/
2026-02-14 16:10:46 +08:00
import type {
AgentActivity,
AgentStatus,
HistoricalEvent,
SupportedLanguage,
} from '@page-agent/core'
2026-01-28 13:15:34 +08:00
import type { LLMConfig } from '@page-agent/llms'
2026-01-24 19:29:27 +08:00
import { useCallback, useEffect, useRef, useState } from 'react'
import { MultiPageAgent } from './MultiPageAgent'
import { DEMO_CONFIG, migrateLegacyEndpoint } from './constants'
2026-02-14 16:10:46 +08:00
/** Language preference: undefined means follow system */
export type LanguagePreference = SupportedLanguage | undefined
2026-03-05 20:34:55 +08:00
export interface AdvancedConfig {
maxSteps?: number
systemInstruction?: string
experimentalLlmsTxt?: boolean
}
export interface ExtConfig extends LLMConfig, AdvancedConfig {
2026-02-14 16:10:46 +08:00
language?: LanguagePreference
}
2026-01-24 19:29:27 +08:00
export interface UseAgentResult {
status: AgentStatus
history: HistoricalEvent[]
activity: AgentActivity | null
currentTask: string
2026-02-14 16:10:46 +08:00
config: ExtConfig | null
2026-01-24 19:29:27 +08:00
execute: (task: string) => Promise<void>
stop: () => void
2026-02-14 16:10:46 +08:00
configure: (config: ExtConfig) => Promise<void>
2026-01-24 19:29:27 +08:00
}
export function useAgent(): UseAgentResult {
const agentRef = useRef<MultiPageAgent | null>(null)
2026-01-24 19:29:27 +08:00
const [status, setStatus] = useState<AgentStatus>('idle')
const [history, setHistory] = useState<HistoricalEvent[]>([])
const [activity, setActivity] = useState<AgentActivity | null>(null)
const [currentTask, setCurrentTask] = useState('')
2026-02-14 16:10:46 +08:00
const [config, setConfig] = useState<ExtConfig | null>(null)
2026-01-24 19:29:27 +08:00
useEffect(() => {
2026-03-05 20:34:55 +08:00
chrome.storage.local.get(['llmConfig', 'language', 'advancedConfig']).then((result) => {
let llmConfig = (result.llmConfig as LLMConfig) ?? DEMO_CONFIG
2026-02-14 16:10:46 +08:00
const language = (result.language as SupportedLanguage) || undefined
2026-03-05 20:34:55 +08:00
const advancedConfig = (result.advancedConfig as AdvancedConfig) ?? {}
// Auto-migrate legacy testing endpoints
const migrated = migrateLegacyEndpoint(llmConfig)
if (migrated !== llmConfig) {
llmConfig = migrated
chrome.storage.local.set({ llmConfig: migrated })
} else if (!result.llmConfig) {
chrome.storage.local.set({ llmConfig: DEMO_CONFIG })
}
2026-03-05 20:34:55 +08:00
setConfig({ ...llmConfig, ...advancedConfig, language })
2026-01-24 19:29:27 +08:00
})
}, [])
useEffect(() => {
if (!config) return
2026-03-05 20:34:55 +08:00
const { systemInstruction, ...agentConfig } = config
const agent = new MultiPageAgent({
...agentConfig,
instructions: systemInstruction ? { system: systemInstruction } : undefined,
})
agentRef.current = agent
2026-01-24 19:29:27 +08:00
const handleStatusChange = (e: Event) => {
const newStatus = agent.status as AgentStatus
2026-01-24 19:29:27 +08:00
setStatus(newStatus)
if (newStatus === 'idle' || newStatus === 'completed' || newStatus === 'error') {
setActivity(null)
}
}
const handleHistoryChange = (e: Event) => {
setHistory([...agent.history])
2026-01-24 19:29:27 +08:00
}
const handleActivity = (e: Event) => {
const newActivity = (e as CustomEvent).detail as AgentActivity
setActivity(newActivity)
}
agent.addEventListener('statuschange', handleStatusChange)
agent.addEventListener('historychange', handleHistoryChange)
agent.addEventListener('activity', handleActivity)
2026-01-24 19:29:27 +08:00
return () => {
agent.removeEventListener('statuschange', handleStatusChange)
agent.removeEventListener('historychange', handleHistoryChange)
agent.removeEventListener('activity', handleActivity)
agent.dispose()
2026-01-24 19:29:27 +08:00
}
}, [config])
2026-01-24 19:29:27 +08:00
const execute = useCallback(async (task: string) => {
const agent = agentRef.current
2026-02-11 19:27:14 +08:00
console.log('🚀 [useAgent] start executing task:', task)
2026-01-28 14:11:44 +08:00
if (!agent) throw new Error('Agent not initialized')
2026-01-24 19:29:27 +08:00
setCurrentTask(task)
setHistory([])
await agent.execute(task)
2026-01-24 19:29:27 +08:00
}, [])
const stop = useCallback(() => {
agentRef.current?.stop()
2026-01-24 19:29:27 +08:00
}, [])
2026-03-05 20:34:55 +08:00
const configure = useCallback(
async ({
language,
maxSteps,
systemInstruction,
experimentalLlmsTxt,
...llmConfig
}: 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 })
},
[]
)
2026-01-24 19:29:27 +08:00
return {
status,
history,
activity,
currentTask,
config,
execute,
stop,
configure,
}
}