diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b8dda9b..554e34b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.29.0" + ".": "0.30.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 470e498..710d8bd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-46c8320dcd9f8fc596f469ef0dd1aafaca591ab36cf2a6f8a7297dc9136bdc71.yml -openapi_spec_hash: 1be1e6589cd94c581b241720e01a65bc -config_hash: b470456b217bb9502f5212311d395a6f +configured_endpoints: 98 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-ccbe854895eb34a9562e33979f5f43cd6ad1f529d5924ee56e56f0c94dcf0454.yml +openapi_spec_hash: 2fa4ecbe742fc46fdde481188c1d885e +config_hash: dd218aae3f852dff79e77febc2077b8e diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f736cb..45e5270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.30.0 (2026-02-03) + +Full Changelog: [v0.29.0...v0.30.0](https://github.com/kernel/kernel-python-sdk/compare/v0.29.0...v0.30.0) + +### Features + +* Neil/kernel 872 templates v3 ([383d071](https://github.com/kernel/kernel-python-sdk/commit/383d071b2dba88ec884c34ea8453b3c0e9c4a969)) + ## 0.29.0 (2026-01-30) Full Changelog: [v0.28.0...v0.29.0](https://github.com/kernel/kernel-python-sdk/compare/v0.28.0...v0.29.0) diff --git a/api.md b/api.md index e951a78..8211665 100644 --- a/api.md +++ b/api.md @@ -59,6 +59,7 @@ from kernel.types import ( InvocationUpdateResponse, InvocationListResponse, InvocationFollowResponse, + InvocationListBrowsersResponse, ) ``` @@ -70,6 +71,7 @@ Methods: - client.invocations.list(\*\*params) -> SyncOffsetPagination[InvocationListResponse] - client.invocations.delete_browsers(id) -> None - client.invocations.follow(id, \*\*params) -> InvocationFollowResponse +- client.invocations.list_browsers(id) -> InvocationListBrowsersResponse # Browsers diff --git a/pyproject.toml b/pyproject.toml index 6643370..16affc3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.29.0" +version = "0.30.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 d24a1a6..e08b152 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.29.0" # x-release-please-version +__version__ = "0.30.0" # x-release-please-version diff --git a/src/kernel/resources/invocations.py b/src/kernel/resources/invocations.py index 3b812d4..3194026 100644 --- a/src/kernel/resources/invocations.py +++ b/src/kernel/resources/invocations.py @@ -26,6 +26,7 @@ from ..types.invocation_follow_response import InvocationFollowResponse from ..types.invocation_update_response import InvocationUpdateResponse from ..types.invocation_retrieve_response import InvocationRetrieveResponse +from ..types.invocation_list_browsers_response import InvocationListBrowsersResponse __all__ = ["InvocationsResource", "AsyncInvocationsResource"] @@ -347,6 +348,39 @@ def follow( stream_cls=Stream[InvocationFollowResponse], ) + def list_browsers( + self, + id: str, + *, + # 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, + ) -> InvocationListBrowsersResponse: + """ + Returns all active browser sessions created within the specified invocation. + + Args: + 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 + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + f"/invocations/{id}/browsers", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InvocationListBrowsersResponse, + ) + class AsyncInvocationsResource(AsyncAPIResource): @cached_property @@ -665,6 +699,39 @@ async def follow( stream_cls=AsyncStream[InvocationFollowResponse], ) + async def list_browsers( + self, + id: str, + *, + # 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, + ) -> InvocationListBrowsersResponse: + """ + Returns all active browser sessions created within the specified invocation. + + Args: + 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 + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + f"/invocations/{id}/browsers", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InvocationListBrowsersResponse, + ) + class InvocationsResourceWithRawResponse: def __init__(self, invocations: InvocationsResource) -> None: @@ -688,6 +755,9 @@ def __init__(self, invocations: InvocationsResource) -> None: self.follow = to_raw_response_wrapper( invocations.follow, ) + self.list_browsers = to_raw_response_wrapper( + invocations.list_browsers, + ) class AsyncInvocationsResourceWithRawResponse: @@ -712,6 +782,9 @@ def __init__(self, invocations: AsyncInvocationsResource) -> None: self.follow = async_to_raw_response_wrapper( invocations.follow, ) + self.list_browsers = async_to_raw_response_wrapper( + invocations.list_browsers, + ) class InvocationsResourceWithStreamingResponse: @@ -736,6 +809,9 @@ def __init__(self, invocations: InvocationsResource) -> None: self.follow = to_streamed_response_wrapper( invocations.follow, ) + self.list_browsers = to_streamed_response_wrapper( + invocations.list_browsers, + ) class AsyncInvocationsResourceWithStreamingResponse: @@ -760,3 +836,6 @@ def __init__(self, invocations: AsyncInvocationsResource) -> None: self.follow = async_to_streamed_response_wrapper( invocations.follow, ) + self.list_browsers = async_to_streamed_response_wrapper( + invocations.list_browsers, + ) diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index ef16ae2..7e3ea2d 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -74,6 +74,7 @@ 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 .extension_download_from_chrome_store_params import ( ExtensionDownloadFromChromeStoreParams as ExtensionDownloadFromChromeStoreParams, ) diff --git a/src/kernel/types/invocation_list_browsers_response.py b/src/kernel/types/invocation_list_browsers_response.py new file mode 100644 index 0000000..4d41a29 --- /dev/null +++ b/src/kernel/types/invocation_list_browsers_response.py @@ -0,0 +1,68 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .profile import Profile +from .._models import BaseModel +from .browser_persistence import BrowserPersistence +from .shared.browser_viewport import BrowserViewport + +__all__ = ["InvocationListBrowsersResponse", "Browser"] + + +class Browser(BaseModel): + cdp_ws_url: str + """Websocket URL for Chrome DevTools Protocol connections to the browser session""" + + created_at: datetime + """When the browser session was created.""" + + headless: bool + """Whether the browser session is running in headless mode.""" + + session_id: str + """Unique identifier for the browser session""" + + stealth: bool + """Whether the browser session is running in stealth mode.""" + + timeout_seconds: int + """The number of seconds of inactivity before the browser session is terminated.""" + + browser_live_view_url: Optional[str] = None + """Remote URL for live viewing the browser session. + + Only available for non-headless browsers. + """ + + deleted_at: Optional[datetime] = None + """When the browser session was soft-deleted. Only present for deleted sessions.""" + + kiosk_mode: Optional[bool] = None + """Whether the browser session is running in kiosk mode.""" + + persistence: Optional[BrowserPersistence] = None + """DEPRECATED: Use timeout_seconds (up to 72 hours) and Profiles instead.""" + + profile: Optional[Profile] = None + """Browser profile metadata.""" + + proxy_id: Optional[str] = None + """ID of the proxy associated with this browser session, if any.""" + + viewport: Optional[BrowserViewport] = None + """Initial browser window size in pixels with optional refresh rate. + + If omitted, image defaults apply (1920x1080@25). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1280x800@60, 1024x768@60, 1200x800@60 If refresh_rate is not + provided, it will be automatically determined from the width and height if they + match a supported configuration exactly. Note: Higher resolutions may affect the + responsiveness of live view browser + """ + + +class InvocationListBrowsersResponse(BaseModel): + browsers: List[Browser] diff --git a/tests/api_resources/test_invocations.py b/tests/api_resources/test_invocations.py index 40c0545..d870adc 100644 --- a/tests/api_resources/test_invocations.py +++ b/tests/api_resources/test_invocations.py @@ -14,6 +14,7 @@ InvocationCreateResponse, InvocationUpdateResponse, InvocationRetrieveResponse, + InvocationListBrowsersResponse, ) from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination @@ -309,6 +310,48 @@ def test_path_params_follow(self, client: Kernel) -> None: id="", ) + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_list_browsers(self, client: Kernel) -> None: + invocation = client.invocations.list_browsers( + "id", + ) + assert_matches_type(InvocationListBrowsersResponse, invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_list_browsers(self, client: Kernel) -> None: + response = client.invocations.with_raw_response.list_browsers( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invocation = response.parse() + assert_matches_type(InvocationListBrowsersResponse, invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_list_browsers(self, client: Kernel) -> None: + with client.invocations.with_streaming_response.list_browsers( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invocation = response.parse() + assert_matches_type(InvocationListBrowsersResponse, invocation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_list_browsers(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.invocations.with_raw_response.list_browsers( + "", + ) + class TestAsyncInvocations: parametrize = pytest.mark.parametrize( @@ -600,3 +643,45 @@ async def test_path_params_follow(self, async_client: AsyncKernel) -> None: await async_client.invocations.with_raw_response.follow( id="", ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_list_browsers(self, async_client: AsyncKernel) -> None: + invocation = await async_client.invocations.list_browsers( + "id", + ) + assert_matches_type(InvocationListBrowsersResponse, invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_list_browsers(self, async_client: AsyncKernel) -> None: + response = await async_client.invocations.with_raw_response.list_browsers( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invocation = await response.parse() + assert_matches_type(InvocationListBrowsersResponse, invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_list_browsers(self, async_client: AsyncKernel) -> None: + async with async_client.invocations.with_streaming_response.list_browsers( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invocation = await response.parse() + assert_matches_type(InvocationListBrowsersResponse, invocation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_list_browsers(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.invocations.with_raw_response.list_browsers( + "", + )