Is your feature request related to a problem? Please describe.
The agent loop appears to lose the real error when a registered tool throws.
executeToolCalls() catches non-abort failures, logs them, and returns no result for that tool:
|
async executeToolCalls( |
|
toolCalls: PromptBasedToolNameAndParams<T>[], |
|
taskScopeToolCalls: PromptBasedToolNameAndParamsDistributed[], |
|
loopImages: ImageDataWithId[] = [], |
|
taskMessageModifier: TaskMessageModifier, |
|
eventBus: EventEmitter<AgentToolCallExecuteHooks>, |
|
) { |
|
toolCalls = this.deduplicateToolCalls(toolCalls) |
|
const currentLoopToolResults: (AgentToolExecuteResult & { toolName: T })[] = [] |
|
for (const chunk of toolCalls) { |
|
const toolName = chunk.toolName as T |
|
const tool = this.tools[toolName] |
|
if (tool) { |
|
const params = chunk.params |
|
this.log.debug('Tool call start', chunk) |
|
const abortController = this.createAbortController() |
|
try { |
|
const executedResults = await tool.execute({ |
|
params, |
|
taskScopeToolCalls, |
|
agentStorage: this.agentStorage, |
|
historyManager: this.historyManager, |
|
loopImages, |
|
abortSignal: abortController.signal, |
|
taskMessageModifier, |
|
hooks: eventBus, |
|
}) |
|
for (const result of executedResults) { |
|
currentLoopToolResults.push({ ...result, toolName }) |
|
} |
|
this.log.debug('Tool call executed', toolName, executedResults) |
|
} |
|
catch (e) { |
|
if (e instanceof AbortError) { |
|
this.log.debug('Tool call aborted', toolName) |
|
break |
|
} |
|
this.log.error('Tool call error', toolName, e) |
|
} |
|
taskMessageModifier.makeAllTaskDone() |
|
} |
|
else { |
|
this.log.warn('Tool not found', chunk) |
|
} |
|
} |
|
return currentLoopToolResults |
The caller then treats an empty result list as Tool not found, even though the tool was present:
|
if (currentLoopToolCalls.length > 0) { |
|
if (agentMessage.content || agentMessage.reasoning) { |
|
// create a new group if there are some plain messages |
|
taskMessageModifier = this.makeTaskMessageGroupProxy(abortController.signal) |
|
} |
|
this.log.debug('Executing tool calls', currentLoopToolCalls) |
|
const toolExecuteResults = await this.executeToolCalls(currentLoopToolCalls, taskScopeToolCalls, loopImages, taskMessageModifier, eventBus) |
|
this.log.debug('Tool calls executed', currentLoopToolCalls, toolExecuteResults) |
|
const toolResults = toolExecuteResults.filter((r) => r.type === 'tool-result') |
|
const handOffResults = toolExecuteResults.filter((r) => r.type === 'hand-off') |
|
if (handOffResults.length > 0) { |
|
const handoffResult = handOffResults[0] |
|
if (handoffResult) { |
|
// This feature is in beta, not used yet |
|
this.log.debug('Hand-off detected', handoffResult) |
|
const subAgent = new Agent({ tools: this.tools, agentStorage: this.agentStorage, historyManager: this.historyManager, maxIterations: this.maxIterations }) |
|
abortController.signal.addEventListener('abort', () => subAgent.stop()) |
|
loopMessages.push({ role: 'user', content: handoffResult.userPrompt }) |
|
const lastMsg = await subAgent.run(this.overrideSystemPrompt([...baseMessages, ...loopMessages], handoffResult.overrideSystemPrompt)) |
|
this.log.debug('Sub-agent finished', lastMsg) |
|
if (lastMsg?.content) loopMessages.push(lastMsg) |
|
} |
|
} |
|
else if (toolResults.length) { |
|
loopMessages.push({ role: 'user', content: this.buildExtendedUserMessage(iteration + 1, originalUserMessageText, toolResults) }) |
|
} |
|
else { |
|
const errorResult = TagBuilder.fromStructured('error', { message: `Tool not found, available tools are: ${Object.keys(this.tools).join(', ')}` }) |
|
loopMessages.push({ role: 'user', content: renderPrompt`${errorResult}` }) |
|
} |
That can give the model misleading recovery context and hide the actionable failure from the user. This is a source-based inference from commit 70a2acc1425749913748c92309254a8f4e69aa8a; I have not reproduced it in a running extension.
Describe the solution you'd like
Convert a non-abort tool exception into a structured error tool result associated with the original toolName. Reserve Tool not found for the branch where the requested tool is genuinely absent. Keep the existing abort behavior unchanged.
Suggested acceptance criteria:
- A registered tool that throws produces a tool-specific error result for the next agent iteration.
- An unknown tool still produces the available-tools guidance.
AbortError stops execution without being converted into a normal tool failure.
- Unit tests cover all three paths and multiple tool calls where one fails.
Describe alternatives you've considered
- Rethrowing the exception would terminate the whole agent loop rather than allow recovery.
- Showing only a UI toast would still withhold the failure reason from the model.
Additional context
If maintainers agree with the desired error-result shape, I would be happy to prepare a focused PR after that guidance.
Is your feature request related to a problem? Please describe.
The agent loop appears to lose the real error when a registered tool throws.
executeToolCalls()catches non-abort failures, logs them, and returns no result for that tool:NativeMindExtension/entrypoints/sidepanel/utils/agent/index.ts
Lines 467 to 512 in 70a2acc
The caller then treats an empty result list as
Tool not found, even though the tool was present:NativeMindExtension/entrypoints/sidepanel/utils/agent/index.ts
Lines 346 to 375 in 70a2acc
That can give the model misleading recovery context and hide the actionable failure from the user. This is a source-based inference from commit
70a2acc1425749913748c92309254a8f4e69aa8a; I have not reproduced it in a running extension.Describe the solution you'd like
Convert a non-abort tool exception into a structured error tool result associated with the original
toolName. ReserveTool not foundfor the branch where the requested tool is genuinely absent. Keep the existing abort behavior unchanged.Suggested acceptance criteria:
AbortErrorstops execution without being converted into a normal tool failure.Describe alternatives you've considered
Additional context
If maintainers agree with the desired error-result shape, I would be happy to prepare a focused PR after that guidance.