diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ce5e5c7c..157f0355 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.35.0" + ".": "0.36.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d8c421cd..2373becf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 61 +configured_endpoints: 62 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/mixedbread%2Fmixedbread-d4c4a6e0d99b371dc5e84a63cf447770fc684d6a0650b2e36013404245a5876b.yml openapi_spec_hash: 9d377ce6164438d3207d8a50c954a9cd -config_hash: 2de40c343cf7b242d5925e3405ee8908 +config_hash: 1f4b314dbc7ae3afe6d669e36217b842 diff --git a/CHANGELOG.md b/CHANGELOG.md index 49bd5fbb..26f7271c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.36.0 (2025-10-30) + +Full Changelog: [v0.35.0...v0.36.0](https://github.com/mixedbread-ai/mixedbread-python/compare/v0.35.0...v0.36.0) + +### Features + +* **api:** update via SDK Studio ([979a334](https://github.com/mixedbread-ai/mixedbread-python/commit/979a33419c7700c2e20c6df2cd532249517a0a00)) + ## 0.35.0 (2025-10-30) Full Changelog: [v0.34.0...v0.35.0](https://github.com/mixedbread-ai/mixedbread-python/compare/v0.34.0...v0.35.0) diff --git a/api.md b/api.md index ba725e0b..664fa3c1 100644 --- a/api.md +++ b/api.md @@ -86,6 +86,7 @@ from mixedbread.types import ( Store, StoreChunkSearchOptions, StoreDeleteResponse, + StoreMetadataFacetsResponse, StoreQuestionAnsweringResponse, StoreSearchResponse, ) @@ -98,6 +99,7 @@ Methods: - client.stores.update(store_identifier, \*\*params) -> Store - client.stores.list(\*\*params) -> SyncCursor[Store] - client.stores.delete(store_identifier) -> StoreDeleteResponse +- client.stores.metadata_facets(store_identifier, \*\*params) -> StoreMetadataFacetsResponse - client.stores.question_answering(\*\*params) -> StoreQuestionAnsweringResponse - client.stores.search(\*\*params) -> StoreSearchResponse diff --git a/pyproject.toml b/pyproject.toml index cc1d73b6..aee7303a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mixedbread" -version = "0.35.0" +version = "0.36.0" description = "The official Python library for the Mixedbread API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/mixedbread/_version.py b/src/mixedbread/_version.py index 372ffb33..90e190d2 100644 --- a/src/mixedbread/_version.py +++ b/src/mixedbread/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "mixedbread" -__version__ = "0.35.0" # x-release-please-version +__version__ = "0.36.0" # x-release-please-version diff --git a/src/mixedbread/resources/stores/stores.py b/src/mixedbread/resources/stores/stores.py index a2128963..f5f00bc5 100644 --- a/src/mixedbread/resources/stores/stores.py +++ b/src/mixedbread/resources/stores/stores.py @@ -19,6 +19,7 @@ store_create_params, store_search_params, store_update_params, + store_metadata_facets_params, store_question_answering_params, ) from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given @@ -37,6 +38,7 @@ from ...types.expires_after_param import ExpiresAfterParam from ...types.store_delete_response import StoreDeleteResponse from ...types.store_search_response import StoreSearchResponse +from ...types.store_metadata_facets_response import StoreMetadataFacetsResponse from ...types.store_chunk_search_options_param import StoreChunkSearchOptionsParam from ...types.store_question_answering_response import StoreQuestionAnsweringResponse @@ -341,6 +343,54 @@ def delete( cast_to=StoreDeleteResponse, ) + def metadata_facets( + self, + store_identifier: str, + *, + filters: Optional[store_metadata_facets_params.Filters] | Omit = omit, + facets: Optional[SequenceNotStr[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, + ) -> StoreMetadataFacetsResponse: + """ + Get metadata facets + + Args: + store_identifier: The ID or name of the store + + filters: Optional filter conditions + + facets: Optional list of facets to return. Use dot for nested fields. + + 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 store_identifier: + raise ValueError(f"Expected a non-empty value for `store_identifier` but received {store_identifier!r}") + return self._post( + f"/v1/stores/{store_identifier}/metadata-facets", + body=maybe_transform( + { + "filters": filters, + "facets": facets, + }, + store_metadata_facets_params.StoreMetadataFacetsParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StoreMetadataFacetsResponse, + ) + def question_answering( self, *, @@ -784,6 +834,54 @@ async def delete( cast_to=StoreDeleteResponse, ) + async def metadata_facets( + self, + store_identifier: str, + *, + filters: Optional[store_metadata_facets_params.Filters] | Omit = omit, + facets: Optional[SequenceNotStr[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, + ) -> StoreMetadataFacetsResponse: + """ + Get metadata facets + + Args: + store_identifier: The ID or name of the store + + filters: Optional filter conditions + + facets: Optional list of facets to return. Use dot for nested fields. + + 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 store_identifier: + raise ValueError(f"Expected a non-empty value for `store_identifier` but received {store_identifier!r}") + return await self._post( + f"/v1/stores/{store_identifier}/metadata-facets", + body=await async_maybe_transform( + { + "filters": filters, + "facets": facets, + }, + store_metadata_facets_params.StoreMetadataFacetsParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StoreMetadataFacetsResponse, + ) + async def question_answering( self, *, @@ -948,6 +1046,9 @@ def __init__(self, stores: StoresResource) -> None: self.delete = to_raw_response_wrapper( stores.delete, ) + self.metadata_facets = to_raw_response_wrapper( + stores.metadata_facets, + ) self.question_answering = to_raw_response_wrapper( stores.question_answering, ) @@ -979,6 +1080,9 @@ def __init__(self, stores: AsyncStoresResource) -> None: self.delete = async_to_raw_response_wrapper( stores.delete, ) + self.metadata_facets = async_to_raw_response_wrapper( + stores.metadata_facets, + ) self.question_answering = async_to_raw_response_wrapper( stores.question_answering, ) @@ -1010,6 +1114,9 @@ def __init__(self, stores: StoresResource) -> None: self.delete = to_streamed_response_wrapper( stores.delete, ) + self.metadata_facets = to_streamed_response_wrapper( + stores.metadata_facets, + ) self.question_answering = to_streamed_response_wrapper( stores.question_answering, ) @@ -1041,6 +1148,9 @@ def __init__(self, stores: AsyncStoresResource) -> None: self.delete = async_to_streamed_response_wrapper( stores.delete, ) + self.metadata_facets = async_to_streamed_response_wrapper( + stores.metadata_facets, + ) self.question_answering = async_to_streamed_response_wrapper( stores.question_answering, ) diff --git a/src/mixedbread/types/__init__.py b/src/mixedbread/types/__init__.py index 3ec3253b..20bcd899 100644 --- a/src/mixedbread/types/__init__.py +++ b/src/mixedbread/types/__init__.py @@ -53,8 +53,10 @@ from .scored_audio_url_input_chunk import ScoredAudioURLInputChunk as ScoredAudioURLInputChunk from .scored_image_url_input_chunk import ScoredImageURLInputChunk as ScoredImageURLInputChunk from .scored_video_url_input_chunk import ScoredVideoURLInputChunk as ScoredVideoURLInputChunk +from .store_metadata_facets_params import StoreMetadataFacetsParams as StoreMetadataFacetsParams from .vector_store_delete_response import VectorStoreDeleteResponse as VectorStoreDeleteResponse from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse +from .store_metadata_facets_response import StoreMetadataFacetsResponse as StoreMetadataFacetsResponse from .store_question_answering_params import StoreQuestionAnsweringParams as StoreQuestionAnsweringParams from .store_chunk_search_options_param import StoreChunkSearchOptionsParam as StoreChunkSearchOptionsParam from .store_question_answering_response import StoreQuestionAnsweringResponse as StoreQuestionAnsweringResponse diff --git a/src/mixedbread/types/store_metadata_facets_params.py b/src/mixedbread/types/store_metadata_facets_params.py new file mode 100644 index 00000000..e1b87603 --- /dev/null +++ b/src/mixedbread/types/store_metadata_facets_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .shared_params.search_filter_condition import SearchFilterCondition + +__all__ = ["StoreMetadataFacetsParams", "Filters", "FiltersUnionMember2"] + + +class StoreMetadataFacetsParams(TypedDict, total=False): + filters: Optional[Filters] + """Optional filter conditions""" + + facets: Optional[SequenceNotStr[str]] + """Optional list of facets to return. Use dot for nested fields.""" + + +FiltersUnionMember2: TypeAlias = Union["SearchFilter", SearchFilterCondition] + +Filters: TypeAlias = Union["SearchFilter", SearchFilterCondition, Iterable[FiltersUnionMember2]] + +from .shared_params.search_filter import SearchFilter diff --git a/src/mixedbread/types/store_metadata_facets_response.py b/src/mixedbread/types/store_metadata_facets_response.py new file mode 100644 index 00000000..989562c4 --- /dev/null +++ b/src/mixedbread/types/store_metadata_facets_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict + +from .._models import BaseModel + +__all__ = ["StoreMetadataFacetsResponse"] + + +class StoreMetadataFacetsResponse(BaseModel): + facets: Dict[str, Dict[str, object]] + """Metadata facets""" diff --git a/tests/api_resources/test_stores.py b/tests/api_resources/test_stores.py index 180773e7..895c5494 100644 --- a/tests/api_resources/test_stores.py +++ b/tests/api_resources/test_stores.py @@ -13,6 +13,7 @@ Store, StoreDeleteResponse, StoreSearchResponse, + StoreMetadataFacetsResponse, StoreQuestionAnsweringResponse, ) from mixedbread.pagination import SyncCursor, AsyncCursor @@ -228,6 +229,90 @@ def test_path_params_delete(self, client: Mixedbread) -> None: "", ) + @parametrize + def test_method_metadata_facets(self, client: Mixedbread) -> None: + store = client.stores.metadata_facets( + store_identifier="store_identifier", + ) + assert_matches_type(StoreMetadataFacetsResponse, store, path=["response"]) + + @parametrize + def test_method_metadata_facets_with_all_params(self, client: Mixedbread) -> None: + store = client.stores.metadata_facets( + store_identifier="store_identifier", + filters={ + "all": [ + { + "key": "price", + "value": "100", + "operator": "gt", + }, + { + "key": "color", + "value": "red", + "operator": "eq", + }, + ], + "any": [ + { + "key": "price", + "value": "100", + "operator": "gt", + }, + { + "key": "color", + "value": "red", + "operator": "eq", + }, + ], + "none": [ + { + "key": "price", + "value": "100", + "operator": "gt", + }, + { + "key": "color", + "value": "red", + "operator": "eq", + }, + ], + }, + facets=["string"], + ) + assert_matches_type(StoreMetadataFacetsResponse, store, path=["response"]) + + @parametrize + def test_raw_response_metadata_facets(self, client: Mixedbread) -> None: + response = client.stores.with_raw_response.metadata_facets( + store_identifier="store_identifier", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + store = response.parse() + assert_matches_type(StoreMetadataFacetsResponse, store, path=["response"]) + + @parametrize + def test_streaming_response_metadata_facets(self, client: Mixedbread) -> None: + with client.stores.with_streaming_response.metadata_facets( + store_identifier="store_identifier", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + store = response.parse() + assert_matches_type(StoreMetadataFacetsResponse, store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_metadata_facets(self, client: Mixedbread) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `store_identifier` but received ''"): + client.stores.with_raw_response.metadata_facets( + store_identifier="", + ) + @parametrize def test_method_question_answering(self, client: Mixedbread) -> None: store = client.stores.question_answering( @@ -619,6 +704,90 @@ async def test_path_params_delete(self, async_client: AsyncMixedbread) -> None: "", ) + @parametrize + async def test_method_metadata_facets(self, async_client: AsyncMixedbread) -> None: + store = await async_client.stores.metadata_facets( + store_identifier="store_identifier", + ) + assert_matches_type(StoreMetadataFacetsResponse, store, path=["response"]) + + @parametrize + async def test_method_metadata_facets_with_all_params(self, async_client: AsyncMixedbread) -> None: + store = await async_client.stores.metadata_facets( + store_identifier="store_identifier", + filters={ + "all": [ + { + "key": "price", + "value": "100", + "operator": "gt", + }, + { + "key": "color", + "value": "red", + "operator": "eq", + }, + ], + "any": [ + { + "key": "price", + "value": "100", + "operator": "gt", + }, + { + "key": "color", + "value": "red", + "operator": "eq", + }, + ], + "none": [ + { + "key": "price", + "value": "100", + "operator": "gt", + }, + { + "key": "color", + "value": "red", + "operator": "eq", + }, + ], + }, + facets=["string"], + ) + assert_matches_type(StoreMetadataFacetsResponse, store, path=["response"]) + + @parametrize + async def test_raw_response_metadata_facets(self, async_client: AsyncMixedbread) -> None: + response = await async_client.stores.with_raw_response.metadata_facets( + store_identifier="store_identifier", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + store = await response.parse() + assert_matches_type(StoreMetadataFacetsResponse, store, path=["response"]) + + @parametrize + async def test_streaming_response_metadata_facets(self, async_client: AsyncMixedbread) -> None: + async with async_client.stores.with_streaming_response.metadata_facets( + store_identifier="store_identifier", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + store = await response.parse() + assert_matches_type(StoreMetadataFacetsResponse, store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_metadata_facets(self, async_client: AsyncMixedbread) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `store_identifier` but received ''"): + await async_client.stores.with_raw_response.metadata_facets( + store_identifier="", + ) + @parametrize async def test_method_question_answering(self, async_client: AsyncMixedbread) -> None: store = await async_client.stores.question_answering(