From bff74c98b5b08e45e291381753340a22c6b04c89 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 27 May 2025 10:19:48 +0000
Subject: [PATCH 1/7] feat(api): update via SDK Studio
---
.stats.yml | 4 +-
api.md | 5 +-
src/hyperspell/resources/documents.py | 191 +++++++++++++++++-
src/hyperspell/types/__init__.py | 2 +-
...{document_list_response.py => document.py} | 4 +-
src/hyperspell/types/query_search_response.py | 78 +------
tests/api_resources/test_documents.py | 105 ++++++++--
7 files changed, 288 insertions(+), 101 deletions(-)
rename src/hyperspell/types/{document_list_response.py => document.py} (95%)
diff --git a/.stats.yml b/.stats.yml
index fd6cf3f6..5eb4c2a9 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 10
+configured_endpoints: 11
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-287b83fd66b657b044f4ab280ab0e72a2ed72c0da50e4a7d09ce98123982262f.yml
openapi_spec_hash: fcef51b5cf5e602a2d8025546e27e24a
-config_hash: a39dfe90372d06d735dfb3d27b30409f
+config_hash: b5cce3817205494675930aad1404bfad
diff --git a/api.md b/api.md
index e5aee0a0..889a4dcc 100644
--- a/api.md
+++ b/api.md
@@ -39,13 +39,14 @@ Methods:
Types:
```python
-from hyperspell.types import DocumentStatus, DocumentListResponse
+from hyperspell.types import Document, DocumentStatus
```
Methods:
-- client.documents.list(\*\*params) -> SyncCursorPage[DocumentListResponse]
+- client.documents.list(\*\*params) -> SyncCursorPage[Document]
- client.documents.add(\*\*params) -> DocumentStatus
+- client.documents.get(resource_id, \*, source) -> Document
- client.documents.upload(\*\*params) -> DocumentStatus
# Collections
diff --git a/src/hyperspell/resources/documents.py b/src/hyperspell/resources/documents.py
index 8b35d2e2..162e9917 100644
--- a/src/hyperspell/resources/documents.py
+++ b/src/hyperspell/resources/documents.py
@@ -4,6 +4,7 @@
from typing import Union, Mapping, Optional, cast
from datetime import datetime
+from typing_extensions import Literal
import httpx
@@ -20,8 +21,8 @@
)
from ..pagination import SyncCursorPage, AsyncCursorPage
from .._base_client import AsyncPaginator, make_request_options
+from ..types.document import Document
from ..types.document_status import DocumentStatus
-from ..types.document_list_response import DocumentListResponse
__all__ = ["DocumentsResource", "AsyncDocumentsResource"]
@@ -58,7 +59,7 @@ def list(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> SyncCursorPage[DocumentListResponse]:
+ ) -> SyncCursorPage[Document]:
"""This endpoint allows you to paginate through all documents in the index.
You can
@@ -77,7 +78,7 @@ def list(
"""
return self._get_api_list(
"/documents/list",
- page=SyncCursorPage[DocumentListResponse],
+ page=SyncCursorPage[Document],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -92,7 +93,7 @@ def list(
document_list_params.DocumentListParams,
),
),
- model=DocumentListResponse,
+ model=Document,
)
def add(
@@ -152,6 +153,88 @@ def add(
cast_to=DocumentStatus,
)
+ def get(
+ self,
+ resource_id: str,
+ *,
+ source: Literal[
+ "collections",
+ "web_crawler",
+ "notion",
+ "slack",
+ "google_calendar",
+ "reddit",
+ "box",
+ "google_drive",
+ "airtable",
+ "algolia",
+ "amplitude",
+ "asana",
+ "ashby",
+ "bamboohr",
+ "basecamp",
+ "bubbles",
+ "calendly",
+ "confluence",
+ "clickup",
+ "datadog",
+ "deel",
+ "discord",
+ "dropbox",
+ "exa",
+ "facebook",
+ "front",
+ "github",
+ "gitlab",
+ "google_docs",
+ "google_mail",
+ "google_sheet",
+ "hubspot",
+ "jira",
+ "linear",
+ "microsoft_teams",
+ "mixpanel",
+ "monday",
+ "outlook",
+ "perplexity",
+ "rippling",
+ "salesforce",
+ "segment",
+ "todoist",
+ "twitter",
+ "zoom",
+ ],
+ # 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,
+ ) -> Document:
+ """
+ Retrieves a document by provider and resource_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 source:
+ raise ValueError(f"Expected a non-empty value for `source` but received {source!r}")
+ if not resource_id:
+ raise ValueError(f"Expected a non-empty value for `resource_id` but received {resource_id!r}")
+ return self._get(
+ f"/documents/get/{source}/{resource_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Document,
+ )
+
def upload(
self,
*,
@@ -238,7 +321,7 @@ def list(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> AsyncPaginator[DocumentListResponse, AsyncCursorPage[DocumentListResponse]]:
+ ) -> AsyncPaginator[Document, AsyncCursorPage[Document]]:
"""This endpoint allows you to paginate through all documents in the index.
You can
@@ -257,7 +340,7 @@ def list(
"""
return self._get_api_list(
"/documents/list",
- page=AsyncCursorPage[DocumentListResponse],
+ page=AsyncCursorPage[Document],
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -272,7 +355,7 @@ def list(
document_list_params.DocumentListParams,
),
),
- model=DocumentListResponse,
+ model=Document,
)
async def add(
@@ -332,6 +415,88 @@ async def add(
cast_to=DocumentStatus,
)
+ async def get(
+ self,
+ resource_id: str,
+ *,
+ source: Literal[
+ "collections",
+ "web_crawler",
+ "notion",
+ "slack",
+ "google_calendar",
+ "reddit",
+ "box",
+ "google_drive",
+ "airtable",
+ "algolia",
+ "amplitude",
+ "asana",
+ "ashby",
+ "bamboohr",
+ "basecamp",
+ "bubbles",
+ "calendly",
+ "confluence",
+ "clickup",
+ "datadog",
+ "deel",
+ "discord",
+ "dropbox",
+ "exa",
+ "facebook",
+ "front",
+ "github",
+ "gitlab",
+ "google_docs",
+ "google_mail",
+ "google_sheet",
+ "hubspot",
+ "jira",
+ "linear",
+ "microsoft_teams",
+ "mixpanel",
+ "monday",
+ "outlook",
+ "perplexity",
+ "rippling",
+ "salesforce",
+ "segment",
+ "todoist",
+ "twitter",
+ "zoom",
+ ],
+ # 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,
+ ) -> Document:
+ """
+ Retrieves a document by provider and resource_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 source:
+ raise ValueError(f"Expected a non-empty value for `source` but received {source!r}")
+ if not resource_id:
+ raise ValueError(f"Expected a non-empty value for `resource_id` but received {resource_id!r}")
+ return await self._get(
+ f"/documents/get/{source}/{resource_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Document,
+ )
+
async def upload(
self,
*,
@@ -396,6 +561,9 @@ def __init__(self, documents: DocumentsResource) -> None:
self.add = to_raw_response_wrapper(
documents.add,
)
+ self.get = to_raw_response_wrapper(
+ documents.get,
+ )
self.upload = to_raw_response_wrapper(
documents.upload,
)
@@ -411,6 +579,9 @@ def __init__(self, documents: AsyncDocumentsResource) -> None:
self.add = async_to_raw_response_wrapper(
documents.add,
)
+ self.get = async_to_raw_response_wrapper(
+ documents.get,
+ )
self.upload = async_to_raw_response_wrapper(
documents.upload,
)
@@ -426,6 +597,9 @@ def __init__(self, documents: DocumentsResource) -> None:
self.add = to_streamed_response_wrapper(
documents.add,
)
+ self.get = to_streamed_response_wrapper(
+ documents.get,
+ )
self.upload = to_streamed_response_wrapper(
documents.upload,
)
@@ -441,6 +615,9 @@ def __init__(self, documents: AsyncDocumentsResource) -> None:
self.add = async_to_streamed_response_wrapper(
documents.add,
)
+ self.get = async_to_streamed_response_wrapper(
+ documents.get,
+ )
self.upload = async_to_streamed_response_wrapper(
documents.upload,
)
diff --git a/src/hyperspell/types/__init__.py b/src/hyperspell/types/__init__.py
index 178fb32e..a1b81417 100644
--- a/src/hyperspell/types/__init__.py
+++ b/src/hyperspell/types/__init__.py
@@ -3,6 +3,7 @@
from __future__ import annotations
from .token import Token as Token
+from .document import Document as Document
from .document_status import DocumentStatus as DocumentStatus
from .auth_me_response import AuthMeResponse as AuthMeResponse
from .document_add_params import DocumentAddParams as DocumentAddParams
@@ -11,7 +12,6 @@
from .query_search_response import QuerySearchResponse as QuerySearchResponse
from .auth_user_token_params import AuthUserTokenParams as AuthUserTokenParams
from .collection_list_params import CollectionListParams as CollectionListParams
-from .document_list_response import DocumentListResponse as DocumentListResponse
from .document_upload_params import DocumentUploadParams as DocumentUploadParams
from .collection_list_response import CollectionListResponse as CollectionListResponse
from .integration_revoke_response import IntegrationRevokeResponse as IntegrationRevokeResponse
diff --git a/src/hyperspell/types/document_list_response.py b/src/hyperspell/types/document.py
similarity index 95%
rename from src/hyperspell/types/document_list_response.py
rename to src/hyperspell/types/document.py
index de9f9bf8..41b3cc80 100644
--- a/src/hyperspell/types/document_list_response.py
+++ b/src/hyperspell/types/document.py
@@ -6,7 +6,7 @@
from .._models import BaseModel
-__all__ = ["DocumentListResponse", "Metadata"]
+__all__ = ["Document", "Metadata"]
class Metadata(BaseModel):
@@ -23,7 +23,7 @@ class Metadata(BaseModel):
def __getattr__(self, attr: str) -> object: ...
-class DocumentListResponse(BaseModel):
+class Document(BaseModel):
resource_id: str
source: Literal[
diff --git a/src/hyperspell/types/query_search_response.py b/src/hyperspell/types/query_search_response.py
index 498aa516..e02d76d4 100644
--- a/src/hyperspell/types/query_search_response.py
+++ b/src/hyperspell/types/query_search_response.py
@@ -1,83 +1,11 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import TYPE_CHECKING, Dict, List, Optional
-from datetime import datetime
-from typing_extensions import Literal
+from typing import Dict, List, Optional
from .._models import BaseModel
+from .document import Document
-__all__ = ["QuerySearchResponse", "Document", "DocumentMetadata"]
-
-
-class DocumentMetadata(BaseModel):
- created_at: Optional[datetime] = None
-
- last_modified: Optional[datetime] = None
-
- url: Optional[str] = None
-
- if TYPE_CHECKING:
- # 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: ...
-
-
-class Document(BaseModel):
- resource_id: str
-
- source: Literal[
- "collections",
- "web_crawler",
- "notion",
- "slack",
- "google_calendar",
- "reddit",
- "box",
- "google_drive",
- "airtable",
- "algolia",
- "amplitude",
- "asana",
- "ashby",
- "bamboohr",
- "basecamp",
- "bubbles",
- "calendly",
- "confluence",
- "clickup",
- "datadog",
- "deel",
- "discord",
- "dropbox",
- "exa",
- "facebook",
- "front",
- "github",
- "gitlab",
- "google_docs",
- "google_mail",
- "google_sheet",
- "hubspot",
- "jira",
- "linear",
- "microsoft_teams",
- "mixpanel",
- "monday",
- "outlook",
- "perplexity",
- "rippling",
- "salesforce",
- "segment",
- "todoist",
- "twitter",
- "zoom",
- ]
-
- metadata: Optional[DocumentMetadata] = None
-
- score: Optional[float] = None
- """The relevance of the resource to the query"""
+__all__ = ["QuerySearchResponse"]
class QuerySearchResponse(BaseModel):
diff --git a/tests/api_resources/test_documents.py b/tests/api_resources/test_documents.py
index 37d3c95a..6418c517 100644
--- a/tests/api_resources/test_documents.py
+++ b/tests/api_resources/test_documents.py
@@ -9,10 +9,7 @@
from hyperspell import Hyperspell, AsyncHyperspell
from tests.utils import assert_matches_type
-from hyperspell.types import (
- DocumentStatus,
- DocumentListResponse,
-)
+from hyperspell.types import Document, DocumentStatus
from hyperspell._utils import parse_datetime
from hyperspell.pagination import SyncCursorPage, AsyncCursorPage
@@ -25,7 +22,7 @@ class TestDocuments:
@parametrize
def test_method_list(self, client: Hyperspell) -> None:
document = client.documents.list()
- assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"])
+ assert_matches_type(SyncCursorPage[Document], document, path=["response"])
@parametrize
def test_method_list_with_all_params(self, client: Hyperspell) -> None:
@@ -34,7 +31,7 @@ def test_method_list_with_all_params(self, client: Hyperspell) -> None:
cursor="cursor",
size=0,
)
- assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"])
+ assert_matches_type(SyncCursorPage[Document], document, path=["response"])
@parametrize
def test_raw_response_list(self, client: Hyperspell) -> None:
@@ -43,7 +40,7 @@ def test_raw_response_list(self, client: Hyperspell) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
document = response.parse()
- assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"])
+ assert_matches_type(SyncCursorPage[Document], document, path=["response"])
@parametrize
def test_streaming_response_list(self, client: Hyperspell) -> None:
@@ -52,7 +49,7 @@ def test_streaming_response_list(self, client: Hyperspell) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
document = response.parse()
- assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"])
+ assert_matches_type(SyncCursorPage[Document], document, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -97,6 +94,48 @@ def test_streaming_response_add(self, client: Hyperspell) -> None:
assert cast(Any, response.is_closed) is True
+ @parametrize
+ def test_method_get(self, client: Hyperspell) -> None:
+ document = client.documents.get(
+ resource_id="resource_id",
+ source="collections",
+ )
+ assert_matches_type(Document, document, path=["response"])
+
+ @parametrize
+ def test_raw_response_get(self, client: Hyperspell) -> None:
+ response = client.documents.with_raw_response.get(
+ resource_id="resource_id",
+ source="collections",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert_matches_type(Document, document, path=["response"])
+
+ @parametrize
+ def test_streaming_response_get(self, client: Hyperspell) -> None:
+ with client.documents.with_streaming_response.get(
+ resource_id="resource_id",
+ source="collections",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = response.parse()
+ assert_matches_type(Document, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_get(self, client: Hyperspell) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `resource_id` but received ''"):
+ client.documents.with_raw_response.get(
+ resource_id="",
+ source="collections",
+ )
+
@parametrize
def test_method_upload(self, client: Hyperspell) -> None:
document = client.documents.upload(
@@ -143,7 +182,7 @@ class TestAsyncDocuments:
@parametrize
async def test_method_list(self, async_client: AsyncHyperspell) -> None:
document = await async_client.documents.list()
- assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"])
+ assert_matches_type(AsyncCursorPage[Document], document, path=["response"])
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncHyperspell) -> None:
@@ -152,7 +191,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncHyperspell)
cursor="cursor",
size=0,
)
- assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"])
+ assert_matches_type(AsyncCursorPage[Document], document, path=["response"])
@parametrize
async def test_raw_response_list(self, async_client: AsyncHyperspell) -> None:
@@ -161,7 +200,7 @@ async def test_raw_response_list(self, async_client: AsyncHyperspell) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
document = await response.parse()
- assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"])
+ assert_matches_type(AsyncCursorPage[Document], document, path=["response"])
@parametrize
async def test_streaming_response_list(self, async_client: AsyncHyperspell) -> None:
@@ -170,7 +209,7 @@ async def test_streaming_response_list(self, async_client: AsyncHyperspell) -> N
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
document = await response.parse()
- assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"])
+ assert_matches_type(AsyncCursorPage[Document], document, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -215,6 +254,48 @@ async def test_streaming_response_add(self, async_client: AsyncHyperspell) -> No
assert cast(Any, response.is_closed) is True
+ @parametrize
+ async def test_method_get(self, async_client: AsyncHyperspell) -> None:
+ document = await async_client.documents.get(
+ resource_id="resource_id",
+ source="collections",
+ )
+ assert_matches_type(Document, document, path=["response"])
+
+ @parametrize
+ async def test_raw_response_get(self, async_client: AsyncHyperspell) -> None:
+ response = await async_client.documents.with_raw_response.get(
+ resource_id="resource_id",
+ source="collections",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = await response.parse()
+ assert_matches_type(Document, document, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_get(self, async_client: AsyncHyperspell) -> None:
+ async with async_client.documents.with_streaming_response.get(
+ resource_id="resource_id",
+ source="collections",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = await response.parse()
+ assert_matches_type(Document, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_get(self, async_client: AsyncHyperspell) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `resource_id` but received ''"):
+ await async_client.documents.with_raw_response.get(
+ resource_id="",
+ source="collections",
+ )
+
@parametrize
async def test_method_upload(self, async_client: AsyncHyperspell) -> None:
document = await async_client.documents.upload(
From b6ad9f43113a8cbf23580027c37ecaf95cb37cb3 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 28 May 2025 13:31:37 +0000
Subject: [PATCH 2/7] feat(api): api update
---
.stats.yml | 4 ++--
src/hyperspell/resources/auth.py | 24 +++++++++++++++++--
.../types/auth_user_token_params.py | 4 ++++
tests/api_resources/test_auth.py | 16 +++++++++++++
4 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 5eb4c2a9..b9f8f6de 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 11
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-287b83fd66b657b044f4ab280ab0e72a2ed72c0da50e4a7d09ce98123982262f.yml
-openapi_spec_hash: fcef51b5cf5e602a2d8025546e27e24a
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-3269b9efc5f1d7e7c249eea6c05f7eae0f9ff375d0440b10aafb9ad6b2440fba.yml
+openapi_spec_hash: cb064dc60b022e43dca5219b25d97861
config_hash: b5cce3817205494675930aad1404bfad
diff --git a/src/hyperspell/resources/auth.py b/src/hyperspell/resources/auth.py
index c579a191..b9e17f87 100644
--- a/src/hyperspell/resources/auth.py
+++ b/src/hyperspell/resources/auth.py
@@ -2,6 +2,8 @@
from __future__ import annotations
+from typing import Optional
+
import httpx
from ..types import auth_user_token_params
@@ -65,6 +67,7 @@ def user_token(
self,
*,
user_id: str,
+ expires_in: Optional[str] | NotGiven = NOT_GIVEN,
# 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,
@@ -78,6 +81,8 @@ def user_token(
safely passed to your user-facing front-end.
Args:
+ expires_in: Token lifetime, e.g., '30m', '2h', '1d'. Defaults to 24 hours if not provided.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -88,7 +93,13 @@ def user_token(
"""
return self._post(
"/auth/user_token",
- body=maybe_transform({"user_id": user_id}, auth_user_token_params.AuthUserTokenParams),
+ body=maybe_transform(
+ {
+ "user_id": user_id,
+ "expires_in": expires_in,
+ },
+ auth_user_token_params.AuthUserTokenParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -139,6 +150,7 @@ async def user_token(
self,
*,
user_id: str,
+ expires_in: Optional[str] | NotGiven = NOT_GIVEN,
# 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,
@@ -152,6 +164,8 @@ async def user_token(
safely passed to your user-facing front-end.
Args:
+ expires_in: Token lifetime, e.g., '30m', '2h', '1d'. Defaults to 24 hours if not provided.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -162,7 +176,13 @@ async def user_token(
"""
return await self._post(
"/auth/user_token",
- body=await async_maybe_transform({"user_id": user_id}, auth_user_token_params.AuthUserTokenParams),
+ body=await async_maybe_transform(
+ {
+ "user_id": user_id,
+ "expires_in": expires_in,
+ },
+ auth_user_token_params.AuthUserTokenParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/hyperspell/types/auth_user_token_params.py b/src/hyperspell/types/auth_user_token_params.py
index b1e44fdc..fa7cc949 100644
--- a/src/hyperspell/types/auth_user_token_params.py
+++ b/src/hyperspell/types/auth_user_token_params.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+from typing import Optional
from typing_extensions import Required, TypedDict
__all__ = ["AuthUserTokenParams"]
@@ -9,3 +10,6 @@
class AuthUserTokenParams(TypedDict, total=False):
user_id: Required[str]
+
+ expires_in: Optional[str]
+ """Token lifetime, e.g., '30m', '2h', '1d'. Defaults to 24 hours if not provided."""
diff --git a/tests/api_resources/test_auth.py b/tests/api_resources/test_auth.py
index a609ea76..e4207ba8 100644
--- a/tests/api_resources/test_auth.py
+++ b/tests/api_resources/test_auth.py
@@ -49,6 +49,14 @@ def test_method_user_token(self, client: Hyperspell) -> None:
)
assert_matches_type(Token, auth, path=["response"])
+ @parametrize
+ def test_method_user_token_with_all_params(self, client: Hyperspell) -> None:
+ auth = client.auth.user_token(
+ user_id="user_id",
+ expires_in="30m",
+ )
+ assert_matches_type(Token, auth, path=["response"])
+
@parametrize
def test_raw_response_user_token(self, client: Hyperspell) -> None:
response = client.auth.with_raw_response.user_token(
@@ -109,6 +117,14 @@ async def test_method_user_token(self, async_client: AsyncHyperspell) -> None:
)
assert_matches_type(Token, auth, path=["response"])
+ @parametrize
+ async def test_method_user_token_with_all_params(self, async_client: AsyncHyperspell) -> None:
+ auth = await async_client.auth.user_token(
+ user_id="user_id",
+ expires_in="30m",
+ )
+ assert_matches_type(Token, auth, path=["response"])
+
@parametrize
async def test_raw_response_user_token(self, async_client: AsyncHyperspell) -> None:
response = await async_client.auth.with_raw_response.user_token(
From 0f349566456957e5b216785db2b5e50bf44795d8 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 29 May 2025 21:44:45 +0000
Subject: [PATCH 3/7] codegen metadata
---
.stats.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.stats.yml b/.stats.yml
index b9f8f6de..53cd9c1f 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 11
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-3269b9efc5f1d7e7c249eea6c05f7eae0f9ff375d0440b10aafb9ad6b2440fba.yml
openapi_spec_hash: cb064dc60b022e43dca5219b25d97861
-config_hash: b5cce3817205494675930aad1404bfad
+config_hash: da009f16a6b9b4db17be2949180ace1e
From 3334f14582bda6ec78c9b479317c8d818b1c1227 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 29 May 2025 22:27:44 +0000
Subject: [PATCH 4/7] feat(api): api update
---
.stats.yml | 6 +-
api.md | 3 +-
src/hyperspell/resources/documents.py | 163 ++++++++++++++++++
src/hyperspell/types/__init__.py | 1 +
src/hyperspell/types/document.py | 18 +-
src/hyperspell/types/document_list_params.py | 53 +++++-
.../types/document_status_response.py | 13 ++
tests/api_resources/test_documents.py | 58 ++++++-
8 files changed, 305 insertions(+), 10 deletions(-)
create mode 100644 src/hyperspell/types/document_status_response.py
diff --git a/.stats.yml b/.stats.yml
index 53cd9c1f..6b2619bf 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 11
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-3269b9efc5f1d7e7c249eea6c05f7eae0f9ff375d0440b10aafb9ad6b2440fba.yml
-openapi_spec_hash: cb064dc60b022e43dca5219b25d97861
+configured_endpoints: 12
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-472f6034747ca75f970d64e57875f1cb24991ad422e17f3e9839757b84e2cb3d.yml
+openapi_spec_hash: 9759125c6a0c64da09c94923667f34a5
config_hash: da009f16a6b9b4db17be2949180ace1e
diff --git a/api.md b/api.md
index 889a4dcc..c8fcbbc2 100644
--- a/api.md
+++ b/api.md
@@ -39,7 +39,7 @@ Methods:
Types:
```python
-from hyperspell.types import Document, DocumentStatus
+from hyperspell.types import Document, DocumentStatus, DocumentStatusResponse
```
Methods:
@@ -47,6 +47,7 @@ Methods:
- client.documents.list(\*\*params) -> SyncCursorPage[Document]
- client.documents.add(\*\*params) -> DocumentStatus
- client.documents.get(resource_id, \*, source) -> Document
+- client.documents.status() -> DocumentStatusResponse
- client.documents.upload(\*\*params) -> DocumentStatus
# Collections
diff --git a/src/hyperspell/resources/documents.py b/src/hyperspell/resources/documents.py
index 162e9917..eda88282 100644
--- a/src/hyperspell/resources/documents.py
+++ b/src/hyperspell/resources/documents.py
@@ -23,6 +23,7 @@
from .._base_client import AsyncPaginator, make_request_options
from ..types.document import Document
from ..types.document_status import DocumentStatus
+from ..types.document_status_response import DocumentStatusResponse
__all__ = ["DocumentsResource", "AsyncDocumentsResource"]
@@ -53,6 +54,56 @@ def list(
collection: Optional[str] | NotGiven = NOT_GIVEN,
cursor: Optional[str] | NotGiven = NOT_GIVEN,
size: int | NotGiven = NOT_GIVEN,
+ source: Optional[
+ Literal[
+ "collections",
+ "web_crawler",
+ "notion",
+ "slack",
+ "google_calendar",
+ "reddit",
+ "box",
+ "google_drive",
+ "airtable",
+ "algolia",
+ "amplitude",
+ "asana",
+ "ashby",
+ "bamboohr",
+ "basecamp",
+ "bubbles",
+ "calendly",
+ "confluence",
+ "clickup",
+ "datadog",
+ "deel",
+ "discord",
+ "dropbox",
+ "exa",
+ "facebook",
+ "front",
+ "github",
+ "gitlab",
+ "google_docs",
+ "google_mail",
+ "google_sheet",
+ "hubspot",
+ "jira",
+ "linear",
+ "microsoft_teams",
+ "mixpanel",
+ "monday",
+ "outlook",
+ "perplexity",
+ "rippling",
+ "salesforce",
+ "segment",
+ "todoist",
+ "twitter",
+ "zoom",
+ ]
+ ]
+ | NotGiven = NOT_GIVEN,
# 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,
@@ -68,6 +119,8 @@ def list(
Args:
collection: Filter documents by collection.
+ source: Filter documents by source.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -89,6 +142,7 @@ def list(
"collection": collection,
"cursor": cursor,
"size": size,
+ "source": source,
},
document_list_params.DocumentListParams,
),
@@ -235,6 +289,28 @@ def get(
cast_to=Document,
)
+ def status(
+ self,
+ *,
+ # 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,
+ ) -> DocumentStatusResponse:
+ """
+ This endpoint shows the indexing progress of documents, both by provider and
+ total.
+ """
+ return self._get(
+ "/documents/status",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DocumentStatusResponse,
+ )
+
def upload(
self,
*,
@@ -315,6 +391,56 @@ def list(
collection: Optional[str] | NotGiven = NOT_GIVEN,
cursor: Optional[str] | NotGiven = NOT_GIVEN,
size: int | NotGiven = NOT_GIVEN,
+ source: Optional[
+ Literal[
+ "collections",
+ "web_crawler",
+ "notion",
+ "slack",
+ "google_calendar",
+ "reddit",
+ "box",
+ "google_drive",
+ "airtable",
+ "algolia",
+ "amplitude",
+ "asana",
+ "ashby",
+ "bamboohr",
+ "basecamp",
+ "bubbles",
+ "calendly",
+ "confluence",
+ "clickup",
+ "datadog",
+ "deel",
+ "discord",
+ "dropbox",
+ "exa",
+ "facebook",
+ "front",
+ "github",
+ "gitlab",
+ "google_docs",
+ "google_mail",
+ "google_sheet",
+ "hubspot",
+ "jira",
+ "linear",
+ "microsoft_teams",
+ "mixpanel",
+ "monday",
+ "outlook",
+ "perplexity",
+ "rippling",
+ "salesforce",
+ "segment",
+ "todoist",
+ "twitter",
+ "zoom",
+ ]
+ ]
+ | NotGiven = NOT_GIVEN,
# 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,
@@ -330,6 +456,8 @@ def list(
Args:
collection: Filter documents by collection.
+ source: Filter documents by source.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -351,6 +479,7 @@ def list(
"collection": collection,
"cursor": cursor,
"size": size,
+ "source": source,
},
document_list_params.DocumentListParams,
),
@@ -497,6 +626,28 @@ async def get(
cast_to=Document,
)
+ async def status(
+ self,
+ *,
+ # 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,
+ ) -> DocumentStatusResponse:
+ """
+ This endpoint shows the indexing progress of documents, both by provider and
+ total.
+ """
+ return await self._get(
+ "/documents/status",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DocumentStatusResponse,
+ )
+
async def upload(
self,
*,
@@ -564,6 +715,9 @@ def __init__(self, documents: DocumentsResource) -> None:
self.get = to_raw_response_wrapper(
documents.get,
)
+ self.status = to_raw_response_wrapper(
+ documents.status,
+ )
self.upload = to_raw_response_wrapper(
documents.upload,
)
@@ -582,6 +736,9 @@ def __init__(self, documents: AsyncDocumentsResource) -> None:
self.get = async_to_raw_response_wrapper(
documents.get,
)
+ self.status = async_to_raw_response_wrapper(
+ documents.status,
+ )
self.upload = async_to_raw_response_wrapper(
documents.upload,
)
@@ -600,6 +757,9 @@ def __init__(self, documents: DocumentsResource) -> None:
self.get = to_streamed_response_wrapper(
documents.get,
)
+ self.status = to_streamed_response_wrapper(
+ documents.status,
+ )
self.upload = to_streamed_response_wrapper(
documents.upload,
)
@@ -618,6 +778,9 @@ def __init__(self, documents: AsyncDocumentsResource) -> None:
self.get = async_to_streamed_response_wrapper(
documents.get,
)
+ self.status = async_to_streamed_response_wrapper(
+ documents.status,
+ )
self.upload = async_to_streamed_response_wrapper(
documents.upload,
)
diff --git a/src/hyperspell/types/__init__.py b/src/hyperspell/types/__init__.py
index a1b81417..4027566b 100644
--- a/src/hyperspell/types/__init__.py
+++ b/src/hyperspell/types/__init__.py
@@ -14,4 +14,5 @@
from .collection_list_params import CollectionListParams as CollectionListParams
from .document_upload_params import DocumentUploadParams as DocumentUploadParams
from .collection_list_response import CollectionListResponse as CollectionListResponse
+from .document_status_response import DocumentStatusResponse as DocumentStatusResponse
from .integration_revoke_response import IntegrationRevokeResponse as IntegrationRevokeResponse
diff --git a/src/hyperspell/types/document.py b/src/hyperspell/types/document.py
index 41b3cc80..69eab7b2 100644
--- a/src/hyperspell/types/document.py
+++ b/src/hyperspell/types/document.py
@@ -1,20 +1,30 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import TYPE_CHECKING, Optional
+from typing import TYPE_CHECKING, List, Optional
from datetime import datetime
from typing_extensions import Literal
from .._models import BaseModel
-__all__ = ["Document", "Metadata"]
+__all__ = ["Document", "Metadata", "MetadataEvent"]
+
+
+class MetadataEvent(BaseModel):
+ message: str
+
+ type: Literal["error", "warning", "info", "success"]
+
+ time: Optional[datetime] = None
class Metadata(BaseModel):
- created_at: Optional[datetime] = None
+ events: Optional[List[MetadataEvent]] = None
+
+ indexed_at: Optional[datetime] = None
last_modified: Optional[datetime] = None
- url: Optional[str] = None
+ status: Optional[Literal["pending", "processing", "completed", "failed"]] = None
if TYPE_CHECKING:
# Stub to indicate that arbitrary properties are accepted.
diff --git a/src/hyperspell/types/document_list_params.py b/src/hyperspell/types/document_list_params.py
index 6d142ffc..53440ca9 100644
--- a/src/hyperspell/types/document_list_params.py
+++ b/src/hyperspell/types/document_list_params.py
@@ -3,7 +3,7 @@
from __future__ import annotations
from typing import Optional
-from typing_extensions import TypedDict
+from typing_extensions import Literal, TypedDict
__all__ = ["DocumentListParams"]
@@ -15,3 +15,54 @@ class DocumentListParams(TypedDict, total=False):
cursor: Optional[str]
size: int
+
+ source: Optional[
+ Literal[
+ "collections",
+ "web_crawler",
+ "notion",
+ "slack",
+ "google_calendar",
+ "reddit",
+ "box",
+ "google_drive",
+ "airtable",
+ "algolia",
+ "amplitude",
+ "asana",
+ "ashby",
+ "bamboohr",
+ "basecamp",
+ "bubbles",
+ "calendly",
+ "confluence",
+ "clickup",
+ "datadog",
+ "deel",
+ "discord",
+ "dropbox",
+ "exa",
+ "facebook",
+ "front",
+ "github",
+ "gitlab",
+ "google_docs",
+ "google_mail",
+ "google_sheet",
+ "hubspot",
+ "jira",
+ "linear",
+ "microsoft_teams",
+ "mixpanel",
+ "monday",
+ "outlook",
+ "perplexity",
+ "rippling",
+ "salesforce",
+ "segment",
+ "todoist",
+ "twitter",
+ "zoom",
+ ]
+ ]
+ """Filter documents by source."""
diff --git a/src/hyperspell/types/document_status_response.py b/src/hyperspell/types/document_status_response.py
new file mode 100644
index 00000000..022be1c7
--- /dev/null
+++ b/src/hyperspell/types/document_status_response.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict
+
+from .._models import BaseModel
+
+__all__ = ["DocumentStatusResponse"]
+
+
+class DocumentStatusResponse(BaseModel):
+ providers: Dict[str, Dict[str, int]]
+
+ total: Dict[str, int]
diff --git a/tests/api_resources/test_documents.py b/tests/api_resources/test_documents.py
index 6418c517..5f4260a5 100644
--- a/tests/api_resources/test_documents.py
+++ b/tests/api_resources/test_documents.py
@@ -9,7 +9,11 @@
from hyperspell import Hyperspell, AsyncHyperspell
from tests.utils import assert_matches_type
-from hyperspell.types import Document, DocumentStatus
+from hyperspell.types import (
+ Document,
+ DocumentStatus,
+ DocumentStatusResponse,
+)
from hyperspell._utils import parse_datetime
from hyperspell.pagination import SyncCursorPage, AsyncCursorPage
@@ -30,6 +34,7 @@ def test_method_list_with_all_params(self, client: Hyperspell) -> None:
collection="collection",
cursor="cursor",
size=0,
+ source="collections",
)
assert_matches_type(SyncCursorPage[Document], document, path=["response"])
@@ -136,6 +141,31 @@ def test_path_params_get(self, client: Hyperspell) -> None:
source="collections",
)
+ @parametrize
+ def test_method_status(self, client: Hyperspell) -> None:
+ document = client.documents.status()
+ assert_matches_type(DocumentStatusResponse, document, path=["response"])
+
+ @parametrize
+ def test_raw_response_status(self, client: Hyperspell) -> None:
+ response = client.documents.with_raw_response.status()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert_matches_type(DocumentStatusResponse, document, path=["response"])
+
+ @parametrize
+ def test_streaming_response_status(self, client: Hyperspell) -> None:
+ with client.documents.with_streaming_response.status() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = response.parse()
+ assert_matches_type(DocumentStatusResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@parametrize
def test_method_upload(self, client: Hyperspell) -> None:
document = client.documents.upload(
@@ -190,6 +220,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncHyperspell)
collection="collection",
cursor="cursor",
size=0,
+ source="collections",
)
assert_matches_type(AsyncCursorPage[Document], document, path=["response"])
@@ -296,6 +327,31 @@ async def test_path_params_get(self, async_client: AsyncHyperspell) -> None:
source="collections",
)
+ @parametrize
+ async def test_method_status(self, async_client: AsyncHyperspell) -> None:
+ document = await async_client.documents.status()
+ assert_matches_type(DocumentStatusResponse, document, path=["response"])
+
+ @parametrize
+ async def test_raw_response_status(self, async_client: AsyncHyperspell) -> None:
+ response = await async_client.documents.with_raw_response.status()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = await response.parse()
+ assert_matches_type(DocumentStatusResponse, document, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_status(self, async_client: AsyncHyperspell) -> None:
+ async with async_client.documents.with_streaming_response.status() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = await response.parse()
+ assert_matches_type(DocumentStatusResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@parametrize
async def test_method_upload(self, async_client: AsyncHyperspell) -> None:
document = await async_client.documents.upload(
From 63edbe9b4b19c321826f2869eb40b99b1dfb90de Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 29 May 2025 22:28:53 +0000
Subject: [PATCH 5/7] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 6b2619bf..1ff8b2f5 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 12
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-472f6034747ca75f970d64e57875f1cb24991ad422e17f3e9839757b84e2cb3d.yml
-openapi_spec_hash: 9759125c6a0c64da09c94923667f34a5
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-1ca02322a64dc74cf4ded90d09e6b722aaf69986d2d76bf5aada8567a72ae46f.yml
+openapi_spec_hash: b067b13c3b9dd9d7eaf7ba920a8d48fe
config_hash: da009f16a6b9b4db17be2949180ace1e
From 1f536d32840d05ab3bff68d0ae4a1ed9ded125d1 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 29 May 2025 22:31:28 +0000
Subject: [PATCH 6/7] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 1ff8b2f5..6b2619bf 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 12
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-1ca02322a64dc74cf4ded90d09e6b722aaf69986d2d76bf5aada8567a72ae46f.yml
-openapi_spec_hash: b067b13c3b9dd9d7eaf7ba920a8d48fe
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hyperspell%2Fhyperspell-472f6034747ca75f970d64e57875f1cb24991ad422e17f3e9839757b84e2cb3d.yml
+openapi_spec_hash: 9759125c6a0c64da09c94923667f34a5
config_hash: da009f16a6b9b4db17be2949180ace1e
From 3620b477f1a757fa3e2b05bdcfd9735453a362b9 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 29 May 2025 22:31:43 +0000
Subject: [PATCH 7/7] release: 0.16.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 10 ++++++++++
pyproject.toml | 2 +-
src/hyperspell/_version.py | 2 +-
4 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index d52d2b97..b4e9013b 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.13.0"
+ ".": "0.16.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3ebd15c3..db238388 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
# Changelog
+## 0.16.0 (2025-05-29)
+
+Full Changelog: [v0.13.0...v0.16.0](https://github.com/hyperspell/python-sdk/compare/v0.13.0...v0.16.0)
+
+### Features
+
+* **api:** api update ([3334f14](https://github.com/hyperspell/python-sdk/commit/3334f14582bda6ec78c9b479317c8d818b1c1227))
+* **api:** api update ([b6ad9f4](https://github.com/hyperspell/python-sdk/commit/b6ad9f43113a8cbf23580027c37ecaf95cb37cb3))
+* **api:** update via SDK Studio ([bff74c9](https://github.com/hyperspell/python-sdk/commit/bff74c98b5b08e45e291381753340a22c6b04c89))
+
## 0.13.0 (2025-05-26)
Full Changelog: [v0.12.0...v0.13.0](https://github.com/hyperspell/python-sdk/compare/v0.12.0...v0.13.0)
diff --git a/pyproject.toml b/pyproject.toml
index 5e390d44..01599def 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "hyperspell"
-version = "0.13.0"
+version = "0.16.0"
description = "The official Python library for the hyperspell API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/hyperspell/_version.py b/src/hyperspell/_version.py
index 58ec2dd0..1d221945 100644
--- a/src/hyperspell/_version.py
+++ b/src/hyperspell/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "hyperspell"
-__version__ = "0.13.0" # x-release-please-version
+__version__ = "0.16.0" # x-release-please-version