Skip to content

Commit 617fd74

Browse files
lesebclaudecdoern
authored
refactor(tools)!: move /v1/tools route to /v1/admin/tools (ogx-ai#5787)
# What does this PR do? Moves the `GET /v1/tools` endpoint to `GET /v1/admin/tools`, following the same pattern as ogx-ai#5659 (connectors → admin). Tools are admin-controlled resources configured at the distribution level, not user-scoped — users don't register or unregister tool groups. The rationale is identical to the connectors move. **Pattern followed from ogx-ai#5659:** - `Admin` protocol gains `list_tools` method - `AdminImpl` delegates to the `ToolGroupsRoutingTable` via `self.deps` - Tools `fastapi_routes.py` deleted; route served by the admin router - Admin router restructured with sub-routers to support both `/v1alpha` (existing admin endpoints) and `/v1` (tools) prefixes **BREAKING CHANGE:** `GET /v1/tools` is removed. Use `GET /v1/admin/tools` instead. ## Test Plan 1. Pre-commit checks pass (all except `api-conformance` which is expected for breaking changes — the `refactor!:` commit message signals intentional breakage) 2. Unit tests pass: `uv run pytest tests/unit/core/ --tb=short -q -k "tool or route or admin"` — 77 passed 3. mypy passes with no errors 4. OpenAPI specs regenerated and validated --------- Signed-off-by: Sébastien Han <seb@redhat.com> Signed-off-by: Charlie Doern <cdoern@redhat.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Charlie Doern <cdoern@redhat.com>
1 parent 58d74f4 commit 617fd74

9 files changed

Lines changed: 65 additions & 81 deletions

File tree

client-sdks/stainless/openapi.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,7 +2087,7 @@ paths:
20872087
title: Identifier
20882088
description: The identifier of the shield to unregister.
20892089
deprecated: true
2090-
/v1/tools:
2090+
/v1/admin/tools:
20912091
get:
20922092
responses:
20932093
'200':
@@ -2112,7 +2112,7 @@ paths:
21122112
- Tools
21132113
summary: List tools with optional tool group filter.
21142114
description: List tools with optional tool group filter.
2115-
operationId: list_tools_v1_tools_get
2115+
operationId: list_tools_v1_admin_tools_get
21162116
parameters:
21172117
- name: toolgroup_id
21182118
in: query

docs/static/ogx-spec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,7 +1926,7 @@ paths:
19261926
input_items = client.responses.input_items.list("resp_abc123")
19271927
for item in input_items:
19281928
print(item)
1929-
/v1/tools:
1929+
/v1/admin/tools:
19301930
get:
19311931
responses:
19321932
'200':
@@ -1951,7 +1951,7 @@ paths:
19511951
- Tools
19521952
summary: List tools with optional tool group filter.
19531953
description: List tools with optional tool group filter.
1954-
operationId: list_tools_v1_tools_get
1954+
operationId: list_tools_v1_admin_tools_get
19551955
parameters:
19561956
- name: toolgroup_id
19571957
in: query

docs/static/stainless-ogx-spec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,7 +2087,7 @@ paths:
20872087
title: Identifier
20882088
description: The identifier of the shield to unregister.
20892089
deprecated: true
2090-
/v1/tools:
2090+
/v1/admin/tools:
20912091
get:
20922092
responses:
20932093
'200':
@@ -2112,7 +2112,7 @@ paths:
21122112
- Tools
21132113
summary: List tools with optional tool group filter.
21142114
description: List tools with optional tool group filter.
2115-
operationId: list_tools_v1_tools_get
2115+
operationId: list_tools_v1_admin_tools_get
21162116
parameters:
21172117
- name: toolgroup_id
21182118
in: query

scripts/openapi_generator/_legacy_order.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"/v1/tool-runtime/list-tools",
4848
"/v1/toolgroups",
4949
"/v1/toolgroups/{toolgroup_id}",
50-
"/v1/tools",
50+
"/v1/admin/tools",
5151
"/v1/tools/{tool_name}",
5252
"/v1/vector-io/insert",
5353
"/v1/vector-io/query",

src/ogx/core/admin.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
ListToolsResponse,
4343
)
4444
from ogx_api.tools import ToolDef
45+
from ogx_api.tools.api import ToolGroups
46+
from ogx_api.tools.models import ListToolDefsResponse, ListToolsRequest
4547

