Skip to content

Commit 6528bc2

Browse files
authored
Merge pull request #1246 from max-svistunov/lcore-1211-tools-endpoint-empty
LCORE-1211 Fix /v1/tools returning empty fields for all tools
2 parents f17ae57 + 757290c commit 6528bc2

2 files changed

Lines changed: 474 additions & 79 deletions

File tree

src/app/endpoints/tools.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,61 @@
2929
router = APIRouter(tags=["tools"])
3030

3131

32+
def _input_schema_to_parameters(
33+
schema: dict[str, Any] | None,
34+
) -> list[dict[str, Any]]:
35+
"""Convert a JSON Schema input_schema to a flat list of parameter dicts.
36+
37+
The Llama Stack SDK returns tool parameters as a JSON Schema object
38+
(``input_schema``). This function converts that representation into
39+
the flat parameter list format used by the tools endpoint response.
40+
41+
Parameters:
42+
schema: JSON Schema dict with ``properties`` and ``required`` keys,
43+
or ``None`` if the tool has no parameters.
44+
45+
Returns:
46+
A list of parameter dicts, each containing ``name``, ``description``,
47+
``parameter_type``, ``required``, and ``default`` keys.
48+
"""
49+
if not schema or "properties" not in schema:
50+
return []
51+
52+
required_params = set(schema.get("required", []))
53+
return [
54+
{
55+
"name": name,
56+
"description": prop.get("description", ""),
57+
"parameter_type": prop.get("type", "string"),
58+
"required": name in required_params,
59+
"default": prop.get("default"),
60+
}
61+
for name, prop in schema["properties"].items()
62+
]
63+
64+
65+
def _normalize_tool_dict(tool_dict: dict[str, Any], toolgroup: Any) -> None:
66+
"""Normalize a ToolDef dict to the endpoint's response format.
67+
68+
Remaps field names (``name`` -> ``identifier``, ``input_schema`` ->
69+
``parameters``) and propagates ``provider_id``/``type`` from the
70+
parent toolgroup. Handles both missing keys and empty legacy
71+
placeholders.
72+
"""
73+
if "name" in tool_dict and not tool_dict.get("identifier"):
74+
tool_dict["identifier"] = tool_dict["name"]
75+
tool_dict.pop("name", None)
76+
77+
if "input_schema" in tool_dict and not tool_dict.get("parameters"):
78+
tool_dict["parameters"] = _input_schema_to_parameters(tool_dict["input_schema"])
79+
tool_dict.pop("input_schema", None)
80+
81+
if not tool_dict.get("provider_id"):
82+
tool_dict["provider_id"] = toolgroup.provider_id
83+
if not tool_dict.get("type"):
84+
tool_dict["type"] = getattr(toolgroup, "type", None) or "tool"
85+
86+
3287
tools_responses: dict[int | str, dict[str, Any]] = {
3388
200: ToolsResponse.openapi_response(),
3489
401: UnauthorizedResponse.openapi_response(
@@ -120,6 +175,8 @@ async def tools_endpoint_handler( # pylint: disable=too-many-locals,too-many-st
120175
for tool in tools_response:
121176
tool_dict = dict(tool)
122177

178+
_normalize_tool_dict(tool_dict, toolgroup)
179+
123180
# Determine server source based on toolgroup type
124181
if toolgroup.identifier in mcp_server_names:
125182
# This is an MCP server toolgroup

0 commit comments

Comments
 (0)