diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index f94eeca..e72f113 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "1.13.0"
+ ".": "1.14.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 1ef2a27..b4d46dd 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 27
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/browserbase-f39b852755134d01a440f7c37701f6c5397f43d13740d9ba08739cae488382a7.yml
-openapi_spec_hash: de6c25eebe5026d0fb9a4d7a93ec7718
-config_hash: d4b0c534eaf7665ea25168e0e824c9d3
+configured_endpoints: 36
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/browserbase-e82c289d3d3aabd936a476cf81630587ffe46ab9e9bdebced4b31b8c2f9bc08f.yml
+openapi_spec_hash: 473121b283812a3dfd866afe9b61dc7d
+config_hash: 1b24ea9fa13645b16b74aa794dbc8190
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a851da..7b1cbfc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## 1.14.0 (2026-07-02)
+
+Full Changelog: [v1.13.0...v1.14.0](https://github.com/browserbase/sdk-python/compare/v1.13.0...v1.14.0)
+
+### Features
+
+* [CORE-000][apps/sdk] Add agents to SDK ([580ec55](https://github.com/browserbase/sdk-python/commit/580ec554b66c71ecaeb1133e28173fc3275c43e9))
+
+
+### Documentation
+
+* document and un-gate allowedDomains session setting ([126cf6d](https://github.com/browserbase/sdk-python/commit/126cf6d331da97cc4c67b2b8f34c467f4449a010))
+
## 1.13.0 (2026-06-08)
Full Changelog: [v1.12.0...v1.13.0](https://github.com/browserbase/sdk-python/compare/v1.12.0...v1.13.0)
diff --git a/api.md b/api.md
index c3a3f4e..39c108f 100644
--- a/api.md
+++ b/api.md
@@ -156,3 +156,44 @@ Methods:
- client.sessions.replays.retrieve(id) -> ReplayRetrieveResponse
- client.sessions.replays.retrieve_page(page_id, \*, id) -> BinaryAPIResponse
+
+# Agents
+
+Types:
+
+```python
+from browserbase.types import (
+ AgentCreateResponse,
+ AgentRetrieveResponse,
+ AgentUpdateResponse,
+ AgentListResponse,
+)
+```
+
+Methods:
+
+- client.agents.create(\*\*params) -> AgentCreateResponse
+- client.agents.retrieve(agent_id) -> AgentRetrieveResponse
+- client.agents.update(agent_id, \*\*params) -> AgentUpdateResponse
+- client.agents.list(\*\*params) -> AgentListResponse
+- client.agents.delete(agent_id) -> None
+
+## Runs
+
+Types:
+
+```python
+from browserbase.types.agents import (
+ RunCreateResponse,
+ RunRetrieveResponse,
+ RunListResponse,
+ RunListMessagesResponse,
+)
+```
+
+Methods:
+
+- client.agents.runs.create(\*\*params) -> RunCreateResponse
+- client.agents.runs.retrieve(run_id) -> RunRetrieveResponse
+- client.agents.runs.list(\*\*params) -> RunListResponse
+- client.agents.runs.list_messages(run_id, \*\*params) -> RunListMessagesResponse
diff --git a/pyproject.toml b/pyproject.toml
index dc2925d..542ff75 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "browserbase"
-version = "1.13.0"
+version = "1.14.0"
description = "The official Python library for the Browserbase API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/browserbase/_client.py b/src/browserbase/_client.py
index d86814d..a2737da 100644
--- a/src/browserbase/_client.py
+++ b/src/browserbase/_client.py
@@ -35,13 +35,14 @@
)
if TYPE_CHECKING:
- from .resources import search, contexts, projects, sessions, fetch_api, extensions, certificates
+ from .resources import agents, search, contexts, projects, sessions, fetch_api, extensions, certificates
from .resources.search import SearchResource, AsyncSearchResource
from .resources.contexts import ContextsResource, AsyncContextsResource
from .resources.projects import ProjectsResource, AsyncProjectsResource
from .resources.fetch_api import FetchAPIResource, AsyncFetchAPIResource
from .resources.extensions import ExtensionsResource, AsyncExtensionsResource
from .resources.certificates import CertificatesResource, AsyncCertificatesResource
+ from .resources.agents.agents import AgentsResource, AsyncAgentsResource
from .resources.sessions.sessions import SessionsResource, AsyncSessionsResource
__all__ = [
@@ -162,6 +163,12 @@ def sessions(self) -> SessionsResource:
return SessionsResource(self)
+ @cached_property
+ def agents(self) -> AgentsResource:
+ from .resources.agents import AgentsResource
+
+ return AgentsResource(self)
+
@cached_property
def with_raw_response(self) -> BrowserbaseWithRawResponse:
return BrowserbaseWithRawResponse(self)
@@ -381,6 +388,12 @@ def sessions(self) -> AsyncSessionsResource:
return AsyncSessionsResource(self)
+ @cached_property
+ def agents(self) -> AsyncAgentsResource:
+ from .resources.agents import AsyncAgentsResource
+
+ return AsyncAgentsResource(self)
+
@cached_property
def with_raw_response(self) -> AsyncBrowserbaseWithRawResponse:
return AsyncBrowserbaseWithRawResponse(self)
@@ -542,6 +555,12 @@ def sessions(self) -> sessions.SessionsResourceWithRawResponse:
return SessionsResourceWithRawResponse(self._client.sessions)
+ @cached_property
+ def agents(self) -> agents.AgentsResourceWithRawResponse:
+ from .resources.agents import AgentsResourceWithRawResponse
+
+ return AgentsResourceWithRawResponse(self._client.agents)
+
class AsyncBrowserbaseWithRawResponse:
_client: AsyncBrowserbase
@@ -591,6 +610,12 @@ def sessions(self) -> sessions.AsyncSessionsResourceWithRawResponse:
return AsyncSessionsResourceWithRawResponse(self._client.sessions)
+ @cached_property
+ def agents(self) -> agents.AsyncAgentsResourceWithRawResponse:
+ from .resources.agents import AsyncAgentsResourceWithRawResponse
+
+ return AsyncAgentsResourceWithRawResponse(self._client.agents)
+
class BrowserbaseWithStreamedResponse:
_client: Browserbase
@@ -640,6 +665,12 @@ def sessions(self) -> sessions.SessionsResourceWithStreamingResponse:
return SessionsResourceWithStreamingResponse(self._client.sessions)
+ @cached_property
+ def agents(self) -> agents.AgentsResourceWithStreamingResponse:
+ from .resources.agents import AgentsResourceWithStreamingResponse
+
+ return AgentsResourceWithStreamingResponse(self._client.agents)
+
class AsyncBrowserbaseWithStreamedResponse:
_client: AsyncBrowserbase
@@ -689,6 +720,12 @@ def sessions(self) -> sessions.AsyncSessionsResourceWithStreamingResponse:
return AsyncSessionsResourceWithStreamingResponse(self._client.sessions)
+ @cached_property
+ def agents(self) -> agents.AsyncAgentsResourceWithStreamingResponse:
+ from .resources.agents import AsyncAgentsResourceWithStreamingResponse
+
+ return AsyncAgentsResourceWithStreamingResponse(self._client.agents)
+
Client = Browserbase
diff --git a/src/browserbase/_version.py b/src/browserbase/_version.py
index 5daf1b6..4df49f4 100644
--- a/src/browserbase/_version.py
+++ b/src/browserbase/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "browserbase"
-__version__ = "1.13.0" # x-release-please-version
+__version__ = "1.14.0" # x-release-please-version
diff --git a/src/browserbase/resources/__init__.py b/src/browserbase/resources/__init__.py
index 6bd0988..4566613 100644
--- a/src/browserbase/resources/__init__.py
+++ b/src/browserbase/resources/__init__.py
@@ -1,5 +1,13 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from .agents import (
+ AgentsResource,
+ AsyncAgentsResource,
+ AgentsResourceWithRawResponse,
+ AsyncAgentsResourceWithRawResponse,
+ AgentsResourceWithStreamingResponse,
+ AsyncAgentsResourceWithStreamingResponse,
+)
from .search import (
SearchResource,
AsyncSearchResource,
@@ -100,4 +108,10 @@
"AsyncSessionsResourceWithRawResponse",
"SessionsResourceWithStreamingResponse",
"AsyncSessionsResourceWithStreamingResponse",
+ "AgentsResource",
+ "AsyncAgentsResource",
+ "AgentsResourceWithRawResponse",
+ "AsyncAgentsResourceWithRawResponse",
+ "AgentsResourceWithStreamingResponse",
+ "AsyncAgentsResourceWithStreamingResponse",
]
diff --git a/src/browserbase/resources/agents/__init__.py b/src/browserbase/resources/agents/__init__.py
new file mode 100644
index 0000000..b393183
--- /dev/null
+++ b/src/browserbase/resources/agents/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .runs import (
+ RunsResource,
+ AsyncRunsResource,
+ RunsResourceWithRawResponse,
+ AsyncRunsResourceWithRawResponse,
+ RunsResourceWithStreamingResponse,
+ AsyncRunsResourceWithStreamingResponse,
+)
+from .agents import (
+ AgentsResource,
+ AsyncAgentsResource,
+ AgentsResourceWithRawResponse,
+ AsyncAgentsResourceWithRawResponse,
+ AgentsResourceWithStreamingResponse,
+ AsyncAgentsResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "RunsResource",
+ "AsyncRunsResource",
+ "RunsResourceWithRawResponse",
+ "AsyncRunsResourceWithRawResponse",
+ "RunsResourceWithStreamingResponse",
+ "AsyncRunsResourceWithStreamingResponse",
+ "AgentsResource",
+ "AsyncAgentsResource",
+ "AgentsResourceWithRawResponse",
+ "AsyncAgentsResourceWithRawResponse",
+ "AgentsResourceWithStreamingResponse",
+ "AsyncAgentsResourceWithStreamingResponse",
+]
diff --git a/src/browserbase/resources/agents/agents.py b/src/browserbase/resources/agents/agents.py
new file mode 100644
index 0000000..2f96517
--- /dev/null
+++ b/src/browserbase/resources/agents/agents.py
@@ -0,0 +1,661 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Union
+from datetime import datetime
+
+import httpx
+
+from .runs import (
+ RunsResource,
+ AsyncRunsResource,
+ RunsResourceWithRawResponse,
+ AsyncRunsResourceWithRawResponse,
+ RunsResourceWithStreamingResponse,
+ AsyncRunsResourceWithStreamingResponse,
+)
+from ...types import agent_list_params, agent_create_params, agent_update_params
+from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from ..._utils import path_template, maybe_transform, async_maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..._base_client import make_request_options
+from ...types.agent_list_response import AgentListResponse
+from ...types.agent_create_response import AgentCreateResponse
+from ...types.agent_update_response import AgentUpdateResponse
+from ...types.agent_retrieve_response import AgentRetrieveResponse
+
+__all__ = ["AgentsResource", "AsyncAgentsResource"]
+
+
+class AgentsResource(SyncAPIResource):
+ @cached_property
+ def runs(self) -> RunsResource:
+ return RunsResource(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/browserbase/sdk-python#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/browserbase/sdk-python#with_streaming_response
+ """
+ return AgentsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ name: str,
+ result_schema: Dict[str, object] | Omit = omit,
+ system_prompt: str | 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,
+ ) -> AgentCreateResponse:
+ """Create a reusable agent.
+
+ An agent defines a `systemPrompt` and `resultSchema`
+ that guide its behavior for every run. Only `name` is required; an agent created
+ with no `systemPrompt` behaves like an unconfigured run.
+
+ Args:
+ name: Human-readable name for the agent. Used to identify the agent in the dashboard
+ and API responses.
+
+ result_schema: An optional [JSON Schema](https://json-schema.org/specification) object. If
+ provided, runs that reference this agent will aim to return a `result` that
+ conforms to this schema when they complete. Can be overridden per run by passing
+ `resultSchema` on the run request.
+
+ system_prompt: System prompt that steers the agent's behavior on every run that uses this
+ agent.
+
+ 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(
+ "/v1/agents",
+ body=maybe_transform(
+ {
+ "name": name,
+ "result_schema": result_schema,
+ "system_prompt": system_prompt,
+ },
+ agent_create_params.AgentCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AgentCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ agent_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,
+ ) -> AgentRetrieveResponse:
+ """
+ Retrieve an agent by ID.
+
+ 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 agent_id:
+ raise ValueError(f"Expected a non-empty value for `agent_id` but received {agent_id!r}")
+ return self._get(
+ path_template("/v1/agents/{agent_id}", agent_id=agent_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AgentRetrieveResponse,
+ )
+
+ def update(
+ self,
+ agent_id: str,
+ *,
+ name: str | Omit = omit,
+ result_schema: Dict[str, object] | Omit = omit,
+ system_prompt: str | 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,
+ ) -> AgentUpdateResponse:
+ """Update an existing agent.
+
+ Only the fields provided in the body are modified;
+ omitted fields are left unchanged.
+
+ Args:
+ name: Human-readable name for the agent. Used to identify the agent in the dashboard
+ and API responses.
+
+ result_schema: An optional [JSON Schema](https://json-schema.org/specification) object. If
+ provided, runs that reference this agent will aim to return a `result` that
+ conforms to this schema when they complete. Can be overridden per run by passing
+ `resultSchema` on the run request.
+
+ system_prompt: New system prompt that steers the agent's behavior on every run that uses this
+ agent.
+
+ 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 agent_id:
+ raise ValueError(f"Expected a non-empty value for `agent_id` but received {agent_id!r}")
+ return self._patch(
+ path_template("/v1/agents/{agent_id}", agent_id=agent_id),
+ body=maybe_transform(
+ {
+ "name": name,
+ "result_schema": result_schema,
+ "system_prompt": system_prompt,
+ },
+ agent_update_params.AgentUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AgentUpdateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ cursor: str | Omit = omit,
+ end_at: Union[str, datetime] | Omit = omit,
+ limit: int | Omit = omit,
+ start_at: Union[str, datetime] | 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,
+ ) -> AgentListResponse:
+ """List agents across your account.
+
+ Supports filtering by creation time.
+
+ Args:
+ cursor: Pagination cursor. Pass the nextCursor from the previous response to fetch the
+ next page. Omit to start from the first page.
+
+ end_at: Only return agents created on or before this timestamp (inclusive). ISO 8601 /
+ RFC 3339, e.g. 2026-01-20T00:00:00Z.
+
+ limit: Maximum number of results to return.
+
+ start_at: Only return agents created on or after this timestamp (inclusive). ISO 8601 /
+ RFC 3339, e.g. 2026-01-19T00:00:00Z.
+
+ 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._get(
+ "/v1/agents",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "end_at": end_at,
+ "limit": limit,
+ "start_at": start_at,
+ },
+ agent_list_params.AgentListParams,
+ ),
+ ),
+ cast_to=AgentListResponse,
+ )
+
+ def delete(
+ self,
+ agent_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,
+ ) -> None:
+ """Delete an agent.
+
+ Runs that already referenced this agent are unaffected.
+
+ 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 agent_id:
+ raise ValueError(f"Expected a non-empty value for `agent_id` but received {agent_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ path_template("/v1/agents/{agent_id}", agent_id=agent_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncAgentsResource(AsyncAPIResource):
+ @cached_property
+ def runs(self) -> AsyncRunsResource:
+ return AsyncRunsResource(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/browserbase/sdk-python#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/browserbase/sdk-python#with_streaming_response
+ """
+ return AsyncAgentsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ name: str,
+ result_schema: Dict[str, object] | Omit = omit,
+ system_prompt: str | 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,
+ ) -> AgentCreateResponse:
+ """Create a reusable agent.
+
+ An agent defines a `systemPrompt` and `resultSchema`
+ that guide its behavior for every run. Only `name` is required; an agent created
+ with no `systemPrompt` behaves like an unconfigured run.
+
+ Args:
+ name: Human-readable name for the agent. Used to identify the agent in the dashboard
+ and API responses.
+
+ result_schema: An optional [JSON Schema](https://json-schema.org/specification) object. If
+ provided, runs that reference this agent will aim to return a `result` that
+ conforms to this schema when they complete. Can be overridden per run by passing
+ `resultSchema` on the run request.
+
+ system_prompt: System prompt that steers the agent's behavior on every run that uses this
+ agent.
+
+ 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(
+ "/v1/agents",
+ body=await async_maybe_transform(
+ {
+ "name": name,
+ "result_schema": result_schema,
+ "system_prompt": system_prompt,
+ },
+ agent_create_params.AgentCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AgentCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ agent_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,
+ ) -> AgentRetrieveResponse:
+ """
+ Retrieve an agent by ID.
+
+ 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 agent_id:
+ raise ValueError(f"Expected a non-empty value for `agent_id` but received {agent_id!r}")
+ return await self._get(
+ path_template("/v1/agents/{agent_id}", agent_id=agent_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AgentRetrieveResponse,
+ )
+
+ async def update(
+ self,
+ agent_id: str,
+ *,
+ name: str | Omit = omit,
+ result_schema: Dict[str, object] | Omit = omit,
+ system_prompt: str | 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,
+ ) -> AgentUpdateResponse:
+ """Update an existing agent.
+
+ Only the fields provided in the body are modified;
+ omitted fields are left unchanged.
+
+ Args:
+ name: Human-readable name for the agent. Used to identify the agent in the dashboard
+ and API responses.
+
+ result_schema: An optional [JSON Schema](https://json-schema.org/specification) object. If
+ provided, runs that reference this agent will aim to return a `result` that
+ conforms to this schema when they complete. Can be overridden per run by passing
+ `resultSchema` on the run request.
+
+ system_prompt: New system prompt that steers the agent's behavior on every run that uses this
+ agent.
+
+ 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 agent_id:
+ raise ValueError(f"Expected a non-empty value for `agent_id` but received {agent_id!r}")
+ return await self._patch(
+ path_template("/v1/agents/{agent_id}", agent_id=agent_id),
+ body=await async_maybe_transform(
+ {
+ "name": name,
+ "result_schema": result_schema,
+ "system_prompt": system_prompt,
+ },
+ agent_update_params.AgentUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AgentUpdateResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ cursor: str | Omit = omit,
+ end_at: Union[str, datetime] | Omit = omit,
+ limit: int | Omit = omit,
+ start_at: Union[str, datetime] | 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,
+ ) -> AgentListResponse:
+ """List agents across your account.
+
+ Supports filtering by creation time.
+
+ Args:
+ cursor: Pagination cursor. Pass the nextCursor from the previous response to fetch the
+ next page. Omit to start from the first page.
+
+ end_at: Only return agents created on or before this timestamp (inclusive). ISO 8601 /
+ RFC 3339, e.g. 2026-01-20T00:00:00Z.
+
+ limit: Maximum number of results to return.
+
+ start_at: Only return agents created on or after this timestamp (inclusive). ISO 8601 /
+ RFC 3339, e.g. 2026-01-19T00:00:00Z.
+
+ 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._get(
+ "/v1/agents",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "cursor": cursor,
+ "end_at": end_at,
+ "limit": limit,
+ "start_at": start_at,
+ },
+ agent_list_params.AgentListParams,
+ ),
+ ),
+ cast_to=AgentListResponse,
+ )
+
+ async def delete(
+ self,
+ agent_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,
+ ) -> None:
+ """Delete an agent.
+
+ Runs that already referenced this agent are unaffected.
+
+ 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 agent_id:
+ raise ValueError(f"Expected a non-empty value for `agent_id` but received {agent_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ path_template("/v1/agents/{agent_id}", agent_id=agent_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AgentsResourceWithRawResponse:
+ def __init__(self, agents: AgentsResource) -> None:
+ self._agents = agents
+
+ self.create = to_raw_response_wrapper(
+ agents.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ agents.retrieve,
+ )
+ self.update = to_raw_response_wrapper(
+ agents.update,
+ )
+ self.list = to_raw_response_wrapper(
+ agents.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ agents.delete,
+ )
+
+ @cached_property
+ def runs(self) -> RunsResourceWithRawResponse:
+ return RunsResourceWithRawResponse(self._agents.runs)
+
+
+class AsyncAgentsResourceWithRawResponse:
+ def __init__(self, agents: AsyncAgentsResource) -> None:
+ self._agents = agents
+
+ self.create = async_to_raw_response_wrapper(
+ agents.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ agents.retrieve,
+ )
+ self.update = async_to_raw_response_wrapper(
+ agents.update,
+ )
+ self.list = async_to_raw_response_wrapper(
+ agents.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ agents.delete,
+ )
+
+ @cached_property
+ def runs(self) -> AsyncRunsResourceWithRawResponse:
+ return AsyncRunsResourceWithRawResponse(self._agents.runs)
+
+
+class AgentsResourceWithStreamingResponse:
+ def __init__(self, agents: AgentsResource) -> None:
+ self._agents = agents
+
+ self.create = to_streamed_response_wrapper(
+ agents.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ agents.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ agents.update,
+ )
+ self.list = to_streamed_response_wrapper(
+ agents.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ agents.delete,
+ )
+
+ @cached_property
+ def runs(self) -> RunsResourceWithStreamingResponse:
+ return RunsResourceWithStreamingResponse(self._agents.runs)
+
+
+class AsyncAgentsResourceWithStreamingResponse:
+ def __init__(self, agents: AsyncAgentsResource) -> None:
+ self._agents = agents
+
+ self.create = async_to_streamed_response_wrapper(
+ agents.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ agents.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ agents.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ agents.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ agents.delete,
+ )
+
+ @cached_property
+ def runs(self) -> AsyncRunsResourceWithStreamingResponse:
+ return AsyncRunsResourceWithStreamingResponse(self._agents.runs)
diff --git a/src/browserbase/resources/agents/runs.py b/src/browserbase/resources/agents/runs.py
new file mode 100644
index 0000000..5f9eeb2
--- /dev/null
+++ b/src/browserbase/resources/agents/runs.py
@@ -0,0 +1,612 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Union
+from datetime import datetime
+from typing_extensions import Literal
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import path_template, maybe_transform, async_maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..._base_client import make_request_options
+from ...types.agents import run_list_params, run_create_params, run_list_messages_params
+from ...types.agents.run_list_response import RunListResponse
+from ...types.agents.run_create_response import RunCreateResponse
+from ...types.agents.run_retrieve_response import RunRetrieveResponse
+from ...types.agents.run_list_messages_response import RunListMessagesResponse
+
+__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/browserbase/sdk-python#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/browserbase/sdk-python#with_streaming_response
+ """
+ return RunsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ task: str,
+ agent_id: str | Omit = omit,
+ browser_settings: run_create_params.BrowserSettings | Omit = omit,
+ result_schema: Dict[str, object] | Omit = omit,
+ variables: Dict[str, run_create_params.Variables] | 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,
+ ) -> RunCreateResponse:
+ """
+ Run a browser agent to complete the `task` by using web search and browser
+ tooling. Optionally pass `agentId` to run a
+ [custom agent](/reference/api/create-an-agent) you've created.
+
+ Args:
+ task: A natural language description of the task the agent should accomplish.
+
+ agent_id: Optionally run a specific [custom agent](/reference/api/create-an-agent) you've
+ created by ID. The run will use the agent's `systemPrompt` and `resultSchema`
+ unless overridden.
+
+ browser_settings: Browser configuration for the agent's session. When omitted, runner defaults
+ apply.
+
+ result_schema: An optional [JSON Schema](https://json-schema.org/specification) object. If
+ provided, the agent will aim to return a `result` that conforms to this schema
+ when the run completes. Overrides the referenced agent's default `resultSchema`
+ for this run only.
+
+ variables: Optional named variables the agent can reference as placeholders, i.e.
+ `%variable%`. Each entry pairs a `value` the placeholder resolves to with an
+ optional `description` that hints to the agent when it should be used. Values
+ are not persisted.
+
+ 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(
+ "/v1/agents/runs",
+ body=maybe_transform(
+ {
+ "task": task,
+ "agent_id": agent_id,
+ "browser_settings": browser_settings,
+ "result_schema": result_schema,
+ "variables": variables,
+ },
+ run_create_params.RunCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RunCreateResponse,
+ )
+
+ 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,
+ ) -> RunRetrieveResponse:
+ """
+ Retrieve the current status and details of a run, including its result and
+ associated session information. To fetch the run's messages, use
+ [List Run Messages](/reference/api/list-run-messages).
+
+ 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(
+ path_template("/v1/agents/runs/{run_id}", run_id=run_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RunRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ agent_id: str | Omit = omit,
+ cursor: str | Omit = omit,
+ end_at: Union[str, datetime] | Omit = omit,
+ limit: int | Omit = omit,
+ start_at: Union[str, datetime] | Omit = omit,
+ status: Literal["PENDING", "RUNNING", "COMPLETED", "FAILED", "STOPPED", "TIMED_OUT"] | 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,
+ ) -> RunListResponse:
+ """List runs across your account.
+
+ Supports filtering by status, by the agent they
+ reference, and by creation time.
+
+ Args:
+ agent_id: Only return runs that reference this agent ID.
+
+ cursor: Pagination cursor. Pass the nextCursor from the previous response to fetch the
+ next page. Omit to start from the first page.
+
+ end_at: Only return runs created on or before this timestamp (inclusive). ISO 8601 / RFC
+ 3339, e.g. 2026-01-20T00:00:00Z.
+
+ limit: Maximum number of results to return.
+
+ start_at: Only return runs created on or after this timestamp (inclusive). ISO 8601 / RFC
+ 3339, e.g. 2026-01-19T00:00:00Z.
+
+ status: Current status of the run.
+
+ - `PENDING` - agent will run soon
+ - `RUNNING` - agent is currently running
+ - `COMPLETED` - agent has finished running
+ - `FAILED` - agent has failed the run
+ - `STOPPED` - run was stopped by the user
+ - `TIMED_OUT` - run exceeded maximum time
+
+ 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._get(
+ "/v1/agents/runs",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "agent_id": agent_id,
+ "cursor": cursor,
+ "end_at": end_at,
+ "limit": limit,
+ "start_at": start_at,
+ "status": status,
+ },
+ run_list_params.RunListParams,
+ ),
+ ),
+ cast_to=RunListResponse,
+ )
+
+ def list_messages(
+ self,
+ run_id: str,
+ *,
+ all: bool | Omit = omit,
+ limit: int | Omit = omit,
+ since: str | 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,
+ ) -> RunListMessagesResponse:
+ """
+ Returns a paginated list of messages produced by a run, in chronological order,
+ with the oldest messages first.
+
+ Messages conform to the
+ [AI SDK UIMessage format](https://ai-sdk.dev/docs/reference/ai-sdk-core/ui-message).
+
+ Args:
+ all: Return every message after `since` in one response, ignoring `limit`.
+
+ limit: Maximum number of messages to return.
+
+ since: The `id` of the last message you've already received. The response will contain
+ messages produced after that one, in chronological order. Omit on the first
+ call. Pass the previous response's `nextSince` value to continue paging or to
+ poll for new messages.
+
+ 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(
+ path_template("/v1/agents/runs/{run_id}/messages", run_id=run_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "all": all,
+ "limit": limit,
+ "since": since,
+ },
+ run_list_messages_params.RunListMessagesParams,
+ ),
+ ),
+ cast_to=RunListMessagesResponse,
+ )
+
+
+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/browserbase/sdk-python#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/browserbase/sdk-python#with_streaming_response
+ """
+ return AsyncRunsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ task: str,
+ agent_id: str | Omit = omit,
+ browser_settings: run_create_params.BrowserSettings | Omit = omit,
+ result_schema: Dict[str, object] | Omit = omit,
+ variables: Dict[str, run_create_params.Variables] | 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,
+ ) -> RunCreateResponse:
+ """
+ Run a browser agent to complete the `task` by using web search and browser
+ tooling. Optionally pass `agentId` to run a
+ [custom agent](/reference/api/create-an-agent) you've created.
+
+ Args:
+ task: A natural language description of the task the agent should accomplish.
+
+ agent_id: Optionally run a specific [custom agent](/reference/api/create-an-agent) you've
+ created by ID. The run will use the agent's `systemPrompt` and `resultSchema`
+ unless overridden.
+
+ browser_settings: Browser configuration for the agent's session. When omitted, runner defaults
+ apply.
+
+ result_schema: An optional [JSON Schema](https://json-schema.org/specification) object. If
+ provided, the agent will aim to return a `result` that conforms to this schema
+ when the run completes. Overrides the referenced agent's default `resultSchema`
+ for this run only.
+
+ variables: Optional named variables the agent can reference as placeholders, i.e.
+ `%variable%`. Each entry pairs a `value` the placeholder resolves to with an
+ optional `description` that hints to the agent when it should be used. Values
+ are not persisted.
+
+ 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(
+ "/v1/agents/runs",
+ body=await async_maybe_transform(
+ {
+ "task": task,
+ "agent_id": agent_id,
+ "browser_settings": browser_settings,
+ "result_schema": result_schema,
+ "variables": variables,
+ },
+ run_create_params.RunCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RunCreateResponse,
+ )
+
+ 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,
+ ) -> RunRetrieveResponse:
+ """
+ Retrieve the current status and details of a run, including its result and
+ associated session information. To fetch the run's messages, use
+ [List Run Messages](/reference/api/list-run-messages).
+
+ 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(
+ path_template("/v1/agents/runs/{run_id}", run_id=run_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RunRetrieveResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ agent_id: str | Omit = omit,
+ cursor: str | Omit = omit,
+ end_at: Union[str, datetime] | Omit = omit,
+ limit: int | Omit = omit,
+ start_at: Union[str, datetime] | Omit = omit,
+ status: Literal["PENDING", "RUNNING", "COMPLETED", "FAILED", "STOPPED", "TIMED_OUT"] | 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,
+ ) -> RunListResponse:
+ """List runs across your account.
+
+ Supports filtering by status, by the agent they
+ reference, and by creation time.
+
+ Args:
+ agent_id: Only return runs that reference this agent ID.
+
+ cursor: Pagination cursor. Pass the nextCursor from the previous response to fetch the
+ next page. Omit to start from the first page.
+
+ end_at: Only return runs created on or before this timestamp (inclusive). ISO 8601 / RFC
+ 3339, e.g. 2026-01-20T00:00:00Z.
+
+ limit: Maximum number of results to return.
+
+ start_at: Only return runs created on or after this timestamp (inclusive). ISO 8601 / RFC
+ 3339, e.g. 2026-01-19T00:00:00Z.
+
+ status: Current status of the run.
+
+ - `PENDING` - agent will run soon
+ - `RUNNING` - agent is currently running
+ - `COMPLETED` - agent has finished running
+ - `FAILED` - agent has failed the run
+ - `STOPPED` - run was stopped by the user
+ - `TIMED_OUT` - run exceeded maximum time
+
+ 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._get(
+ "/v1/agents/runs",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "agent_id": agent_id,
+ "cursor": cursor,
+ "end_at": end_at,
+ "limit": limit,
+ "start_at": start_at,
+ "status": status,
+ },
+ run_list_params.RunListParams,
+ ),
+ ),
+ cast_to=RunListResponse,
+ )
+
+ async def list_messages(
+ self,
+ run_id: str,
+ *,
+ all: bool | Omit = omit,
+ limit: int | Omit = omit,
+ since: str | 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,
+ ) -> RunListMessagesResponse:
+ """
+ Returns a paginated list of messages produced by a run, in chronological order,
+ with the oldest messages first.
+
+ Messages conform to the
+ [AI SDK UIMessage format](https://ai-sdk.dev/docs/reference/ai-sdk-core/ui-message).
+
+ Args:
+ all: Return every message after `since` in one response, ignoring `limit`.
+
+ limit: Maximum number of messages to return.
+
+ since: The `id` of the last message you've already received. The response will contain
+ messages produced after that one, in chronological order. Omit on the first
+ call. Pass the previous response's `nextSince` value to continue paging or to
+ poll for new messages.
+
+ 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(
+ path_template("/v1/agents/runs/{run_id}/messages", run_id=run_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "all": all,
+ "limit": limit,
+ "since": since,
+ },
+ run_list_messages_params.RunListMessagesParams,
+ ),
+ ),
+ cast_to=RunListMessagesResponse,
+ )
+
+
+class RunsResourceWithRawResponse:
+ def __init__(self, runs: RunsResource) -> None:
+ self._runs = runs
+
+ self.create = to_raw_response_wrapper(
+ runs.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ runs.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ runs.list,
+ )
+ self.list_messages = to_raw_response_wrapper(
+ runs.list_messages,
+ )
+
+
+class AsyncRunsResourceWithRawResponse:
+ def __init__(self, runs: AsyncRunsResource) -> None:
+ self._runs = runs
+
+ self.create = async_to_raw_response_wrapper(
+ runs.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ runs.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ runs.list,
+ )
+ self.list_messages = async_to_raw_response_wrapper(
+ runs.list_messages,
+ )
+
+
+class RunsResourceWithStreamingResponse:
+ def __init__(self, runs: RunsResource) -> None:
+ self._runs = runs
+
+ self.create = to_streamed_response_wrapper(
+ runs.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ runs.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ runs.list,
+ )
+ self.list_messages = to_streamed_response_wrapper(
+ runs.list_messages,
+ )
+
+
+class AsyncRunsResourceWithStreamingResponse:
+ def __init__(self, runs: AsyncRunsResource) -> None:
+ self._runs = runs
+
+ self.create = async_to_streamed_response_wrapper(
+ runs.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ runs.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ runs.list,
+ )
+ self.list_messages = async_to_streamed_response_wrapper(
+ runs.list_messages,
+ )
diff --git a/src/browserbase/types/__init__.py b/src/browserbase/types/__init__.py
index 72d472a..a8fdf3d 100644
--- a/src/browserbase/types/__init__.py
+++ b/src/browserbase/types/__init__.py
@@ -8,15 +8,22 @@
from .extension import Extension as Extension
from .certificate import Certificate as Certificate
from .project_usage import ProjectUsage as ProjectUsage
+from .agent_list_params import AgentListParams as AgentListParams
from .search_web_params import SearchWebParams as SearchWebParams
from .session_live_urls import SessionLiveURLs as SessionLiveURLs
+from .agent_create_params import AgentCreateParams as AgentCreateParams
+from .agent_list_response import AgentListResponse as AgentListResponse
+from .agent_update_params import AgentUpdateParams as AgentUpdateParams
from .search_web_response import SearchWebResponse as SearchWebResponse
from .session_list_params import SessionListParams as SessionListParams
+from .agent_create_response import AgentCreateResponse as AgentCreateResponse
+from .agent_update_response import AgentUpdateResponse as AgentUpdateResponse
from .context_create_params import ContextCreateParams as ContextCreateParams
from .project_list_response import ProjectListResponse as ProjectListResponse
from .session_create_params import SessionCreateParams as SessionCreateParams
from .session_list_response import SessionListResponse as SessionListResponse
from .session_update_params import SessionUpdateParams as SessionUpdateParams
+from .agent_retrieve_response import AgentRetrieveResponse as AgentRetrieveResponse
from .context_create_response import ContextCreateResponse as ContextCreateResponse
from .context_update_response import ContextUpdateResponse as ContextUpdateResponse
from .extension_create_params import ExtensionCreateParams as ExtensionCreateParams
diff --git a/src/browserbase/types/agent_create_params.py b/src/browserbase/types/agent_create_params.py
new file mode 100644
index 0000000..db78f8b
--- /dev/null
+++ b/src/browserbase/types/agent_create_params.py
@@ -0,0 +1,32 @@
+# 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, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["AgentCreateParams"]
+
+
+class AgentCreateParams(TypedDict, total=False):
+ name: Required[str]
+ """Human-readable name for the agent.
+
+ Used to identify the agent in the dashboard and API responses.
+ """
+
+ result_schema: Annotated[Dict[str, object], PropertyInfo(alias="resultSchema")]
+ """An optional [JSON Schema](https://json-schema.org/specification) object.
+
+ If provided, runs that reference this agent will aim to return a `result` that
+ conforms to this schema when they complete. Can be overridden per run by passing
+ `resultSchema` on the run request.
+ """
+
+ system_prompt: Annotated[str, PropertyInfo(alias="systemPrompt")]
+ """
+ System prompt that steers the agent's behavior on every run that uses this
+ agent.
+ """
diff --git a/src/browserbase/types/agent_create_response.py b/src/browserbase/types/agent_create_response.py
new file mode 100644
index 0000000..a57263c
--- /dev/null
+++ b/src/browserbase/types/agent_create_response.py
@@ -0,0 +1,43 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["AgentCreateResponse"]
+
+
+class AgentCreateResponse(BaseModel):
+ """A reusable agent.
+
+ Referenced by `agentId` to apply a system prompt to every run that uses the agent.
+ """
+
+ agent_id: str = FieldInfo(alias="agentId")
+ """Unique identifier for the agent.
+
+ Use this value as `agentId` when creating an agent run.
+ """
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ name: str
+ """Human-readable name for the agent.
+
+ Used to identify the agent in the dashboard and API responses.
+ """
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+ result_schema: Optional[Dict[str, object]] = FieldInfo(alias="resultSchema", default=None)
+ """
+ [JSON Schema](https://json-schema.org/specification) that runs referencing this
+ agent will aim to conform their `result` to. Can be overridden per run by
+ passing `resultSchema` on the run request.
+ """
+
+ system_prompt: Optional[str] = FieldInfo(alias="systemPrompt", default=None)
+ """System prompt applied to every run that uses this agent."""
diff --git a/src/browserbase/types/agent_list_params.py b/src/browserbase/types/agent_list_params.py
new file mode 100644
index 0000000..e964859
--- /dev/null
+++ b/src/browserbase/types/agent_list_params.py
@@ -0,0 +1,35 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import datetime
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["AgentListParams"]
+
+
+class AgentListParams(TypedDict, total=False):
+ cursor: str
+ """Pagination cursor.
+
+ Pass the nextCursor from the previous response to fetch the next page. Omit to
+ start from the first page.
+ """
+
+ end_at: Annotated[Union[str, datetime], PropertyInfo(alias="endAt", format="iso8601")]
+ """Only return agents created on or before this timestamp (inclusive).
+
+ ISO 8601 / RFC 3339, e.g. 2026-01-20T00:00:00Z.
+ """
+
+ limit: int
+ """Maximum number of results to return."""
+
+ start_at: Annotated[Union[str, datetime], PropertyInfo(alias="startAt", format="iso8601")]
+ """Only return agents created on or after this timestamp (inclusive).
+
+ ISO 8601 / RFC 3339, e.g. 2026-01-19T00:00:00Z.
+ """
diff --git a/src/browserbase/types/agent_list_response.py b/src/browserbase/types/agent_list_response.py
new file mode 100644
index 0000000..b169ea4
--- /dev/null
+++ b/src/browserbase/types/agent_list_response.py
@@ -0,0 +1,60 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["AgentListResponse", "Data"]
+
+
+class Data(BaseModel):
+ """A reusable agent.
+
+ Referenced by `agentId` to apply a system prompt to every run that uses the agent.
+ """
+
+ agent_id: str = FieldInfo(alias="agentId")
+ """Unique identifier for the agent.
+
+ Use this value as `agentId` when creating an agent run.
+ """
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ name: str
+ """Human-readable name for the agent.
+
+ Used to identify the agent in the dashboard and API responses.
+ """
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+ result_schema: Optional[Dict[str, object]] = FieldInfo(alias="resultSchema", default=None)
+ """
+ [JSON Schema](https://json-schema.org/specification) that runs referencing this
+ agent will aim to conform their `result` to. Can be overridden per run by
+ passing `resultSchema` on the run request.
+ """
+
+ system_prompt: Optional[str] = FieldInfo(alias="systemPrompt", default=None)
+ """System prompt applied to every run that uses this agent."""
+
+
+class AgentListResponse(BaseModel):
+ """A page of agents."""
+
+ data: List[Data]
+ """The page of matching agents."""
+
+ limit: int
+ """The maximum number of results returned in this page."""
+
+ next_cursor: Optional[str] = FieldInfo(alias="nextCursor", default=None)
+ """Cursor for the next page.
+
+ Pass it back as `cursor` on the next request to continue paging. null when there
+ are no more results.
+ """
diff --git a/src/browserbase/types/agent_retrieve_response.py b/src/browserbase/types/agent_retrieve_response.py
new file mode 100644
index 0000000..8754cb6
--- /dev/null
+++ b/src/browserbase/types/agent_retrieve_response.py
@@ -0,0 +1,43 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["AgentRetrieveResponse"]
+
+
+class AgentRetrieveResponse(BaseModel):
+ """A reusable agent.
+
+ Referenced by `agentId` to apply a system prompt to every run that uses the agent.
+ """
+
+ agent_id: str = FieldInfo(alias="agentId")
+ """Unique identifier for the agent.
+
+ Use this value as `agentId` when creating an agent run.
+ """
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ name: str
+ """Human-readable name for the agent.
+
+ Used to identify the agent in the dashboard and API responses.
+ """
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+ result_schema: Optional[Dict[str, object]] = FieldInfo(alias="resultSchema", default=None)
+ """
+ [JSON Schema](https://json-schema.org/specification) that runs referencing this
+ agent will aim to conform their `result` to. Can be overridden per run by
+ passing `resultSchema` on the run request.
+ """
+
+ system_prompt: Optional[str] = FieldInfo(alias="systemPrompt", default=None)
+ """System prompt applied to every run that uses this agent."""
diff --git a/src/browserbase/types/agent_update_params.py b/src/browserbase/types/agent_update_params.py
new file mode 100644
index 0000000..7772029
--- /dev/null
+++ b/src/browserbase/types/agent_update_params.py
@@ -0,0 +1,32 @@
+# 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 Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["AgentUpdateParams"]
+
+
+class AgentUpdateParams(TypedDict, total=False):
+ name: str
+ """Human-readable name for the agent.
+
+ Used to identify the agent in the dashboard and API responses.
+ """
+
+ result_schema: Annotated[Dict[str, object], PropertyInfo(alias="resultSchema")]
+ """An optional [JSON Schema](https://json-schema.org/specification) object.
+
+ If provided, runs that reference this agent will aim to return a `result` that
+ conforms to this schema when they complete. Can be overridden per run by passing
+ `resultSchema` on the run request.
+ """
+
+ system_prompt: Annotated[str, PropertyInfo(alias="systemPrompt")]
+ """
+ New system prompt that steers the agent's behavior on every run that uses this
+ agent.
+ """
diff --git a/src/browserbase/types/agent_update_response.py b/src/browserbase/types/agent_update_response.py
new file mode 100644
index 0000000..654b106
--- /dev/null
+++ b/src/browserbase/types/agent_update_response.py
@@ -0,0 +1,43 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["AgentUpdateResponse"]
+
+
+class AgentUpdateResponse(BaseModel):
+ """A reusable agent.
+
+ Referenced by `agentId` to apply a system prompt to every run that uses the agent.
+ """
+
+ agent_id: str = FieldInfo(alias="agentId")
+ """Unique identifier for the agent.
+
+ Use this value as `agentId` when creating an agent run.
+ """
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ name: str
+ """Human-readable name for the agent.
+
+ Used to identify the agent in the dashboard and API responses.
+ """
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+ result_schema: Optional[Dict[str, object]] = FieldInfo(alias="resultSchema", default=None)
+ """
+ [JSON Schema](https://json-schema.org/specification) that runs referencing this
+ agent will aim to conform their `result` to. Can be overridden per run by
+ passing `resultSchema` on the run request.
+ """
+
+ system_prompt: Optional[str] = FieldInfo(alias="systemPrompt", default=None)
+ """System prompt applied to every run that uses this agent."""
diff --git a/src/browserbase/types/agents/__init__.py b/src/browserbase/types/agents/__init__.py
new file mode 100644
index 0000000..2d33f6e
--- /dev/null
+++ b/src/browserbase/types/agents/__init__.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .run_list_params import RunListParams as RunListParams
+from .run_create_params import RunCreateParams as RunCreateParams
+from .run_list_response import RunListResponse as RunListResponse
+from .run_create_response import RunCreateResponse as RunCreateResponse
+from .run_retrieve_response import RunRetrieveResponse as RunRetrieveResponse
+from .run_list_messages_params import RunListMessagesParams as RunListMessagesParams
+from .run_list_messages_response import RunListMessagesResponse as RunListMessagesResponse
diff --git a/src/browserbase/types/agents/run_create_params.py b/src/browserbase/types/agents/run_create_params.py
new file mode 100644
index 0000000..00a45a4
--- /dev/null
+++ b/src/browserbase/types/agents/run_create_params.py
@@ -0,0 +1,78 @@
+# 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, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["RunCreateParams", "BrowserSettings", "BrowserSettingsContext", "Variables"]
+
+
+class RunCreateParams(TypedDict, total=False):
+ task: Required[str]
+ """A natural language description of the task the agent should accomplish."""
+
+ agent_id: Annotated[str, PropertyInfo(alias="agentId")]
+ """
+ Optionally run a specific [custom agent](/reference/api/create-an-agent) you've
+ created by ID. The run will use the agent's `systemPrompt` and `resultSchema`
+ unless overridden.
+ """
+
+ browser_settings: Annotated[BrowserSettings, PropertyInfo(alias="browserSettings")]
+ """Browser configuration for the agent's session.
+
+ When omitted, runner defaults apply.
+ """
+
+ result_schema: Annotated[Dict[str, object], PropertyInfo(alias="resultSchema")]
+ """An optional [JSON Schema](https://json-schema.org/specification) object.
+
+ If provided, the agent will aim to return a `result` that conforms to this
+ schema when the run completes. Overrides the referenced agent's default
+ `resultSchema` for this run only.
+ """
+
+ variables: Dict[str, Variables]
+ """Optional named variables the agent can reference as placeholders, i.e.
+
+ `%variable%`. Each entry pairs a `value` the placeholder resolves to with an
+ optional `description` that hints to the agent when it should be used. Values
+ are not persisted.
+ """
+
+
+class BrowserSettingsContext(TypedDict, total=False):
+ id: Required[str]
+ """The Context ID."""
+
+ persist: bool
+ """Whether to persist the context after browsing. Defaults to false."""
+
+
+class BrowserSettings(TypedDict, total=False):
+ """Browser configuration for the agent's session.
+
+ When omitted, runner defaults apply.
+ """
+
+ context: BrowserSettingsContext
+
+ proxies: bool
+ """Set true to route the agent's browser session through the default proxy."""
+
+ verified: bool
+ """Set true to enable Browserbase Verified for the session."""
+
+
+class Variables(TypedDict, total=False):
+ value: Required[str]
+ """The value the placeholder resolves to when the agent uses it."""
+
+ description: str
+ """
+ Optional hint to the agent describing what this variable represents and when to
+ use it.
+ """
diff --git a/src/browserbase/types/agents/run_create_response.py b/src/browserbase/types/agents/run_create_response.py
new file mode 100644
index 0000000..05a7b52
--- /dev/null
+++ b/src/browserbase/types/agents/run_create_response.py
@@ -0,0 +1,76 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["RunCreateResponse", "Cause"]
+
+
+class Cause(BaseModel):
+ code: str
+ """Structured failure code (e.g., RUNNER_HEARTBEAT_LOST)."""
+
+ message: Optional[str] = None
+ """Human-readable failure detail."""
+
+
+class RunCreateResponse(BaseModel):
+ """One execution of an agent against a task.
+
+ Created in `pending` and transitioned through `running` → `completed`/`failed` by the runner.
+ """
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ run_id: str = FieldInfo(alias="runId")
+ """Unique identifier for the run."""
+
+ status: Literal["PENDING", "RUNNING", "COMPLETED", "FAILED", "STOPPED", "TIMED_OUT"]
+ """Current status of the run.
+
+ - `PENDING` - agent will run soon
+ - `RUNNING` - agent is currently running
+ - `COMPLETED` - agent has finished running
+ - `FAILED` - agent has failed the run
+ - `STOPPED` - run was stopped by the user
+ - `TIMED_OUT` - run exceeded maximum time
+ """
+
+ task: str
+ """The original task description."""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+ agent_id: Optional[str] = FieldInfo(alias="agentId", default=None)
+ """The ID of the agent applied to this run, if any. Omitted for ad-hoc runs."""
+
+ cause: Optional[Cause] = None
+
+ ended_at: Optional[datetime] = FieldInfo(alias="endedAt", default=None)
+
+ result: Optional[Dict[str, object]] = None
+ """The agent's structured result for the run.
+
+ Only present when the run has finished and output is available. The result
+ conforms to the provided [JSON Schema](https://json-schema.org/specification)
+ when one is set.
+ """
+
+ result_schema: Optional[Dict[str, object]] = FieldInfo(alias="resultSchema", default=None)
+ """
+ Per-run [JSON Schema](https://json-schema.org/specification) override for the
+ result shape. When unset, the agent's default `resultSchema` applies.
+ """
+
+ sandbox_id: Optional[str] = FieldInfo(alias="sandboxId", default=None)
+ """External sandbox identifier assigned by the runner. Optional."""
+
+ session_id: Optional[str] = FieldInfo(alias="sessionId", default=None)
+ """The Browserbase session ID powering this run."""
+
+ started_at: Optional[datetime] = FieldInfo(alias="startedAt", default=None)
diff --git a/src/browserbase/types/agents/run_list_messages_params.py b/src/browserbase/types/agents/run_list_messages_params.py
new file mode 100644
index 0000000..193fc25
--- /dev/null
+++ b/src/browserbase/types/agents/run_list_messages_params.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["RunListMessagesParams"]
+
+
+class RunListMessagesParams(TypedDict, total=False):
+ all: bool
+ """Return every message after `since` in one response, ignoring `limit`."""
+
+ limit: int
+ """Maximum number of messages to return."""
+
+ since: str
+ """The `id` of the last message you've already received.
+
+ The response will contain messages produced after that one, in chronological
+ order. Omit on the first call. Pass the previous response's `nextSince` value to
+ continue paging or to poll for new messages.
+ """
diff --git a/src/browserbase/types/agents/run_list_messages_response.py b/src/browserbase/types/agents/run_list_messages_response.py
new file mode 100644
index 0000000..f870f70
--- /dev/null
+++ b/src/browserbase/types/agents/run_list_messages_response.py
@@ -0,0 +1,85 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import TYPE_CHECKING, Dict, List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["RunListMessagesResponse", "Data", "DataMessage", "DataMessageContentUnionMember1"]
+
+
+class DataMessageContentUnionMember1(BaseModel):
+ type: str
+ """text | reasoning | file | tool-call | tool-result"""
+
+ data: Optional[str] = None
+
+ input: Optional[object] = None
+
+ media_type: Optional[str] = FieldInfo(alias="mediaType", default=None)
+
+ output: Optional[object] = None
+
+ text: Optional[str] = None
+
+ tool_call_id: Optional[str] = FieldInfo(alias="toolCallId", default=None)
+
+ tool_name: Optional[str] = FieldInfo(alias="toolName", default=None)
+
+ if TYPE_CHECKING:
+ # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a
+ # value to this field, so for compatibility we avoid doing it at runtime.
+ __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]
+
+ # Stub to indicate that arbitrary properties are accepted.
+ # To access properties that are not valid identifiers you can use `getattr`, e.g.
+ # `getattr(obj, '$type')`
+ def __getattr__(self, attr: str) -> object: ...
+ else:
+ __pydantic_extra__: Dict[str, object]
+
+
+class DataMessage(BaseModel):
+ """An AI SDK response message (assistant or tool)."""
+
+ content: Union[str, List[DataMessageContentUnionMember1]]
+ """Plain string (assistant text) or an array of typed parts."""
+
+ role: Literal["assistant", "tool"]
+
+ if TYPE_CHECKING:
+ # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a
+ # value to this field, so for compatibility we avoid doing it at runtime.
+ __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]
+
+ # Stub to indicate that arbitrary properties are accepted.
+ # To access properties that are not valid identifiers you can use `getattr`, e.g.
+ # `getattr(obj, '$type')`
+ def __getattr__(self, attr: str) -> object: ...
+ else:
+ __pydantic_extra__: Dict[str, object]
+
+
+class Data(BaseModel):
+ id: str
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ message: DataMessage
+ """An AI SDK response message (assistant or tool)."""
+
+
+class RunListMessagesResponse(BaseModel):
+ data: List[Data]
+ """The page of messages, in chronological order, with the oldest messages first."""
+
+ next_since: Optional[str] = FieldInfo(alias="nextSince", default=None)
+ """The `id` of the last message in `data`.
+
+ Pass it back as `since` on the next request to continue paging, or to poll for
+ new messages. `null` only when the run has no messages yet; in that case, omit
+ `since` and retry.
+ """
diff --git a/src/browserbase/types/agents/run_list_params.py b/src/browserbase/types/agents/run_list_params.py
new file mode 100644
index 0000000..d0a2c0e
--- /dev/null
+++ b/src/browserbase/types/agents/run_list_params.py
@@ -0,0 +1,49 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["RunListParams"]
+
+
+class RunListParams(TypedDict, total=False):
+ agent_id: Annotated[str, PropertyInfo(alias="agentId")]
+ """Only return runs that reference this agent ID."""
+
+ cursor: str
+ """Pagination cursor.
+
+ Pass the nextCursor from the previous response to fetch the next page. Omit to
+ start from the first page.
+ """
+
+ end_at: Annotated[Union[str, datetime], PropertyInfo(alias="endAt", format="iso8601")]
+ """Only return runs created on or before this timestamp (inclusive).
+
+ ISO 8601 / RFC 3339, e.g. 2026-01-20T00:00:00Z.
+ """
+
+ limit: int
+ """Maximum number of results to return."""
+
+ start_at: Annotated[Union[str, datetime], PropertyInfo(alias="startAt", format="iso8601")]
+ """Only return runs created on or after this timestamp (inclusive).
+
+ ISO 8601 / RFC 3339, e.g. 2026-01-19T00:00:00Z.
+ """
+
+ status: Literal["PENDING", "RUNNING", "COMPLETED", "FAILED", "STOPPED", "TIMED_OUT"]
+ """Current status of the run.
+
+ - `PENDING` - agent will run soon
+ - `RUNNING` - agent is currently running
+ - `COMPLETED` - agent has finished running
+ - `FAILED` - agent has failed the run
+ - `STOPPED` - run was stopped by the user
+ - `TIMED_OUT` - run exceeded maximum time
+ """
diff --git a/src/browserbase/types/agents/run_list_response.py b/src/browserbase/types/agents/run_list_response.py
new file mode 100644
index 0000000..5e711f4
--- /dev/null
+++ b/src/browserbase/types/agents/run_list_response.py
@@ -0,0 +1,93 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["RunListResponse", "Data", "DataCause"]
+
+
+class DataCause(BaseModel):
+ code: str
+ """Structured failure code (e.g., RUNNER_HEARTBEAT_LOST)."""
+
+ message: Optional[str] = None
+ """Human-readable failure detail."""
+
+
+class Data(BaseModel):
+ """One execution of an agent against a task.
+
+ Created in `pending` and transitioned through `running` → `completed`/`failed` by the runner.
+ """
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ run_id: str = FieldInfo(alias="runId")
+ """Unique identifier for the run."""
+
+ status: Literal["PENDING", "RUNNING", "COMPLETED", "FAILED", "STOPPED", "TIMED_OUT"]
+ """Current status of the run.
+
+ - `PENDING` - agent will run soon
+ - `RUNNING` - agent is currently running
+ - `COMPLETED` - agent has finished running
+ - `FAILED` - agent has failed the run
+ - `STOPPED` - run was stopped by the user
+ - `TIMED_OUT` - run exceeded maximum time
+ """
+
+ task: str
+ """The original task description."""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+ agent_id: Optional[str] = FieldInfo(alias="agentId", default=None)
+ """The ID of the agent applied to this run, if any. Omitted for ad-hoc runs."""
+
+ cause: Optional[DataCause] = None
+
+ ended_at: Optional[datetime] = FieldInfo(alias="endedAt", default=None)
+
+ result: Optional[Dict[str, object]] = None
+ """The agent's structured result for the run.
+
+ Only present when the run has finished and output is available. The result
+ conforms to the provided [JSON Schema](https://json-schema.org/specification)
+ when one is set.
+ """
+
+ result_schema: Optional[Dict[str, object]] = FieldInfo(alias="resultSchema", default=None)
+ """
+ Per-run [JSON Schema](https://json-schema.org/specification) override for the
+ result shape. When unset, the agent's default `resultSchema` applies.
+ """
+
+ sandbox_id: Optional[str] = FieldInfo(alias="sandboxId", default=None)
+ """External sandbox identifier assigned by the runner. Optional."""
+
+ session_id: Optional[str] = FieldInfo(alias="sessionId", default=None)
+ """The Browserbase session ID powering this run."""
+
+ started_at: Optional[datetime] = FieldInfo(alias="startedAt", default=None)
+
+
+class RunListResponse(BaseModel):
+ """A page of agent runs."""
+
+ data: List[Data]
+ """The page of matching agent runs."""
+
+ limit: int
+ """The maximum number of results returned in this page."""
+
+ next_cursor: Optional[str] = FieldInfo(alias="nextCursor", default=None)
+ """Cursor for the next page.
+
+ Pass it back as `cursor` on the next request to continue paging. null when there
+ are no more results.
+ """
diff --git a/src/browserbase/types/agents/run_retrieve_response.py b/src/browserbase/types/agents/run_retrieve_response.py
new file mode 100644
index 0000000..0706046
--- /dev/null
+++ b/src/browserbase/types/agents/run_retrieve_response.py
@@ -0,0 +1,76 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["RunRetrieveResponse", "Cause"]
+
+
+class Cause(BaseModel):
+ code: str
+ """Structured failure code (e.g., RUNNER_HEARTBEAT_LOST)."""
+
+ message: Optional[str] = None
+ """Human-readable failure detail."""
+
+
+class RunRetrieveResponse(BaseModel):
+ """One execution of an agent against a task.
+
+ Created in `pending` and transitioned through `running` → `completed`/`failed` by the runner.
+ """
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ run_id: str = FieldInfo(alias="runId")
+ """Unique identifier for the run."""
+
+ status: Literal["PENDING", "RUNNING", "COMPLETED", "FAILED", "STOPPED", "TIMED_OUT"]
+ """Current status of the run.
+
+ - `PENDING` - agent will run soon
+ - `RUNNING` - agent is currently running
+ - `COMPLETED` - agent has finished running
+ - `FAILED` - agent has failed the run
+ - `STOPPED` - run was stopped by the user
+ - `TIMED_OUT` - run exceeded maximum time
+ """
+
+ task: str
+ """The original task description."""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+ agent_id: Optional[str] = FieldInfo(alias="agentId", default=None)
+ """The ID of the agent applied to this run, if any. Omitted for ad-hoc runs."""
+
+ cause: Optional[Cause] = None
+
+ ended_at: Optional[datetime] = FieldInfo(alias="endedAt", default=None)
+
+ result: Optional[Dict[str, object]] = None
+ """The agent's structured result for the run.
+
+ Only present when the run has finished and output is available. The result
+ conforms to the provided [JSON Schema](https://json-schema.org/specification)
+ when one is set.
+ """
+
+ result_schema: Optional[Dict[str, object]] = FieldInfo(alias="resultSchema", default=None)
+ """
+ Per-run [JSON Schema](https://json-schema.org/specification) override for the
+ result shape. When unset, the agent's default `resultSchema` applies.
+ """
+
+ sandbox_id: Optional[str] = FieldInfo(alias="sandboxId", default=None)
+ """External sandbox identifier assigned by the runner. Optional."""
+
+ session_id: Optional[str] = FieldInfo(alias="sessionId", default=None)
+ """The Browserbase session ID powering this run."""
+
+ started_at: Optional[datetime] = FieldInfo(alias="startedAt", default=None)
diff --git a/src/browserbase/types/session_create_params.py b/src/browserbase/types/session_create_params.py
index 2d0d39a..b01d447 100644
--- a/src/browserbase/types/session_create_params.py
+++ b/src/browserbase/types/session_create_params.py
@@ -90,6 +90,18 @@ class BrowserSettings(TypedDict, total=False):
advanced_stealth: Annotated[bool, PropertyInfo(alias="advancedStealth")]
"""Advanced Browser Stealth Mode"""
+ allowed_domains: Annotated[SequenceNotStr[str], PropertyInfo(alias="allowedDomains")]
+ """An optional list of allowed domains for the session.
+
+ If you pass one or more domains, Browserbase restricts top-level (main-frame)
+ page navigations to the listed domains and their subdomains. For example,
+ `example.com` also permits `www.example.com` and `a.b.example.com`, but not
+ `notexample.com`. Matching is domain-based, not full-URL. An empty list (the
+ default) disables the restriction entirely. Browserbase enforces only main-frame
+ navigations; it does not block iframe/subframe loads or other in-page resource
+ requests (images, scripts, XHR, etc.).
+ """
+
block_ads: Annotated[bool, PropertyInfo(alias="blockAds")]
"""Enable or disable ad blocking in the browser. Defaults to `false`."""
diff --git a/tests/api_resources/agents/__init__.py b/tests/api_resources/agents/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /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/test_runs.py b/tests/api_resources/agents/test_runs.py
new file mode 100644
index 0000000..b491203
--- /dev/null
+++ b/tests/api_resources/agents/test_runs.py
@@ -0,0 +1,384 @@
+# 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 browserbase import Browserbase, AsyncBrowserbase
+from tests.utils import assert_matches_type
+from browserbase._utils import parse_datetime
+from browserbase.types.agents import (
+ RunListResponse,
+ RunCreateResponse,
+ RunRetrieveResponse,
+ RunListMessagesResponse,
+)
+
+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"])
+
+ @parametrize
+ def test_method_create(self, client: Browserbase) -> None:
+ run = client.agents.runs.create(
+ task="x",
+ )
+ assert_matches_type(RunCreateResponse, run, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Browserbase) -> None:
+ run = client.agents.runs.create(
+ task="x",
+ agent_id="agentId",
+ browser_settings={
+ "context": {
+ "id": "id",
+ "persist": True,
+ },
+ "proxies": True,
+ "verified": True,
+ },
+ result_schema={"foo": "bar"},
+ variables={
+ "foo": {
+ "value": "value",
+ "description": "description",
+ }
+ },
+ )
+ assert_matches_type(RunCreateResponse, run, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Browserbase) -> None:
+ response = client.agents.runs.with_raw_response.create(
+ task="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ run = response.parse()
+ assert_matches_type(RunCreateResponse, run, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Browserbase) -> None:
+ with client.agents.runs.with_streaming_response.create(
+ task="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ run = response.parse()
+ assert_matches_type(RunCreateResponse, run, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retrieve(self, client: Browserbase) -> None:
+ run = client.agents.runs.retrieve(
+ "runId",
+ )
+ assert_matches_type(RunRetrieveResponse, run, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Browserbase) -> None:
+ response = client.agents.runs.with_raw_response.retrieve(
+ "runId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ run = response.parse()
+ assert_matches_type(RunRetrieveResponse, run, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Browserbase) -> None:
+ with client.agents.runs.with_streaming_response.retrieve(
+ "runId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ run = response.parse()
+ assert_matches_type(RunRetrieveResponse, run, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: Browserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"):
+ client.agents.runs.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Browserbase) -> None:
+ run = client.agents.runs.list()
+ assert_matches_type(RunListResponse, run, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Browserbase) -> None:
+ run = client.agents.runs.list(
+ agent_id="agentId",
+ cursor="cursor",
+ end_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ limit=1,
+ start_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ status="PENDING",
+ )
+ assert_matches_type(RunListResponse, run, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Browserbase) -> None:
+ response = client.agents.runs.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ run = response.parse()
+ assert_matches_type(RunListResponse, run, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Browserbase) -> None:
+ with client.agents.runs.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ run = response.parse()
+ assert_matches_type(RunListResponse, run, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_list_messages(self, client: Browserbase) -> None:
+ run = client.agents.runs.list_messages(
+ run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(RunListMessagesResponse, run, path=["response"])
+
+ @parametrize
+ def test_method_list_messages_with_all_params(self, client: Browserbase) -> None:
+ run = client.agents.runs.list_messages(
+ run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ all=True,
+ limit=1,
+ since="since",
+ )
+ assert_matches_type(RunListMessagesResponse, run, path=["response"])
+
+ @parametrize
+ def test_raw_response_list_messages(self, client: Browserbase) -> None:
+ response = client.agents.runs.with_raw_response.list_messages(
+ run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ run = response.parse()
+ assert_matches_type(RunListMessagesResponse, run, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list_messages(self, client: Browserbase) -> None:
+ with client.agents.runs.with_streaming_response.list_messages(
+ run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ run = response.parse()
+ assert_matches_type(RunListMessagesResponse, run, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list_messages(self, client: Browserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"):
+ client.agents.runs.with_raw_response.list_messages(
+ run_id="",
+ )
+
+
+class TestAsyncRuns:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncBrowserbase) -> None:
+ run = await async_client.agents.runs.create(
+ task="x",
+ )
+ assert_matches_type(RunCreateResponse, run, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncBrowserbase) -> None:
+ run = await async_client.agents.runs.create(
+ task="x",
+ agent_id="agentId",
+ browser_settings={
+ "context": {
+ "id": "id",
+ "persist": True,
+ },
+ "proxies": True,
+ "verified": True,
+ },
+ result_schema={"foo": "bar"},
+ variables={
+ "foo": {
+ "value": "value",
+ "description": "description",
+ }
+ },
+ )
+ assert_matches_type(RunCreateResponse, run, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.runs.with_raw_response.create(
+ task="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ run = await response.parse()
+ assert_matches_type(RunCreateResponse, run, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.runs.with_streaming_response.create(
+ task="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ run = await response.parse()
+ assert_matches_type(RunCreateResponse, run, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncBrowserbase) -> None:
+ run = await async_client.agents.runs.retrieve(
+ "runId",
+ )
+ assert_matches_type(RunRetrieveResponse, run, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.runs.with_raw_response.retrieve(
+ "runId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ run = await response.parse()
+ assert_matches_type(RunRetrieveResponse, run, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.runs.with_streaming_response.retrieve(
+ "runId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ run = await response.parse()
+ assert_matches_type(RunRetrieveResponse, run, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncBrowserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"):
+ await async_client.agents.runs.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncBrowserbase) -> None:
+ run = await async_client.agents.runs.list()
+ assert_matches_type(RunListResponse, run, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncBrowserbase) -> None:
+ run = await async_client.agents.runs.list(
+ agent_id="agentId",
+ cursor="cursor",
+ end_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ limit=1,
+ start_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ status="PENDING",
+ )
+ assert_matches_type(RunListResponse, run, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.runs.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ run = await response.parse()
+ assert_matches_type(RunListResponse, run, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.runs.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ run = await response.parse()
+ assert_matches_type(RunListResponse, run, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_list_messages(self, async_client: AsyncBrowserbase) -> None:
+ run = await async_client.agents.runs.list_messages(
+ run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(RunListMessagesResponse, run, path=["response"])
+
+ @parametrize
+ async def test_method_list_messages_with_all_params(self, async_client: AsyncBrowserbase) -> None:
+ run = await async_client.agents.runs.list_messages(
+ run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ all=True,
+ limit=1,
+ since="since",
+ )
+ assert_matches_type(RunListMessagesResponse, run, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list_messages(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.runs.with_raw_response.list_messages(
+ run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ run = await response.parse()
+ assert_matches_type(RunListMessagesResponse, run, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list_messages(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.runs.with_streaming_response.list_messages(
+ run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ run = await response.parse()
+ assert_matches_type(RunListMessagesResponse, run, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list_messages(self, async_client: AsyncBrowserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"):
+ await async_client.agents.runs.with_raw_response.list_messages(
+ run_id="",
+ )
diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py
new file mode 100644
index 0000000..2521848
--- /dev/null
+++ b/tests/api_resources/test_agents.py
@@ -0,0 +1,428 @@
+# 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 browserbase import Browserbase, AsyncBrowserbase
+from tests.utils import assert_matches_type
+from browserbase.types import (
+ AgentListResponse,
+ AgentCreateResponse,
+ AgentUpdateResponse,
+ AgentRetrieveResponse,
+)
+from browserbase._utils import parse_datetime
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAgents:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Browserbase) -> None:
+ agent = client.agents.create(
+ name="x",
+ )
+ assert_matches_type(AgentCreateResponse, agent, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Browserbase) -> None:
+ agent = client.agents.create(
+ name="x",
+ result_schema={"foo": "bar"},
+ system_prompt="x",
+ )
+ assert_matches_type(AgentCreateResponse, agent, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Browserbase) -> None:
+ response = client.agents.with_raw_response.create(
+ name="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = response.parse()
+ assert_matches_type(AgentCreateResponse, agent, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Browserbase) -> None:
+ with client.agents.with_streaming_response.create(
+ name="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = response.parse()
+ assert_matches_type(AgentCreateResponse, agent, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retrieve(self, client: Browserbase) -> None:
+ agent = client.agents.retrieve(
+ "agentId",
+ )
+ assert_matches_type(AgentRetrieveResponse, agent, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Browserbase) -> None:
+ response = client.agents.with_raw_response.retrieve(
+ "agentId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = response.parse()
+ assert_matches_type(AgentRetrieveResponse, agent, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Browserbase) -> None:
+ with client.agents.with_streaming_response.retrieve(
+ "agentId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = response.parse()
+ assert_matches_type(AgentRetrieveResponse, agent, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: Browserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `agent_id` but received ''"):
+ client.agents.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_update(self, client: Browserbase) -> None:
+ agent = client.agents.update(
+ agent_id="agentId",
+ )
+ assert_matches_type(AgentUpdateResponse, agent, path=["response"])
+
+ @parametrize
+ def test_method_update_with_all_params(self, client: Browserbase) -> None:
+ agent = client.agents.update(
+ agent_id="agentId",
+ name="x",
+ result_schema={"foo": "bar"},
+ system_prompt="x",
+ )
+ assert_matches_type(AgentUpdateResponse, agent, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: Browserbase) -> None:
+ response = client.agents.with_raw_response.update(
+ agent_id="agentId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = response.parse()
+ assert_matches_type(AgentUpdateResponse, agent, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: Browserbase) -> None:
+ with client.agents.with_streaming_response.update(
+ agent_id="agentId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = response.parse()
+ assert_matches_type(AgentUpdateResponse, agent, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: Browserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `agent_id` but received ''"):
+ client.agents.with_raw_response.update(
+ agent_id="",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Browserbase) -> None:
+ agent = client.agents.list()
+ assert_matches_type(AgentListResponse, agent, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Browserbase) -> None:
+ agent = client.agents.list(
+ cursor="cursor",
+ end_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ limit=1,
+ start_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ )
+ assert_matches_type(AgentListResponse, agent, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Browserbase) -> None:
+ response = client.agents.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = response.parse()
+ assert_matches_type(AgentListResponse, agent, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Browserbase) -> None:
+ with client.agents.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = response.parse()
+ assert_matches_type(AgentListResponse, agent, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_delete(self, client: Browserbase) -> None:
+ agent = client.agents.delete(
+ "agentId",
+ )
+ assert agent is None
+
+ @parametrize
+ def test_raw_response_delete(self, client: Browserbase) -> None:
+ response = client.agents.with_raw_response.delete(
+ "agentId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = response.parse()
+ assert agent is None
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Browserbase) -> None:
+ with client.agents.with_streaming_response.delete(
+ "agentId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = response.parse()
+ assert agent is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: Browserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `agent_id` but received ''"):
+ client.agents.with_raw_response.delete(
+ "",
+ )
+
+
+class TestAsyncAgents:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncBrowserbase) -> None:
+ agent = await async_client.agents.create(
+ name="x",
+ )
+ assert_matches_type(AgentCreateResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncBrowserbase) -> None:
+ agent = await async_client.agents.create(
+ name="x",
+ result_schema={"foo": "bar"},
+ system_prompt="x",
+ )
+ assert_matches_type(AgentCreateResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.with_raw_response.create(
+ name="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = await response.parse()
+ assert_matches_type(AgentCreateResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.with_streaming_response.create(
+ name="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = await response.parse()
+ assert_matches_type(AgentCreateResponse, agent, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncBrowserbase) -> None:
+ agent = await async_client.agents.retrieve(
+ "agentId",
+ )
+ assert_matches_type(AgentRetrieveResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.with_raw_response.retrieve(
+ "agentId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = await response.parse()
+ assert_matches_type(AgentRetrieveResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.with_streaming_response.retrieve(
+ "agentId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = await response.parse()
+ assert_matches_type(AgentRetrieveResponse, agent, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncBrowserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `agent_id` but received ''"):
+ await async_client.agents.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncBrowserbase) -> None:
+ agent = await async_client.agents.update(
+ agent_id="agentId",
+ )
+ assert_matches_type(AgentUpdateResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncBrowserbase) -> None:
+ agent = await async_client.agents.update(
+ agent_id="agentId",
+ name="x",
+ result_schema={"foo": "bar"},
+ system_prompt="x",
+ )
+ assert_matches_type(AgentUpdateResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.with_raw_response.update(
+ agent_id="agentId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = await response.parse()
+ assert_matches_type(AgentUpdateResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.with_streaming_response.update(
+ agent_id="agentId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = await response.parse()
+ assert_matches_type(AgentUpdateResponse, agent, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncBrowserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `agent_id` but received ''"):
+ await async_client.agents.with_raw_response.update(
+ agent_id="",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncBrowserbase) -> None:
+ agent = await async_client.agents.list()
+ assert_matches_type(AgentListResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncBrowserbase) -> None:
+ agent = await async_client.agents.list(
+ cursor="cursor",
+ end_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ limit=1,
+ start_at=parse_datetime("2019-12-27T18:11:19.117Z"),
+ )
+ assert_matches_type(AgentListResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = await response.parse()
+ assert_matches_type(AgentListResponse, agent, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = await response.parse()
+ assert_matches_type(AgentListResponse, agent, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncBrowserbase) -> None:
+ agent = await async_client.agents.delete(
+ "agentId",
+ )
+ assert agent is None
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncBrowserbase) -> None:
+ response = await async_client.agents.with_raw_response.delete(
+ "agentId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ agent = await response.parse()
+ assert agent is None
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncBrowserbase) -> None:
+ async with async_client.agents.with_streaming_response.delete(
+ "agentId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ agent = await response.parse()
+ assert agent is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncBrowserbase) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `agent_id` but received ''"):
+ await async_client.agents.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/test_sessions.py b/tests/api_resources/test_sessions.py
index fe6d486..f83f3d2 100644
--- a/tests/api_resources/test_sessions.py
+++ b/tests/api_resources/test_sessions.py
@@ -33,6 +33,7 @@ def test_method_create_with_all_params(self, client: Browserbase) -> None:
session = client.sessions.create(
browser_settings={
"advanced_stealth": True,
+ "allowed_domains": ["string"],
"block_ads": True,
"captcha_image_selector": "captchaImageSelector",
"captcha_input_selector": "captchaInputSelector",
@@ -269,6 +270,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncBrowserbas
session = await async_client.sessions.create(
browser_settings={
"advanced_stealth": True,
+ "allowed_domains": ["string"],
"block_ads": True,
"captcha_image_selector": "captchaImageSelector",
"captcha_input_selector": "captchaInputSelector",