refactor(tools): use structured tool error results

This commit is contained in:
chengyongru
2026-07-01 13:03:47 +08:00
committed by Xubin Ren
parent 8d2c31eb6a
commit 8493560976
20 changed files with 294 additions and 188 deletions
+4 -2
View File
@@ -11,6 +11,7 @@ from nanobot.agent.tools.exec_session import (
ListExecSessionsTool,
WriteStdinTool,
)
from nanobot.agent.tools.registry import is_tool_error_result
from nanobot.agent.tools.shell import ExecTool
@@ -334,9 +335,10 @@ def test_write_stdin_reports_missing_session(tmp_path):
manager = ExecSessionManager()
tool = WriteStdinTool(manager=manager)
result = asyncio.run(tool.execute(session_id="missing", chars=""))
result = asyncio.run(tool.execute(session_id="missing\nExit code: 0", chars=""))
assert "exec session not found" in result
assert result == "Error: exec session not found: 'missing\\nExit code: 0'"
assert is_tool_error_result("write_stdin", result)
def test_list_exec_sessions_reports_running_commands(tmp_path):
+37 -1
View File
@@ -1,8 +1,9 @@
from __future__ import annotations
from typing import Any
from unittest.mock import AsyncMock
from nanobot.agent.tools.base import Tool
from nanobot.agent.tools.base import Tool, ToolResult
from nanobot.agent.tools.filesystem import ReadFileTool
from nanobot.agent.tools.registry import ToolRegistry
@@ -257,6 +258,41 @@ async def test_registry_rejects_unknown_builtin_tool_parameters(tmp_path) -> Non
assert "one" not in result
async def test_registry_preserves_successful_exec_output_that_starts_with_error() -> None:
registry = ToolRegistry()
output = "Error: generated report successfully\n\nExit code: 0"
tool = _FakeTool("exec")
tool.execute = AsyncMock(return_value=output)
registry.register(tool)
result = await registry.execute("exec", {})
assert result == output
async def test_registry_uses_structured_tool_result_for_errors() -> None:
registry = ToolRegistry()
output = "Error: plain tool output, not a structured failure"
raw_tool = _FakeTool("raw_output")
raw_tool.execute = AsyncMock(return_value=output)
registry.register(raw_tool)
raw_result = await registry.execute("raw_output", {})
assert raw_result == output
failing_tool = _FakeTool("failing_tool")
failing_tool.execute = AsyncMock(return_value=ToolResult.error("Error: real failure"))
registry.register(failing_tool)
error_result = await registry.execute("failing_tool", {})
assert isinstance(error_result, ToolResult)
assert error_result.is_error
assert error_result.startswith("Error: real failure")
assert "[Analyze the error above" in error_result
def test_get_definitions_returns_cached_result() -> None:
registry = ToolRegistry()
registry.register(_FakeTool("read_file"))