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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "2.2.0"
".": "2.3.0-alpha.1"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 14
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/turbopuffer-benesch/turbopuffer-6717a82f2b22fd2b55bce7acb7d5e9a694c51132a5522626d39684bff6e0cb83.yml
openapi_spec_hash: 647e6105fbcaba7eaed15f1859f1c463
config_hash: 3917af929e17def75be204eb7e4000fa
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/turbopuffer-benesch/turbopuffer-ffcaae9b05de6560eb11bb0821cf4d6ebc06f1464c6d8258d79c1a0f2eda41fb.yml
openapi_spec_hash: 2ffbfcbe9c95eb73ef0be3dbef708e6a
config_hash: bab72dc9f937352c7a01a37dadd44122
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Changelog

## 2.3.0-alpha.1 (2026-06-02)

Full Changelog: [v2.2.0...v2.3.0-alpha.1](https://github.com/turbopuffer/turbopuffer-python/compare/v2.2.0...v2.3.0-alpha.1)

### Features

* openapi: spec for `rerank_by: ["RRF"]` ([80ab218](https://github.com/turbopuffer/turbopuffer-python/commit/80ab218582e9b4e78dd9fca42cdce6f2a76761cf))
* rename /docs/auth to /docs/overview ([1340eb1](https://github.com/turbopuffer/turbopuffer-python/commit/1340eb172500c78d9ce73bfe8ce557bcdb40c4d7))
* spec: add SDK support for native embedding ([ca71729](https://github.com/turbopuffer/turbopuffer-python/commit/ca71729755294ed2eb073453e33baa8c89548063))


### Bug Fixes

* reject malicious poll locations ([#236](https://github.com/turbopuffer/turbopuffer-python/issues/236)) ([3f6123a](https://github.com/turbopuffer/turbopuffer-python/commit/3f6123a88c2c3795f9eb4da31ef66eaa9081db18))
* type rerank_by parameter as RerankBy ([#239](https://github.com/turbopuffer/turbopuffer-python/issues/239)) ([6f07a95](https://github.com/turbopuffer/turbopuffer-python/commit/6f07a95860f5dff9b699776d7916606b5c6f7cab))


### Chores

* fix API docs links ([#235](https://github.com/turbopuffer/turbopuffer-python/issues/235)) ([204b46b](https://github.com/turbopuffer/turbopuffer-python/commit/204b46bf15c5694bdd38339b8471c46e16e697a0))

## 2.2.0 (2026-05-28)

Full Changelog: [v2.1.0...v2.2.0](https://github.com/turbopuffer/turbopuffer-python/compare/v2.1.0...v2.2.0)
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
<!-- prettier-ignore -->
<a href="https://pypi.org/project/turbopuffer/"><img src="https://img.shields.io/pypi/v/turbopuffer.svg?label=pypi%20(stable)" alt="PyPI version" align="right"></a>

The turbopuffer Python library provides convenient access to the Turbopuffer HTTP API from any Python 3.9+
The turbopuffer Python library provides convenient access to the [turbopuffer HTTP API](https://turbopuffer.com/docs/overview) from any Python 3.9+
application. The library includes type definitions for all request params and response fields,
and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).

It is generated with [Stainless](https://www.stainless.com/).

## MCP Server

Use the Turbopuffer 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.
Use the turbopuffer 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.

[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40turbopuffer%2Fturbopuffer-mcp&config=eyJuYW1lIjoiQHR1cmJvcHVmZmVyL3R1cmJvcHVmZmVyLW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL3R1cmJvcHVmZmVyLnN0bG1jcC5jb20iLCJoZWFkZXJzIjp7IngtdHVyYm9wdWZmZXItYXBpLWtleSI6InRwdWZfQTEuLi4ifX0)
[![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%40turbopuffer%2Fturbopuffer-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fturbopuffer.stlmcp.com%22%2C%22headers%22%3A%7B%22x-turbopuffer-api-key%22%3A%22tpuf_A1...%22%7D%7D)
Expand All @@ -20,13 +20,13 @@ Use the Turbopuffer MCP Server to enable AI assistants to interact with this API

## Documentation

The HTTP API documentation can be found at [turbopuffer.com/docs](https://turbopuffer.com/docs).
The HTTP API documentation can be found at [turbopuffer.com/docs/overview](https://turbopuffer.com/docs/overview).

## Installation

```sh
# install from PyPI
pip install turbopuffer
pip install --pre turbopuffer
```

## Usage
Expand Down Expand Up @@ -128,7 +128,7 @@ You can enable this by installing `aiohttp`:

```sh
# install from PyPI
pip install turbopuffer[aiohttp]
pip install --pre turbopuffer[aiohttp]
```

Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
Expand Down Expand Up @@ -172,7 +172,7 @@ Typed requests and responses provide autocomplete and documentation within your

## Pagination

List methods in the Turbopuffer API are paginated.
List methods in the turbopuffer API are paginated.

This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:

Expand Down
4 changes: 4 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Types:
from turbopuffer.types import (
AggregateBy,
AggregationGroup,
AttributeEmbed,
AttributeEmbedConfig,
AttributeSchema,
AttributeSchemaConfig,
AttributeType,
Expand All @@ -29,6 +31,7 @@ from turbopuffer.types import (
CopyFromNamespaceParams,
DecayParams,
DistanceMetric,
EmbedParams,
Encryption,
FullTextSearch,
FullTextSearchConfig,
Expand All @@ -44,6 +47,7 @@ from turbopuffer.types import (
QueryBilling,
QueryPerformance,
Row,
RrfParams,
SaturateParams,
SparseDistanceMetric,
Tokenizer,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "turbopuffer"
version = "2.2.0"
version = "2.3.0-alpha.1"
description = "The official Python library for the turbopuffer API"
dynamic = ["readme"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion scripts/gen
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -e

cd "$(dirname "$0")/.."

apigen_image=ghcr.io/turbopuffer/turbopuffer-apigen:864b25e7f396607f5fee302f6aed713afab55020
apigen_image=ghcr.io/turbopuffer/turbopuffer-apigen:1b58f2aa9172bf7a668bf862c271b852e95a846b

apigen() {
if [[ "$TURBOPUFFER_DEV_APIGEN" ]]; then
Expand Down
2 changes: 1 addition & 1 deletion src/turbopuffer/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "turbopuffer"
__version__ = "2.2.0" # x-release-please-version
__version__ = "2.3.0-alpha.1" # x-release-please-version
25 changes: 22 additions & 3 deletions src/turbopuffer/lib/respond_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,33 @@ def _respond_async_applied(response: httpx.Response) -> bool:


def _extract_location(response: httpx.Response) -> str:
location: str = response.headers.get(HEADER_LOCATION, "").strip()
if not location:
raw_location: str = response.headers.get(HEADER_LOCATION, "").strip()
if not raw_location:
raise APIResponseValidationError(
response=response,
body=response.text,
message="missing 'Location' header on respond-async response",
)
return location

orig = response.request.url
try:
# Resolve the Location against the original request URL.
location = orig.join(raw_location)
except httpx.InvalidURL as err:
raise APIResponseValidationError(
response=response,
body=response.text,
message=f"malformed 'Location' header: {raw_location!r}",
) from err

# Reject a Location pointing at a different origin, to prevent API key exfiltration.
if (location.scheme, location.host, location.port) != (orig.scheme, orig.host, orig.port):
raise APIResponseValidationError(
response=response,
body=response.text,
message=f"'Location' origin does not match request origin: {raw_location!r}",
)
return str(location)


class _PollError(BaseModel):
Expand Down
10 changes: 9 additions & 1 deletion src/turbopuffer/resources/namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)
from .._exceptions import NotFoundError
from .._base_client import make_request_options
from ..types.custom import Filter, RankBy, GroupBy, AggregateBy
from ..types.custom import Filter, RankBy, GroupBy, RerankBy, AggregateBy
from ..types.id_param import IDParam
from ..types.row_param import RowParam
from ..types.columns_param import ColumnsParam
Expand Down Expand Up @@ -376,6 +376,7 @@ def multi_query(
namespace: str | None = None,
queries: Iterable[namespace_multi_query_params.Query],
consistency: namespace_multi_query_params.Consistency | Omit = omit,
rerank_by: RerankBy | Omit = omit,
vector_encoding: VectorEncoding | 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.
Expand All @@ -390,6 +391,8 @@ def multi_query(
Args:
consistency: The consistency level for a query.

rerank_by: How to combine the rows returned by each sub-query into a single ranked list.

vector_encoding: The encoding to use for vectors in the response.

extra_headers: Send extra headers
Expand All @@ -410,6 +413,7 @@ def multi_query(
{
"queries": queries,
"consistency": consistency,
"rerank_by": rerank_by,
"vector_encoding": vector_encoding,
},
namespace_multi_query_params.NamespaceMultiQueryParams,
Expand Down Expand Up @@ -1131,6 +1135,7 @@ async def multi_query(
namespace: str | None = None,
queries: Iterable[namespace_multi_query_params.Query],
consistency: namespace_multi_query_params.Consistency | Omit = omit,
rerank_by: RerankBy | Omit = omit,
vector_encoding: VectorEncoding | 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.
Expand All @@ -1145,6 +1150,8 @@ async def multi_query(
Args:
consistency: The consistency level for a query.

rerank_by: How to combine the rows returned by each sub-query into a single ranked list.

vector_encoding: The encoding to use for vectors in the response.

extra_headers: Send extra headers
Expand All @@ -1165,6 +1172,7 @@ async def multi_query(
{
"queries": queries,
"consistency": consistency,
"rerank_by": rerank_by,
"vector_encoding": vector_encoding,
},
namespace_multi_query_params.NamespaceMultiQueryParams,
Expand Down
6 changes: 6 additions & 0 deletions src/turbopuffer/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@
from .row_param import RowParam as RowParam
from .tokenizer import Tokenizer as Tokenizer
from .encryption import Encryption as Encryption
from .rrf_params import RrfParams as RrfParams
from .limit_param import LimitParam as LimitParam
from .decay_params import DecayParams as DecayParams
from .embed_params import EmbedParams as EmbedParams
from .fuzzy_params import FuzzyParams as FuzzyParams
from .vector_param import VectorParam as VectorParam
from .columns_param import ColumnsParam as ColumnsParam
from .query_billing import QueryBilling as QueryBilling
from .write_billing import WriteBilling as WriteBilling
from .attribute_type import AttributeType as AttributeType
from .pinning_config import PinningConfig as PinningConfig
from .attribute_embed import AttributeEmbed as AttributeEmbed
from .distance_metric import DistanceMetric as DistanceMetric
from .saturate_params import SaturateParams as SaturateParams
from .vector_encoding import VectorEncoding as VectorEncoding
Expand All @@ -32,6 +35,8 @@
from .bm25_clause_params import Bm25ClauseParams as Bm25ClauseParams
from .namespace_metadata import NamespaceMetadata as NamespaceMetadata
from .pinning_config_param import PinningConfigParam as PinningConfigParam
from .attribute_embed_param import AttributeEmbedParam as AttributeEmbedParam
from .attribute_embed_config import AttributeEmbedConfig as AttributeEmbedConfig
from .attribute_schema_param import AttributeSchemaParam as AttributeSchemaParam
from .full_text_search_param import FullTextSearchParam as FullTextSearchParam
from .namespace_query_params import NamespaceQueryParams as NamespaceQueryParams
Expand All @@ -48,6 +53,7 @@
from .namespace_schema_response import NamespaceSchemaResponse as NamespaceSchemaResponse
from .copy_from_namespace_params import CopyFromNamespaceParams as CopyFromNamespaceParams
from .namespace_copy_from_params import NamespaceCopyFromParams as NamespaceCopyFromParams
from .attribute_embed_config_param import AttributeEmbedConfigParam as AttributeEmbedConfigParam
from .branch_from_namespace_params import BranchFromNamespaceParams as BranchFromNamespaceParams
from .namespace_branch_from_params import NamespaceBranchFromParams as NamespaceBranchFromParams
from .namespace_copy_from_response import NamespaceCopyFromResponse as NamespaceCopyFromResponse
Expand Down
10 changes: 10 additions & 0 deletions src/turbopuffer/types/attribute_embed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Union
from typing_extensions import TypeAlias

from .attribute_embed_config import AttributeEmbedConfig

__all__ = ["AttributeEmbed"]

AttributeEmbed: TypeAlias = Union[str, AttributeEmbedConfig, None]
32 changes: 32 additions & 0 deletions src/turbopuffer/types/attribute_embed_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Optional

from .._models import BaseModel

__all__ = ["AttributeEmbedConfig"]


class AttributeEmbedConfig(BaseModel):
"""Configuration options for automatic embedding."""

model: str
"""The model to use for embedding.

See our documentation for a list of models supported in each region.
"""

attribute: Optional[str] = None
"""The name of an existing vector attribute to store embeddings in.

If omitted, turbopuffer will generate a computed vector attribute named
`$embed_<attribute>`.
"""

dims: Optional[int] = None
"""The dimensionality to embed at.

If not set, will pick the default for this model. If you're storing embeddings
in an existing attribute, this can be omitted, and may not be set to a value
other than the dimensions of that attribute.
"""
32 changes: 32 additions & 0 deletions src/turbopuffer/types/attribute_embed_config_param.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from __future__ import annotations

from typing_extensions import Required, TypedDict

__all__ = ["AttributeEmbedConfigParam"]


class AttributeEmbedConfigParam(TypedDict, total=False):
"""Configuration options for automatic embedding."""

model: Required[str]
"""The model to use for embedding.

See our documentation for a list of models supported in each region.
"""

attribute: str
"""The name of an existing vector attribute to store embeddings in.

If omitted, turbopuffer will generate a computed vector attribute named
`$embed_<attribute>`.
"""

dims: int
"""The dimensionality to embed at.

If not set, will pick the default for this model. If you're storing embeddings
in an existing attribute, this can be omitted, and may not be set to a value
other than the dimensions of that attribute.
"""
12 changes: 12 additions & 0 deletions src/turbopuffer/types/attribute_embed_param.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from __future__ import annotations

from typing import Union
from typing_extensions import TypeAlias

from .attribute_embed_config_param import AttributeEmbedConfigParam

__all__ = ["AttributeEmbedParam"]

AttributeEmbedParam: TypeAlias = Union[str, AttributeEmbedConfigParam]
8 changes: 8 additions & 0 deletions src/turbopuffer/types/attribute_schema_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .._models import BaseModel
from .attribute_type import AttributeType
from .attribute_embed import AttributeEmbed
from .distance_metric import DistanceMetric
from .full_text_search import FullTextSearch
from .sparse_distance_metric import SparseDistanceMetric
Expand Down Expand Up @@ -48,6 +49,13 @@ class AttributeSchemaConfig(BaseModel):
Can be a boolean or a detailed configuration object.
"""

embed: Optional[AttributeEmbed] = None
"""Whether to automatically embed this string attribute into a vector attribute.

Can be a model name, a detailed configuration object, or `null` to remove an
existing embedding configuration.
"""

filterable: Optional[bool] = None
"""Whether or not the attributes can be used in filters."""

Expand Down
Loading
Loading