|
5 | 5 | from typing import Any |
6 | 6 |
|
7 | 7 | from deepset_mcp.api.exceptions import UnexpectedAPIError |
8 | | -from deepset_mcp.api.pipeline_template.models import PipelineTemplate, PipelineTemplateList |
| 8 | +from deepset_mcp.api.pipeline_template.models import PipelineTemplate |
9 | 9 | from deepset_mcp.api.pipeline_template.protocols import PipelineTemplateResourceProtocol |
10 | 10 | from deepset_mcp.api.protocols import AsyncClientProtocol |
| 11 | +from deepset_mcp.api.shared_models import PaginatedResponse |
11 | 12 | from deepset_mcp.api.transport import raise_for_status |
12 | 13 |
|
13 | 14 |
|
@@ -46,47 +47,58 @@ async def get_template(self, template_name: str) -> PipelineTemplate: |
46 | 47 |
|
47 | 48 | return PipelineTemplate.model_validate(data) |
48 | 49 |
|
49 | | - async def list_templates( |
50 | | - self, limit: int = 100, field: str = "created_at", order: str = "DESC", filter: str | None = None |
51 | | - ) -> PipelineTemplateList: |
52 | | - """List pipeline templates in the configured workspace. |
53 | | -
|
54 | | - Parameters |
55 | | - ---------- |
56 | | - limit : int, optional (default=100) |
57 | | - Maximum number of templates to return |
58 | | - field : str, optional (default="created_at") |
59 | | - Field to sort by |
60 | | - order : str, optional (default="DESC") |
61 | | - Sort order (ASC or DESC) |
62 | | - filter : str | None, optional (default=None) |
63 | | - OData filter expression for filtering templates |
64 | | -
|
65 | | - Returns |
66 | | - ------- |
67 | | - PipelineTemplateList |
68 | | - List of pipeline templates with metadata |
| 50 | + async def list( |
| 51 | + self, |
| 52 | + limit: int = 10, |
| 53 | + after: str | None = None, |
| 54 | + field: str = "created_at", |
| 55 | + order: str = "DESC", |
| 56 | + filter: str | None = None, |
| 57 | + ) -> PaginatedResponse[PipelineTemplate]: |
| 58 | + """Lists pipeline templates and returns the first page of results. |
| 59 | +
|
| 60 | + The returned object can be iterated over to fetch subsequent pages. |
| 61 | +
|
| 62 | + :param limit: The maximum number of pipeline templates to return per page. |
| 63 | + :param after: The cursor to fetch the next page of results. |
| 64 | + :param field: Field to sort by (default: "created_at"). |
| 65 | + :param order: Sort order, either "ASC" or "DESC" (default: "DESC"). |
| 66 | + :param filter: OData filter expression for filtering templates. |
| 67 | + :returns: A `PaginatedResponse` object containing the first page of pipeline templates. |
69 | 68 | """ |
70 | | - params = {"limit": limit, "page_number": 1, "field": field, "order": order} |
71 | | - |
| 69 | + # TODO: Remove when fixed |
| 70 | + if after is not None: |
| 71 | + raise ValueError("Pagination using 'after' parameter is currently not supported by the deepset platform.") |
| 72 | + |
| 73 | + # 1. Prepare arguments for the initial API call |
| 74 | + # TODO: Pagination in the deepset API is currently implemented in an unintuitive way. |
| 75 | + # TODO: The cursor is always time based (created_at) and after signifies templates older than the current cursor |
| 76 | + # TODO: while 'before' signals templates younger than the current cursor. |
| 77 | + # TODO: This is applied irrespective of any sort (e.g. name) that would conflict with this approach. |
| 78 | + # TODO: Change this to 'after' once the behaviour is fixed on the deepset API |
| 79 | + request_params = {"limit": limit, "before": after, "field": field, "order": order} |
72 | 80 | if filter is not None: |
73 | | - params["filter"] = filter |
| 81 | + request_params["filter"] = filter |
| 82 | + request_params = {k: v for k, v in request_params.items() if v is not None} |
74 | 83 |
|
75 | | - response = await self._client.request( |
76 | | - f"/v1/workspaces/{self._workspace}/pipeline_templates", |
77 | | - method="GET", |
78 | | - params=params, |
79 | | - ) |
80 | | - |
81 | | - raise_for_status(response) |
| 84 | + # 2. Make the first API call using a private, stateless method |
| 85 | + page = await self._list_api_call(**request_params) |
82 | 86 |
|
83 | | - if response.json is None: |
84 | | - raise UnexpectedAPIError(message="Unexpected API response, no templates returned.") |
85 | | - |
86 | | - response_data: dict[str, Any] = response.json |
| 87 | + # 3. Inject the logic needed for subsequent fetches into the response object |
| 88 | + page._inject_paginator( |
| 89 | + fetch_func=self._list_api_call, |
| 90 | + # Base args for the *next* fetch don't include initial cursors |
| 91 | + base_args={"limit": limit, "field": field, "order": order, "filter": filter}, |
| 92 | + ) |
| 93 | + return page |
87 | 94 |
|
88 | | - return PipelineTemplateList( |
89 | | - data=[PipelineTemplate.model_validate(template) for template in response_data["data"]], |
90 | | - has_more=response_data.get("has_more", False), |
91 | | - total=response_data.get("total", len(response_data["data"])), |
| 95 | + async def _list_api_call(self, **kwargs: Any) -> PaginatedResponse[PipelineTemplate]: |
| 96 | + """A private, stateless method that performs the raw API call.""" |
| 97 | + resp = await self._client.request( |
| 98 | + endpoint=f"v1/workspaces/{self._workspace}/pipeline_templates", method="GET", params=kwargs |
92 | 99 | ) |
| 100 | + raise_for_status(resp) |
| 101 | + if resp.json is None: |
| 102 | + raise UnexpectedAPIError(status_code=resp.status_code, message="Empty response", detail=None) |
| 103 | + |
| 104 | + return PaginatedResponse[PipelineTemplate].create_with_cursor_field(resp.json, "name") |
0 commit comments