From 839c38bc95d9147b140481907621942c5c503ead Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 7 Apr 2026 16:10:39 +0000
Subject: [PATCH 1/4] fix(client): preserve hardcoded query params when merging
with user params
---
src/runwayml/_base_client.py | 4 +++
tests/test_client.py | 48 ++++++++++++++++++++++++++++++++++++
2 files changed, 52 insertions(+)
diff --git a/src/runwayml/_base_client.py b/src/runwayml/_base_client.py
index 5845965..4a464b2 100644
--- a/src/runwayml/_base_client.py
+++ b/src/runwayml/_base_client.py
@@ -540,6 +540,10 @@ def _build_request(
files = cast(HttpxRequestFiles, ForceMultipartDict())
prepared_url = self._prepare_url(options.url)
+ # preserve hard-coded query params from the url
+ if params and prepared_url.query:
+ params = {**dict(prepared_url.params.items()), **params}
+ prepared_url = prepared_url.copy_with(raw_path=prepared_url.raw_path.split(b"?", 1)[0])
if "_" in prepared_url.host:
# work around https://github.com/encode/httpx/discussions/2880
kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")}
diff --git a/tests/test_client.py b/tests/test_client.py
index cff614b..f755671 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -429,6 +429,30 @@ def test_default_query_option(self) -> None:
client.close()
+ def test_hardcoded_query_params_in_url(self, client: RunwayML) -> None:
+ request = client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true"))
+ url = httpx.URL(request.url)
+ assert dict(url.params) == {"beta": "true"}
+
+ request = client._build_request(
+ FinalRequestOptions(
+ method="get",
+ url="/foo?beta=true",
+ params={"limit": "10", "page": "abc"},
+ )
+ )
+ url = httpx.URL(request.url)
+ assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"}
+
+ request = client._build_request(
+ FinalRequestOptions(
+ method="get",
+ url="/files/a%2Fb?beta=true",
+ params={"limit": "10"},
+ )
+ )
+ assert request.url.raw_path == b"/files/a%2Fb?beta=true&limit=10"
+
def test_request_extra_json(self, client: RunwayML) -> None:
request = client._build_request(
FinalRequestOptions(
@@ -1340,6 +1364,30 @@ async def test_default_query_option(self) -> None:
await client.close()
+ async def test_hardcoded_query_params_in_url(self, async_client: AsyncRunwayML) -> None:
+ request = async_client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true"))
+ url = httpx.URL(request.url)
+ assert dict(url.params) == {"beta": "true"}
+
+ request = async_client._build_request(
+ FinalRequestOptions(
+ method="get",
+ url="/foo?beta=true",
+ params={"limit": "10", "page": "abc"},
+ )
+ )
+ url = httpx.URL(request.url)
+ assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"}
+
+ request = async_client._build_request(
+ FinalRequestOptions(
+ method="get",
+ url="/files/a%2Fb?beta=true",
+ params={"limit": "10"},
+ )
+ )
+ assert request.url.raw_path == b"/files/a%2Fb?beta=true&limit=10"
+
def test_request_extra_json(self, client: RunwayML) -> None:
request = client._build_request(
FinalRequestOptions(
From 75b6deda8c5733115af29c9374ae10f3d4f4716a Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 10 Apr 2026 09:16:11 +0000
Subject: [PATCH 2/4] feat(api): add avatar_videos resource
---
.stats.yml | 8 +-
api.md | 12 +
src/runwayml/_client.py | 38 ++++
src/runwayml/resources/__init__.py | 42 ++++
src/runwayml/resources/avatar_videos.py | 205 ++++++++++++++++++
src/runwayml/resources/voices.py | 16 +-
src/runwayml/types/__init__.py | 2 +
.../types/avatar_video_create_params.py | 153 +++++++++++++
.../types/avatar_video_create_response.py | 13 ++
src/runwayml/types/voice_create_params.py | 26 ++-
src/runwayml/types/voice_preview_params.py | 8 +-
tests/api_resources/test_avatar_videos.py | 164 ++++++++++++++
tests/api_resources/test_voices.py | 28 +--
13 files changed, 683 insertions(+), 32 deletions(-)
create mode 100644 src/runwayml/resources/avatar_videos.py
create mode 100644 src/runwayml/types/avatar_video_create_params.py
create mode 100644 src/runwayml/types/avatar_video_create_response.py
create mode 100644 tests/api_resources/test_avatar_videos.py
diff --git a/.stats.yml b/.stats.yml
index e1f2c3e..4a5de71 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 36
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml%2Frunwayml-8efb262fec205b8ab10f02929369aa1eb1ae72fba3cc8037552f439ab63c1f2d.yml
-openapi_spec_hash: 265ec44f88060288ab3dc2142eb29585
-config_hash: 8e05a8613b4c0e602d485566da4e5264
+configured_endpoints: 37
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml%2Frunwayml-ee023fb84f0e74914e23b019b4c0951108b7ff83b983563c91ae07986524b674.yml
+openapi_spec_hash: 2472895eb74737ecef2cbee707e50cac
+config_hash: 3063a17ad98d447287f6f7eab9d6d1d6
diff --git a/api.md b/api.md
index 0697df7..14ba311 100644
--- a/api.md
+++ b/api.md
@@ -165,6 +165,18 @@ Methods:
- client.avatars.list(\*\*params) -> SyncCursorPage[AvatarListResponse]
- client.avatars.delete(id) -> None
+# AvatarVideos
+
+Types:
+
+```python
+from runwayml.types import AvatarVideoCreateResponse
+```
+
+Methods:
+
+- client.avatar_videos.create(\*\*params) -> AvatarVideoCreateResponse
+
# Documents
Types:
diff --git a/src/runwayml/_client.py b/src/runwayml/_client.py
index 898ef6e..3bc29b0 100644
--- a/src/runwayml/_client.py
+++ b/src/runwayml/_client.py
@@ -40,6 +40,7 @@
workflows,
organization,
sound_effect,
+ avatar_videos,
text_to_image,
text_to_video,
voice_dubbing,
@@ -60,6 +61,7 @@
from .resources.workflows import WorkflowsResource, AsyncWorkflowsResource
from .resources.organization import OrganizationResource, AsyncOrganizationResource
from .resources.sound_effect import SoundEffectResource, AsyncSoundEffectResource
+ from .resources.avatar_videos import AvatarVideosResource, AsyncAvatarVideosResource
from .resources.text_to_image import TextToImageResource, AsyncTextToImageResource
from .resources.text_to_video import TextToVideoResource, AsyncTextToVideoResource
from .resources.voice_dubbing import VoiceDubbingResource, AsyncVoiceDubbingResource
@@ -240,6 +242,12 @@ def avatars(self) -> AvatarsResource:
return AvatarsResource(self)
+ @cached_property
+ def avatar_videos(self) -> AvatarVideosResource:
+ from .resources.avatar_videos import AvatarVideosResource
+
+ return AvatarVideosResource(self)
+
@cached_property
def documents(self) -> DocumentsResource:
from .resources.documents import DocumentsResource
@@ -542,6 +550,12 @@ def avatars(self) -> AsyncAvatarsResource:
return AsyncAvatarsResource(self)
+ @cached_property
+ def avatar_videos(self) -> AsyncAvatarVideosResource:
+ from .resources.avatar_videos import AsyncAvatarVideosResource
+
+ return AsyncAvatarVideosResource(self)
+
@cached_property
def documents(self) -> AsyncDocumentsResource:
from .resources.documents import AsyncDocumentsResource
@@ -789,6 +803,12 @@ def avatars(self) -> avatars.AvatarsResourceWithRawResponse:
return AvatarsResourceWithRawResponse(self._client.avatars)
+ @cached_property
+ def avatar_videos(self) -> avatar_videos.AvatarVideosResourceWithRawResponse:
+ from .resources.avatar_videos import AvatarVideosResourceWithRawResponse
+
+ return AvatarVideosResourceWithRawResponse(self._client.avatar_videos)
+
@cached_property
def documents(self) -> documents.DocumentsResourceWithRawResponse:
from .resources.documents import DocumentsResourceWithRawResponse
@@ -921,6 +941,12 @@ def avatars(self) -> avatars.AsyncAvatarsResourceWithRawResponse:
return AsyncAvatarsResourceWithRawResponse(self._client.avatars)
+ @cached_property
+ def avatar_videos(self) -> avatar_videos.AsyncAvatarVideosResourceWithRawResponse:
+ from .resources.avatar_videos import AsyncAvatarVideosResourceWithRawResponse
+
+ return AsyncAvatarVideosResourceWithRawResponse(self._client.avatar_videos)
+
@cached_property
def documents(self) -> documents.AsyncDocumentsResourceWithRawResponse:
from .resources.documents import AsyncDocumentsResourceWithRawResponse
@@ -1053,6 +1079,12 @@ def avatars(self) -> avatars.AvatarsResourceWithStreamingResponse:
return AvatarsResourceWithStreamingResponse(self._client.avatars)
+ @cached_property
+ def avatar_videos(self) -> avatar_videos.AvatarVideosResourceWithStreamingResponse:
+ from .resources.avatar_videos import AvatarVideosResourceWithStreamingResponse
+
+ return AvatarVideosResourceWithStreamingResponse(self._client.avatar_videos)
+
@cached_property
def documents(self) -> documents.DocumentsResourceWithStreamingResponse:
from .resources.documents import DocumentsResourceWithStreamingResponse
@@ -1185,6 +1217,12 @@ def avatars(self) -> avatars.AsyncAvatarsResourceWithStreamingResponse:
return AsyncAvatarsResourceWithStreamingResponse(self._client.avatars)
+ @cached_property
+ def avatar_videos(self) -> avatar_videos.AsyncAvatarVideosResourceWithStreamingResponse:
+ from .resources.avatar_videos import AsyncAvatarVideosResourceWithStreamingResponse
+
+ return AsyncAvatarVideosResourceWithStreamingResponse(self._client.avatar_videos)
+
@cached_property
def documents(self) -> documents.AsyncDocumentsResourceWithStreamingResponse:
from .resources.documents import AsyncDocumentsResourceWithStreamingResponse
diff --git a/src/runwayml/resources/__init__.py b/src/runwayml/resources/__init__.py
index ff71c4e..9f06fac 100644
--- a/src/runwayml/resources/__init__.py
+++ b/src/runwayml/resources/__init__.py
@@ -16,6 +16,14 @@
VoicesResourceWithStreamingResponse,
AsyncVoicesResourceWithStreamingResponse,
)
+from .avatars import (
+ AvatarsResource,
+ AsyncAvatarsResource,
+ AvatarsResourceWithRawResponse,
+ AsyncAvatarsResourceWithRawResponse,
+ AvatarsResourceWithStreamingResponse,
+ AsyncAvatarsResourceWithStreamingResponse,
+)
from .uploads import (
UploadsResource,
AsyncUploadsResource,
@@ -24,6 +32,14 @@
UploadsResourceWithStreamingResponse,
AsyncUploadsResourceWithStreamingResponse,
)
+from .documents import (
+ DocumentsResource,
+ AsyncDocumentsResource,
+ DocumentsResourceWithRawResponse,
+ AsyncDocumentsResourceWithRawResponse,
+ DocumentsResourceWithStreamingResponse,
+ AsyncDocumentsResourceWithStreamingResponse,
+)
from .workflows import (
WorkflowsResource,
AsyncWorkflowsResource,
@@ -48,6 +64,14 @@
SoundEffectResourceWithStreamingResponse,
AsyncSoundEffectResourceWithStreamingResponse,
)
+from .avatar_videos import (
+ AvatarVideosResource,
+ AsyncAvatarVideosResource,
+ AvatarVideosResourceWithRawResponse,
+ AsyncAvatarVideosResourceWithRawResponse,
+ AvatarVideosResourceWithStreamingResponse,
+ AsyncAvatarVideosResourceWithStreamingResponse,
+)
from .text_to_image import (
TextToImageResource,
AsyncTextToImageResource,
@@ -216,6 +240,24 @@
"AsyncUploadsResourceWithRawResponse",
"UploadsResourceWithStreamingResponse",
"AsyncUploadsResourceWithStreamingResponse",
+ "AvatarsResource",
+ "AsyncAvatarsResource",
+ "AvatarsResourceWithRawResponse",
+ "AsyncAvatarsResourceWithRawResponse",
+ "AvatarsResourceWithStreamingResponse",
+ "AsyncAvatarsResourceWithStreamingResponse",
+ "AvatarVideosResource",
+ "AsyncAvatarVideosResource",
+ "AvatarVideosResourceWithRawResponse",
+ "AsyncAvatarVideosResourceWithRawResponse",
+ "AvatarVideosResourceWithStreamingResponse",
+ "AsyncAvatarVideosResourceWithStreamingResponse",
+ "DocumentsResource",
+ "AsyncDocumentsResource",
+ "DocumentsResourceWithRawResponse",
+ "AsyncDocumentsResourceWithRawResponse",
+ "DocumentsResourceWithStreamingResponse",
+ "AsyncDocumentsResourceWithStreamingResponse",
"RealtimeSessionsResource",
"AsyncRealtimeSessionsResource",
"RealtimeSessionsResourceWithRawResponse",
diff --git a/src/runwayml/resources/avatar_videos.py b/src/runwayml/resources/avatar_videos.py
new file mode 100644
index 0000000..43f9a3c
--- /dev/null
+++ b/src/runwayml/resources/avatar_videos.py
@@ -0,0 +1,205 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import avatar_video_create_params
+from .._types import Body, Query, Headers, NotGiven, 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.avatar_video_create_response import AvatarVideoCreateResponse
+
+__all__ = ["AvatarVideosResource", "AsyncAvatarVideosResource"]
+
+
+class AvatarVideosResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AvatarVideosResourceWithRawResponse:
+ """
+ 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 AvatarVideosResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AvatarVideosResourceWithStreamingResponse:
+ """
+ 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 AvatarVideosResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ avatar: avatar_video_create_params.Avatar,
+ model: Literal["gwm1_avatars"],
+ speech: avatar_video_create_params.Speech,
+ # 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,
+ ) -> AvatarVideoCreateResponse:
+ """Start an asynchronous task to generate a video of an avatar speaking.
+
+ Provide
+ `speech` with `type: "audio"` (audio file) or `type: "text"` (text script for
+ TTS). Poll `GET /v1/tasks/:id` to check progress and retrieve the output video
+ URL once complete.
+
+ Args:
+ avatar: The avatar configuration for the session.
+
+ model: The model to use for avatar video generation.
+
+ speech: The speech source for avatar video generation. Either an audio file or text
+ script.
+
+ 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/avatar_videos",
+ body=maybe_transform(
+ {
+ "avatar": avatar,
+ "model": model,
+ "speech": speech,
+ },
+ avatar_video_create_params.AvatarVideoCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AvatarVideoCreateResponse,
+ )
+
+
+class AsyncAvatarVideosResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncAvatarVideosResourceWithRawResponse:
+ """
+ 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 AsyncAvatarVideosResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAvatarVideosResourceWithStreamingResponse:
+ """
+ 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 AsyncAvatarVideosResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ avatar: avatar_video_create_params.Avatar,
+ model: Literal["gwm1_avatars"],
+ speech: avatar_video_create_params.Speech,
+ # 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,
+ ) -> AvatarVideoCreateResponse:
+ """Start an asynchronous task to generate a video of an avatar speaking.
+
+ Provide
+ `speech` with `type: "audio"` (audio file) or `type: "text"` (text script for
+ TTS). Poll `GET /v1/tasks/:id` to check progress and retrieve the output video
+ URL once complete.
+
+ Args:
+ avatar: The avatar configuration for the session.
+
+ model: The model to use for avatar video generation.
+
+ speech: The speech source for avatar video generation. Either an audio file or text
+ script.
+
+ 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/avatar_videos",
+ body=await async_maybe_transform(
+ {
+ "avatar": avatar,
+ "model": model,
+ "speech": speech,
+ },
+ avatar_video_create_params.AvatarVideoCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AvatarVideoCreateResponse,
+ )
+
+
+class AvatarVideosResourceWithRawResponse:
+ def __init__(self, avatar_videos: AvatarVideosResource) -> None:
+ self._avatar_videos = avatar_videos
+
+ self.create = to_raw_response_wrapper(
+ avatar_videos.create,
+ )
+
+
+class AsyncAvatarVideosResourceWithRawResponse:
+ def __init__(self, avatar_videos: AsyncAvatarVideosResource) -> None:
+ self._avatar_videos = avatar_videos
+
+ self.create = async_to_raw_response_wrapper(
+ avatar_videos.create,
+ )
+
+
+class AvatarVideosResourceWithStreamingResponse:
+ def __init__(self, avatar_videos: AvatarVideosResource) -> None:
+ self._avatar_videos = avatar_videos
+
+ self.create = to_streamed_response_wrapper(
+ avatar_videos.create,
+ )
+
+
+class AsyncAvatarVideosResourceWithStreamingResponse:
+ def __init__(self, avatar_videos: AsyncAvatarVideosResource) -> None:
+ self._avatar_videos = avatar_videos
+
+ self.create = async_to_streamed_response_wrapper(
+ avatar_videos.create,
+ )
diff --git a/src/runwayml/resources/voices.py b/src/runwayml/resources/voices.py
index 7ec7166..bd7ec81 100644
--- a/src/runwayml/resources/voices.py
+++ b/src/runwayml/resources/voices.py
@@ -62,7 +62,8 @@ def create(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> VoiceCreateResponse:
"""
- Create a custom voice from a text description.
+ Create a custom voice from a text description, or clone a voice from an audio
+ sample.
Args:
from_: The source configuration for creating the voice.
@@ -218,7 +219,7 @@ def delete(
def preview(
self,
*,
- model: Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"],
+ model: Literal["eleven_ttv_v3", "eleven_multilingual_ttv_v2"],
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.
@@ -233,7 +234,8 @@ def preview(
audition a voice before creating it.
Args:
- model: The voice design model to use.
+ model: The voice design model to use. Prefer eleven_ttv_v3 (latest);
+ eleven_multilingual_ttv_v2 is the previous generation.
prompt: A text description of the desired voice characteristics. Must be at least 20
characters.
@@ -296,7 +298,8 @@ async def create(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> VoiceCreateResponse:
"""
- Create a custom voice from a text description.
+ Create a custom voice from a text description, or clone a voice from an audio
+ sample.
Args:
from_: The source configuration for creating the voice.
@@ -452,7 +455,7 @@ async def delete(
async def preview(
self,
*,
- model: Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"],
+ model: Literal["eleven_ttv_v3", "eleven_multilingual_ttv_v2"],
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.
@@ -467,7 +470,8 @@ async def preview(
audition a voice before creating it.
Args:
- model: The voice design model to use.
+ model: The voice design model to use. Prefer eleven_ttv_v3 (latest);
+ eleven_multilingual_ttv_v2 is the previous generation.
prompt: A text description of the desired voice characteristics. Must be at least 20
characters.
diff --git a/src/runwayml/types/__init__.py b/src/runwayml/types/__init__.py
index a3e8611..16995b4 100644
--- a/src/runwayml/types/__init__.py
+++ b/src/runwayml/types/__init__.py
@@ -25,12 +25,14 @@
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 .avatar_video_create_params import AvatarVideoCreateParams as AvatarVideoCreateParams
from .document_retrieve_response import DocumentRetrieveResponse as DocumentRetrieveResponse
from .sound_effect_create_params import SoundEffectCreateParams as SoundEffectCreateParams
from .workflow_retrieve_response import WorkflowRetrieveResponse as WorkflowRetrieveResponse
from .text_to_image_create_params import TextToImageCreateParams as TextToImageCreateParams
from .text_to_video_create_params import TextToVideoCreateParams as TextToVideoCreateParams
from .voice_dubbing_create_params import VoiceDubbingCreateParams as VoiceDubbingCreateParams
+from .avatar_video_create_response import AvatarVideoCreateResponse as AvatarVideoCreateResponse
from .image_to_video_create_params import ImageToVideoCreateParams as ImageToVideoCreateParams
from .sound_effect_create_response import SoundEffectCreateResponse as SoundEffectCreateResponse
from .text_to_speech_create_params import TextToSpeechCreateParams as TextToSpeechCreateParams
diff --git a/src/runwayml/types/avatar_video_create_params.py b/src/runwayml/types/avatar_video_create_params.py
new file mode 100644
index 0000000..f647a6d
--- /dev/null
+++ b/src/runwayml/types/avatar_video_create_params.py
@@ -0,0 +1,153 @@
+# 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__ = [
+ "AvatarVideoCreateParams",
+ "Avatar",
+ "AvatarRunwayPreset",
+ "AvatarCustom",
+ "Speech",
+ "SpeechAudio",
+ "SpeechText",
+ "SpeechTextVoice",
+ "SpeechTextVoicePreset",
+ "SpeechTextVoiceCustom",
+]
+
+
+class AvatarVideoCreateParams(TypedDict, total=False):
+ avatar: Required[Avatar]
+ """The avatar configuration for the session."""
+
+ model: Required[Literal["gwm1_avatars"]]
+ """The model to use for avatar video generation."""
+
+ speech: Required[Speech]
+ """The speech source for avatar video generation.
+
+ Either an audio file or text script.
+ """
+
+
+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]
+
+
+class SpeechAudio(TypedDict, total=False):
+ """Provide an audio file for the avatar to speak."""
+
+ audio: Required[str]
+ """A HTTPS URL."""
+
+ type: Required[Literal["audio"]]
+
+
+class SpeechTextVoicePreset(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"),
+ ]
+ ]
+
+ type: Required[Literal["preset"]]
+
+
+class SpeechTextVoiceCustom(TypedDict, total=False):
+ """A custom voice created via the Voices API."""
+
+ id: Required[str]
+
+ type: Required[Literal["custom"]]
+
+
+SpeechTextVoice: TypeAlias = Union[SpeechTextVoicePreset, SpeechTextVoiceCustom]
+
+
+class SpeechText(TypedDict, total=False):
+ """Provide text for the avatar to speak via TTS."""
+
+ text: Required[str]
+ """Text script for speech-driven video generation."""
+
+ type: Required[Literal["text"]]
+
+ voice: SpeechTextVoice
+ """Optional voice override for TTS.
+
+ If not provided, the avatar's configured voice is used.
+ """
+
+
+Speech: TypeAlias = Union[SpeechAudio, SpeechText]
diff --git a/src/runwayml/types/avatar_video_create_response.py b/src/runwayml/types/avatar_video_create_response.py
new file mode 100644
index 0000000..4c7cec2
--- /dev/null
+++ b/src/runwayml/types/avatar_video_create_response.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["AvatarVideoCreateResponse"]
+
+
+class AvatarVideoCreateResponse(BaseModel):
+ id: str
+ """The ID of the avatar video task.
+
+ Use `GET /v1/tasks/:id` to poll for status and output.
+ """
diff --git a/src/runwayml/types/voice_create_params.py b/src/runwayml/types/voice_create_params.py
index c008f45..c7acad5 100644
--- a/src/runwayml/types/voice_create_params.py
+++ b/src/runwayml/types/voice_create_params.py
@@ -2,12 +2,12 @@
from __future__ import annotations
-from typing import Optional
-from typing_extensions import Literal, Required, Annotated, TypedDict
+from typing import Union, Optional
+from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict
from .._utils import PropertyInfo
-__all__ = ["VoiceCreateParams", "From"]
+__all__ = ["VoiceCreateParams", "From", "FromText", "FromAudio"]
class VoiceCreateParams(TypedDict, total=False):
@@ -21,11 +21,15 @@ class VoiceCreateParams(TypedDict, total=False):
"""An optional description of the voice."""
-class From(TypedDict, total=False):
+class FromText(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."""
+ model: Required[Literal["eleven_ttv_v3", "eleven_multilingual_ttv_v2"]]
+ """The voice design model to use.
+
+ Prefer eleven_ttv_v3 (latest); eleven_multilingual_ttv_v2 is the previous
+ generation.
+ """
prompt: Required[str]
"""A text description of the desired voice characteristics.
@@ -34,3 +38,13 @@ class From(TypedDict, total=False):
"""
type: Required[Literal["text"]]
+
+
+class FromAudio(TypedDict, total=False):
+ audio: Required[str]
+ """A HTTPS URL."""
+
+ type: Required[Literal["audio"]]
+
+
+From: TypeAlias = Union[FromText, FromAudio]
diff --git a/src/runwayml/types/voice_preview_params.py b/src/runwayml/types/voice_preview_params.py
index f603c8a..bf5c30b 100644
--- a/src/runwayml/types/voice_preview_params.py
+++ b/src/runwayml/types/voice_preview_params.py
@@ -8,8 +8,12 @@
class VoicePreviewParams(TypedDict, total=False):
- model: Required[Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"]]
- """The voice design model to use."""
+ model: Required[Literal["eleven_ttv_v3", "eleven_multilingual_ttv_v2"]]
+ """The voice design model to use.
+
+ Prefer eleven_ttv_v3 (latest); eleven_multilingual_ttv_v2 is the previous
+ generation.
+ """
prompt: Required[str]
"""A text description of the desired voice characteristics.
diff --git a/tests/api_resources/test_avatar_videos.py b/tests/api_resources/test_avatar_videos.py
new file mode 100644
index 0000000..60984eb
--- /dev/null
+++ b/tests/api_resources/test_avatar_videos.py
@@ -0,0 +1,164 @@
+# 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 AvatarVideoCreateResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAvatarVideos:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: RunwayML) -> None:
+ avatar_video = client.avatar_videos.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ speech={
+ "audio": "https://example.com/file",
+ "type": "audio",
+ },
+ )
+ assert_matches_type(AvatarVideoCreateResponse, avatar_video, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: RunwayML) -> None:
+ avatar_video = client.avatar_videos.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ speech={
+ "audio": "https://example.com/file",
+ "type": "audio",
+ },
+ )
+ assert_matches_type(AvatarVideoCreateResponse, avatar_video, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: RunwayML) -> None:
+ response = client.avatar_videos.with_raw_response.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ speech={
+ "audio": "https://example.com/file",
+ "type": "audio",
+ },
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar_video = response.parse()
+ assert_matches_type(AvatarVideoCreateResponse, avatar_video, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: RunwayML) -> None:
+ with client.avatar_videos.with_streaming_response.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ speech={
+ "audio": "https://example.com/file",
+ "type": "audio",
+ },
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar_video = response.parse()
+ assert_matches_type(AvatarVideoCreateResponse, avatar_video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncAvatarVideos:
+ 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_video = await async_client.avatar_videos.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ speech={
+ "audio": "https://example.com/file",
+ "type": "audio",
+ },
+ )
+ assert_matches_type(AvatarVideoCreateResponse, avatar_video, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) -> None:
+ avatar_video = await async_client.avatar_videos.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ speech={
+ "audio": "https://example.com/file",
+ "type": "audio",
+ },
+ )
+ assert_matches_type(AvatarVideoCreateResponse, avatar_video, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None:
+ response = await async_client.avatar_videos.with_raw_response.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ speech={
+ "audio": "https://example.com/file",
+ "type": "audio",
+ },
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ avatar_video = await response.parse()
+ assert_matches_type(AvatarVideoCreateResponse, avatar_video, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None:
+ async with async_client.avatar_videos.with_streaming_response.create(
+ avatar={
+ "preset_id": "game-character",
+ "type": "runway-preset",
+ },
+ model="gwm1_avatars",
+ speech={
+ "audio": "https://example.com/file",
+ "type": "audio",
+ },
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ avatar_video = await response.parse()
+ assert_matches_type(AvatarVideoCreateResponse, avatar_video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_voices.py b/tests/api_resources/test_voices.py
index 548a5aa..9076209 100644
--- a/tests/api_resources/test_voices.py
+++ b/tests/api_resources/test_voices.py
@@ -27,7 +27,7 @@ class TestVoices:
def test_method_create(self, client: RunwayML) -> None:
voice = client.voices.create(
from_={
- "model": "eleven_multilingual_ttv_v2",
+ "model": "eleven_ttv_v3",
"prompt": "xxxxxxxxxxxxxxxxxxxx",
"type": "text",
},
@@ -39,7 +39,7 @@ def test_method_create(self, client: RunwayML) -> None:
def test_method_create_with_all_params(self, client: RunwayML) -> None:
voice = client.voices.create(
from_={
- "model": "eleven_multilingual_ttv_v2",
+ "model": "eleven_ttv_v3",
"prompt": "xxxxxxxxxxxxxxxxxxxx",
"type": "text",
},
@@ -52,7 +52,7 @@ def test_method_create_with_all_params(self, client: RunwayML) -> None:
def test_raw_response_create(self, client: RunwayML) -> None:
response = client.voices.with_raw_response.create(
from_={
- "model": "eleven_multilingual_ttv_v2",
+ "model": "eleven_ttv_v3",
"prompt": "xxxxxxxxxxxxxxxxxxxx",
"type": "text",
},
@@ -68,7 +68,7 @@ def test_raw_response_create(self, client: RunwayML) -> None:
def test_streaming_response_create(self, client: RunwayML) -> None:
with client.voices.with_streaming_response.create(
from_={
- "model": "eleven_multilingual_ttv_v2",
+ "model": "eleven_ttv_v3",
"prompt": "xxxxxxxxxxxxxxxxxxxx",
"type": "text",
},
@@ -200,7 +200,7 @@ def test_path_params_delete(self, client: RunwayML) -> None:
@parametrize
def test_method_preview(self, client: RunwayML) -> None:
voice = client.voices.preview(
- model="eleven_multilingual_ttv_v2",
+ model="eleven_ttv_v3",
prompt="xxxxxxxxxxxxxxxxxxxx",
)
assert_matches_type(VoicePreviewResponse, voice, path=["response"])
@@ -208,7 +208,7 @@ def test_method_preview(self, client: RunwayML) -> None:
@parametrize
def test_raw_response_preview(self, client: RunwayML) -> None:
response = client.voices.with_raw_response.preview(
- model="eleven_multilingual_ttv_v2",
+ model="eleven_ttv_v3",
prompt="xxxxxxxxxxxxxxxxxxxx",
)
@@ -220,7 +220,7 @@ def test_raw_response_preview(self, client: RunwayML) -> None:
@parametrize
def test_streaming_response_preview(self, client: RunwayML) -> None:
with client.voices.with_streaming_response.preview(
- model="eleven_multilingual_ttv_v2",
+ model="eleven_ttv_v3",
prompt="xxxxxxxxxxxxxxxxxxxx",
) as response:
assert not response.is_closed
@@ -241,7 +241,7 @@ class TestAsyncVoices:
async def test_method_create(self, async_client: AsyncRunwayML) -> None:
voice = await async_client.voices.create(
from_={
- "model": "eleven_multilingual_ttv_v2",
+ "model": "eleven_ttv_v3",
"prompt": "xxxxxxxxxxxxxxxxxxxx",
"type": "text",
},
@@ -253,7 +253,7 @@ async def test_method_create(self, async_client: AsyncRunwayML) -> None:
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",
+ "model": "eleven_ttv_v3",
"prompt": "xxxxxxxxxxxxxxxxxxxx",
"type": "text",
},
@@ -266,7 +266,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunwayML)
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",
+ "model": "eleven_ttv_v3",
"prompt": "xxxxxxxxxxxxxxxxxxxx",
"type": "text",
},
@@ -282,7 +282,7 @@ async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None:
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",
+ "model": "eleven_ttv_v3",
"prompt": "xxxxxxxxxxxxxxxxxxxx",
"type": "text",
},
@@ -414,7 +414,7 @@ async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None:
@parametrize
async def test_method_preview(self, async_client: AsyncRunwayML) -> None:
voice = await async_client.voices.preview(
- model="eleven_multilingual_ttv_v2",
+ model="eleven_ttv_v3",
prompt="xxxxxxxxxxxxxxxxxxxx",
)
assert_matches_type(VoicePreviewResponse, voice, path=["response"])
@@ -422,7 +422,7 @@ async def test_method_preview(self, async_client: AsyncRunwayML) -> None:
@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",
+ model="eleven_ttv_v3",
prompt="xxxxxxxxxxxxxxxxxxxx",
)
@@ -434,7 +434,7 @@ async def test_raw_response_preview(self, async_client: AsyncRunwayML) -> None:
@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",
+ model="eleven_ttv_v3",
prompt="xxxxxxxxxxxxxxxxxxxx",
) as response:
assert not response.is_closed
From e8fe41ba8c95f2263a08faefe2d791374b1db5d0 Mon Sep 17 00:00:00 2001
From: Daniil
Date: Fri, 10 Apr 2026 11:32:22 +0200
Subject: [PATCH 3/4] feat(polling): add wait_for_task_output to
avatar_videos.create
---
src/runwayml/resources/avatar_videos.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/runwayml/resources/avatar_videos.py b/src/runwayml/resources/avatar_videos.py
index 43f9a3c..c4abd94 100644
--- a/src/runwayml/resources/avatar_videos.py
+++ b/src/runwayml/resources/avatar_videos.py
@@ -17,6 +17,12 @@
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
+from ..lib.polling import (
+ NewTaskCreatedResponse,
+ AsyncNewTaskCreatedResponse,
+ create_waitable_resource,
+ create_async_waitable_resource,
+)
from .._base_client import make_request_options
from ..types.avatar_video_create_response import AvatarVideoCreateResponse
@@ -55,7 +61,7 @@ def create(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AvatarVideoCreateResponse:
+ ) -> NewTaskCreatedResponse:
"""Start an asynchronous task to generate a video of an avatar speaking.
Provide
@@ -92,7 +98,7 @@ def create(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=AvatarVideoCreateResponse,
+ cast_to=create_waitable_resource(AvatarVideoCreateResponse, self._client),
)
@@ -128,7 +134,7 @@ async def create(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AvatarVideoCreateResponse:
+ ) -> AsyncNewTaskCreatedResponse:
"""Start an asynchronous task to generate a video of an avatar speaking.
Provide
@@ -165,7 +171,7 @@ async def create(
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=AvatarVideoCreateResponse,
+ cast_to=create_async_waitable_resource(AvatarVideoCreateResponse, self._client),
)
From df9e90835b34e7e58bc508a95b622a919414e33b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 10 Apr 2026 09:32:51 +0000
Subject: [PATCH 4/4] release: 4.11.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 19 +++++++++++++++++++
pyproject.toml | 2 +-
src/runwayml/_version.py | 2 +-
4 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index ad56a78..a43b15a 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "4.10.0"
+ ".": "4.11.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a8084fe..401169b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,24 @@
# Changelog
+## 4.11.0 (2026-04-10)
+
+Full Changelog: [v4.10.0...v4.11.0](https://github.com/runwayml/sdk-python/compare/v4.10.0...v4.11.0)
+
+### Features
+
+* **api:** add avatar_videos resource ([75b6ded](https://github.com/runwayml/sdk-python/commit/75b6deda8c5733115af29c9374ae10f3d4f4716a))
+* **polling:** add wait_for_task_output to avatar_videos.create ([e8fe41b](https://github.com/runwayml/sdk-python/commit/e8fe41ba8c95f2263a08faefe2d791374b1db5d0))
+
+
+### Bug Fixes
+
+* **client:** preserve hardcoded query params when merging with user params ([839c38b](https://github.com/runwayml/sdk-python/commit/839c38bc95d9147b140481907621942c5c503ead))
+
+
+### Chores
+
+* pin GitHub Actions to full commit SHAs ([8f7689b](https://github.com/runwayml/sdk-python/commit/8f7689bac99f57930dd88a9ab3d4c9a279a13888))
+
## 4.10.0 (2026-04-01)
Full Changelog: [v4.9.0...v4.10.0](https://github.com/runwayml/sdk-python/compare/v4.9.0...v4.10.0)
diff --git a/pyproject.toml b/pyproject.toml
index dcbf477..c8a9c2f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "runwayml"
-version = "4.10.0"
+version = "4.11.0"
description = "The official Python library for the runwayml API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/runwayml/_version.py b/src/runwayml/_version.py
index 1f2d85c..2d1640a 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.10.0" # x-release-please-version
+__version__ = "4.11.0" # x-release-please-version