Skip to content

Commit 763131a

Browse files
release: 3.19.0 (#325)
* feat(internal): implement indices array format for query and form serialization * STG-1537 default local-mode sessions to local browser * release: 3.19.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: monadoid <sam.finton@gmail.com> Co-authored-by: Sam F <43347795+monadoid@users.noreply.github.com>
1 parent dfc4a7a commit 763131a

File tree

7 files changed

+62
-4
lines changed

7 files changed

+62
-4
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "3.18.0"
2+
".": "3.19.0"
33
}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## 3.19.0 (2026-03-27)
4+
5+
Full Changelog: [v3.18.0...v3.19.0](https://github.com/browserbase/stagehand-python/compare/v3.18.0...v3.19.0)
6+
7+
### Features
8+
9+
* **internal:** implement indices array format for query and form serialization ([b2cccf5](https://github.com/browserbase/stagehand-python/commit/b2cccf56bc7e99d7869b8ed9339956a9f160348a))
10+
311
## 3.18.0 (2026-03-25)
412

513
Full Changelog: [v3.7.0...v3.18.0](https://github.com/browserbase/stagehand-python/compare/v3.7.0...v3.18.0)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "stagehand"
3-
version = "3.18.0"
3+
version = "3.19.0"
44
description = "The official Python library for the stagehand API"
55
dynamic = ["readme"]
66
license = "MIT"

src/stagehand/_qs.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,10 @@ def _stringify_item(
101101
items.extend(self._stringify_item(key, item, opts))
102102
return items
103103
elif array_format == "indices":
104-
raise NotImplementedError("The array indices format is not supported yet")
104+
items = []
105+
for i, item in enumerate(value):
106+
items.extend(self._stringify_item(f"{key}[{i}]", item, opts))
107+
return items
105108
elif array_format == "brackets":
106109
items = []
107110
key = key + "[]"

src/stagehand/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "stagehand"
4-
__version__ = "3.18.0" # x-release-please-version
4+
__version__ = "3.19.0" # x-release-please-version

src/stagehand/resources/sessions_helpers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ def start(
8383
extra_body: Body | None = None,
8484
timeout: float | httpx.Timeout | None | NotGiven = not_given,
8585
) -> Session:
86+
if browser is omit and getattr(self._client, "_server_mode", None) == "local":
87+
browser = {"type": "local"}
88+
8689
start_response = super().start(
8790
model_name=model_name,
8891
act_timeout_ms=act_timeout_ms,
@@ -136,6 +139,9 @@ async def start(
136139
extra_body: Body | None = None,
137140
timeout: float | httpx.Timeout | None | NotGiven = not_given,
138141
) -> AsyncSession:
142+
if browser is omit and getattr(self._client, "_server_mode", None) == "local":
143+
browser = {"type": "local"}
144+
139145
start_response: SessionStartResponse = await super().start(
140146
model_name=model_name,
141147
act_timeout_ms=act_timeout_ms,

tests/test_local_server.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
import json
4+
35
import httpx
46
import pytest
57
from respx import MockRouter
@@ -67,6 +69,45 @@ def test_sync_local_mode_starts_before_first_request(respx_mock: MockRouter, mon
6769
assert dummy.closed == 1
6870

6971

72+
@pytest.mark.respx(base_url="http://127.0.0.1:43127")
73+
def test_sync_local_mode_defaults_browser_type_local_when_omitted(
74+
respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
75+
) -> None:
76+
_set_required_env(monkeypatch)
77+
78+
dummy = _DummySeaServer("http://127.0.0.1:43127")
79+
request_body: dict[str, object] = {}
80+
81+
def _capture_start_request(request: httpx.Request) -> httpx.Response:
82+
request_body["json"] = json.loads(request.content.decode("utf-8"))
83+
return httpx.Response(
84+
200,
85+
json={
86+
"success": True,
87+
"data": {
88+
"available": True,
89+
"connectUrl": "ws://example",
90+
"sessionId": "00000000-0000-0000-0000-000000000001",
91+
},
92+
},
93+
)
94+
95+
respx_mock.post("/v1/sessions/start").mock(side_effect=_capture_start_request)
96+
97+
client = Stagehand(server="local", _local_stagehand_binary_path="/does/not/matter/in/test")
98+
client._sea_server = dummy # type: ignore[attr-defined]
99+
100+
resp = client.sessions.start(model_name="openai/gpt-5-nano")
101+
assert resp.success is True
102+
assert request_body["json"] == {
103+
"modelName": "openai/gpt-5-nano",
104+
"browser": {"type": "local"},
105+
}
106+
107+
client.close()
108+
assert dummy.closed == 1
109+
110+
70111
@pytest.mark.respx(base_url="http://127.0.0.1:43124")
71112
@pytest.mark.asyncio
72113
async def test_async_local_mode_starts_before_first_request(

0 commit comments

Comments
 (0)