feat(ext): add agent heart beat check
This commit is contained in:
@@ -5,12 +5,26 @@ import { TabsController } from './TabsController'
|
|||||||
import SYSTEM_PROMPT from './system_prompt.md?raw'
|
import SYSTEM_PROMPT from './system_prompt.md?raw'
|
||||||
import { createTabTools } from './tabTools'
|
import { createTabTools } from './tabTools'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MultiPageAgent
|
||||||
|
* - use with extension
|
||||||
|
* - can be used from a side panel or a content script
|
||||||
|
*/
|
||||||
export class MultiPageAgent extends PageAgentCore {
|
export class MultiPageAgent extends PageAgentCore {
|
||||||
constructor(config: Omit<PageAgentConfig, 'pageController'>) {
|
constructor(config: Omit<PageAgentConfig, 'pageController'>) {
|
||||||
const tabsController = new TabsController()
|
const tabsController = new TabsController()
|
||||||
const pageController = new RemotePageController(tabsController)
|
const pageController = new RemotePageController(tabsController)
|
||||||
const customTools = createTabTools(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({
|
super({
|
||||||
...config,
|
...config,
|
||||||
pageController: pageController as any,
|
pageController: pageController as any,
|
||||||
@@ -20,18 +34,34 @@ export class MultiPageAgent extends PageAgentCore {
|
|||||||
onBeforeTask: async (agent) => {
|
onBeforeTask: async (agent) => {
|
||||||
await tabsController.init(agent.task)
|
await tabsController.init(agent.task)
|
||||||
|
|
||||||
|
heartBeatInterval = window.setInterval(() => {
|
||||||
|
chrome.storage.local.set({
|
||||||
|
agentHeartbeat: Date.now(),
|
||||||
|
})
|
||||||
|
}, 1_000)
|
||||||
|
|
||||||
await chrome.storage.local.set({
|
await chrome.storage.local.set({
|
||||||
isAgentRunning: true,
|
isAgentRunning: true,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onAfterTask: async () => {
|
onAfterTask: async () => {
|
||||||
|
if (heartBeatInterval) {
|
||||||
|
window.clearInterval(heartBeatInterval)
|
||||||
|
heartBeatInterval = null
|
||||||
|
}
|
||||||
|
|
||||||
await chrome.storage.local.set({
|
await chrome.storage.local.set({
|
||||||
isAgentRunning: false,
|
isAgentRunning: false,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onDispose: () => {
|
onDispose: () => {
|
||||||
|
if (heartBeatInterval) {
|
||||||
|
window.clearInterval(heartBeatInterval)
|
||||||
|
heartBeatInterval = null
|
||||||
|
}
|
||||||
|
|
||||||
chrome.storage.local.set({
|
chrome.storage.local.set({
|
||||||
isAgentRunning: false,
|
isAgentRunning: false,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -21,17 +21,14 @@ export function initPageController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
intervalID = window.setInterval(async () => {
|
intervalID = window.setInterval(async () => {
|
||||||
|
const agentHeartbeat = (await chrome.storage.local.get('agentHeartbeat')).agentHeartbeat
|
||||||
|
const now = Date.now()
|
||||||
|
const agentInTouch = typeof agentHeartbeat === 'number' && now - agentHeartbeat < 2_000
|
||||||
|
|
||||||
const isAgentRunning = (await chrome.storage.local.get('isAgentRunning')).isAgentRunning
|
const isAgentRunning = (await chrome.storage.local.get('isAgentRunning')).isAgentRunning
|
||||||
const currentTabId = (await chrome.storage.local.get('currentTabId')).currentTabId
|
const currentTabId = (await chrome.storage.local.get('currentTabId')).currentTabId
|
||||||
|
|
||||||
const shouldShowMask = isAgentRunning && currentTabId === (await myTabIdPromise)
|
const shouldShowMask = isAgentRunning && agentInTouch && currentTabId === (await myTabIdPromise)
|
||||||
|
|
||||||
// console.log('[RemotePageController] polling:', {
|
|
||||||
// isAgentRunning,
|
|
||||||
// currentTabId,
|
|
||||||
// myTabId: await myTabIdPromise,
|
|
||||||
// shouldShowMask,
|
|
||||||
// })
|
|
||||||
|
|
||||||
if (shouldShowMask) {
|
if (shouldShowMask) {
|
||||||
const pc = getPC()
|
const pc = getPC()
|
||||||
@@ -45,13 +42,13 @@ export function initPageController() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAgentRunning) {
|
if (!isAgentRunning && agentInTouch) {
|
||||||
if (pageController) {
|
if (pageController) {
|
||||||
pageController.dispose()
|
pageController.dispose()
|
||||||
pageController = null
|
pageController = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1_000)
|
}, 500)
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse): true | undefined => {
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse): true | undefined => {
|
||||||
if (message.type !== 'PAGE_CONTROL') {
|
if (message.type !== 'PAGE_CONTROL') {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { handlePageControlMessage } from '@/agent/RemotePageController.background'
|
import { handlePageControlMessage } from '@/agent/RemotePageController.background'
|
||||||
import { handleTabControlMessage } from '@/agent/TabsController.background'
|
import { handleTabControlMessage } from '@/agent/TabsController.background'
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse): true | undefined => {
|
||||||
if (message.type === 'TAB_CONTROL') {
|
if (message.type === 'TAB_CONTROL') {
|
||||||
return handleTabControlMessage(message, sender, sendResponse)
|
return handleTabControlMessage(message, sender, sendResponse)
|
||||||
} else if (message.type === 'PAGE_CONTROL') {
|
} else if (message.type === 'PAGE_CONTROL') {
|
||||||
|
|||||||
Reference in New Issue
Block a user