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
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/sambanova-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand All @@ -43,10 +43,10 @@ jobs:
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/sambanova-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand All @@ -61,7 +61,7 @@ jobs:
github.repository == 'stainless-sdks/sambanova-python' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setOutput('github_token', await core.getIDToken());

Expand All @@ -81,10 +81,10 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/sambanova-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:
id-token: write

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.9.13'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
if: github.repository == 'sambanova/sambanova-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Check release environment
run: |
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.8.2"
".": "1.9.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 8
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sambanova/sambanova-5884297580e5423cf40bd59057ea55da0384fe34f431a80cac0eece6176c6057.yml
openapi_spec_hash: 9306c1d75784a840a2973024fa94d22d
config_hash: 315596f19f192be2b7bf343664a7eb90
configured_endpoints: 10
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sambanova/sambanova-f9a2632e2ea9632e8b40258f57bfa8b529b926d72fd8b1f9550848fbb880e0de.yml
openapi_spec_hash: 8df9e2ad31769c26c590dacf3517bc36
config_hash: d33fc68f92caf09c6b3b40675a111114
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 1.9.0 (2026-05-26)

Full Changelog: [v1.8.2...v1.9.0](https://github.com/sambanova/sambanova-python/compare/v1.8.2...v1.9.0)

### Features

* **api:** add anthropic compatible messages api support ([0ddfd33](https://github.com/sambanova/sambanova-python/commit/0ddfd334decc86831f840cd8c0de2c3a73e378a2))
* **internal/types:** support eagerly validating pydantic iterators ([cc4aade](https://github.com/sambanova/sambanova-python/commit/cc4aade45c484980fafacf2e315ca6f1564e0ace))


### Bug Fixes

* **client:** add missing f-string prefix in file type error message ([c6b84e8](https://github.com/sambanova/sambanova-python/commit/c6b84e853be657a330e6754894911bdaac07dc67))

## 1.8.2 (2026-05-07)

Full Changelog: [v1.8.1...v1.8.2](https://github.com/sambanova/sambanova-python/compare/v1.8.1...v1.8.2)
Expand Down
19 changes: 19 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,25 @@ Methods:

- <code title="post /responses">client.responses.<a href="./src/sambanova/resources/responses.py">create</a>(\*\*<a href="src/sambanova/types/response_create_params.py">params</a>) -> <a href="./src/sambanova/types/response_create_response.py">ResponseCreateResponse</a></code>

# Messages

Types:

```python
from sambanova.types import (
Message,
MessageCountTokensResponse,
MessageErrorResponse,
MessageStreamEvent,
MessageCreateResponse,
)
```

Methods:

- <code title="post /messages">client.messages.<a href="./src/sambanova/resources/messages.py">create</a>(\*\*<a href="src/sambanova/types/message_create_params.py">params</a>) -> <a href="./src/sambanova/types/message_create_response.py">MessageCreateResponse</a></code>
- <code title="post /messages/count_tokens">client.messages.<a href="./src/sambanova/resources/messages.py">count_tokens</a>(\*\*<a href="src/sambanova/types/message_count_tokens_params.py">params</a>) -> <a href="./src/sambanova/types/message_count_tokens_response.py">MessageCountTokensResponse</a></code>

# Models

Types:
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 = "sambanova"
version = "1.8.2"
version = "1.9.0"
description = "The official Python library for the SambaNova API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
79 changes: 78 additions & 1 deletion src/sambanova/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@
)

if TYPE_CHECKING:
from .resources import chat, audio, models, responses, embeddings, completions
from .resources import chat, audio, models, messages, responses, embeddings, completions
from .resources.models import ModelsResource, AsyncModelsResource
from .resources.messages import MessagesResource, AsyncMessagesResource
from .resources.chat.chat import ChatResource, AsyncChatResource
from .resources.responses import ResponsesResource, AsyncResponsesResource
from .resources.embeddings import EmbeddingsResource, AsyncEmbeddingsResource
Expand All @@ -58,12 +59,14 @@
class SambaNova(SyncAPIClient):
# client options
api_key: str
x_api_key: str | None
integration_source: str | None

def __init__(
self,
*,
api_key: str | None = None,
x_api_key: str | None = None,
integration_source: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
Expand All @@ -88,6 +91,7 @@ def __init__(

This automatically infers the following arguments from their corresponding environment variables if they are not provided:
- `api_key` from `SAMBANOVA_API_KEY`
- `x_api_key` from `SAMBANOVA_API_KEY`
- `integration_source` from `SAMBANOVA_INTEGRATION_SOURCE`
"""
if api_key is None:
Expand All @@ -98,6 +102,10 @@ def __init__(
)
self.api_key = api_key

if x_api_key is None:
x_api_key = os.environ.get("SAMBANOVA_API_KEY")
self.x_api_key = x_api_key

if integration_source is None:
integration_source = os.environ.get("SAMBANOVA_INTEGRATION_SOURCE")
self.integration_source = integration_source
Expand Down Expand Up @@ -159,6 +167,12 @@ def responses(self) -> ResponsesResource:

return ResponsesResource(self)

@cached_property
def messages(self) -> MessagesResource:
from .resources.messages import MessagesResource

return MessagesResource(self)

@cached_property
def models(self) -> ModelsResource:
from .resources.models import ModelsResource
Expand All @@ -181,9 +195,20 @@ def qs(self) -> Querystring:
@property
@override
def auth_headers(self) -> dict[str, str]:
return {**self._api_key, **self._x_api_key}

@property
def _api_key(self) -> dict[str, str]:
api_key = self.api_key
return {"Authorization": f"Bearer {api_key}"}

@property
def _x_api_key(self) -> dict[str, str]:
x_api_key = self.x_api_key
if x_api_key is None:
return {}
return {"x-api-key": x_api_key}

@property
@override
def default_headers(self) -> dict[str, str | Omit]:
Expand All @@ -198,6 +223,7 @@ def copy(
self,
*,
api_key: str | None = None,
x_api_key: str | None = None,
integration_source: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
Expand Down Expand Up @@ -233,6 +259,7 @@ def copy(
http_client = http_client or self._client
return self.__class__(
api_key=api_key or self.api_key,
x_api_key=x_api_key or self.x_api_key,
integration_source=integration_source or self.integration_source,
base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
Expand Down Expand Up @@ -284,12 +311,14 @@ def _make_status_error(
class AsyncSambaNova(AsyncAPIClient):
# client options
api_key: str
x_api_key: str | None
integration_source: str | None

def __init__(
self,
*,
api_key: str | None = None,
x_api_key: str | None = None,
integration_source: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
Expand All @@ -314,6 +343,7 @@ def __init__(

This automatically infers the following arguments from their corresponding environment variables if they are not provided:
- `api_key` from `SAMBANOVA_API_KEY`
- `x_api_key` from `SAMBANOVA_API_KEY`
- `integration_source` from `SAMBANOVA_INTEGRATION_SOURCE`
"""
if api_key is None:
Expand All @@ -324,6 +354,10 @@ def __init__(
)
self.api_key = api_key

if x_api_key is None:
x_api_key = os.environ.get("SAMBANOVA_API_KEY")
self.x_api_key = x_api_key

if integration_source is None:
integration_source = os.environ.get("SAMBANOVA_INTEGRATION_SOURCE")
self.integration_source = integration_source
Expand Down Expand Up @@ -385,6 +419,12 @@ def responses(self) -> AsyncResponsesResource:

return AsyncResponsesResource(self)

@cached_property
def messages(self) -> AsyncMessagesResource:
from .resources.messages import AsyncMessagesResource

return AsyncMessagesResource(self)

@cached_property
def models(self) -> AsyncModelsResource:
from .resources.models import AsyncModelsResource
Expand All @@ -407,9 +447,20 @@ def qs(self) -> Querystring:
@property
@override
def auth_headers(self) -> dict[str, str]:
return {**self._api_key, **self._x_api_key}

@property
def _api_key(self) -> dict[str, str]:
api_key = self.api_key
return {"Authorization": f"Bearer {api_key}"}

@property
def _x_api_key(self) -> dict[str, str]:
x_api_key = self.x_api_key
if x_api_key is None:
return {}
return {"x-api-key": x_api_key}

@property
@override
def default_headers(self) -> dict[str, str | Omit]:
Expand All @@ -424,6 +475,7 @@ def copy(
self,
*,
api_key: str | None = None,
x_api_key: str | None = None,
integration_source: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
Expand Down Expand Up @@ -459,6 +511,7 @@ def copy(
http_client = http_client or self._client
return self.__class__(
api_key=api_key or self.api_key,
x_api_key=x_api_key or self.x_api_key,
integration_source=integration_source or self.integration_source,
base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
Expand Down Expand Up @@ -543,6 +596,12 @@ def responses(self) -> responses.ResponsesResourceWithRawResponse:

return ResponsesResourceWithRawResponse(self._client.responses)

@cached_property
def messages(self) -> messages.MessagesResourceWithRawResponse:
from .resources.messages import MessagesResourceWithRawResponse

return MessagesResourceWithRawResponse(self._client.messages)

@cached_property
def models(self) -> models.ModelsResourceWithRawResponse:
from .resources.models import ModelsResourceWithRawResponse
Expand Down Expand Up @@ -586,6 +645,12 @@ def responses(self) -> responses.AsyncResponsesResourceWithRawResponse:

return AsyncResponsesResourceWithRawResponse(self._client.responses)

@cached_property
def messages(self) -> messages.AsyncMessagesResourceWithRawResponse:
from .resources.messages import AsyncMessagesResourceWithRawResponse

return AsyncMessagesResourceWithRawResponse(self._client.messages)

@cached_property
def models(self) -> models.AsyncModelsResourceWithRawResponse:
from .resources.models import AsyncModelsResourceWithRawResponse
Expand Down Expand Up @@ -629,6 +694,12 @@ def responses(self) -> responses.ResponsesResourceWithStreamingResponse:

return ResponsesResourceWithStreamingResponse(self._client.responses)

@cached_property
def messages(self) -> messages.MessagesResourceWithStreamingResponse:
from .resources.messages import MessagesResourceWithStreamingResponse

return MessagesResourceWithStreamingResponse(self._client.messages)

@cached_property
def models(self) -> models.ModelsResourceWithStreamingResponse:
from .resources.models import ModelsResourceWithStreamingResponse
Expand Down Expand Up @@ -672,6 +743,12 @@ def responses(self) -> responses.AsyncResponsesResourceWithStreamingResponse:

return AsyncResponsesResourceWithStreamingResponse(self._client.responses)

@cached_property
def messages(self) -> messages.AsyncMessagesResourceWithStreamingResponse:
from .resources.messages import AsyncMessagesResourceWithStreamingResponse

return AsyncMessagesResourceWithStreamingResponse(self._client.messages)

@cached_property
def models(self) -> models.AsyncModelsResourceWithStreamingResponse:
from .resources.models import AsyncModelsResourceWithStreamingResponse
Expand Down
2 changes: 1 addition & 1 deletion src/sambanova/_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles
elif is_sequence_t(files):
files = [(key, await _async_transform_file(file)) for key, file in files]
else:
raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence")
raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence")

return files

Expand Down
Loading
Loading