From 7ff0bdf181029f0711b694fb6498fbc75183b0f3 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 3 Jun 2026 21:04:44 +0000
Subject: [PATCH 1/5] feat: api: paginate GET /proxies
---
.stats.yml | 6 +-
api.md | 2 +-
src/kernel/resources/proxies.py | 83 +++++++++++++++++++++----
src/kernel/types/__init__.py | 1 +
src/kernel/types/proxy_list_params.py | 15 +++++
src/kernel/types/proxy_list_response.py | 42 ++++++-------
tests/api_resources/test_proxies.py | 31 +++++++--
7 files changed, 134 insertions(+), 46 deletions(-)
create mode 100644 src/kernel/types/proxy_list_params.py
diff --git a/.stats.yml b/.stats.yml
index 27228661..032ac8ce 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 117
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-33e46e6a0095c2ec39a51860ee4e133c5a21a80a90cbe9e52953c07e5e0295de.yml
-openapi_spec_hash: 4aa466b9af39768b65a44b68ae0d1f6e
-config_hash: ede72e4ae65cc5a6d6927938b3455c46
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-f3e52a8a9d9e37f8b527bdcce63b39cf8807d138cf3570c9954ba7f42ef02375.yml
+openapi_spec_hash: 2b787691eba1bb7bafb553528c09d5c0
+config_hash: e12afec516ced9520590c7a05af7a6f7
diff --git a/api.md b/api.md
index a7fda470..1cc2b82f 100644
--- a/api.md
+++ b/api.md
@@ -324,7 +324,7 @@ Methods:
- client.proxies.create(\*\*params) -> ProxyCreateResponse
- client.proxies.retrieve(id) -> ProxyRetrieveResponse
-- client.proxies.list() -> ProxyListResponse
+- client.proxies.list(\*\*params) -> SyncOffsetPagination[ProxyListResponse]
- client.proxies.delete(id) -> None
- client.proxies.check(id, \*\*params) -> ProxyCheckResponse
diff --git a/src/kernel/resources/proxies.py b/src/kernel/resources/proxies.py
index 501a2e88..2239a854 100644
--- a/src/kernel/resources/proxies.py
+++ b/src/kernel/resources/proxies.py
@@ -6,7 +6,7 @@
import httpx
-from ..types import proxy_check_params, proxy_create_params
+from ..types import proxy_list_params, proxy_check_params, proxy_create_params
from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given
from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -17,7 +17,8 @@
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
-from .._base_client import make_request_options
+from ..pagination import SyncOffsetPagination, AsyncOffsetPagination
+from .._base_client import AsyncPaginator, make_request_options
from ..types.proxy_list_response import ProxyListResponse
from ..types.proxy_check_response import ProxyCheckResponse
from ..types.proxy_create_response import ProxyCreateResponse
@@ -140,20 +141,48 @@ def retrieve(
def list(
self,
*,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> ProxyListResponse:
- """List proxies owned by the caller's organization."""
- return self._get(
+ ) -> SyncOffsetPagination[ProxyListResponse]:
+ """
+ List proxies owned by the caller's organization.
+
+ Args:
+ limit: Limit the number of proxies to return.
+
+ offset: Offset the number of proxies to return.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/proxies",
+ page=SyncOffsetPagination[ProxyListResponse],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ proxy_list_params.ProxyListParams,
+ ),
),
- cast_to=ProxyListResponse,
+ model=ProxyListResponse,
)
def delete(
@@ -357,23 +386,51 @@ async def retrieve(
cast_to=ProxyRetrieveResponse,
)
- async def list(
+ def list(
self,
*,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> ProxyListResponse:
- """List proxies owned by the caller's organization."""
- return await self._get(
+ ) -> AsyncPaginator[ProxyListResponse, AsyncOffsetPagination[ProxyListResponse]]:
+ """
+ List proxies owned by the caller's organization.
+
+ Args:
+ limit: Limit the number of proxies to return.
+
+ offset: Offset the number of proxies to return.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/proxies",
+ page=AsyncOffsetPagination[ProxyListResponse],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ proxy_list_params.ProxyListParams,
+ ),
),
- cast_to=ProxyListResponse,
+ model=ProxyListResponse,
)
async def delete(
diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py
index fb6fd589..bdc65fdf 100644
--- a/src/kernel/types/__init__.py
+++ b/src/kernel/types/__init__.py
@@ -25,6 +25,7 @@
from .created_api_key import CreatedAPIKey as CreatedAPIKey
from .browser_pool_ref import BrowserPoolRef as BrowserPoolRef
from .app_list_response import AppListResponse as AppListResponse
+from .proxy_list_params import ProxyListParams as ProxyListParams
from .proxy_check_params import ProxyCheckParams as ProxyCheckParams
from .api_key_list_params import APIKeyListParams as APIKeyListParams
from .browser_curl_params import BrowserCurlParams as BrowserCurlParams
diff --git a/src/kernel/types/proxy_list_params.py b/src/kernel/types/proxy_list_params.py
new file mode 100644
index 00000000..78972bcb
--- /dev/null
+++ b/src/kernel/types/proxy_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["ProxyListParams"]
+
+
+class ProxyListParams(TypedDict, total=False):
+ limit: int
+ """Limit the number of proxies to return."""
+
+ offset: int
+ """Offset the number of proxies to return."""
diff --git a/src/kernel/types/proxy_list_response.py b/src/kernel/types/proxy_list_response.py
index d1ddc079..6d40a8a4 100644
--- a/src/kernel/types/proxy_list_response.py
+++ b/src/kernel/types/proxy_list_response.py
@@ -8,31 +8,30 @@
__all__ = [
"ProxyListResponse",
- "ProxyListResponseItem",
- "ProxyListResponseItemConfig",
- "ProxyListResponseItemConfigDatacenterProxyConfig",
- "ProxyListResponseItemConfigIspProxyConfig",
- "ProxyListResponseItemConfigResidentialProxyConfig",
- "ProxyListResponseItemConfigMobileProxyConfig",
- "ProxyListResponseItemConfigCustomProxyConfig",
+ "Config",
+ "ConfigDatacenterProxyConfig",
+ "ConfigIspProxyConfig",
+ "ConfigResidentialProxyConfig",
+ "ConfigMobileProxyConfig",
+ "ConfigCustomProxyConfig",
]
-class ProxyListResponseItemConfigDatacenterProxyConfig(BaseModel):
+class ConfigDatacenterProxyConfig(BaseModel):
"""Configuration for a datacenter proxy."""
country: Optional[str] = None
"""ISO 3166 country code. Defaults to US if not provided."""
-class ProxyListResponseItemConfigIspProxyConfig(BaseModel):
+class ConfigIspProxyConfig(BaseModel):
"""Configuration for an ISP proxy."""
country: Optional[str] = None
"""ISO 3166 country code. Defaults to US if not provided."""
-class ProxyListResponseItemConfigResidentialProxyConfig(BaseModel):
+class ConfigResidentialProxyConfig(BaseModel):
"""Configuration for residential proxies."""
asn: Optional[str] = None
@@ -57,7 +56,7 @@ class ProxyListResponseItemConfigResidentialProxyConfig(BaseModel):
"""US ZIP code."""
-class ProxyListResponseItemConfigMobileProxyConfig(BaseModel):
+class ConfigMobileProxyConfig(BaseModel):
"""Configuration for mobile proxies."""
city: Optional[str] = None
@@ -70,7 +69,7 @@ class ProxyListResponseItemConfigMobileProxyConfig(BaseModel):
"""US-only state code. Mobile carrier routing can make observed geo vary."""
-class ProxyListResponseItemConfigCustomProxyConfig(BaseModel):
+class ConfigCustomProxyConfig(BaseModel):
"""Configuration for a custom proxy (e.g., private proxy server)."""
host: str
@@ -86,16 +85,16 @@ class ProxyListResponseItemConfigCustomProxyConfig(BaseModel):
"""Username for proxy authentication."""
-ProxyListResponseItemConfig: TypeAlias = Union[
- ProxyListResponseItemConfigDatacenterProxyConfig,
- ProxyListResponseItemConfigIspProxyConfig,
- ProxyListResponseItemConfigResidentialProxyConfig,
- ProxyListResponseItemConfigMobileProxyConfig,
- ProxyListResponseItemConfigCustomProxyConfig,
+Config: TypeAlias = Union[
+ ConfigDatacenterProxyConfig,
+ ConfigIspProxyConfig,
+ ConfigResidentialProxyConfig,
+ ConfigMobileProxyConfig,
+ ConfigCustomProxyConfig,
]
-class ProxyListResponseItem(BaseModel):
+class ProxyListResponse(BaseModel):
"""Configuration for routing traffic through a proxy."""
type: Literal["datacenter", "isp", "residential", "mobile", "custom"]
@@ -110,7 +109,7 @@ class ProxyListResponseItem(BaseModel):
bypass_hosts: Optional[List[str]] = None
"""Hostnames that should bypass the parent proxy and connect directly."""
- config: Optional[ProxyListResponseItemConfig] = None
+ config: Optional[Config] = None
"""Configuration specific to the selected proxy `type`."""
ip_address: Optional[str] = None
@@ -127,6 +126,3 @@ class ProxyListResponseItem(BaseModel):
status: Optional[Literal["available", "unavailable"]] = None
"""Current health status of the proxy."""
-
-
-ProxyListResponse: TypeAlias = List[ProxyListResponseItem]
diff --git a/tests/api_resources/test_proxies.py b/tests/api_resources/test_proxies.py
index fd8080ee..64cb90b9 100644
--- a/tests/api_resources/test_proxies.py
+++ b/tests/api_resources/test_proxies.py
@@ -15,6 +15,7 @@
ProxyCreateResponse,
ProxyRetrieveResponse,
)
+from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -114,7 +115,16 @@ def test_path_params_retrieve(self, client: Kernel) -> None:
@parametrize
def test_method_list(self, client: Kernel) -> None:
proxy = client.proxies.list()
- assert_matches_type(ProxyListResponse, proxy, path=["response"])
+ assert_matches_type(SyncOffsetPagination[ProxyListResponse], proxy, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Kernel) -> None:
+ proxy = client.proxies.list(
+ limit=1,
+ offset=0,
+ )
+ assert_matches_type(SyncOffsetPagination[ProxyListResponse], proxy, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -124,7 +134,7 @@ def test_raw_response_list(self, client: Kernel) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
proxy = response.parse()
- assert_matches_type(ProxyListResponse, proxy, path=["response"])
+ assert_matches_type(SyncOffsetPagination[ProxyListResponse], proxy, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -134,7 +144,7 @@ def test_streaming_response_list(self, client: Kernel) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
proxy = response.parse()
- assert_matches_type(ProxyListResponse, proxy, path=["response"])
+ assert_matches_type(SyncOffsetPagination[ProxyListResponse], proxy, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -329,7 +339,16 @@ async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncKernel) -> None:
proxy = await async_client.proxies.list()
- assert_matches_type(ProxyListResponse, proxy, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[ProxyListResponse], proxy, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None:
+ proxy = await async_client.proxies.list(
+ limit=1,
+ offset=0,
+ )
+ assert_matches_type(AsyncOffsetPagination[ProxyListResponse], proxy, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -339,7 +358,7 @@ async def test_raw_response_list(self, async_client: AsyncKernel) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
proxy = await response.parse()
- assert_matches_type(ProxyListResponse, proxy, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[ProxyListResponse], proxy, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -349,7 +368,7 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
proxy = await response.parse()
- assert_matches_type(ProxyListResponse, proxy, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[ProxyListResponse], proxy, path=["response"])
assert cast(Any, response.is_closed) is True
From c25d693e310a1035d74654018f68b311f37545d0 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 3 Jun 2026 21:54:03 +0000
Subject: [PATCH 2/5] feat: api: paginate GET /browser_pools
---
.stats.yml | 6 +-
api.md | 4 +-
src/kernel/resources/browser_pools.py | 83 ++++++++++++++++---
src/kernel/types/__init__.py | 2 +-
src/kernel/types/browser_pool_list_params.py | 15 ++++
.../types/browser_pool_list_response.py | 10 ---
tests/api_resources/test_browser_pools.py | 32 +++++--
7 files changed, 116 insertions(+), 36 deletions(-)
create mode 100644 src/kernel/types/browser_pool_list_params.py
delete mode 100644 src/kernel/types/browser_pool_list_response.py
diff --git a/.stats.yml b/.stats.yml
index 032ac8ce..d6e38f27 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 117
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-f3e52a8a9d9e37f8b527bdcce63b39cf8807d138cf3570c9954ba7f42ef02375.yml
-openapi_spec_hash: 2b787691eba1bb7bafb553528c09d5c0
-config_hash: e12afec516ced9520590c7a05af7a6f7
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-e5524e6eeeedc614c05bf19896f1ce6c4f8a113de85c02952d6874d579651f70.yml
+openapi_spec_hash: 7815a189a50e6aa9e283213cc78d041c
+config_hash: 453b25a35834fd59a55a2315d1d50746
diff --git a/api.md b/api.md
index 1cc2b82f..8a6b8c6e 100644
--- a/api.md
+++ b/api.md
@@ -349,7 +349,7 @@ Methods:
Types:
```python
-from kernel.types import BrowserPool, BrowserPoolListResponse, BrowserPoolAcquireResponse
+from kernel.types import BrowserPool, BrowserPoolAcquireResponse
```
Methods:
@@ -357,7 +357,7 @@ Methods:
- client.browser_pools.create(\*\*params) -> BrowserPool
- client.browser_pools.retrieve(id_or_name) -> BrowserPool
- client.browser_pools.update(id_or_name, \*\*params) -> BrowserPool
-- client.browser_pools.list() -> BrowserPoolListResponse
+- client.browser_pools.list(\*\*params) -> SyncOffsetPagination[BrowserPool]
- client.browser_pools.delete(id_or_name, \*\*params) -> None
- client.browser_pools.acquire(id_or_name, \*\*params) -> BrowserPoolAcquireResponse
- client.browser_pools.flush(id_or_name) -> None
diff --git a/src/kernel/resources/browser_pools.py b/src/kernel/resources/browser_pools.py
index 64751271..203e22ad 100644
--- a/src/kernel/resources/browser_pools.py
+++ b/src/kernel/resources/browser_pools.py
@@ -7,6 +7,7 @@
import httpx
from ..types import (
+ browser_pool_list_params,
browser_pool_create_params,
browser_pool_delete_params,
browser_pool_update_params,
@@ -23,9 +24,9 @@
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
-from .._base_client import make_request_options
+from ..pagination import SyncOffsetPagination, AsyncOffsetPagination
+from .._base_client import AsyncPaginator, make_request_options
from ..types.browser_pool import BrowserPool
-from ..types.browser_pool_list_response import BrowserPoolListResponse
from ..types.browser_pool_acquire_response import BrowserPoolAcquireResponse
from ..types.shared_params.browser_profile import BrowserProfile
from ..types.shared_params.browser_viewport import BrowserViewport
@@ -326,20 +327,48 @@ def update(
def list(
self,
*,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> BrowserPoolListResponse:
- """List browser pools owned by the caller's organization."""
- return self._get(
+ ) -> SyncOffsetPagination[BrowserPool]:
+ """
+ List browser pools owned by the caller's organization.
+
+ Args:
+ limit: Limit the number of browser pools to return.
+
+ offset: Offset the number of browser pools to return.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/browser_pools",
+ page=SyncOffsetPagination[BrowserPool],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ browser_pool_list_params.BrowserPoolListParams,
+ ),
),
- cast_to=BrowserPoolListResponse,
+ model=BrowserPool,
)
def delete(
@@ -801,23 +830,51 @@ async def update(
cast_to=BrowserPool,
)
- async def list(
+ def list(
self,
*,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> BrowserPoolListResponse:
- """List browser pools owned by the caller's organization."""
- return await self._get(
+ ) -> AsyncPaginator[BrowserPool, AsyncOffsetPagination[BrowserPool]]:
+ """
+ List browser pools owned by the caller's organization.
+
+ Args:
+ limit: Limit the number of browser pools to return.
+
+ offset: Offset the number of browser pools to return.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/browser_pools",
+ page=AsyncOffsetPagination[BrowserPool],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ browser_pool_list_params.BrowserPoolListParams,
+ ),
),
- cast_to=BrowserPoolListResponse,
+ model=BrowserPool,
)
async def delete(
diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py
index bdc65fdf..ae16742d 100644
--- a/src/kernel/types/__init__.py
+++ b/src/kernel/types/__init__.py
@@ -57,6 +57,7 @@
from .extension_list_response import ExtensionListResponse as ExtensionListResponse
from .extension_upload_params import ExtensionUploadParams as ExtensionUploadParams
from .proxy_retrieve_response import ProxyRetrieveResponse as ProxyRetrieveResponse
+from .browser_pool_list_params import BrowserPoolListParams as BrowserPoolListParams
from .credential_create_params import CredentialCreateParams as CredentialCreateParams
from .credential_provider_item import CredentialProviderItem as CredentialProviderItem
from .credential_update_params import CredentialUpdateParams as CredentialUpdateParams
@@ -71,7 +72,6 @@
from .extension_upload_response import ExtensionUploadResponse as ExtensionUploadResponse
from .browser_pool_create_params import BrowserPoolCreateParams as BrowserPoolCreateParams
from .browser_pool_delete_params import BrowserPoolDeleteParams as BrowserPoolDeleteParams
-from .browser_pool_list_response import BrowserPoolListResponse as BrowserPoolListResponse
from .browser_pool_update_params import BrowserPoolUpdateParams as BrowserPoolUpdateParams
from .deployment_create_response import DeploymentCreateResponse as DeploymentCreateResponse
from .deployment_follow_response import DeploymentFollowResponse as DeploymentFollowResponse
diff --git a/src/kernel/types/browser_pool_list_params.py b/src/kernel/types/browser_pool_list_params.py
new file mode 100644
index 00000000..f8111e3e
--- /dev/null
+++ b/src/kernel/types/browser_pool_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["BrowserPoolListParams"]
+
+
+class BrowserPoolListParams(TypedDict, total=False):
+ limit: int
+ """Limit the number of browser pools to return."""
+
+ offset: int
+ """Offset the number of browser pools to return."""
diff --git a/src/kernel/types/browser_pool_list_response.py b/src/kernel/types/browser_pool_list_response.py
deleted file mode 100644
index a11c4de2..00000000
--- a/src/kernel/types/browser_pool_list_response.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List
-from typing_extensions import TypeAlias
-
-from .browser_pool import BrowserPool
-
-__all__ = ["BrowserPoolListResponse"]
-
-BrowserPoolListResponse: TypeAlias = List[BrowserPool]
diff --git a/tests/api_resources/test_browser_pools.py b/tests/api_resources/test_browser_pools.py
index 42f47e63..c71e6c27 100644
--- a/tests/api_resources/test_browser_pools.py
+++ b/tests/api_resources/test_browser_pools.py
@@ -11,9 +11,9 @@
from tests.utils import assert_matches_type
from kernel.types import (
BrowserPool,
- BrowserPoolListResponse,
BrowserPoolAcquireResponse,
)
+from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -211,7 +211,16 @@ def test_path_params_update(self, client: Kernel) -> None:
@parametrize
def test_method_list(self, client: Kernel) -> None:
browser_pool = client.browser_pools.list()
- assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"])
+ assert_matches_type(SyncOffsetPagination[BrowserPool], browser_pool, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Kernel) -> None:
+ browser_pool = client.browser_pools.list(
+ limit=1,
+ offset=0,
+ )
+ assert_matches_type(SyncOffsetPagination[BrowserPool], browser_pool, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -221,7 +230,7 @@ def test_raw_response_list(self, client: Kernel) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
browser_pool = response.parse()
- assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"])
+ assert_matches_type(SyncOffsetPagination[BrowserPool], browser_pool, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -231,7 +240,7 @@ def test_streaming_response_list(self, client: Kernel) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
browser_pool = response.parse()
- assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"])
+ assert_matches_type(SyncOffsetPagination[BrowserPool], browser_pool, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -631,7 +640,16 @@ async def test_path_params_update(self, async_client: AsyncKernel) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncKernel) -> None:
browser_pool = await async_client.browser_pools.list()
- assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[BrowserPool], browser_pool, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None:
+ browser_pool = await async_client.browser_pools.list(
+ limit=1,
+ offset=0,
+ )
+ assert_matches_type(AsyncOffsetPagination[BrowserPool], browser_pool, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -641,7 +659,7 @@ async def test_raw_response_list(self, async_client: AsyncKernel) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
browser_pool = await response.parse()
- assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[BrowserPool], browser_pool, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -651,7 +669,7 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
browser_pool = await response.parse()
- assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[BrowserPool], browser_pool, path=["response"])
assert cast(Any, response.is_closed) is True
From 55c332493f9c7efd21ef8a2fdae40c8318e704cb Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 4 Jun 2026 14:29:10 +0000
Subject: [PATCH 3/5] feat: api: paginate GET /extensions
---
.stats.yml | 6 +-
api.md | 2 +-
src/kernel/resources/extensions.py | 83 +++++++++++++++++----
src/kernel/types/__init__.py | 1 +
src/kernel/types/extension_list_params.py | 15 ++++
src/kernel/types/extension_list_response.py | 10 +--
tests/api_resources/test_extensions.py | 31 ++++++--
7 files changed, 118 insertions(+), 30 deletions(-)
create mode 100644 src/kernel/types/extension_list_params.py
diff --git a/.stats.yml b/.stats.yml
index d6e38f27..582e6b44 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 117
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-e5524e6eeeedc614c05bf19896f1ce6c4f8a113de85c02952d6874d579651f70.yml
-openapi_spec_hash: 7815a189a50e6aa9e283213cc78d041c
-config_hash: 453b25a35834fd59a55a2315d1d50746
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-9a76e7a837ac9ffbe0e9557d618ce9b676e052249e364e516c28ddb33b912019.yml
+openapi_spec_hash: c0e5412cc95139f11a8b8635559bb985
+config_hash: 098a7f3fd134c8e4cbd3a44750892a18
diff --git a/api.md b/api.md
index 8a6b8c6e..6001d530 100644
--- a/api.md
+++ b/api.md
@@ -338,7 +338,7 @@ from kernel.types import ExtensionListResponse, ExtensionUploadResponse
Methods:
-- client.extensions.list() -> ExtensionListResponse
+- client.extensions.list(\*\*params) -> SyncOffsetPagination[ExtensionListResponse]
- client.extensions.delete(id_or_name) -> None
- client.extensions.download(id_or_name) -> BinaryAPIResponse
- client.extensions.download_from_chrome_store(\*\*params) -> BinaryAPIResponse
diff --git a/src/kernel/resources/extensions.py b/src/kernel/resources/extensions.py
index d5cf0eb7..5b7215be 100644
--- a/src/kernel/resources/extensions.py
+++ b/src/kernel/resources/extensions.py
@@ -7,7 +7,7 @@
import httpx
-from ..types import extension_upload_params, extension_download_from_chrome_store_params
+from ..types import extension_list_params, extension_upload_params, extension_download_from_chrome_store_params
from .._files import deepcopy_with_paths
from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, omit, not_given
from .._utils import extract_files, path_template, maybe_transform, async_maybe_transform
@@ -27,7 +27,8 @@
async_to_custom_raw_response_wrapper,
async_to_custom_streamed_response_wrapper,
)
-from .._base_client import make_request_options
+from ..pagination import SyncOffsetPagination, AsyncOffsetPagination
+from .._base_client import AsyncPaginator, make_request_options
from ..types.extension_list_response import ExtensionListResponse
from ..types.extension_upload_response import ExtensionUploadResponse
@@ -59,20 +60,48 @@ def with_streaming_response(self) -> ExtensionsResourceWithStreamingResponse:
def list(
self,
*,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> ExtensionListResponse:
- """List extensions owned by the caller's organization."""
- return self._get(
+ ) -> SyncOffsetPagination[ExtensionListResponse]:
+ """
+ List extensions owned by the caller's organization.
+
+ Args:
+ limit: Limit the number of extensions to return.
+
+ offset: Offset the number of extensions to return.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/extensions",
+ page=SyncOffsetPagination[ExtensionListResponse],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ extension_list_params.ExtensionListParams,
+ ),
),
- cast_to=ExtensionListResponse,
+ model=ExtensionListResponse,
)
def delete(
@@ -266,23 +295,51 @@ def with_streaming_response(self) -> AsyncExtensionsResourceWithStreamingRespons
"""
return AsyncExtensionsResourceWithStreamingResponse(self)
- async def list(
+ def list(
self,
*,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> ExtensionListResponse:
- """List extensions owned by the caller's organization."""
- return await self._get(
+ ) -> AsyncPaginator[ExtensionListResponse, AsyncOffsetPagination[ExtensionListResponse]]:
+ """
+ List extensions owned by the caller's organization.
+
+ Args:
+ limit: Limit the number of extensions to return.
+
+ offset: Offset the number of extensions to return.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/extensions",
+ page=AsyncOffsetPagination[ExtensionListResponse],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ extension_list_params.ExtensionListParams,
+ ),
),
- cast_to=ExtensionListResponse,
+ model=ExtensionListResponse,
)
async def delete(
diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py
index ae16742d..ef27f493 100644
--- a/src/kernel/types/__init__.py
+++ b/src/kernel/types/__init__.py
@@ -42,6 +42,7 @@
from .browser_curl_response import BrowserCurlResponse as BrowserCurlResponse
from .browser_list_response import BrowserListResponse as BrowserListResponse
from .browser_update_params import BrowserUpdateParams as BrowserUpdateParams
+from .extension_list_params import ExtensionListParams as ExtensionListParams
from .profile_create_params import ProfileCreateParams as ProfileCreateParams
from .project_create_params import ProjectCreateParams as ProjectCreateParams
from .project_update_params import ProjectUpdateParams as ProjectUpdateParams
diff --git a/src/kernel/types/extension_list_params.py b/src/kernel/types/extension_list_params.py
new file mode 100644
index 00000000..bccd61eb
--- /dev/null
+++ b/src/kernel/types/extension_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["ExtensionListParams"]
+
+
+class ExtensionListParams(TypedDict, total=False):
+ limit: int
+ """Limit the number of extensions to return."""
+
+ offset: int
+ """Offset the number of extensions to return."""
diff --git a/src/kernel/types/extension_list_response.py b/src/kernel/types/extension_list_response.py
index bf9e544d..6bb33561 100644
--- a/src/kernel/types/extension_list_response.py
+++ b/src/kernel/types/extension_list_response.py
@@ -1,15 +1,14 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import List, Optional
+from typing import Optional
from datetime import datetime
-from typing_extensions import TypeAlias
from .._models import BaseModel
-__all__ = ["ExtensionListResponse", "ExtensionListResponseItem"]
+__all__ = ["ExtensionListResponse"]
-class ExtensionListResponseItem(BaseModel):
+class ExtensionListResponse(BaseModel):
"""A browser extension uploaded to Kernel."""
id: str
@@ -29,6 +28,3 @@ class ExtensionListResponseItem(BaseModel):
Must be unique within the project.
"""
-
-
-ExtensionListResponse: TypeAlias = List[ExtensionListResponseItem]
diff --git a/tests/api_resources/test_extensions.py b/tests/api_resources/test_extensions.py
index 4a28fb5e..302ba958 100644
--- a/tests/api_resources/test_extensions.py
+++ b/tests/api_resources/test_extensions.py
@@ -21,6 +21,7 @@
StreamedBinaryAPIResponse,
AsyncStreamedBinaryAPIResponse,
)
+from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -32,7 +33,16 @@ class TestExtensions:
@parametrize
def test_method_list(self, client: Kernel) -> None:
extension = client.extensions.list()
- assert_matches_type(ExtensionListResponse, extension, path=["response"])
+ assert_matches_type(SyncOffsetPagination[ExtensionListResponse], extension, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Kernel) -> None:
+ extension = client.extensions.list(
+ limit=1,
+ offset=0,
+ )
+ assert_matches_type(SyncOffsetPagination[ExtensionListResponse], extension, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -42,7 +52,7 @@ def test_raw_response_list(self, client: Kernel) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
extension = response.parse()
- assert_matches_type(ExtensionListResponse, extension, path=["response"])
+ assert_matches_type(SyncOffsetPagination[ExtensionListResponse], extension, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -52,7 +62,7 @@ def test_streaming_response_list(self, client: Kernel) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
extension = response.parse()
- assert_matches_type(ExtensionListResponse, extension, path=["response"])
+ assert_matches_type(SyncOffsetPagination[ExtensionListResponse], extension, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -256,7 +266,16 @@ class TestAsyncExtensions:
@parametrize
async def test_method_list(self, async_client: AsyncKernel) -> None:
extension = await async_client.extensions.list()
- assert_matches_type(ExtensionListResponse, extension, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[ExtensionListResponse], extension, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None:
+ extension = await async_client.extensions.list(
+ limit=1,
+ offset=0,
+ )
+ assert_matches_type(AsyncOffsetPagination[ExtensionListResponse], extension, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -266,7 +285,7 @@ async def test_raw_response_list(self, async_client: AsyncKernel) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
extension = await response.parse()
- assert_matches_type(ExtensionListResponse, extension, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[ExtensionListResponse], extension, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -276,7 +295,7 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
extension = await response.parse()
- assert_matches_type(ExtensionListResponse, extension, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[ExtensionListResponse], extension, path=["response"])
assert cast(Any, response.is_closed) is True
From 01897bc9f7215580aa2f2ca41bfcf1b4d29e9005 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 4 Jun 2026 15:04:06 +0000
Subject: [PATCH 4/5] feat: api: paginate GET /org/credential_providers
---
.stats.yml | 6 +-
api.md | 3 +-
src/kernel/resources/credential_providers.py | 88 ++++++++++++++++---
src/kernel/types/__init__.py | 2 +-
.../types/credential_provider_list_params.py | 15 ++++
.../credential_provider_list_response.py | 10 ---
.../test_credential_providers.py | 32 +++++--
7 files changed, 119 insertions(+), 37 deletions(-)
create mode 100644 src/kernel/types/credential_provider_list_params.py
delete mode 100644 src/kernel/types/credential_provider_list_response.py
diff --git a/.stats.yml b/.stats.yml
index 582e6b44..5ea72073 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 117
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-9a76e7a837ac9ffbe0e9557d618ce9b676e052249e364e516c28ddb33b912019.yml
-openapi_spec_hash: c0e5412cc95139f11a8b8635559bb985
-config_hash: 098a7f3fd134c8e4cbd3a44750892a18
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-e6c711f0d29a7d956cc8ca621440da966c1f1575b1205d01328b1099edf1c517.yml
+openapi_spec_hash: c06e7e36de1c6f9b29b54a6e3dc08ee5
+config_hash: 36159c262d293fbeacf513ab600a1729
diff --git a/api.md b/api.md
index 6001d530..8f9df345 100644
--- a/api.md
+++ b/api.md
@@ -441,7 +441,6 @@ from kernel.types import (
CredentialProviderItem,
CredentialProviderTestResult,
UpdateCredentialProviderRequest,
- CredentialProviderListResponse,
CredentialProviderListItemsResponse,
)
```
@@ -451,7 +450,7 @@ Methods:
- client.credential_providers.create(\*\*params) -> CredentialProvider
- client.credential_providers.retrieve(id) -> CredentialProvider
- client.credential_providers.update(id, \*\*params) -> CredentialProvider
-- client.credential_providers.list() -> CredentialProviderListResponse
+- client.credential_providers.list(\*\*params) -> SyncOffsetPagination[CredentialProvider]
- client.credential_providers.delete(id) -> None
- client.credential_providers.list_items(id) -> CredentialProviderListItemsResponse
- client.credential_providers.test(id) -> CredentialProviderTestResult
diff --git a/src/kernel/resources/credential_providers.py b/src/kernel/resources/credential_providers.py
index 2dede2c4..06bf2aee 100644
--- a/src/kernel/resources/credential_providers.py
+++ b/src/kernel/resources/credential_providers.py
@@ -6,7 +6,11 @@
import httpx
-from ..types import credential_provider_create_params, credential_provider_update_params
+from ..types import (
+ credential_provider_list_params,
+ credential_provider_create_params,
+ credential_provider_update_params,
+)
from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -17,10 +21,10 @@
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
-from .._base_client import make_request_options
+from ..pagination import SyncOffsetPagination, AsyncOffsetPagination
+from .._base_client import AsyncPaginator, make_request_options
from ..types.credential_provider import CredentialProvider
from ..types.credential_provider_test_result import CredentialProviderTestResult
-from ..types.credential_provider_list_response import CredentialProviderListResponse
from ..types.credential_provider_list_items_response import CredentialProviderListItemsResponse
__all__ = ["CredentialProvidersResource", "AsyncCredentialProvidersResource"]
@@ -194,20 +198,48 @@ def update(
def list(
self,
*,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CredentialProviderListResponse:
- """List external credential providers configured for the organization."""
- return self._get(
+ ) -> SyncOffsetPagination[CredentialProvider]:
+ """
+ List external credential providers configured for the organization.
+
+ Args:
+ limit: Limit the number of credential providers to return.
+
+ offset: Offset the number of credential providers to return.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/org/credential_providers",
+ page=SyncOffsetPagination[CredentialProvider],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ credential_provider_list_params.CredentialProviderListParams,
+ ),
),
- cast_to=CredentialProviderListResponse,
+ model=CredentialProvider,
)
def delete(
@@ -477,23 +509,51 @@ async def update(
cast_to=CredentialProvider,
)
- async def list(
+ def list(
self,
*,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> CredentialProviderListResponse:
- """List external credential providers configured for the organization."""
- return await self._get(
+ ) -> AsyncPaginator[CredentialProvider, AsyncOffsetPagination[CredentialProvider]]:
+ """
+ List external credential providers configured for the organization.
+
+ Args:
+ limit: Limit the number of credential providers to return.
+
+ offset: Offset the number of credential providers to return.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/org/credential_providers",
+ page=AsyncOffsetPagination[CredentialProvider],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ credential_provider_list_params.CredentialProviderListParams,
+ ),
),
- cast_to=CredentialProviderListResponse,
+ model=CredentialProvider,
)
async def delete(
diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py
index ef27f493..7932162d 100644
--- a/src/kernel/types/__init__.py
+++ b/src/kernel/types/__init__.py
@@ -86,9 +86,9 @@
from .browser_pool_acquire_response import BrowserPoolAcquireResponse as BrowserPoolAcquireResponse
from .credential_totp_code_response import CredentialTotpCodeResponse as CredentialTotpCodeResponse
from .browser_load_extensions_params import BrowserLoadExtensionsParams as BrowserLoadExtensionsParams
+from .credential_provider_list_params import CredentialProviderListParams as CredentialProviderListParams
from .credential_provider_test_result import CredentialProviderTestResult as CredentialProviderTestResult
from .credential_provider_create_params import CredentialProviderCreateParams as CredentialProviderCreateParams
-from .credential_provider_list_response import CredentialProviderListResponse as CredentialProviderListResponse
from .credential_provider_update_params import CredentialProviderUpdateParams as CredentialProviderUpdateParams
from .invocation_list_browsers_response import InvocationListBrowsersResponse as InvocationListBrowsersResponse
from .credential_provider_list_items_response import (
diff --git a/src/kernel/types/credential_provider_list_params.py b/src/kernel/types/credential_provider_list_params.py
new file mode 100644
index 00000000..87dbfd69
--- /dev/null
+++ b/src/kernel/types/credential_provider_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["CredentialProviderListParams"]
+
+
+class CredentialProviderListParams(TypedDict, total=False):
+ limit: int
+ """Limit the number of credential providers to return."""
+
+ offset: int
+ """Offset the number of credential providers to return."""
diff --git a/src/kernel/types/credential_provider_list_response.py b/src/kernel/types/credential_provider_list_response.py
deleted file mode 100644
index 59814e03..00000000
--- a/src/kernel/types/credential_provider_list_response.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List
-from typing_extensions import TypeAlias
-
-from .credential_provider import CredentialProvider
-
-__all__ = ["CredentialProviderListResponse"]
-
-CredentialProviderListResponse: TypeAlias = List[CredentialProvider]
diff --git a/tests/api_resources/test_credential_providers.py b/tests/api_resources/test_credential_providers.py
index 93f44145..d9795332 100644
--- a/tests/api_resources/test_credential_providers.py
+++ b/tests/api_resources/test_credential_providers.py
@@ -12,9 +12,9 @@
from kernel.types import (
CredentialProvider,
CredentialProviderTestResult,
- CredentialProviderListResponse,
CredentialProviderListItemsResponse,
)
+from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -174,7 +174,16 @@ def test_path_params_update(self, client: Kernel) -> None:
@parametrize
def test_method_list(self, client: Kernel) -> None:
credential_provider = client.credential_providers.list()
- assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"])
+ assert_matches_type(SyncOffsetPagination[CredentialProvider], credential_provider, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Kernel) -> None:
+ credential_provider = client.credential_providers.list(
+ limit=1,
+ offset=0,
+ )
+ assert_matches_type(SyncOffsetPagination[CredentialProvider], credential_provider, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -184,7 +193,7 @@ def test_raw_response_list(self, client: Kernel) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
credential_provider = response.parse()
- assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"])
+ assert_matches_type(SyncOffsetPagination[CredentialProvider], credential_provider, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -194,7 +203,7 @@ def test_streaming_response_list(self, client: Kernel) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
credential_provider = response.parse()
- assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"])
+ assert_matches_type(SyncOffsetPagination[CredentialProvider], credential_provider, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -482,7 +491,16 @@ async def test_path_params_update(self, async_client: AsyncKernel) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncKernel) -> None:
credential_provider = await async_client.credential_providers.list()
- assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[CredentialProvider], credential_provider, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None:
+ credential_provider = await async_client.credential_providers.list(
+ limit=1,
+ offset=0,
+ )
+ assert_matches_type(AsyncOffsetPagination[CredentialProvider], credential_provider, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -492,7 +510,7 @@ async def test_raw_response_list(self, async_client: AsyncKernel) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
credential_provider = await response.parse()
- assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[CredentialProvider], credential_provider, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -502,7 +520,7 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
credential_provider = await response.parse()
- assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"])
+ assert_matches_type(AsyncOffsetPagination[CredentialProvider], credential_provider, path=["response"])
assert cast(Any, response.is_closed) is True
From 14e4b34cd4dfaf19da62c4826a4efeefcc86b4f4 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 4 Jun 2026 15:04:39 +0000
Subject: [PATCH 5/5] release: 0.62.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 11 +++++++++++
pyproject.toml | 2 +-
src/kernel/_version.py | 2 +-
4 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index f7e971ea..fdce8724 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.61.0"
+ ".": "0.62.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fbffa57e..bbd58123 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## 0.62.0 (2026-06-04)
+
+Full Changelog: [v0.61.0...v0.62.0](https://github.com/kernel/kernel-python-sdk/compare/v0.61.0...v0.62.0)
+
+### Features
+
+* api: paginate GET /browser_pools ([c25d693](https://github.com/kernel/kernel-python-sdk/commit/c25d693e310a1035d74654018f68b311f37545d0))
+* api: paginate GET /extensions ([55c3324](https://github.com/kernel/kernel-python-sdk/commit/55c332493f9c7efd21ef8a2fdae40c8318e704cb))
+* api: paginate GET /org/credential_providers ([01897bc](https://github.com/kernel/kernel-python-sdk/commit/01897bc9f7215580aa2f2ca41bfcf1b4d29e9005))
+* api: paginate GET /proxies ([7ff0bdf](https://github.com/kernel/kernel-python-sdk/commit/7ff0bdf181029f0711b694fb6498fbc75183b0f3))
+
## 0.61.0 (2026-06-03)
Full Changelog: [v0.60.0...v0.61.0](https://github.com/kernel/kernel-python-sdk/compare/v0.60.0...v0.61.0)
diff --git a/pyproject.toml b/pyproject.toml
index 2b9342ba..f246f34a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "kernel"
-version = "0.61.0"
+version = "0.62.0"
description = "The official Python library for the kernel API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/kernel/_version.py b/src/kernel/_version.py
index fc502359..785c4450 100644
--- a/src/kernel/_version.py
+++ b/src/kernel/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "kernel"
-__version__ = "0.61.0" # x-release-please-version
+__version__ = "0.62.0" # x-release-please-version