Skip to content

[Fix] Improve tool error handling and async operations#622

Merged
dingyi222666 merged 2 commits into
v1-devfrom
fix/mcp
Oct 28, 2025
Merged

[Fix] Improve tool error handling and async operations#622
dingyi222666 merged 2 commits into
v1-devfrom
fix/mcp

Conversation

@dingyi222666
Copy link
Copy Markdown
Member

This PR improves error handling in agent tool execution and fixes async operation handling in MCP tool integration.

Bug fixes

  • Fixed missing default error handler for tool runtime errors in AgentExecutor, preventing unhandled exceptions
  • Fixed non-string tool observations causing errors by converting them to JSON instead of throwing
  • Fixed MCP tool calls not properly awaiting async operations
  • Fixed excessive JSON stringification in MCP tool response logging

Other Changes

  • Added type annotation for observation variable to improve type safety
  • Improved error messages to be more user-friendly

…ions

- Add default error handler for tool runtime errors in AgentExecutor
- Convert non-string tool observations to JSON instead of throwing
- Make MCP tool calls properly await async operations
- Improve MCP tool response logging to avoid unnecessary stringification

These changes ensure better error resilience and proper async handling
in both core agent execution and MCP tool integration.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 28, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (26)
  • packages/adapter-azure-openai/package.json is excluded by !**/*.json
  • packages/adapter-claude/package.json is excluded by !**/*.json
  • packages/adapter-deepseek/package.json is excluded by !**/*.json
  • packages/adapter-dify/package.json is excluded by !**/*.json
  • packages/adapter-doubao/package.json is excluded by !**/*.json
  • packages/adapter-gemini/package.json is excluded by !**/*.json
  • packages/adapter-hunyuan/package.json is excluded by !**/*.json
  • packages/adapter-ollama/package.json is excluded by !**/*.json
  • packages/adapter-openai-like/package.json is excluded by !**/*.json
  • packages/adapter-openai/package.json is excluded by !**/*.json
  • packages/adapter-qwen/package.json is excluded by !**/*.json
  • packages/adapter-rwkv/package.json is excluded by !**/*.json
  • packages/adapter-spark/package.json is excluded by !**/*.json
  • packages/adapter-wenxin/package.json is excluded by !**/*.json
  • packages/adapter-zhipu/package.json is excluded by !**/*.json
  • packages/core/package.json is excluded by !**/*.json
  • packages/extension-long-memory/package.json is excluded by !**/*.json
  • packages/extension-mcp/package.json is excluded by !**/*.json
  • packages/extension-tools/package.json is excluded by !**/*.json
  • packages/extension-variable/package.json is excluded by !**/*.json
  • packages/renderer-image/package.json is excluded by !**/*.json
  • packages/service-embeddings/package.json is excluded by !**/*.json
  • packages/service-image/package.json is excluded by !**/*.json
  • packages/service-search/package.json is excluded by !**/*.json
  • packages/service-vector-store/package.json is excluded by !**/*.json
  • packages/shared-adapter/package.json is excluded by !**/*.json

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

总体概览

本变更对代理执行器的错误处理机制进行了调整,将非字符串工具观测值从抛出异常改为日志警告并强制转换;同时优化了MCP客户端的异步调用流程和日志输出格式。

变更概览

功能群组 / 文件 变更摘要
代理执行器错误处理
packages/core/src/llm-core/agent/executor.ts
handleToolRuntimeErrors属性添加默认初始值;当工具返回非字符串观测值时,改为记录警告并通过JSON.stringify()强制转换,而非抛出异常
MCP服务异步调用
packages/extension-mcp/src/service.ts
在工具调用流程中使用await callTool()确保Promise被完全解析后再继续执行
MCP工具日志记录
packages/extension-mcp/src/utils.ts
将MCP工具调用结果日志从格式化JSON字符串改为直接记录原始对象

序列图

sequenceDiagram
    participant Agent as 代理执行器
    participant Tool as 工具调用
    participant Result as 返回结果
    
    Agent->>Tool: 调用工具
    Tool->>Result: 执行工具逻辑
    
    alt 返回字符串观测值
        Result-->>Agent: 字符串结果
        Agent->>Agent: 直接使用观测值
    else 返回非字符串观测值
        Result-->>Agent: 非字符串对象
        Agent->>Agent: ⚠️ 记录警告日志
        Agent->>Agent: JSON.stringify()强制转换
        Agent->>Agent: 继续执行(无异常)
    end
    
    Note over Agent: handleToolRuntimeErrors<br/>提供降级错误处理