4648
logger = get_logger(name=__name__, category="core")
4749

@@ -249,3 +251,10 @@ async def list_connector_tools(
249251

250252
async def get_connector_tool(self, request: GetConnectorToolRequest, authorization: str | None = None) -> ToolDef:
251253
return await self._connectors.get_connector_tool(request, authorization=authorization)
254+
255+
@property
256+
def _tool_groups(self) -> ToolGroups:
257+
return cast(ToolGroups, self.deps[Api.tool_groups.value])
258+
259+
async def list_tools(self, request: ListToolsRequest) -> ListToolDefsResponse:
260+
return await self._tool_groups.list_tools(request)

src/ogx_api/admin/api.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Protocol, runtime_checkable
88

99
from ogx_api.connectors.api import Connectors
10+
from ogx_api.tools.models import ListToolDefsResponse, ListToolsRequest
1011

1112
from .models import (
1213
HealthInfo,
@@ -72,3 +73,13 @@ async def version(self) -> VersionInfo:
7273
:returns: Version information containing the service version number.
7374
"""
7475
...
76+
77+
async def list_tools(self, request: ListToolsRequest) -> ListToolDefsResponse:
78+
"""List tools.
79+
80+
List tools with optional tool group filter.
81+
82+
:param request: Request containing optional filter parameters
83+
:returns: A ListToolDefsResponse containing available tool definitions.
84+
"""
85+
...

src/ogx_api/admin/fastapi_routes.py

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
)
2626
from ogx_api.router_utils import create_path_dependency, create_query_dependency, standard_responses
2727
from ogx_api.tools import ToolDef
28-
from ogx_api.version import OGX_API_V1ALPHA
28+
from ogx_api.tools.models import ListToolDefsResponse, ListToolsRequest
29+
from ogx_api.version import OGX_API_V1, OGX_API_V1ALPHA
2930

3031
from .api import Admin
3132
from .models import (
@@ -41,6 +42,7 @@
4142
# Automatically generate dependency functions from Pydantic models
4243
get_inspect_provider_request = create_path_dependency(InspectProviderRequest)
4344
get_list_routes_request = create_query_dependency(ListRoutesRequest)
45+
get_list_tools_request = create_query_dependency(ListToolsRequest)
4446
get_connector_request = create_path_dependency(GetConnectorRequest)
4547
list_connector_tools_request = create_path_dependency(ListConnectorToolsRequest)
4648

@@ -55,12 +57,15 @@ def create_router(impl: Admin) -> APIRouter:
5557
APIRouter configured for the Admin API
5658
"""
5759
router = APIRouter(
60+
responses=standard_responses,
61+
)
62+
63+
v1alpha_router = APIRouter(
5864
prefix=f"/{OGX_API_V1ALPHA}",
5965
tags=["Admin"],
60-
responses=standard_responses,
6166
)
6267

63-
@router.get(
68+
@v1alpha_router.get(
6469
"/admin/providers",
6570
response_model=ListProvidersResponse,
6671
summary="List all available providers",
@@ -72,7 +77,7 @@ def create_router(impl: Admin) -> APIRouter:
7277
async def list_providers() -> ListProvidersResponse:
7378
return await impl.list_providers()
7479

75-
@router.get(
80+
@v1alpha_router.get(
7681
"/admin/providers/{provider_id}",
7782
response_model=ProviderInfo,
7883
summary="Get provider details",
@@ -87,7 +92,7 @@ async def inspect_provider(
8792
) -> ProviderInfo:
8893
return await impl.inspect_provider(request)
8994

90-
@router.get(
95+
@v1alpha_router.get(
9196
"/admin/inspect/routes",
9297
response_model=ListRoutesResponse,
9398
summary="List all available API routes",
@@ -101,7 +106,7 @@ async def list_routes(
101106
) -> ListRoutesResponse:
102107
return await impl.list_routes(request)
103108

104-
@router.get(
109+
@v1alpha_router.get(
105110
"/admin/health",
106111
response_model=HealthInfo,
107112
summary="Get service health status",
@@ -113,7 +118,7 @@ async def list_routes(
113118
async def health() -> HealthInfo:
114119
return await impl.health()
115120

116-
@router.get(
121+
@v1alpha_router.get(
117122
"/admin/version",
118123
response_model=VersionInfo,
119124
summary="Get service version",
@@ -125,7 +130,7 @@ async def health() -> HealthInfo:
125130
async def version() -> VersionInfo:
126131
return await impl.version()
127132

128-
@router.get(
133+
@v1alpha_router.get(
129134
"/admin/connectors",
130135
response_model=ListConnectorsResponse,
131136
summary="List all connectors.",
@@ -134,7 +139,7 @@ async def version() -> VersionInfo:
134139
async def list_connectors() -> ListConnectorsResponse:
135140
return await impl.list_connectors()
136141

137-
@router.get(
142+
@v1alpha_router.get(
138143
"/admin/connectors/{connector_id}/tools/{tool_name}",
139144
response_model=ToolDef,
140145
summary="Get a tool by name from a connector.",
@@ -148,7 +153,7 @@ async def get_connector_tool(
148153
request = GetConnectorToolRequest(connector_id=connector_id, tool_name=tool_name)
149154
return await impl.get_connector_tool(request, authorization=authorization)
150155

151-
@router.get(
156+
@v1alpha_router.get(
152157
"/admin/connectors/{connector_id}/tools",
153158
response_model=ListToolsResponse,
154159
summary="List tools from a connector.",
@@ -160,7 +165,7 @@ async def list_connector_tools(
160165
) -> ListToolsResponse:
161166
return await impl.list_connector_tools(request, authorization=authorization)
162167

163-
@router.get(
168+
@v1alpha_router.get(
164169
"/admin/connectors/{connector_id}",
165170
response_model=Connector,
166171
summary="Get a connector by its ID.",
@@ -172,4 +177,26 @@ async def get_connector(
172177
) -> Connector:
173178
return await impl.get_connector(request, authorization=authorization)
174179

180+
v1_router = APIRouter(
181+
prefix=f"/{OGX_API_V1}",
182+
tags=["Tools"],
183+
)
184+
185+
@v1_router.get(
186+
"/admin/tools",
187+
response_model=ListToolDefsResponse,
188+
summary="List tools with optional tool group filter.",
189+
description="List tools with optional tool group filter.",
190+
responses={
191+
200: {"description": "A ListToolDefsResponse."},
192+
},
193+
)
194+
async def list_tools(
195+
request: Annotated[ListToolsRequest, Depends(get_list_tools_request)],
196+
) -> ListToolDefsResponse:
197+
return await impl.list_tools(request)
198+
199+
router.include_router(v1alpha_router)
200+
router.include_router(v1_router)
201+
175202
return router

src/ogx_api/tools/__init__.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,8 @@
88
99
This module contains the ToolGroups and ToolRuntime protocol definitions.
1010
Pydantic models are defined in ogx_api.tools.models.
11-
The FastAPI router is defined in ogx_api.tools.fastapi_routes.
1211
"""
1312

14-
# Import fastapi_routes for router factory access
15-
from . import fastapi_routes
16-
1713
# Import protocols for re-export
1814
from .api import ToolGroups, ToolRuntime
1915

@@ -42,5 +38,4 @@
4238
"ToolInvocationResult",
4339
"ToolRuntime",
4440
"ToolStore",
45-
"fastapi_routes",
4641
]

src/ogx_api/tools/fastapi_routes.py

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)