From e9265c4ffba59e8cfd8a02e12653b83a471aced3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 03:49:08 +0000 Subject: [PATCH 1/5] chore(internal): codegen related update --- src/kernel/_client.py | 60 ++++++++++++++++++++ src/kernel/resources/apps.py | 4 ++ src/kernel/resources/auth/auth.py | 6 ++ src/kernel/resources/auth/connections.py | 4 ++ src/kernel/resources/browser_pools.py | 4 ++ src/kernel/resources/browsers/browsers.py | 34 +++++++++++ src/kernel/resources/browsers/fs/fs.py | 10 ++++ src/kernel/resources/browsers/fs/watch.py | 4 ++ src/kernel/resources/browsers/logs.py | 4 ++ src/kernel/resources/browsers/playwright.py | 4 ++ src/kernel/resources/browsers/process.py | 4 ++ src/kernel/resources/browsers/replays.py | 4 ++ src/kernel/resources/credential_providers.py | 4 ++ src/kernel/resources/credentials.py | 4 ++ src/kernel/resources/deployments.py | 4 ++ src/kernel/resources/extensions.py | 4 ++ src/kernel/resources/invocations.py | 4 ++ src/kernel/resources/profiles.py | 4 ++ src/kernel/resources/proxies.py | 4 ++ 19 files changed, 170 insertions(+) diff --git a/src/kernel/_client.py b/src/kernel/_client.py index df7fd255..84fc48dd 100644 --- a/src/kernel/_client.py +++ b/src/kernel/_client.py @@ -155,30 +155,35 @@ def __init__( @cached_property def deployments(self) -> DeploymentsResource: + """Create and manage app deployments and stream deployment events.""" from .resources.deployments import DeploymentsResource return DeploymentsResource(self) @cached_property def apps(self) -> AppsResource: + """List applications and versions.""" from .resources.apps import AppsResource return AppsResource(self) @cached_property def invocations(self) -> InvocationsResource: + """Invoke actions and stream or query invocation status and events.""" from .resources.invocations import InvocationsResource return InvocationsResource(self) @cached_property def browsers(self) -> BrowsersResource: + """Create and manage browser sessions.""" from .resources.browsers import BrowsersResource return BrowsersResource(self) @cached_property def profiles(self) -> ProfilesResource: + """Create, list, retrieve, and delete browser profiles.""" from .resources.profiles import ProfilesResource return ProfilesResource(self) @@ -191,30 +196,35 @@ def auth(self) -> AuthResource: @cached_property def proxies(self) -> ProxiesResource: + """Create and manage proxy configurations for routing browser traffic.""" from .resources.proxies import ProxiesResource return ProxiesResource(self) @cached_property def extensions(self) -> ExtensionsResource: + """Create, list, retrieve, and delete browser extensions.""" from .resources.extensions import ExtensionsResource return ExtensionsResource(self) @cached_property def browser_pools(self) -> BrowserPoolsResource: + """Create and manage browser pools for acquiring and releasing browsers.""" from .resources.browser_pools import BrowserPoolsResource return BrowserPoolsResource(self) @cached_property def credentials(self) -> CredentialsResource: + """Create and manage credentials for authentication.""" from .resources.credentials import CredentialsResource return CredentialsResource(self) @cached_property def credential_providers(self) -> CredentialProvidersResource: + """Configure external credential providers like 1Password.""" from .resources.credential_providers import CredentialProvidersResource return CredentialProvidersResource(self) @@ -415,30 +425,35 @@ def __init__( @cached_property def deployments(self) -> AsyncDeploymentsResource: + """Create and manage app deployments and stream deployment events.""" from .resources.deployments import AsyncDeploymentsResource return AsyncDeploymentsResource(self) @cached_property def apps(self) -> AsyncAppsResource: + """List applications and versions.""" from .resources.apps import AsyncAppsResource return AsyncAppsResource(self) @cached_property def invocations(self) -> AsyncInvocationsResource: + """Invoke actions and stream or query invocation status and events.""" from .resources.invocations import AsyncInvocationsResource return AsyncInvocationsResource(self) @cached_property def browsers(self) -> AsyncBrowsersResource: + """Create and manage browser sessions.""" from .resources.browsers import AsyncBrowsersResource return AsyncBrowsersResource(self) @cached_property def profiles(self) -> AsyncProfilesResource: + """Create, list, retrieve, and delete browser profiles.""" from .resources.profiles import AsyncProfilesResource return AsyncProfilesResource(self) @@ -451,30 +466,35 @@ def auth(self) -> AsyncAuthResource: @cached_property def proxies(self) -> AsyncProxiesResource: + """Create and manage proxy configurations for routing browser traffic.""" from .resources.proxies import AsyncProxiesResource return AsyncProxiesResource(self) @cached_property def extensions(self) -> AsyncExtensionsResource: + """Create, list, retrieve, and delete browser extensions.""" from .resources.extensions import AsyncExtensionsResource return AsyncExtensionsResource(self) @cached_property def browser_pools(self) -> AsyncBrowserPoolsResource: + """Create and manage browser pools for acquiring and releasing browsers.""" from .resources.browser_pools import AsyncBrowserPoolsResource return AsyncBrowserPoolsResource(self) @cached_property def credentials(self) -> AsyncCredentialsResource: + """Create and manage credentials for authentication.""" from .resources.credentials import AsyncCredentialsResource return AsyncCredentialsResource(self) @cached_property def credential_providers(self) -> AsyncCredentialProvidersResource: + """Configure external credential providers like 1Password.""" from .resources.credential_providers import AsyncCredentialProvidersResource return AsyncCredentialProvidersResource(self) @@ -602,30 +622,35 @@ def __init__(self, client: Kernel) -> None: @cached_property def deployments(self) -> deployments.DeploymentsResourceWithRawResponse: + """Create and manage app deployments and stream deployment events.""" from .resources.deployments import DeploymentsResourceWithRawResponse return DeploymentsResourceWithRawResponse(self._client.deployments) @cached_property def apps(self) -> apps.AppsResourceWithRawResponse: + """List applications and versions.""" from .resources.apps import AppsResourceWithRawResponse return AppsResourceWithRawResponse(self._client.apps) @cached_property def invocations(self) -> invocations.InvocationsResourceWithRawResponse: + """Invoke actions and stream or query invocation status and events.""" from .resources.invocations import InvocationsResourceWithRawResponse return InvocationsResourceWithRawResponse(self._client.invocations) @cached_property def browsers(self) -> browsers.BrowsersResourceWithRawResponse: + """Create and manage browser sessions.""" from .resources.browsers import BrowsersResourceWithRawResponse return BrowsersResourceWithRawResponse(self._client.browsers) @cached_property def profiles(self) -> profiles.ProfilesResourceWithRawResponse: + """Create, list, retrieve, and delete browser profiles.""" from .resources.profiles import ProfilesResourceWithRawResponse return ProfilesResourceWithRawResponse(self._client.profiles) @@ -638,30 +663,35 @@ def auth(self) -> auth.AuthResourceWithRawResponse: @cached_property def proxies(self) -> proxies.ProxiesResourceWithRawResponse: + """Create and manage proxy configurations for routing browser traffic.""" from .resources.proxies import ProxiesResourceWithRawResponse return ProxiesResourceWithRawResponse(self._client.proxies) @cached_property def extensions(self) -> extensions.ExtensionsResourceWithRawResponse: + """Create, list, retrieve, and delete browser extensions.""" from .resources.extensions import ExtensionsResourceWithRawResponse return ExtensionsResourceWithRawResponse(self._client.extensions) @cached_property def browser_pools(self) -> browser_pools.BrowserPoolsResourceWithRawResponse: + """Create and manage browser pools for acquiring and releasing browsers.""" from .resources.browser_pools import BrowserPoolsResourceWithRawResponse return BrowserPoolsResourceWithRawResponse(self._client.browser_pools) @cached_property def credentials(self) -> credentials.CredentialsResourceWithRawResponse: + """Create and manage credentials for authentication.""" from .resources.credentials import CredentialsResourceWithRawResponse return CredentialsResourceWithRawResponse(self._client.credentials) @cached_property def credential_providers(self) -> credential_providers.CredentialProvidersResourceWithRawResponse: + """Configure external credential providers like 1Password.""" from .resources.credential_providers import CredentialProvidersResourceWithRawResponse return CredentialProvidersResourceWithRawResponse(self._client.credential_providers) @@ -675,30 +705,35 @@ def __init__(self, client: AsyncKernel) -> None: @cached_property def deployments(self) -> deployments.AsyncDeploymentsResourceWithRawResponse: + """Create and manage app deployments and stream deployment events.""" from .resources.deployments import AsyncDeploymentsResourceWithRawResponse return AsyncDeploymentsResourceWithRawResponse(self._client.deployments) @cached_property def apps(self) -> apps.AsyncAppsResourceWithRawResponse: + """List applications and versions.""" from .resources.apps import AsyncAppsResourceWithRawResponse return AsyncAppsResourceWithRawResponse(self._client.apps) @cached_property def invocations(self) -> invocations.AsyncInvocationsResourceWithRawResponse: + """Invoke actions and stream or query invocation status and events.""" from .resources.invocations import AsyncInvocationsResourceWithRawResponse return AsyncInvocationsResourceWithRawResponse(self._client.invocations) @cached_property def browsers(self) -> browsers.AsyncBrowsersResourceWithRawResponse: + """Create and manage browser sessions.""" from .resources.browsers import AsyncBrowsersResourceWithRawResponse return AsyncBrowsersResourceWithRawResponse(self._client.browsers) @cached_property def profiles(self) -> profiles.AsyncProfilesResourceWithRawResponse: + """Create, list, retrieve, and delete browser profiles.""" from .resources.profiles import AsyncProfilesResourceWithRawResponse return AsyncProfilesResourceWithRawResponse(self._client.profiles) @@ -711,30 +746,35 @@ def auth(self) -> auth.AsyncAuthResourceWithRawResponse: @cached_property def proxies(self) -> proxies.AsyncProxiesResourceWithRawResponse: + """Create and manage proxy configurations for routing browser traffic.""" from .resources.proxies import AsyncProxiesResourceWithRawResponse return AsyncProxiesResourceWithRawResponse(self._client.proxies) @cached_property def extensions(self) -> extensions.AsyncExtensionsResourceWithRawResponse: + """Create, list, retrieve, and delete browser extensions.""" from .resources.extensions import AsyncExtensionsResourceWithRawResponse return AsyncExtensionsResourceWithRawResponse(self._client.extensions) @cached_property def browser_pools(self) -> browser_pools.AsyncBrowserPoolsResourceWithRawResponse: + """Create and manage browser pools for acquiring and releasing browsers.""" from .resources.browser_pools import AsyncBrowserPoolsResourceWithRawResponse return AsyncBrowserPoolsResourceWithRawResponse(self._client.browser_pools) @cached_property def credentials(self) -> credentials.AsyncCredentialsResourceWithRawResponse: + """Create and manage credentials for authentication.""" from .resources.credentials import AsyncCredentialsResourceWithRawResponse return AsyncCredentialsResourceWithRawResponse(self._client.credentials) @cached_property def credential_providers(self) -> credential_providers.AsyncCredentialProvidersResourceWithRawResponse: + """Configure external credential providers like 1Password.""" from .resources.credential_providers import AsyncCredentialProvidersResourceWithRawResponse return AsyncCredentialProvidersResourceWithRawResponse(self._client.credential_providers) @@ -748,30 +788,35 @@ def __init__(self, client: Kernel) -> None: @cached_property def deployments(self) -> deployments.DeploymentsResourceWithStreamingResponse: + """Create and manage app deployments and stream deployment events.""" from .resources.deployments import DeploymentsResourceWithStreamingResponse return DeploymentsResourceWithStreamingResponse(self._client.deployments) @cached_property def apps(self) -> apps.AppsResourceWithStreamingResponse: + """List applications and versions.""" from .resources.apps import AppsResourceWithStreamingResponse return AppsResourceWithStreamingResponse(self._client.apps) @cached_property def invocations(self) -> invocations.InvocationsResourceWithStreamingResponse: + """Invoke actions and stream or query invocation status and events.""" from .resources.invocations import InvocationsResourceWithStreamingResponse return InvocationsResourceWithStreamingResponse(self._client.invocations) @cached_property def browsers(self) -> browsers.BrowsersResourceWithStreamingResponse: + """Create and manage browser sessions.""" from .resources.browsers import BrowsersResourceWithStreamingResponse return BrowsersResourceWithStreamingResponse(self._client.browsers) @cached_property def profiles(self) -> profiles.ProfilesResourceWithStreamingResponse: + """Create, list, retrieve, and delete browser profiles.""" from .resources.profiles import ProfilesResourceWithStreamingResponse return ProfilesResourceWithStreamingResponse(self._client.profiles) @@ -784,30 +829,35 @@ def auth(self) -> auth.AuthResourceWithStreamingResponse: @cached_property def proxies(self) -> proxies.ProxiesResourceWithStreamingResponse: + """Create and manage proxy configurations for routing browser traffic.""" from .resources.proxies import ProxiesResourceWithStreamingResponse return ProxiesResourceWithStreamingResponse(self._client.proxies) @cached_property def extensions(self) -> extensions.ExtensionsResourceWithStreamingResponse: + """Create, list, retrieve, and delete browser extensions.""" from .resources.extensions import ExtensionsResourceWithStreamingResponse return ExtensionsResourceWithStreamingResponse(self._client.extensions) @cached_property def browser_pools(self) -> browser_pools.BrowserPoolsResourceWithStreamingResponse: + """Create and manage browser pools for acquiring and releasing browsers.""" from .resources.browser_pools import BrowserPoolsResourceWithStreamingResponse return BrowserPoolsResourceWithStreamingResponse(self._client.browser_pools) @cached_property def credentials(self) -> credentials.CredentialsResourceWithStreamingResponse: + """Create and manage credentials for authentication.""" from .resources.credentials import CredentialsResourceWithStreamingResponse return CredentialsResourceWithStreamingResponse(self._client.credentials) @cached_property def credential_providers(self) -> credential_providers.CredentialProvidersResourceWithStreamingResponse: + """Configure external credential providers like 1Password.""" from .resources.credential_providers import CredentialProvidersResourceWithStreamingResponse return CredentialProvidersResourceWithStreamingResponse(self._client.credential_providers) @@ -821,30 +871,35 @@ def __init__(self, client: AsyncKernel) -> None: @cached_property def deployments(self) -> deployments.AsyncDeploymentsResourceWithStreamingResponse: + """Create and manage app deployments and stream deployment events.""" from .resources.deployments import AsyncDeploymentsResourceWithStreamingResponse return AsyncDeploymentsResourceWithStreamingResponse(self._client.deployments) @cached_property def apps(self) -> apps.AsyncAppsResourceWithStreamingResponse: + """List applications and versions.""" from .resources.apps import AsyncAppsResourceWithStreamingResponse return AsyncAppsResourceWithStreamingResponse(self._client.apps) @cached_property def invocations(self) -> invocations.AsyncInvocationsResourceWithStreamingResponse: + """Invoke actions and stream or query invocation status and events.""" from .resources.invocations import AsyncInvocationsResourceWithStreamingResponse return AsyncInvocationsResourceWithStreamingResponse(self._client.invocations) @cached_property def browsers(self) -> browsers.AsyncBrowsersResourceWithStreamingResponse: + """Create and manage browser sessions.""" from .resources.browsers import AsyncBrowsersResourceWithStreamingResponse return AsyncBrowsersResourceWithStreamingResponse(self._client.browsers) @cached_property def profiles(self) -> profiles.AsyncProfilesResourceWithStreamingResponse: + """Create, list, retrieve, and delete browser profiles.""" from .resources.profiles import AsyncProfilesResourceWithStreamingResponse return AsyncProfilesResourceWithStreamingResponse(self._client.profiles) @@ -857,30 +912,35 @@ def auth(self) -> auth.AsyncAuthResourceWithStreamingResponse: @cached_property def proxies(self) -> proxies.AsyncProxiesResourceWithStreamingResponse: + """Create and manage proxy configurations for routing browser traffic.""" from .resources.proxies import AsyncProxiesResourceWithStreamingResponse return AsyncProxiesResourceWithStreamingResponse(self._client.proxies) @cached_property def extensions(self) -> extensions.AsyncExtensionsResourceWithStreamingResponse: + """Create, list, retrieve, and delete browser extensions.""" from .resources.extensions import AsyncExtensionsResourceWithStreamingResponse return AsyncExtensionsResourceWithStreamingResponse(self._client.extensions) @cached_property def browser_pools(self) -> browser_pools.AsyncBrowserPoolsResourceWithStreamingResponse: + """Create and manage browser pools for acquiring and releasing browsers.""" from .resources.browser_pools import AsyncBrowserPoolsResourceWithStreamingResponse return AsyncBrowserPoolsResourceWithStreamingResponse(self._client.browser_pools) @cached_property def credentials(self) -> credentials.AsyncCredentialsResourceWithStreamingResponse: + """Create and manage credentials for authentication.""" from .resources.credentials import AsyncCredentialsResourceWithStreamingResponse return AsyncCredentialsResourceWithStreamingResponse(self._client.credentials) @cached_property def credential_providers(self) -> credential_providers.AsyncCredentialProvidersResourceWithStreamingResponse: + """Configure external credential providers like 1Password.""" from .resources.credential_providers import AsyncCredentialProvidersResourceWithStreamingResponse return AsyncCredentialProvidersResourceWithStreamingResponse(self._client.credential_providers) diff --git a/src/kernel/resources/apps.py b/src/kernel/resources/apps.py index 7383c29e..4290f3f6 100644 --- a/src/kernel/resources/apps.py +++ b/src/kernel/resources/apps.py @@ -23,6 +23,8 @@ class AppsResource(SyncAPIResource): + """List applications and versions.""" + @cached_property def with_raw_response(self) -> AppsResourceWithRawResponse: """ @@ -104,6 +106,8 @@ def list( class AsyncAppsResource(AsyncAPIResource): + """List applications and versions.""" + @cached_property def with_raw_response(self) -> AsyncAppsResourceWithRawResponse: """ diff --git a/src/kernel/resources/auth/auth.py b/src/kernel/resources/auth/auth.py index b5980e6b..f8744950 100644 --- a/src/kernel/resources/auth/auth.py +++ b/src/kernel/resources/auth/auth.py @@ -19,6 +19,7 @@ class AuthResource(SyncAPIResource): @cached_property def connections(self) -> ConnectionsResource: + """Create and manage auth connections for automated credential capture and login.""" return ConnectionsResource(self._client) @cached_property @@ -44,6 +45,7 @@ def with_streaming_response(self) -> AuthResourceWithStreamingResponse: class AsyncAuthResource(AsyncAPIResource): @cached_property def connections(self) -> AsyncConnectionsResource: + """Create and manage auth connections for automated credential capture and login.""" return AsyncConnectionsResource(self._client) @cached_property @@ -72,6 +74,7 @@ def __init__(self, auth: AuthResource) -> None: @cached_property def connections(self) -> ConnectionsResourceWithRawResponse: + """Create and manage auth connections for automated credential capture and login.""" return ConnectionsResourceWithRawResponse(self._auth.connections) @@ -81,6 +84,7 @@ def __init__(self, auth: AsyncAuthResource) -> None: @cached_property def connections(self) -> AsyncConnectionsResourceWithRawResponse: + """Create and manage auth connections for automated credential capture and login.""" return AsyncConnectionsResourceWithRawResponse(self._auth.connections) @@ -90,6 +94,7 @@ def __init__(self, auth: AuthResource) -> None: @cached_property def connections(self) -> ConnectionsResourceWithStreamingResponse: + """Create and manage auth connections for automated credential capture and login.""" return ConnectionsResourceWithStreamingResponse(self._auth.connections) @@ -99,4 +104,5 @@ def __init__(self, auth: AsyncAuthResource) -> None: @cached_property def connections(self) -> AsyncConnectionsResourceWithStreamingResponse: + """Create and manage auth connections for automated credential capture and login.""" return AsyncConnectionsResourceWithStreamingResponse(self._auth.connections) diff --git a/src/kernel/resources/auth/connections.py b/src/kernel/resources/auth/connections.py index 93b6cf6a..fed66797 100644 --- a/src/kernel/resources/auth/connections.py +++ b/src/kernel/resources/auth/connections.py @@ -34,6 +34,8 @@ class ConnectionsResource(SyncAPIResource): + """Create and manage auth connections for automated credential capture and login.""" + @cached_property def with_raw_response(self) -> ConnectionsResourceWithRawResponse: """ @@ -413,6 +415,8 @@ def submit( class AsyncConnectionsResource(AsyncAPIResource): + """Create and manage auth connections for automated credential capture and login.""" + @cached_property def with_raw_response(self) -> AsyncConnectionsResourceWithRawResponse: """ diff --git a/src/kernel/resources/browser_pools.py b/src/kernel/resources/browser_pools.py index 9177d678..a5b6e59a 100644 --- a/src/kernel/resources/browser_pools.py +++ b/src/kernel/resources/browser_pools.py @@ -35,6 +35,8 @@ class BrowserPoolsResource(SyncAPIResource): + """Create and manage browser pools for acquiring and releasing browsers.""" + @cached_property def with_raw_response(self) -> BrowserPoolsResourceWithRawResponse: """ @@ -473,6 +475,8 @@ def release( class AsyncBrowserPoolsResource(AsyncAPIResource): + """Create and manage browser pools for acquiring and releasing browsers.""" + @cached_property def with_raw_response(self) -> AsyncBrowserPoolsResourceWithRawResponse: """ diff --git a/src/kernel/resources/browsers/browsers.py b/src/kernel/resources/browsers/browsers.py index 59cecda1..32855ee8 100644 --- a/src/kernel/resources/browsers/browsers.py +++ b/src/kernel/resources/browsers/browsers.py @@ -89,20 +89,26 @@ class BrowsersResource(SyncAPIResource): + """Create and manage browser sessions.""" + @cached_property def replays(self) -> ReplaysResource: + """Record and manage browser session video replays.""" return ReplaysResource(self._client) @cached_property def fs(self) -> FsResource: + """Read, write, and manage files on the browser instance.""" return FsResource(self._client) @cached_property def process(self) -> ProcessResource: + """Execute and manage processes on the browser instance.""" return ProcessResource(self._client) @cached_property def logs(self) -> LogsResource: + """Stream logs from the browser instance.""" return LogsResource(self._client) @cached_property @@ -111,6 +117,7 @@ def computer(self) -> ComputerResource: @cached_property def playwright(self) -> PlaywrightResource: + """Execute Playwright code against the browser instance.""" return PlaywrightResource(self._client) @cached_property @@ -509,20 +516,26 @@ def load_extensions( class AsyncBrowsersResource(AsyncAPIResource): + """Create and manage browser sessions.""" + @cached_property def replays(self) -> AsyncReplaysResource: + """Record and manage browser session video replays.""" return AsyncReplaysResource(self._client) @cached_property def fs(self) -> AsyncFsResource: + """Read, write, and manage files on the browser instance.""" return AsyncFsResource(self._client) @cached_property def process(self) -> AsyncProcessResource: + """Execute and manage processes on the browser instance.""" return AsyncProcessResource(self._client) @cached_property def logs(self) -> AsyncLogsResource: + """Stream logs from the browser instance.""" return AsyncLogsResource(self._client) @cached_property @@ -531,6 +544,7 @@ def computer(self) -> AsyncComputerResource: @cached_property def playwright(self) -> AsyncPlaywrightResource: + """Execute Playwright code against the browser instance.""" return AsyncPlaywrightResource(self._client) @cached_property @@ -960,18 +974,22 @@ def __init__(self, browsers: BrowsersResource) -> None: @cached_property def replays(self) -> ReplaysResourceWithRawResponse: + """Record and manage browser session video replays.""" return ReplaysResourceWithRawResponse(self._browsers.replays) @cached_property def fs(self) -> FsResourceWithRawResponse: + """Read, write, and manage files on the browser instance.""" return FsResourceWithRawResponse(self._browsers.fs) @cached_property def process(self) -> ProcessResourceWithRawResponse: + """Execute and manage processes on the browser instance.""" return ProcessResourceWithRawResponse(self._browsers.process) @cached_property def logs(self) -> LogsResourceWithRawResponse: + """Stream logs from the browser instance.""" return LogsResourceWithRawResponse(self._browsers.logs) @cached_property @@ -980,6 +998,7 @@ def computer(self) -> ComputerResourceWithRawResponse: @cached_property def playwright(self) -> PlaywrightResourceWithRawResponse: + """Execute Playwright code against the browser instance.""" return PlaywrightResourceWithRawResponse(self._browsers.playwright) @@ -1013,18 +1032,22 @@ def __init__(self, browsers: AsyncBrowsersResource) -> None: @cached_property def replays(self) -> AsyncReplaysResourceWithRawResponse: + """Record and manage browser session video replays.""" return AsyncReplaysResourceWithRawResponse(self._browsers.replays) @cached_property def fs(self) -> AsyncFsResourceWithRawResponse: + """Read, write, and manage files on the browser instance.""" return AsyncFsResourceWithRawResponse(self._browsers.fs) @cached_property def process(self) -> AsyncProcessResourceWithRawResponse: + """Execute and manage processes on the browser instance.""" return AsyncProcessResourceWithRawResponse(self._browsers.process) @cached_property def logs(self) -> AsyncLogsResourceWithRawResponse: + """Stream logs from the browser instance.""" return AsyncLogsResourceWithRawResponse(self._browsers.logs) @cached_property @@ -1033,6 +1056,7 @@ def computer(self) -> AsyncComputerResourceWithRawResponse: @cached_property def playwright(self) -> AsyncPlaywrightResourceWithRawResponse: + """Execute Playwright code against the browser instance.""" return AsyncPlaywrightResourceWithRawResponse(self._browsers.playwright) @@ -1066,18 +1090,22 @@ def __init__(self, browsers: BrowsersResource) -> None: @cached_property def replays(self) -> ReplaysResourceWithStreamingResponse: + """Record and manage browser session video replays.""" return ReplaysResourceWithStreamingResponse(self._browsers.replays) @cached_property def fs(self) -> FsResourceWithStreamingResponse: + """Read, write, and manage files on the browser instance.""" return FsResourceWithStreamingResponse(self._browsers.fs) @cached_property def process(self) -> ProcessResourceWithStreamingResponse: + """Execute and manage processes on the browser instance.""" return ProcessResourceWithStreamingResponse(self._browsers.process) @cached_property def logs(self) -> LogsResourceWithStreamingResponse: + """Stream logs from the browser instance.""" return LogsResourceWithStreamingResponse(self._browsers.logs) @cached_property @@ -1086,6 +1114,7 @@ def computer(self) -> ComputerResourceWithStreamingResponse: @cached_property def playwright(self) -> PlaywrightResourceWithStreamingResponse: + """Execute Playwright code against the browser instance.""" return PlaywrightResourceWithStreamingResponse(self._browsers.playwright) @@ -1119,18 +1148,22 @@ def __init__(self, browsers: AsyncBrowsersResource) -> None: @cached_property def replays(self) -> AsyncReplaysResourceWithStreamingResponse: + """Record and manage browser session video replays.""" return AsyncReplaysResourceWithStreamingResponse(self._browsers.replays) @cached_property def fs(self) -> AsyncFsResourceWithStreamingResponse: + """Read, write, and manage files on the browser instance.""" return AsyncFsResourceWithStreamingResponse(self._browsers.fs) @cached_property def process(self) -> AsyncProcessResourceWithStreamingResponse: + """Execute and manage processes on the browser instance.""" return AsyncProcessResourceWithStreamingResponse(self._browsers.process) @cached_property def logs(self) -> AsyncLogsResourceWithStreamingResponse: + """Stream logs from the browser instance.""" return AsyncLogsResourceWithStreamingResponse(self._browsers.logs) @cached_property @@ -1139,4 +1172,5 @@ def computer(self) -> AsyncComputerResourceWithStreamingResponse: @cached_property def playwright(self) -> AsyncPlaywrightResourceWithStreamingResponse: + """Execute Playwright code against the browser instance.""" return AsyncPlaywrightResourceWithStreamingResponse(self._browsers.playwright) diff --git a/src/kernel/resources/browsers/fs/fs.py b/src/kernel/resources/browsers/fs/fs.py index 3501a2a6..1bd16afb 100644 --- a/src/kernel/resources/browsers/fs/fs.py +++ b/src/kernel/resources/browsers/fs/fs.py @@ -69,8 +69,11 @@ class FsResource(SyncAPIResource): + """Read, write, and manage files on the browser instance.""" + @cached_property def watch(self) -> WatchResource: + """Read, write, and manage files on the browser instance.""" return WatchResource(self._client) @cached_property @@ -628,8 +631,11 @@ def write_file( class AsyncFsResource(AsyncAPIResource): + """Read, write, and manage files on the browser instance.""" + @cached_property def watch(self) -> AsyncWatchResource: + """Read, write, and manage files on the browser instance.""" return AsyncWatchResource(self._client) @cached_property @@ -1231,6 +1237,7 @@ def __init__(self, fs: FsResource) -> None: @cached_property def watch(self) -> WatchResourceWithRawResponse: + """Read, write, and manage files on the browser instance.""" return WatchResourceWithRawResponse(self._fs.watch) @@ -1279,6 +1286,7 @@ def __init__(self, fs: AsyncFsResource) -> None: @cached_property def watch(self) -> AsyncWatchResourceWithRawResponse: + """Read, write, and manage files on the browser instance.""" return AsyncWatchResourceWithRawResponse(self._fs.watch) @@ -1327,6 +1335,7 @@ def __init__(self, fs: FsResource) -> None: @cached_property def watch(self) -> WatchResourceWithStreamingResponse: + """Read, write, and manage files on the browser instance.""" return WatchResourceWithStreamingResponse(self._fs.watch) @@ -1375,4 +1384,5 @@ def __init__(self, fs: AsyncFsResource) -> None: @cached_property def watch(self) -> AsyncWatchResourceWithStreamingResponse: + """Read, write, and manage files on the browser instance.""" return AsyncWatchResourceWithStreamingResponse(self._fs.watch) diff --git a/src/kernel/resources/browsers/fs/watch.py b/src/kernel/resources/browsers/fs/watch.py index 2a5c1e30..ca438673 100644 --- a/src/kernel/resources/browsers/fs/watch.py +++ b/src/kernel/resources/browsers/fs/watch.py @@ -24,6 +24,8 @@ class WatchResource(SyncAPIResource): + """Read, write, and manage files on the browser instance.""" + @cached_property def with_raw_response(self) -> WatchResourceWithRawResponse: """ @@ -167,6 +169,8 @@ def stop( class AsyncWatchResource(AsyncAPIResource): + """Read, write, and manage files on the browser instance.""" + @cached_property def with_raw_response(self) -> AsyncWatchResourceWithRawResponse: """ diff --git a/src/kernel/resources/browsers/logs.py b/src/kernel/resources/browsers/logs.py index ab97a70d..01328551 100644 --- a/src/kernel/resources/browsers/logs.py +++ b/src/kernel/resources/browsers/logs.py @@ -25,6 +25,8 @@ class LogsResource(SyncAPIResource): + """Stream logs from the browser instance.""" + @cached_property def with_raw_response(self) -> LogsResourceWithRawResponse: """ @@ -102,6 +104,8 @@ def stream( class AsyncLogsResource(AsyncAPIResource): + """Stream logs from the browser instance.""" + @cached_property def with_raw_response(self) -> AsyncLogsResourceWithRawResponse: """ diff --git a/src/kernel/resources/browsers/playwright.py b/src/kernel/resources/browsers/playwright.py index 5c47e3bf..6979a9de 100644 --- a/src/kernel/resources/browsers/playwright.py +++ b/src/kernel/resources/browsers/playwright.py @@ -22,6 +22,8 @@ class PlaywrightResource(SyncAPIResource): + """Execute Playwright code against the browser instance.""" + @cached_property def with_raw_response(self) -> PlaywrightResourceWithRawResponse: """ @@ -96,6 +98,8 @@ def execute( class AsyncPlaywrightResource(AsyncAPIResource): + """Execute Playwright code against the browser instance.""" + @cached_property def with_raw_response(self) -> AsyncPlaywrightResourceWithRawResponse: """ diff --git a/src/kernel/resources/browsers/process.py b/src/kernel/resources/browsers/process.py index 9932f40c..86752a5e 100644 --- a/src/kernel/resources/browsers/process.py +++ b/src/kernel/resources/browsers/process.py @@ -38,6 +38,8 @@ class ProcessResource(SyncAPIResource): + """Execute and manage processes on the browser instance.""" + @cached_property def with_raw_response(self) -> ProcessResourceWithRawResponse: """ @@ -407,6 +409,8 @@ def stdout_stream( class AsyncProcessResource(AsyncAPIResource): + """Execute and manage processes on the browser instance.""" + @cached_property def with_raw_response(self) -> AsyncProcessResourceWithRawResponse: """ diff --git a/src/kernel/resources/browsers/replays.py b/src/kernel/resources/browsers/replays.py index 8a1d1996..743a6668 100644 --- a/src/kernel/resources/browsers/replays.py +++ b/src/kernel/resources/browsers/replays.py @@ -31,6 +31,8 @@ class ReplaysResource(SyncAPIResource): + """Record and manage browser session video replays.""" + @cached_property def with_raw_response(self) -> ReplaysResourceWithRawResponse: """ @@ -205,6 +207,8 @@ def stop( class AsyncReplaysResource(AsyncAPIResource): + """Record and manage browser session video replays.""" + @cached_property def with_raw_response(self) -> AsyncReplaysResourceWithRawResponse: """ diff --git a/src/kernel/resources/credential_providers.py b/src/kernel/resources/credential_providers.py index 8df7d55c..c7ad4b00 100644 --- a/src/kernel/resources/credential_providers.py +++ b/src/kernel/resources/credential_providers.py @@ -27,6 +27,8 @@ class CredentialProvidersResource(SyncAPIResource): + """Configure external credential providers like 1Password.""" + @cached_property def with_raw_response(self) -> CredentialProvidersResourceWithRawResponse: """ @@ -311,6 +313,8 @@ def test( class AsyncCredentialProvidersResource(AsyncAPIResource): + """Configure external credential providers like 1Password.""" + @cached_property def with_raw_response(self) -> AsyncCredentialProvidersResourceWithRawResponse: """ diff --git a/src/kernel/resources/credentials.py b/src/kernel/resources/credentials.py index 30e72e84..000c7675 100644 --- a/src/kernel/resources/credentials.py +++ b/src/kernel/resources/credentials.py @@ -26,6 +26,8 @@ class CredentialsResource(SyncAPIResource): + """Create and manage credentials for authentication.""" + @cached_property def with_raw_response(self) -> CredentialsResourceWithRawResponse: """ @@ -321,6 +323,8 @@ def totp_code( class AsyncCredentialsResource(AsyncAPIResource): + """Create and manage credentials for authentication.""" + @cached_property def with_raw_response(self) -> AsyncCredentialsResourceWithRawResponse: """ diff --git a/src/kernel/resources/deployments.py b/src/kernel/resources/deployments.py index 753eb8b1..b6a72d2d 100644 --- a/src/kernel/resources/deployments.py +++ b/src/kernel/resources/deployments.py @@ -30,6 +30,8 @@ class DeploymentsResource(SyncAPIResource): + """Create and manage app deployments and stream deployment events.""" + @cached_property def with_raw_response(self) -> DeploymentsResourceWithRawResponse: """ @@ -293,6 +295,8 @@ def follow( class AsyncDeploymentsResource(AsyncAPIResource): + """Create and manage app deployments and stream deployment events.""" + @cached_property def with_raw_response(self) -> AsyncDeploymentsResourceWithRawResponse: """ diff --git a/src/kernel/resources/extensions.py b/src/kernel/resources/extensions.py index 69497b1f..ffdef29e 100644 --- a/src/kernel/resources/extensions.py +++ b/src/kernel/resources/extensions.py @@ -34,6 +34,8 @@ class ExtensionsResource(SyncAPIResource): + """Create, list, retrieve, and delete browser extensions.""" + @cached_property def with_raw_response(self) -> ExtensionsResourceWithRawResponse: """ @@ -241,6 +243,8 @@ def upload( class AsyncExtensionsResource(AsyncAPIResource): + """Create, list, retrieve, and delete browser extensions.""" + @cached_property def with_raw_response(self) -> AsyncExtensionsResourceWithRawResponse: """ diff --git a/src/kernel/resources/invocations.py b/src/kernel/resources/invocations.py index 3194026d..25be409f 100644 --- a/src/kernel/resources/invocations.py +++ b/src/kernel/resources/invocations.py @@ -32,6 +32,8 @@ class InvocationsResource(SyncAPIResource): + """Invoke actions and stream or query invocation status and events.""" + @cached_property def with_raw_response(self) -> InvocationsResourceWithRawResponse: """ @@ -383,6 +385,8 @@ def list_browsers( class AsyncInvocationsResource(AsyncAPIResource): + """Invoke actions and stream or query invocation status and events.""" + @cached_property def with_raw_response(self) -> AsyncInvocationsResourceWithRawResponse: """ diff --git a/src/kernel/resources/profiles.py b/src/kernel/resources/profiles.py index e9b124b5..f75569f2 100644 --- a/src/kernel/resources/profiles.py +++ b/src/kernel/resources/profiles.py @@ -31,6 +31,8 @@ class ProfilesResource(SyncAPIResource): + """Create, list, retrieve, and delete browser profiles.""" + @cached_property def with_raw_response(self) -> ProfilesResourceWithRawResponse: """ @@ -241,6 +243,8 @@ def download( class AsyncProfilesResource(AsyncAPIResource): + """Create, list, retrieve, and delete browser profiles.""" + @cached_property def with_raw_response(self) -> AsyncProfilesResourceWithRawResponse: """ diff --git a/src/kernel/resources/proxies.py b/src/kernel/resources/proxies.py index d42f7b04..0c2508c0 100644 --- a/src/kernel/resources/proxies.py +++ b/src/kernel/resources/proxies.py @@ -27,6 +27,8 @@ class ProxiesResource(SyncAPIResource): + """Create and manage proxy configurations for routing browser traffic.""" + @cached_property def with_raw_response(self) -> ProxiesResourceWithRawResponse: """ @@ -224,6 +226,8 @@ def check( class AsyncProxiesResource(AsyncAPIResource): + """Create and manage proxy configurations for routing browser traffic.""" + @cached_property def with_raw_response(self) -> AsyncProxiesResourceWithRawResponse: """ From 077a61c3c3f287eaddd3f90cf4f5cf04dc7baf39 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:32:31 +0000 Subject: [PATCH 2/5] feat: [kernel-1028] add api clipboard support --- .stats.yml | 8 +- api.md | 3 + src/kernel/resources/browsers/computer.py | 170 +++++++++++++++++ src/kernel/types/browsers/__init__.py | 2 + .../computer_read_clipboard_response.py | 10 + .../computer_write_clipboard_params.py | 12 ++ tests/api_resources/browsers/test_computer.py | 177 ++++++++++++++++++ 7 files changed, 378 insertions(+), 4 deletions(-) create mode 100644 src/kernel/types/browsers/computer_read_clipboard_response.py create mode 100644 src/kernel/types/browsers/computer_write_clipboard_params.py diff --git a/.stats.yml b/.stats.yml index d4eead98..a08c103b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 101 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-a935c8aae21f8ddb83ea5e289034df12cbde88d432fa2b287629814bb3f58bb6.yml -openapi_spec_hash: df3189b9728372f01662a19c060bcbc5 -config_hash: 81f143f4bee47ae7b0b8357551babadf +configured_endpoints: 103 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-f05b888046776a18dbffc1264a27c0256839d132066ef5f6e09ccf1bc505a8f7.yml +openapi_spec_hash: 646fce3982d3efbdb38004b0e4ac4d17 +config_hash: cff4d43372b6fa66b64e2d4150f6aa76 diff --git a/api.md b/api.md index 511ab51f..cce73021 100644 --- a/api.md +++ b/api.md @@ -192,6 +192,7 @@ Types: ```python from kernel.types.browsers import ( ComputerGetMousePositionResponse, + ComputerReadClipboardResponse, ComputerSetCursorVisibilityResponse, ) ``` @@ -205,9 +206,11 @@ Methods: - client.browsers.computer.get_mouse_position(id) -> ComputerGetMousePositionResponse - client.browsers.computer.move_mouse(id, \*\*params) -> None - client.browsers.computer.press_key(id, \*\*params) -> None +- client.browsers.computer.read_clipboard(id) -> ComputerReadClipboardResponse - client.browsers.computer.scroll(id, \*\*params) -> None - client.browsers.computer.set_cursor_visibility(id, \*\*params) -> ComputerSetCursorVisibilityResponse - client.browsers.computer.type_text(id, \*\*params) -> None +- client.browsers.computer.write_clipboard(id, \*\*params) -> None ## Playwright diff --git a/src/kernel/resources/browsers/computer.py b/src/kernel/resources/browsers/computer.py index 933767f0..cc61834b 100644 --- a/src/kernel/resources/browsers/computer.py +++ b/src/kernel/resources/browsers/computer.py @@ -34,9 +34,11 @@ computer_drag_mouse_params, computer_move_mouse_params, computer_click_mouse_params, + computer_write_clipboard_params, computer_capture_screenshot_params, computer_set_cursor_visibility_params, ) +from ...types.browsers.computer_read_clipboard_response import ComputerReadClipboardResponse from ...types.browsers.computer_get_mouse_position_response import ComputerGetMousePositionResponse from ...types.browsers.computer_set_cursor_visibility_response import ComputerSetCursorVisibilityResponse @@ -408,6 +410,39 @@ def press_key( cast_to=NoneType, ) + def read_clipboard( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ComputerReadClipboardResponse: + """ + Read text from the clipboard on the browser instance + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + f"/browsers/{id}/computer/clipboard/read", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ComputerReadClipboardResponse, + ) + def scroll( self, id: str, @@ -553,6 +588,44 @@ def type_text( cast_to=NoneType, ) + def write_clipboard( + self, + id: str, + *, + text: 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: + """ + Write text to the clipboard on the browser instance + + Args: + text: Text to write to the system clipboard + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/browsers/{id}/computer/clipboard/write", + body=maybe_transform({"text": text}, computer_write_clipboard_params.ComputerWriteClipboardParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + class AsyncComputerResource(AsyncAPIResource): @cached_property @@ -919,6 +992,39 @@ async def press_key( cast_to=NoneType, ) + async def read_clipboard( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ComputerReadClipboardResponse: + """ + Read text from the clipboard on the browser instance + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + f"/browsers/{id}/computer/clipboard/read", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ComputerReadClipboardResponse, + ) + async def scroll( self, id: str, @@ -1064,6 +1170,46 @@ async def type_text( cast_to=NoneType, ) + async def write_clipboard( + self, + id: str, + *, + text: 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: + """ + Write text to the clipboard on the browser instance + + Args: + text: Text to write to the system clipboard + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/browsers/{id}/computer/clipboard/write", + body=await async_maybe_transform( + {"text": text}, computer_write_clipboard_params.ComputerWriteClipboardParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + class ComputerResourceWithRawResponse: def __init__(self, computer: ComputerResource) -> None: @@ -1091,6 +1237,9 @@ def __init__(self, computer: ComputerResource) -> None: self.press_key = to_raw_response_wrapper( computer.press_key, ) + self.read_clipboard = to_raw_response_wrapper( + computer.read_clipboard, + ) self.scroll = to_raw_response_wrapper( computer.scroll, ) @@ -1100,6 +1249,9 @@ def __init__(self, computer: ComputerResource) -> None: self.type_text = to_raw_response_wrapper( computer.type_text, ) + self.write_clipboard = to_raw_response_wrapper( + computer.write_clipboard, + ) class AsyncComputerResourceWithRawResponse: @@ -1128,6 +1280,9 @@ def __init__(self, computer: AsyncComputerResource) -> None: self.press_key = async_to_raw_response_wrapper( computer.press_key, ) + self.read_clipboard = async_to_raw_response_wrapper( + computer.read_clipboard, + ) self.scroll = async_to_raw_response_wrapper( computer.scroll, ) @@ -1137,6 +1292,9 @@ def __init__(self, computer: AsyncComputerResource) -> None: self.type_text = async_to_raw_response_wrapper( computer.type_text, ) + self.write_clipboard = async_to_raw_response_wrapper( + computer.write_clipboard, + ) class ComputerResourceWithStreamingResponse: @@ -1165,6 +1323,9 @@ def __init__(self, computer: ComputerResource) -> None: self.press_key = to_streamed_response_wrapper( computer.press_key, ) + self.read_clipboard = to_streamed_response_wrapper( + computer.read_clipboard, + ) self.scroll = to_streamed_response_wrapper( computer.scroll, ) @@ -1174,6 +1335,9 @@ def __init__(self, computer: ComputerResource) -> None: self.type_text = to_streamed_response_wrapper( computer.type_text, ) + self.write_clipboard = to_streamed_response_wrapper( + computer.write_clipboard, + ) class AsyncComputerResourceWithStreamingResponse: @@ -1202,6 +1366,9 @@ def __init__(self, computer: AsyncComputerResource) -> None: self.press_key = async_to_streamed_response_wrapper( computer.press_key, ) + self.read_clipboard = async_to_streamed_response_wrapper( + computer.read_clipboard, + ) self.scroll = async_to_streamed_response_wrapper( computer.scroll, ) @@ -1211,3 +1378,6 @@ def __init__(self, computer: AsyncComputerResource) -> None: self.type_text = async_to_streamed_response_wrapper( computer.type_text, ) + self.write_clipboard = async_to_streamed_response_wrapper( + computer.write_clipboard, + ) diff --git a/src/kernel/types/browsers/__init__.py b/src/kernel/types/browsers/__init__.py index 3daee051..1e47205d 100644 --- a/src/kernel/types/browsers/__init__.py +++ b/src/kernel/types/browsers/__init__.py @@ -41,6 +41,8 @@ from .playwright_execute_response import PlaywrightExecuteResponse as PlaywrightExecuteResponse from .f_set_file_permissions_params import FSetFilePermissionsParams as FSetFilePermissionsParams from .process_stdout_stream_response import ProcessStdoutStreamResponse as ProcessStdoutStreamResponse +from .computer_write_clipboard_params import ComputerWriteClipboardParams as ComputerWriteClipboardParams +from .computer_read_clipboard_response import ComputerReadClipboardResponse as ComputerReadClipboardResponse from .computer_capture_screenshot_params import ComputerCaptureScreenshotParams as ComputerCaptureScreenshotParams from .computer_get_mouse_position_response import ComputerGetMousePositionResponse as ComputerGetMousePositionResponse from .computer_set_cursor_visibility_params import ( diff --git a/src/kernel/types/browsers/computer_read_clipboard_response.py b/src/kernel/types/browsers/computer_read_clipboard_response.py new file mode 100644 index 00000000..e5210090 --- /dev/null +++ b/src/kernel/types/browsers/computer_read_clipboard_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["ComputerReadClipboardResponse"] + + +class ComputerReadClipboardResponse(BaseModel): + text: str + """Current clipboard text content""" diff --git a/src/kernel/types/browsers/computer_write_clipboard_params.py b/src/kernel/types/browsers/computer_write_clipboard_params.py new file mode 100644 index 00000000..81f7b095 --- /dev/null +++ b/src/kernel/types/browsers/computer_write_clipboard_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__ = ["ComputerWriteClipboardParams"] + + +class ComputerWriteClipboardParams(TypedDict, total=False): + text: Required[str] + """Text to write to the system clipboard""" diff --git a/tests/api_resources/browsers/test_computer.py b/tests/api_resources/browsers/test_computer.py index 091fc91d..32a4ca9c 100644 --- a/tests/api_resources/browsers/test_computer.py +++ b/tests/api_resources/browsers/test_computer.py @@ -18,6 +18,7 @@ AsyncStreamedBinaryAPIResponse, ) from kernel.types.browsers import ( + ComputerReadClipboardResponse, ComputerGetMousePositionResponse, ComputerSetCursorVisibilityResponse, ) @@ -426,6 +427,48 @@ def test_path_params_press_key(self, client: Kernel) -> None: keys=["string"], ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_read_clipboard(self, client: Kernel) -> None: + computer = client.browsers.computer.read_clipboard( + "id", + ) + assert_matches_type(ComputerReadClipboardResponse, computer, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_read_clipboard(self, client: Kernel) -> None: + response = client.browsers.computer.with_raw_response.read_clipboard( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + computer = response.parse() + assert_matches_type(ComputerReadClipboardResponse, computer, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_read_clipboard(self, client: Kernel) -> None: + with client.browsers.computer.with_streaming_response.read_clipboard( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + computer = response.parse() + assert_matches_type(ComputerReadClipboardResponse, computer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_read_clipboard(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.browsers.computer.with_raw_response.read_clipboard( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_scroll(self, client: Kernel) -> None: @@ -591,6 +634,52 @@ def test_path_params_type_text(self, client: Kernel) -> None: text="text", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_write_clipboard(self, client: Kernel) -> None: + computer = client.browsers.computer.write_clipboard( + id="id", + text="text", + ) + assert computer is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_write_clipboard(self, client: Kernel) -> None: + response = client.browsers.computer.with_raw_response.write_clipboard( + id="id", + text="text", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + computer = response.parse() + assert computer is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_write_clipboard(self, client: Kernel) -> None: + with client.browsers.computer.with_streaming_response.write_clipboard( + id="id", + text="text", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + computer = response.parse() + assert computer is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_write_clipboard(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.browsers.computer.with_raw_response.write_clipboard( + id="", + text="text", + ) + class TestAsyncComputer: parametrize = pytest.mark.parametrize( @@ -999,6 +1088,48 @@ async def test_path_params_press_key(self, async_client: AsyncKernel) -> None: keys=["string"], ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_read_clipboard(self, async_client: AsyncKernel) -> None: + computer = await async_client.browsers.computer.read_clipboard( + "id", + ) + assert_matches_type(ComputerReadClipboardResponse, computer, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_read_clipboard(self, async_client: AsyncKernel) -> None: + response = await async_client.browsers.computer.with_raw_response.read_clipboard( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + computer = await response.parse() + assert_matches_type(ComputerReadClipboardResponse, computer, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_read_clipboard(self, async_client: AsyncKernel) -> None: + async with async_client.browsers.computer.with_streaming_response.read_clipboard( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + computer = await response.parse() + assert_matches_type(ComputerReadClipboardResponse, computer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_read_clipboard(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.browsers.computer.with_raw_response.read_clipboard( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_scroll(self, async_client: AsyncKernel) -> None: @@ -1163,3 +1294,49 @@ async def test_path_params_type_text(self, async_client: AsyncKernel) -> None: id="", text="text", ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_write_clipboard(self, async_client: AsyncKernel) -> None: + computer = await async_client.browsers.computer.write_clipboard( + id="id", + text="text", + ) + assert computer is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_write_clipboard(self, async_client: AsyncKernel) -> None: + response = await async_client.browsers.computer.with_raw_response.write_clipboard( + id="id", + text="text", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + computer = await response.parse() + assert computer is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_write_clipboard(self, async_client: AsyncKernel) -> None: + async with async_client.browsers.computer.with_streaming_response.write_clipboard( + id="id", + text="text", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + computer = await response.parse() + assert computer is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_write_clipboard(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.browsers.computer.with_raw_response.write_clipboard( + id="", + text="text", + ) From 8b3db281a64cafba5dac7effdc264f30a94c38ea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 22:37:29 +0000 Subject: [PATCH 3/5] feat: expose smooth mouse movement via public API --- .stats.yml | 4 ++-- src/kernel/resources/browsers/computer.py | 18 ++++++++++++++++++ .../types/browsers/computer_batch_params.py | 9 +++++++++ .../browsers/computer_move_mouse_params.py | 9 +++++++++ tests/api_resources/browsers/test_computer.py | 4 ++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a08c103b..d2f972b9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 103 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-f05b888046776a18dbffc1264a27c0256839d132066ef5f6e09ccf1bc505a8f7.yml -openapi_spec_hash: 646fce3982d3efbdb38004b0e4ac4d17 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2ba004ce5444b5f8abe3bcf66fd7c6da394bc964e8b2bf197576841135a48046.yml +openapi_spec_hash: f156ea2ae35e4d148704c6e4ce051239 config_hash: cff4d43372b6fa66b64e2d4150f6aa76 diff --git a/src/kernel/resources/browsers/computer.py b/src/kernel/resources/browsers/computer.py index cc61834b..1357c1e8 100644 --- a/src/kernel/resources/browsers/computer.py +++ b/src/kernel/resources/browsers/computer.py @@ -310,7 +310,9 @@ def move_mouse( *, x: int, y: int, + duration_ms: int | Omit = omit, hold_keys: SequenceNotStr[str] | Omit = omit, + smooth: 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, @@ -326,8 +328,13 @@ def move_mouse( y: Y coordinate to move the cursor to + duration_ms: Target total duration in milliseconds for the mouse movement when smooth=true. + Omit for automatic timing based on distance. + hold_keys: Modifier keys to hold during the move + smooth: Use human-like Bezier curve path instead of instant mouse movement. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -345,7 +352,9 @@ def move_mouse( { "x": x, "y": y, + "duration_ms": duration_ms, "hold_keys": hold_keys, + "smooth": smooth, }, computer_move_mouse_params.ComputerMoveMouseParams, ), @@ -892,7 +901,9 @@ async def move_mouse( *, x: int, y: int, + duration_ms: int | Omit = omit, hold_keys: SequenceNotStr[str] | Omit = omit, + smooth: 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, @@ -908,8 +919,13 @@ async def move_mouse( y: Y coordinate to move the cursor to + duration_ms: Target total duration in milliseconds for the mouse movement when smooth=true. + Omit for automatic timing based on distance. + hold_keys: Modifier keys to hold during the move + smooth: Use human-like Bezier curve path instead of instant mouse movement. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -927,7 +943,9 @@ async def move_mouse( { "x": x, "y": y, + "duration_ms": duration_ms, "hold_keys": hold_keys, + "smooth": smooth, }, computer_move_mouse_params.ComputerMoveMouseParams, ), diff --git a/src/kernel/types/browsers/computer_batch_params.py b/src/kernel/types/browsers/computer_batch_params.py index 601cd2b9..9aca7244 100644 --- a/src/kernel/types/browsers/computer_batch_params.py +++ b/src/kernel/types/browsers/computer_batch_params.py @@ -79,9 +79,18 @@ class ActionMoveMouse(TypedDict, total=False): y: Required[int] """Y coordinate to move the cursor to""" + duration_ms: int + """Target total duration in milliseconds for the mouse movement when smooth=true. + + Omit for automatic timing based on distance. + """ + hold_keys: SequenceNotStr[str] """Modifier keys to hold during the move""" + smooth: bool + """Use human-like Bezier curve path instead of instant mouse movement.""" + class ActionPressKey(TypedDict, total=False): keys: Required[SequenceNotStr[str]] diff --git a/src/kernel/types/browsers/computer_move_mouse_params.py b/src/kernel/types/browsers/computer_move_mouse_params.py index 1769e074..3a4f99e5 100644 --- a/src/kernel/types/browsers/computer_move_mouse_params.py +++ b/src/kernel/types/browsers/computer_move_mouse_params.py @@ -16,5 +16,14 @@ class ComputerMoveMouseParams(TypedDict, total=False): y: Required[int] """Y coordinate to move the cursor to""" + duration_ms: int + """Target total duration in milliseconds for the mouse movement when smooth=true. + + Omit for automatic timing based on distance. + """ + hold_keys: SequenceNotStr[str] """Modifier keys to hold during the move""" + + smooth: bool + """Use human-like Bezier curve path instead of instant mouse movement.""" diff --git a/tests/api_resources/browsers/test_computer.py b/tests/api_resources/browsers/test_computer.py index 32a4ca9c..09960bfc 100644 --- a/tests/api_resources/browsers/test_computer.py +++ b/tests/api_resources/browsers/test_computer.py @@ -326,7 +326,9 @@ def test_method_move_mouse_with_all_params(self, client: Kernel) -> None: id="id", x=0, y=0, + duration_ms=50, hold_keys=["string"], + smooth=True, ) assert computer is None @@ -987,7 +989,9 @@ async def test_method_move_mouse_with_all_params(self, async_client: AsyncKernel id="id", x=0, y=0, + duration_ms=50, hold_keys=["string"], + smooth=True, ) assert computer is None From c4b8c62622354859847c13234ee9f54611f4175f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:43:01 +0000 Subject: [PATCH 4/5] feat: add force flag to viewport resize to bypass live view/recording check --- .stats.yml | 4 ++-- src/kernel/resources/browsers/browsers.py | 4 ++-- src/kernel/types/browser_update_params.py | 16 ++++++++++++++-- tests/api_resources/test_browsers.py | 2 ++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index d2f972b9..e1ce185b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 103 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2ba004ce5444b5f8abe3bcf66fd7c6da394bc964e8b2bf197576841135a48046.yml -openapi_spec_hash: f156ea2ae35e4d148704c6e4ce051239 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-ef24d4bf172555bcbe8e3b432c644a25a1c6afd99c958a2eda8c3b1ea9568113.yml +openapi_spec_hash: b603c5a983e837928fa7d1100ed64fc9 config_hash: cff4d43372b6fa66b64e2d4150f6aa76 diff --git a/src/kernel/resources/browsers/browsers.py b/src/kernel/resources/browsers/browsers.py index 32855ee8..235da236 100644 --- a/src/kernel/resources/browsers/browsers.py +++ b/src/kernel/resources/browsers/browsers.py @@ -284,7 +284,7 @@ def update( *, profile: BrowserProfile | Omit = omit, proxy_id: Optional[str] | Omit = omit, - viewport: BrowserViewport | Omit = omit, + viewport: browser_update_params.Viewport | 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, @@ -711,7 +711,7 @@ async def update( *, profile: BrowserProfile | Omit = omit, proxy_id: Optional[str] | Omit = omit, - viewport: BrowserViewport | Omit = omit, + viewport: browser_update_params.Viewport | 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/browser_update_params.py b/src/kernel/types/browser_update_params.py index 917cd7da..5c211948 100644 --- a/src/kernel/types/browser_update_params.py +++ b/src/kernel/types/browser_update_params.py @@ -8,7 +8,7 @@ from .shared_params.browser_profile import BrowserProfile from .shared_params.browser_viewport import BrowserViewport -__all__ = ["BrowserUpdateParams"] +__all__ = ["BrowserUpdateParams", "Viewport"] class BrowserUpdateParams(TypedDict, total=False): @@ -24,5 +24,17 @@ class BrowserUpdateParams(TypedDict, total=False): Omit to leave unchanged, set to empty string to remove proxy. """ - viewport: BrowserViewport + viewport: Viewport """Viewport configuration to apply to the browser session.""" + + +class Viewport(BrowserViewport, total=False): + """Viewport configuration to apply to the browser session.""" + + force: bool + """ + If true, allow the viewport change even when a live view or recording/replay is + active. Active recordings will be gracefully stopped and restarted at the new + resolution as separate segments. If false (default), the resize is refused when + a live view or recording is active. + """ diff --git a/tests/api_resources/test_browsers.py b/tests/api_resources/test_browsers.py index 2addbb87..1e612ff2 100644 --- a/tests/api_resources/test_browsers.py +++ b/tests/api_resources/test_browsers.py @@ -158,6 +158,7 @@ def test_method_update_with_all_params(self, client: Kernel) -> None: "height": 800, "width": 1280, "refresh_rate": 60, + "force": True, }, ) assert_matches_type(BrowserUpdateResponse, browser, path=["response"]) @@ -521,6 +522,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> "height": 800, "width": 1280, "refresh_rate": 60, + "force": True, }, ) assert_matches_type(BrowserUpdateResponse, browser, path=["response"]) From 474dcda4ebe5a117ec930a4b92d258d4487c42fa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:47:13 +0000 Subject: [PATCH 5/5] release: 0.42.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 52afe059..dc28bb87 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.42.0" + ".": "0.42.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d5c4d947..338a74af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 0.42.1 (2026-03-05) + +Full Changelog: [v0.42.0...v0.42.1](https://github.com/kernel/kernel-python-sdk/compare/v0.42.0...v0.42.1) + +### Features + +* [kernel-1028] add api clipboard support ([077a61c](https://github.com/kernel/kernel-python-sdk/commit/077a61c3c3f287eaddd3f90cf4f5cf04dc7baf39)) +* add force flag to viewport resize to bypass live view/recording check ([c4b8c62](https://github.com/kernel/kernel-python-sdk/commit/c4b8c62622354859847c13234ee9f54611f4175f)) +* expose smooth mouse movement via public API ([8b3db28](https://github.com/kernel/kernel-python-sdk/commit/8b3db281a64cafba5dac7effdc264f30a94c38ea)) + + +### Chores + +* **internal:** codegen related update ([e9265c4](https://github.com/kernel/kernel-python-sdk/commit/e9265c4ffba59e8cfd8a02e12653b83a471aced3)) + ## 0.42.0 (2026-03-02) Full Changelog: [v0.41.0...v0.42.0](https://github.com/kernel/kernel-python-sdk/compare/v0.41.0...v0.42.0) diff --git a/pyproject.toml b/pyproject.toml index 968ba8d8..225ad6fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.42.0" +version = "0.42.1" 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 7a26ebd7..e6149c73 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.42.0" # x-release-please-version +__version__ = "0.42.1" # x-release-please-version