fix: preserve legacy plugin tool errors

This commit is contained in:
chengyongru
2026-07-01 13:03:47 +08:00
committed by Xubin Ren
parent 8493560976
commit b0258e8b20
4 changed files with 245 additions and 4 deletions
+67 -1
View File
@@ -8,7 +8,7 @@ from typing import Any
from loguru import logger
from nanobot.agent.tools.base import Tool
from nanobot.agent.tools.base import Tool, ToolResult
from nanobot.agent.tools.registry import ToolRegistry
_SKIP_MODULES = frozenset({
@@ -96,6 +96,8 @@ class ToolLoader:
if not tool_cls.enabled(ctx):
continue
tool = tool_cls.create(ctx)
if is_plugin_source:
tool = _LegacyErrorPrefixTool(tool)
if registry.has(tool.name):
if is_plugin_source and tool.name in builtin_names:
logger.warning(
@@ -114,3 +116,67 @@ class ToolLoader:
except Exception:
logger.exception("Failed to register tool: %s", cls_label)
return registered
class _LegacyErrorPrefixTool(Tool):
"""Compatibility wrapper for external tools using the old error-string contract."""
_plugin_discoverable = False
def __init__(self, wrapped: Tool) -> None:
self._wrapped = wrapped
@property
def name(self) -> str:
return self._wrapped.name
@property
def description(self) -> str:
return self._wrapped.description
@property
def parameters(self) -> dict[str, Any]:
return self._wrapped.parameters
@property
def read_only(self) -> bool:
return self._wrapped.read_only
@property
def exclusive(self) -> bool:
return self._wrapped.exclusive
@property
def concurrency_safe(self) -> bool:
return self._wrapped.concurrency_safe
@property
def config_key(self) -> str:
return getattr(self._wrapped, "config_key", "")
def set_context(self, ctx: Any) -> None:
set_context = getattr(self._wrapped, "set_context", None)
if callable(set_context):
set_context(ctx)
def cast_params(self, params: dict[str, Any]) -> dict[str, Any]:
return self._wrapped.cast_params(params)
def validate_params(self, params: dict[str, Any]) -> list[str]:
return self._wrapped.validate_params(params)
def to_schema(self) -> dict[str, Any]:
return self._wrapped.to_schema()
async def execute(self, **kwargs: Any) -> Any:
result = await self._wrapped.execute(**kwargs)
if (
isinstance(result, str)
and not isinstance(result, ToolResult)
and result.startswith("Error:")
):
return ToolResult.error(result)
return result
def __getattr__(self, name: str) -> Any:
return getattr(self._wrapped, name)
+2 -2
View File
@@ -445,9 +445,9 @@ class WebSearchTool(Tool):
items = [{"title": answer_text or "Olostep answer", "url": "", "content": "\n".join(source_lines)}]
return _format_results(query, items, n)
except Olostep_BaseError as e:
return f"Olostep search error: {type(e).__name__}: {e}"
return ToolResult.error(f"Error: Olostep search error: {type(e).__name__}: {e}")
except Exception as e:
return f"Olostep search error: {type(e).__name__}: {e}"
return ToolResult.error(f"Error: Olostep search error: {type(e).__name__}: {e}")
async def _search_brave(self, query: str, n: int) -> str:
api_key = self.config.api_key or os.environ.get("BRAVE_API_KEY", "")