Loading

代码审查工作量估计

🎯 2 (简单) | ⏱️ ~12 分钟

  • executor.ts:主要变更涉及错误处理策略的改变(从异常抛出到日志警告),逻辑改动相对明确
  • service.ts:await语句的添加是标准的异步控制流改进,变更有限
  • utils.ts:日志格式调整是纯粹的输出格式改变,无逻辑影响

需要重点关注的区域:

  • executor.ts中的观测值强制转换逻辑是否在所有执行路径(主路径和单个操作路径)中保持一致
  • service.ts中await的添加是否会影响现有的错误捕获机制
  • utils.ts的日志格式改变是否符合下游日志处理系统的期望

可能相关的PR

诗歌

🐰 工具出错莫担忧,
观测字符巧转流,
日志轻声为导航,
Promise待命方圆成,
执行器稳如磐石。

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed PR标题"[Fix] Improve tool error handling and async operations"准确反映了changeset中的主要改动。标题涵盖了两个核心变化:AgentExecutor中的错误处理改进和MCP服务中的异步操作修复。标题简洁明了,清晰传达了更改的主要目的,使团队成员扫描历史记录时能够理解该PR的重点。
Description Check ✅ Passed PR描述与changeset完全相关。描述准确列出了所有实现的bug修复和改进,包括AgentExecutor中的默认错误处理器、非字符串观察值的JSON转换、MCP工具调用中的async/await修复和日志输出格式的优化。描述提供了足够的上下文信息,清楚地解释了所做的改进及其目的,满足了对PR描述的要求。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @dingyi222666, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the stability and reliability of agent tool execution by improving error handling mechanisms and ensuring correct asynchronous operation management. It addresses several bug fixes related to unhandled exceptions, non-string tool outputs, and proper awaiting of async calls within the MCP tool integration, alongside minor improvements to logging and type safety.

Highlights

  • Robust Error Handling: Implemented a default error handler for tool runtime errors in AgentExecutor to prevent unhandled exceptions and provide a user-friendly message.
  • Flexible Tool Observations: Modified tool execution to convert non-string observations to JSON and log a warning instead of throwing an error, improving resilience and data handling.
  • Correct Async Operations: Ensured MCP tool calls properly await asynchronous operations, resolving potential race conditions or unhandled promises within the langChainTool.
  • Optimized Logging: Reduced excessive JSON stringification in MCP tool response logging for cleaner and more efficient output.
  • Type Safety: Added a type annotation for the observation variable to enhance type safety and code clarity.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several valuable improvements to error handling and asynchronous operations. Key changes include adding a default error handler in AgentExecutor to prevent unhandled exceptions, gracefully handling non-string tool observations by converting them to JSON, and fixing an issue with awaiting asynchronous MCP tool calls. These changes enhance the robustness and reliability of the agent. My review includes a suggestion to refine the new default error handler to provide cleaner error messages and avoid exposing internal implementation details.

Comment thread packages/core/src/llm-core/agent/executor.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/extension-mcp/src/utils.ts (1)

391-396: 返回值类型与实现不一致(会导致编译错误/运行时歧义)

_here_返回了字符串而函数签名要求第一个元素为内容块数组。应返回内容块数组以保持与签名和调用方约定一致。

建议改为保持数组形态(或移除该特判),例如:

-    if (convertedContent.length === 1 && convertedContent[0].type === 'text') {
-        return [convertedContent[0].text, []] // artifacts]
-    }
+    if (convertedContent.length === 1 && convertedContent[0].type === 'text') {
+        return [convertedContent, []] // 保持内容块数组形态
+    }
packages/core/src/llm-core/agent/executor.ts (1)

731-759: 流式/分步路径未对工具运行时错误应用同样的兜底(与上方路径不一致)

这里仅处理了ToolInputParsingException,其他运行时错误将导致空观察值,用户体验不一致。

建议与上方路径对齐,使用handleToolRuntimeErrors兜底,并保持字符串化一致性:

         try {
             observation = await tool.invoke(
                 agentAction.toolInput,
                 runManager?.getChild()
             )
             if (typeof observation !== 'string') {
                 logger.warn(
                     `Tool ${tool.name} returned non-string observation`,
                     observation
                 )
                 observation = JSON.stringify(observation)
             }
-        } catch (e) {
+        } catch (e) {
             if (e instanceof ToolInputParsingException) {
                 ...
-            }
+            } else if (this.handleToolRuntimeErrors !== undefined) {
+                observation = this.handleToolRuntimeErrors(e as Error)
+            } else {
+                observation = 'Tool execution failed.'
+            }
         }
