diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3c9ae23..bd7f384 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.1.1" + ".": "4.2.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index f7f71cf..cfa3db4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 15 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml%2Frunwayml-c2a88516fa0c20ca73f742f8d876f5e773747b4f6903508b1824c0939b313b82.yml -openapi_spec_hash: 660d0eec8f3940727f541dd05121627b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml%2Frunwayml-f1f066255f00c8db87d86efaff73852278f21c2619f83dcf9f4e5cf54ef146b0.yml +openapi_spec_hash: af56570f2801ec4bfc94a05ca5393f9c config_hash: b98eed33f1bba05e3c2a3e20d85d582a diff --git a/CHANGELOG.md b/CHANGELOG.md index c1be736..02392b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 4.2.0 (2025-12-04) + +Full Changelog: [v4.1.1...v4.2.0](https://github.com/runwayml/sdk-python/compare/v4.1.1...v4.2.0) + +### Features + +* **api:** Autogen spec updates ([e9d2114](https://github.com/runwayml/sdk-python/commit/e9d2114b819a6a641e716c0823ba1f182c3b5400)) +* **api:** gemini_3_pro t2i ([1f1fcfa](https://github.com/runwayml/sdk-python/commit/1f1fcfa6bac257df24a383613389010d0c481f5d)) +* **api:** gemini_3_pro t2i ([ea8a4ec](https://github.com/runwayml/sdk-python/commit/ea8a4ec3e05e27e5b4db85481846678c0fc0c009)) +* **api:** Remove unreleased model ([ee474d5](https://github.com/runwayml/sdk-python/commit/ee474d50717cd5517f2bbcb072fd044205587260)) +* **api:** Revert G3P changes ([3959ddf](https://github.com/runwayml/sdk-python/commit/3959ddfb5bfee6a7beff2cd6d294b59204dd6fae)) + + +### Chores + +* **docs:** use environment variables for authentication in code snippets ([cd6776e](https://github.com/runwayml/sdk-python/commit/cd6776ecdccbb9bebb88db16a4b3ef46b246d23d)) +* update lockfile ([7199587](https://github.com/runwayml/sdk-python/commit/719958796a3c89ff20b2e4e2b0db1e375f836125)) + ## 4.1.1 (2025-11-28) Full Changelog: [v4.1.0...v4.1.1](https://github.com/runwayml/sdk-python/compare/v4.1.0...v4.1.1) diff --git a/README.md b/README.md index b4dda86..50dfb5d 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ pip install runwayml[aiohttp] Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python +import os import asyncio from runwayml import DefaultAioHttpClient from runwayml import AsyncRunwayML @@ -96,7 +97,7 @@ from runwayml import AsyncRunwayML async def main() -> None: async with AsyncRunwayML( - api_key="My API Key", + api_key=os.environ.get("RUNWAYML_API_SECRET"), # This is the default and can be omitted http_client=DefaultAioHttpClient(), ) as client: image_to_video = await client.image_to_video.create( diff --git a/pyproject.toml b/pyproject.toml index c18acaa..668ea2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,20 +1,22 @@ [project] name = "runwayml" -version = "4.1.1" +version = "4.2.0" description = "The official Python library for the runwayml API" dynamic = ["readme"] license = "Apache-2.0" authors = [ { name = "RunwayML", email = "dev-feedback@runwayml.com" }, ] + dependencies = [ - "httpx>=0.23.0, <1", - "pydantic>=1.9.0, <3", - "typing-extensions>=4.10, <5", - "anyio>=3.5.0, <5", - "distro>=1.7.0, <2", - "sniffio", + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.10, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", ] + requires-python = ">= 3.9" classifiers = [ "Typing :: Typed", diff --git a/requirements-dev.lock b/requirements-dev.lock index c8a60e4..cd73af7 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -12,40 +12,45 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.8 +aiohttp==3.13.2 # via httpx-aiohttp # via runwayml -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.12.0 # via httpx # via runwayml -argcomplete==3.1.2 +argcomplete==3.6.3 # via nox async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 + # via nox +backports-asyncio-runner==1.2.0 + # via pytest-asyncio +certifi==2025.11.12 # via httpcore # via httpx -colorlog==6.7.0 +colorlog==6.10.1 + # via nox +dependency-groups==1.3.1 # via nox -dirty-equals==0.6.0 -distlib==0.3.7 +dirty-equals==0.11 +distlib==0.4.0 # via virtualenv -distro==1.8.0 +distro==1.9.0 # via runwayml -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio # via pytest -execnet==2.1.1 +execnet==2.1.2 # via pytest-xdist -filelock==3.12.4 +filelock==3.19.1 # via virtualenv -frozenlist==1.6.2 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -58,82 +63,87 @@ httpx==0.28.1 # via runwayml httpx-aiohttp==0.1.9 # via runwayml -idna==3.4 +humanize==4.13.0 + # via nox +idna==3.11 # via anyio # via httpx # via yarl -importlib-metadata==7.0.0 -iniconfig==2.0.0 +importlib-metadata==8.7.0 +iniconfig==2.1.0 # via pytest markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -multidict==6.4.4 +multidict==6.7.0 # via aiohttp # via yarl mypy==1.17.0 -mypy-extensions==1.0.0 +mypy-extensions==1.1.0 # via mypy -nodeenv==1.8.0 +nodeenv==1.9.1 # via pyright -nox==2023.4.22 -packaging==23.2 +nox==2025.11.12 +packaging==25.0 + # via dependency-groups # via nox # via pytest pathspec==0.12.1 # via mypy -platformdirs==3.11.0 +platformdirs==4.4.0 # via virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via pytest -propcache==0.3.1 +propcache==0.4.1 # via aiohttp # via yarl -pydantic==2.11.9 +pydantic==2.12.5 # via runwayml -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic -pygments==2.18.0 +pygments==2.19.2 + # via pytest # via rich pyright==1.1.399 -pytest==8.3.3 +pytest==8.4.2 # via pytest-asyncio # via pytest-xdist -pytest-asyncio==0.24.0 -pytest-xdist==3.7.0 -python-dateutil==2.8.2 +pytest-asyncio==1.2.0 +pytest-xdist==3.8.0 +python-dateutil==2.9.0.post0 # via time-machine -pytz==2023.3.post1 - # via dirty-equals respx==0.22.0 -rich==13.7.1 -ruff==0.9.4 -setuptools==68.2.2 - # via nodeenv -six==1.16.0 +rich==14.2.0 +ruff==0.14.7 +six==1.17.0 # via python-dateutil -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via runwayml -time-machine==2.9.0 -tomli==2.0.2 +time-machine==2.19.0 +tomli==2.3.0 + # via dependency-groups # via mypy + # via nox # via pytest -typing-extensions==4.12.2 +typing-extensions==4.15.0 + # via aiosignal # via anyio + # via exceptiongroup # via multidict # via mypy # via pydantic # via pydantic-core # via pyright + # via pytest-asyncio # via runwayml # via typing-inspection -typing-inspection==0.4.1 + # via virtualenv +typing-inspection==0.4.2 # via pydantic -virtualenv==20.24.5 +virtualenv==20.35.4 # via nox -yarl==1.20.0 +yarl==1.22.0 # via aiohttp -zipp==3.17.0 +zipp==3.23.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index a6ec1c3..3fd0b43 100644 --- a/requirements.lock +++ b/requirements.lock @@ -12,28 +12,28 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.8 +aiohttp==3.13.2 # via httpx-aiohttp # via runwayml -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.12.0 # via httpx # via runwayml async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 +certifi==2025.11.12 # via httpcore # via httpx -distro==1.8.0 +distro==1.9.0 # via runwayml -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio -frozenlist==1.6.2 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -45,25 +45,26 @@ httpx==0.28.1 # via runwayml httpx-aiohttp==0.1.9 # via runwayml -idna==3.4 +idna==3.11 # via anyio # via httpx # via yarl -multidict==6.4.4 +multidict==6.7.0 # via aiohttp # via yarl -propcache==0.3.1 +propcache==0.4.1 # via aiohttp # via yarl pydantic==2.12.5 # via runwayml pydantic-core==2.41.5 # via pydantic -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via runwayml typing-extensions==4.15.0 + # via aiosignal # via anyio + # via exceptiongroup # via multidict # via pydantic # via pydantic-core @@ -71,5 +72,5 @@ typing-extensions==4.15.0 # via typing-inspection typing-inspection==0.4.2 # via pydantic -yarl==1.20.0 +yarl==1.22.0 # via aiohttp diff --git a/src/runwayml/_version.py b/src/runwayml/_version.py index ab67098..9e0ccac 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.1.1" # x-release-please-version +__version__ = "4.2.0" # x-release-please-version diff --git a/src/runwayml/lib/polling.py b/src/runwayml/lib/polling.py index 5c40a6e..d91c537 100644 --- a/src/runwayml/lib/polling.py +++ b/src/runwayml/lib/polling.py @@ -1,12 +1,22 @@ import time import random -from typing import TYPE_CHECKING, Type, Union, TypeVar, cast -from typing_extensions import ParamSpec +from typing import TYPE_CHECKING, Type, Union, TypeVar, Callable, Annotated, Coroutine, cast +from typing_extensions import ParamSpec, TypeAlias import anyio +from runwayml._utils import PropertyInfo + from .._models import BaseModel -from ..types.task_retrieve_response import TaskRetrieveResponse +from ..types.task_retrieve_response import ( + Failed, + Pending, + Running, + Cancelled, + Succeeded, + Throttled, + TaskRetrieveResponse, +) if TYPE_CHECKING: from .._client import RunwayML, AsyncRunwayML @@ -40,10 +50,6 @@ class NewTaskCreatedResponse(AwaitableTaskResponseMixin, BaseModel): id: str -class AwaitableTaskRetrieveResponse(AwaitableTaskResponseMixin, TaskRetrieveResponse): - pass - - class AsyncAwaitableTaskResponseMixin: async def wait_for_task_output(self, timeout: Union[float, None] = 60 * 10) -> TaskRetrieveResponse: # type: ignore[empty-body] """ @@ -67,10 +73,6 @@ class AsyncNewTaskCreatedResponse(AsyncAwaitableTaskResponseMixin, BaseModel): id: str -class AsyncAwaitableTaskRetrieveResponse(AsyncAwaitableTaskResponseMixin, TaskRetrieveResponse): - pass - - def create_waitable_resource(base_class: Type[T], client: "RunwayML") -> Type[NewTaskCreatedResponse]: class WithClient(base_class): # type: ignore[valid-type,misc] id: str @@ -125,3 +127,74 @@ class TaskTimeoutError(Exception): def __init__(self, task_details: TaskRetrieveResponse): self.task_details = task_details super().__init__(f"Task timed out") + + + +class AwaitablePending(AwaitableTaskResponseMixin, Pending): ... +class AwaitableThrottled(AwaitableTaskResponseMixin, Throttled): ... +class AwaitableCancelled(AwaitableTaskResponseMixin, Cancelled): ... +class AwaitableRunning(AwaitableTaskResponseMixin, Running): ... +class AwaitableFailed(AwaitableTaskResponseMixin, Failed): ... +class AwaitableSucceeded(AwaitableTaskResponseMixin, Succeeded): ... + +AwaitableTaskRetrieveResponse: TypeAlias = Annotated[ + Union[AwaitablePending, AwaitableThrottled, AwaitableCancelled, AwaitableRunning, AwaitableFailed, AwaitableSucceeded], + PropertyInfo(discriminator="status") +] + +class AsyncAwaitablePending(AsyncAwaitableTaskResponseMixin, Pending): ... +class AsyncAwaitableThrottled(AsyncAwaitableTaskResponseMixin, Throttled): ... +class AsyncAwaitableCancelled(AsyncAwaitableTaskResponseMixin, Cancelled): ... +class AsyncAwaitableRunning(AsyncAwaitableTaskResponseMixin, Running): ... +class AsyncAwaitableFailed(AsyncAwaitableTaskResponseMixin, Failed): ... +class AsyncAwaitableSucceeded(AsyncAwaitableTaskResponseMixin, Succeeded): ... + +AsyncAwaitableTaskRetrieveResponse: TypeAlias = Annotated[ + Union[AsyncAwaitablePending, AsyncAwaitableThrottled, AsyncAwaitableCancelled, AsyncAwaitableRunning, AsyncAwaitableFailed, AsyncAwaitableSucceeded], + PropertyInfo(discriminator="status") +] + +def _make_sync_wait_for_task_output(client: "RunwayML") -> Callable[["AwaitableTaskResponseMixin", Union[float, None]], TaskRetrieveResponse]: + """Create a wait_for_task_output method bound to the given client.""" + def wait_for_task_output(self: "AwaitableTaskResponseMixin", timeout: Union[float, None] = 60 * 10) -> TaskRetrieveResponse: + start_time = time.time() + while True: + time.sleep(POLL_TIME + random.random() * POLL_JITTER - POLL_JITTER / 2) + task_details = client.tasks.retrieve(self.id) # type: ignore[attr-defined] + if task_details.status == "SUCCEEDED": + return task_details + if task_details.status == "FAILED": + raise TaskFailedError(task_details) + if timeout is not None and time.time() - start_time > timeout: + raise TaskTimeoutError(task_details) + return wait_for_task_output + + +def inject_sync_wait_method(client: "RunwayML", response: T) -> T: + """Inject the wait_for_task_output method onto the response instance.""" + import types + response.wait_for_task_output = types.MethodType(_make_sync_wait_for_task_output(client), response) # type: ignore[attr-defined] + return response + + +def _make_async_wait_for_task_output(client: "AsyncRunwayML") -> Callable[["AsyncAwaitableTaskResponseMixin", Union[float, None]], Coroutine[None, None, TaskRetrieveResponse]]: + """Create an async wait_for_task_output method bound to the given client.""" + async def wait_for_task_output(self: "AsyncAwaitableTaskResponseMixin", timeout: Union[float, None] = 60 * 10) -> TaskRetrieveResponse: + start_time = anyio.current_time() + while True: + await anyio.sleep(POLL_TIME + random.random() * POLL_JITTER - POLL_JITTER / 2) + task_details = await client.tasks.retrieve(self.id) # type: ignore[attr-defined] + if task_details.status == "SUCCEEDED": + return task_details + if task_details.status == "FAILED" or task_details.status == "CANCELLED": + raise TaskFailedError(task_details) + if timeout is not None and anyio.current_time() - start_time > timeout: + raise TaskTimeoutError(task_details) + return wait_for_task_output + + +def inject_async_wait_method(client: "AsyncRunwayML", response: T) -> T: + """Inject the async wait_for_task_output method onto the response instance.""" + import types + response.wait_for_task_output = types.MethodType(_make_async_wait_for_task_output(client), response) # type: ignore[attr-defined] + return response diff --git a/src/runwayml/resources/tasks.py b/src/runwayml/resources/tasks.py index 496d1c4..3803e98 100644 --- a/src/runwayml/resources/tasks.py +++ b/src/runwayml/resources/tasks.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import cast +from typing import Any, cast import httpx @@ -18,11 +18,10 @@ from ..lib.polling import ( AwaitableTaskRetrieveResponse, AsyncAwaitableTaskRetrieveResponse, - create_waitable_resource, - create_async_waitable_resource, + inject_sync_wait_method, + inject_async_wait_method, ) from .._base_client import make_request_options -from ..types.task_retrieve_response import TaskRetrieveResponse __all__ = ["TasksResource", "AsyncTasksResource"] @@ -74,15 +73,14 @@ def retrieve( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._get( + response = self._get( f"/v1/tasks/{id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=cast( - type[AwaitableTaskRetrieveResponse], create_waitable_resource(TaskRetrieveResponse, self._client) - ), + cast_to=cast(Any, AwaitableTaskRetrieveResponse), # Union types cannot be passed in as arguments in the type system ) + return cast(AwaitableTaskRetrieveResponse, inject_sync_wait_method(self._client, response)) def delete( self, @@ -171,16 +169,14 @@ async def retrieve( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._get( + response = await self._get( f"/v1/tasks/{id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=cast( - type[AsyncAwaitableTaskRetrieveResponse], - create_async_waitable_resource(TaskRetrieveResponse, self._client), - ), + cast_to=cast(Any, AsyncAwaitableTaskRetrieveResponse), # Union types cannot be passed in as arguments in the type system ) + return cast(AsyncAwaitableTaskRetrieveResponse, inject_async_wait_method(self._client, response)) async def delete( self, diff --git a/src/runwayml/types/character_performance_create_response.py b/src/runwayml/types/character_performance_create_response.py index 61b4fff..48ab1c5 100644 --- a/src/runwayml/types/character_performance_create_response.py +++ b/src/runwayml/types/character_performance_create_response.py @@ -7,3 +7,4 @@ class CharacterPerformanceCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/image_to_video_create_response.py b/src/runwayml/types/image_to_video_create_response.py index 5c381da..8b03891 100644 --- a/src/runwayml/types/image_to_video_create_response.py +++ b/src/runwayml/types/image_to_video_create_response.py @@ -7,3 +7,4 @@ class ImageToVideoCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/organization_retrieve_response.py b/src/runwayml/types/organization_retrieve_response.py index 3621c54..f3a56ca 100644 --- a/src/runwayml/types/organization_retrieve_response.py +++ b/src/runwayml/types/organization_retrieve_response.py @@ -1,173 +1,15 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict from pydantic import Field as FieldInfo from .._models import BaseModel -__all__ = [ - "OrganizationRetrieveResponse", - "Tier", - "TierModels", - "TierModelsActTwo", - "TierModelsElevenMultilingualStsV2", - "TierModelsElevenMultilingualV2", - "TierModelsElevenTextToSoundV2", - "TierModelsElevenVoiceDubbing", - "TierModelsElevenVoiceIsolation", - "TierModelsGemini2_5Flash", - "TierModelsGen3aTurbo", - "TierModelsGen4Aleph", - "TierModelsGen4Image", - "TierModelsGen4ImageTurbo", - "TierModelsGen4Turbo", - "TierModelsUpscaleV1", - "TierModelsVeo3", - "TierModelsVeo3_1", - "TierModelsVeo3_1Fast", - "Usage", - "UsageModels", - "UsageModelsActTwo", - "UsageModelsElevenMultilingualStsV2", - "UsageModelsElevenMultilingualV2", - "UsageModelsElevenTextToSoundV2", - "UsageModelsElevenVoiceDubbing", - "UsageModelsElevenVoiceIsolation", - "UsageModelsGemini2_5Flash", - "UsageModelsGen3aTurbo", - "UsageModelsGen4Aleph", - "UsageModelsGen4Image", - "UsageModelsGen4ImageTurbo", - "UsageModelsGen4Turbo", - "UsageModelsUpscaleV1", - "UsageModelsVeo3", - "UsageModelsVeo3_1", - "UsageModelsVeo3_1Fast", -] +__all__ = ["OrganizationRetrieveResponse", "Tier", "TierModels", "Usage", "UsageModels"] -class TierModelsActTwo(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsElevenMultilingualStsV2(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsElevenMultilingualV2(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsElevenTextToSoundV2(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsElevenVoiceDubbing(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsElevenVoiceIsolation(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsGemini2_5Flash(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsGen3aTurbo(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsGen4Aleph(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsGen4Image(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsGen4ImageTurbo(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsGen4Turbo(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsUpscaleV1(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsVeo3(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsVeo3_1(BaseModel): - max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") - """The maximum number of generations that can be run concurrently for this model.""" - - max_daily_generations: int = FieldInfo(alias="maxDailyGenerations") - """The maximum number of generations that can be created each day for this model.""" - - -class TierModelsVeo3_1Fast(BaseModel): +class TierModels(BaseModel): max_concurrent_generations: int = FieldInfo(alias="maxConcurrentGenerations") """The maximum number of generations that can be run concurrently for this model.""" @@ -175,197 +17,21 @@ class TierModelsVeo3_1Fast(BaseModel): """The maximum number of generations that can be created each day for this model.""" -class TierModels(BaseModel): - act_two: Optional[TierModelsActTwo] = None - """Limits associated with the act_two model.""" - - eleven_multilingual_sts_v2: Optional[TierModelsElevenMultilingualStsV2] = None - """Limits associated with the eleven_multilingual_sts_v2 model.""" - - eleven_multilingual_v2: Optional[TierModelsElevenMultilingualV2] = None - """Limits associated with the eleven_multilingual_v2 model.""" - - eleven_text_to_sound_v2: Optional[TierModelsElevenTextToSoundV2] = None - """Limits associated with the eleven_text_to_sound_v2 model.""" - - eleven_voice_dubbing: Optional[TierModelsElevenVoiceDubbing] = None - """Limits associated with the eleven_voice_dubbing model.""" - - eleven_voice_isolation: Optional[TierModelsElevenVoiceIsolation] = None - """Limits associated with the eleven_voice_isolation model.""" - - gemini_2_5_flash: Optional[TierModelsGemini2_5Flash] = FieldInfo(alias="gemini_2.5_flash", default=None) - """Limits associated with the gemini_2.5_flash model.""" - - gen3a_turbo: Optional[TierModelsGen3aTurbo] = None - """Limits associated with the gen3a_turbo model.""" - - gen4_aleph: Optional[TierModelsGen4Aleph] = None - """Limits associated with the gen4_aleph model.""" - - gen4_image: Optional[TierModelsGen4Image] = None - """Limits associated with the gen4_image model.""" - - gen4_image_turbo: Optional[TierModelsGen4ImageTurbo] = None - """Limits associated with the gen4_image_turbo model.""" - - gen4_turbo: Optional[TierModelsGen4Turbo] = None - """Limits associated with the gen4_turbo model.""" - - upscale_v1: Optional[TierModelsUpscaleV1] = None - """Limits associated with the upscale_v1 model.""" - - veo3: Optional[TierModelsVeo3] = None - """Limits associated with the veo3 model.""" - - veo3_1: Optional[TierModelsVeo3_1] = FieldInfo(alias="veo3.1", default=None) - """Limits associated with the veo3.1 model.""" - - veo3_1_fast: Optional[TierModelsVeo3_1Fast] = FieldInfo(alias="veo3.1_fast", default=None) - """Limits associated with the veo3.1_fast model.""" - - class Tier(BaseModel): max_monthly_credit_spend: int = FieldInfo(alias="maxMonthlyCreditSpend") """The maximum number of credits that can be purchased in a month.""" - models: TierModels + models: Dict[str, TierModels] """An object containing model-specific limits. Each key represents a model.""" -class UsageModelsActTwo(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsElevenMultilingualStsV2(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsElevenMultilingualV2(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsElevenTextToSoundV2(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsElevenVoiceDubbing(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsElevenVoiceIsolation(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsGemini2_5Flash(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsGen3aTurbo(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsGen4Aleph(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsGen4Image(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsGen4ImageTurbo(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsGen4Turbo(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsUpscaleV1(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsVeo3(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsVeo3_1(BaseModel): - daily_generations: int = FieldInfo(alias="dailyGenerations") - """The number of generations that have been run for this model in the past day.""" - - -class UsageModelsVeo3_1Fast(BaseModel): +class UsageModels(BaseModel): daily_generations: int = FieldInfo(alias="dailyGenerations") """The number of generations that have been run for this model in the past day.""" -class UsageModels(BaseModel): - act_two: Optional[UsageModelsActTwo] = None - """Usage data for the act_two model.""" - - eleven_multilingual_sts_v2: Optional[UsageModelsElevenMultilingualStsV2] = None - """Usage data for the eleven_multilingual_sts_v2 model.""" - - eleven_multilingual_v2: Optional[UsageModelsElevenMultilingualV2] = None - """Usage data for the eleven_multilingual_v2 model.""" - - eleven_text_to_sound_v2: Optional[UsageModelsElevenTextToSoundV2] = None - """Usage data for the eleven_text_to_sound_v2 model.""" - - eleven_voice_dubbing: Optional[UsageModelsElevenVoiceDubbing] = None - """Usage data for the eleven_voice_dubbing model.""" - - eleven_voice_isolation: Optional[UsageModelsElevenVoiceIsolation] = None - """Usage data for the eleven_voice_isolation model.""" - - gemini_2_5_flash: Optional[UsageModelsGemini2_5Flash] = FieldInfo(alias="gemini_2.5_flash", default=None) - """Usage data for the gemini_2.5_flash model.""" - - gen3a_turbo: Optional[UsageModelsGen3aTurbo] = None - """Usage data for the gen3a_turbo model.""" - - gen4_aleph: Optional[UsageModelsGen4Aleph] = None - """Usage data for the gen4_aleph model.""" - - gen4_image: Optional[UsageModelsGen4Image] = None - """Usage data for the gen4_image model.""" - - gen4_image_turbo: Optional[UsageModelsGen4ImageTurbo] = None - """Usage data for the gen4_image_turbo model.""" - - gen4_turbo: Optional[UsageModelsGen4Turbo] = None - """Usage data for the gen4_turbo model.""" - - upscale_v1: Optional[UsageModelsUpscaleV1] = None - """Usage data for the upscale_v1 model.""" - - veo3: Optional[UsageModelsVeo3] = None - """Usage data for the veo3 model.""" - - veo3_1: Optional[UsageModelsVeo3_1] = FieldInfo(alias="veo3.1", default=None) - """Usage data for the veo3.1 model.""" - - veo3_1_fast: Optional[UsageModelsVeo3_1Fast] = FieldInfo(alias="veo3.1_fast", default=None) - """Usage data for the veo3.1_fast model.""" - - class Usage(BaseModel): - models: UsageModels - """Usage data for each model.""" + models: Dict[str, UsageModels] class OrganizationRetrieveResponse(BaseModel): diff --git a/src/runwayml/types/organization_retrieve_usage_response.py b/src/runwayml/types/organization_retrieve_usage_response.py index ad90712..bce820c 100644 --- a/src/runwayml/types/organization_retrieve_usage_response.py +++ b/src/runwayml/types/organization_retrieve_usage_response.py @@ -13,27 +13,27 @@ class ResultUsedCredit(BaseModel): amount: int - """The number of credits used for the model.""" + """The number of credits spent on the model.""" model: Literal[ - "act_two", - "eleven_multilingual_sts_v2", - "eleven_multilingual_v2", - "eleven_text_to_sound_v2", - "eleven_voice_dubbing", - "eleven_voice_isolation", - "gemini_2.5_flash", "gen3a_turbo", - "gen4_aleph", + "gen4_turbo", "gen4_image", "gen4_image_turbo", - "gen4_turbo", "upscale_v1", + "act_two", + "gen4_aleph", "veo3", "veo3.1", "veo3.1_fast", + "gemini_2.5_flash", + "eleven_multilingual_v2", + "eleven_text_to_sound_v2", + "eleven_voice_isolation", + "eleven_voice_dubbing", + "eleven_multilingual_sts_v2", ] - """The model whose usage resulted in the credit usage.""" + """The model that credits were spent on.""" class Result(BaseModel): @@ -50,22 +50,22 @@ class Result(BaseModel): class OrganizationRetrieveUsageResponse(BaseModel): models: List[ Literal[ - "act_two", - "eleven_multilingual_sts_v2", - "eleven_multilingual_v2", - "eleven_text_to_sound_v2", - "eleven_voice_dubbing", - "eleven_voice_isolation", - "gemini_2.5_flash", "gen3a_turbo", - "gen4_aleph", + "gen4_turbo", "gen4_image", "gen4_image_turbo", - "gen4_turbo", "upscale_v1", + "act_two", + "gen4_aleph", "veo3", "veo3.1", "veo3.1_fast", + "gemini_2.5_flash", + "eleven_multilingual_v2", + "eleven_text_to_sound_v2", + "eleven_voice_isolation", + "eleven_voice_dubbing", + "eleven_multilingual_sts_v2", ] ] """The list of models with usage during the queried time range.""" diff --git a/src/runwayml/types/sound_effect_create_response.py b/src/runwayml/types/sound_effect_create_response.py index 604a06d..0dc690b 100644 --- a/src/runwayml/types/sound_effect_create_response.py +++ b/src/runwayml/types/sound_effect_create_response.py @@ -7,3 +7,4 @@ class SoundEffectCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/speech_to_speech_create_response.py b/src/runwayml/types/speech_to_speech_create_response.py index 03a93b3..f682d47 100644 --- a/src/runwayml/types/speech_to_speech_create_response.py +++ b/src/runwayml/types/speech_to_speech_create_response.py @@ -7,3 +7,4 @@ class SpeechToSpeechCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/task_retrieve_response.py b/src/runwayml/types/task_retrieve_response.py index 47b9601..9284246 100644 --- a/src/runwayml/types/task_retrieve_response.py +++ b/src/runwayml/types/task_retrieve_response.py @@ -1,59 +1,99 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import List, Union, Optional from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, Annotated, TypeAlias from pydantic import Field as FieldInfo +from .._utils import PropertyInfo from .._models import BaseModel -__all__ = ["TaskRetrieveResponse"] +__all__ = ["TaskRetrieveResponse", "Pending", "Throttled", "Cancelled", "Running", "Failed", "Succeeded"] -class TaskRetrieveResponse(BaseModel): +class Pending(BaseModel): id: str """The ID of the task being returned.""" created_at: datetime = FieldInfo(alias="createdAt") """The timestamp that the task was submitted at.""" - status: Literal["RUNNING", "SUCCEEDED", "FAILED", "PENDING", "CANCELLED", "THROTTLED"] - """ - - `PENDING` tasks have been enqueued and are waiting to run. - - `THROTTLED` tasks are waiting to be enqueued until other jobs have finished - running. - - `RUNNING` tasks are currently being processed. - - `SUCCEEDED` tasks have completed successfully. - - `FAILED` tasks have failed. - - `CANCELLED` tasks have been aborted. - """ + status: Literal["PENDING"] - failure: Optional[str] = None - """ - If the status is `FAILED`, this will contain a human-friendly reason for the - failure. + +class Throttled(BaseModel): + id: str + """The ID of the task being returned.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """The timestamp that the task was submitted at.""" + + status: Literal["THROTTLED"] + + +class Cancelled(BaseModel): + id: str + """The ID of the task being returned.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """The timestamp that the task was submitted at.""" + + status: Literal["CANCELLED"] + + +class Running(BaseModel): + id: str + """The ID of the task being returned.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """The timestamp that the task was submitted at.""" + + progress: float + + status: Literal["RUNNING"] + + +class Failed(BaseModel): + id: str + """The ID of the task being returned.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """The timestamp that the task was submitted at.""" + + failure: str + """A human-friendly reason for the failure. + + We do not recommend returning this to users directly without adding context. """ + status: Literal["FAILED"] + failure_code: Optional[str] = FieldInfo(alias="failureCode", default=None) - """ - If the task has a status of `FAILED`, this contains a machine-readable error - code. This is a dot-separated string, with the leftmost segment being the most - generic and the rightmost segment being the most specific. For example, - `SAFETY.INPUT.TEXT` would indicate that the task failed due to a content - moderation error on the input text. + """A machine-readable error code for the failure. + + See https://docs.dev.runwayml.com/errors/task-failures/ for more information. """ - output: Optional[List[str]] = None - """If the status is `SUCCEEDED`, this will contain an array of strings. - Each string will be a URL that returns an output from the task. URLs expire - within 24-48 hours; fetch the task again to get fresh URLs. It is expected that - you download the assets at these URLs and store them in your own storage system. - """ +class Succeeded(BaseModel): + id: str + """The ID of the task being returned.""" - progress: Optional[float] = None - """ - If the task has a status of `RUNNING`, this will contain a floating point number - between 0 and 1 representing the progress of the generation. + created_at: datetime = FieldInfo(alias="createdAt") + """The timestamp that the task was submitted at.""" + + output: List[str] + """An array of URLs that return the output of the task. + + These URLs will expire within 24-48 hours; fetch the task again to get fresh + URLs. It is expected that you download the assets at these URLs and store them + in your own storage system. """ + + status: Literal["SUCCEEDED"] + + +TaskRetrieveResponse: TypeAlias = Annotated[ + Union[Pending, Throttled, Cancelled, Running, Failed, Succeeded], PropertyInfo(discriminator="status") +] diff --git a/src/runwayml/types/text_to_image_create_params.py b/src/runwayml/types/text_to_image_create_params.py index 164616c..8a1e6c6 100644 --- a/src/runwayml/types/text_to_image_create_params.py +++ b/src/runwayml/types/text_to_image_create_params.py @@ -74,6 +74,10 @@ class Gen4ImageTurboReferenceImage(TypedDict, total=False): """A HTTPS URL.""" tag: str + """A tag to identify the reference image. + + This is used to reference the image in prompt text. + """ class Gen4ImageTurboContentModeration(TypedDict, total=False): @@ -146,6 +150,10 @@ class Gen4ImageReferenceImage(TypedDict, total=False): """A HTTPS URL.""" tag: str + """A tag to identify the reference image. + + This is used to reference the image in prompt text. + """ class Gemini2_5Flash(TypedDict, total=False): @@ -185,6 +193,10 @@ class Gemini2_5FlashReferenceImage(TypedDict, total=False): """A HTTPS URL.""" tag: str + """A tag to identify the reference image. + + This is used to reference the image in prompt text. + """ TextToImageCreateParams: TypeAlias = Union[Gen4ImageTurbo, Gen4Image, Gemini2_5Flash] diff --git a/src/runwayml/types/text_to_image_create_response.py b/src/runwayml/types/text_to_image_create_response.py index 79f659e..353b565 100644 --- a/src/runwayml/types/text_to_image_create_response.py +++ b/src/runwayml/types/text_to_image_create_response.py @@ -7,3 +7,4 @@ class TextToImageCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/text_to_speech_create_response.py b/src/runwayml/types/text_to_speech_create_response.py index f7d45a6..3a97053 100644 --- a/src/runwayml/types/text_to_speech_create_response.py +++ b/src/runwayml/types/text_to_speech_create_response.py @@ -7,3 +7,4 @@ class TextToSpeechCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/text_to_video_create_response.py b/src/runwayml/types/text_to_video_create_response.py index d0c8bdf..61b1718 100644 --- a/src/runwayml/types/text_to_video_create_response.py +++ b/src/runwayml/types/text_to_video_create_response.py @@ -7,3 +7,4 @@ class TextToVideoCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/video_to_video_create_response.py b/src/runwayml/types/video_to_video_create_response.py index 6ab01a7..ad85b7b 100644 --- a/src/runwayml/types/video_to_video_create_response.py +++ b/src/runwayml/types/video_to_video_create_response.py @@ -7,3 +7,4 @@ class VideoToVideoCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/video_upscale_create_response.py b/src/runwayml/types/video_upscale_create_response.py index 73a0bd1..0cf0a9e 100644 --- a/src/runwayml/types/video_upscale_create_response.py +++ b/src/runwayml/types/video_upscale_create_response.py @@ -7,3 +7,4 @@ class VideoUpscaleCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/voice_dubbing_create_response.py b/src/runwayml/types/voice_dubbing_create_response.py index 3f105d6..1c8c4e5 100644 --- a/src/runwayml/types/voice_dubbing_create_response.py +++ b/src/runwayml/types/voice_dubbing_create_response.py @@ -7,3 +7,4 @@ class VoiceDubbingCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/src/runwayml/types/voice_isolation_create_response.py b/src/runwayml/types/voice_isolation_create_response.py index e1eed57..ff24226 100644 --- a/src/runwayml/types/voice_isolation_create_response.py +++ b/src/runwayml/types/voice_isolation_create_response.py @@ -7,3 +7,4 @@ class VoiceIsolationCreateResponse(BaseModel): id: str + """The ID of the task that was created. Use this to retrieve the task later.""" diff --git a/tests/api_resources/test_voice_dubbing.py b/tests/api_resources/test_voice_dubbing.py index ac23d9f..aab73a9 100644 --- a/tests/api_resources/test_voice_dubbing.py +++ b/tests/api_resources/test_voice_dubbing.py @@ -34,7 +34,7 @@ def test_method_create_with_all_params(self, client: RunwayML) -> None: target_lang="en", disable_voice_cloning=True, drop_background_audio=True, - num_speakers=9007199254740991, + num_speakers=1, ) assert_matches_type(VoiceDubbingCreateResponse, voice_dubbing, path=["response"]) @@ -89,7 +89,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) target_lang="en", disable_voice_cloning=True, drop_background_audio=True, - num_speakers=9007199254740991, + num_speakers=1, ) assert_matches_type(VoiceDubbingCreateResponse, voice_dubbing, path=["response"])