diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 85ea8cd..1eec10e 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "4.6.3"
+ ".": "4.7.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 720cb80..e306cf4 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 14
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml%2Frunwayml-b3276a8508268090b14e297f5cb18448da7a763653c6d38c23f0eea0984d8008.yml
-openapi_spec_hash: 95ae975f17217c8d144c4ba80846beca
-config_hash: 803d5c0aa94eea0a7981b91728218d3f
+configured_endpoints: 31
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml%2Frunwayml-4ddc8e3d83c8601fc378c702bbcb5af2976b481db513bd389a5f57645a20cd04.yml
+openapi_spec_hash: 5795c6af9e9404765bda670e781fe500
+config_hash: 3c88fcd4dd6f3a7d7f6e94b57b430243
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1f5833e..f371af4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## 4.7.0 (2026-03-06)
+
+Full Changelog: [v4.6.3...v4.7.0](https://github.com/runwayml/sdk-python/compare/v4.6.3...v4.7.0)
+
+### Features
+
+* **api:** add avatar, voice, document, and realtime session endpoints ([18b1573](https://github.com/runwayml/sdk-python/commit/18b15733d52e1ddb60d1f9a847e4fd7a712b4701))
+
+
+### Chores
+
+* **test:** do not count install time for mock server timeout ([84988e1](https://github.com/runwayml/sdk-python/commit/84988e1eeaa6d25b265bfb77863ed6a4ce271201))
+
## 4.6.3 (2026-02-27)
Full Changelog: [v4.6.2...v4.6.3](https://github.com/runwayml/sdk-python/compare/v4.6.2...v4.6.3)
diff --git a/README.md b/README.md
index 10b9971..00f3a2a 100644
--- a/README.md
+++ b/README.md
@@ -121,6 +121,77 @@ Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typ
Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.
+## Pagination
+
+List methods in the RunwayML API are paginated.
+
+This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:
+
+```python
+from runwayml import RunwayML
+
+client = RunwayML()
+
+all_avatars = []
+# Automatically fetches more pages as needed.
+for avatar in client.avatars.list(
+ limit=1,
+):
+ # Do something with avatar here
+ all_avatars.append(avatar)
+print(all_avatars)
+```
+
+Or, asynchronously:
+
+```python
+import asyncio
+from runwayml import AsyncRunwayML
+
+client = AsyncRunwayML()
+
+
+async def main() -> None:
+ all_avatars = []
+ # Iterate through items across all pages, issuing requests as needed.
+ async for avatar in client.avatars.list(
+ limit=1,
+ ):
+ all_avatars.append(avatar)
+ print(all_avatars)
+
+
+asyncio.run(main())
+```
+
+Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:
+
+```python
+first_page = await client.avatars.list(
+ limit=1,
+)
+if first_page.has_next_page():
+ print(f"will fetch next page using these details: {first_page.next_page_info()}")
+ next_page = await first_page.get_next_page()
+ print(f"number of items we just fetched: {len(next_page.data)}")
+
+# Remove `await` for non-async usage.
+```
+
+Or just work directly with the returned data:
+
+```python
+first_page = await client.avatars.list(
+ limit=1,
+)
+
+print(f"next page cursor: {first_page.next_cursor}") # => "next page cursor: ..."
+for avatar in first_page.data:
+ print(avatar)
+
+# Remove `await` for non-async usage.
+```
+
## Nested params
Nested parameters are dictionaries, typed using `TypedDict`, for example:
diff --git a/api.md b/api.md
index 72145fe..6661946 100644
--- a/api.md
+++ b/api.md
@@ -143,3 +143,74 @@ Methods:
- client.organization.retrieve() -> OrganizationRetrieveResponse
- client.organization.retrieve_usage(\*\*params) -> OrganizationRetrieveUsageResponse
+
+# Avatars
+
+Types:
+
+```python
+from runwayml.types import (
+ AvatarCreateResponse,
+ AvatarRetrieveResponse,
+ AvatarUpdateResponse,
+ AvatarListResponse,
+)
+```
+
+Methods:
+
+- client.avatars.create(\*\*params) -> AvatarCreateResponse
+- client.avatars.retrieve(id) -> AvatarRetrieveResponse
+- client.avatars.update(id, \*\*params) -> AvatarUpdateResponse
+- client.avatars.list(\*\*params) -> SyncCursorPage[AvatarListResponse]
+- client.avatars.delete(id) -> None
+
+# Documents
+
+Types:
+
+```python
+from runwayml.types import DocumentCreateResponse, DocumentRetrieveResponse, DocumentListResponse
+```
+
+Methods:
+
+- client.documents.create(\*\*params) -> DocumentCreateResponse
+- client.documents.retrieve(id) -> DocumentRetrieveResponse
+- client.documents.list(\*\*params) -> SyncCursorPage[DocumentListResponse]
+- client.documents.delete(id) -> None
+
+# RealtimeSessions
+
+Types:
+
+```python
+from runwayml.types import RealtimeSessionCreateResponse, RealtimeSessionRetrieveResponse
+```
+
+Methods:
+
+- client.realtime_sessions.create(\*\*params) -> RealtimeSessionCreateResponse
+- client.realtime_sessions.retrieve(id) -> RealtimeSessionRetrieveResponse
+- client.realtime_sessions.delete(id) -> None
+
+# Voices
+
+Types:
+
+```python
+from runwayml.types import (
+ VoiceCreateResponse,
+ VoiceRetrieveResponse,
+ VoiceListResponse,
+ VoicePreviewResponse,
+)
+```
+
+Methods:
+
+- client.voices.create(\*\*params) -> VoiceCreateResponse
+- client.voices.retrieve(id) -> VoiceRetrieveResponse
+- client.voices.list(\*\*params) -> SyncCursorPage[VoiceListResponse]
+- client.voices.delete(id) -> None
+- client.voices.preview(\*\*params) -> VoicePreviewResponse
diff --git a/pyproject.toml b/pyproject.toml
index 020798f..8f44411 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "runwayml"
-version = "4.6.3"
+version = "4.7.0"
description = "The official Python library for the runwayml API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/scripts/mock b/scripts/mock
index 0b28f6e..bcf3b39 100755
--- a/scripts/mock
+++ b/scripts/mock
@@ -21,11 +21,22 @@ echo "==> Starting mock server with URL ${URL}"
# Run prism mock on the given spec
if [ "$1" == "--daemon" ]; then
+ # Pre-install the package so the download doesn't eat into the startup timeout
+ npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version
+
npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log &
- # Wait for server to come online
+ # Wait for server to come online (max 30s)
echo -n "Waiting for server"
+ attempts=0
while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do
+ attempts=$((attempts + 1))
+ if [ "$attempts" -ge 300 ]; then
+ echo
+ echo "Timed out waiting for Prism server to start"
+ cat .prism.log
+ exit 1
+ fi
echo -n "."
sleep 0.1
done
diff --git a/src/runwayml/_client.py b/src/runwayml/_client.py
index 047882b..4bee591 100644
--- a/src/runwayml/_client.py
+++ b/src/runwayml/_client.py
@@ -33,7 +33,10 @@
if TYPE_CHECKING:
from .resources import (
tasks,
+ voices,
+ avatars,
uploads,
+ documents,
organization,
sound_effect,
text_to_image,
@@ -44,10 +47,14 @@
video_to_video,
voice_isolation,
speech_to_speech,
+ realtime_sessions,
character_performance,
)
from .resources.tasks import TasksResource, AsyncTasksResource
+ from .resources.voices import VoicesResource, AsyncVoicesResource
+ from .resources.avatars import AvatarsResource, AsyncAvatarsResource
from .resources.uploads import UploadsResource, AsyncUploadsResource
+ from .resources.documents import DocumentsResource, AsyncDocumentsResource
from .resources.organization import OrganizationResource, AsyncOrganizationResource
from .resources.sound_effect import SoundEffectResource, AsyncSoundEffectResource
from .resources.text_to_image import TextToImageResource, AsyncTextToImageResource
@@ -58,6 +65,7 @@
from .resources.video_to_video import VideoToVideoResource, AsyncVideoToVideoResource
from .resources.voice_isolation import VoiceIsolationResource, AsyncVoiceIsolationResource
from .resources.speech_to_speech import SpeechToSpeechResource, AsyncSpeechToSpeechResource
+ from .resources.realtime_sessions import RealtimeSessionsResource, AsyncRealtimeSessionsResource
from .resources.character_performance import CharacterPerformanceResource, AsyncCharacterPerformanceResource
__all__ = [
@@ -222,6 +230,30 @@ def organization(self) -> OrganizationResource:
return OrganizationResource(self)
+ @cached_property
+ def avatars(self) -> AvatarsResource:
+ from .resources.avatars import AvatarsResource
+
+ return AvatarsResource(self)
+
+ @cached_property
+ def documents(self) -> DocumentsResource:
+ from .resources.documents import DocumentsResource
+
+ return DocumentsResource(self)
+
+ @cached_property
+ def realtime_sessions(self) -> RealtimeSessionsResource:
+ from .resources.realtime_sessions import RealtimeSessionsResource
+
+ return RealtimeSessionsResource(self)
+
+ @cached_property
+ def voices(self) -> VoicesResource:
+ from .resources.voices import VoicesResource
+
+ return VoicesResource(self)
+
@cached_property
def with_raw_response(self) -> RunwayMLWithRawResponse:
return RunwayMLWithRawResponse(self)
@@ -488,6 +520,30 @@ def organization(self) -> AsyncOrganizationResource:
return AsyncOrganizationResource(self)
+ @cached_property
+ def avatars(self) -> AsyncAvatarsResource:
+ from .resources.avatars import AsyncAvatarsResource
+
+ return AsyncAvatarsResource(self)
+
+ @cached_property
+ def documents(self) -> AsyncDocumentsResource:
+ from .resources.documents import AsyncDocumentsResource
+
+ return AsyncDocumentsResource(self)
+
+ @cached_property
+ def realtime_sessions(self) -> AsyncRealtimeSessionsResource:
+ from .resources.realtime_sessions import AsyncRealtimeSessionsResource
+
+ return AsyncRealtimeSessionsResource(self)
+
+ @cached_property
+ def voices(self) -> AsyncVoicesResource:
+ from .resources.voices import AsyncVoicesResource
+
+ return AsyncVoicesResource(self)
+
@cached_property
def with_raw_response(self) -> AsyncRunwayMLWithRawResponse:
return AsyncRunwayMLWithRawResponse(self)
@@ -699,6 +755,30 @@ def organization(self) -> organization.OrganizationResourceWithRawResponse:
return OrganizationResourceWithRawResponse(self._client.organization)
+ @cached_property
+ def avatars(self) -> avatars.AvatarsResourceWithRawResponse:
+ from .resources.avatars import AvatarsResourceWithRawResponse
+
+ return AvatarsResourceWithRawResponse(self._client.avatars)
+
+ @cached_property
+ def documents(self) -> documents.DocumentsResourceWithRawResponse:
+ from .resources.documents import DocumentsResourceWithRawResponse
+
+ return DocumentsResourceWithRawResponse(self._client.documents)
+
+ @cached_property
+ def realtime_sessions(self) -> realtime_sessions.RealtimeSessionsResourceWithRawResponse:
+ from .resources.realtime_sessions import RealtimeSessionsResourceWithRawResponse
+
+ return RealtimeSessionsResourceWithRawResponse(self._client.realtime_sessions)
+
+ @cached_property
+ def voices(self) -> voices.VoicesResourceWithRawResponse:
+ from .resources.voices import VoicesResourceWithRawResponse
+
+ return VoicesResourceWithRawResponse(self._client.voices)
+
class AsyncRunwayMLWithRawResponse:
_client: AsyncRunwayML
@@ -795,6 +875,30 @@ def organization(self) -> organization.AsyncOrganizationResourceWithRawResponse:
return AsyncOrganizationResourceWithRawResponse(self._client.organization)
+ @cached_property
+ def avatars(self) -> avatars.AsyncAvatarsResourceWithRawResponse:
+ from .resources.avatars import AsyncAvatarsResourceWithRawResponse
+
+ return AsyncAvatarsResourceWithRawResponse(self._client.avatars)
+
+ @cached_property
+ def documents(self) -> documents.AsyncDocumentsResourceWithRawResponse:
+ from .resources.documents import AsyncDocumentsResourceWithRawResponse
+
+ return AsyncDocumentsResourceWithRawResponse(self._client.documents)
+
+ @cached_property
+ def realtime_sessions(self) -> realtime_sessions.AsyncRealtimeSessionsResourceWithRawResponse:
+ from .resources.realtime_sessions import AsyncRealtimeSessionsResourceWithRawResponse
+
+ return AsyncRealtimeSessionsResourceWithRawResponse(self._client.realtime_sessions)
+
+ @cached_property
+ def voices(self) -> voices.AsyncVoicesResourceWithRawResponse:
+ from .resources.voices import AsyncVoicesResourceWithRawResponse
+
+ return AsyncVoicesResourceWithRawResponse(self._client.voices)
+
class RunwayMLWithStreamedResponse:
_client: RunwayML
@@ -891,6 +995,30 @@ def organization(self) -> organization.OrganizationResourceWithStreamingResponse
return OrganizationResourceWithStreamingResponse(self._client.organization)
+ @cached_property
+ def avatars(self) -> avatars.AvatarsResourceWithStreamingResponse:
+ from .resources.avatars import AvatarsResourceWithStreamingResponse
+
+ return AvatarsResourceWithStreamingResponse(self._client.avatars)
+
+ @cached_property
+ def documents(self) -> documents.DocumentsResourceWithStreamingResponse:
+ from .resources.documents import DocumentsResourceWithStreamingResponse
+
+ return DocumentsResourceWithStreamingResponse(self._client.documents)
+
+ @cached_property
+ def realtime_sessions(self) -> realtime_sessions.RealtimeSessionsResourceWithStreamingResponse:
+ from .resources.realtime_sessions import RealtimeSessionsResourceWithStreamingResponse
+
+ return RealtimeSessionsResourceWithStreamingResponse(self._client.realtime_sessions)
+
+ @cached_property
+ def voices(self) -> voices.VoicesResourceWithStreamingResponse:
+ from .resources.voices import VoicesResourceWithStreamingResponse
+
+ return VoicesResourceWithStreamingResponse(self._client.voices)
+
class AsyncRunwayMLWithStreamedResponse:
_client: AsyncRunwayML
@@ -987,6 +1115,30 @@ def organization(self) -> organization.AsyncOrganizationResourceWithStreamingRes
return AsyncOrganizationResourceWithStreamingResponse(self._client.organization)
+ @cached_property
+ def avatars(self) -> avatars.AsyncAvatarsResourceWithStreamingResponse:
+ from .resources.avatars import AsyncAvatarsResourceWithStreamingResponse
+
+ return AsyncAvatarsResourceWithStreamingResponse(self._client.avatars)
+
+ @cached_property
+ def documents(self) -> documents.AsyncDocumentsResourceWithStreamingResponse:
+ from .resources.documents import AsyncDocumentsResourceWithStreamingResponse
+
+ return AsyncDocumentsResourceWithStreamingResponse(self._client.documents)
+
+ @cached_property
+ def realtime_sessions(self) -> realtime_sessions.AsyncRealtimeSessionsResourceWithStreamingResponse:
+ from .resources.realtime_sessions import AsyncRealtimeSessionsResourceWithStreamingResponse
+
+ return AsyncRealtimeSessionsResourceWithStreamingResponse(self._client.realtime_sessions)
+
+ @cached_property
+ def voices(self) -> voices.AsyncVoicesResourceWithStreamingResponse:
+ from .resources.voices import AsyncVoicesResourceWithStreamingResponse
+
+ return AsyncVoicesResourceWithStreamingResponse(self._client.voices)
+
Client = RunwayML
diff --git a/src/runwayml/_version.py b/src/runwayml/_version.py
index 0a54027..86051f8 100644
--- a/src/runwayml/_version.py
+++ b/src/runwayml/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "runwayml"
-__version__ = "4.6.3" # x-release-please-version
+__version__ = "4.7.0" # x-release-please-version
diff --git a/src/runwayml/pagination.py b/src/runwayml/pagination.py
new file mode 100644
index 0000000..a61c6ad
--- /dev/null
+++ b/src/runwayml/pagination.py
@@ -0,0 +1,52 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Generic, TypeVar, Optional
+from typing_extensions import override
+
+from pydantic import Field as FieldInfo
+
+from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage
+
+__all__ = ["SyncCursorPage", "AsyncCursorPage"]
+
+_T = TypeVar("_T")
+
+
+class SyncCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ data: List[_T]
+ next_cursor: Optional[str] = FieldInfo(alias="nextCursor", default=None)
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ data = self.data
+ if not data:
+ return []
+ return data
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class AsyncCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ data: List[_T]
+ next_cursor: Optional[str] = FieldInfo(alias="nextCursor", default=None)
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ data = self.data
+ if not data:
+ return []
+ return data
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
diff --git a/src/runwayml/resources/__init__.py b/src/runwayml/resources/__init__.py
index 1b6f367..cd9219d 100644
--- a/src/runwayml/resources/__init__.py
+++ b/src/runwayml/resources/__init__.py
@@ -96,6 +96,14 @@
SpeechToSpeechResourceWithStreamingResponse,
AsyncSpeechToSpeechResourceWithStreamingResponse,
)
+from .realtime_sessions import (
+ RealtimeSessionsResource,
+ AsyncRealtimeSessionsResource,
+ RealtimeSessionsResourceWithRawResponse,
+ AsyncRealtimeSessionsResourceWithRawResponse,
+ RealtimeSessionsResourceWithStreamingResponse,
+ AsyncRealtimeSessionsResourceWithStreamingResponse,
+)
from .character_performance import (
CharacterPerformanceResource,
AsyncCharacterPerformanceResource,
@@ -184,4 +192,10 @@
"AsyncUploadsResourceWithRawResponse",
"UploadsResourceWithStreamingResponse",
"AsyncUploadsResourceWithStreamingResponse",
+ "RealtimeSessionsResource",
+ "AsyncRealtimeSessionsResource",
+ "RealtimeSessionsResourceWithRawResponse",
+ "AsyncRealtimeSessionsResourceWithRawResponse",
+ "RealtimeSessionsResourceWithStreamingResponse",
+ "AsyncRealtimeSessionsResourceWithStreamingResponse",
]
diff --git a/src/runwayml/resources/avatars.py b/src/runwayml/resources/avatars.py
new file mode 100644
index 0000000..4556c2c
--- /dev/null
+++ b/src/runwayml/resources/avatars.py
@@ -0,0 +1,682 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Any, Optional, cast
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import avatar_list_params, avatar_create_params, avatar_update_params
+from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given
+from .._utils import maybe_transform, async_maybe_transform
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..pagination import SyncCursorPage, AsyncCursorPage
+from .._base_client import AsyncPaginator, make_request_options
+from ..types.avatar_list_response import AvatarListResponse
+from ..types.avatar_create_response import AvatarCreateResponse
+from ..types.avatar_update_response import AvatarUpdateResponse
+from ..types.avatar_retrieve_response import AvatarRetrieveResponse
+
+__all__ = ["AvatarsResource", "AsyncAvatarsResource"]
+
+
+class AvatarsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AvatarsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AvatarsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AvatarsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response
+ """
+ return AvatarsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ name: str,
+ personality: str,
+ reference_image: str,
+ voice: avatar_create_params.Voice,
+ document_ids: SequenceNotStr[str] | Omit = omit,
+ image_processing: Literal["optimize", "none"] | Omit = omit,
+ start_script: 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,
+ ) -> AvatarCreateResponse:
+ """
+ Create a new avatar with a reference image and voice.
+
+ Args:
+ name: The character name for the avatar.
+
+ personality: System prompt defining how the avatar should behave in conversations.
+
+ reference_image: A HTTPS URL.
+
+ voice: The voice configuration for the avatar.
+
+ document_ids: Optional list of knowledge document IDs to attach to this avatar. Documents
+ provide additional context during conversations.
+
+ image_processing: Controls image preprocessing. `optimize` improves the image for better avatar
+ results. `none` uses the image as-is; quality not guaranteed.
+
+ start_script: Optional opening message that the avatar will say when a session starts.
+
+ 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
+ """
+ return cast(
+ AvatarCreateResponse,
+ self._post(
+ "/v1/avatars",
+ body=maybe_transform(
+ {
+ "name": name,
+ "personality": personality,
+ "reference_image": reference_image,
+ "voice": voice,
+ "document_ids": document_ids,
+ "image_processing": image_processing,
+ "start_script": start_script,
+ },
+ avatar_create_params.AvatarCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AvatarCreateResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> AvatarRetrieveResponse:
+ """
+ Get details of a specific avatar.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ AvatarRetrieveResponse,
+ self._get(
+ f"/v1/avatars/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AvatarRetrieveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def update(
+ self,
+ id: str,
+ *,
+ document_ids: SequenceNotStr[str] | Omit = omit,
+ image_processing: Literal["optimize", "none"] | Omit = omit,
+ name: str | Omit = omit,
+ personality: str | Omit = omit,
+ reference_image: str | Omit = omit,
+ start_script: Optional[str] | Omit = omit,
+ voice: avatar_update_params.Voice | 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,
+ ) -> AvatarUpdateResponse:
+ """Update an existing avatar.
+
+ At least one field must be provided.
+
+ Args:
+ document_ids: List of knowledge document IDs to attach to this avatar. Replaces all current
+ attachments. Documents provide additional context during conversations.
+
+ image_processing: Controls image preprocessing. `optimize` improves the image for better avatar
+ results. `none` uses the image as-is; quality not guaranteed.
+
+ name: The character name for the avatar.
+
+ personality: System prompt defining how the avatar should behave in conversations.
+
+ reference_image: A HTTPS URL.
+
+ start_script: Optional opening message that the avatar will say when a session starts. Set to
+ null to clear.
+
+ voice: The voice configuration for the avatar.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ AvatarUpdateResponse,
+ self._patch(
+ f"/v1/avatars/{id}",
+ body=maybe_transform(
+ {
+ "document_ids": document_ids,
+ "image_processing": image_processing,
+ "name": name,
+ "personality": personality,
+ "reference_image": reference_image,
+ "start_script": start_script,
+ "voice": voice,
+ },
+ avatar_update_params.AvatarUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AvatarUpdateResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def list(
+ self,
+ *,
+ limit: int,
+ cursor: 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,
+ ) -> SyncCursorPage[AvatarListResponse]:
+ """
+ List avatars for the authenticated user with cursor-based pagination.
+
+ Args:
+ limit: The maximum number of items to return per page.
+
+ cursor: Cursor from a previous response for fetching the next page of results.
+
+ 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
+ """
+ return self._get_api_list(
+ "/v1/avatars",
+ page=SyncCursorPage[AvatarListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "cursor": cursor,
+ },
+ avatar_list_params.AvatarListParams,
+ ),
+ ),
+ model=cast(Any, AvatarListResponse), # Union types cannot be passed in as arguments in the type system
+ )
+
+ def delete(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> None:
+ """
+ Delete an avatar.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ f"/v1/avatars/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncAvatarsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncAvatarsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncAvatarsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAvatarsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response
+ """
+ return AsyncAvatarsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ name: str,
+ personality: str,
+ reference_image: str,
+ voice: avatar_create_params.Voice,
+ document_ids: SequenceNotStr[str] | Omit = omit,
+ image_processing: Literal["optimize", "none"] | Omit = omit,
+ start_script: 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,
+ ) -> AvatarCreateResponse:
+ """
+ Create a new avatar with a reference image and voice.
+
+ Args:
+ name: The character name for the avatar.
+
+ personality: System prompt defining how the avatar should behave in conversations.
+
+ reference_image: A HTTPS URL.
+
+ voice: The voice configuration for the avatar.
+
+ document_ids: Optional list of knowledge document IDs to attach to this avatar. Documents
+ provide additional context during conversations.
+
+ image_processing: Controls image preprocessing. `optimize` improves the image for better avatar
+ results. `none` uses the image as-is; quality not guaranteed.
+
+ start_script: Optional opening message that the avatar will say when a session starts.
+
+ 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
+ """
+ return cast(
+ AvatarCreateResponse,
+ await self._post(
+ "/v1/avatars",
+ body=await async_maybe_transform(
+ {
+ "name": name,
+ "personality": personality,
+ "reference_image": reference_image,
+ "voice": voice,
+ "document_ids": document_ids,
+ "image_processing": image_processing,
+ "start_script": start_script,
+ },
+ avatar_create_params.AvatarCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AvatarCreateResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ async def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> AvatarRetrieveResponse:
+ """
+ Get details of a specific avatar.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ AvatarRetrieveResponse,
+ await self._get(
+ f"/v1/avatars/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AvatarRetrieveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ async def update(
+ self,
+ id: str,
+ *,
+ document_ids: SequenceNotStr[str] | Omit = omit,
+ image_processing: Literal["optimize", "none"] | Omit = omit,
+ name: str | Omit = omit,
+ personality: str | Omit = omit,
+ reference_image: str | Omit = omit,
+ start_script: Optional[str] | Omit = omit,
+ voice: avatar_update_params.Voice | 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,
+ ) -> AvatarUpdateResponse:
+ """Update an existing avatar.
+
+ At least one field must be provided.
+
+ Args:
+ document_ids: List of knowledge document IDs to attach to this avatar. Replaces all current
+ attachments. Documents provide additional context during conversations.
+
+ image_processing: Controls image preprocessing. `optimize` improves the image for better avatar
+ results. `none` uses the image as-is; quality not guaranteed.
+
+ name: The character name for the avatar.
+
+ personality: System prompt defining how the avatar should behave in conversations.
+
+ reference_image: A HTTPS URL.
+
+ start_script: Optional opening message that the avatar will say when a session starts. Set to
+ null to clear.
+
+ voice: The voice configuration for the avatar.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ AvatarUpdateResponse,
+ await self._patch(
+ f"/v1/avatars/{id}",
+ body=await async_maybe_transform(
+ {
+ "document_ids": document_ids,
+ "image_processing": image_processing,
+ "name": name,
+ "personality": personality,
+ "reference_image": reference_image,
+ "start_script": start_script,
+ "voice": voice,
+ },
+ avatar_update_params.AvatarUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AvatarUpdateResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def list(
+ self,
+ *,
+ limit: int,
+ cursor: 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,
+ ) -> AsyncPaginator[AvatarListResponse, AsyncCursorPage[AvatarListResponse]]:
+ """
+ List avatars for the authenticated user with cursor-based pagination.
+
+ Args:
+ limit: The maximum number of items to return per page.
+
+ cursor: Cursor from a previous response for fetching the next page of results.
+
+ 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
+ """
+ return self._get_api_list(
+ "/v1/avatars",
+ page=AsyncCursorPage[AvatarListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "cursor": cursor,
+ },
+ avatar_list_params.AvatarListParams,
+ ),
+ ),
+ model=cast(Any, AvatarListResponse), # Union types cannot be passed in as arguments in the type system
+ )
+
+ async def delete(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> None:
+ """
+ Delete an avatar.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ f"/v1/avatars/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AvatarsResourceWithRawResponse:
+ def __init__(self, avatars: AvatarsResource) -> None:
+ self._avatars = avatars
+
+ self.create = to_raw_response_wrapper(
+ avatars.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ avatars.retrieve,
+ )
+ self.update = to_raw_response_wrapper(
+ avatars.update,
+ )
+ self.list = to_raw_response_wrapper(
+ avatars.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ avatars.delete,
+ )
+
+
+class AsyncAvatarsResourceWithRawResponse:
+ def __init__(self, avatars: AsyncAvatarsResource) -> None:
+ self._avatars = avatars
+
+ self.create = async_to_raw_response_wrapper(
+ avatars.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ avatars.retrieve,
+ )
+ self.update = async_to_raw_response_wrapper(
+ avatars.update,
+ )
+ self.list = async_to_raw_response_wrapper(
+ avatars.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ avatars.delete,
+ )
+
+
+class AvatarsResourceWithStreamingResponse:
+ def __init__(self, avatars: AvatarsResource) -> None:
+ self._avatars = avatars
+
+ self.create = to_streamed_response_wrapper(
+ avatars.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ avatars.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ avatars.update,
+ )
+ self.list = to_streamed_response_wrapper(
+ avatars.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ avatars.delete,
+ )
+
+
+class AsyncAvatarsResourceWithStreamingResponse:
+ def __init__(self, avatars: AsyncAvatarsResource) -> None:
+ self._avatars = avatars
+
+ self.create = async_to_streamed_response_wrapper(
+ avatars.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ avatars.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ avatars.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ avatars.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ avatars.delete,
+ )
diff --git a/src/runwayml/resources/documents.py b/src/runwayml/resources/documents.py
new file mode 100644
index 0000000..8e5ba60
--- /dev/null
+++ b/src/runwayml/resources/documents.py
@@ -0,0 +1,462 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..types import document_list_params, document_create_params
+from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from .._utils import maybe_transform, async_maybe_transform
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..pagination import SyncCursorPage, AsyncCursorPage
+from .._base_client import AsyncPaginator, make_request_options
+from ..types.document_list_response import DocumentListResponse
+from ..types.document_create_response import DocumentCreateResponse
+from ..types.document_retrieve_response import DocumentRetrieveResponse
+
+__all__ = ["DocumentsResource", "AsyncDocumentsResource"]
+
+
+class DocumentsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> DocumentsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return DocumentsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> DocumentsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response
+ """
+ return DocumentsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ content: str,
+ name: str,
+ # 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,
+ ) -> DocumentCreateResponse:
+ """Create a new knowledge document.
+
+ Documents can be attached to avatars to provide
+ additional context during conversations.
+
+ Args:
+ content: The markdown or plain text content of the document.
+
+ name: A descriptive name for the document.
+
+ 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
+ """
+ return self._post(
+ "/v1/documents",
+ body=maybe_transform(
+ {
+ "content": content,
+ "name": name,
+ },
+ document_create_params.DocumentCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DocumentCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> DocumentRetrieveResponse:
+ """
+ Get details of a specific knowledge document.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return self._get(
+ f"/v1/documents/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DocumentRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ limit: int,
+ cursor: 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,
+ ) -> SyncCursorPage[DocumentListResponse]:
+ """
+ List knowledge documents for the authenticated user with cursor-based
+ pagination.
+
+ Args:
+ limit: The maximum number of items to return per page.
+
+ cursor: Cursor from a previous response for fetching the next page of results.
+
+ 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
+ """
+ return self._get_api_list(
+ "/v1/documents",
+ page=SyncCursorPage[DocumentListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "cursor": cursor,
+ },
+ document_list_params.DocumentListParams,
+ ),
+ ),
+ model=DocumentListResponse,
+ )
+
+ def delete(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> None:
+ """Delete a knowledge document.
+
+ This also removes it from all avatars it was
+ attached to.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ f"/v1/documents/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncDocumentsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncDocumentsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncDocumentsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncDocumentsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response
+ """
+ return AsyncDocumentsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ content: str,
+ name: str,
+ # 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,
+ ) -> DocumentCreateResponse:
+ """Create a new knowledge document.
+
+ Documents can be attached to avatars to provide
+ additional context during conversations.
+
+ Args:
+ content: The markdown or plain text content of the document.
+
+ name: A descriptive name for the document.
+
+ 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
+ """
+ return await self._post(
+ "/v1/documents",
+ body=await async_maybe_transform(
+ {
+ "content": content,
+ "name": name,
+ },
+ document_create_params.DocumentCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DocumentCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> DocumentRetrieveResponse:
+ """
+ Get details of a specific knowledge document.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return await self._get(
+ f"/v1/documents/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DocumentRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ limit: int,
+ cursor: 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,
+ ) -> AsyncPaginator[DocumentListResponse, AsyncCursorPage[DocumentListResponse]]:
+ """
+ List knowledge documents for the authenticated user with cursor-based
+ pagination.
+
+ Args:
+ limit: The maximum number of items to return per page.
+
+ cursor: Cursor from a previous response for fetching the next page of results.
+
+ 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
+ """
+ return self._get_api_list(
+ "/v1/documents",
+ page=AsyncCursorPage[DocumentListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "cursor": cursor,
+ },
+ document_list_params.DocumentListParams,
+ ),
+ ),
+ model=DocumentListResponse,
+ )
+
+ async def delete(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> None:
+ """Delete a knowledge document.
+
+ This also removes it from all avatars it was
+ attached to.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ f"/v1/documents/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class DocumentsResourceWithRawResponse:
+ def __init__(self, documents: DocumentsResource) -> None:
+ self._documents = documents
+
+ self.create = to_raw_response_wrapper(
+ documents.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ documents.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ documents.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ documents.delete,
+ )
+
+
+class AsyncDocumentsResourceWithRawResponse:
+ def __init__(self, documents: AsyncDocumentsResource) -> None:
+ self._documents = documents
+
+ self.create = async_to_raw_response_wrapper(
+ documents.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ documents.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ documents.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ documents.delete,
+ )
+
+
+class DocumentsResourceWithStreamingResponse:
+ def __init__(self, documents: DocumentsResource) -> None:
+ self._documents = documents
+
+ self.create = to_streamed_response_wrapper(
+ documents.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ documents.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ documents.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ documents.delete,
+ )
+
+
+class AsyncDocumentsResourceWithStreamingResponse:
+ def __init__(self, documents: AsyncDocumentsResource) -> None:
+ self._documents = documents
+
+ self.create = async_to_streamed_response_wrapper(
+ documents.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ documents.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ documents.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ documents.delete,
+ )
diff --git a/src/runwayml/resources/realtime_sessions.py b/src/runwayml/resources/realtime_sessions.py
new file mode 100644
index 0000000..fc5281a
--- /dev/null
+++ b/src/runwayml/resources/realtime_sessions.py
@@ -0,0 +1,365 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Any, cast
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import realtime_session_create_params
+from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from .._utils import maybe_transform, async_maybe_transform
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from .._base_client import make_request_options
+from ..types.realtime_session_create_response import RealtimeSessionCreateResponse
+from ..types.realtime_session_retrieve_response import RealtimeSessionRetrieveResponse
+
+__all__ = ["RealtimeSessionsResource", "AsyncRealtimeSessionsResource"]
+
+
+class RealtimeSessionsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> RealtimeSessionsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return RealtimeSessionsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> RealtimeSessionsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response
+ """
+ return RealtimeSessionsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ avatar: realtime_session_create_params.Avatar,
+ model: Literal["gwm1_avatars"],
+ max_duration: int | 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,
+ ) -> RealtimeSessionCreateResponse:
+ """
+ Create a new realtime session with the specified model configuration.
+
+ Args:
+ avatar: The avatar configuration for the session.
+
+ model: The realtime session model type.
+
+ max_duration: Maximum session duration in seconds.
+
+ 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
+ """
+ return self._post(
+ "/v1/realtime_sessions",
+ body=maybe_transform(
+ {
+ "avatar": avatar,
+ "model": model,
+ "max_duration": max_duration,
+ },
+ realtime_session_create_params.RealtimeSessionCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RealtimeSessionCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> RealtimeSessionRetrieveResponse:
+ """
+ Get the status of a realtime session.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ RealtimeSessionRetrieveResponse,
+ self._get(
+ f"/v1/realtime_sessions/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, RealtimeSessionRetrieveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def delete(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> None:
+ """
+ Cancel an active realtime session.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ f"/v1/realtime_sessions/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncRealtimeSessionsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncRealtimeSessionsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncRealtimeSessionsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncRealtimeSessionsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response
+ """
+ return AsyncRealtimeSessionsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ avatar: realtime_session_create_params.Avatar,
+ model: Literal["gwm1_avatars"],
+ max_duration: int | 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,
+ ) -> RealtimeSessionCreateResponse:
+ """
+ Create a new realtime session with the specified model configuration.
+
+ Args:
+ avatar: The avatar configuration for the session.
+
+ model: The realtime session model type.
+
+ max_duration: Maximum session duration in seconds.
+
+ 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
+ """
+ return await self._post(
+ "/v1/realtime_sessions",
+ body=await async_maybe_transform(
+ {
+ "avatar": avatar,
+ "model": model,
+ "max_duration": max_duration,
+ },
+ realtime_session_create_params.RealtimeSessionCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RealtimeSessionCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> RealtimeSessionRetrieveResponse:
+ """
+ Get the status of a realtime session.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ RealtimeSessionRetrieveResponse,
+ await self._get(
+ f"/v1/realtime_sessions/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, RealtimeSessionRetrieveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ async def delete(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> None:
+ """
+ Cancel an active realtime session.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ f"/v1/realtime_sessions/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class RealtimeSessionsResourceWithRawResponse:
+ def __init__(self, realtime_sessions: RealtimeSessionsResource) -> None:
+ self._realtime_sessions = realtime_sessions
+
+ self.create = to_raw_response_wrapper(
+ realtime_sessions.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ realtime_sessions.retrieve,
+ )
+ self.delete = to_raw_response_wrapper(
+ realtime_sessions.delete,
+ )
+
+
+class AsyncRealtimeSessionsResourceWithRawResponse:
+ def __init__(self, realtime_sessions: AsyncRealtimeSessionsResource) -> None:
+ self._realtime_sessions = realtime_sessions
+
+ self.create = async_to_raw_response_wrapper(
+ realtime_sessions.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ realtime_sessions.retrieve,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ realtime_sessions.delete,
+ )
+
+
+class RealtimeSessionsResourceWithStreamingResponse:
+ def __init__(self, realtime_sessions: RealtimeSessionsResource) -> None:
+ self._realtime_sessions = realtime_sessions
+
+ self.create = to_streamed_response_wrapper(
+ realtime_sessions.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ realtime_sessions.retrieve,
+ )
+ self.delete = to_streamed_response_wrapper(
+ realtime_sessions.delete,
+ )
+
+
+class AsyncRealtimeSessionsResourceWithStreamingResponse:
+ def __init__(self, realtime_sessions: AsyncRealtimeSessionsResource) -> None:
+ self._realtime_sessions = realtime_sessions
+
+ self.create = async_to_streamed_response_wrapper(
+ realtime_sessions.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ realtime_sessions.retrieve,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ realtime_sessions.delete,
+ )
diff --git a/src/runwayml/resources/voices.py b/src/runwayml/resources/voices.py
new file mode 100644
index 0000000..3636ad9
--- /dev/null
+++ b/src/runwayml/resources/voices.py
@@ -0,0 +1,580 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Any, Optional, cast
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import voice_list_params, voice_create_params, voice_preview_params
+from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from .._utils import maybe_transform, async_maybe_transform
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..pagination import SyncCursorPage, AsyncCursorPage
+from .._base_client import AsyncPaginator, make_request_options
+from ..types.voice_list_response import VoiceListResponse
+from ..types.voice_create_response import VoiceCreateResponse
+from ..types.voice_preview_response import VoicePreviewResponse
+from ..types.voice_retrieve_response import VoiceRetrieveResponse
+
+__all__ = ["VoicesResource", "AsyncVoicesResource"]
+
+
+class VoicesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> VoicesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return VoicesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> VoicesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response
+ """
+ return VoicesResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ from_: voice_create_params.From,
+ name: str,
+ description: Optional[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,
+ ) -> VoiceCreateResponse:
+ """
+ Create a custom voice from a text description.
+
+ Args:
+ from_: The source configuration for creating the voice.
+
+ name: A name for the voice.
+
+ description: An optional description of the voice.
+
+ 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
+ """
+ return self._post(
+ "/v1/voices",
+ body=maybe_transform(
+ {
+ "from_": from_,
+ "name": name,
+ "description": description,
+ },
+ voice_create_params.VoiceCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VoiceCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> VoiceRetrieveResponse:
+ """
+ Get details about a specific custom voice.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ VoiceRetrieveResponse,
+ self._get(
+ f"/v1/voices/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, VoiceRetrieveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def list(
+ self,
+ *,
+ limit: int,
+ cursor: 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,
+ ) -> SyncCursorPage[VoiceListResponse]:
+ """
+ List custom voices for the authenticated organization with cursor-based
+ pagination.
+
+ Args:
+ limit: The maximum number of items to return per page.
+
+ cursor: Cursor from a previous response for fetching the next page of results.
+
+ 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
+ """
+ return self._get_api_list(
+ "/v1/voices",
+ page=SyncCursorPage[VoiceListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "cursor": cursor,
+ },
+ voice_list_params.VoiceListParams,
+ ),
+ ),
+ model=cast(Any, VoiceListResponse), # Union types cannot be passed in as arguments in the type system
+ )
+
+ def delete(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> None:
+ """
+ Delete a custom voice.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ f"/v1/voices/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def preview(
+ self,
+ *,
+ model: Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"],
+ prompt: str,
+ # 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,
+ ) -> VoicePreviewResponse:
+ """Generate a short audio preview of a voice from a text description.
+
+ Use this to
+ audition a voice before creating it.
+
+ Args:
+ model: The voice design model to use.
+
+ prompt: A text description of the desired voice characteristics. Must be at least 20
+ characters.
+
+ 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
+ """
+ return self._post(
+ "/v1/voices/preview",
+ body=maybe_transform(
+ {
+ "model": model,
+ "prompt": prompt,
+ },
+ voice_preview_params.VoicePreviewParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VoicePreviewResponse,
+ )
+
+
+class AsyncVoicesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncVoicesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncVoicesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncVoicesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response
+ """
+ return AsyncVoicesResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ from_: voice_create_params.From,
+ name: str,
+ description: Optional[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,
+ ) -> VoiceCreateResponse:
+ """
+ Create a custom voice from a text description.
+
+ Args:
+ from_: The source configuration for creating the voice.
+
+ name: A name for the voice.
+
+ description: An optional description of the voice.
+
+ 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
+ """
+ return await self._post(
+ "/v1/voices",
+ body=await async_maybe_transform(
+ {
+ "from_": from_,
+ "name": name,
+ "description": description,
+ },
+ voice_create_params.VoiceCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VoiceCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> VoiceRetrieveResponse:
+ """
+ Get details about a specific custom voice.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ VoiceRetrieveResponse,
+ await self._get(
+ f"/v1/voices/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, VoiceRetrieveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def list(
+ self,
+ *,
+ limit: int,
+ cursor: 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,
+ ) -> AsyncPaginator[VoiceListResponse, AsyncCursorPage[VoiceListResponse]]:
+ """
+ List custom voices for the authenticated organization with cursor-based
+ pagination.
+
+ Args:
+ limit: The maximum number of items to return per page.
+
+ cursor: Cursor from a previous response for fetching the next page of results.
+
+ 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
+ """
+ return self._get_api_list(
+ "/v1/voices",
+ page=AsyncCursorPage[VoiceListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "cursor": cursor,
+ },
+ voice_list_params.VoiceListParams,
+ ),
+ ),
+ model=cast(Any, VoiceListResponse), # Union types cannot be passed in as arguments in the type system
+ )
+
+ async def delete(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> None:
+ """
+ Delete a custom voice.
+
+ 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 id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ f"/v1/voices/{id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def preview(
+ self,
+ *,
+ model: Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"],
+ prompt: str,
+ # 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,
+ ) -> VoicePreviewResponse:
+ """Generate a short audio preview of a voice from a text description.
+
+ Use this to
+ audition a voice before creating it.
+
+ Args:
+ model: The voice design model to use.
+
+ prompt: A text description of the desired voice characteristics. Must be at least 20
+ characters.
+
+ 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
+ """
+ return await self._post(
+ "/v1/voices/preview",
+ body=await async_maybe_transform(
+ {
+ "model": model,
+ "prompt": prompt,
+ },
+ voice_preview_params.VoicePreviewParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VoicePreviewResponse,
+ )
+
+
+class VoicesResourceWithRawResponse:
+ def __init__(self, voices: VoicesResource) -> None:
+ self._voices = voices
+
+ self.create = to_raw_response_wrapper(
+ voices.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ voices.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ voices.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ voices.delete,
+ )
+ self.preview = to_raw_response_wrapper(
+ voices.preview,
+ )
+
+
+class AsyncVoicesResourceWithRawResponse:
+ def __init__(self, voices: AsyncVoicesResource) -> None:
+ self._voices = voices
+
+ self.create = async_to_raw_response_wrapper(
+ voices.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ voices.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ voices.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ voices.delete,
+ )
+ self.preview = async_to_raw_response_wrapper(
+ voices.preview,
+ )
+
+
+class VoicesResourceWithStreamingResponse:
+ def __init__(self, voices: VoicesResource) -> None:
+ self._voices = voices
+
+ self.create = to_streamed_response_wrapper(
+ voices.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ voices.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ voices.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ voices.delete,
+ )
+ self.preview = to_streamed_response_wrapper(
+ voices.preview,
+ )
+
+
+class AsyncVoicesResourceWithStreamingResponse:
+ def __init__(self, voices: AsyncVoicesResource) -> None:
+ self._voices = voices
+
+ self.create = async_to_streamed_response_wrapper(
+ voices.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ voices.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ voices.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ voices.delete,
+ )
+ self.preview = async_to_streamed_response_wrapper(
+ voices.preview,
+ )
diff --git a/src/runwayml/types/__init__.py b/src/runwayml/types/__init__.py
index 7dd42d4..1d7a4d9 100644
--- a/src/runwayml/types/__init__.py
+++ b/src/runwayml/types/__init__.py
@@ -2,7 +2,26 @@
from __future__ import annotations
+from .voice_list_params import VoiceListParams as VoiceListParams
+from .avatar_list_params import AvatarListParams as AvatarListParams
+from .voice_create_params import VoiceCreateParams as VoiceCreateParams
+from .voice_list_response import VoiceListResponse as VoiceListResponse
+from .avatar_create_params import AvatarCreateParams as AvatarCreateParams
+from .avatar_list_response import AvatarListResponse as AvatarListResponse
+from .avatar_update_params import AvatarUpdateParams as AvatarUpdateParams
+from .document_list_params import DocumentListParams as DocumentListParams
+from .voice_preview_params import VoicePreviewParams as VoicePreviewParams
+from .voice_create_response import VoiceCreateResponse as VoiceCreateResponse
+from .avatar_create_response import AvatarCreateResponse as AvatarCreateResponse
+from .avatar_update_response import AvatarUpdateResponse as AvatarUpdateResponse
+from .document_create_params import DocumentCreateParams as DocumentCreateParams
+from .document_list_response import DocumentListResponse as DocumentListResponse
from .task_retrieve_response import TaskRetrieveResponse as TaskRetrieveResponse
+from .voice_preview_response import VoicePreviewResponse as VoicePreviewResponse
+from .voice_retrieve_response import VoiceRetrieveResponse as VoiceRetrieveResponse
+from .avatar_retrieve_response import AvatarRetrieveResponse as AvatarRetrieveResponse
+from .document_create_response import DocumentCreateResponse as DocumentCreateResponse
+from .document_retrieve_response import DocumentRetrieveResponse as DocumentRetrieveResponse
from .sound_effect_create_params import SoundEffectCreateParams as SoundEffectCreateParams
from .text_to_image_create_params import TextToImageCreateParams as TextToImageCreateParams
from .text_to_video_create_params import TextToVideoCreateParams as TextToVideoCreateParams
@@ -17,12 +36,15 @@
from .voice_isolation_create_params import VoiceIsolationCreateParams as VoiceIsolationCreateParams
from .image_to_video_create_response import ImageToVideoCreateResponse as ImageToVideoCreateResponse
from .organization_retrieve_response import OrganizationRetrieveResponse as OrganizationRetrieveResponse
+from .realtime_session_create_params import RealtimeSessionCreateParams as RealtimeSessionCreateParams
from .speech_to_speech_create_params import SpeechToSpeechCreateParams as SpeechToSpeechCreateParams
from .text_to_speech_create_response import TextToSpeechCreateResponse as TextToSpeechCreateResponse
from .video_to_video_create_response import VideoToVideoCreateResponse as VideoToVideoCreateResponse
from .voice_isolation_create_response import VoiceIsolationCreateResponse as VoiceIsolationCreateResponse
+from .realtime_session_create_response import RealtimeSessionCreateResponse as RealtimeSessionCreateResponse
from .speech_to_speech_create_response import SpeechToSpeechCreateResponse as SpeechToSpeechCreateResponse
from .organization_retrieve_usage_params import OrganizationRetrieveUsageParams as OrganizationRetrieveUsageParams
+from .realtime_session_retrieve_response import RealtimeSessionRetrieveResponse as RealtimeSessionRetrieveResponse
from .character_performance_create_params import CharacterPerformanceCreateParams as CharacterPerformanceCreateParams
from .organization_retrieve_usage_response import OrganizationRetrieveUsageResponse as OrganizationRetrieveUsageResponse
from .character_performance_create_response import (
diff --git a/src/runwayml/types/avatar_create_params.py b/src/runwayml/types/avatar_create_params.py
new file mode 100644
index 0000000..2574c91
--- /dev/null
+++ b/src/runwayml/types/avatar_create_params.py
@@ -0,0 +1,107 @@
+# 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 Literal, Required, Annotated, TypeAlias, TypedDict
+
+from .._types import SequenceNotStr
+from .._utils import PropertyInfo
+
+__all__ = ["AvatarCreateParams", "Voice", "VoiceRunwayLivePreset", "VoiceCustom"]
+
+
+class AvatarCreateParams(TypedDict, total=False):
+ name: Required[str]
+ """The character name for the avatar."""
+
+ personality: Required[str]
+ """System prompt defining how the avatar should behave in conversations."""
+
+ reference_image: Required[Annotated[str, PropertyInfo(alias="referenceImage")]]
+ """A HTTPS URL."""
+
+ voice: Required[Voice]
+ """The voice configuration for the avatar."""
+
+ document_ids: Annotated[SequenceNotStr[str], PropertyInfo(alias="documentIds")]
+ """Optional list of knowledge document IDs to attach to this avatar.
+
+ Documents provide additional context during conversations.
+ """
+
+ image_processing: Annotated[Literal["optimize", "none"], PropertyInfo(alias="imageProcessing")]
+ """Controls image preprocessing.
+
+ `optimize` improves the image for better avatar results. `none` uses the image
+ as-is; quality not guaranteed.
+ """
+
+ start_script: Annotated[str, PropertyInfo(alias="startScript")]
+ """Optional opening message that the avatar will say when a session starts."""
+
+
+class VoiceRunwayLivePreset(TypedDict, total=False):
+ """A preset voice from the Runway API."""
+
+ preset_id: Required[
+ Annotated[
+ Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ],
+ PropertyInfo(alias="presetId"),
+ ]
+ ]
+ """The ID of a preset voice.
+
+ Available voices: `victoria` (Victoria), `vincent` (Vincent), `clara` (Clara),
+ `drew` (Drew), `skye` (Skye), `max` (Max), `morgan` (Morgan), `felix` (Felix),
+ `mia` (Mia), `marcus` (Marcus), `summer` (Summer), `ruby` (Ruby), `aurora`
+ (Aurora), `jasper` (Jasper), `leo` (Leo), `adrian` (Adrian), `nina` (Nina),
+ `emma` (Emma), `blake` (Blake), `david` (David), `maya` (Maya), `nathan`
+ (Nathan), `sam` (Sam), `georgia` (Georgia), `petra` (Petra), `adam` (Adam),
+ `zach` (Zach), `violet` (Violet), `roman` (Roman), `luna` (Luna).
+ """
+
+ type: Required[Literal["runway-live-preset"]]
+
+
+class VoiceCustom(TypedDict, total=False):
+ """A custom voice created via the Voices API."""
+
+ id: Required[str]
+ """The ID of a custom voice created via the Voices API."""
+
+ type: Required[Literal["custom"]]
+
+
+Voice: TypeAlias = Union[VoiceRunwayLivePreset, VoiceCustom]
diff --git a/src/runwayml/types/avatar_create_response.py b/src/runwayml/types/avatar_create_response.py
new file mode 100644
index 0000000..8b5f990
--- /dev/null
+++ b/src/runwayml/types/avatar_create_response.py
@@ -0,0 +1,368 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = [
+ "AvatarCreateResponse",
+ "Processing",
+ "ProcessingVoice",
+ "ProcessingVoiceRunwayLivePreset",
+ "ProcessingVoiceCustom",
+ "Ready",
+ "ReadyVoice",
+ "ReadyVoiceRunwayLivePreset",
+ "ReadyVoiceCustom",
+ "Failed",
+ "FailedVoice",
+ "FailedVoiceRunwayLivePreset",
+ "FailedVoiceCustom",
+]
+
+
+class ProcessingVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class ProcessingVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+ProcessingVoice: TypeAlias = Annotated[
+ Union[ProcessingVoiceRunwayLivePreset, ProcessingVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Processing(BaseModel):
+ """An avatar that is still being processed."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["PROCESSING"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: ProcessingVoice
+ """The voice configured for this avatar."""
+
+
+class ReadyVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class ReadyVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+ReadyVoice: TypeAlias = Annotated[
+ Union[ReadyVoiceRunwayLivePreset, ReadyVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Ready(BaseModel):
+ """An avatar that is ready for use in sessions."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["READY"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: ReadyVoice
+ """The voice configured for this avatar."""
+
+
+class FailedVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class FailedVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+FailedVoice: TypeAlias = Annotated[
+ Union[FailedVoiceRunwayLivePreset, FailedVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Failed(BaseModel):
+ """An avatar that failed to finish processing."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ failure_reason: str = FieldInfo(alias="failureReason")
+ """A human-readable error message.
+
+ This value is not stable and should not be matched against programmatically.
+ """
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["FAILED"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: FailedVoice
+ """The voice configured for this avatar."""
+
+
+AvatarCreateResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")]
diff --git a/src/runwayml/types/avatar_list_params.py b/src/runwayml/types/avatar_list_params.py
new file mode 100644
index 0000000..051c552
--- /dev/null
+++ b/src/runwayml/types/avatar_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["AvatarListParams"]
+
+
+class AvatarListParams(TypedDict, total=False):
+ limit: Required[int]
+ """The maximum number of items to return per page."""
+
+ cursor: str
+ """Cursor from a previous response for fetching the next page of results."""
diff --git a/src/runwayml/types/avatar_list_response.py b/src/runwayml/types/avatar_list_response.py
new file mode 100644
index 0000000..fd2e650
--- /dev/null
+++ b/src/runwayml/types/avatar_list_response.py
@@ -0,0 +1,368 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = [
+ "AvatarListResponse",
+ "Processing",
+ "ProcessingVoice",
+ "ProcessingVoiceRunwayLivePreset",
+ "ProcessingVoiceCustom",
+ "Ready",
+ "ReadyVoice",
+ "ReadyVoiceRunwayLivePreset",
+ "ReadyVoiceCustom",
+ "Failed",
+ "FailedVoice",
+ "FailedVoiceRunwayLivePreset",
+ "FailedVoiceCustom",
+]
+
+
+class ProcessingVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class ProcessingVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+ProcessingVoice: TypeAlias = Annotated[
+ Union[ProcessingVoiceRunwayLivePreset, ProcessingVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Processing(BaseModel):
+ """An avatar that is still being processed."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["PROCESSING"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: ProcessingVoice
+ """The voice configured for this avatar."""
+
+
+class ReadyVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class ReadyVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+ReadyVoice: TypeAlias = Annotated[
+ Union[ReadyVoiceRunwayLivePreset, ReadyVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Ready(BaseModel):
+ """An avatar that is ready for use in sessions."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["READY"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: ReadyVoice
+ """The voice configured for this avatar."""
+
+
+class FailedVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class FailedVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+FailedVoice: TypeAlias = Annotated[
+ Union[FailedVoiceRunwayLivePreset, FailedVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Failed(BaseModel):
+ """An avatar that failed to finish processing."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ failure_reason: str = FieldInfo(alias="failureReason")
+ """A human-readable error message.
+
+ This value is not stable and should not be matched against programmatically.
+ """
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["FAILED"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: FailedVoice
+ """The voice configured for this avatar."""
+
+
+AvatarListResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")]
diff --git a/src/runwayml/types/avatar_retrieve_response.py b/src/runwayml/types/avatar_retrieve_response.py
new file mode 100644
index 0000000..0f37a12
--- /dev/null
+++ b/src/runwayml/types/avatar_retrieve_response.py
@@ -0,0 +1,368 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = [
+ "AvatarRetrieveResponse",
+ "Processing",
+ "ProcessingVoice",
+ "ProcessingVoiceRunwayLivePreset",
+ "ProcessingVoiceCustom",
+ "Ready",
+ "ReadyVoice",
+ "ReadyVoiceRunwayLivePreset",
+ "ReadyVoiceCustom",
+ "Failed",
+ "FailedVoice",
+ "FailedVoiceRunwayLivePreset",
+ "FailedVoiceCustom",
+]
+
+
+class ProcessingVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class ProcessingVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+ProcessingVoice: TypeAlias = Annotated[
+ Union[ProcessingVoiceRunwayLivePreset, ProcessingVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Processing(BaseModel):
+ """An avatar that is still being processed."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["PROCESSING"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: ProcessingVoice
+ """The voice configured for this avatar."""
+
+
+class ReadyVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class ReadyVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+ReadyVoice: TypeAlias = Annotated[
+ Union[ReadyVoiceRunwayLivePreset, ReadyVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Ready(BaseModel):
+ """An avatar that is ready for use in sessions."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["READY"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: ReadyVoice
+ """The voice configured for this avatar."""
+
+
+class FailedVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class FailedVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+FailedVoice: TypeAlias = Annotated[
+ Union[FailedVoiceRunwayLivePreset, FailedVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Failed(BaseModel):
+ """An avatar that failed to finish processing."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ failure_reason: str = FieldInfo(alias="failureReason")
+ """A human-readable error message.
+
+ This value is not stable and should not be matched against programmatically.
+ """
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["FAILED"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: FailedVoice
+ """The voice configured for this avatar."""
+
+
+AvatarRetrieveResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")]
diff --git a/src/runwayml/types/avatar_update_params.py b/src/runwayml/types/avatar_update_params.py
new file mode 100644
index 0000000..eb3fe85
--- /dev/null
+++ b/src/runwayml/types/avatar_update_params.py
@@ -0,0 +1,111 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict
+
+from .._types import SequenceNotStr
+from .._utils import PropertyInfo
+
+__all__ = ["AvatarUpdateParams", "Voice", "VoiceRunwayLivePreset", "VoiceCustom"]
+
+
+class AvatarUpdateParams(TypedDict, total=False):
+ document_ids: Annotated[SequenceNotStr[str], PropertyInfo(alias="documentIds")]
+ """List of knowledge document IDs to attach to this avatar.
+
+ Replaces all current attachments. Documents provide additional context during
+ conversations.
+ """
+
+ image_processing: Annotated[Literal["optimize", "none"], PropertyInfo(alias="imageProcessing")]
+ """Controls image preprocessing.
+
+ `optimize` improves the image for better avatar results. `none` uses the image
+ as-is; quality not guaranteed.
+ """
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ reference_image: Annotated[str, PropertyInfo(alias="referenceImage")]
+ """A HTTPS URL."""
+
+ start_script: Annotated[Optional[str], PropertyInfo(alias="startScript")]
+ """Optional opening message that the avatar will say when a session starts.
+
+ Set to null to clear.
+ """
+
+ voice: Voice
+ """The voice configuration for the avatar."""
+
+
+class VoiceRunwayLivePreset(TypedDict, total=False):
+ """A preset voice from the Runway API."""
+
+ preset_id: Required[
+ Annotated[
+ Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ],
+ PropertyInfo(alias="presetId"),
+ ]
+ ]
+ """The ID of a preset voice.
+
+ Available voices: `victoria` (Victoria), `vincent` (Vincent), `clara` (Clara),
+ `drew` (Drew), `skye` (Skye), `max` (Max), `morgan` (Morgan), `felix` (Felix),
+ `mia` (Mia), `marcus` (Marcus), `summer` (Summer), `ruby` (Ruby), `aurora`
+ (Aurora), `jasper` (Jasper), `leo` (Leo), `adrian` (Adrian), `nina` (Nina),
+ `emma` (Emma), `blake` (Blake), `david` (David), `maya` (Maya), `nathan`
+ (Nathan), `sam` (Sam), `georgia` (Georgia), `petra` (Petra), `adam` (Adam),
+ `zach` (Zach), `violet` (Violet), `roman` (Roman), `luna` (Luna).
+ """
+
+ type: Required[Literal["runway-live-preset"]]
+
+
+class VoiceCustom(TypedDict, total=False):
+ """A custom voice created via the Voices API."""
+
+ id: Required[str]
+ """The ID of a custom voice created via the Voices API."""
+
+ type: Required[Literal["custom"]]
+
+
+Voice: TypeAlias = Union[VoiceRunwayLivePreset, VoiceCustom]
diff --git a/src/runwayml/types/avatar_update_response.py b/src/runwayml/types/avatar_update_response.py
new file mode 100644
index 0000000..6b9b0c6
--- /dev/null
+++ b/src/runwayml/types/avatar_update_response.py
@@ -0,0 +1,368 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = [
+ "AvatarUpdateResponse",
+ "Processing",
+ "ProcessingVoice",
+ "ProcessingVoiceRunwayLivePreset",
+ "ProcessingVoiceCustom",
+ "Ready",
+ "ReadyVoice",
+ "ReadyVoiceRunwayLivePreset",
+ "ReadyVoiceCustom",
+ "Failed",
+ "FailedVoice",
+ "FailedVoiceRunwayLivePreset",
+ "FailedVoiceCustom",
+]
+
+
+class ProcessingVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class ProcessingVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+ProcessingVoice: TypeAlias = Annotated[
+ Union[ProcessingVoiceRunwayLivePreset, ProcessingVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Processing(BaseModel):
+ """An avatar that is still being processed."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["PROCESSING"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: ProcessingVoice
+ """The voice configured for this avatar."""
+
+
+class ReadyVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class ReadyVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+ReadyVoice: TypeAlias = Annotated[
+ Union[ReadyVoiceRunwayLivePreset, ReadyVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Ready(BaseModel):
+ """An avatar that is ready for use in sessions."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["READY"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: ReadyVoice
+ """The voice configured for this avatar."""
+
+
+class FailedVoiceRunwayLivePreset(BaseModel):
+ """A preset voice from the Runway API."""
+
+ description: str
+ """A brief description of the voice characteristics."""
+
+ name: str
+ """The display name of the voice."""
+
+ preset_id: Literal[
+ "victoria",
+ "vincent",
+ "clara",
+ "drew",
+ "skye",
+ "max",
+ "morgan",
+ "felix",
+ "mia",
+ "marcus",
+ "summer",
+ "ruby",
+ "aurora",
+ "jasper",
+ "leo",
+ "adrian",
+ "nina",
+ "emma",
+ "blake",
+ "david",
+ "maya",
+ "nathan",
+ "sam",
+ "georgia",
+ "petra",
+ "adam",
+ "zach",
+ "violet",
+ "roman",
+ "luna",
+ ] = FieldInfo(alias="presetId")
+ """The preset voice identifier."""
+
+ type: Literal["runway-live-preset"]
+
+
+class FailedVoiceCustom(BaseModel):
+ """A custom voice created via the Voices API."""
+
+ id: str
+ """The unique identifier of the custom voice."""
+
+ deleted: bool
+ """Whether the voice has been deleted.
+
+ When true, name and description are omitted.
+ """
+
+ type: Literal["custom"]
+
+ description: Optional[str] = None
+ """A brief description of the voice characteristics."""
+
+ name: Optional[str] = None
+ """The display name of the voice."""
+
+
+FailedVoice: TypeAlias = Annotated[
+ Union[FailedVoiceRunwayLivePreset, FailedVoiceCustom], PropertyInfo(discriminator="type")
+]
+
+
+class Failed(BaseModel):
+ """An avatar that failed to finish processing."""
+
+ id: str
+ """The unique identifier of the avatar."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the avatar was created."""
+
+ document_ids: List[str] = FieldInfo(alias="documentIds")
+ """IDs of knowledge documents attached to this avatar."""
+
+ failure_reason: str = FieldInfo(alias="failureReason")
+ """A human-readable error message.
+
+ This value is not stable and should not be matched against programmatically.
+ """
+
+ name: str
+ """The character name for the avatar."""
+
+ personality: str
+ """System prompt defining how the avatar should behave in conversations."""
+
+ processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the processed reference image."""
+
+ reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None)
+ """A URI pointing to a low-resolution preview of the avatar's reference image."""
+
+ start_script: Optional[str] = FieldInfo(alias="startScript", default=None)
+ """
+ Opening message that the avatar will say when a session starts, or null if not
+ set.
+ """
+
+ status: Literal["FAILED"]
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the avatar was last updated."""
+
+ voice: FailedVoice
+ """The voice configured for this avatar."""
+
+
+AvatarUpdateResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")]
diff --git a/src/runwayml/types/document_create_params.py b/src/runwayml/types/document_create_params.py
new file mode 100644
index 0000000..1ea559f
--- /dev/null
+++ b/src/runwayml/types/document_create_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["DocumentCreateParams"]
+
+
+class DocumentCreateParams(TypedDict, total=False):
+ content: Required[str]
+ """The markdown or plain text content of the document."""
+
+ name: Required[str]
+ """A descriptive name for the document."""
diff --git a/src/runwayml/types/document_create_response.py b/src/runwayml/types/document_create_response.py
new file mode 100644
index 0000000..9277124
--- /dev/null
+++ b/src/runwayml/types/document_create_response.py
@@ -0,0 +1,45 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["DocumentCreateResponse", "UsedBy"]
+
+
+class UsedBy(BaseModel):
+ id: str
+ """The avatar ID."""
+
+ image_url: Optional[str] = FieldInfo(alias="imageUrl", default=None)
+ """URL to the avatar image, or null if not yet processed."""
+
+ name: str
+ """The avatar name."""
+
+
+class DocumentCreateResponse(BaseModel):
+ id: str
+ """The unique identifier of the document."""
+
+ content: str
+ """The full content of the document."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the document was created."""
+
+ name: str
+ """The name of the document."""
+
+ type: Literal["text", "file"]
+ """The type of document."""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the document was last updated."""
+
+ used_by: List[UsedBy] = FieldInfo(alias="usedBy")
+ """Avatars that use this document. Always empty for newly created documents."""
diff --git a/src/runwayml/types/document_list_params.py b/src/runwayml/types/document_list_params.py
new file mode 100644
index 0000000..97e5b63
--- /dev/null
+++ b/src/runwayml/types/document_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["DocumentListParams"]
+
+
+class DocumentListParams(TypedDict, total=False):
+ limit: Required[int]
+ """The maximum number of items to return per page."""
+
+ cursor: str
+ """Cursor from a previous response for fetching the next page of results."""
diff --git a/src/runwayml/types/document_list_response.py b/src/runwayml/types/document_list_response.py
new file mode 100644
index 0000000..d9d65fe
--- /dev/null
+++ b/src/runwayml/types/document_list_response.py
@@ -0,0 +1,42 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["DocumentListResponse", "UsedBy"]
+
+
+class UsedBy(BaseModel):
+ id: str
+ """The avatar ID."""
+
+ image_url: Optional[str] = FieldInfo(alias="imageUrl", default=None)
+ """URL to the avatar image, or null if not yet processed."""
+
+ name: str
+ """The avatar name."""
+
+
+class DocumentListResponse(BaseModel):
+ id: str
+ """The unique identifier of the document."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the document was created."""
+
+ name: str
+ """The name of the document."""
+
+ type: Literal["text", "file"]
+ """The type of document."""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the document was last updated."""
+
+ used_by: List[UsedBy] = FieldInfo(alias="usedBy")
+ """Avatars that use this document."""
diff --git a/src/runwayml/types/document_retrieve_response.py b/src/runwayml/types/document_retrieve_response.py
new file mode 100644
index 0000000..de805ec
--- /dev/null
+++ b/src/runwayml/types/document_retrieve_response.py
@@ -0,0 +1,45 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["DocumentRetrieveResponse", "UsedBy"]
+
+
+class UsedBy(BaseModel):
+ id: str
+ """The avatar ID."""
+
+ image_url: Optional[str] = FieldInfo(alias="imageUrl", default=None)
+ """URL to the avatar image, or null if not yet processed."""
+
+ name: str
+ """The avatar name."""
+
+
+class DocumentRetrieveResponse(BaseModel):
+ id: str
+ """The unique identifier of the document."""
+
+ content: str
+ """The full content of the document."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the document was created."""
+
+ name: str
+ """The name of the document."""
+
+ type: Literal["text", "file"]
+ """The type of document."""
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+ """When the document was last updated."""
+
+ used_by: List[UsedBy] = FieldInfo(alias="usedBy")
+ """Avatars that use this document."""
diff --git a/src/runwayml/types/organization_retrieve_usage_response.py b/src/runwayml/types/organization_retrieve_usage_response.py
index faefaf2..99326c9 100644
--- a/src/runwayml/types/organization_retrieve_usage_response.py
+++ b/src/runwayml/types/organization_retrieve_usage_response.py
@@ -32,6 +32,8 @@ class ResultUsedCredit(BaseModel):
"eleven_voice_isolation",
"eleven_voice_dubbing",
"eleven_multilingual_sts_v2",
+ "gwm1_avatars",
+ "voice_processing",
]
"""The model that credits were spent on."""
@@ -66,6 +68,8 @@ class OrganizationRetrieveUsageResponse(BaseModel):
"eleven_voice_isolation",
"eleven_voice_dubbing",
"eleven_multilingual_sts_v2",
+ "gwm1_avatars",
+ "voice_processing",
]
]
"""The list of models with usage during the queried time range."""
diff --git a/src/runwayml/types/realtime_session_create_params.py b/src/runwayml/types/realtime_session_create_params.py
new file mode 100644
index 0000000..3cedd9b
--- /dev/null
+++ b/src/runwayml/types/realtime_session_create_params.py
@@ -0,0 +1,57 @@
+# 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 Literal, Required, Annotated, TypeAlias, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["RealtimeSessionCreateParams", "Avatar", "AvatarRunwayPreset", "AvatarCustom"]
+
+
+class RealtimeSessionCreateParams(TypedDict, total=False):
+ avatar: Required[Avatar]
+ """The avatar configuration for the session."""
+
+ model: Required[Literal["gwm1_avatars"]]
+ """The realtime session model type."""
+
+ max_duration: Annotated[int, PropertyInfo(alias="maxDuration")]
+ """Maximum session duration in seconds."""
+
+
+class AvatarRunwayPreset(TypedDict, total=False):
+ """A preset avatar from Runway."""
+
+ preset_id: Required[
+ Annotated[
+ Literal[
+ "game-character",
+ "music-superstar",
+ "game-character-man",
+ "cat-character",
+ "influencer",
+ "tennis-coach",
+ "human-resource",
+ "fashion-designer",
+ "cooking-teacher",
+ ],
+ PropertyInfo(alias="presetId"),
+ ]
+ ]
+ """ID of a preset avatar."""
+
+ type: Required[Literal["runway-preset"]]
+
+
+class AvatarCustom(TypedDict, total=False):
+ """A user-created avatar."""
+
+ avatar_id: Required[Annotated[str, PropertyInfo(alias="avatarId")]]
+ """ID of a user-created avatar."""
+
+ type: Required[Literal["custom"]]
+
+
+Avatar: TypeAlias = Union[AvatarRunwayPreset, AvatarCustom]
diff --git a/src/runwayml/types/realtime_session_create_response.py b/src/runwayml/types/realtime_session_create_response.py
new file mode 100644
index 0000000..434f3ba
--- /dev/null
+++ b/src/runwayml/types/realtime_session_create_response.py
@@ -0,0 +1,10 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["RealtimeSessionCreateResponse"]
+
+
+class RealtimeSessionCreateResponse(BaseModel):
+ id: str
+ """The ID of the created realtime session."""
diff --git a/src/runwayml/types/realtime_session_retrieve_response.py b/src/runwayml/types/realtime_session_retrieve_response.py
new file mode 100644
index 0000000..2956214
--- /dev/null
+++ b/src/runwayml/types/realtime_session_retrieve_response.py
@@ -0,0 +1,116 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = ["RealtimeSessionRetrieveResponse", "NotReady", "Ready", "Running", "Completed", "Failed", "Cancelled"]
+
+
+class NotReady(BaseModel):
+ """A session that is being provisioned."""
+
+ id: str
+ """The realtime session ID."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the session was created."""
+
+ status: Literal["NOT_READY"]
+
+ queued: Optional[bool] = None
+ """When true, the session is waiting in a queue for available capacity.
+
+ When false or absent, the session is actively being provisioned.
+ """
+
+
+class Ready(BaseModel):
+ """A session that is ready to connect."""
+
+ id: str
+ """The realtime session ID."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the session was created."""
+
+ expires_at: datetime = FieldInfo(alias="expiresAt")
+ """When the session credentials expire."""
+
+ session_key: str = FieldInfo(alias="sessionKey")
+ """Session key for authenticating the /consume endpoint. Use as Bearer token."""
+
+ status: Literal["READY"]
+
+
+class Running(BaseModel):
+ """A session with an active WebRTC connection."""
+
+ id: str
+ """The realtime session ID."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the session was created."""
+
+ status: Literal["RUNNING"]
+
+
+class Completed(BaseModel):
+ """A session that ended normally."""
+
+ id: str
+ """The realtime session ID."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the session was created."""
+
+ duration: int
+ """The session duration in seconds."""
+
+ status: Literal["COMPLETED"]
+
+
+class Failed(BaseModel):
+ """A session that encountered an error."""
+
+ id: str
+ """The realtime session ID."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the session was created."""
+
+ failure: str
+ """A human-readable error message.
+
+ This value is not stable and should not be matched against programmatically.
+ """
+
+ failure_code: str = FieldInfo(alias="failureCode")
+ """A stable, machine-readable error code.
+
+ See https://docs.dev.runwayml.com/errors/task-failures/ for more information.
+ """
+
+ status: Literal["FAILED"]
+
+
+class Cancelled(BaseModel):
+ """A session that was explicitly cancelled."""
+
+ id: str
+ """The realtime session ID."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the session was created."""
+
+ status: Literal["CANCELLED"]
+
+
+RealtimeSessionRetrieveResponse: TypeAlias = Annotated[
+ Union[NotReady, Ready, Running, Completed, Failed, Cancelled], PropertyInfo(discriminator="status")
+]
diff --git a/src/runwayml/types/voice_create_params.py b/src/runwayml/types/voice_create_params.py
new file mode 100644
index 0000000..c008f45
--- /dev/null
+++ b/src/runwayml/types/voice_create_params.py
@@ -0,0 +1,36 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["VoiceCreateParams", "From"]
+
+
+class VoiceCreateParams(TypedDict, total=False):
+ from_: Required[Annotated[From, PropertyInfo(alias="from")]]
+ """The source configuration for creating the voice."""
+
+ name: Required[str]
+ """A name for the voice."""
+
+ description: Optional[str]
+ """An optional description of the voice."""
+
+
+class From(TypedDict, total=False):
+ """The source configuration for creating the voice."""
+
+ model: Required[Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"]]
+ """The voice design model to use."""
+
+ prompt: Required[str]
+ """A text description of the desired voice characteristics.
+
+ Must be at least 20 characters.
+ """
+
+ type: Required[Literal["text"]]
diff --git a/src/runwayml/types/voice_create_response.py b/src/runwayml/types/voice_create_response.py
new file mode 100644
index 0000000..1bab78e
--- /dev/null
+++ b/src/runwayml/types/voice_create_response.py
@@ -0,0 +1,10 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["VoiceCreateResponse"]
+
+
+class VoiceCreateResponse(BaseModel):
+ id: str
+ """The ID of the voice that was created."""
diff --git a/src/runwayml/types/voice_list_params.py b/src/runwayml/types/voice_list_params.py
new file mode 100644
index 0000000..306876f
--- /dev/null
+++ b/src/runwayml/types/voice_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["VoiceListParams"]
+
+
+class VoiceListParams(TypedDict, total=False):
+ limit: Required[int]
+ """The maximum number of items to return per page."""
+
+ cursor: str
+ """Cursor from a previous response for fetching the next page of results."""
diff --git a/src/runwayml/types/voice_list_response.py b/src/runwayml/types/voice_list_response.py
new file mode 100644
index 0000000..19d691c
--- /dev/null
+++ b/src/runwayml/types/voice_list_response.py
@@ -0,0 +1,81 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = ["VoiceListResponse", "Processing", "Ready", "Failed"]
+
+
+class Processing(BaseModel):
+ """A voice that is still being processed."""
+
+ id: str
+ """The unique identifier of the voice."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the voice was created."""
+
+ description: Optional[str] = None
+ """A description of the voice, or null if not set."""
+
+ name: str
+ """The name of the voice."""
+
+ status: Literal["PROCESSING"]
+
+
+class Ready(BaseModel):
+ """A voice that is ready for use."""
+
+ id: str
+ """The unique identifier of the voice."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the voice was created."""
+
+ description: Optional[str] = None
+ """A description of the voice, or null if not set."""
+
+ name: str
+ """The name of the voice."""
+
+ preview_url: Optional[str] = FieldInfo(alias="previewUrl", default=None)
+ """
+ A signed URL to an MP3 audio sample of the voice, or null if no sample is
+ available.
+ """
+
+ status: Literal["READY"]
+
+
+class Failed(BaseModel):
+ """A voice that failed to finish processing."""
+
+ id: str
+ """The unique identifier of the voice."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the voice was created."""
+
+ description: Optional[str] = None
+ """A description of the voice, or null if not set."""
+
+ failure_reason: str = FieldInfo(alias="failureReason")
+ """A human-readable error message.
+
+ This value is not stable and should not be matched against programmatically.
+ """
+
+ name: str
+ """The name of the voice."""
+
+ status: Literal["FAILED"]
+
+
+VoiceListResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")]
diff --git a/src/runwayml/types/voice_preview_params.py b/src/runwayml/types/voice_preview_params.py
new file mode 100644
index 0000000..f603c8a
--- /dev/null
+++ b/src/runwayml/types/voice_preview_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["VoicePreviewParams"]
+
+
+class VoicePreviewParams(TypedDict, total=False):
+ model: Required[Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"]]
+ """The voice design model to use."""
+
+ prompt: Required[str]
+ """A text description of the desired voice characteristics.
+
+ Must be at least 20 characters.
+ """
diff --git a/src/runwayml/types/voice_preview_response.py b/src/runwayml/types/voice_preview_response.py
new file mode 100644
index 0000000..716a051
--- /dev/null
+++ b/src/runwayml/types/voice_preview_response.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["VoicePreviewResponse"]
+
+
+class VoicePreviewResponse(BaseModel):
+ duration_secs: float = FieldInfo(alias="durationSecs")
+ """Duration of the audio preview in seconds."""
+
+ url: str
+ """A presigned URL to the audio preview. The URL expires after 24 hours."""
diff --git a/src/runwayml/types/voice_retrieve_response.py b/src/runwayml/types/voice_retrieve_response.py
new file mode 100644
index 0000000..5aa18e6
--- /dev/null
+++ b/src/runwayml/types/voice_retrieve_response.py
@@ -0,0 +1,81 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from .._utils import PropertyInfo
+from .._models import BaseModel
+
+__all__ = ["VoiceRetrieveResponse", "Processing", "Ready", "Failed"]
+
+
+class Processing(BaseModel):
+ """A voice that is still being processed."""
+
+ id: str
+ """The unique identifier of the voice."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the voice was created."""
+
+ description: Optional[str] = None
+ """A description of the voice, or null if not set."""
+
+ name: str
+ """The name of the voice."""
+
+ status: Literal["PROCESSING"]
+
+
+class Ready(BaseModel):
+ """A voice that is ready for use."""
+
+ id: str
+ """The unique identifier of the voice."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the voice was created."""
+
+ description: Optional[str] = None
+ """A description of the voice, or null if not set."""
+
+ name: str
+ """The name of the voice."""
+
+ preview_url: Optional[str] = FieldInfo(alias="previewUrl", default=None)
+ """
+ A signed URL to an MP3 audio sample of the voice, or null if no sample is
+ available.
+ """
+
+ status: Literal["READY"]
+
+
+class Failed(BaseModel):
+ """A voice that failed to finish processing."""
+
+ id: str
+ """The unique identifier of the voice."""
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+ """When the voice was created."""
+
+ description: Optional[str] = None
+ """A description of the voice, or null if not set."""
+
+ failure_reason: str = FieldInfo(alias="failureReason")
+ """A human-readable error message.
+
+ This value is not stable and should not be matched against programmatically.
+ """
+
+ name: str
+ """The name of the voice."""
+
+ status: Literal["FAILED"]
+
+
+VoiceRetrieveResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")]
diff --git a/tests/api_resources/test_avatars.py b/tests/api_resources/test_avatars.py
new file mode 100644
index 0000000..3ba4a33
--- /dev/null
+++ b/tests/api_resources/test_avatars.py
@@ -0,0 +1,500 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from runwayml import RunwayML, AsyncRunwayML
+from tests.utils import assert_matches_type
+from runwayml.types import (
+ AvatarListResponse,
+ AvatarCreateResponse,
+ AvatarUpdateResponse,
+ AvatarRetrieveResponse,
+)
+from runwayml.pagination import SyncCursorPage, AsyncCursorPage
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAvatars:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: RunwayML) -> None:
+ avatar = client.avatars.create(
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ )
+ assert_matches_type(AvatarCreateResponse, avatar, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: RunwayML) -> None:
+ avatar = client.avatars.create(
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ document_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ image_processing="optimize",
+ start_script="Hello! How can I help you today?",
+ )
+ assert_matches_type(AvatarCreateResponse, avatar, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: RunwayML) -> None:
+ response = client.avatars.with_raw_response.create(
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = response.parse()
+ assert_matches_type(AvatarCreateResponse, avatar, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: RunwayML) -> None:
+ with client.avatars.with_streaming_response.create(
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = response.parse()
+ assert_matches_type(AvatarCreateResponse, avatar, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retrieve(self, client: RunwayML) -> None:
+ avatar = client.avatars.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: RunwayML) -> None:
+ response = client.avatars.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = response.parse()
+ assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: RunwayML) -> None:
+ with client.avatars.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = response.parse()
+ assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.avatars.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_update(self, client: RunwayML) -> None:
+ avatar = client.avatars.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(AvatarUpdateResponse, avatar, path=["response"])
+
+ @parametrize
+ def test_method_update_with_all_params(self, client: RunwayML) -> None:
+ avatar = client.avatars.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ document_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ image_processing="optimize",
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ start_script="Hello! How can I help you today?",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ )
+ assert_matches_type(AvatarUpdateResponse, avatar, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: RunwayML) -> None:
+ response = client.avatars.with_raw_response.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = response.parse()
+ assert_matches_type(AvatarUpdateResponse, avatar, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: RunwayML) -> None:
+ with client.avatars.with_streaming_response.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = response.parse()
+ assert_matches_type(AvatarUpdateResponse, avatar, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.avatars.with_raw_response.update(
+ id="",
+ )
+
+ @parametrize
+ def test_method_list(self, client: RunwayML) -> None:
+ avatar = client.avatars.list(
+ limit=1,
+ )
+ assert_matches_type(SyncCursorPage[AvatarListResponse], avatar, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: RunwayML) -> None:
+ avatar = client.avatars.list(
+ limit=1,
+ cursor="x",
+ )
+ assert_matches_type(SyncCursorPage[AvatarListResponse], avatar, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: RunwayML) -> None:
+ response = client.avatars.with_raw_response.list(
+ limit=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = response.parse()
+ assert_matches_type(SyncCursorPage[AvatarListResponse], avatar, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: RunwayML) -> None:
+ with client.avatars.with_streaming_response.list(
+ limit=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = response.parse()
+ assert_matches_type(SyncCursorPage[AvatarListResponse], avatar, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_delete(self, client: RunwayML) -> None:
+ avatar = client.avatars.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert avatar is None
+
+ @parametrize
+ def test_raw_response_delete(self, client: RunwayML) -> None:
+ response = client.avatars.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = response.parse()
+ assert avatar is None
+
+ @parametrize
+ def test_streaming_response_delete(self, client: RunwayML) -> None:
+ with client.avatars.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = response.parse()
+ assert avatar is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.avatars.with_raw_response.delete(
+ "",
+ )
+
+
+class TestAsyncAvatars:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncRunwayML) -> None:
+ avatar = await async_client.avatars.create(
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ )
+ assert_matches_type(AvatarCreateResponse, avatar, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) -> None:
+ avatar = await async_client.avatars.create(
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ document_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ image_processing="optimize",
+ start_script="Hello! How can I help you today?",
+ )
+ assert_matches_type(AvatarCreateResponse, avatar, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.avatars.with_raw_response.create(
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = await response.parse()
+ assert_matches_type(AvatarCreateResponse, avatar, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.avatars.with_streaming_response.create(
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = await response.parse()
+ assert_matches_type(AvatarCreateResponse, avatar, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncRunwayML) -> None:
+ avatar = await async_client.avatars.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.avatars.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = await response.parse()
+ assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.avatars.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = await response.parse()
+ assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.avatars.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncRunwayML) -> None:
+ avatar = await async_client.avatars.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(AvatarUpdateResponse, avatar, path=["response"])
+
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncRunwayML) -> None:
+ avatar = await async_client.avatars.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ document_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
+ image_processing="optimize",
+ name="x",
+ personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.",
+ reference_image="https://example.com/reference.jpg",
+ start_script="Hello! How can I help you today?",
+ voice={
+ "preset_id": "adrian",
+ "type": "runway-live-preset",
+ },
+ )
+ assert_matches_type(AvatarUpdateResponse, avatar, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.avatars.with_raw_response.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = await response.parse()
+ assert_matches_type(AvatarUpdateResponse, avatar, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.avatars.with_streaming_response.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = await response.parse()
+ assert_matches_type(AvatarUpdateResponse, avatar, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.avatars.with_raw_response.update(
+ id="",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncRunwayML) -> None:
+ avatar = await async_client.avatars.list(
+ limit=1,
+ )
+ assert_matches_type(AsyncCursorPage[AvatarListResponse], avatar, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncRunwayML) -> None:
+ avatar = await async_client.avatars.list(
+ limit=1,
+ cursor="x",
+ )
+ assert_matches_type(AsyncCursorPage[AvatarListResponse], avatar, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.avatars.with_raw_response.list(
+ limit=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = await response.parse()
+ assert_matches_type(AsyncCursorPage[AvatarListResponse], avatar, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.avatars.with_streaming_response.list(
+ limit=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = await response.parse()
+ assert_matches_type(AsyncCursorPage[AvatarListResponse], avatar, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncRunwayML) -> None:
+ avatar = await async_client.avatars.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert avatar is None
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.avatars.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar = await response.parse()
+ assert avatar is None
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.avatars.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar = await response.parse()
+ assert avatar is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.avatars.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/test_documents.py b/tests/api_resources/test_documents.py
new file mode 100644
index 0000000..fb21e0e
--- /dev/null
+++ b/tests/api_resources/test_documents.py
@@ -0,0 +1,327 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from runwayml import RunwayML, AsyncRunwayML
+from tests.utils import assert_matches_type
+from runwayml.types import (
+ DocumentListResponse,
+ DocumentCreateResponse,
+ DocumentRetrieveResponse,
+)
+from runwayml.pagination import SyncCursorPage, AsyncCursorPage
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestDocuments:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: RunwayML) -> None:
+ document = client.documents.create(
+ content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...",
+ name="Product FAQ",
+ )
+ assert_matches_type(DocumentCreateResponse, document, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: RunwayML) -> None:
+ response = client.documents.with_raw_response.create(
+ content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...",
+ name="Product FAQ",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert_matches_type(DocumentCreateResponse, document, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: RunwayML) -> None:
+ with client.documents.with_streaming_response.create(
+ content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...",
+ name="Product FAQ",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = response.parse()
+ assert_matches_type(DocumentCreateResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retrieve(self, client: RunwayML) -> None:
+ document = client.documents.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(DocumentRetrieveResponse, document, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: RunwayML) -> None:
+ response = client.documents.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert_matches_type(DocumentRetrieveResponse, document, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: RunwayML) -> None:
+ with client.documents.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = response.parse()
+ assert_matches_type(DocumentRetrieveResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.documents.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_list(self, client: RunwayML) -> None:
+ document = client.documents.list(
+ limit=1,
+ )
+ assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: RunwayML) -> None:
+ document = client.documents.list(
+ limit=1,
+ cursor="x",
+ )
+ assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: RunwayML) -> None:
+ response = client.documents.with_raw_response.list(
+ limit=1,
+ )
+
+ 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"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: RunwayML) -> None:
+ with client.documents.with_streaming_response.list(
+ limit=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = response.parse()
+ assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_delete(self, client: RunwayML) -> None:
+ document = client.documents.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert document is None
+
+ @parametrize
+ def test_raw_response_delete(self, client: RunwayML) -> None:
+ response = client.documents.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert document is None
+
+ @parametrize
+ def test_streaming_response_delete(self, client: RunwayML) -> None:
+ with client.documents.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = response.parse()
+ assert document is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.documents.with_raw_response.delete(
+ "",
+ )
+
+
+class TestAsyncDocuments:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncRunwayML) -> None:
+ document = await async_client.documents.create(
+ content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...",
+ name="Product FAQ",
+ )
+ assert_matches_type(DocumentCreateResponse, document, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.documents.with_raw_response.create(
+ content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...",
+ name="Product FAQ",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = await response.parse()
+ assert_matches_type(DocumentCreateResponse, document, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.documents.with_streaming_response.create(
+ content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...",
+ name="Product FAQ",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = await response.parse()
+ assert_matches_type(DocumentCreateResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncRunwayML) -> None:
+ document = await async_client.documents.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(DocumentRetrieveResponse, document, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.documents.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = await response.parse()
+ assert_matches_type(DocumentRetrieveResponse, document, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.documents.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = await response.parse()
+ assert_matches_type(DocumentRetrieveResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.documents.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncRunwayML) -> None:
+ document = await async_client.documents.list(
+ limit=1,
+ )
+ assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncRunwayML) -> None:
+ document = await async_client.documents.list(
+ limit=1,
+ cursor="x",
+ )
+ assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.documents.with_raw_response.list(
+ limit=1,
+ )
+
+ 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"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.documents.with_streaming_response.list(
+ limit=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = await response.parse()
+ assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncRunwayML) -> None:
+ document = await async_client.documents.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert document is None
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.documents.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = await response.parse()
+ assert document is None
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.documents.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = await response.parse()
+ assert document is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.documents.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/test_realtime_sessions.py b/tests/api_resources/test_realtime_sessions.py
new file mode 100644
index 0000000..2392ca8
--- /dev/null
+++ b/tests/api_resources/test_realtime_sessions.py
@@ -0,0 +1,289 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from runwayml import RunwayML, AsyncRunwayML
+from tests.utils import assert_matches_type
+from runwayml.types import (
+ RealtimeSessionCreateResponse,
+ RealtimeSessionRetrieveResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestRealtimeSessions:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: RunwayML) -> None:
+ realtime_session = client.realtime_sessions.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ )
+ assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: RunwayML) -> None:
+ realtime_session = client.realtime_sessions.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ max_duration=10,
+ )
+ assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: RunwayML) -> None:
+ response = client.realtime_sessions.with_raw_response.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ realtime_session = response.parse()
+ assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: RunwayML) -> None:
+ with client.realtime_sessions.with_streaming_response.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ realtime_session = response.parse()
+ assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retrieve(self, client: RunwayML) -> None:
+ realtime_session = client.realtime_sessions.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: RunwayML) -> None:
+ response = client.realtime_sessions.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ realtime_session = response.parse()
+ assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: RunwayML) -> None:
+ with client.realtime_sessions.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ realtime_session = response.parse()
+ assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.realtime_sessions.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: RunwayML) -> None:
+ realtime_session = client.realtime_sessions.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert realtime_session is None
+
+ @parametrize
+ def test_raw_response_delete(self, client: RunwayML) -> None:
+ response = client.realtime_sessions.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ realtime_session = response.parse()
+ assert realtime_session is None
+
+ @parametrize
+ def test_streaming_response_delete(self, client: RunwayML) -> None:
+ with client.realtime_sessions.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ realtime_session = response.parse()
+ assert realtime_session is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.realtime_sessions.with_raw_response.delete(
+ "",
+ )
+
+
+class TestAsyncRealtimeSessions:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncRunwayML) -> None:
+ realtime_session = await async_client.realtime_sessions.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ )
+ assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) -> None:
+ realtime_session = await async_client.realtime_sessions.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ max_duration=10,
+ )
+ assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.realtime_sessions.with_raw_response.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ realtime_session = await response.parse()
+ assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.realtime_sessions.with_streaming_response.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ realtime_session = await response.parse()
+ assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncRunwayML) -> None:
+ realtime_session = await async_client.realtime_sessions.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.realtime_sessions.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ realtime_session = await response.parse()
+ assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.realtime_sessions.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ realtime_session = await response.parse()
+ assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.realtime_sessions.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncRunwayML) -> None:
+ realtime_session = await async_client.realtime_sessions.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert realtime_session is None
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.realtime_sessions.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ realtime_session = await response.parse()
+ assert realtime_session is None
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.realtime_sessions.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ realtime_session = await response.parse()
+ assert realtime_session is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.realtime_sessions.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/test_voices.py b/tests/api_resources/test_voices.py
new file mode 100644
index 0000000..548a5aa
--- /dev/null
+++ b/tests/api_resources/test_voices.py
@@ -0,0 +1,446 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from runwayml import RunwayML, AsyncRunwayML
+from tests.utils import assert_matches_type
+from runwayml.types import (
+ VoiceListResponse,
+ VoiceCreateResponse,
+ VoicePreviewResponse,
+ VoiceRetrieveResponse,
+)
+from runwayml.pagination import SyncCursorPage, AsyncCursorPage
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestVoices:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: RunwayML) -> None:
+ voice = client.voices.create(
+ from_={
+ "model": "eleven_multilingual_ttv_v2",
+ "prompt": "xxxxxxxxxxxxxxxxxxxx",
+ "type": "text",
+ },
+ name="x",
+ )
+ assert_matches_type(VoiceCreateResponse, voice, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: RunwayML) -> None:
+ voice = client.voices.create(
+ from_={
+ "model": "eleven_multilingual_ttv_v2",
+ "prompt": "xxxxxxxxxxxxxxxxxxxx",
+ "type": "text",
+ },
+ name="x",
+ description="x",
+ )
+ assert_matches_type(VoiceCreateResponse, voice, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: RunwayML) -> None:
+ response = client.voices.with_raw_response.create(
+ from_={
+ "model": "eleven_multilingual_ttv_v2",
+ "prompt": "xxxxxxxxxxxxxxxxxxxx",
+ "type": "text",
+ },
+ name="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = response.parse()
+ assert_matches_type(VoiceCreateResponse, voice, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: RunwayML) -> None:
+ with client.voices.with_streaming_response.create(
+ from_={
+ "model": "eleven_multilingual_ttv_v2",
+ "prompt": "xxxxxxxxxxxxxxxxxxxx",
+ "type": "text",
+ },
+ name="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = response.parse()
+ assert_matches_type(VoiceCreateResponse, voice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retrieve(self, client: RunwayML) -> None:
+ voice = client.voices.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(VoiceRetrieveResponse, voice, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: RunwayML) -> None:
+ response = client.voices.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = response.parse()
+ assert_matches_type(VoiceRetrieveResponse, voice, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: RunwayML) -> None:
+ with client.voices.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = response.parse()
+ assert_matches_type(VoiceRetrieveResponse, voice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.voices.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_list(self, client: RunwayML) -> None:
+ voice = client.voices.list(
+ limit=1,
+ )
+ assert_matches_type(SyncCursorPage[VoiceListResponse], voice, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: RunwayML) -> None:
+ voice = client.voices.list(
+ limit=1,
+ cursor="x",
+ )
+ assert_matches_type(SyncCursorPage[VoiceListResponse], voice, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: RunwayML) -> None:
+ response = client.voices.with_raw_response.list(
+ limit=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = response.parse()
+ assert_matches_type(SyncCursorPage[VoiceListResponse], voice, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: RunwayML) -> None:
+ with client.voices.with_streaming_response.list(
+ limit=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = response.parse()
+ assert_matches_type(SyncCursorPage[VoiceListResponse], voice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_delete(self, client: RunwayML) -> None:
+ voice = client.voices.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert voice is None
+
+ @parametrize
+ def test_raw_response_delete(self, client: RunwayML) -> None:
+ response = client.voices.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = response.parse()
+ assert voice is None
+
+ @parametrize
+ def test_streaming_response_delete(self, client: RunwayML) -> None:
+ with client.voices.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = response.parse()
+ assert voice is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: RunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.voices.with_raw_response.delete(
+ "",
+ )
+
+ @parametrize
+ def test_method_preview(self, client: RunwayML) -> None:
+ voice = client.voices.preview(
+ model="eleven_multilingual_ttv_v2",
+ prompt="xxxxxxxxxxxxxxxxxxxx",
+ )
+ assert_matches_type(VoicePreviewResponse, voice, path=["response"])
+
+ @parametrize
+ def test_raw_response_preview(self, client: RunwayML) -> None:
+ response = client.voices.with_raw_response.preview(
+ model="eleven_multilingual_ttv_v2",
+ prompt="xxxxxxxxxxxxxxxxxxxx",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = response.parse()
+ assert_matches_type(VoicePreviewResponse, voice, path=["response"])
+
+ @parametrize
+ def test_streaming_response_preview(self, client: RunwayML) -> None:
+ with client.voices.with_streaming_response.preview(
+ model="eleven_multilingual_ttv_v2",
+ prompt="xxxxxxxxxxxxxxxxxxxx",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = response.parse()
+ assert_matches_type(VoicePreviewResponse, voice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncVoices:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncRunwayML) -> None:
+ voice = await async_client.voices.create(
+ from_={
+ "model": "eleven_multilingual_ttv_v2",
+ "prompt": "xxxxxxxxxxxxxxxxxxxx",
+ "type": "text",
+ },
+ name="x",
+ )
+ assert_matches_type(VoiceCreateResponse, voice, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) -> None:
+ voice = await async_client.voices.create(
+ from_={
+ "model": "eleven_multilingual_ttv_v2",
+ "prompt": "xxxxxxxxxxxxxxxxxxxx",
+ "type": "text",
+ },
+ name="x",
+ description="x",
+ )
+ assert_matches_type(VoiceCreateResponse, voice, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.voices.with_raw_response.create(
+ from_={
+ "model": "eleven_multilingual_ttv_v2",
+ "prompt": "xxxxxxxxxxxxxxxxxxxx",
+ "type": "text",
+ },
+ name="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = await response.parse()
+ assert_matches_type(VoiceCreateResponse, voice, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.voices.with_streaming_response.create(
+ from_={
+ "model": "eleven_multilingual_ttv_v2",
+ "prompt": "xxxxxxxxxxxxxxxxxxxx",
+ "type": "text",
+ },
+ name="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = await response.parse()
+ assert_matches_type(VoiceCreateResponse, voice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncRunwayML) -> None:
+ voice = await async_client.voices.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(VoiceRetrieveResponse, voice, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.voices.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = await response.parse()
+ assert_matches_type(VoiceRetrieveResponse, voice, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.voices.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = await response.parse()
+ assert_matches_type(VoiceRetrieveResponse, voice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.voices.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncRunwayML) -> None:
+ voice = await async_client.voices.list(
+ limit=1,
+ )
+ assert_matches_type(AsyncCursorPage[VoiceListResponse], voice, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncRunwayML) -> None:
+ voice = await async_client.voices.list(
+ limit=1,
+ cursor="x",
+ )
+ assert_matches_type(AsyncCursorPage[VoiceListResponse], voice, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.voices.with_raw_response.list(
+ limit=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = await response.parse()
+ assert_matches_type(AsyncCursorPage[VoiceListResponse], voice, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.voices.with_streaming_response.list(
+ limit=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = await response.parse()
+ assert_matches_type(AsyncCursorPage[VoiceListResponse], voice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncRunwayML) -> None:
+ voice = await async_client.voices.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert voice is None
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.voices.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = await response.parse()
+ assert voice is None
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.voices.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = await response.parse()
+ assert voice is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.voices.with_raw_response.delete(
+ "",
+ )
+
+ @parametrize
+ async def test_method_preview(self, async_client: AsyncRunwayML) -> None:
+ voice = await async_client.voices.preview(
+ model="eleven_multilingual_ttv_v2",
+ prompt="xxxxxxxxxxxxxxxxxxxx",
+ )
+ assert_matches_type(VoicePreviewResponse, voice, path=["response"])
+
+ @parametrize
+ async def test_raw_response_preview(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.voices.with_raw_response.preview(
+ model="eleven_multilingual_ttv_v2",
+ prompt="xxxxxxxxxxxxxxxxxxxx",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ voice = await response.parse()
+ assert_matches_type(VoicePreviewResponse, voice, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_preview(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.voices.with_streaming_response.preview(
+ model="eleven_multilingual_ttv_v2",
+ prompt="xxxxxxxxxxxxxxxxxxxx",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ voice = await response.parse()
+ assert_matches_type(VoicePreviewResponse, voice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True