"""List documentation for all registered tools in the tool registry."""
from __future__ import annotations
import json
import logging
from typing import Optional
logger = logging.getLogger(__name__)
TOOL_NAME = "list_all_tools"
TOOL_DESCRIPTION = (
"List documentation for ALL tools registered in the registry, "
"including names, descriptions, and parameters. "
"Optionally filter by keyword. If a channel ID is provided, "
"the listing is also uploaded to that channel as a JSON file."
)
TOOL_PARAMETERS = {
"type": "object",
"properties": {
"search_keyword": {
"type": "string",
"description": "Optional keyword to search tool names and descriptions.",
},
"include_parameters": {
"type": "boolean",
"description": "Include parameter details (default true).",
},
"channel": {
"type": "string",
"description": (
"Optional channel ID. When provided, the tools listing "
"is uploaded to this channel as a JSON file in addition "
"to being returned."
),
},
},
}
[docs]
async def run(
search_keyword: Optional[str] = None,
include_parameters: bool = True,
channel: Optional[str] = None,
ctx=None,
**_kwargs,
) -> str:
"""Execute this tool and return the result.
Args:
search_keyword (Optional[str]): The search keyword value.
include_parameters (bool): The include parameters value.
channel (Optional[str]): Channel ID to upload the listing to.
ctx: Tool execution context providing access to bot internals.
Returns:
str: Result string.
"""
try:
registry = getattr(ctx, "tool_registry", None) if ctx else None
if registry is None:
return json.dumps({
"success": False,
"error": "Tool registry not available via ctx",
})
all_tools = registry.list_tools()
if search_keyword:
kw = search_keyword.lower()
all_tools = [
t for t in all_tools
if kw in t.name.lower()
or (t.description and kw in t.description.lower())
]
tools_docs = []
for tool in sorted(all_tools, key=lambda t: t.name):
doc: dict = {
"name": tool.name,
"description": tool.description or "No description available",
}
if include_parameters and tool.parameters:
doc["parameters"] = {
"properties": tool.parameters.get("properties", {}),
"required": tool.parameters.get("required", []),
}
tools_docs.append(doc)
result = {
"success": True,
"tool_count": len(tools_docs),
"filter_applied": search_keyword or None,
"tools": tools_docs,
}
# -- Upload to channel if requested --
if channel:
adapter = getattr(ctx, "adapter", None) if ctx else None
if adapter is None:
result["channel_upload"] = "skipped — no platform adapter available"
else:
try:
result_json = json.dumps(result, indent=2).encode("utf-8")
await adapter.send_file(
channel,
result_json,
"tools_list.json",
"application/json",
)
result["channel_upload"] = f"uploaded to {channel}"
except Exception as upload_err:
logger.warning(
"Failed to upload tools list to channel %s: %s",
channel, upload_err,
)
result["channel_upload"] = f"failed — {upload_err}"
return json.dumps(result, indent=2)
except Exception as e:
logger.error("Error listing tools: %s", e)
return json.dumps({"success": False, "error": f"Failed to list tools: {e}"})