🧹 Nitpick comments (6)
packages/extension-mcp/src/utils.ts (2)

480-483: 日志记录直接打印对象可能放大日志与泄露大字段

直接传入result可能在某些 logger 中输出巨大 base64/二进制或嵌套对象,影响性能与可读性。建议仅输出关键信息(如isErrorcontent中各项的type),并对内容长度做截断。

示例:

-logger.debug(
-  `MCP tool '${toolName}' on server '${serverName}' returned:`,
-  result
-)
+logger.debug(
+  `MCP tool '${toolName}' on server '${serverName}' returned:`,
+  {
+    isError: (result as any)?.isError,
+    types: Array.isArray((result as any)?.content)
+      ? (result as any).content.map((c: any) => c?.type).slice(0, 10)
+      : typeof (result as any)?.content
+  }
+)

503-521: 命名小问题:参数名应为 mimeType(非 mineType)

当前putResourceToStorage使用了mineType,容易误解且与上文调用的不一致。建议更正命名以提升可读性。

-async function putResourceToStorage(
-    ctx: Context,
-    blob: string | Buffer,
-    mineType: string
-) {
+async function putResourceToStorage(
+    ctx: Context,
+    blob: string | Buffer,
+    mimeType: string
+) {
-  const extension = mimeTypes.extension(mineType)
+  const extension = mimeTypes.extension(mimeType)
   ...
-  if (!extension) {
-      throw new Error(`Unsupported mime type: ${mineType}`)
+  if (!extension) {
+      throw new Error(`Unsupported mime type: ${mimeType}`)
   }
packages/extension-mcp/src/service.ts (1)

258-259: 传入的 serverName 实际是工具名,日志含义可能混乱

此处serverName: name中的name来自工具名,而非服务器标识。utils.ts 中的日志/报错会将其当作“服务器名”展示,容易误导排查。

建议在构建toolToClientMap时同时保存一个可识别的服务器标识(如urlcommand摘要),并在此处传入该标识作为serverName

packages/core/src/llm-core/agent/executor.ts (3)

395-397: 新增默认的工具运行时错误处理器

默认处理器可避免空观察值,提升鲁棒性。注意:拼接原始错误信息可能在生产中暴露实现细节。建议在生产构建中可选地隐藏具体错误内容,仅保留友好提示。


579-595: 对非字符串观察值进行告警并 JSON 序列化的策略是合理的

此变更与上游返回的“content_and_artifact”响应兼容,避免抛错。若担心循环结构导致JSON.stringify失败,可考虑降级为util.inspect或使用安全序列化库。


588-589: 无效工具提示建议统一口径

两处无效工具提示信息不一致(一个不含可用列表,一个包含)。建议统一并包含可用工具列表,便于模型自纠。

示例(第一处):

-: `${action.tool} is not a valid tool, try another one.`
+: `${action.tool} is not a valid tool, try another available tool: ${Object.keys(toolsByName).join(', ')}`

Also applies to: 761-766

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f73325 and afcfac9.

📒 Files selected for processing (3)
  • packages/core/src/llm-core/agent/executor.ts (4 hunks)
  • packages/extension-mcp/src/service.ts (1 hunks)
  • packages/extension-mcp/src/utils.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/extension-mcp/src/service.ts (1)
packages/extension-mcp/src/utils.ts (1)
  • callTool (438-501)
packages/core/src/llm-core/agent/executor.ts (3)
packages/adapter-zhipu/src/client.ts (1)
  • logger (29-31)
packages/extension-mcp/src/index.ts (1)
  • logger (8-8)
packages/extension-long-memory/src/index.ts (1)
  • logger (9-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: lint
  • GitHub Check: build
🔇 Additional comments (1)
packages/extension-mcp/src/service.ts (1)

253-264: 显式 await 是必要的(修正异步顺序问题)

return await callTool(...)保证在工具链继续前已拿到结果,匹配上游执行器的观察值处理逻辑。变更合理。

如需确认端到端行为,请用一条会返回非字符串内容块的 MCP 工具做一次实际调用,确保不再出现“Promise 被传递”为观察值的情况。

- Bump core package to 1.3.0-alpha.78
- Bump extension-mcp to 1.3.0-alpha.16
- Update peer dependency references across all adapter and extension packages
@dingyi222666 dingyi222666 merged commit b70e820 into v1-dev Oct 28, 2025
3 checks passed
@dingyi222666 dingyi222666 deleted the fix/mcp branch November 15, 2025 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant