Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.106.0"
".": "0.107.0"
}
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
configured_endpoints: 164
configured_endpoints: 165
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## [0.107.0](https://github.com/kernel/kernel-python-sdk/compare/v0.106.0...v0.107.0) (2026-09-16)


### Features

* Classify unevaluable config registry targets ([12ced86](https://github.com/kernel/kernel-python-sdk/commit/12ced8647c23aa43c625b288ed48c7cdf8da9125))
* Expose persistent Browser REPL through the API ([755dba5](https://github.com/kernel/kernel-python-sdk/commit/755dba5d1273ef9083ffbc4bc7f4adf30aea2fe9))
* Return Link spend request errors directly ([82d9f84](https://github.com/kernel/kernel-python-sdk/commit/82d9f8400a761a37debabeb79e6e5d8bec2cbe32))

## 0.106.0 (2026-09-16)

Full Changelog: [v0.104.0...v0.106.0](https://github.com/kernel/kernel-python-sdk/compare/v0.104.0...v0.106.0)
Expand Down
6 changes: 6 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ from kernel.types import (
BrowserProxy,
BrowserProxyConfig,
BrowserProxyMode,
BrowserReplContent,
BrowserReplImageContent,
BrowserReplRequest,
BrowserReplResult,
BrowserReplTextContent,
BrowserUsage,
Profile,
Tags,
Expand All @@ -145,6 +150,7 @@ Methods:
- <code title="post /browsers/{id_or_name}/curl">client.browsers.<a href="./src/kernel/resources/browsers/browsers.py">curl</a>(id_or_name, \*\*<a href="src/kernel/types/browser_curl_params.py">params</a>) -> <a href="./src/kernel/types/browser_curl_response.py">BrowserCurlResponse</a></code>
- <code title="delete /browsers/{id_or_name}">client.browsers.<a href="./src/kernel/resources/browsers/browsers.py">delete_by_id</a>(id_or_name) -> None</code>
- <code title="post /browsers/{id_or_name}/extensions">client.browsers.<a href="./src/kernel/resources/browsers/browsers.py">load_extensions</a>(id_or_name, \*\*<a href="src/kernel/types/browser_load_extensions_params.py">params</a>) -> None</code>
- <code title="post /browsers/{id_or_name}/repl">client.browsers.<a href="./src/kernel/resources/browsers/browsers.py">repl</a>(id_or_name, \*\*<a href="src/kernel/types/browser_repl_params.py">params</a>) -> <a href="./src/kernel/types/browser_repl_result.py">BrowserReplResult</a></code>

## Telemetry

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "kernel"
version = "0.106.0"
version = "0.107.0"
description = "The official Python library for the kernel API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
6 changes: 0 additions & 6 deletions src/kernel/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ def config_registry(self) -> ConfigRegistryResource:

@cached_property
def browsers(self) -> BrowsersResource:
"""Create and manage browser sessions."""
from .resources.browsers import BrowsersResource

return BrowsersResource(self)
Expand Down Expand Up @@ -652,7 +651,6 @@ def config_registry(self) -> AsyncConfigRegistryResource:

@cached_property
def browsers(self) -> AsyncBrowsersResource:
"""Create and manage browser sessions."""
from .resources.browsers import AsyncBrowsersResource

return AsyncBrowsersResource(self)
Expand Down Expand Up @@ -959,7 +957,6 @@ def config_registry(self) -> config_registry.ConfigRegistryResourceWithRawRespon

@cached_property
def browsers(self) -> browsers.BrowsersResourceWithRawResponse:
"""Create and manage browser sessions."""
from .resources.browsers import BrowsersResourceWithRawResponse

return BrowsersResourceWithRawResponse(self._client.browsers)
Expand Down Expand Up @@ -1098,7 +1095,6 @@ def config_registry(self) -> config_registry.AsyncConfigRegistryResourceWithRawR

@cached_property
def browsers(self) -> browsers.AsyncBrowsersResourceWithRawResponse:
"""Create and manage browser sessions."""
from .resources.browsers import AsyncBrowsersResourceWithRawResponse

return AsyncBrowsersResourceWithRawResponse(self._client.browsers)
Expand Down Expand Up @@ -1237,7 +1233,6 @@ def config_registry(self) -> config_registry.ConfigRegistryResourceWithStreaming

@cached_property
def browsers(self) -> browsers.BrowsersResourceWithStreamingResponse:
"""Create and manage browser sessions."""
from .resources.browsers import BrowsersResourceWithStreamingResponse

return BrowsersResourceWithStreamingResponse(self._client.browsers)
Expand Down Expand Up @@ -1376,7 +1371,6 @@ def config_registry(self) -> config_registry.AsyncConfigRegistryResourceWithStre

@cached_property
def browsers(self) -> browsers.AsyncBrowsersResourceWithStreamingResponse:
"""Create and manage browser sessions."""
from .resources.browsers import AsyncBrowsersResourceWithStreamingResponse

return AsyncBrowsersResourceWithStreamingResponse(self._client.browsers)
Expand Down
2 changes: 1 addition & 1 deletion src/kernel/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "kernel"
__version__ = "0.106.0" # x-release-please-version
__version__ = "0.107.0" # x-release-please-version
152 changes: 148 additions & 4 deletions src/kernel/resources/browsers/browsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
BrowserMemoryRequest,
browser_curl_params,
browser_list_params,
browser_repl_params,
browser_create_params,
browser_update_params,
browser_retrieve_params,
Expand Down Expand Up @@ -95,6 +96,7 @@
from ...pagination import SyncOffsetPagination, AsyncOffsetPagination
from ..._base_client import AsyncPaginator, make_request_options
from ...types.tags_param import TagsParam
from ...types.browser_repl_result import BrowserReplResult
from ...types.browser_curl_response import BrowserCurlResponse
from ...types.browser_list_response import BrowserListResponse
from ...types.vault_reference_param import VaultReferenceParam
Expand All @@ -118,8 +120,6 @@


class BrowsersResource(SyncAPIResource):
"""Create and manage browser sessions."""

@cached_property
def telemetry(self) -> TelemetryResource:
"""
Expand Down Expand Up @@ -753,10 +753,75 @@ def load_extensions(
cast_to=NoneType,
)

def repl(
self,
id_or_name: str,
*,
code: str,
reset: bool | Omit = omit,
timeout_sec: 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,
) -> BrowserReplResult:
"""
Execute JavaScript in a persistent Node.js runtime inside the browser VM.
Top-level bindings, closures, mutations, and dynamically imported modules
persist across calls until the REPL is reset or replaced. Start with
`repl.help()` to list available methods, or call `repl.help("click")` for
detailed help.

Expression values are ignored. Emit ordered text or image output with
`repl.write(...)`, console methods, or `repl.emitImage(...)`. The runtime also
exposes browser-control helpers, WebMCP, Patchright, Playwright, and raw CDP.

Executions are serialized. A timeout, crash, OOM, or protocol failure terminates
the REPL and changes its `repl_id`. This is unrestricted code execution inside
the browser VM and is not sandboxed.

Args:
code: JavaScript evaluated in a persistent Node.js runtime. Top-level bindings persist
until the browser VM's API process exits, the REPL is reset, or the REPL is
terminated after a crash or timeout. Static top-level imports are unsupported;
use dynamic `import()`. Expression values are ignored; emit output with
`repl.write(...)`, console methods, or `repl.emitImage(...)`. May be empty only
when `reset` is true.

reset: Terminate the current REPL, start a fresh one, and then evaluate code.

timeout_sec: Maximum execution time in seconds. Default is 60.

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(
path_template("/browsers/{id_or_name}/repl", id_or_name=id_or_name),
body=maybe_transform(
{
"code": code,
"reset": reset,
"timeout_sec": timeout_sec,
},
browser_repl_params.BrowserReplParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=BrowserReplResult,
)

class AsyncBrowsersResource(AsyncAPIResource):
"""Create and manage browser sessions."""

class AsyncBrowsersResource(AsyncAPIResource):
@cached_property
def telemetry(self) -> AsyncTelemetryResource:
"""
Expand Down Expand Up @@ -1390,6 +1455,73 @@ async def load_extensions(
cast_to=NoneType,
)

async def repl(
self,
id_or_name: str,
*,
code: str,
reset: bool | Omit = omit,
timeout_sec: 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,
) -> BrowserReplResult:
"""
Execute JavaScript in a persistent Node.js runtime inside the browser VM.
Top-level bindings, closures, mutations, and dynamically imported modules
persist across calls until the REPL is reset or replaced. Start with
`repl.help()` to list available methods, or call `repl.help("click")` for
detailed help.

Expression values are ignored. Emit ordered text or image output with
`repl.write(...)`, console methods, or `repl.emitImage(...)`. The runtime also
exposes browser-control helpers, WebMCP, Patchright, Playwright, and raw CDP.

Executions are serialized. A timeout, crash, OOM, or protocol failure terminates
the REPL and changes its `repl_id`. This is unrestricted code execution inside
the browser VM and is not sandboxed.

Args:
code: JavaScript evaluated in a persistent Node.js runtime. Top-level bindings persist
until the browser VM's API process exits, the REPL is reset, or the REPL is
terminated after a crash or timeout. Static top-level imports are unsupported;
use dynamic `import()`. Expression values are ignored; emit output with
`repl.write(...)`, console methods, or `repl.emitImage(...)`. May be empty only
when `reset` is true.

reset: Terminate the current REPL, start a fresh one, and then evaluate code.

timeout_sec: Maximum execution time in seconds. Default is 60.

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(
path_template("/browsers/{id_or_name}/repl", id_or_name=id_or_name),
body=await async_maybe_transform(
{
"code": code,
"reset": reset,
"timeout_sec": timeout_sec,
},
browser_repl_params.BrowserReplParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=BrowserReplResult,
)


class BrowsersResourceWithRawResponse:
def __init__(self, browsers: BrowsersResource) -> None:
Expand All @@ -1416,6 +1548,9 @@ def __init__(self, browsers: BrowsersResource) -> None:
self.load_extensions = to_raw_response_wrapper(
browsers.load_extensions,
)
self.repl = to_raw_response_wrapper(
browsers.repl,
)

@cached_property
def telemetry(self) -> TelemetryResourceWithRawResponse:
Expand Down Expand Up @@ -1485,6 +1620,9 @@ def __init__(self, browsers: AsyncBrowsersResource) -> None:
self.load_extensions = async_to_raw_response_wrapper(
browsers.load_extensions,
)
self.repl = async_to_raw_response_wrapper(
browsers.repl,
)

@cached_property
def telemetry(self) -> AsyncTelemetryResourceWithRawResponse:
Expand Down Expand Up @@ -1554,6 +1692,9 @@ def __init__(self, browsers: BrowsersResource) -> None:
self.load_extensions = to_streamed_response_wrapper(
browsers.load_extensions,
)
self.repl = to_streamed_response_wrapper(
browsers.repl,
)

@cached_property
def telemetry(self) -> TelemetryResourceWithStreamingResponse:
Expand Down Expand Up @@ -1623,6 +1764,9 @@ def __init__(self, browsers: AsyncBrowsersResource) -> None:
self.load_extensions = async_to_streamed_response_wrapper(
browsers.load_extensions,
)
self.repl = async_to_streamed_response_wrapper(
browsers.repl,
)

@cached_property
def telemetry(self) -> AsyncTelemetryResourceWithStreamingResponse:
Expand Down
Loading
Loading