Skip to content

Commit 6e919c8

Browse files
committed
fix(agent): improve event cleanup and enhance view_Image result handling in agent
1 parent 95861c7 commit 6e919c8

File tree

3 files changed

+32
-21
lines changed

3 files changed

+32
-21
lines changed

entrypoints/sidepanel/App.vue

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<script setup lang="tsx">
1414
import mime from 'mime'
15-
import { useTemplateRef, watch } from 'vue'
15+
import { onBeforeUnmount, useTemplateRef, watch } from 'vue'
1616
import { browser } from 'wxt/browser'
1717
1818
import { useZIndex } from '@/composables/useZIndex'
@@ -37,7 +37,7 @@ const mainRef = useTemplateRef('mainRef')
3737
const { index: onboardingPanelZIndex } = useZIndex('settings')
3838
const userConfig = await getUserConfig()
3939
40-
registerSidepanelRpcEvent('gmailAction', async (e) => {
40+
const cleanupGmailActionEvent = registerSidepanelRpcEvent('gmailAction', async (e) => {
4141
const { action, data } = e
4242
logger.debug('Gmail action triggered:', action, data)
4343
if (action === 'summary') {
@@ -73,7 +73,7 @@ registerSidepanelRpcEvent('gmailAction', async (e) => {
7373
}
7474
})
7575
76-
registerSidepanelRpcEvent('contextMenuClicked', async (e) => {
76+
const cleanupContextMenuEvent = registerSidepanelRpcEvent('contextMenuClicked', async (e) => {
7777
const menuItemId = e.menuItemId as ContextMenuId
7878
const windowId = e.tabInfo.windowId
7979
if (windowId !== (await browser.windows.getCurrent()).id) return
@@ -118,6 +118,11 @@ registerSidepanelRpcEvent('contextMenuClicked', async (e) => {
118118
}, { immediate: true })
119119
}
120120
})
121+
122+
onBeforeUnmount(() => {
123+
cleanupContextMenuEvent()
124+
cleanupGmailActionEvent()
125+
})
121126
</script>
122127

123128
<style lang="scss">

entrypoints/sidepanel/utils/agent/index.ts

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export class Agent<T extends PromptBasedToolName> {
115115
}
116116

117117
injectImagesToLastMessage(messages: CoreMessage[], images: Base64ImageData[]) {
118-
const lastMessage = messages[messages.length - 1]
118+
const lastMessage = structuredClone(messages[messages.length - 1])
119119
if (lastMessage && lastMessage.role === 'user') {
120120
if (typeof lastMessage.content === 'string') {
121121
lastMessage.content = [
@@ -126,8 +126,9 @@ export class Agent<T extends PromptBasedToolName> {
126126
else {
127127
lastMessage.content.push(...images.map((img) => ({ type: 'image' as const, image: img.data, mimeType: img.type })))
128128
}
129+
return [...messages.slice(0, -1), lastMessage]
129130
}
130-
return messages
131+
return [...messages]
131132
}
132133

133134
overrideSystemPrompt(messages: CoreMessage[], systemPrompt?: string) {
@@ -254,14 +255,18 @@ export class Agent<T extends PromptBasedToolName> {
254255
}
255256

256257
// iteration starts from 1
257-
buildExtendedUserMessage(iteration: number, originalUserMessage: string, toolResults?: string) {
258+
buildExtendedUserMessage(iteration: number, originalUserMessage: string, toolResults?: (AgentToolExecuteResultToolResult & { toolName: T })[]) {
258259
if (iteration === 1) return `${originalUserMessage}\n\n${AGENT_INITIAL_GUIDANCE.build()}`
259-
const textBuilder = new TextBuilder(`${originalUserMessage}`)
260-
if (toolResults) {
261-
textBuilder.insertContent(toolResults)
260+
if (toolResults?.length) {
261+
const toolResultPart = this.toolResultsToPrompt(toolResults)
262+
const hasViewImageTool = toolResults.some((t) => t.toolName === 'view_image')
263+
// compatible with gemma3 model, which will loop infinitely if the view_image tool result has original user message
264+
const textBuilder = new TextBuilder(!hasViewImageTool ? originalUserMessage : '')
265+
textBuilder.insertContent(toolResultPart)
262266
textBuilder.insertContent(AGENT_TOOL_CALL_RESULT_GUIDANCE)
267+
return textBuilder.build().trim()
263268
}
264-
return textBuilder.build()
269+
return new TextBuilder(originalUserMessage).build().trim()
265270
}
266271

267272
async run(rawBaseMessages: CoreMessage[]) {
@@ -340,14 +345,12 @@ export class Agent<T extends PromptBasedToolName> {
340345
taskMessageModifier = this.makeTaskMessageGroupProxy(abortController.signal)
341346
}
342347
this.log.debug('Executing tool calls', currentLoopToolCalls)
343-
const toolResults = await this.executeToolCalls(currentLoopToolCalls, taskScopeToolCalls, loopImages, taskMessageModifier, eventBus)
344-
this.log.debug('Tool calls executed', currentLoopToolCalls, toolResults)
345-
if (toolResults.length === 0) {
346-
const errorResult = TagBuilder.fromStructured('error', { message: `Tool not found, available tools are: ${Object.keys(this.tools).join(', ')}` })
347-
loopMessages.push({ role: 'user', content: renderPrompt`${errorResult}` })
348-
}
349-
else if (toolResults.some((result) => result.type === 'hand-off')) {
350-
const handoffResult = toolResults.find((result) => result.type === 'hand-off')
348+
const toolExecuteResults = await this.executeToolCalls(currentLoopToolCalls, taskScopeToolCalls, loopImages, taskMessageModifier, eventBus)
349+
this.log.debug('Tool calls executed', currentLoopToolCalls, toolExecuteResults)
350+
const toolResults = toolExecuteResults.filter((r) => r.type === 'tool-result')
351+
const handOffResults = toolExecuteResults.filter((r) => r.type === 'hand-off')
352+
if (handOffResults.length > 0) {
353+
const handoffResult = handOffResults[0]
351354
if (handoffResult) {
352355
// This feature is in beta, not used yet
353356
this.log.debug('Hand-off detected', handoffResult)
@@ -359,9 +362,12 @@ export class Agent<T extends PromptBasedToolName> {
359362
if (lastMsg?.content) loopMessages.push(lastMsg)
360363
}
361364
}
365+
else if (toolResults.length) {
366+
loopMessages.push({ role: 'user', content: this.buildExtendedUserMessage(iteration + 1, originalUserMessageText, toolResults) })
367+
}
362368
else {
363-
const toolResultPart = this.toolResultsToPrompt(toolResults.filter((t) => t.type === 'tool-result'))
364-
loopMessages.push({ role: 'user', content: this.buildExtendedUserMessage(iteration + 1, originalUserMessageText, toolResultPart) })
369+
const errorResult = TagBuilder.fromStructured('error', { message: `Tool not found, available tools are: ${Object.keys(this.tools).join(', ')}` })
370+
loopMessages.push({ role: 'user', content: renderPrompt`${errorResult}` })
365371
}
366372
}
367373
}

entrypoints/sidepanel/utils/chat/tool-calls/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,8 @@ export const executePageClick: AgentToolCallExecute<'click'> = async ({ params,
408408
const result = await browserSession.buildAccessibleMarkdown({ highlightInteractiveElements, contentFilterThreshold, abortSignal })
409409
if (lastTabResult && result) {
410410
const diffs = markdownSectionDiff(lastTabResult.content, result.content)
411-
log.debug(`Found diffs between old and new tab content: ${diffs}`, { lastTabResult, result })
412411
const shouldUseDiff = diffs.trim() && diffs.length < (result.content.length / 2) // not to use diff result if there are too many changes
412+
log.debug(`Found diffs between old and new tab content: ${diffs}`, { lastTabResult, result, shouldUseDiff })
413413
if (shouldUseDiff) {
414414
taskMsg.summary = t('chat.tool_calls.page_click.redirected', { destination: normalizeInnerText(currentTabInfo?.title) || currentTabInfo?.url || '' })
415415
return [{

0 commit comments

Comments
 (0)