From 9a1e7bf9c92d64da4a151dd44cc60057c75c63bf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 22 Nov 2025 03:34:11 +0000 Subject: [PATCH 01/10] chore: add Python 3.14 classifier and testing --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index b5d3ecb5..43139568 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", From b8729284ba804461749dad0ac4613aea3c6b3ce6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:52:40 +0000 Subject: [PATCH 02/10] feat: Mason/agent auth api --- .stats.yml | 8 +- api.md | 35 ++ src/kernel/_client.py | 9 + src/kernel/resources/__init__.py | 14 + src/kernel/resources/agents/__init__.py | 33 ++ src/kernel/resources/agents/agents.py | 102 ++++ src/kernel/resources/agents/auth/__init__.py | 33 ++ src/kernel/resources/agents/auth/auth.py | 239 ++++++++++ src/kernel/resources/agents/auth/runs.py | 434 ++++++++++++++++++ src/kernel/types/agents/__init__.py | 10 + .../agents/agent_auth_discover_response.py | 28 ++ .../types/agents/agent_auth_run_response.py | 22 + .../types/agents/agent_auth_start_response.py | 21 + .../agents/agent_auth_submit_response.py | 34 ++ src/kernel/types/agents/auth/__init__.py | 7 + .../types/agents/auth/run_exchange_params.py | 12 + .../agents/auth/run_exchange_response.py | 13 + .../types/agents/auth/run_submit_params.py | 13 + src/kernel/types/agents/auth_start_params.py | 26 ++ src/kernel/types/agents/discovered_field.py | 28 ++ tests/api_resources/agents/__init__.py | 1 + tests/api_resources/agents/auth/__init__.py | 1 + tests/api_resources/agents/auth/test_runs.py | 401 ++++++++++++++++ tests/api_resources/agents/test_auth.py | 120 +++++ 24 files changed, 1640 insertions(+), 4 deletions(-) create mode 100644 src/kernel/resources/agents/__init__.py create mode 100644 src/kernel/resources/agents/agents.py create mode 100644 src/kernel/resources/agents/auth/__init__.py create mode 100644 src/kernel/resources/agents/auth/auth.py create mode 100644 src/kernel/resources/agents/auth/runs.py create mode 100644 src/kernel/types/agents/__init__.py create mode 100644 src/kernel/types/agents/agent_auth_discover_response.py create mode 100644 src/kernel/types/agents/agent_auth_run_response.py create mode 100644 src/kernel/types/agents/agent_auth_start_response.py create mode 100644 src/kernel/types/agents/agent_auth_submit_response.py create mode 100644 src/kernel/types/agents/auth/__init__.py create mode 100644 src/kernel/types/agents/auth/run_exchange_params.py create mode 100644 src/kernel/types/agents/auth/run_exchange_response.py create mode 100644 src/kernel/types/agents/auth/run_submit_params.py create mode 100644 src/kernel/types/agents/auth_start_params.py create mode 100644 src/kernel/types/agents/discovered_field.py create mode 100644 tests/api_resources/agents/__init__.py create mode 100644 tests/api_resources/agents/auth/__init__.py create mode 100644 tests/api_resources/agents/auth/test_runs.py create mode 100644 tests/api_resources/agents/test_auth.py diff --git a/.stats.yml b/.stats.yml index 11b820d4..bdbede3e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 66 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2af1b468584cb44aa9babbbfb82bff4055614fbb5c815084a6b7dacc1cf1a822.yml -openapi_spec_hash: 891affa2849341ea01d62011125f7edc -config_hash: 9421eb86b7f3f4b274f123279da3858e +configured_endpoints: 71 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-bb3f37e55117a56e7a4208bd646d3a68adeb651ced8531e13fbfc1fc9dcb05a4.yml +openapi_spec_hash: 7303ce8ce3130e16a6a5c2bb49e43e9b +config_hash: be146470fb2d4583b6533859f0fa48f5 diff --git a/api.md b/api.md index afa0ddd4..483ff9cb 100644 --- a/api.md +++ b/api.md @@ -243,3 +243,38 @@ Methods: - client.extensions.download(id_or_name) -> BinaryAPIResponse - client.extensions.download_from_chrome_store(\*\*params) -> BinaryAPIResponse - client.extensions.upload(\*\*params) -> ExtensionUploadResponse + +# Agents + +## Auth + +Types: + +```python +from kernel.types.agents import ( + AgentAuthDiscoverResponse, + AgentAuthRunResponse, + AgentAuthStartResponse, + AgentAuthSubmitResponse, + DiscoveredField, +) +``` + +Methods: + +- client.agents.auth.start(\*\*params) -> AgentAuthStartResponse + +### Runs + +Types: + +```python +from kernel.types.agents.auth import RunExchangeResponse +``` + +Methods: + +- client.agents.auth.runs.retrieve(run_id) -> AgentAuthRunResponse +- client.agents.auth.runs.discover(run_id) -> AgentAuthDiscoverResponse +- client.agents.auth.runs.exchange(run_id, \*\*params) -> RunExchangeResponse +- client.agents.auth.runs.submit(run_id, \*\*params) -> AgentAuthSubmitResponse diff --git a/src/kernel/_client.py b/src/kernel/_client.py index ea9e51b9..ba424335 100644 --- a/src/kernel/_client.py +++ b/src/kernel/_client.py @@ -29,6 +29,7 @@ SyncAPIClient, AsyncAPIClient, ) +from .resources.agents import agents from .resources.browsers import browsers __all__ = [ @@ -57,6 +58,7 @@ class Kernel(SyncAPIClient): profiles: profiles.ProfilesResource proxies: proxies.ProxiesResource extensions: extensions.ExtensionsResource + agents: agents.AgentsResource with_raw_response: KernelWithRawResponse with_streaming_response: KernelWithStreamedResponse @@ -145,6 +147,7 @@ def __init__( self.profiles = profiles.ProfilesResource(self) self.proxies = proxies.ProxiesResource(self) self.extensions = extensions.ExtensionsResource(self) + self.agents = agents.AgentsResource(self) self.with_raw_response = KernelWithRawResponse(self) self.with_streaming_response = KernelWithStreamedResponse(self) @@ -263,6 +266,7 @@ class AsyncKernel(AsyncAPIClient): profiles: profiles.AsyncProfilesResource proxies: proxies.AsyncProxiesResource extensions: extensions.AsyncExtensionsResource + agents: agents.AsyncAgentsResource with_raw_response: AsyncKernelWithRawResponse with_streaming_response: AsyncKernelWithStreamedResponse @@ -351,6 +355,7 @@ def __init__( self.profiles = profiles.AsyncProfilesResource(self) self.proxies = proxies.AsyncProxiesResource(self) self.extensions = extensions.AsyncExtensionsResource(self) + self.agents = agents.AsyncAgentsResource(self) self.with_raw_response = AsyncKernelWithRawResponse(self) self.with_streaming_response = AsyncKernelWithStreamedResponse(self) @@ -470,6 +475,7 @@ def __init__(self, client: Kernel) -> None: self.profiles = profiles.ProfilesResourceWithRawResponse(client.profiles) self.proxies = proxies.ProxiesResourceWithRawResponse(client.proxies) self.extensions = extensions.ExtensionsResourceWithRawResponse(client.extensions) + self.agents = agents.AgentsResourceWithRawResponse(client.agents) class AsyncKernelWithRawResponse: @@ -481,6 +487,7 @@ def __init__(self, client: AsyncKernel) -> None: self.profiles = profiles.AsyncProfilesResourceWithRawResponse(client.profiles) self.proxies = proxies.AsyncProxiesResourceWithRawResponse(client.proxies) self.extensions = extensions.AsyncExtensionsResourceWithRawResponse(client.extensions) + self.agents = agents.AsyncAgentsResourceWithRawResponse(client.agents) class KernelWithStreamedResponse: @@ -492,6 +499,7 @@ def __init__(self, client: Kernel) -> None: self.profiles = profiles.ProfilesResourceWithStreamingResponse(client.profiles) self.proxies = proxies.ProxiesResourceWithStreamingResponse(client.proxies) self.extensions = extensions.ExtensionsResourceWithStreamingResponse(client.extensions) + self.agents = agents.AgentsResourceWithStreamingResponse(client.agents) class AsyncKernelWithStreamedResponse: @@ -503,6 +511,7 @@ def __init__(self, client: AsyncKernel) -> None: self.profiles = profiles.AsyncProfilesResourceWithStreamingResponse(client.profiles) self.proxies = proxies.AsyncProxiesResourceWithStreamingResponse(client.proxies) self.extensions = extensions.AsyncExtensionsResourceWithStreamingResponse(client.extensions) + self.agents = agents.AsyncAgentsResourceWithStreamingResponse(client.agents) Client = Kernel diff --git a/src/kernel/resources/__init__.py b/src/kernel/resources/__init__.py index 1b68d89f..233ef508 100644 --- a/src/kernel/resources/__init__.py +++ b/src/kernel/resources/__init__.py @@ -8,6 +8,14 @@ AppsResourceWithStreamingResponse, AsyncAppsResourceWithStreamingResponse, ) +from .agents import ( + AgentsResource, + AsyncAgentsResource, + AgentsResourceWithRawResponse, + AsyncAgentsResourceWithRawResponse, + AgentsResourceWithStreamingResponse, + AsyncAgentsResourceWithStreamingResponse, +) from .proxies import ( ProxiesResource, AsyncProxiesResource, @@ -100,4 +108,10 @@ "AsyncExtensionsResourceWithRawResponse", "ExtensionsResourceWithStreamingResponse", "AsyncExtensionsResourceWithStreamingResponse", + "AgentsResource", + "AsyncAgentsResource", + "AgentsResourceWithRawResponse", + "AsyncAgentsResourceWithRawResponse", + "AgentsResourceWithStreamingResponse", + "AsyncAgentsResourceWithStreamingResponse", ] diff --git a/src/kernel/resources/agents/__init__.py b/src/kernel/resources/agents/__init__.py new file mode 100644 index 00000000..cb159eb7 --- /dev/null +++ b/src/kernel/resources/agents/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .auth import ( + AuthResource, + AsyncAuthResource, + AuthResourceWithRawResponse, + AsyncAuthResourceWithRawResponse, + AuthResourceWithStreamingResponse, + AsyncAuthResourceWithStreamingResponse, +) +from .agents import ( + AgentsResource, + AsyncAgentsResource, + AgentsResourceWithRawResponse, + AsyncAgentsResourceWithRawResponse, + AgentsResourceWithStreamingResponse, + AsyncAgentsResourceWithStreamingResponse, +) + +__all__ = [ + "AuthResource", + "AsyncAuthResource", + "AuthResourceWithRawResponse", + "AsyncAuthResourceWithRawResponse", + "AuthResourceWithStreamingResponse", + "AsyncAuthResourceWithStreamingResponse", + "AgentsResource", + "AsyncAgentsResource", + "AgentsResourceWithRawResponse", + "AsyncAgentsResourceWithRawResponse", + "AgentsResourceWithStreamingResponse", + "AsyncAgentsResourceWithStreamingResponse", +] diff --git a/src/kernel/resources/agents/agents.py b/src/kernel/resources/agents/agents.py new file mode 100644 index 00000000..b7bb580c --- /dev/null +++ b/src/kernel/resources/agents/agents.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..._compat import cached_property +from .auth.auth import ( + AuthResource, + AsyncAuthResource, + AuthResourceWithRawResponse, + AsyncAuthResourceWithRawResponse, + AuthResourceWithStreamingResponse, + AsyncAuthResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["AgentsResource", "AsyncAgentsResource"] + + +class AgentsResource(SyncAPIResource): + @cached_property + def auth(self) -> AuthResource: + return AuthResource(self._client) + + @cached_property + def with_raw_response(self) -> AgentsResourceWithRawResponse: + """ + 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AgentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AgentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return AgentsResourceWithStreamingResponse(self) + + +class AsyncAgentsResource(AsyncAPIResource): + @cached_property + def auth(self) -> AsyncAuthResource: + return AsyncAuthResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncAgentsResourceWithRawResponse: + """ + 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncAgentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAgentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return AsyncAgentsResourceWithStreamingResponse(self) + + +class AgentsResourceWithRawResponse: + def __init__(self, agents: AgentsResource) -> None: + self._agents = agents + + @cached_property + def auth(self) -> AuthResourceWithRawResponse: + return AuthResourceWithRawResponse(self._agents.auth) + + +class AsyncAgentsResourceWithRawResponse: + def __init__(self, agents: AsyncAgentsResource) -> None: + self._agents = agents + + @cached_property + def auth(self) -> AsyncAuthResourceWithRawResponse: + return AsyncAuthResourceWithRawResponse(self._agents.auth) + + +class AgentsResourceWithStreamingResponse: + def __init__(self, agents: AgentsResource) -> None: + self._agents = agents + + @cached_property + def auth(self) -> AuthResourceWithStreamingResponse: + return AuthResourceWithStreamingResponse(self._agents.auth) + + +class AsyncAgentsResourceWithStreamingResponse: + def __init__(self, agents: AsyncAgentsResource) -> None: + self._agents = agents + + @cached_property + def auth(self) -> AsyncAuthResourceWithStreamingResponse: + return AsyncAuthResourceWithStreamingResponse(self._agents.auth) diff --git a/src/kernel/resources/agents/auth/__init__.py b/src/kernel/resources/agents/auth/__init__.py new file mode 100644 index 00000000..d9853204 --- /dev/null +++ b/src/kernel/resources/agents/auth/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .auth import ( + AuthResource, + AsyncAuthResource, + AuthResourceWithRawResponse, + AsyncAuthResourceWithRawResponse, + AuthResourceWithStreamingResponse, + AsyncAuthResourceWithStreamingResponse, +) +from .runs import ( + RunsResource, + AsyncRunsResource, + RunsResourceWithRawResponse, + AsyncRunsResourceWithRawResponse, + RunsResourceWithStreamingResponse, + AsyncRunsResourceWithStreamingResponse, +) + +__all__ = [ + "RunsResource", + "AsyncRunsResource", + "RunsResourceWithRawResponse", + "AsyncRunsResourceWithRawResponse", + "RunsResourceWithStreamingResponse", + "AsyncRunsResourceWithStreamingResponse", + "AuthResource", + "AsyncAuthResource", + "AuthResourceWithRawResponse", + "AsyncAuthResourceWithRawResponse", + "AuthResourceWithStreamingResponse", + "AsyncAuthResourceWithStreamingResponse", +] diff --git a/src/kernel/resources/agents/auth/auth.py b/src/kernel/resources/agents/auth/auth.py new file mode 100644 index 00000000..2e099095 --- /dev/null +++ b/src/kernel/resources/agents/auth/auth.py @@ -0,0 +1,239 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .runs import ( + RunsResource, + AsyncRunsResource, + RunsResourceWithRawResponse, + AsyncRunsResourceWithRawResponse, + RunsResourceWithStreamingResponse, + AsyncRunsResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import 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.agents import auth_start_params +from ....types.agents.agent_auth_start_response import AgentAuthStartResponse + +__all__ = ["AuthResource", "AsyncAuthResource"] + + +class AuthResource(SyncAPIResource): + @cached_property + def runs(self) -> RunsResource: + return RunsResource(self._client) + + @cached_property + def with_raw_response(self) -> AuthResourceWithRawResponse: + """ + 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AuthResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AuthResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return AuthResourceWithStreamingResponse(self) + + def start( + self, + *, + profile_name: str, + target_domain: str, + app_logo_url: str | Omit = omit, + proxy: auth_start_params.Proxy | 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, + ) -> AgentAuthStartResponse: + """Creates a browser session and returns a handoff code for the hosted flow. + + Uses + standard API key or JWT authentication (not the JWT returned by the exchange + endpoint). + + Args: + profile_name: Name of the profile to use for this flow + + target_domain: Target domain for authentication + + app_logo_url: Optional logo URL for the application + + proxy: Optional proxy configuration + + 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._post( + "/agents/auth/start", + body=maybe_transform( + { + "profile_name": profile_name, + "target_domain": target_domain, + "app_logo_url": app_logo_url, + "proxy": proxy, + }, + auth_start_params.AuthStartParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentAuthStartResponse, + ) + + +class AsyncAuthResource(AsyncAPIResource): + @cached_property + def runs(self) -> AsyncRunsResource: + return AsyncRunsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncAuthResourceWithRawResponse: + """ + 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncAuthResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAuthResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return AsyncAuthResourceWithStreamingResponse(self) + + async def start( + self, + *, + profile_name: str, + target_domain: str, + app_logo_url: str | Omit = omit, + proxy: auth_start_params.Proxy | 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, + ) -> AgentAuthStartResponse: + """Creates a browser session and returns a handoff code for the hosted flow. + + Uses + standard API key or JWT authentication (not the JWT returned by the exchange + endpoint). + + Args: + profile_name: Name of the profile to use for this flow + + target_domain: Target domain for authentication + + app_logo_url: Optional logo URL for the application + + proxy: Optional proxy configuration + + 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 await self._post( + "/agents/auth/start", + body=await async_maybe_transform( + { + "profile_name": profile_name, + "target_domain": target_domain, + "app_logo_url": app_logo_url, + "proxy": proxy, + }, + auth_start_params.AuthStartParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentAuthStartResponse, + ) + + +class AuthResourceWithRawResponse: + def __init__(self, auth: AuthResource) -> None: + self._auth = auth + + self.start = to_raw_response_wrapper( + auth.start, + ) + + @cached_property + def runs(self) -> RunsResourceWithRawResponse: + return RunsResourceWithRawResponse(self._auth.runs) + + +class AsyncAuthResourceWithRawResponse: + def __init__(self, auth: AsyncAuthResource) -> None: + self._auth = auth + + self.start = async_to_raw_response_wrapper( + auth.start, + ) + + @cached_property + def runs(self) -> AsyncRunsResourceWithRawResponse: + return AsyncRunsResourceWithRawResponse(self._auth.runs) + + +class AuthResourceWithStreamingResponse: + def __init__(self, auth: AuthResource) -> None: + self._auth = auth + + self.start = to_streamed_response_wrapper( + auth.start, + ) + + @cached_property + def runs(self) -> RunsResourceWithStreamingResponse: + return RunsResourceWithStreamingResponse(self._auth.runs) + + +class AsyncAuthResourceWithStreamingResponse: + def __init__(self, auth: AsyncAuthResource) -> None: + self._auth = auth + + self.start = async_to_streamed_response_wrapper( + auth.start, + ) + + @cached_property + def runs(self) -> AsyncRunsResourceWithStreamingResponse: + return AsyncRunsResourceWithStreamingResponse(self._auth.runs) diff --git a/src/kernel/resources/agents/auth/runs.py b/src/kernel/resources/agents/auth/runs.py new file mode 100644 index 00000000..6ea09403 --- /dev/null +++ b/src/kernel/resources/agents/auth/runs.py @@ -0,0 +1,434 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import 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.agents.auth import run_submit_params, run_exchange_params +from ....types.agents.agent_auth_run_response import AgentAuthRunResponse +from ....types.agents.agent_auth_submit_response import AgentAuthSubmitResponse +from ....types.agents.auth.run_exchange_response import RunExchangeResponse +from ....types.agents.agent_auth_discover_response import AgentAuthDiscoverResponse + +__all__ = ["RunsResource", "AsyncRunsResource"] + + +class RunsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RunsResourceWithRawResponse: + """ + 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return RunsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RunsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return RunsResourceWithStreamingResponse(self) + + def retrieve( + self, + run_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, + ) -> AgentAuthRunResponse: + """Returns run details including app_name and target_domain. + + Uses the JWT returned + by the exchange endpoint, or standard API key or JWT authentication. + + 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 run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._get( + f"/agents/auth/runs/{run_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentAuthRunResponse, + ) + + def discover( + self, + run_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, + ) -> AgentAuthDiscoverResponse: + """ + Inspects the target site to detect logged-in state or discover required fields. + Returns 200 with success: true when fields are found, or 4xx/5xx for failures. + Requires the JWT returned by the exchange endpoint. + + 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 run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._post( + f"/agents/auth/runs/{run_id}/discover", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentAuthDiscoverResponse, + ) + + def exchange( + self, + run_id: str, + *, + code: 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, + ) -> RunExchangeResponse: + """Validates the handoff code and returns a JWT token for subsequent requests. + + No + authentication required (the handoff code serves as the credential). + + Args: + code: Handoff code from start endpoint + + 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 run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._post( + f"/agents/auth/runs/{run_id}/exchange", + body=maybe_transform({"code": code}, run_exchange_params.RunExchangeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunExchangeResponse, + ) + + def submit( + self, + run_id: str, + *, + field_values: Dict[str, 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, + ) -> AgentAuthSubmitResponse: + """ + Submits field values for the discovered login form and may return additional + auth fields or success. Requires the JWT returned by the exchange endpoint. + + Args: + field_values: Values for the discovered login fields + + 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 run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return self._post( + f"/agents/auth/runs/{run_id}/submit", + body=maybe_transform({"field_values": field_values}, run_submit_params.RunSubmitParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentAuthSubmitResponse, + ) + + +class AsyncRunsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRunsResourceWithRawResponse: + """ + 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncRunsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRunsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return AsyncRunsResourceWithStreamingResponse(self) + + async def retrieve( + self, + run_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, + ) -> AgentAuthRunResponse: + """Returns run details including app_name and target_domain. + + Uses the JWT returned + by the exchange endpoint, or standard API key or JWT authentication. + + 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 run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return await self._get( + f"/agents/auth/runs/{run_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentAuthRunResponse, + ) + + async def discover( + self, + run_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, + ) -> AgentAuthDiscoverResponse: + """ + Inspects the target site to detect logged-in state or discover required fields. + Returns 200 with success: true when fields are found, or 4xx/5xx for failures. + Requires the JWT returned by the exchange endpoint. + + 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 run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return await self._post( + f"/agents/auth/runs/{run_id}/discover", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentAuthDiscoverResponse, + ) + + async def exchange( + self, + run_id: str, + *, + code: 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, + ) -> RunExchangeResponse: + """Validates the handoff code and returns a JWT token for subsequent requests. + + No + authentication required (the handoff code serves as the credential). + + Args: + code: Handoff code from start endpoint + + 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 run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return await self._post( + f"/agents/auth/runs/{run_id}/exchange", + body=await async_maybe_transform({"code": code}, run_exchange_params.RunExchangeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RunExchangeResponse, + ) + + async def submit( + self, + run_id: str, + *, + field_values: Dict[str, 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, + ) -> AgentAuthSubmitResponse: + """ + Submits field values for the discovered login form and may return additional + auth fields or success. Requires the JWT returned by the exchange endpoint. + + Args: + field_values: Values for the discovered login fields + + 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 run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") + return await self._post( + f"/agents/auth/runs/{run_id}/submit", + body=await async_maybe_transform({"field_values": field_values}, run_submit_params.RunSubmitParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentAuthSubmitResponse, + ) + + +class RunsResourceWithRawResponse: + def __init__(self, runs: RunsResource) -> None: + self._runs = runs + + self.retrieve = to_raw_response_wrapper( + runs.retrieve, + ) + self.discover = to_raw_response_wrapper( + runs.discover, + ) + self.exchange = to_raw_response_wrapper( + runs.exchange, + ) + self.submit = to_raw_response_wrapper( + runs.submit, + ) + + +class AsyncRunsResourceWithRawResponse: + def __init__(self, runs: AsyncRunsResource) -> None: + self._runs = runs + + self.retrieve = async_to_raw_response_wrapper( + runs.retrieve, + ) + self.discover = async_to_raw_response_wrapper( + runs.discover, + ) + self.exchange = async_to_raw_response_wrapper( + runs.exchange, + ) + self.submit = async_to_raw_response_wrapper( + runs.submit, + ) + + +class RunsResourceWithStreamingResponse: + def __init__(self, runs: RunsResource) -> None: + self._runs = runs + + self.retrieve = to_streamed_response_wrapper( + runs.retrieve, + ) + self.discover = to_streamed_response_wrapper( + runs.discover, + ) + self.exchange = to_streamed_response_wrapper( + runs.exchange, + ) + self.submit = to_streamed_response_wrapper( + runs.submit, + ) + + +class AsyncRunsResourceWithStreamingResponse: + def __init__(self, runs: AsyncRunsResource) -> None: + self._runs = runs + + self.retrieve = async_to_streamed_response_wrapper( + runs.retrieve, + ) + self.discover = async_to_streamed_response_wrapper( + runs.discover, + ) + self.exchange = async_to_streamed_response_wrapper( + runs.exchange, + ) + self.submit = async_to_streamed_response_wrapper( + runs.submit, + ) diff --git a/src/kernel/types/agents/__init__.py b/src/kernel/types/agents/__init__.py new file mode 100644 index 00000000..e8c22774 --- /dev/null +++ b/src/kernel/types/agents/__init__.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .discovered_field import DiscoveredField as DiscoveredField +from .auth_start_params import AuthStartParams as AuthStartParams +from .agent_auth_run_response import AgentAuthRunResponse as AgentAuthRunResponse +from .agent_auth_start_response import AgentAuthStartResponse as AgentAuthStartResponse +from .agent_auth_submit_response import AgentAuthSubmitResponse as AgentAuthSubmitResponse +from .agent_auth_discover_response import AgentAuthDiscoverResponse as AgentAuthDiscoverResponse diff --git a/src/kernel/types/agents/agent_auth_discover_response.py b/src/kernel/types/agents/agent_auth_discover_response.py new file mode 100644 index 00000000..000bdec2 --- /dev/null +++ b/src/kernel/types/agents/agent_auth_discover_response.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .discovered_field import DiscoveredField + +__all__ = ["AgentAuthDiscoverResponse"] + + +class AgentAuthDiscoverResponse(BaseModel): + success: bool + """Whether discovery succeeded""" + + error_message: Optional[str] = None + """Error message if discovery failed""" + + fields: Optional[List[DiscoveredField]] = None + """Discovered form fields (present when success is true)""" + + logged_in: Optional[bool] = None + """Whether user is already logged in""" + + login_url: Optional[str] = None + """URL of the discovered login page""" + + page_title: Optional[str] = None + """Title of the login page""" diff --git a/src/kernel/types/agents/agent_auth_run_response.py b/src/kernel/types/agents/agent_auth_run_response.py new file mode 100644 index 00000000..0ec0b0bb --- /dev/null +++ b/src/kernel/types/agents/agent_auth_run_response.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AgentAuthRunResponse"] + + +class AgentAuthRunResponse(BaseModel): + app_name: str + """App name (org name at time of run creation)""" + + expires_at: datetime + """When the handoff code expires""" + + status: Literal["ACTIVE", "ENDED", "EXPIRED", "CANCELED"] + """Run status""" + + target_domain: str + """Target domain for authentication""" diff --git a/src/kernel/types/agents/agent_auth_start_response.py b/src/kernel/types/agents/agent_auth_start_response.py new file mode 100644 index 00000000..2855fc2d --- /dev/null +++ b/src/kernel/types/agents/agent_auth_start_response.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["AgentAuthStartResponse"] + + +class AgentAuthStartResponse(BaseModel): + expires_at: datetime + """When the handoff code expires""" + + handoff_code: str + """One-time code for handoff""" + + hosted_url: str + """URL to redirect user to""" + + run_id: str + """Unique identifier for the run""" diff --git a/src/kernel/types/agents/agent_auth_submit_response.py b/src/kernel/types/agents/agent_auth_submit_response.py new file mode 100644 index 00000000..c57002fb --- /dev/null +++ b/src/kernel/types/agents/agent_auth_submit_response.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .discovered_field import DiscoveredField + +__all__ = ["AgentAuthSubmitResponse"] + + +class AgentAuthSubmitResponse(BaseModel): + success: bool + """Whether submission succeeded""" + + additional_fields: Optional[List[DiscoveredField]] = None + """ + Additional fields needed (e.g., OTP) - present when needs_additional_auth is + true + """ + + app_name: Optional[str] = None + """App name (only present when logged_in is true)""" + + error_message: Optional[str] = None + """Error message if submission failed""" + + logged_in: Optional[bool] = None + """Whether user is now logged in""" + + needs_additional_auth: Optional[bool] = None + """Whether additional authentication fields are needed""" + + target_domain: Optional[str] = None + """Target domain (only present when logged_in is true)""" diff --git a/src/kernel/types/agents/auth/__init__.py b/src/kernel/types/agents/auth/__init__.py new file mode 100644 index 00000000..78a13a38 --- /dev/null +++ b/src/kernel/types/agents/auth/__init__.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .run_submit_params import RunSubmitParams as RunSubmitParams +from .run_exchange_params import RunExchangeParams as RunExchangeParams +from .run_exchange_response import RunExchangeResponse as RunExchangeResponse diff --git a/src/kernel/types/agents/auth/run_exchange_params.py b/src/kernel/types/agents/auth/run_exchange_params.py new file mode 100644 index 00000000..1a23b25d --- /dev/null +++ b/src/kernel/types/agents/auth/run_exchange_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RunExchangeParams"] + + +class RunExchangeParams(TypedDict, total=False): + code: Required[str] + """Handoff code from start endpoint""" diff --git a/src/kernel/types/agents/auth/run_exchange_response.py b/src/kernel/types/agents/auth/run_exchange_response.py new file mode 100644 index 00000000..347c57c3 --- /dev/null +++ b/src/kernel/types/agents/auth/run_exchange_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["RunExchangeResponse"] + + +class RunExchangeResponse(BaseModel): + jwt: str + """JWT token with run_id claim (30 minute TTL)""" + + run_id: str + """Run ID""" diff --git a/src/kernel/types/agents/auth/run_submit_params.py b/src/kernel/types/agents/auth/run_submit_params.py new file mode 100644 index 00000000..efaf9ea5 --- /dev/null +++ b/src/kernel/types/agents/auth/run_submit_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import Required, TypedDict + +__all__ = ["RunSubmitParams"] + + +class RunSubmitParams(TypedDict, total=False): + field_values: Required[Dict[str, str]] + """Values for the discovered login fields""" diff --git a/src/kernel/types/agents/auth_start_params.py b/src/kernel/types/agents/auth_start_params.py new file mode 100644 index 00000000..6e0f0c82 --- /dev/null +++ b/src/kernel/types/agents/auth_start_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["AuthStartParams", "Proxy"] + + +class AuthStartParams(TypedDict, total=False): + profile_name: Required[str] + """Name of the profile to use for this flow""" + + target_domain: Required[str] + """Target domain for authentication""" + + app_logo_url: str + """Optional logo URL for the application""" + + proxy: Proxy + """Optional proxy configuration""" + + +class Proxy(TypedDict, total=False): + proxy_id: str + """ID of the proxy to use""" diff --git a/src/kernel/types/agents/discovered_field.py b/src/kernel/types/agents/discovered_field.py new file mode 100644 index 00000000..90a4864c --- /dev/null +++ b/src/kernel/types/agents/discovered_field.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["DiscoveredField"] + + +class DiscoveredField(BaseModel): + label: str + """Field label""" + + name: str + """Field name""" + + selector: str + """CSS selector for the field""" + + type: Literal["text", "email", "password", "tel", "number", "url", "code", "checkbox"] + """Field type""" + + placeholder: Optional[str] = None + """Field placeholder""" + + required: Optional[bool] = None + """Whether field is required""" diff --git a/tests/api_resources/agents/__init__.py b/tests/api_resources/agents/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/agents/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/agents/auth/__init__.py b/tests/api_resources/agents/auth/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/agents/auth/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/agents/auth/test_runs.py b/tests/api_resources/agents/auth/test_runs.py new file mode 100644 index 00000000..25fbdb14 --- /dev/null +++ b/tests/api_resources/agents/auth/test_runs.py @@ -0,0 +1,401 @@ +# 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.agents import AgentAuthRunResponse, AgentAuthSubmitResponse, AgentAuthDiscoverResponse +from kernel.types.agents.auth import RunExchangeResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRuns: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_retrieve(self, client: Kernel) -> None: + run = client.agents.auth.runs.retrieve( + "run_id", + ) + assert_matches_type(AgentAuthRunResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Kernel) -> None: + response = client.agents.auth.runs.with_raw_response.retrieve( + "run_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(AgentAuthRunResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Kernel) -> None: + with client.agents.auth.runs.with_streaming_response.retrieve( + "run_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(AgentAuthRunResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.agents.auth.runs.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_discover(self, client: Kernel) -> None: + run = client.agents.auth.runs.discover( + "run_id", + ) + assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_discover(self, client: Kernel) -> None: + response = client.agents.auth.runs.with_raw_response.discover( + "run_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_discover(self, client: Kernel) -> None: + with client.agents.auth.runs.with_streaming_response.discover( + "run_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_discover(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.agents.auth.runs.with_raw_response.discover( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_exchange(self, client: Kernel) -> None: + run = client.agents.auth.runs.exchange( + run_id="run_id", + code="otp_abc123xyz", + ) + assert_matches_type(RunExchangeResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_exchange(self, client: Kernel) -> None: + response = client.agents.auth.runs.with_raw_response.exchange( + run_id="run_id", + code="otp_abc123xyz", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(RunExchangeResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_exchange(self, client: Kernel) -> None: + with client.agents.auth.runs.with_streaming_response.exchange( + run_id="run_id", + code="otp_abc123xyz", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(RunExchangeResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_exchange(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.agents.auth.runs.with_raw_response.exchange( + run_id="", + code="otp_abc123xyz", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_submit(self, client: Kernel) -> None: + run = client.agents.auth.runs.submit( + run_id="run_id", + field_values={ + "email": "user@example.com", + "password": "********", + }, + ) + assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_submit(self, client: Kernel) -> None: + response = client.agents.auth.runs.with_raw_response.submit( + run_id="run_id", + field_values={ + "email": "user@example.com", + "password": "********", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = response.parse() + assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_submit(self, client: Kernel) -> None: + with client.agents.auth.runs.with_streaming_response.submit( + run_id="run_id", + field_values={ + "email": "user@example.com", + "password": "********", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = response.parse() + assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_submit(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.agents.auth.runs.with_raw_response.submit( + run_id="", + field_values={ + "email": "user@example.com", + "password": "********", + }, + ) + + +class TestAsyncRuns: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKernel) -> None: + run = await async_client.agents.auth.runs.retrieve( + "run_id", + ) + assert_matches_type(AgentAuthRunResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: + response = await async_client.agents.auth.runs.with_raw_response.retrieve( + "run_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = await response.parse() + assert_matches_type(AgentAuthRunResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: + async with async_client.agents.auth.runs.with_streaming_response.retrieve( + "run_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(AgentAuthRunResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.agents.auth.runs.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_discover(self, async_client: AsyncKernel) -> None: + run = await async_client.agents.auth.runs.discover( + "run_id", + ) + assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_discover(self, async_client: AsyncKernel) -> None: + response = await async_client.agents.auth.runs.with_raw_response.discover( + "run_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = await response.parse() + assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_discover(self, async_client: AsyncKernel) -> None: + async with async_client.agents.auth.runs.with_streaming_response.discover( + "run_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_discover(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.agents.auth.runs.with_raw_response.discover( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_exchange(self, async_client: AsyncKernel) -> None: + run = await async_client.agents.auth.runs.exchange( + run_id="run_id", + code="otp_abc123xyz", + ) + assert_matches_type(RunExchangeResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_exchange(self, async_client: AsyncKernel) -> None: + response = await async_client.agents.auth.runs.with_raw_response.exchange( + run_id="run_id", + code="otp_abc123xyz", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = await response.parse() + assert_matches_type(RunExchangeResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_exchange(self, async_client: AsyncKernel) -> None: + async with async_client.agents.auth.runs.with_streaming_response.exchange( + run_id="run_id", + code="otp_abc123xyz", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(RunExchangeResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_exchange(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.agents.auth.runs.with_raw_response.exchange( + run_id="", + code="otp_abc123xyz", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_submit(self, async_client: AsyncKernel) -> None: + run = await async_client.agents.auth.runs.submit( + run_id="run_id", + field_values={ + "email": "user@example.com", + "password": "********", + }, + ) + assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_submit(self, async_client: AsyncKernel) -> None: + response = await async_client.agents.auth.runs.with_raw_response.submit( + run_id="run_id", + field_values={ + "email": "user@example.com", + "password": "********", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + run = await response.parse() + assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_submit(self, async_client: AsyncKernel) -> None: + async with async_client.agents.auth.runs.with_streaming_response.submit( + run_id="run_id", + field_values={ + "email": "user@example.com", + "password": "********", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + run = await response.parse() + assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_submit(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.agents.auth.runs.with_raw_response.submit( + run_id="", + field_values={ + "email": "user@example.com", + "password": "********", + }, + ) diff --git a/tests/api_resources/agents/test_auth.py b/tests/api_resources/agents/test_auth.py new file mode 100644 index 00000000..32d2784f --- /dev/null +++ b/tests/api_resources/agents/test_auth.py @@ -0,0 +1,120 @@ +# 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.agents import AgentAuthStartResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAuth: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_start(self, client: Kernel) -> None: + auth = client.agents.auth.start( + profile_name="auth-abc123", + target_domain="doordash.com", + ) + assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_start_with_all_params(self, client: Kernel) -> None: + auth = client.agents.auth.start( + profile_name="auth-abc123", + target_domain="doordash.com", + app_logo_url="https://example.com/logo.png", + proxy={"proxy_id": "proxy_id"}, + ) + assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_start(self, client: Kernel) -> None: + response = client.agents.auth.with_raw_response.start( + profile_name="auth-abc123", + target_domain="doordash.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + auth = response.parse() + assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_start(self, client: Kernel) -> None: + with client.agents.auth.with_streaming_response.start( + profile_name="auth-abc123", + target_domain="doordash.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + auth = response.parse() + assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAuth: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_start(self, async_client: AsyncKernel) -> None: + auth = await async_client.agents.auth.start( + profile_name="auth-abc123", + target_domain="doordash.com", + ) + assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_start_with_all_params(self, async_client: AsyncKernel) -> None: + auth = await async_client.agents.auth.start( + profile_name="auth-abc123", + target_domain="doordash.com", + app_logo_url="https://example.com/logo.png", + proxy={"proxy_id": "proxy_id"}, + ) + assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_start(self, async_client: AsyncKernel) -> None: + response = await async_client.agents.auth.with_raw_response.start( + profile_name="auth-abc123", + target_domain="doordash.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + auth = await response.parse() + assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_start(self, async_client: AsyncKernel) -> None: + async with async_client.agents.auth.with_streaming_response.start( + profile_name="auth-abc123", + target_domain="doordash.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + auth = await response.parse() + assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) + + assert cast(Any, response.is_closed) is True From 97876e25f1a6286ca6e4167a1ea34698bece00c6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 18:13:27 +0000 Subject: [PATCH 03/10] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index bdbede3e..fa4f9006 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 71 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-bb3f37e55117a56e7a4208bd646d3a68adeb651ced8531e13fbfc1fc9dcb05a4.yml -openapi_spec_hash: 7303ce8ce3130e16a6a5c2bb49e43e9b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-ae9ed0d949aa701dd3873e49080fe923404a8869ffcb69b7c912a3f244d0236d.yml +openapi_spec_hash: 654d6e13a8bfe2103b373c668f43b33d config_hash: be146470fb2d4583b6533859f0fa48f5 From a2f7605b72d38968fe83d6c7780956478812880a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 00:27:26 +0000 Subject: [PATCH 04/10] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index fa4f9006..541095fa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 71 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-ae9ed0d949aa701dd3873e49080fe923404a8869ffcb69b7c912a3f244d0236d.yml -openapi_spec_hash: 654d6e13a8bfe2103b373c668f43b33d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2a63841293bec1bb651c5a24a95b2e9b5c07851dec1164de1aa2f87dafc51046.yml +openapi_spec_hash: d0bb3ca22c10b79758d503f717dd8e2f config_hash: be146470fb2d4583b6533859f0fa48f5 From c82f496ba0112b195f65da9498fb22ab65d501fb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 03:12:20 +0000 Subject: [PATCH 05/10] fix: ensure streams are always closed --- src/kernel/_streaming.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/kernel/_streaming.py b/src/kernel/_streaming.py index e6d03062..369a3f6d 100644 --- a/src/kernel/_streaming.py +++ b/src/kernel/_streaming.py @@ -54,11 +54,12 @@ def __stream__(self) -> Iterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # As we might not fully consume the response stream, we need to close it explicitly - response.close() + try: + for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() def __enter__(self) -> Self: return self @@ -117,11 +118,12 @@ async def __stream__(self) -> AsyncIterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - async for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # As we might not fully consume the response stream, we need to close it explicitly - await response.aclose() + try: + async for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() async def __aenter__(self) -> Self: return self From 038b10d52935961c37ebb0806e9b0754b4d53a20 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 03:13:24 +0000 Subject: [PATCH 06/10] chore(deps): mypy 1.18.1 has a regression, pin to 1.17 --- pyproject.toml | 2 +- requirements-dev.lock | 4 +++- requirements.lock | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 43139568..71c4c9aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ managed = true # version pins are in requirements-dev.lock dev-dependencies = [ "pyright==1.1.399", - "mypy", + "mypy==1.17", "respx", "pytest", "pytest-asyncio", diff --git a/requirements-dev.lock b/requirements-dev.lock index fc032738..b435fc70 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -72,7 +72,7 @@ mdurl==0.1.2 multidict==6.4.4 # via aiohttp # via yarl -mypy==1.14.1 +mypy==1.17.0 mypy-extensions==1.0.0 # via mypy nodeenv==1.8.0 @@ -81,6 +81,8 @@ nox==2023.4.22 packaging==23.2 # via nox # via pytest +pathspec==0.12.1 + # via mypy platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 diff --git a/requirements.lock b/requirements.lock index ed64e3db..646e8cda 100644 --- a/requirements.lock +++ b/requirements.lock @@ -55,21 +55,21 @@ multidict==6.4.4 propcache==0.3.1 # via aiohttp # via yarl -pydantic==2.11.9 +pydantic==2.12.5 # via kernel -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic sniffio==1.3.0 # via anyio # via kernel -typing-extensions==4.12.2 +typing-extensions==4.15.0 # via anyio # via kernel # via multidict # via pydantic # via pydantic-core # via typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic yarl==1.20.0 # via aiohttp From 5a76df0f20dcc45f0e16a1f78766a3e5aeaf5537 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 01:22:10 +0000 Subject: [PATCH 07/10] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 541095fa..a6b35ee5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 71 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2a63841293bec1bb651c5a24a95b2e9b5c07851dec1164de1aa2f87dafc51046.yml -openapi_spec_hash: d0bb3ca22c10b79758d503f717dd8e2f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-92b20a9e4650f645d3bb23b64f4ae72287bb41d3922ff1371426a91879186362.yml +openapi_spec_hash: a3c5f41d36734c980bc5313ee60b97cf config_hash: be146470fb2d4583b6533859f0fa48f5 From c2d7408a770ddd34902986015da0bfde3477f586 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 20:24:28 +0000 Subject: [PATCH 08/10] feat: Browser pools sdk release --- .stats.yml | 8 +- api.md | 54 +- src/kernel/_client.py | 19 +- src/kernel/resources/__init__.py | 28 +- src/kernel/resources/agents/__init__.py | 33 - src/kernel/resources/agents/agents.py | 102 -- src/kernel/resources/agents/auth/__init__.py | 33 - src/kernel/resources/agents/auth/auth.py | 239 ---- src/kernel/resources/agents/auth/runs.py | 434 ------- src/kernel/resources/browser_pools.py | 1022 +++++++++++++++++ src/kernel/resources/browsers/browsers.py | 15 +- src/kernel/types/__init__.py | 12 + src/kernel/types/agents/__init__.py | 10 - .../agents/agent_auth_discover_response.py | 28 - .../types/agents/agent_auth_run_response.py | 22 - .../types/agents/agent_auth_start_response.py | 21 - .../agents/agent_auth_submit_response.py | 34 - src/kernel/types/agents/auth/__init__.py | 7 - .../types/agents/auth/run_exchange_params.py | 12 - .../agents/auth/run_exchange_response.py | 13 - .../types/agents/auth/run_submit_params.py | 13 - src/kernel/types/agents/auth_start_params.py | 26 - src/kernel/types/agents/discovered_field.py | 28 - src/kernel/types/browser_create_params.py | 55 +- src/kernel/types/browser_create_response.py | 19 +- src/kernel/types/browser_list_response.py | 19 +- src/kernel/types/browser_pool.py | 29 + .../types/browser_pool_acquire_params.py | 16 + .../types/browser_pool_acquire_response.py | 64 ++ .../types/browser_pool_create_params.py | 75 ++ .../types/browser_pool_delete_params.py | 15 + .../types/browser_pool_list_response.py | 10 + .../types/browser_pool_release_params.py | 18 + src/kernel/types/browser_pool_request.py | 73 ++ .../types/browser_pool_update_params.py | 81 ++ src/kernel/types/browser_retrieve_response.py | 19 +- src/kernel/types/shared/__init__.py | 3 + src/kernel/types/shared/browser_extension.py | 18 + src/kernel/types/shared/browser_profile.py | 24 + src/kernel/types/shared/browser_viewport.py | 21 + src/kernel/types/shared_params/__init__.py | 5 + .../types/shared_params/browser_extension.py | 18 + .../types/shared_params/browser_profile.py | 24 + .../types/shared_params/browser_viewport.py | 21 + tests/api_resources/agents/__init__.py | 1 - tests/api_resources/agents/auth/__init__.py | 1 - tests/api_resources/agents/auth/test_runs.py | 401 ------- tests/api_resources/agents/test_auth.py | 120 -- tests/api_resources/test_browser_pools.py | 856 ++++++++++++++ 49 files changed, 2486 insertions(+), 1733 deletions(-) delete mode 100644 src/kernel/resources/agents/__init__.py delete mode 100644 src/kernel/resources/agents/agents.py delete mode 100644 src/kernel/resources/agents/auth/__init__.py delete mode 100644 src/kernel/resources/agents/auth/auth.py delete mode 100644 src/kernel/resources/agents/auth/runs.py create mode 100644 src/kernel/resources/browser_pools.py delete mode 100644 src/kernel/types/agents/__init__.py delete mode 100644 src/kernel/types/agents/agent_auth_discover_response.py delete mode 100644 src/kernel/types/agents/agent_auth_run_response.py delete mode 100644 src/kernel/types/agents/agent_auth_start_response.py delete mode 100644 src/kernel/types/agents/agent_auth_submit_response.py delete mode 100644 src/kernel/types/agents/auth/__init__.py delete mode 100644 src/kernel/types/agents/auth/run_exchange_params.py delete mode 100644 src/kernel/types/agents/auth/run_exchange_response.py delete mode 100644 src/kernel/types/agents/auth/run_submit_params.py delete mode 100644 src/kernel/types/agents/auth_start_params.py delete mode 100644 src/kernel/types/agents/discovered_field.py create mode 100644 src/kernel/types/browser_pool.py create mode 100644 src/kernel/types/browser_pool_acquire_params.py create mode 100644 src/kernel/types/browser_pool_acquire_response.py create mode 100644 src/kernel/types/browser_pool_create_params.py create mode 100644 src/kernel/types/browser_pool_delete_params.py create mode 100644 src/kernel/types/browser_pool_list_response.py create mode 100644 src/kernel/types/browser_pool_release_params.py create mode 100644 src/kernel/types/browser_pool_request.py create mode 100644 src/kernel/types/browser_pool_update_params.py create mode 100644 src/kernel/types/shared/browser_extension.py create mode 100644 src/kernel/types/shared/browser_profile.py create mode 100644 src/kernel/types/shared/browser_viewport.py create mode 100644 src/kernel/types/shared_params/__init__.py create mode 100644 src/kernel/types/shared_params/browser_extension.py create mode 100644 src/kernel/types/shared_params/browser_profile.py create mode 100644 src/kernel/types/shared_params/browser_viewport.py delete mode 100644 tests/api_resources/agents/__init__.py delete mode 100644 tests/api_resources/agents/auth/__init__.py delete mode 100644 tests/api_resources/agents/auth/test_runs.py delete mode 100644 tests/api_resources/agents/test_auth.py create mode 100644 tests/api_resources/test_browser_pools.py diff --git a/.stats.yml b/.stats.yml index a6b35ee5..c32f96db 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 71 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-92b20a9e4650f645d3bb23b64f4ae72287bb41d3922ff1371426a91879186362.yml -openapi_spec_hash: a3c5f41d36734c980bc5313ee60b97cf -config_hash: be146470fb2d4583b6533859f0fa48f5 +configured_endpoints: 74 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-340c8f009b71922347d4c238c8715cd752c8965abfa12cbb1ffabe35edc338a8.yml +openapi_spec_hash: efc13ab03ef89cc07333db8ab5345f31 +config_hash: a4124701ae0a474e580d7416adbcfb00 diff --git a/api.md b/api.md index 483ff9cb..fe6b45c0 100644 --- a/api.md +++ b/api.md @@ -1,7 +1,17 @@ # Shared Types ```python -from kernel.types import AppAction, ErrorDetail, ErrorEvent, ErrorModel, HeartbeatEvent, LogEvent +from kernel.types import ( + AppAction, + BrowserExtension, + BrowserProfile, + BrowserViewport, + ErrorDetail, + ErrorEvent, + ErrorModel, + HeartbeatEvent, + LogEvent, +) ``` # Deployments @@ -244,37 +254,29 @@ Methods: - client.extensions.download_from_chrome_store(\*\*params) -> BinaryAPIResponse - client.extensions.upload(\*\*params) -> ExtensionUploadResponse -# Agents - -## Auth +# BrowserPools Types: ```python -from kernel.types.agents import ( - AgentAuthDiscoverResponse, - AgentAuthRunResponse, - AgentAuthStartResponse, - AgentAuthSubmitResponse, - DiscoveredField, +from kernel.types import ( + BrowserPool, + BrowserPoolAcquireRequest, + BrowserPoolReleaseRequest, + BrowserPoolRequest, + BrowserPoolUpdateRequest, + BrowserPoolListResponse, + BrowserPoolAcquireResponse, ) ``` Methods: -- client.agents.auth.start(\*\*params) -> AgentAuthStartResponse - -### Runs - -Types: - -```python -from kernel.types.agents.auth import RunExchangeResponse -``` - -Methods: - -- client.agents.auth.runs.retrieve(run_id) -> AgentAuthRunResponse -- client.agents.auth.runs.discover(run_id) -> AgentAuthDiscoverResponse -- client.agents.auth.runs.exchange(run_id, \*\*params) -> RunExchangeResponse -- client.agents.auth.runs.submit(run_id, \*\*params) -> AgentAuthSubmitResponse +- 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.delete(id_or_name, \*\*params) -> None +- client.browser_pools.acquire(id_or_name, \*\*params) -> BrowserPoolAcquireResponse +- client.browser_pools.flush(id_or_name) -> None +- client.browser_pools.release(id_or_name, \*\*params) -> None diff --git a/src/kernel/_client.py b/src/kernel/_client.py index ba424335..37ba4890 100644 --- a/src/kernel/_client.py +++ b/src/kernel/_client.py @@ -21,7 +21,7 @@ ) from ._utils import is_given, get_async_library from ._version import __version__ -from .resources import apps, proxies, profiles, extensions, deployments, invocations +from .resources import apps, proxies, profiles, extensions, deployments, invocations, browser_pools from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import KernelError, APIStatusError from ._base_client import ( @@ -29,7 +29,6 @@ SyncAPIClient, AsyncAPIClient, ) -from .resources.agents import agents from .resources.browsers import browsers __all__ = [ @@ -58,7 +57,7 @@ class Kernel(SyncAPIClient): profiles: profiles.ProfilesResource proxies: proxies.ProxiesResource extensions: extensions.ExtensionsResource - agents: agents.AgentsResource + browser_pools: browser_pools.BrowserPoolsResource with_raw_response: KernelWithRawResponse with_streaming_response: KernelWithStreamedResponse @@ -147,7 +146,7 @@ def __init__( self.profiles = profiles.ProfilesResource(self) self.proxies = proxies.ProxiesResource(self) self.extensions = extensions.ExtensionsResource(self) - self.agents = agents.AgentsResource(self) + self.browser_pools = browser_pools.BrowserPoolsResource(self) self.with_raw_response = KernelWithRawResponse(self) self.with_streaming_response = KernelWithStreamedResponse(self) @@ -266,7 +265,7 @@ class AsyncKernel(AsyncAPIClient): profiles: profiles.AsyncProfilesResource proxies: proxies.AsyncProxiesResource extensions: extensions.AsyncExtensionsResource - agents: agents.AsyncAgentsResource + browser_pools: browser_pools.AsyncBrowserPoolsResource with_raw_response: AsyncKernelWithRawResponse with_streaming_response: AsyncKernelWithStreamedResponse @@ -355,7 +354,7 @@ def __init__( self.profiles = profiles.AsyncProfilesResource(self) self.proxies = proxies.AsyncProxiesResource(self) self.extensions = extensions.AsyncExtensionsResource(self) - self.agents = agents.AsyncAgentsResource(self) + self.browser_pools = browser_pools.AsyncBrowserPoolsResource(self) self.with_raw_response = AsyncKernelWithRawResponse(self) self.with_streaming_response = AsyncKernelWithStreamedResponse(self) @@ -475,7 +474,7 @@ def __init__(self, client: Kernel) -> None: self.profiles = profiles.ProfilesResourceWithRawResponse(client.profiles) self.proxies = proxies.ProxiesResourceWithRawResponse(client.proxies) self.extensions = extensions.ExtensionsResourceWithRawResponse(client.extensions) - self.agents = agents.AgentsResourceWithRawResponse(client.agents) + self.browser_pools = browser_pools.BrowserPoolsResourceWithRawResponse(client.browser_pools) class AsyncKernelWithRawResponse: @@ -487,7 +486,7 @@ def __init__(self, client: AsyncKernel) -> None: self.profiles = profiles.AsyncProfilesResourceWithRawResponse(client.profiles) self.proxies = proxies.AsyncProxiesResourceWithRawResponse(client.proxies) self.extensions = extensions.AsyncExtensionsResourceWithRawResponse(client.extensions) - self.agents = agents.AsyncAgentsResourceWithRawResponse(client.agents) + self.browser_pools = browser_pools.AsyncBrowserPoolsResourceWithRawResponse(client.browser_pools) class KernelWithStreamedResponse: @@ -499,7 +498,7 @@ def __init__(self, client: Kernel) -> None: self.profiles = profiles.ProfilesResourceWithStreamingResponse(client.profiles) self.proxies = proxies.ProxiesResourceWithStreamingResponse(client.proxies) self.extensions = extensions.ExtensionsResourceWithStreamingResponse(client.extensions) - self.agents = agents.AgentsResourceWithStreamingResponse(client.agents) + self.browser_pools = browser_pools.BrowserPoolsResourceWithStreamingResponse(client.browser_pools) class AsyncKernelWithStreamedResponse: @@ -511,7 +510,7 @@ def __init__(self, client: AsyncKernel) -> None: self.profiles = profiles.AsyncProfilesResourceWithStreamingResponse(client.profiles) self.proxies = proxies.AsyncProxiesResourceWithStreamingResponse(client.proxies) self.extensions = extensions.AsyncExtensionsResourceWithStreamingResponse(client.extensions) - self.agents = agents.AsyncAgentsResourceWithStreamingResponse(client.agents) + self.browser_pools = browser_pools.AsyncBrowserPoolsResourceWithStreamingResponse(client.browser_pools) Client = Kernel diff --git a/src/kernel/resources/__init__.py b/src/kernel/resources/__init__.py index 233ef508..cf08046e 100644 --- a/src/kernel/resources/__init__.py +++ b/src/kernel/resources/__init__.py @@ -8,14 +8,6 @@ AppsResourceWithStreamingResponse, AsyncAppsResourceWithStreamingResponse, ) -from .agents import ( - AgentsResource, - AsyncAgentsResource, - AgentsResourceWithRawResponse, - AsyncAgentsResourceWithRawResponse, - AgentsResourceWithStreamingResponse, - AsyncAgentsResourceWithStreamingResponse, -) from .proxies import ( ProxiesResource, AsyncProxiesResource, @@ -64,6 +56,14 @@ InvocationsResourceWithStreamingResponse, AsyncInvocationsResourceWithStreamingResponse, ) +from .browser_pools import ( + BrowserPoolsResource, + AsyncBrowserPoolsResource, + BrowserPoolsResourceWithRawResponse, + AsyncBrowserPoolsResourceWithRawResponse, + BrowserPoolsResourceWithStreamingResponse, + AsyncBrowserPoolsResourceWithStreamingResponse, +) __all__ = [ "DeploymentsResource", @@ -108,10 +108,10 @@ "AsyncExtensionsResourceWithRawResponse", "ExtensionsResourceWithStreamingResponse", "AsyncExtensionsResourceWithStreamingResponse", - "AgentsResource", - "AsyncAgentsResource", - "AgentsResourceWithRawResponse", - "AsyncAgentsResourceWithRawResponse", - "AgentsResourceWithStreamingResponse", - "AsyncAgentsResourceWithStreamingResponse", + "BrowserPoolsResource", + "AsyncBrowserPoolsResource", + "BrowserPoolsResourceWithRawResponse", + "AsyncBrowserPoolsResourceWithRawResponse", + "BrowserPoolsResourceWithStreamingResponse", + "AsyncBrowserPoolsResourceWithStreamingResponse", ] diff --git a/src/kernel/resources/agents/__init__.py b/src/kernel/resources/agents/__init__.py deleted file mode 100644 index cb159eb7..00000000 --- a/src/kernel/resources/agents/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .auth import ( - AuthResource, - AsyncAuthResource, - AuthResourceWithRawResponse, - AsyncAuthResourceWithRawResponse, - AuthResourceWithStreamingResponse, - AsyncAuthResourceWithStreamingResponse, -) -from .agents import ( - AgentsResource, - AsyncAgentsResource, - AgentsResourceWithRawResponse, - AsyncAgentsResourceWithRawResponse, - AgentsResourceWithStreamingResponse, - AsyncAgentsResourceWithStreamingResponse, -) - -__all__ = [ - "AuthResource", - "AsyncAuthResource", - "AuthResourceWithRawResponse", - "AsyncAuthResourceWithRawResponse", - "AuthResourceWithStreamingResponse", - "AsyncAuthResourceWithStreamingResponse", - "AgentsResource", - "AsyncAgentsResource", - "AgentsResourceWithRawResponse", - "AsyncAgentsResourceWithRawResponse", - "AgentsResourceWithStreamingResponse", - "AsyncAgentsResourceWithStreamingResponse", -] diff --git a/src/kernel/resources/agents/agents.py b/src/kernel/resources/agents/agents.py deleted file mode 100644 index b7bb580c..00000000 --- a/src/kernel/resources/agents/agents.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..._compat import cached_property -from .auth.auth import ( - AuthResource, - AsyncAuthResource, - AuthResourceWithRawResponse, - AsyncAuthResourceWithRawResponse, - AuthResourceWithStreamingResponse, - AsyncAuthResourceWithStreamingResponse, -) -from ..._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["AgentsResource", "AsyncAgentsResource"] - - -class AgentsResource(SyncAPIResource): - @cached_property - def auth(self) -> AuthResource: - return AuthResource(self._client) - - @cached_property - def with_raw_response(self) -> AgentsResourceWithRawResponse: - """ - 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers - """ - return AgentsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AgentsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response - """ - return AgentsResourceWithStreamingResponse(self) - - -class AsyncAgentsResource(AsyncAPIResource): - @cached_property - def auth(self) -> AsyncAuthResource: - return AsyncAuthResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncAgentsResourceWithRawResponse: - """ - 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers - """ - return AsyncAgentsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAgentsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response - """ - return AsyncAgentsResourceWithStreamingResponse(self) - - -class AgentsResourceWithRawResponse: - def __init__(self, agents: AgentsResource) -> None: - self._agents = agents - - @cached_property - def auth(self) -> AuthResourceWithRawResponse: - return AuthResourceWithRawResponse(self._agents.auth) - - -class AsyncAgentsResourceWithRawResponse: - def __init__(self, agents: AsyncAgentsResource) -> None: - self._agents = agents - - @cached_property - def auth(self) -> AsyncAuthResourceWithRawResponse: - return AsyncAuthResourceWithRawResponse(self._agents.auth) - - -class AgentsResourceWithStreamingResponse: - def __init__(self, agents: AgentsResource) -> None: - self._agents = agents - - @cached_property - def auth(self) -> AuthResourceWithStreamingResponse: - return AuthResourceWithStreamingResponse(self._agents.auth) - - -class AsyncAgentsResourceWithStreamingResponse: - def __init__(self, agents: AsyncAgentsResource) -> None: - self._agents = agents - - @cached_property - def auth(self) -> AsyncAuthResourceWithStreamingResponse: - return AsyncAuthResourceWithStreamingResponse(self._agents.auth) diff --git a/src/kernel/resources/agents/auth/__init__.py b/src/kernel/resources/agents/auth/__init__.py deleted file mode 100644 index d9853204..00000000 --- a/src/kernel/resources/agents/auth/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .auth import ( - AuthResource, - AsyncAuthResource, - AuthResourceWithRawResponse, - AsyncAuthResourceWithRawResponse, - AuthResourceWithStreamingResponse, - AsyncAuthResourceWithStreamingResponse, -) -from .runs import ( - RunsResource, - AsyncRunsResource, - RunsResourceWithRawResponse, - AsyncRunsResourceWithRawResponse, - RunsResourceWithStreamingResponse, - AsyncRunsResourceWithStreamingResponse, -) - -__all__ = [ - "RunsResource", - "AsyncRunsResource", - "RunsResourceWithRawResponse", - "AsyncRunsResourceWithRawResponse", - "RunsResourceWithStreamingResponse", - "AsyncRunsResourceWithStreamingResponse", - "AuthResource", - "AsyncAuthResource", - "AuthResourceWithRawResponse", - "AsyncAuthResourceWithRawResponse", - "AuthResourceWithStreamingResponse", - "AsyncAuthResourceWithStreamingResponse", -] diff --git a/src/kernel/resources/agents/auth/auth.py b/src/kernel/resources/agents/auth/auth.py deleted file mode 100644 index 2e099095..00000000 --- a/src/kernel/resources/agents/auth/auth.py +++ /dev/null @@ -1,239 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .runs import ( - RunsResource, - AsyncRunsResource, - RunsResourceWithRawResponse, - AsyncRunsResourceWithRawResponse, - RunsResourceWithStreamingResponse, - AsyncRunsResourceWithStreamingResponse, -) -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import 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.agents import auth_start_params -from ....types.agents.agent_auth_start_response import AgentAuthStartResponse - -__all__ = ["AuthResource", "AsyncAuthResource"] - - -class AuthResource(SyncAPIResource): - @cached_property - def runs(self) -> RunsResource: - return RunsResource(self._client) - - @cached_property - def with_raw_response(self) -> AuthResourceWithRawResponse: - """ - 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers - """ - return AuthResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AuthResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response - """ - return AuthResourceWithStreamingResponse(self) - - def start( - self, - *, - profile_name: str, - target_domain: str, - app_logo_url: str | Omit = omit, - proxy: auth_start_params.Proxy | 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, - ) -> AgentAuthStartResponse: - """Creates a browser session and returns a handoff code for the hosted flow. - - Uses - standard API key or JWT authentication (not the JWT returned by the exchange - endpoint). - - Args: - profile_name: Name of the profile to use for this flow - - target_domain: Target domain for authentication - - app_logo_url: Optional logo URL for the application - - proxy: Optional proxy configuration - - 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._post( - "/agents/auth/start", - body=maybe_transform( - { - "profile_name": profile_name, - "target_domain": target_domain, - "app_logo_url": app_logo_url, - "proxy": proxy, - }, - auth_start_params.AuthStartParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentAuthStartResponse, - ) - - -class AsyncAuthResource(AsyncAPIResource): - @cached_property - def runs(self) -> AsyncRunsResource: - return AsyncRunsResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncAuthResourceWithRawResponse: - """ - 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers - """ - return AsyncAuthResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAuthResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response - """ - return AsyncAuthResourceWithStreamingResponse(self) - - async def start( - self, - *, - profile_name: str, - target_domain: str, - app_logo_url: str | Omit = omit, - proxy: auth_start_params.Proxy | 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, - ) -> AgentAuthStartResponse: - """Creates a browser session and returns a handoff code for the hosted flow. - - Uses - standard API key or JWT authentication (not the JWT returned by the exchange - endpoint). - - Args: - profile_name: Name of the profile to use for this flow - - target_domain: Target domain for authentication - - app_logo_url: Optional logo URL for the application - - proxy: Optional proxy configuration - - 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 await self._post( - "/agents/auth/start", - body=await async_maybe_transform( - { - "profile_name": profile_name, - "target_domain": target_domain, - "app_logo_url": app_logo_url, - "proxy": proxy, - }, - auth_start_params.AuthStartParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentAuthStartResponse, - ) - - -class AuthResourceWithRawResponse: - def __init__(self, auth: AuthResource) -> None: - self._auth = auth - - self.start = to_raw_response_wrapper( - auth.start, - ) - - @cached_property - def runs(self) -> RunsResourceWithRawResponse: - return RunsResourceWithRawResponse(self._auth.runs) - - -class AsyncAuthResourceWithRawResponse: - def __init__(self, auth: AsyncAuthResource) -> None: - self._auth = auth - - self.start = async_to_raw_response_wrapper( - auth.start, - ) - - @cached_property - def runs(self) -> AsyncRunsResourceWithRawResponse: - return AsyncRunsResourceWithRawResponse(self._auth.runs) - - -class AuthResourceWithStreamingResponse: - def __init__(self, auth: AuthResource) -> None: - self._auth = auth - - self.start = to_streamed_response_wrapper( - auth.start, - ) - - @cached_property - def runs(self) -> RunsResourceWithStreamingResponse: - return RunsResourceWithStreamingResponse(self._auth.runs) - - -class AsyncAuthResourceWithStreamingResponse: - def __init__(self, auth: AsyncAuthResource) -> None: - self._auth = auth - - self.start = async_to_streamed_response_wrapper( - auth.start, - ) - - @cached_property - def runs(self) -> AsyncRunsResourceWithStreamingResponse: - return AsyncRunsResourceWithStreamingResponse(self._auth.runs) diff --git a/src/kernel/resources/agents/auth/runs.py b/src/kernel/resources/agents/auth/runs.py deleted file mode 100644 index 6ea09403..00000000 --- a/src/kernel/resources/agents/auth/runs.py +++ /dev/null @@ -1,434 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict - -import httpx - -from ...._types import Body, Query, Headers, NotGiven, not_given -from ...._utils import 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.agents.auth import run_submit_params, run_exchange_params -from ....types.agents.agent_auth_run_response import AgentAuthRunResponse -from ....types.agents.agent_auth_submit_response import AgentAuthSubmitResponse -from ....types.agents.auth.run_exchange_response import RunExchangeResponse -from ....types.agents.agent_auth_discover_response import AgentAuthDiscoverResponse - -__all__ = ["RunsResource", "AsyncRunsResource"] - - -class RunsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> RunsResourceWithRawResponse: - """ - 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers - """ - return RunsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RunsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response - """ - return RunsResourceWithStreamingResponse(self) - - def retrieve( - self, - run_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, - ) -> AgentAuthRunResponse: - """Returns run details including app_name and target_domain. - - Uses the JWT returned - by the exchange endpoint, or standard API key or JWT authentication. - - 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 run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._get( - f"/agents/auth/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentAuthRunResponse, - ) - - def discover( - self, - run_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, - ) -> AgentAuthDiscoverResponse: - """ - Inspects the target site to detect logged-in state or discover required fields. - Returns 200 with success: true when fields are found, or 4xx/5xx for failures. - Requires the JWT returned by the exchange endpoint. - - 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 run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._post( - f"/agents/auth/runs/{run_id}/discover", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentAuthDiscoverResponse, - ) - - def exchange( - self, - run_id: str, - *, - code: 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, - ) -> RunExchangeResponse: - """Validates the handoff code and returns a JWT token for subsequent requests. - - No - authentication required (the handoff code serves as the credential). - - Args: - code: Handoff code from start endpoint - - 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 run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._post( - f"/agents/auth/runs/{run_id}/exchange", - body=maybe_transform({"code": code}, run_exchange_params.RunExchangeParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunExchangeResponse, - ) - - def submit( - self, - run_id: str, - *, - field_values: Dict[str, 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, - ) -> AgentAuthSubmitResponse: - """ - Submits field values for the discovered login form and may return additional - auth fields or success. Requires the JWT returned by the exchange endpoint. - - Args: - field_values: Values for the discovered login fields - - 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 run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._post( - f"/agents/auth/runs/{run_id}/submit", - body=maybe_transform({"field_values": field_values}, run_submit_params.RunSubmitParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentAuthSubmitResponse, - ) - - -class AsyncRunsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncRunsResourceWithRawResponse: - """ - 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers - """ - return AsyncRunsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRunsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response - """ - return AsyncRunsResourceWithStreamingResponse(self) - - async def retrieve( - self, - run_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, - ) -> AgentAuthRunResponse: - """Returns run details including app_name and target_domain. - - Uses the JWT returned - by the exchange endpoint, or standard API key or JWT authentication. - - 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 run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return await self._get( - f"/agents/auth/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentAuthRunResponse, - ) - - async def discover( - self, - run_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, - ) -> AgentAuthDiscoverResponse: - """ - Inspects the target site to detect logged-in state or discover required fields. - Returns 200 with success: true when fields are found, or 4xx/5xx for failures. - Requires the JWT returned by the exchange endpoint. - - 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 run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return await self._post( - f"/agents/auth/runs/{run_id}/discover", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentAuthDiscoverResponse, - ) - - async def exchange( - self, - run_id: str, - *, - code: 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, - ) -> RunExchangeResponse: - """Validates the handoff code and returns a JWT token for subsequent requests. - - No - authentication required (the handoff code serves as the credential). - - Args: - code: Handoff code from start endpoint - - 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 run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return await self._post( - f"/agents/auth/runs/{run_id}/exchange", - body=await async_maybe_transform({"code": code}, run_exchange_params.RunExchangeParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunExchangeResponse, - ) - - async def submit( - self, - run_id: str, - *, - field_values: Dict[str, 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, - ) -> AgentAuthSubmitResponse: - """ - Submits field values for the discovered login form and may return additional - auth fields or success. Requires the JWT returned by the exchange endpoint. - - Args: - field_values: Values for the discovered login fields - - 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 run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return await self._post( - f"/agents/auth/runs/{run_id}/submit", - body=await async_maybe_transform({"field_values": field_values}, run_submit_params.RunSubmitParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentAuthSubmitResponse, - ) - - -class RunsResourceWithRawResponse: - def __init__(self, runs: RunsResource) -> None: - self._runs = runs - - self.retrieve = to_raw_response_wrapper( - runs.retrieve, - ) - self.discover = to_raw_response_wrapper( - runs.discover, - ) - self.exchange = to_raw_response_wrapper( - runs.exchange, - ) - self.submit = to_raw_response_wrapper( - runs.submit, - ) - - -class AsyncRunsResourceWithRawResponse: - def __init__(self, runs: AsyncRunsResource) -> None: - self._runs = runs - - self.retrieve = async_to_raw_response_wrapper( - runs.retrieve, - ) - self.discover = async_to_raw_response_wrapper( - runs.discover, - ) - self.exchange = async_to_raw_response_wrapper( - runs.exchange, - ) - self.submit = async_to_raw_response_wrapper( - runs.submit, - ) - - -class RunsResourceWithStreamingResponse: - def __init__(self, runs: RunsResource) -> None: - self._runs = runs - - self.retrieve = to_streamed_response_wrapper( - runs.retrieve, - ) - self.discover = to_streamed_response_wrapper( - runs.discover, - ) - self.exchange = to_streamed_response_wrapper( - runs.exchange, - ) - self.submit = to_streamed_response_wrapper( - runs.submit, - ) - - -class AsyncRunsResourceWithStreamingResponse: - def __init__(self, runs: AsyncRunsResource) -> None: - self._runs = runs - - self.retrieve = async_to_streamed_response_wrapper( - runs.retrieve, - ) - self.discover = async_to_streamed_response_wrapper( - runs.discover, - ) - self.exchange = async_to_streamed_response_wrapper( - runs.exchange, - ) - self.submit = async_to_streamed_response_wrapper( - runs.submit, - ) diff --git a/src/kernel/resources/browser_pools.py b/src/kernel/resources/browser_pools.py new file mode 100644 index 00000000..d085d515 --- /dev/null +++ b/src/kernel/resources/browser_pools.py @@ -0,0 +1,1022 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ..types import ( + browser_pool_create_params, + browser_pool_delete_params, + browser_pool_update_params, + browser_pool_acquire_params, + browser_pool_release_params, +) +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from .._utils import 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.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 +from ..types.shared_params.browser_extension import BrowserExtension + +__all__ = ["BrowserPoolsResource", "AsyncBrowserPoolsResource"] + + +class BrowserPoolsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BrowserPoolsResourceWithRawResponse: + """ + 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return BrowserPoolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BrowserPoolsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return BrowserPoolsResourceWithStreamingResponse(self) + + def create( + self, + *, + size: int, + extensions: Iterable[BrowserExtension] | Omit = omit, + fill_rate_per_minute: int | Omit = omit, + headless: bool | Omit = omit, + kiosk_mode: bool | Omit = omit, + name: str | Omit = omit, + profile: BrowserProfile | Omit = omit, + proxy_id: str | Omit = omit, + stealth: bool | Omit = omit, + timeout_seconds: int | Omit = omit, + viewport: BrowserViewport | 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, + ) -> BrowserPool: + """ + Create a new browser pool with the specified configuration and size. + + Args: + size: Number of browsers to create in the pool + + extensions: List of browser extensions to load into the session. Provide each by id or name. + + fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10%. + + headless: If true, launches the browser using a headless image. Defaults to false. + + kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + + name: Optional name for the browser pool. Must be unique within the organization. + + profile: Profile selection for the browser session. Provide either id or name. If + specified, the matching profile will be loaded into the browser session. + Profiles must be created beforehand. + + proxy_id: Optional proxy to associate to the browser session. Must reference a proxy + belonging to the caller's org. + + stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + + timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, + image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 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 + + 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._post( + "/browser_pools", + body=maybe_transform( + { + "size": size, + "extensions": extensions, + "fill_rate_per_minute": fill_rate_per_minute, + "headless": headless, + "kiosk_mode": kiosk_mode, + "name": name, + "profile": profile, + "proxy_id": proxy_id, + "stealth": stealth, + "timeout_seconds": timeout_seconds, + "viewport": viewport, + }, + browser_pool_create_params.BrowserPoolCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + def retrieve( + self, + id_or_name: 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, + ) -> BrowserPool: + """ + Retrieve details for a single browser pool by its ID or name. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._get( + f"/browser_pools/{id_or_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + def update( + self, + id_or_name: str, + *, + size: int, + discard_all_idle: bool | Omit = omit, + extensions: Iterable[BrowserExtension] | Omit = omit, + fill_rate_per_minute: int | Omit = omit, + headless: bool | Omit = omit, + kiosk_mode: bool | Omit = omit, + name: str | Omit = omit, + profile: BrowserProfile | Omit = omit, + proxy_id: str | Omit = omit, + stealth: bool | Omit = omit, + timeout_seconds: int | Omit = omit, + viewport: BrowserViewport | 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, + ) -> BrowserPool: + """ + Updates the configuration used to create browsers in the pool. + + Args: + size: Number of browsers to create in the pool + + discard_all_idle: Whether to discard all idle browsers and rebuild the pool immediately. Defaults + to true. + + extensions: List of browser extensions to load into the session. Provide each by id or name. + + fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10%. + + headless: If true, launches the browser using a headless image. Defaults to false. + + kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + + name: Optional name for the browser pool. Must be unique within the organization. + + profile: Profile selection for the browser session. Provide either id or name. If + specified, the matching profile will be loaded into the browser session. + Profiles must be created beforehand. + + proxy_id: Optional proxy to associate to the browser session. Must reference a proxy + belonging to the caller's org. + + stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + + timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, + image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 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 + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._patch( + f"/browser_pools/{id_or_name}", + body=maybe_transform( + { + "size": size, + "discard_all_idle": discard_all_idle, + "extensions": extensions, + "fill_rate_per_minute": fill_rate_per_minute, + "headless": headless, + "kiosk_mode": kiosk_mode, + "name": name, + "profile": profile, + "proxy_id": proxy_id, + "stealth": stealth, + "timeout_seconds": timeout_seconds, + "viewport": viewport, + }, + browser_pool_update_params.BrowserPoolUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + def list( + self, + *, + # 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( + "/browser_pools", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPoolListResponse, + ) + + def delete( + self, + id_or_name: str, + *, + force: bool | 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, + ) -> None: + """Delete a browser pool and all browsers in it. + + By default, deletion is blocked if + browsers are currently leased. Use force=true to terminate leased browsers. + + Args: + force: If true, force delete even if browsers are currently leased. Leased browsers + will be terminated. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/browser_pools/{id_or_name}", + body=maybe_transform({"force": force}, browser_pool_delete_params.BrowserPoolDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def acquire( + self, + id_or_name: str, + *, + acquire_timeout_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, + ) -> BrowserPoolAcquireResponse: + """Long-polling endpoint to acquire a browser from the pool. + + Returns immediately + when a browser is available, or returns 204 No Content when the poll times out. + The client should retry the request to continue waiting for a browser. The + acquired browser will use the pool's timeout_seconds for its idle timeout. + + Args: + acquire_timeout_seconds: Maximum number of seconds to wait for a browser to be available. Defaults to the + calculated time it would take to fill the pool at the currently configured fill + rate. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._post( + f"/browser_pools/{id_or_name}/acquire", + body=maybe_transform( + {"acquire_timeout_seconds": acquire_timeout_seconds}, + browser_pool_acquire_params.BrowserPoolAcquireParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPoolAcquireResponse, + ) + + def flush( + self, + id_or_name: 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, + ) -> None: + """ + Destroys all idle browsers in the pool; leased browsers are not affected. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/browser_pools/{id_or_name}/flush", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def release( + self, + id_or_name: str, + *, + session_id: str, + reuse: bool | 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, + ) -> None: + """ + Release a browser back to the pool, optionally recreating the browser instance. + + Args: + session_id: Browser session ID to release back to the pool + + reuse: Whether to reuse the browser instance or destroy it and create a new one. + Defaults to true. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/browser_pools/{id_or_name}/release", + body=maybe_transform( + { + "session_id": session_id, + "reuse": reuse, + }, + browser_pool_release_params.BrowserPoolReleaseParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncBrowserPoolsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBrowserPoolsResourceWithRawResponse: + """ + 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/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncBrowserPoolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBrowserPoolsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return AsyncBrowserPoolsResourceWithStreamingResponse(self) + + async def create( + self, + *, + size: int, + extensions: Iterable[BrowserExtension] | Omit = omit, + fill_rate_per_minute: int | Omit = omit, + headless: bool | Omit = omit, + kiosk_mode: bool | Omit = omit, + name: str | Omit = omit, + profile: BrowserProfile | Omit = omit, + proxy_id: str | Omit = omit, + stealth: bool | Omit = omit, + timeout_seconds: int | Omit = omit, + viewport: BrowserViewport | 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, + ) -> BrowserPool: + """ + Create a new browser pool with the specified configuration and size. + + Args: + size: Number of browsers to create in the pool + + extensions: List of browser extensions to load into the session. Provide each by id or name. + + fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10%. + + headless: If true, launches the browser using a headless image. Defaults to false. + + kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + + name: Optional name for the browser pool. Must be unique within the organization. + + profile: Profile selection for the browser session. Provide either id or name. If + specified, the matching profile will be loaded into the browser session. + Profiles must be created beforehand. + + proxy_id: Optional proxy to associate to the browser session. Must reference a proxy + belonging to the caller's org. + + stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + + timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, + image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 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 + + 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 await self._post( + "/browser_pools", + body=await async_maybe_transform( + { + "size": size, + "extensions": extensions, + "fill_rate_per_minute": fill_rate_per_minute, + "headless": headless, + "kiosk_mode": kiosk_mode, + "name": name, + "profile": profile, + "proxy_id": proxy_id, + "stealth": stealth, + "timeout_seconds": timeout_seconds, + "viewport": viewport, + }, + browser_pool_create_params.BrowserPoolCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + async def retrieve( + self, + id_or_name: 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, + ) -> BrowserPool: + """ + Retrieve details for a single browser pool by its ID or name. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._get( + f"/browser_pools/{id_or_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + async def update( + self, + id_or_name: str, + *, + size: int, + discard_all_idle: bool | Omit = omit, + extensions: Iterable[BrowserExtension] | Omit = omit, + fill_rate_per_minute: int | Omit = omit, + headless: bool | Omit = omit, + kiosk_mode: bool | Omit = omit, + name: str | Omit = omit, + profile: BrowserProfile | Omit = omit, + proxy_id: str | Omit = omit, + stealth: bool | Omit = omit, + timeout_seconds: int | Omit = omit, + viewport: BrowserViewport | 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, + ) -> BrowserPool: + """ + Updates the configuration used to create browsers in the pool. + + Args: + size: Number of browsers to create in the pool + + discard_all_idle: Whether to discard all idle browsers and rebuild the pool immediately. Defaults + to true. + + extensions: List of browser extensions to load into the session. Provide each by id or name. + + fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10%. + + headless: If true, launches the browser using a headless image. Defaults to false. + + kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + + name: Optional name for the browser pool. Must be unique within the organization. + + profile: Profile selection for the browser session. Provide either id or name. If + specified, the matching profile will be loaded into the browser session. + Profiles must be created beforehand. + + proxy_id: Optional proxy to associate to the browser session. Must reference a proxy + belonging to the caller's org. + + stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + + timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, + image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 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 + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._patch( + f"/browser_pools/{id_or_name}", + body=await async_maybe_transform( + { + "size": size, + "discard_all_idle": discard_all_idle, + "extensions": extensions, + "fill_rate_per_minute": fill_rate_per_minute, + "headless": headless, + "kiosk_mode": kiosk_mode, + "name": name, + "profile": profile, + "proxy_id": proxy_id, + "stealth": stealth, + "timeout_seconds": timeout_seconds, + "viewport": viewport, + }, + browser_pool_update_params.BrowserPoolUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + async def list( + self, + *, + # 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( + "/browser_pools", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPoolListResponse, + ) + + async def delete( + self, + id_or_name: str, + *, + force: bool | 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, + ) -> None: + """Delete a browser pool and all browsers in it. + + By default, deletion is blocked if + browsers are currently leased. Use force=true to terminate leased browsers. + + Args: + force: If true, force delete even if browsers are currently leased. Leased browsers + will be terminated. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/browser_pools/{id_or_name}", + body=await async_maybe_transform({"force": force}, browser_pool_delete_params.BrowserPoolDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def acquire( + self, + id_or_name: str, + *, + acquire_timeout_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, + ) -> BrowserPoolAcquireResponse: + """Long-polling endpoint to acquire a browser from the pool. + + Returns immediately + when a browser is available, or returns 204 No Content when the poll times out. + The client should retry the request to continue waiting for a browser. The + acquired browser will use the pool's timeout_seconds for its idle timeout. + + Args: + acquire_timeout_seconds: Maximum number of seconds to wait for a browser to be available. Defaults to the + calculated time it would take to fill the pool at the currently configured fill + rate. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._post( + f"/browser_pools/{id_or_name}/acquire", + body=await async_maybe_transform( + {"acquire_timeout_seconds": acquire_timeout_seconds}, + browser_pool_acquire_params.BrowserPoolAcquireParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPoolAcquireResponse, + ) + + async def flush( + self, + id_or_name: 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, + ) -> None: + """ + Destroys all idle browsers in the pool; leased browsers are not affected. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/browser_pools/{id_or_name}/flush", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def release( + self, + id_or_name: str, + *, + session_id: str, + reuse: bool | 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, + ) -> None: + """ + Release a browser back to the pool, optionally recreating the browser instance. + + Args: + session_id: Browser session ID to release back to the pool + + reuse: Whether to reuse the browser instance or destroy it and create a new one. + Defaults to true. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/browser_pools/{id_or_name}/release", + body=await async_maybe_transform( + { + "session_id": session_id, + "reuse": reuse, + }, + browser_pool_release_params.BrowserPoolReleaseParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class BrowserPoolsResourceWithRawResponse: + def __init__(self, browser_pools: BrowserPoolsResource) -> None: + self._browser_pools = browser_pools + + self.create = to_raw_response_wrapper( + browser_pools.create, + ) + self.retrieve = to_raw_response_wrapper( + browser_pools.retrieve, + ) + self.update = to_raw_response_wrapper( + browser_pools.update, + ) + self.list = to_raw_response_wrapper( + browser_pools.list, + ) + self.delete = to_raw_response_wrapper( + browser_pools.delete, + ) + self.acquire = to_raw_response_wrapper( + browser_pools.acquire, + ) + self.flush = to_raw_response_wrapper( + browser_pools.flush, + ) + self.release = to_raw_response_wrapper( + browser_pools.release, + ) + + +class AsyncBrowserPoolsResourceWithRawResponse: + def __init__(self, browser_pools: AsyncBrowserPoolsResource) -> None: + self._browser_pools = browser_pools + + self.create = async_to_raw_response_wrapper( + browser_pools.create, + ) + self.retrieve = async_to_raw_response_wrapper( + browser_pools.retrieve, + ) + self.update = async_to_raw_response_wrapper( + browser_pools.update, + ) + self.list = async_to_raw_response_wrapper( + browser_pools.list, + ) + self.delete = async_to_raw_response_wrapper( + browser_pools.delete, + ) + self.acquire = async_to_raw_response_wrapper( + browser_pools.acquire, + ) + self.flush = async_to_raw_response_wrapper( + browser_pools.flush, + ) + self.release = async_to_raw_response_wrapper( + browser_pools.release, + ) + + +class BrowserPoolsResourceWithStreamingResponse: + def __init__(self, browser_pools: BrowserPoolsResource) -> None: + self._browser_pools = browser_pools + + self.create = to_streamed_response_wrapper( + browser_pools.create, + ) + self.retrieve = to_streamed_response_wrapper( + browser_pools.retrieve, + ) + self.update = to_streamed_response_wrapper( + browser_pools.update, + ) + self.list = to_streamed_response_wrapper( + browser_pools.list, + ) + self.delete = to_streamed_response_wrapper( + browser_pools.delete, + ) + self.acquire = to_streamed_response_wrapper( + browser_pools.acquire, + ) + self.flush = to_streamed_response_wrapper( + browser_pools.flush, + ) + self.release = to_streamed_response_wrapper( + browser_pools.release, + ) + + +class AsyncBrowserPoolsResourceWithStreamingResponse: + def __init__(self, browser_pools: AsyncBrowserPoolsResource) -> None: + self._browser_pools = browser_pools + + self.create = async_to_streamed_response_wrapper( + browser_pools.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + browser_pools.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + browser_pools.update, + ) + self.list = async_to_streamed_response_wrapper( + browser_pools.list, + ) + self.delete = async_to_streamed_response_wrapper( + browser_pools.delete, + ) + self.acquire = async_to_streamed_response_wrapper( + browser_pools.acquire, + ) + self.flush = async_to_streamed_response_wrapper( + browser_pools.flush, + ) + self.release = async_to_streamed_response_wrapper( + browser_pools.release, + ) diff --git a/src/kernel/resources/browsers/browsers.py b/src/kernel/resources/browsers/browsers.py index 84a4fe48..f41b46ad 100644 --- a/src/kernel/resources/browsers/browsers.py +++ b/src/kernel/resources/browsers/browsers.py @@ -76,6 +76,9 @@ from ...types.browser_create_response import BrowserCreateResponse from ...types.browser_persistence_param import BrowserPersistenceParam from ...types.browser_retrieve_response import BrowserRetrieveResponse +from ...types.shared_params.browser_profile import BrowserProfile +from ...types.shared_params.browser_viewport import BrowserViewport +from ...types.shared_params.browser_extension import BrowserExtension __all__ = ["BrowsersResource", "AsyncBrowsersResource"] @@ -127,16 +130,16 @@ def with_streaming_response(self) -> BrowsersResourceWithStreamingResponse: def create( self, *, - extensions: Iterable[browser_create_params.Extension] | Omit = omit, + extensions: Iterable[BrowserExtension] | Omit = omit, headless: bool | Omit = omit, invocation_id: str | Omit = omit, kiosk_mode: bool | Omit = omit, persistence: BrowserPersistenceParam | Omit = omit, - profile: browser_create_params.Profile | Omit = omit, + profile: BrowserProfile | Omit = omit, proxy_id: str | Omit = omit, stealth: bool | Omit = omit, timeout_seconds: int | Omit = omit, - viewport: browser_create_params.Viewport | Omit = omit, + viewport: BrowserViewport | 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, @@ -470,16 +473,16 @@ def with_streaming_response(self) -> AsyncBrowsersResourceWithStreamingResponse: async def create( self, *, - extensions: Iterable[browser_create_params.Extension] | Omit = omit, + extensions: Iterable[BrowserExtension] | Omit = omit, headless: bool | Omit = omit, invocation_id: str | Omit = omit, kiosk_mode: bool | Omit = omit, persistence: BrowserPersistenceParam | Omit = omit, - profile: browser_create_params.Profile | Omit = omit, + profile: BrowserProfile | Omit = omit, proxy_id: str | Omit = omit, stealth: bool | Omit = omit, timeout_seconds: int | Omit = omit, - viewport: browser_create_params.Viewport | Omit = omit, + viewport: BrowserViewport | 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, diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index 208a8bda..45b0c4ba 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -8,15 +8,20 @@ ErrorEvent as ErrorEvent, ErrorModel as ErrorModel, ErrorDetail as ErrorDetail, + BrowserProfile as BrowserProfile, HeartbeatEvent as HeartbeatEvent, + BrowserViewport as BrowserViewport, + BrowserExtension as BrowserExtension, ) from .profile import Profile as Profile +from .browser_pool import BrowserPool as BrowserPool from .app_list_params import AppListParams as AppListParams from .app_list_response import AppListResponse as AppListResponse from .browser_list_params import BrowserListParams as BrowserListParams from .browser_persistence import BrowserPersistence as BrowserPersistence from .proxy_create_params import ProxyCreateParams as ProxyCreateParams from .proxy_list_response import ProxyListResponse as ProxyListResponse +from .browser_pool_request import BrowserPoolRequest as BrowserPoolRequest from .browser_create_params import BrowserCreateParams as BrowserCreateParams from .browser_delete_params import BrowserDeleteParams as BrowserDeleteParams from .browser_list_response import BrowserListResponse as BrowserListResponse @@ -41,13 +46,20 @@ from .browser_persistence_param import BrowserPersistenceParam as BrowserPersistenceParam from .browser_retrieve_response import BrowserRetrieveResponse as BrowserRetrieveResponse 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 from .invocation_create_response import InvocationCreateResponse as InvocationCreateResponse from .invocation_follow_response import InvocationFollowResponse as InvocationFollowResponse from .invocation_update_response import InvocationUpdateResponse as InvocationUpdateResponse +from .browser_pool_acquire_params import BrowserPoolAcquireParams as BrowserPoolAcquireParams +from .browser_pool_release_params import BrowserPoolReleaseParams as BrowserPoolReleaseParams from .deployment_retrieve_response import DeploymentRetrieveResponse as DeploymentRetrieveResponse from .invocation_retrieve_response import InvocationRetrieveResponse as InvocationRetrieveResponse +from .browser_pool_acquire_response import BrowserPoolAcquireResponse as BrowserPoolAcquireResponse from .browser_load_extensions_params import BrowserLoadExtensionsParams as BrowserLoadExtensionsParams from .extension_download_from_chrome_store_params import ( ExtensionDownloadFromChromeStoreParams as ExtensionDownloadFromChromeStoreParams, diff --git a/src/kernel/types/agents/__init__.py b/src/kernel/types/agents/__init__.py deleted file mode 100644 index e8c22774..00000000 --- a/src/kernel/types/agents/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .discovered_field import DiscoveredField as DiscoveredField -from .auth_start_params import AuthStartParams as AuthStartParams -from .agent_auth_run_response import AgentAuthRunResponse as AgentAuthRunResponse -from .agent_auth_start_response import AgentAuthStartResponse as AgentAuthStartResponse -from .agent_auth_submit_response import AgentAuthSubmitResponse as AgentAuthSubmitResponse -from .agent_auth_discover_response import AgentAuthDiscoverResponse as AgentAuthDiscoverResponse diff --git a/src/kernel/types/agents/agent_auth_discover_response.py b/src/kernel/types/agents/agent_auth_discover_response.py deleted file mode 100644 index 000bdec2..00000000 --- a/src/kernel/types/agents/agent_auth_discover_response.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel -from .discovered_field import DiscoveredField - -__all__ = ["AgentAuthDiscoverResponse"] - - -class AgentAuthDiscoverResponse(BaseModel): - success: bool - """Whether discovery succeeded""" - - error_message: Optional[str] = None - """Error message if discovery failed""" - - fields: Optional[List[DiscoveredField]] = None - """Discovered form fields (present when success is true)""" - - logged_in: Optional[bool] = None - """Whether user is already logged in""" - - login_url: Optional[str] = None - """URL of the discovered login page""" - - page_title: Optional[str] = None - """Title of the login page""" diff --git a/src/kernel/types/agents/agent_auth_run_response.py b/src/kernel/types/agents/agent_auth_run_response.py deleted file mode 100644 index 0ec0b0bb..00000000 --- a/src/kernel/types/agents/agent_auth_run_response.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["AgentAuthRunResponse"] - - -class AgentAuthRunResponse(BaseModel): - app_name: str - """App name (org name at time of run creation)""" - - expires_at: datetime - """When the handoff code expires""" - - status: Literal["ACTIVE", "ENDED", "EXPIRED", "CANCELED"] - """Run status""" - - target_domain: str - """Target domain for authentication""" diff --git a/src/kernel/types/agents/agent_auth_start_response.py b/src/kernel/types/agents/agent_auth_start_response.py deleted file mode 100644 index 2855fc2d..00000000 --- a/src/kernel/types/agents/agent_auth_start_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["AgentAuthStartResponse"] - - -class AgentAuthStartResponse(BaseModel): - expires_at: datetime - """When the handoff code expires""" - - handoff_code: str - """One-time code for handoff""" - - hosted_url: str - """URL to redirect user to""" - - run_id: str - """Unique identifier for the run""" diff --git a/src/kernel/types/agents/agent_auth_submit_response.py b/src/kernel/types/agents/agent_auth_submit_response.py deleted file mode 100644 index c57002fb..00000000 --- a/src/kernel/types/agents/agent_auth_submit_response.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel -from .discovered_field import DiscoveredField - -__all__ = ["AgentAuthSubmitResponse"] - - -class AgentAuthSubmitResponse(BaseModel): - success: bool - """Whether submission succeeded""" - - additional_fields: Optional[List[DiscoveredField]] = None - """ - Additional fields needed (e.g., OTP) - present when needs_additional_auth is - true - """ - - app_name: Optional[str] = None - """App name (only present when logged_in is true)""" - - error_message: Optional[str] = None - """Error message if submission failed""" - - logged_in: Optional[bool] = None - """Whether user is now logged in""" - - needs_additional_auth: Optional[bool] = None - """Whether additional authentication fields are needed""" - - target_domain: Optional[str] = None - """Target domain (only present when logged_in is true)""" diff --git a/src/kernel/types/agents/auth/__init__.py b/src/kernel/types/agents/auth/__init__.py deleted file mode 100644 index 78a13a38..00000000 --- a/src/kernel/types/agents/auth/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .run_submit_params import RunSubmitParams as RunSubmitParams -from .run_exchange_params import RunExchangeParams as RunExchangeParams -from .run_exchange_response import RunExchangeResponse as RunExchangeResponse diff --git a/src/kernel/types/agents/auth/run_exchange_params.py b/src/kernel/types/agents/auth/run_exchange_params.py deleted file mode 100644 index 1a23b25d..00000000 --- a/src/kernel/types/agents/auth/run_exchange_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["RunExchangeParams"] - - -class RunExchangeParams(TypedDict, total=False): - code: Required[str] - """Handoff code from start endpoint""" diff --git a/src/kernel/types/agents/auth/run_exchange_response.py b/src/kernel/types/agents/auth/run_exchange_response.py deleted file mode 100644 index 347c57c3..00000000 --- a/src/kernel/types/agents/auth/run_exchange_response.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["RunExchangeResponse"] - - -class RunExchangeResponse(BaseModel): - jwt: str - """JWT token with run_id claim (30 minute TTL)""" - - run_id: str - """Run ID""" diff --git a/src/kernel/types/agents/auth/run_submit_params.py b/src/kernel/types/agents/auth/run_submit_params.py deleted file mode 100644 index efaf9ea5..00000000 --- a/src/kernel/types/agents/auth/run_submit_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Required, TypedDict - -__all__ = ["RunSubmitParams"] - - -class RunSubmitParams(TypedDict, total=False): - field_values: Required[Dict[str, str]] - """Values for the discovered login fields""" diff --git a/src/kernel/types/agents/auth_start_params.py b/src/kernel/types/agents/auth_start_params.py deleted file mode 100644 index 6e0f0c82..00000000 --- a/src/kernel/types/agents/auth_start_params.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["AuthStartParams", "Proxy"] - - -class AuthStartParams(TypedDict, total=False): - profile_name: Required[str] - """Name of the profile to use for this flow""" - - target_domain: Required[str] - """Target domain for authentication""" - - app_logo_url: str - """Optional logo URL for the application""" - - proxy: Proxy - """Optional proxy configuration""" - - -class Proxy(TypedDict, total=False): - proxy_id: str - """ID of the proxy to use""" diff --git a/src/kernel/types/agents/discovered_field.py b/src/kernel/types/agents/discovered_field.py deleted file mode 100644 index 90a4864c..00000000 --- a/src/kernel/types/agents/discovered_field.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["DiscoveredField"] - - -class DiscoveredField(BaseModel): - label: str - """Field label""" - - name: str - """Field name""" - - selector: str - """CSS selector for the field""" - - type: Literal["text", "email", "password", "tel", "number", "url", "code", "checkbox"] - """Field type""" - - placeholder: Optional[str] = None - """Field placeholder""" - - required: Optional[bool] = None - """Whether field is required""" diff --git a/src/kernel/types/browser_create_params.py b/src/kernel/types/browser_create_params.py index 1e54ce75..d1ff7907 100644 --- a/src/kernel/types/browser_create_params.py +++ b/src/kernel/types/browser_create_params.py @@ -3,15 +3,18 @@ from __future__ import annotations from typing import Iterable -from typing_extensions import Required, TypedDict +from typing_extensions import TypedDict from .browser_persistence_param import BrowserPersistenceParam +from .shared_params.browser_profile import BrowserProfile +from .shared_params.browser_viewport import BrowserViewport +from .shared_params.browser_extension import BrowserExtension -__all__ = ["BrowserCreateParams", "Extension", "Profile", "Viewport"] +__all__ = ["BrowserCreateParams"] class BrowserCreateParams(TypedDict, total=False): - extensions: Iterable[Extension] + extensions: Iterable[BrowserExtension] """List of browser extensions to load into the session. Provide each by id or name. @@ -35,7 +38,7 @@ class BrowserCreateParams(TypedDict, total=False): persistence: BrowserPersistenceParam """Optional persistence configuration for the browser session.""" - profile: Profile + profile: BrowserProfile """Profile selection for the browser session. Provide either id or name. If specified, the matching profile will be loaded @@ -64,7 +67,7 @@ class BrowserCreateParams(TypedDict, total=False): specified value. """ - viewport: Viewport + viewport: BrowserViewport """Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport @@ -75,45 +78,3 @@ class BrowserCreateParams(TypedDict, total=False): configuration exactly. Note: Higher resolutions may affect the responsiveness of live view browser """ - - -class Extension(TypedDict, total=False): - id: str - """Extension ID to load for this browser session""" - - name: str - """Extension name to load for this browser session (instead of id). - - Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. - """ - - -class Profile(TypedDict, total=False): - id: str - """Profile ID to load for this browser session""" - - name: str - """Profile name to load for this browser session (instead of id). - - Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. - """ - - save_changes: bool - """ - If true, save changes made during the session back to the profile when the - session ends. - """ - - -class Viewport(TypedDict, total=False): - height: Required[int] - """Browser window height in pixels.""" - - width: Required[int] - """Browser window width in pixels.""" - - refresh_rate: int - """Display refresh rate in Hz. - - If omitted, automatically determined from width and height. - """ diff --git a/src/kernel/types/browser_create_response.py b/src/kernel/types/browser_create_response.py index 21041eaa..0a5f33d4 100644 --- a/src/kernel/types/browser_create_response.py +++ b/src/kernel/types/browser_create_response.py @@ -6,22 +6,9 @@ from .profile import Profile from .._models import BaseModel from .browser_persistence import BrowserPersistence +from .shared.browser_viewport import BrowserViewport -__all__ = ["BrowserCreateResponse", "Viewport"] - - -class Viewport(BaseModel): - height: int - """Browser window height in pixels.""" - - width: int - """Browser window width in pixels.""" - - refresh_rate: Optional[int] = None - """Display refresh rate in Hz. - - If omitted, automatically determined from width and height. - """ +__all__ = ["BrowserCreateResponse"] class BrowserCreateResponse(BaseModel): @@ -64,7 +51,7 @@ class BrowserCreateResponse(BaseModel): proxy_id: Optional[str] = None """ID of the proxy associated with this browser session, if any.""" - viewport: Optional[Viewport] = None + viewport: Optional[BrowserViewport] = None """Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport diff --git a/src/kernel/types/browser_list_response.py b/src/kernel/types/browser_list_response.py index 74978690..d6397291 100644 --- a/src/kernel/types/browser_list_response.py +++ b/src/kernel/types/browser_list_response.py @@ -6,22 +6,9 @@ from .profile import Profile from .._models import BaseModel from .browser_persistence import BrowserPersistence +from .shared.browser_viewport import BrowserViewport -__all__ = ["BrowserListResponse", "Viewport"] - - -class Viewport(BaseModel): - height: int - """Browser window height in pixels.""" - - width: int - """Browser window width in pixels.""" - - refresh_rate: Optional[int] = None - """Display refresh rate in Hz. - - If omitted, automatically determined from width and height. - """ +__all__ = ["BrowserListResponse"] class BrowserListResponse(BaseModel): @@ -64,7 +51,7 @@ class BrowserListResponse(BaseModel): proxy_id: Optional[str] = None """ID of the proxy associated with this browser session, if any.""" - viewport: Optional[Viewport] = None + viewport: Optional[BrowserViewport] = None """Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport diff --git a/src/kernel/types/browser_pool.py b/src/kernel/types/browser_pool.py new file mode 100644 index 00000000..5fd30dca --- /dev/null +++ b/src/kernel/types/browser_pool.py @@ -0,0 +1,29 @@ +# 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_pool_request import BrowserPoolRequest + +__all__ = ["BrowserPool"] + + +class BrowserPool(BaseModel): + id: str + """Unique identifier for the browser pool""" + + acquired_count: int + """Number of browsers currently acquired from the pool""" + + available_count: int + """Number of browsers currently available in the pool""" + + browser_pool_config: BrowserPoolRequest + """Configuration used to create all browsers in this pool""" + + created_at: datetime + """Timestamp when the browser pool was created""" + + name: Optional[str] = None + """Browser pool name, if set""" diff --git a/src/kernel/types/browser_pool_acquire_params.py b/src/kernel/types/browser_pool_acquire_params.py new file mode 100644 index 00000000..d0df921a --- /dev/null +++ b/src/kernel/types/browser_pool_acquire_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BrowserPoolAcquireParams"] + + +class BrowserPoolAcquireParams(TypedDict, total=False): + acquire_timeout_seconds: int + """Maximum number of seconds to wait for a browser to be available. + + Defaults to the calculated time it would take to fill the pool at the currently + configured fill rate. + """ diff --git a/src/kernel/types/browser_pool_acquire_response.py b/src/kernel/types/browser_pool_acquire_response.py new file mode 100644 index 00000000..76ad037b --- /dev/null +++ b/src/kernel/types/browser_pool_acquire_response.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import 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__ = ["BrowserPoolAcquireResponse"] + + +class BrowserPoolAcquireResponse(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 + """Optional persistence configuration for the browser session.""" + + 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 (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 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 + """ diff --git a/src/kernel/types/browser_pool_create_params.py b/src/kernel/types/browser_pool_create_params.py new file mode 100644 index 00000000..c7f87c64 --- /dev/null +++ b/src/kernel/types/browser_pool_create_params.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .shared_params.browser_profile import BrowserProfile +from .shared_params.browser_viewport import BrowserViewport +from .shared_params.browser_extension import BrowserExtension + +__all__ = ["BrowserPoolCreateParams"] + + +class BrowserPoolCreateParams(TypedDict, total=False): + size: Required[int] + """Number of browsers to create in the pool""" + + extensions: Iterable[BrowserExtension] + """List of browser extensions to load into the session. + + Provide each by id or name. + """ + + fill_rate_per_minute: int + """Percentage of the pool to fill per minute. Defaults to 10%.""" + + headless: bool + """If true, launches the browser using a headless image. Defaults to false.""" + + kiosk_mode: bool + """ + If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + """ + + name: str + """Optional name for the browser pool. Must be unique within the organization.""" + + profile: BrowserProfile + """Profile selection for the browser session. + + Provide either id or name. If specified, the matching profile will be loaded + into the browser session. Profiles must be created beforehand. + """ + + proxy_id: str + """Optional proxy to associate to the browser session. + + Must reference a proxy belonging to the caller's org. + """ + + stealth: bool + """ + If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + """ + + timeout_seconds: int + """ + Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + """ + + viewport: BrowserViewport + """Initial browser window size in pixels with optional refresh rate. + + If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 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 + """ diff --git a/src/kernel/types/browser_pool_delete_params.py b/src/kernel/types/browser_pool_delete_params.py new file mode 100644 index 00000000..0a63c0f1 --- /dev/null +++ b/src/kernel/types/browser_pool_delete_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__ = ["BrowserPoolDeleteParams"] + + +class BrowserPoolDeleteParams(TypedDict, total=False): + force: bool + """If true, force delete even if browsers are currently leased. + + Leased browsers will be terminated. + """ diff --git a/src/kernel/types/browser_pool_list_response.py b/src/kernel/types/browser_pool_list_response.py new file mode 100644 index 00000000..a11c4de2 --- /dev/null +++ b/src/kernel/types/browser_pool_list_response.py @@ -0,0 +1,10 @@ +# 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/src/kernel/types/browser_pool_release_params.py b/src/kernel/types/browser_pool_release_params.py new file mode 100644 index 00000000..104b0b0c --- /dev/null +++ b/src/kernel/types/browser_pool_release_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BrowserPoolReleaseParams"] + + +class BrowserPoolReleaseParams(TypedDict, total=False): + session_id: Required[str] + """Browser session ID to release back to the pool""" + + reuse: bool + """Whether to reuse the browser instance or destroy it and create a new one. + + Defaults to true. + """ diff --git a/src/kernel/types/browser_pool_request.py b/src/kernel/types/browser_pool_request.py new file mode 100644 index 00000000..c25b3a55 --- /dev/null +++ b/src/kernel/types/browser_pool_request.py @@ -0,0 +1,73 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .shared.browser_profile import BrowserProfile +from .shared.browser_viewport import BrowserViewport +from .shared.browser_extension import BrowserExtension + +__all__ = ["BrowserPoolRequest"] + + +class BrowserPoolRequest(BaseModel): + size: int + """Number of browsers to create in the pool""" + + extensions: Optional[List[BrowserExtension]] = None + """List of browser extensions to load into the session. + + Provide each by id or name. + """ + + fill_rate_per_minute: Optional[int] = None + """Percentage of the pool to fill per minute. Defaults to 10%.""" + + headless: Optional[bool] = None + """If true, launches the browser using a headless image. Defaults to false.""" + + kiosk_mode: Optional[bool] = None + """ + If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + """ + + name: Optional[str] = None + """Optional name for the browser pool. Must be unique within the organization.""" + + profile: Optional[BrowserProfile] = None + """Profile selection for the browser session. + + Provide either id or name. If specified, the matching profile will be loaded + into the browser session. Profiles must be created beforehand. + """ + + proxy_id: Optional[str] = None + """Optional proxy to associate to the browser session. + + Must reference a proxy belonging to the caller's org. + """ + + stealth: Optional[bool] = None + """ + If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + """ + + timeout_seconds: Optional[int] = None + """ + Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + """ + + viewport: Optional[BrowserViewport] = None + """Initial browser window size in pixels with optional refresh rate. + + If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 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 + """ diff --git a/src/kernel/types/browser_pool_update_params.py b/src/kernel/types/browser_pool_update_params.py new file mode 100644 index 00000000..ed9a7e84 --- /dev/null +++ b/src/kernel/types/browser_pool_update_params.py @@ -0,0 +1,81 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .shared_params.browser_profile import BrowserProfile +from .shared_params.browser_viewport import BrowserViewport +from .shared_params.browser_extension import BrowserExtension + +__all__ = ["BrowserPoolUpdateParams"] + + +class BrowserPoolUpdateParams(TypedDict, total=False): + size: Required[int] + """Number of browsers to create in the pool""" + + discard_all_idle: bool + """Whether to discard all idle browsers and rebuild the pool immediately. + + Defaults to true. + """ + + extensions: Iterable[BrowserExtension] + """List of browser extensions to load into the session. + + Provide each by id or name. + """ + + fill_rate_per_minute: int + """Percentage of the pool to fill per minute. Defaults to 10%.""" + + headless: bool + """If true, launches the browser using a headless image. Defaults to false.""" + + kiosk_mode: bool + """ + If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + """ + + name: str + """Optional name for the browser pool. Must be unique within the organization.""" + + profile: BrowserProfile + """Profile selection for the browser session. + + Provide either id or name. If specified, the matching profile will be loaded + into the browser session. Profiles must be created beforehand. + """ + + proxy_id: str + """Optional proxy to associate to the browser session. + + Must reference a proxy belonging to the caller's org. + """ + + stealth: bool + """ + If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + """ + + timeout_seconds: int + """ + Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + """ + + viewport: BrowserViewport + """Initial browser window size in pixels with optional refresh rate. + + If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 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 + """ diff --git a/src/kernel/types/browser_retrieve_response.py b/src/kernel/types/browser_retrieve_response.py index 527386da..111149b3 100644 --- a/src/kernel/types/browser_retrieve_response.py +++ b/src/kernel/types/browser_retrieve_response.py @@ -6,22 +6,9 @@ from .profile import Profile from .._models import BaseModel from .browser_persistence import BrowserPersistence +from .shared.browser_viewport import BrowserViewport -__all__ = ["BrowserRetrieveResponse", "Viewport"] - - -class Viewport(BaseModel): - height: int - """Browser window height in pixels.""" - - width: int - """Browser window width in pixels.""" - - refresh_rate: Optional[int] = None - """Display refresh rate in Hz. - - If omitted, automatically determined from width and height. - """ +__all__ = ["BrowserRetrieveResponse"] class BrowserRetrieveResponse(BaseModel): @@ -64,7 +51,7 @@ class BrowserRetrieveResponse(BaseModel): proxy_id: Optional[str] = None """ID of the proxy associated with this browser session, if any.""" - viewport: Optional[Viewport] = None + viewport: Optional[BrowserViewport] = None """Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport diff --git a/src/kernel/types/shared/__init__.py b/src/kernel/types/shared/__init__.py index ea360f12..6b649199 100644 --- a/src/kernel/types/shared/__init__.py +++ b/src/kernel/types/shared/__init__.py @@ -5,4 +5,7 @@ from .error_event import ErrorEvent as ErrorEvent from .error_model import ErrorModel as ErrorModel from .error_detail import ErrorDetail as ErrorDetail +from .browser_profile import BrowserProfile as BrowserProfile from .heartbeat_event import HeartbeatEvent as HeartbeatEvent +from .browser_viewport import BrowserViewport as BrowserViewport +from .browser_extension import BrowserExtension as BrowserExtension diff --git a/src/kernel/types/shared/browser_extension.py b/src/kernel/types/shared/browser_extension.py new file mode 100644 index 00000000..7bc1a5ff --- /dev/null +++ b/src/kernel/types/shared/browser_extension.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BrowserExtension"] + + +class BrowserExtension(BaseModel): + id: Optional[str] = None + """Extension ID to load for this browser session""" + + name: Optional[str] = None + """Extension name to load for this browser session (instead of id). + + Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. + """ diff --git a/src/kernel/types/shared/browser_profile.py b/src/kernel/types/shared/browser_profile.py new file mode 100644 index 00000000..5f790ccb --- /dev/null +++ b/src/kernel/types/shared/browser_profile.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BrowserProfile"] + + +class BrowserProfile(BaseModel): + id: Optional[str] = None + """Profile ID to load for this browser session""" + + name: Optional[str] = None + """Profile name to load for this browser session (instead of id). + + Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. + """ + + save_changes: Optional[bool] = None + """ + If true, save changes made during the session back to the profile when the + session ends. + """ diff --git a/src/kernel/types/shared/browser_viewport.py b/src/kernel/types/shared/browser_viewport.py new file mode 100644 index 00000000..abffcc29 --- /dev/null +++ b/src/kernel/types/shared/browser_viewport.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BrowserViewport"] + + +class BrowserViewport(BaseModel): + height: int + """Browser window height in pixels.""" + + width: int + """Browser window width in pixels.""" + + refresh_rate: Optional[int] = None + """Display refresh rate in Hz. + + If omitted, automatically determined from width and height. + """ diff --git a/src/kernel/types/shared_params/__init__.py b/src/kernel/types/shared_params/__init__.py new file mode 100644 index 00000000..de63c649 --- /dev/null +++ b/src/kernel/types/shared_params/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .browser_profile import BrowserProfile as BrowserProfile +from .browser_viewport import BrowserViewport as BrowserViewport +from .browser_extension import BrowserExtension as BrowserExtension diff --git a/src/kernel/types/shared_params/browser_extension.py b/src/kernel/types/shared_params/browser_extension.py new file mode 100644 index 00000000..d81ac708 --- /dev/null +++ b/src/kernel/types/shared_params/browser_extension.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BrowserExtension"] + + +class BrowserExtension(TypedDict, total=False): + id: str + """Extension ID to load for this browser session""" + + name: str + """Extension name to load for this browser session (instead of id). + + Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. + """ diff --git a/src/kernel/types/shared_params/browser_profile.py b/src/kernel/types/shared_params/browser_profile.py new file mode 100644 index 00000000..e1027d22 --- /dev/null +++ b/src/kernel/types/shared_params/browser_profile.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BrowserProfile"] + + +class BrowserProfile(TypedDict, total=False): + id: str + """Profile ID to load for this browser session""" + + name: str + """Profile name to load for this browser session (instead of id). + + Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. + """ + + save_changes: bool + """ + If true, save changes made during the session back to the profile when the + session ends. + """ diff --git a/src/kernel/types/shared_params/browser_viewport.py b/src/kernel/types/shared_params/browser_viewport.py new file mode 100644 index 00000000..b7cb2f0f --- /dev/null +++ b/src/kernel/types/shared_params/browser_viewport.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BrowserViewport"] + + +class BrowserViewport(TypedDict, total=False): + height: Required[int] + """Browser window height in pixels.""" + + width: Required[int] + """Browser window width in pixels.""" + + refresh_rate: int + """Display refresh rate in Hz. + + If omitted, automatically determined from width and height. + """ diff --git a/tests/api_resources/agents/__init__.py b/tests/api_resources/agents/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/agents/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/agents/auth/__init__.py b/tests/api_resources/agents/auth/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/agents/auth/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/agents/auth/test_runs.py b/tests/api_resources/agents/auth/test_runs.py deleted file mode 100644 index 25fbdb14..00000000 --- a/tests/api_resources/agents/auth/test_runs.py +++ /dev/null @@ -1,401 +0,0 @@ -# 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.agents import AgentAuthRunResponse, AgentAuthSubmitResponse, AgentAuthDiscoverResponse -from kernel.types.agents.auth import RunExchangeResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestRuns: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_method_retrieve(self, client: Kernel) -> None: - run = client.agents.auth.runs.retrieve( - "run_id", - ) - assert_matches_type(AgentAuthRunResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_raw_response_retrieve(self, client: Kernel) -> None: - response = client.agents.auth.runs.with_raw_response.retrieve( - "run_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(AgentAuthRunResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_streaming_response_retrieve(self, client: Kernel) -> None: - with client.agents.auth.runs.with_streaming_response.retrieve( - "run_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(AgentAuthRunResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_path_params_retrieve(self, client: Kernel) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.agents.auth.runs.with_raw_response.retrieve( - "", - ) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_method_discover(self, client: Kernel) -> None: - run = client.agents.auth.runs.discover( - "run_id", - ) - assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_raw_response_discover(self, client: Kernel) -> None: - response = client.agents.auth.runs.with_raw_response.discover( - "run_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_streaming_response_discover(self, client: Kernel) -> None: - with client.agents.auth.runs.with_streaming_response.discover( - "run_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_path_params_discover(self, client: Kernel) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.agents.auth.runs.with_raw_response.discover( - "", - ) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_method_exchange(self, client: Kernel) -> None: - run = client.agents.auth.runs.exchange( - run_id="run_id", - code="otp_abc123xyz", - ) - assert_matches_type(RunExchangeResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_raw_response_exchange(self, client: Kernel) -> None: - response = client.agents.auth.runs.with_raw_response.exchange( - run_id="run_id", - code="otp_abc123xyz", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(RunExchangeResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_streaming_response_exchange(self, client: Kernel) -> None: - with client.agents.auth.runs.with_streaming_response.exchange( - run_id="run_id", - code="otp_abc123xyz", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(RunExchangeResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_path_params_exchange(self, client: Kernel) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.agents.auth.runs.with_raw_response.exchange( - run_id="", - code="otp_abc123xyz", - ) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_method_submit(self, client: Kernel) -> None: - run = client.agents.auth.runs.submit( - run_id="run_id", - field_values={ - "email": "user@example.com", - "password": "********", - }, - ) - assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_raw_response_submit(self, client: Kernel) -> None: - response = client.agents.auth.runs.with_raw_response.submit( - run_id="run_id", - field_values={ - "email": "user@example.com", - "password": "********", - }, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_streaming_response_submit(self, client: Kernel) -> None: - with client.agents.auth.runs.with_streaming_response.submit( - run_id="run_id", - field_values={ - "email": "user@example.com", - "password": "********", - }, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_path_params_submit(self, client: Kernel) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - client.agents.auth.runs.with_raw_response.submit( - run_id="", - field_values={ - "email": "user@example.com", - "password": "********", - }, - ) - - -class TestAsyncRuns: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_method_retrieve(self, async_client: AsyncKernel) -> None: - run = await async_client.agents.auth.runs.retrieve( - "run_id", - ) - assert_matches_type(AgentAuthRunResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: - response = await async_client.agents.auth.runs.with_raw_response.retrieve( - "run_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(AgentAuthRunResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: - async with async_client.agents.auth.runs.with_streaming_response.retrieve( - "run_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(AgentAuthRunResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.agents.auth.runs.with_raw_response.retrieve( - "", - ) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_method_discover(self, async_client: AsyncKernel) -> None: - run = await async_client.agents.auth.runs.discover( - "run_id", - ) - assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_raw_response_discover(self, async_client: AsyncKernel) -> None: - response = await async_client.agents.auth.runs.with_raw_response.discover( - "run_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_streaming_response_discover(self, async_client: AsyncKernel) -> None: - async with async_client.agents.auth.runs.with_streaming_response.discover( - "run_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(AgentAuthDiscoverResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_path_params_discover(self, async_client: AsyncKernel) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.agents.auth.runs.with_raw_response.discover( - "", - ) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_method_exchange(self, async_client: AsyncKernel) -> None: - run = await async_client.agents.auth.runs.exchange( - run_id="run_id", - code="otp_abc123xyz", - ) - assert_matches_type(RunExchangeResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_raw_response_exchange(self, async_client: AsyncKernel) -> None: - response = await async_client.agents.auth.runs.with_raw_response.exchange( - run_id="run_id", - code="otp_abc123xyz", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(RunExchangeResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_streaming_response_exchange(self, async_client: AsyncKernel) -> None: - async with async_client.agents.auth.runs.with_streaming_response.exchange( - run_id="run_id", - code="otp_abc123xyz", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(RunExchangeResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_path_params_exchange(self, async_client: AsyncKernel) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.agents.auth.runs.with_raw_response.exchange( - run_id="", - code="otp_abc123xyz", - ) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_method_submit(self, async_client: AsyncKernel) -> None: - run = await async_client.agents.auth.runs.submit( - run_id="run_id", - field_values={ - "email": "user@example.com", - "password": "********", - }, - ) - assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_raw_response_submit(self, async_client: AsyncKernel) -> None: - response = await async_client.agents.auth.runs.with_raw_response.submit( - run_id="run_id", - field_values={ - "email": "user@example.com", - "password": "********", - }, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_streaming_response_submit(self, async_client: AsyncKernel) -> None: - async with async_client.agents.auth.runs.with_streaming_response.submit( - run_id="run_id", - field_values={ - "email": "user@example.com", - "password": "********", - }, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(AgentAuthSubmitResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_path_params_submit(self, async_client: AsyncKernel) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): - await async_client.agents.auth.runs.with_raw_response.submit( - run_id="", - field_values={ - "email": "user@example.com", - "password": "********", - }, - ) diff --git a/tests/api_resources/agents/test_auth.py b/tests/api_resources/agents/test_auth.py deleted file mode 100644 index 32d2784f..00000000 --- a/tests/api_resources/agents/test_auth.py +++ /dev/null @@ -1,120 +0,0 @@ -# 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.agents import AgentAuthStartResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestAuth: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_method_start(self, client: Kernel) -> None: - auth = client.agents.auth.start( - profile_name="auth-abc123", - target_domain="doordash.com", - ) - assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_method_start_with_all_params(self, client: Kernel) -> None: - auth = client.agents.auth.start( - profile_name="auth-abc123", - target_domain="doordash.com", - app_logo_url="https://example.com/logo.png", - proxy={"proxy_id": "proxy_id"}, - ) - assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_raw_response_start(self, client: Kernel) -> None: - response = client.agents.auth.with_raw_response.start( - profile_name="auth-abc123", - target_domain="doordash.com", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - auth = response.parse() - assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - def test_streaming_response_start(self, client: Kernel) -> None: - with client.agents.auth.with_streaming_response.start( - profile_name="auth-abc123", - target_domain="doordash.com", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - auth = response.parse() - assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncAuth: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_method_start(self, async_client: AsyncKernel) -> None: - auth = await async_client.agents.auth.start( - profile_name="auth-abc123", - target_domain="doordash.com", - ) - assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_method_start_with_all_params(self, async_client: AsyncKernel) -> None: - auth = await async_client.agents.auth.start( - profile_name="auth-abc123", - target_domain="doordash.com", - app_logo_url="https://example.com/logo.png", - proxy={"proxy_id": "proxy_id"}, - ) - assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_raw_response_start(self, async_client: AsyncKernel) -> None: - response = await async_client.agents.auth.with_raw_response.start( - profile_name="auth-abc123", - target_domain="doordash.com", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - auth = await response.parse() - assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) - - @pytest.mark.skip(reason="Prism tests are disabled") - @parametrize - async def test_streaming_response_start(self, async_client: AsyncKernel) -> None: - async with async_client.agents.auth.with_streaming_response.start( - profile_name="auth-abc123", - target_domain="doordash.com", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - auth = await response.parse() - assert_matches_type(AgentAuthStartResponse, auth, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_browser_pools.py b/tests/api_resources/test_browser_pools.py new file mode 100644 index 00000000..6a8f164e --- /dev/null +++ b/tests/api_resources/test_browser_pools.py @@ -0,0 +1,856 @@ +# 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 import ( + BrowserPool, + BrowserPoolListResponse, + BrowserPoolAcquireResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBrowserPools: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_create(self, client: Kernel) -> None: + browser_pool = client.browser_pools.create( + size=10, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.create( + size=10, + extensions=[ + { + "id": "id", + "name": "name", + } + ], + fill_rate_per_minute=0, + headless=False, + kiosk_mode=True, + name="my-pool", + profile={ + "id": "id", + "name": "name", + "save_changes": True, + }, + proxy_id="proxy_id", + stealth=True, + timeout_seconds=60, + viewport={ + "height": 800, + "width": 1280, + "refresh_rate": 60, + }, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_create(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.create( + size=10, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.create( + size=10, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_retrieve(self, client: Kernel) -> None: + browser_pool = client.browser_pools.retrieve( + "id_or_name", + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.retrieve( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.retrieve( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_update(self, client: Kernel) -> None: + browser_pool = client.browser_pools.update( + id_or_name="id_or_name", + size=10, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_update_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.update( + id_or_name="id_or_name", + size=10, + discard_all_idle=False, + extensions=[ + { + "id": "id", + "name": "name", + } + ], + fill_rate_per_minute=0, + headless=False, + kiosk_mode=True, + name="my-pool", + profile={ + "id": "id", + "name": "name", + "save_changes": True, + }, + proxy_id="proxy_id", + stealth=True, + timeout_seconds=60, + viewport={ + "height": 800, + "width": 1280, + "refresh_rate": 60, + }, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_update(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.update( + id_or_name="id_or_name", + size=10, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_update(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.update( + id_or_name="id_or_name", + size=10, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_update(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.update( + id_or_name="", + size=10, + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_list(self, client: Kernel) -> None: + browser_pool = client.browser_pools.list() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_list(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.list() + + 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"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_delete(self, client: Kernel) -> None: + browser_pool = client.browser_pools.delete( + id_or_name="id_or_name", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_delete_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.delete( + id_or_name="id_or_name", + force=True, + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.delete( + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.delete( + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_delete(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.delete( + id_or_name="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_acquire(self, client: Kernel) -> None: + browser_pool = client.browser_pools.acquire( + id_or_name="id_or_name", + ) + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_acquire_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.acquire( + id_or_name="id_or_name", + acquire_timeout_seconds=0, + ) + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_acquire(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.acquire( + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_acquire(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.acquire( + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_acquire(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.acquire( + id_or_name="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_flush(self, client: Kernel) -> None: + browser_pool = client.browser_pools.flush( + "id_or_name", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_flush(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.flush( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_flush(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.flush( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_flush(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.flush( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_release(self, client: Kernel) -> None: + browser_pool = client.browser_pools.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_release_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + reuse=False, + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_release(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_release(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_release(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.release( + id_or_name="", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + + +class TestAsyncBrowserPools: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.create( + size=10, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.create( + size=10, + extensions=[ + { + "id": "id", + "name": "name", + } + ], + fill_rate_per_minute=0, + headless=False, + kiosk_mode=True, + name="my-pool", + profile={ + "id": "id", + "name": "name", + "save_changes": True, + }, + proxy_id="proxy_id", + stealth=True, + timeout_seconds=60, + viewport={ + "height": 800, + "width": 1280, + "refresh_rate": 60, + }, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.create( + size=10, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.create( + size=10, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.retrieve( + "id_or_name", + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.retrieve( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.retrieve( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_retrieve(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.browser_pools.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_update(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.update( + id_or_name="id_or_name", + size=10, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.update( + id_or_name="id_or_name", + size=10, + discard_all_idle=False, + extensions=[ + { + "id": "id", + "name": "name", + } + ], + fill_rate_per_minute=0, + headless=False, + kiosk_mode=True, + name="my-pool", + profile={ + "id": "id", + "name": "name", + "save_changes": True, + }, + proxy_id="proxy_id", + stealth=True, + timeout_seconds=60, + viewport={ + "height": 800, + "width": 1280, + "refresh_rate": 60, + }, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_update(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.update( + id_or_name="id_or_name", + size=10, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_update(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.update( + id_or_name="id_or_name", + size=10, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_update(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.browser_pools.with_raw_response.update( + id_or_name="", + size=10, + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @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"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.list() + + 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"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.delete( + id_or_name="id_or_name", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.delete( + id_or_name="id_or_name", + force=True, + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.delete( + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.delete( + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_delete(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.browser_pools.with_raw_response.delete( + id_or_name="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_acquire(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.acquire( + id_or_name="id_or_name", + ) + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_acquire_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.acquire( + id_or_name="id_or_name", + acquire_timeout_seconds=0, + ) + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_acquire(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.acquire( + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_acquire(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.acquire( + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_acquire(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.browser_pools.with_raw_response.acquire( + id_or_name="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_flush(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.flush( + "id_or_name", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_flush(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.flush( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_flush(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.flush( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_flush(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.browser_pools.with_raw_response.flush( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_release(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_release_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + reuse=False, + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_release(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_release(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_release(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.browser_pools.with_raw_response.release( + id_or_name="", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) From 77f575baaf6475b4095bf4bab530d19d9dd70a7b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 22:14:13 +0000 Subject: [PATCH 09/10] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c32f96db..25e77f1e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 74 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-340c8f009b71922347d4c238c8715cd752c8965abfa12cbb1ffabe35edc338a8.yml -openapi_spec_hash: efc13ab03ef89cc07333db8ab5345f31 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-3db06d1628149b5ea8303f1c72250664dfd7cb4a14ceb6102f1ae6e85c92c038.yml +openapi_spec_hash: e5b3da2da328eb26d2a70e2521744c62 config_hash: a4124701ae0a474e580d7416adbcfb00 From e16538cc64d01b8ae1dd4f512fb74abb25bbbc3f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 22:14:32 +0000 Subject: [PATCH 10/10] release: 0.21.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 20 ++++++++++++++++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0c2ecec6..86b0e83d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.20.0" + ".": "0.21.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c0c65e07..a726401d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 0.21.0 (2025-12-02) + +Full Changelog: [v0.20.0...v0.21.0](https://github.com/onkernel/kernel-python-sdk/compare/v0.20.0...v0.21.0) + +### Features + +* Browser pools sdk release ([c2d7408](https://github.com/onkernel/kernel-python-sdk/commit/c2d7408a770ddd34902986015da0bfde3477f586)) +* Mason/agent auth api ([b872928](https://github.com/onkernel/kernel-python-sdk/commit/b8729284ba804461749dad0ac4613aea3c6b3ce6)) + + +### Bug Fixes + +* ensure streams are always closed ([c82f496](https://github.com/onkernel/kernel-python-sdk/commit/c82f496ba0112b195f65da9498fb22ab65d501fb)) + + +### Chores + +* add Python 3.14 classifier and testing ([9a1e7bf](https://github.com/onkernel/kernel-python-sdk/commit/9a1e7bf9c92d64da4a151dd44cc60057c75c63bf)) +* **deps:** mypy 1.18.1 has a regression, pin to 1.17 ([038b10d](https://github.com/onkernel/kernel-python-sdk/commit/038b10d52935961c37ebb0806e9b0754b4d53a20)) + ## 0.20.0 (2025-11-19) Full Changelog: [v0.19.2...v0.20.0](https://github.com/onkernel/kernel-python-sdk/compare/v0.19.2...v0.20.0) diff --git a/pyproject.toml b/pyproject.toml index 71c4c9aa..f4bbe655 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.20.0" +version = "0.21.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 1a28cba2..1bd01d63 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.20.0" # x-release-please-version +__version__ = "0.21.0" # x-release-please-version