Skip to content

Commit 3047ea8

Browse files
release: 2.4.0 (#17)
Automated Release PR --- ## 2.4.0 (2026-04-10) Full Changelog: [v2.3.0...v2.4.0](v2.3.0...v2.4.0) ### Features * **api:** add input endpoint ([f3b1f16](f3b1f16)) * **api:** api update ([cda5c19](cda5c19)) * **api:** api update ([ed80ce0](ed80ce0)) * **api:** better handling of SSE events ([6b6ba7b](6b6ba7b)) * **internal:** implement indices array format for query and form serialization ([97a9bb7](97a9bb7)) ### Bug Fixes * **client:** preserve hardcoded query params when merging with user params ([2cda6ae](2cda6ae)) * **deps:** bump minimum typing-extensions version ([1946504](1946504)) * ensure file data are only sent as 1 parameter ([10f77bc](10f77bc)) * **pydantic:** do not pass `by_alias` unless set ([a32962e](a32962e)) * sanitize endpoint path params ([f4632c7](f4632c7)) ### Chores * **ci:** skip lint on metadata-only changes ([9710840](9710840)) * configure new SDK language ([f5f587a](f5f587a)) * **internal:** tweak CI branches ([8458777](8458777)) * **internal:** update gitignore ([e39102c](e39102c)) --- This pull request is managed by Stainless's [GitHub App](https://github.com/apps/stainless-app). The [semver version number](https://semver.org/#semantic-versioning-specification-semver) is based on included [commit messages](https://www.conventionalcommits.org/en/v1.0.0/). Alternatively, you can manually set the version number in the title of this pull request. For a better experience, it is recommended to use either rebase-merge or squash-merge when merging this pull request. 🔗 Stainless [website](https://www.stainlessapi.com) 📚 Read the [docs](https://app.stainlessapi.com/docs) 🙋 [Reach out](mailto:support@stainlessapi.com) for help or questions --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent cfe2d44 commit 3047ea8

30 files changed

+687
-36
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
name: CI
22
on:
33
push:
4-
branches-ignore:
5-
- 'generated'
6-
- 'codegen/**'
7-
- 'integrated/**'
8-
- 'stl-preview-head/**'
9-
- 'stl-preview-base/**'
4+
branches:
5+
- '**'
6+
- '!integrated/**'
7+
- '!stl-preview-head/**'
8+
- '!stl-preview-base/**'
9+
- '!generated'
10+
- '!codegen/**'
11+
- 'codegen/stl/**'
1012
pull_request:
1113
branches-ignore:
1214
- 'stl-preview-head/**'
@@ -17,7 +19,7 @@ jobs:
1719
timeout-minutes: 10
1820
name: lint
1921
runs-on: ${{ github.repository == 'stainless-sdks/tabstack-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
20-
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
22+
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
2123
steps:
2224
- uses: actions/checkout@v6
2325

@@ -33,7 +35,7 @@ jobs:
3335
run: ./scripts/lint
3436

3537
build:
36-
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
38+
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
3739
timeout-minutes: 10
3840
name: build
3941
permissions:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.prism.log
2+
.stdy.log
23
_dev
34

45
__pycache__

.release-please-manifest.json

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

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 5
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/mozilla%2Ftabstack-8f80078ef30bc395d44843f9ce076188ba43a297e158d5f3672c45dc814ffcf0.yml
3-
openapi_spec_hash: c615a817dcb27c55bd15b9b9346669c2
4-
config_hash: 6b388b673b2a48895ab10da245fb6771
1+
configured_endpoints: 6
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/mozilla%2Ftabstack-ab135cad4c10edc98bbe45d18a1ca23d2d4aa4b2ba2e4554e6991e322ce46231.yml
3+
openapi_spec_hash: 3e8185dfbbd4e83d5f05ded9ce9c5b06
4+
config_hash: 57c64e5e8fe99c1bd7af536d82af4ad9

CHANGELOG.md

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

3+
## 2.4.0 (2026-04-10)
4+
5+
Full Changelog: [v2.3.0...v2.4.0](https://github.com/Mozilla-Ocho/tabstack-python/compare/v2.3.0...v2.4.0)
6+
7+
### Features
8+
9+
* **api:** add input endpoint ([f3b1f16](https://github.com/Mozilla-Ocho/tabstack-python/commit/f3b1f16204c0d724193815c5e34100831f0a2653))
10+
* **api:** api update ([cda5c19](https://github.com/Mozilla-Ocho/tabstack-python/commit/cda5c19baedee455072a8071cb2741714a9ded19))
11+
* **api:** api update ([ed80ce0](https://github.com/Mozilla-Ocho/tabstack-python/commit/ed80ce06975480e8466b18b75397ee3c761f6398))
12+
* **api:** better handling of SSE events ([6b6ba7b](https://github.com/Mozilla-Ocho/tabstack-python/commit/6b6ba7b5b6a6aba119a6caf6aec3af5ff5c6350b))
13+
* **internal:** implement indices array format for query and form serialization ([97a9bb7](https://github.com/Mozilla-Ocho/tabstack-python/commit/97a9bb7241ad0c7a98483d81f74bbb5ee40e1b93))
14+
15+
16+
### Bug Fixes
17+
18+
* **client:** preserve hardcoded query params when merging with user params ([2cda6ae](https://github.com/Mozilla-Ocho/tabstack-python/commit/2cda6aeb86a50115ba347549452c57700e810679))
19+
* **deps:** bump minimum typing-extensions version ([1946504](https://github.com/Mozilla-Ocho/tabstack-python/commit/194650472a951f76bd180e1dd08507fcf2670577))
20+
* ensure file data are only sent as 1 parameter ([10f77bc](https://github.com/Mozilla-Ocho/tabstack-python/commit/10f77bcad1e0ea05151f291bf55b17a04512465a))
21+
* **pydantic:** do not pass `by_alias` unless set ([a32962e](https://github.com/Mozilla-Ocho/tabstack-python/commit/a32962e54563d7073726b4463d70017fc2a40331))
22+
* sanitize endpoint path params ([f4632c7](https://github.com/Mozilla-Ocho/tabstack-python/commit/f4632c74a42a3ea56998e6f9d9afacace4bd4a5c))
23+
24+
25+
### Chores
26+
27+
* **ci:** skip lint on metadata-only changes ([9710840](https://github.com/Mozilla-Ocho/tabstack-python/commit/97108400820fbe715dcb922c997b87b612bf588e))
28+
* configure new SDK language ([f5f587a](https://github.com/Mozilla-Ocho/tabstack-python/commit/f5f587ab07a757e4ada42e6bc3c802f29591c536))
29+
* **internal:** tweak CI branches ([8458777](https://github.com/Mozilla-Ocho/tabstack-python/commit/8458777f42fdbdc611d213513b1e7f026886ba42))
30+
* **internal:** update gitignore ([e39102c](https://github.com/Mozilla-Ocho/tabstack-python/commit/e39102cd8c44fbbaec52a5bed74a11deab25b97f))
31+
332
## 2.3.0 (2026-03-12)
433

534
Full Changelog: [v2.2.0...v2.3.0](https://github.com/Mozilla-Ocho/tabstack-python/compare/v2.2.0...v2.3.0)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ It is generated with [Stainless](https://www.stainless.com/).
1313

1414
Use the Tabstack MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.
1515

16-
[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40tabstack%2Fmcp&config=eyJuYW1lIjoiQHRhYnN0YWNrL21jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL3RhYnN0YWNrLnN0bG1jcC5jb20iLCJoZWFkZXJzIjp7IngtdGFic3RhY2stYXBpLWtleSI6Ik15IEFQSSBLZXkifX0)
17-
[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40tabstack%2Fmcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Ftabstack.stlmcp.com%22%2C%22headers%22%3A%7B%22x-tabstack-api-key%22%3A%22My%20API%20Key%22%7D%7D)
16+
[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40tabstack%2Fsdk-mcp&config=eyJuYW1lIjoiQHRhYnN0YWNrL3Nkay1tY3AiLCJ0cmFuc3BvcnQiOiJodHRwIiwidXJsIjoiaHR0cHM6Ly90YWJzdGFjay5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LXRhYnN0YWNrLWFwaS1rZXkiOiJNeSBBUEkgS2V5In19)
17+
[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40tabstack%2Fsdk-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Ftabstack.stlmcp.com%22%2C%22headers%22%3A%7B%22x-tabstack-api-key%22%3A%22My%20API%20Key%22%7D%7D)
1818

1919
> Note: You may need to set environment variables in your MCP client.
2020

api.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
Types:
44

55
```python
6-
from tabstack.types import AutomateEvent, ResearchEvent
6+
from tabstack.types import AutomateEvent, ResearchEvent, AgentAutomateInputResponse
77
```
88

99
Methods:
1010

1111
- <code title="post /automate">client.agent.<a href="./src/tabstack/resources/agent.py">automate</a>(\*\*<a href="src/tabstack/types/agent_automate_params.py">params</a>) -> <a href="./src/tabstack/types/automate_event.py">AutomateEvent</a></code>
12+
- <code title="post /automate/{requestID}/input">client.agent.<a href="./src/tabstack/resources/agent.py">automate_input</a>(request_id, \*\*<a href="src/tabstack/types/agent_automate_input_params.py">params</a>) -> <a href="./src/tabstack/types/agent_automate_input_response.py">AgentAutomateInputResponse</a></code>
1213
- <code title="post /research">client.agent.<a href="./src/tabstack/resources/agent.py">research</a>(\*\*<a href="src/tabstack/types/agent_research_params.py">params</a>) -> <a href="./src/tabstack/types/research_event.py">ResearchEvent</a></code>
1314

1415
# Extract

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "tabstack"
3-
version = "2.3.0"
3+
version = "2.4.0"
44
description = "The official Python library for the tabstack API"
55
dynamic = ["readme"]
66
license = "Apache-2.0"
@@ -11,7 +11,7 @@ authors = [
1111
dependencies = [
1212
"httpx>=0.23.0, <1",
1313
"pydantic>=1.9.0, <3",
14-
"typing-extensions>=4.10, <5",
14+
"typing-extensions>=4.14, <5",
1515
"anyio>=3.5.0, <5",
1616
"distro>=1.7.0, <2",
1717
"sniffio",

src/tabstack/_base_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,10 @@ def _build_request(
540540
files = cast(HttpxRequestFiles, ForceMultipartDict())
541541

542542
prepared_url = self._prepare_url(options.url)
543+
# preserve hard-coded query params from the url
544+
if params and prepared_url.query:
545+
params = {**dict(prepared_url.params.items()), **params}
546+
prepared_url = prepared_url.copy_with(raw_path=prepared_url.raw_path.split(b"?", 1)[0])
543547
if "_" in prepared_url.host:
544548
# work around https://github.com/encode/httpx/discussions/2880
545549
kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")}
@@ -1952,6 +1956,7 @@ def make_request_options(
19521956
idempotency_key: str | None = None,
19531957
timeout: float | httpx.Timeout | None | NotGiven = not_given,
19541958
post_parser: PostParser | NotGiven = not_given,
1959+
synthesize_event_and_data: bool | None = None,
19551960
) -> RequestOptions:
19561961
"""Create a dict of type RequestOptions without keys of NotGiven values."""
19571962
options: RequestOptions = {}
@@ -1977,6 +1982,9 @@ def make_request_options(
19771982
# internal
19781983
options["post_parser"] = post_parser # type: ignore
19791984

1985+
if synthesize_event_and_data is not None:
1986+
options["synthesize_event_and_data"] = synthesize_event_and_data
1987+
19801988
return options
19811989

19821990

src/tabstack/_compat.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload
44
from datetime import date, datetime
5-
from typing_extensions import Self, Literal
5+
from typing_extensions import Self, Literal, TypedDict
66

77
import pydantic
88
from pydantic.fields import FieldInfo
@@ -131,6 +131,10 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str:
131131
return model.model_dump_json(indent=indent)
132132

133133

134+
class _ModelDumpKwargs(TypedDict, total=False):
135+
by_alias: bool
136+
137+
134138
def model_dump(
135139
model: pydantic.BaseModel,
136140
*,
@@ -142,14 +146,17 @@ def model_dump(
142146
by_alias: bool | None = None,
143147
) -> dict[str, Any]:
144148
if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
149+
kwargs: _ModelDumpKwargs = {}
150+
if by_alias is not None:
151+
kwargs["by_alias"] = by_alias
145152
return model.model_dump(
146153
mode=mode,
147154
exclude=exclude,
148155
exclude_unset=exclude_unset,
149156
exclude_defaults=exclude_defaults,
150157
# warnings are not supported in Pydantic v1
151158
warnings=True if PYDANTIC_V1 else warnings,
152-
by_alias=by_alias,
159+
**kwargs,
153160
)
154161
return cast(
155162
"dict[str, Any]",

0 commit comments

Comments
 (0)