diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e205138b..2b1627bc 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.147.0" + ".": "0.148.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 4725ed91..4731cdc5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 178 +configured_endpoints: 179 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c359945..377050c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.148.0](https://github.com/kernel/kernel-python-sdk/compare/v0.147.0...v0.148.0) (2026-11-12) + + +### Features + +* Add scoped live view URLs ([aeabbe3](https://github.com/kernel/kernel-python-sdk/commit/aeabbe3c29e4d51e8b9a6cc3d77497da6a655f32)) +* Pace 1Password status checks on the partner schedule ([aeabbe3](https://github.com/kernel/kernel-python-sdk/commit/aeabbe3c29e4d51e8b9a6cc3d77497da6a655f32)) +* Return the 1Password access request reference on the approval action ([aeabbe3](https://github.com/kernel/kernel-python-sdk/commit/aeabbe3c29e4d51e8b9a6cc3d77497da6a655f32)) + ## [0.147.0](https://github.com/kernel/kernel-python-sdk/compare/v0.146.0...v0.147.0) (2026-11-12) diff --git a/api.md b/api.md index e33b0798..b6bbfdd2 100644 --- a/api.md +++ b/api.md @@ -228,6 +228,18 @@ Methods: - client.browsers.telemetry.events(id_or_name, \*\*params) -> SyncOffsetPagination[TelemetryEventsResponse] - client.browsers.telemetry.stream(id_or_name, \*\*params) -> TelemetryStreamResponse +## LiveView + +Types: + +```python +from kernel.types.browsers import BrowserLiveView, BrowserLiveViewRequest, BrowserLiveViewScope +``` + +Methods: + +- client.browsers.live_view.create(id_or_name, \*\*params) -> BrowserLiveView + ## Replays Types: diff --git a/pyproject.toml b/pyproject.toml index 973785ff..db1d4adb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.147.0" +version = "0.148.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 b92cbde8..eb83d220 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.147.0" # x-release-please-version +__version__ = "0.148.0" # x-release-please-version diff --git a/src/kernel/resources/browsers/__init__.py b/src/kernel/resources/browsers/__init__.py index c6ee6a5f..91092fc8 100644 --- a/src/kernel/resources/browsers/__init__.py +++ b/src/kernel/resources/browsers/__init__.py @@ -56,6 +56,14 @@ ComputerResourceWithStreamingResponse, AsyncComputerResourceWithStreamingResponse, ) +from .live_view import ( + LiveViewResource, + AsyncLiveViewResource, + LiveViewResourceWithRawResponse, + AsyncLiveViewResourceWithRawResponse, + LiveViewResourceWithStreamingResponse, + AsyncLiveViewResourceWithStreamingResponse, +) from .telemetry import ( TelemetryResource, AsyncTelemetryResource, @@ -80,6 +88,12 @@ "AsyncTelemetryResourceWithRawResponse", "TelemetryResourceWithStreamingResponse", "AsyncTelemetryResourceWithStreamingResponse", + "LiveViewResource", + "AsyncLiveViewResource", + "LiveViewResourceWithRawResponse", + "AsyncLiveViewResourceWithRawResponse", + "LiveViewResourceWithStreamingResponse", + "AsyncLiveViewResourceWithStreamingResponse", "ReplaysResource", "AsyncReplaysResource", "ReplaysResourceWithRawResponse", diff --git a/src/kernel/resources/browsers/browsers.py b/src/kernel/resources/browsers/browsers.py index c1340c2a..0086cd57 100644 --- a/src/kernel/resources/browsers/browsers.py +++ b/src/kernel/resources/browsers/browsers.py @@ -64,6 +64,14 @@ AsyncComputerResourceWithStreamingResponse, ) from ..._compat import cached_property +from .live_view import ( + LiveViewResource, + AsyncLiveViewResource, + LiveViewResourceWithRawResponse, + AsyncLiveViewResourceWithRawResponse, + LiveViewResourceWithStreamingResponse, + AsyncLiveViewResourceWithStreamingResponse, +) from .telemetry import ( TelemetryResource, AsyncTelemetryResource, @@ -135,6 +143,11 @@ def telemetry(self) -> TelemetryResource: """ return TelemetryResource(self._client) + @cached_property + def live_view(self) -> LiveViewResource: + """Create and manage browser sessions.""" + return LiveViewResource(self._client) + @cached_property def replays(self) -> ReplaysResource: """Record and manage browser session video replays.""" @@ -1000,6 +1013,11 @@ def telemetry(self) -> AsyncTelemetryResource: """ return AsyncTelemetryResource(self._client) + @cached_property + def live_view(self) -> AsyncLiveViewResource: + """Create and manage browser sessions.""" + return AsyncLiveViewResource(self._client) + @cached_property def replays(self) -> AsyncReplaysResource: """Record and manage browser session video replays.""" @@ -1896,6 +1914,11 @@ def telemetry(self) -> TelemetryResourceWithRawResponse: """ return TelemetryResourceWithRawResponse(self._browsers.telemetry) + @cached_property + def live_view(self) -> LiveViewResourceWithRawResponse: + """Create and manage browser sessions.""" + return LiveViewResourceWithRawResponse(self._browsers.live_view) + @cached_property def replays(self) -> ReplaysResourceWithRawResponse: """Record and manage browser session video replays.""" @@ -1973,6 +1996,11 @@ def telemetry(self) -> AsyncTelemetryResourceWithRawResponse: """ return AsyncTelemetryResourceWithRawResponse(self._browsers.telemetry) + @cached_property + def live_view(self) -> AsyncLiveViewResourceWithRawResponse: + """Create and manage browser sessions.""" + return AsyncLiveViewResourceWithRawResponse(self._browsers.live_view) + @cached_property def replays(self) -> AsyncReplaysResourceWithRawResponse: """Record and manage browser session video replays.""" @@ -2050,6 +2078,11 @@ def telemetry(self) -> TelemetryResourceWithStreamingResponse: """ return TelemetryResourceWithStreamingResponse(self._browsers.telemetry) + @cached_property + def live_view(self) -> LiveViewResourceWithStreamingResponse: + """Create and manage browser sessions.""" + return LiveViewResourceWithStreamingResponse(self._browsers.live_view) + @cached_property def replays(self) -> ReplaysResourceWithStreamingResponse: """Record and manage browser session video replays.""" @@ -2127,6 +2160,11 @@ def telemetry(self) -> AsyncTelemetryResourceWithStreamingResponse: """ return AsyncTelemetryResourceWithStreamingResponse(self._browsers.telemetry) + @cached_property + def live_view(self) -> AsyncLiveViewResourceWithStreamingResponse: + """Create and manage browser sessions.""" + return AsyncLiveViewResourceWithStreamingResponse(self._browsers.live_view) + @cached_property def replays(self) -> AsyncReplaysResourceWithStreamingResponse: """Record and manage browser session video replays.""" diff --git a/src/kernel/resources/browsers/live_view.py b/src/kernel/resources/browsers/live_view.py new file mode 100644 index 00000000..145dcef8 --- /dev/null +++ b/src/kernel/resources/browsers/live_view.py @@ -0,0 +1,226 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.browsers import BrowserLiveViewScope, live_view_create_params +from ...types.browsers.browser_live_view import BrowserLiveView +from ...types.browsers.browser_live_view_scope import BrowserLiveViewScope + +__all__ = ["LiveViewResource", "AsyncLiveViewResource"] + + +class LiveViewResource(SyncAPIResource): + """Create and manage browser sessions.""" + + @cached_property + def with_raw_response(self) -> LiveViewResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return LiveViewResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LiveViewResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return LiveViewResourceWithStreamingResponse(self) + + def create( + self, + id_or_name: str, + *, + scope: BrowserLiveViewScope | Omit = omit, + ttl_seconds: 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, + idempotency_key: str | None = None, + ) -> BrowserLiveView: + """ + Creates a live view URL for a headful browser that grants either read-only or + control access. The URL works only for the live view: it cannot connect to CDP, + WebDriver, or any other browser endpoint. A read-only URL shows the browser but + cannot send input, regardless of query parameters. The URL stays valid until the + browser is deleted, or until `ttl_seconds` elapse when set. For a browser + acquired from a pool, it stops working when the browser is released. Nothing is + stored, so a URL cannot be revoked before then. + + Args: + scope: `read` shows the browser without accepting input. `control` also lets the viewer + drive the browser through the live view. + + ttl_seconds: Seconds until the URL expires. Omit to keep it valid until the browser is + deleted. + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._post( + path_template("/browsers/{id_or_name}/live_view", id_or_name=id_or_name), + body=maybe_transform( + { + "scope": scope, + "ttl_seconds": ttl_seconds, + }, + live_view_create_params.LiveViewCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=BrowserLiveView, + ) + + +class AsyncLiveViewResource(AsyncAPIResource): + """Create and manage browser sessions.""" + + @cached_property + def with_raw_response(self) -> AsyncLiveViewResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncLiveViewResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLiveViewResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return AsyncLiveViewResourceWithStreamingResponse(self) + + async def create( + self, + id_or_name: str, + *, + scope: BrowserLiveViewScope | Omit = omit, + ttl_seconds: 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, + idempotency_key: str | None = None, + ) -> BrowserLiveView: + """ + Creates a live view URL for a headful browser that grants either read-only or + control access. The URL works only for the live view: it cannot connect to CDP, + WebDriver, or any other browser endpoint. A read-only URL shows the browser but + cannot send input, regardless of query parameters. The URL stays valid until the + browser is deleted, or until `ttl_seconds` elapse when set. For a browser + acquired from a pool, it stops working when the browser is released. Nothing is + stored, so a URL cannot be revoked before then. + + Args: + scope: `read` shows the browser without accepting input. `control` also lets the viewer + drive the browser through the live view. + + ttl_seconds: Seconds until the URL expires. Omit to keep it valid until the browser is + deleted. + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._post( + path_template("/browsers/{id_or_name}/live_view", id_or_name=id_or_name), + body=await async_maybe_transform( + { + "scope": scope, + "ttl_seconds": ttl_seconds, + }, + live_view_create_params.LiveViewCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=BrowserLiveView, + ) + + +class LiveViewResourceWithRawResponse: + def __init__(self, live_view: LiveViewResource) -> None: + self._live_view = live_view + + self.create = to_raw_response_wrapper( + live_view.create, + ) + + +class AsyncLiveViewResourceWithRawResponse: + def __init__(self, live_view: AsyncLiveViewResource) -> None: + self._live_view = live_view + + self.create = async_to_raw_response_wrapper( + live_view.create, + ) + + +class LiveViewResourceWithStreamingResponse: + def __init__(self, live_view: LiveViewResource) -> None: + self._live_view = live_view + + self.create = to_streamed_response_wrapper( + live_view.create, + ) + + +class AsyncLiveViewResourceWithStreamingResponse: + def __init__(self, live_view: AsyncLiveViewResource) -> None: + self._live_view = live_view + + self.create = async_to_streamed_response_wrapper( + live_view.create, + ) diff --git a/src/kernel/resources/vaults/items.py b/src/kernel/resources/vaults/items.py index 4cbd2c63..4db4472a 100644 --- a/src/kernel/resources/vaults/items.py +++ b/src/kernel/resources/vaults/items.py @@ -1221,6 +1221,9 @@ def perform_operation( return 403 without both permissions. Args: + timeout_seconds: How long to keep checking on the schedule. The call still waits for its first + scheduled check, at most 20 seconds, when that comes later. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -3312,6 +3315,9 @@ async def perform_operation( return 403 without both permissions. Args: + timeout_seconds: How long to keep checking on the schedule. The call still waits for its first + scheduled check, at most 20 seconds, when that comes later. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request diff --git a/src/kernel/types/browsers/__init__.py b/src/kernel/types/browsers/__init__.py index 27104cff..6836b81b 100644 --- a/src/kernel/types/browsers/__init__.py +++ b/src/kernel/types/browsers/__init__.py @@ -11,6 +11,7 @@ from .tools_response import ToolsResponse as ToolsResponse from .f_upload_params import FUploadParams as FUploadParams from .tool_annotations import ToolAnnotations as ToolAnnotations +from .browser_live_view import BrowserLiveView as BrowserLiveView from .invocation_result import InvocationResult as InvocationResult from .log_stream_params import LogStreamParams as LogStreamParams from .browser_call_stack import BrowserCallStack as BrowserCallStack @@ -42,8 +43,10 @@ from .computer_scroll_params import ComputerScrollParams as ComputerScrollParams from .process_spawn_response import ProcessSpawnResponse as ProcessSpawnResponse from .process_stdin_response import ProcessStdinResponse as ProcessStdinResponse +from .browser_live_view_scope import BrowserLiveViewScope as BrowserLiveViewScope from .browser_page_load_event import BrowserPageLoadEvent as BrowserPageLoadEvent from .browser_telemetry_event import BrowserTelemetryEvent as BrowserTelemetryEvent +from .live_view_create_params import LiveViewCreateParams as LiveViewCreateParams from .process_resize_response import ProcessResizeResponse as ProcessResizeResponse from .process_status_response import ProcessStatusResponse as ProcessStatusResponse from .telemetry_events_params import TelemetryEventsParams as TelemetryEventsParams diff --git a/src/kernel/types/browsers/browser_live_view.py b/src/kernel/types/browsers/browser_live_view.py new file mode 100644 index 00000000..a76e2a5e --- /dev/null +++ b/src/kernel/types/browsers/browser_live_view.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel +from .browser_live_view_scope import BrowserLiveViewScope + +__all__ = ["BrowserLiveView"] + + +class BrowserLiveView(BaseModel): + scope: BrowserLiveViewScope + """`read` shows the browser without accepting input. + + `control` also lets the viewer drive the browser through the live view. + """ + + url: str + """Live view URL. Treat it as a credential.""" + + expires_at: Optional[datetime] = None + """When the URL expires. Absent when it stays valid until the browser is deleted.""" diff --git a/src/kernel/types/browsers/browser_live_view_scope.py b/src/kernel/types/browsers/browser_live_view_scope.py new file mode 100644 index 00000000..5f8b6b57 --- /dev/null +++ b/src/kernel/types/browsers/browser_live_view_scope.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["BrowserLiveViewScope"] + +BrowserLiveViewScope: TypeAlias = Literal["read", "control"] diff --git a/src/kernel/types/browsers/live_view_create_params.py b/src/kernel/types/browsers/live_view_create_params.py new file mode 100644 index 00000000..4746831f --- /dev/null +++ b/src/kernel/types/browsers/live_view_create_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .browser_live_view_scope import BrowserLiveViewScope + +__all__ = ["LiveViewCreateParams"] + + +class LiveViewCreateParams(TypedDict, total=False): + scope: BrowserLiveViewScope + """`read` shows the browser without accepting input. + + `control` also lets the viewer drive the browser through the live view. + """ + + ttl_seconds: int + """Seconds until the URL expires. + + Omit to keep it valid until the browser is deleted. + """ diff --git a/src/kernel/types/vaults/credential_vault_item.py b/src/kernel/types/vaults/credential_vault_item.py index f2e40546..1a636c42 100644 --- a/src/kernel/types/vaults/credential_vault_item.py +++ b/src/kernel/types/vaults/credential_vault_item.py @@ -60,6 +60,15 @@ class AvailableOperation(BaseModel): class ActionOnePasswordAccessApprovalAction(BaseModel): + access_request_reference: str + """ + The access_request_reference value from url, for approving inside your own iOS + or Android app with 1Password's action extension or authorization activity. Pass + it unchanged; the grant comes back to your app, and 1pw_access_request_status + records it in Kernel. Treat it like url, which carries the same request text, + and keep it out of logs. + """ + instructions: str """ Steps for the agent to hand approval to the human and poll the resulting @@ -71,8 +80,10 @@ class ActionOnePasswordAccessApprovalAction(BaseModel): url: str """Native 1Password approval link. - Present it to the account owner without modifying it; it does not grant access - until they approve in their app. + Present it to the account owner unchanged, except that you may append + `&return_url=` so 1Password sends them back to your app after + they decide (1Password 8.12.46 or later on iOS, Android and desktop). It does + not grant access until they approve in their app. """ @@ -90,9 +101,10 @@ class CredentialVaultItem(BaseModel): """Kernel credentials advertise collect and fill when eligible. 1Password credentials advertise 1pw_create_access_request until a request is - made, 1pw_access_request_status while its approval is pending, and 1pw_fill - after access is granted. Managed auth credentials advertise fill while ready and - nothing otherwise. + made, 1pw_access_request_status while its approval is pending (and + 1pw_create_access_request again once the 3-minute status-check window has + passed), and 1pw_fill after access is granted. Managed auth credentials + advertise fill while ready and nothing otherwise. """ created_at: datetime diff --git a/src/kernel/types/vaults/item_perform_operation_params.py b/src/kernel/types/vaults/item_perform_operation_params.py index 094c3aa9..93e0ed8e 100644 --- a/src/kernel/types/vaults/item_perform_operation_params.py +++ b/src/kernel/types/vaults/item_perform_operation_params.py @@ -217,6 +217,11 @@ class OnePasswordPollAccessVaultItemOperationRequest(TypedDict, total=False): type: Required[Literal["1pw_access_request_status"]] timeout_seconds: int + """How long to keep checking on the schedule. + + The call still waits for its first scheduled check, at most 20 seconds, when + that comes later. + """ class OnePasswordFillVaultItemOperationRequest(TypedDict, total=False): diff --git a/src/kernel/types/vaults/one_password_credential_vault_item_state.py b/src/kernel/types/vaults/one_password_credential_vault_item_state.py index 36f9fb1e..3d9f6651 100644 --- a/src/kernel/types/vaults/one_password_credential_vault_item_state.py +++ b/src/kernel/types/vaults/one_password_credential_vault_item_state.py @@ -87,7 +87,11 @@ class AccessRequest(BaseModel): has_autofill_token: bool state: str - """One of pending, resolved, denied, or failed.""" + """One of pending, resolved, denied, failed, expired, or unknown. + + expired returns the item to pending_authorization so access can be requested + again; unknown is a state 1Password added later and is treated as failed. + """ created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) """Provider-created timestamp as returned by the broker.""" diff --git a/tests/api_resources/browsers/test_live_view.py b/tests/api_resources/browsers/test_live_view.py new file mode 100644 index 00000000..5db09055 --- /dev/null +++ b/tests/api_resources/browsers/test_live_view.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from kernel import Kernel, AsyncKernel +from tests.utils import assert_matches_type +from kernel.types.browsers import BrowserLiveView + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLiveView: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Kernel) -> None: + live_view = client.browsers.live_view.create( + id_or_name="htzv5orfit78e1m2biiifpbv", + ) + assert_matches_type(BrowserLiveView, live_view, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Kernel) -> None: + live_view = client.browsers.live_view.create( + id_or_name="htzv5orfit78e1m2biiifpbv", + scope="read", + ttl_seconds=3600, + ) + assert_matches_type(BrowserLiveView, live_view, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Kernel) -> None: + response = client.browsers.live_view.with_raw_response.create( + id_or_name="htzv5orfit78e1m2biiifpbv", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + live_view = response.parse() + assert_matches_type(BrowserLiveView, live_view, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Kernel) -> None: + with client.browsers.live_view.with_streaming_response.create( + id_or_name="htzv5orfit78e1m2biiifpbv", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + live_view = response.parse() + assert_matches_type(BrowserLiveView, live_view, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_create(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browsers.live_view.with_raw_response.create( + id_or_name="", + ) + + +class TestAsyncLiveView: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncKernel) -> None: + live_view = await async_client.browsers.live_view.create( + id_or_name="htzv5orfit78e1m2biiifpbv", + ) + assert_matches_type(BrowserLiveView, live_view, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> None: + live_view = await async_client.browsers.live_view.create( + id_or_name="htzv5orfit78e1m2biiifpbv", + scope="read", + ttl_seconds=3600, + ) + assert_matches_type(BrowserLiveView, live_view, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncKernel) -> None: + response = await async_client.browsers.live_view.with_raw_response.create( + id_or_name="htzv5orfit78e1m2biiifpbv", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + live_view = await response.parse() + assert_matches_type(BrowserLiveView, live_view, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncKernel) -> None: + async with async_client.browsers.live_view.with_streaming_response.create( + id_or_name="htzv5orfit78e1m2biiifpbv", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + live_view = await response.parse() + assert_matches_type(BrowserLiveView, live_view, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_create(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + await async_client.browsers.live_view.with_raw_response.create( + id_or_name="", + )