Skip to content

[Bug] 工具调用缺乏统一结果协议 / Tool Call Lacks Unified Result Protocol #133

@SunYanbox

Description

@SunYanbox

问题描述 / Description

当前工具调用实现中存在三个相互关联的缺陷,导致错误被错误地记录为成功、审计数据失真、以及调用方无法可靠区分成功与失败状态。
The current tool call implementation has three interrelated defects that cause errors to be incorrectly recorded as successes, corrupted audit data, and callers unable to reliably distinguish success from failure.


A. 双层异常处理互相冲突 / Double-Layer Exception Handling Conflict

位置 / Location: tool_registry.py:185-209base_tool.py:228-246

handle_tool_exceptions 装饰器在工具方法内部捕获所有异常并返回错误字符串。注册表 execute 方法中的 try/except 因此永远无法触发,导致 status 始终为硬编码的 "success"
The handle_tool_exceptions decorator catches all exceptions inside tool methods and returns error strings. Consequently, the try/except block in the registry's execute method never fires, keeping status stuck at the hardcoded "success".

# tool_registry.py:185-209
status = "success"                       # 初始设为 success,永远不会被改为 error
try:
    result = tool.func(*args, **kwargs)   # ← 装饰器已捕获异常并返回字符串
except Exception as e:                    # ← 永远不会执行
    status = "error"                      
    result = f'<func_name=...'

self._log_tool_call(func_name, kwargs, duration_ms, status)  # status 永远是 "success"

影响 / Impact: 所有调用(包括失败的)在审计日志中均被记录为成功。依赖 status 的错误分类逻辑(如 tool_registry.py:259-270PENDING_AUDIT 判定)完全失效。
All calls (including failures) are logged as successes in audit logs. Error classification logic depending on status (e.g., PENDING_AUDIT determination at tool_registry.py:259-270) is completely broken.


B. 返回类型不一致 / Inconsistent Return Types

位置 / Location: ls 工具,glob 工具,read 工具,stat 工具

工具 / Tool 成功返回类型 / Success Return Type 错误返回类型 / Error Return Type
ls list[str] str
glob list[str] str
read str str
stat str str

影响 / Impact: 调用方无法通过类型系统可靠区分成功与错误。对 ls 结果调用 isinstance(result, list) 可以部分区分,但这是隐式约定而非显式协议。
Callers cannot reliably distinguish success from error via the type system. Using isinstance(result, list) on ls results works partially, but this is an implicit convention, not an explicit protocol.


C. 封装穿透 / Encapsulation Breach

位置 / Location: base_tool.py:184edit_tool.py:109write_tool.py:55

工具类直接访问 self.workspace._current_session_id(私有属性),绕过了 Workspace 的封装边界。
Tool classes directly access self.workspace._current_session_id (a private attribute), bypassing Workspace's encapsulation boundary.

影响 / Impact: 破坏模块化设计。Workspacedb 提供了 @property 做延迟加载,但 session_id 没有对等接口,封装策略不一致。
Breaks modular design. Workspace provides a @property for lazy loading db, but session_id has no equivalent interface — encapsulation strategy is inconsistent.


修复建议 / Fix Suggestions

  1. 移除或重构异常处理装饰器:让装饰器将异常转换为结构化结果(如 ToolResult(error=...))而非吞噬异常,或完全移除装饰器,让注册表层的 try/except 统一处理。
    Remove or refactor the exception handling decorator: Let the decorator convert exceptions to structured results (e.g., ToolResult(error=...)) instead of swallowing them, or remove the decorator entirely and let the registry layer handle exceptions uniformly.

  2. 统一返回类型:所有工具应返回相同类型(如 ToolResult),显式包含 success 标志、数据或错误信息。
    Unify return types: All tools should return the same type (e.g., ToolResult), explicitly containing a success flag, data, or error information.

  3. 修复封装穿透:为 Workspace 添加 session_id 的公开 getter(如 @property def session_id(self)),工具类通过该接口访问。
    Fix encapsulation breach: Add a public getter for session_id on Workspace (e.g., @property def session_id(self)), and have tools access it via that interface.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions