import { type PageAgentConfig, PageAgentCore } from '@page-agent/core' import { RemotePageController } from './RemotePageController' import { TabsController } from './TabsController' import SYSTEM_PROMPT from './system_prompt.md?raw' import { createTabTools } from './tabTools' /** * MultiPageAgent * - use with extension * - can be used from a side panel or a content script */ export class MultiPageAgent extends PageAgentCore { constructor(config: Omit) { const tabsController = new TabsController() const pageController = new RemotePageController(tabsController) const customTools = createTabTools(tabsController) /** * When the agent is in side-panel and user closed the side-panel. * There is no chance for isAgentRunning to be set false. * (unload event doesn't work well in side panel.) * (I'm trying not to use long-lived connection because the lifecycle of a sw is hard to predict.) * This heartbeat mechanism acts as a backup. */ let heartBeatInterval: null | number = null super({ ...config, pageController: pageController as any, customTools: customTools, customSystemPrompt: SYSTEM_PROMPT, onBeforeTask: async (agent) => { await tabsController.init(agent.task) heartBeatInterval = window.setInterval(() => { chrome.storage.local.set({ agentHeartbeat: Date.now(), }) }, 1_000) await chrome.storage.local.set({ isAgentRunning: true, }) }, onAfterTask: async () => { if (heartBeatInterval) { window.clearInterval(heartBeatInterval) heartBeatInterval = null } await chrome.storage.local.set({ isAgentRunning: false, }) }, onDispose: () => { if (heartBeatInterval) { window.clearInterval(heartBeatInterval) heartBeatInterval = null } chrome.storage.local.set({ isAgentRunning: false, }) // no need to dispose tabsController and pageController // as they do not keep references }, }) } }