diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25d3171..ef043ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: lint: timeout-minutes: 10 name: lint - runs-on: ${{ github.repository == 'stainless-sdks/runwayml-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -37,7 +37,7 @@ jobs: build: timeout-minutes: 5 name: build - runs-on: ${{ github.repository == 'stainless-sdks/runwayml-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') permissions: contents: read @@ -77,7 +77,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ${{ github.repository == 'stainless-sdks/runwayml-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7a2c622..58acdf5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.10.0" + ".": "4.11.0" } diff --git a/.stats.yml b/.stats.yml index 8c6b27f..1f5c262 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 51 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml/runwayml-391d899ffd246491c8d2a02adec62eb5fc1b00044e6704a7886d8e8e09d72484.yml -openapi_spec_hash: 475451c27bcc5721a02ee92c1898000e -config_hash: 7caf94f26186e1ee432efcaa0b590bab +configured_endpoints: 57 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml/runwayml-33021d52306cc82f369d7ad1d391bc94fd5a377d4a92be35ece073b73f64a454.yml +openapi_spec_hash: d70a1ddd98e8aff8e1d298ff9c21b343 +config_hash: 6bdea3c3109ee75952f779d566c229ea diff --git a/CHANGELOG.md b/CHANGELOG.md index 704e545..46a8f46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 4.11.0 (2026-07-21) + +Full Changelog: [v4.10.0...v4.11.0](https://github.com/runwayml/sdk-node/compare/v4.10.0...v4.11.0) + +### Features + +* **api:** add Model Router CRUD and routed video generation ([48477a0](https://github.com/runwayml/sdk-node/commit/48477a0707fe103d36df277fd387bb446b2b2961)) +* **stlc:** configurable CI runner and private-production-repo support in workflow templates ([7d32a50](https://github.com/runwayml/sdk-node/commit/7d32a50f43bd87fd47b0a4cf019f79ee0892f94a)) + + +### Bug Fixes + +* **client:** make generate.video responses awaitable ([73d3025](https://github.com/runwayml/sdk-node/commit/73d30259966bf4ab280f273d3a232c878bb7c15f)) + ## 4.10.0 (2026-07-13) Full Changelog: [v4.9.1...v4.10.0](https://github.com/runwayml/sdk-node/compare/v4.9.1...v4.10.0) diff --git a/MIGRATION.md b/MIGRATION.md index 8378726..dff845b 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -53,6 +53,7 @@ client.example.list(undefined, { headers: { ... } }); This affects the following methods: +- `client.routers.update()` - `client.organization.retrieveUsage()` - `client.avatars.update()` - `client.documents.update()` @@ -161,8 +162,8 @@ The `for await` syntax **is not affected**. This still works as-is: ```ts // Automatically fetches more pages as needed. -for await (const avatarListResponse of client.avatars.list({ limit: 1 })) { - console.log(avatarListResponse); +for await (const routerListResponse of client.routers.list({ limit: 1 })) { + console.log(routerListResponse); } ``` @@ -184,10 +185,10 @@ Page classes for individual methods are now type aliases: ```ts // Before -export class AvatarListResponsesCursorPage extends CursorPage {} +export class RouterListResponsesCursorPage extends CursorPage {} // After -export type AvatarListResponsesCursorPage = CursorPage; +export type RouterListResponsesCursorPage = CursorPage; ``` If you were importing these classes at runtime, you'll need to switch to importing the base class or only import them at the type-level. diff --git a/README.md b/README.md index bfaff95..6e11a66 100644 --- a/README.md +++ b/README.md @@ -156,22 +156,22 @@ List methods in the RunwayML API are paginated. You can use the `for await … of` syntax to iterate through items across all pages: ```ts -async function fetchAllAvatarListResponses(params) { - const allAvatarListResponses = []; +async function fetchAllRouterListResponses(params) { + const allRouterListResponses = []; // Automatically fetches more pages as needed. - for await (const avatarListResponse of client.avatars.list({ limit: 1 })) { - allAvatarListResponses.push(avatarListResponse); + for await (const routerListResponse of client.routers.list({ limit: 1 })) { + allRouterListResponses.push(routerListResponse); } - return allAvatarListResponses; + return allRouterListResponses; } ``` Alternatively, you can request a single page at a time: ```ts -let page = await client.avatars.list({ limit: 1 }); -for (const avatarListResponse of page.data) { - console.log(avatarListResponse); +let page = await client.routers.list({ limit: 1 }); +for (const routerListResponse of page.data) { + console.log(routerListResponse); } // Convenience methods are provided for manually paginating: diff --git a/api.md b/api.md index 08738e9..129ee27 100644 --- a/api.md +++ b/api.md @@ -129,6 +129,35 @@ Methods: - client.videoUpscale.create({ ...params }) -> VideoUpscaleCreateResponse +# Generate + +## Video + +Types: + +- VideoCreateResponse + +Methods: + +- client.generate.video.create({ ...params }) -> VideoCreateResponse + +# Routers + +Types: + +- RouterCreateResponse +- RouterRetrieveResponse +- RouterUpdateResponse +- RouterListResponse + +Methods: + +- client.routers.create({ ...params }) -> RouterCreateResponse +- client.routers.retrieve(id) -> RouterRetrieveResponse +- client.routers.update(id, { ...params }) -> RouterUpdateResponse +- client.routers.list({ ...params }) -> RouterListResponsesCursorPage +- client.routers.delete(id) -> void + # Organization Types: diff --git a/package.json b/package.json index 1e69367..24a8970 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@runwayml/sdk", - "version": "4.10.0", + "version": "4.11.0", "description": "The official TypeScript library for the RunwayML API", "author": "RunwayML ", "types": "dist/index.d.ts", diff --git a/src/client.ts b/src/client.ts index 1c722ef..4d719ea 100644 --- a/src/client.ts +++ b/src/client.ts @@ -94,6 +94,17 @@ import { RecipeProductUgcResponse, Recipes, } from './resources/recipes'; +import { + RouterCreateParams, + RouterCreateResponse, + RouterListParams, + RouterListResponse, + RouterListResponsesCursorPage, + RouterRetrieveResponse, + RouterUpdateParams, + RouterUpdateResponse, + Routers, +} from './resources/routers'; import { SoundEffect, SoundEffectCreateParams, SoundEffectCreateResponse } from './resources/sound-effect'; import { SpeechToSpeech, @@ -150,6 +161,7 @@ import { WorkflowRunResponse, Workflows, } from './resources/workflows'; +import { Generate } from './resources/generate/generate'; import { type Fetch } from './internal/builtin-types'; import { isRunningInBrowser } from './internal/detect-platform'; import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; @@ -962,6 +974,8 @@ export class RunwayML { * These endpoints all kick off tasks to create generations. */ videoUpscale: API.VideoUpscale = new API.VideoUpscale(this); + generate: API.Generate = new API.Generate(this); + routers: API.Routers = new API.Routers(this); organization: API.Organization = new API.Organization(this); avatars: API.Avatars = new API.Avatars(this); avatarConversations: API.AvatarConversations = new API.AvatarConversations(this); @@ -988,6 +1002,8 @@ RunwayML.VoiceDubbing = VoiceDubbing; RunwayML.SpeechToSpeech = SpeechToSpeech; RunwayML.ImageUpscale = ImageUpscale; RunwayML.VideoUpscale = VideoUpscale; +RunwayML.Generate = Generate; +RunwayML.Routers = Routers; RunwayML.Organization = Organization; RunwayML.Avatars = Avatars; RunwayML.AvatarConversations = AvatarConversations; @@ -1080,6 +1096,20 @@ export declare namespace RunwayML { type VideoUpscaleCreateParams as VideoUpscaleCreateParams, }; + export { Generate as Generate }; + + export { + Routers as Routers, + type RouterCreateResponse as RouterCreateResponse, + type RouterRetrieveResponse as RouterRetrieveResponse, + type RouterUpdateResponse as RouterUpdateResponse, + type RouterListResponse as RouterListResponse, + type RouterListResponsesCursorPage as RouterListResponsesCursorPage, + type RouterCreateParams as RouterCreateParams, + type RouterUpdateParams as RouterUpdateParams, + type RouterListParams as RouterListParams, + }; + export { Organization as Organization, type OrganizationRetrieveResponse as OrganizationRetrieveResponse, diff --git a/src/resources/generate.ts b/src/resources/generate.ts new file mode 100644 index 0000000..77825f8 --- /dev/null +++ b/src/resources/generate.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './generate/index'; diff --git a/src/resources/generate/generate.ts b/src/resources/generate/generate.ts new file mode 100644 index 0000000..2d7d265 --- /dev/null +++ b/src/resources/generate/generate.ts @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as VideoAPI from './video'; +import { Video, VideoCreateParams, VideoCreateResponse } from './video'; + +export class Generate extends APIResource { + video: VideoAPI.Video = new VideoAPI.Video(this._client); +} + +Generate.Video = Video; + +export declare namespace Generate { + export { + Video as Video, + type VideoCreateResponse as VideoCreateResponse, + type VideoCreateParams as VideoCreateParams, + }; +} diff --git a/src/resources/generate/index.ts b/src/resources/generate/index.ts new file mode 100644 index 0000000..379bec1 --- /dev/null +++ b/src/resources/generate/index.ts @@ -0,0 +1,4 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { Generate } from './generate'; +export { Video, type VideoCreateResponse, type VideoCreateParams } from './video'; diff --git a/src/resources/generate/video.ts b/src/resources/generate/video.ts new file mode 100644 index 0000000..a8f954a --- /dev/null +++ b/src/resources/generate/video.ts @@ -0,0 +1,300 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import { RequestOptions } from '../../internal/request-options'; +import { APIPromiseWithAwaitableTask, wrapAsWaitableResource } from '../../lib/polling'; + +export class Video extends APIResource { + /** + * Start a video generation task using a saved Model Router config instead of + * naming a model. + */ + create( + body: VideoCreateParams, + options?: RequestOptions, + ): APIPromiseWithAwaitableTask { + return wrapAsWaitableResource(this._client)( + this._client.post('/v1/generate/video', { body, ...options }), + ); + } +} + +export interface VideoCreateResponse { + /** + * The ID of the created task. Poll GET /v1/tasks/:id for the result. + */ + id: string; + + /** + * Metadata describing which model the router selected and why. + */ + routing: VideoCreateResponse.Routing; +} + +export namespace VideoCreateResponse { + /** + * Metadata describing which model the router selected and why. + */ + export interface Routing { + /** + * The slug of the router config that was applied to this request. + */ + configId: string; + + /** + * Estimated cost, computed against current pricing. + */ + estimatedCost: Routing.EstimatedCost; + + /** + * The public name of the model the router selected. + */ + model: string; + + /** + * The provider of the selected model. + */ + provider: string; + + /** + * Request-side defaults resolved for the routing response. Not necessarily + * identical to prepared model options. + */ + resolvedInput: Routing.ResolvedInput; + + /** + * The resolved config settings the router used for this request. + */ + resolvedSettings: Routing.ResolvedSettings; + } + + export namespace Routing { + /** + * Estimated cost, computed against current pricing. + */ + export interface EstimatedCost { + /** + * Estimated cost of the generation in credits. + */ + credits: number; + } + + /** + * Request-side defaults resolved for the routing response. Not necessarily + * identical to prepared model options. + */ + export interface ResolvedInput { + /** + * Duration in seconds used for routing display (request value or router default). + */ + duration: number; + + /** + * Concrete output ratio derived from aspectRatio (e.g. "1280:720"), or the router + * default. + */ + ratio: string; + + /** + * Resolution tier from the request, or the router default when omitted. + */ + resolution: string; + } + + /** + * The resolved config settings the router used for this request. + */ + export interface ResolvedSettings { + /** + * The single optimization preference the config selected, used as the soft + * weighting when scoring eligible models. + */ + optimizeFor: 'cost' | 'latency' | 'quality'; + + /** + * The applied maximum credits per generation for this request’s modality, or null + * if the config sets no ceiling. + */ + priceCeiling: number | null; + } + } +} + +export interface VideoCreateParams { + /** + * The slug of a saved Model Router config to route this request with. + */ + configId: string; + + /** + * Model-agnostic video generation input. Fields are optional; the router selects a + * model and maps these options to it. + */ + input: VideoCreateParams.Input; +} + +export namespace VideoCreateParams { + /** + * Model-agnostic video generation input. Fields are optional; the router selects a + * model and maps these options to it. + */ + export interface Input { + /** + * Desired aspect ratio. Models that do not support the requested aspect are + * excluded. + */ + aspectRatio?: '16:9' | '9:16' | '1:1' | '4:3' | '3:4' | '21:9'; + + /** + * Whether to generate native audio with the video. When true, only models that + * output audio remain eligible; when false, silent models and models with an audio + * toggle remain eligible (always-on native-audio models are excluded). When + * omitted, the selected model’s default applies. + */ + audio?: boolean; + + /** + * Settings that affect the behavior of the content moderation system. + */ + contentModeration?: Input.ContentModeration; + + /** + * Desired duration of the output video, in seconds. Unsupported values exclude + * models; with a source video, V2V duration support applies. + */ + duration?: number; + + /** + * Timed guidance images for video restyle. Requires a source video; unsupported + * models are excluded. + */ + keyframes?: Array; + + /** + * A text description of what to avoid in the output. + */ + negativePrompt?: string; + + /** + * A text prompt describing the desired video. + */ + promptText?: string; + + /** + * Optional audio inputs for the generation. + */ + referenceAudio?: Array; + + /** + * Optional image inputs. Each entry requires a `role`. At most one `first` and one + * `last` are allowed; multiple `reference` images are allowed. + */ + referenceImages?: Array; + + /** + * Optional video inputs. Each entry requires a `role`. Use `source` for + * video-to-video; use `reference` for additional context videos (only models that + * support them remain eligible). At most one `source` is allowed. + */ + referenceVideos?: Array; + + /** + * Desired output resolution tier. Models that do not support the requested tier + * are excluded. + */ + resolution?: '480p' | '720p' | '1080p' | '4k'; + + /** + * A seed for reproducible generation. Random if omitted. + */ + seed?: number; + } + + export namespace Input { + /** + * Settings that affect the behavior of the content moderation system. + */ + export interface ContentModeration { + /** + * When set to `low`, the content moderation system will be less strict about + * preventing generations that include recognizable public figures. + */ + publicFigureThreshold?: 'auto' | 'low'; + } + + export interface UnionMember0 { + seconds: number; + + /** + * A HTTPS URL. + */ + uri: string; + + range?: UnionMember0.Range; + } + + export namespace UnionMember0 { + export interface Range { + end_seconds: number; + + start_seconds: number; + } + } + + export interface UnionMember1 { + at: number; + + /** + * A HTTPS URL. + */ + uri: string; + + range?: UnionMember1.Range; + } + + export namespace UnionMember1 { + export interface Range { + end_seconds: number; + + start_seconds: number; + } + } + + export interface ReferenceAudio { + /** + * A HTTPS URL. + */ + uri: string; + } + + export interface ReferenceImage { + /** + * How the image is used. `first` is the starting frame; `last` is an end frame; + * `reference` is additional image context. + */ + role: 'first' | 'last' | 'reference'; + + /** + * A HTTPS URL. + */ + uri: string; + } + + export interface ReferenceVideo { + /** + * How the video is used. `source` is the primary video-to-video input; `reference` + * is additional video context. + */ + role: 'source' | 'reference'; + + /** + * A HTTPS URL. + */ + uri: string; + } + } +} + +export declare namespace Video { + export { type VideoCreateResponse as VideoCreateResponse, type VideoCreateParams as VideoCreateParams }; +} diff --git a/src/resources/index.ts b/src/resources/index.ts index c450fce..84d674a 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -36,6 +36,7 @@ export { type DocumentListParams, type DocumentListResponsesCursorPage, } from './documents'; +export { Generate } from './generate/generate'; export { ImageToVideo, type ImageToVideoCreateResponse, @@ -75,6 +76,17 @@ export { type RecipeProductSwapParams, type RecipeProductUgcParams, } from './recipes'; +export { + Routers, + type RouterCreateResponse, + type RouterRetrieveResponse, + type RouterUpdateResponse, + type RouterListResponse, + type RouterCreateParams, + type RouterUpdateParams, + type RouterListParams, + type RouterListResponsesCursorPage, +} from './routers'; export { SoundEffect, type SoundEffectCreateResponse, type SoundEffectCreateParams } from './sound-effect'; export { SpeechToSpeech, diff --git a/src/resources/organization.ts b/src/resources/organization.ts index 08e9803..3a75126 100644 --- a/src/resources/organization.ts +++ b/src/resources/organization.ts @@ -116,6 +116,7 @@ export interface OrganizationRetrieveUsageResponse { | 'gemini_image3_pro' | 'gemini_image3.1_flash' | 'seedream5_pro' + | 'seedream5_lite' | 'gemini_omni_flash' | 'eleven_multilingual_v2' | 'seed_audio' @@ -153,6 +154,16 @@ export interface OrganizationRetrieveUsageResponse { >; results: Array; + + /** + * Reserved for future use. + */ + apiKeys?: Array; + + /** + * Reserved for future use. + */ + resultsByApiKey?: Array; } export namespace OrganizationRetrieveUsageResponse { @@ -196,6 +207,7 @@ export namespace OrganizationRetrieveUsageResponse { | 'gemini_image3_pro' | 'gemini_image3.1_flash' | 'seedream5_pro' + | 'seedream5_lite' | 'gemini_omni_flash' | 'eleven_multilingual_v2' | 'seed_audio' @@ -232,6 +244,20 @@ export namespace OrganizationRetrieveUsageResponse { | 'ad_localization'; } } + + export interface ResultsByAPIKey { + date: string; + + usedCredits: Array; + } + + export namespace ResultsByAPIKey { + export interface UsedCredit { + amount: number; + + apiKeyId: string; + } + } } export interface OrganizationRetrieveUsageParams { diff --git a/src/resources/routers.ts b/src/resources/routers.ts new file mode 100644 index 0000000..65d0389 --- /dev/null +++ b/src/resources/routers.ts @@ -0,0 +1,622 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../core/pagination'; +import { buildHeaders } from '../internal/headers'; +import { RequestOptions } from '../internal/request-options'; +import { path } from '../internal/utils/path'; + +export class Routers extends APIResource { + /** + * Create a Model Router configuration. + */ + create(body: RouterCreateParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/routers', { body, ...options }); + } + + /** + * Retrieve a Model Router configuration by ID. + */ + retrieve(id: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/routers/${id}`, options); + } + + /** + * Update a Model Router configuration. Settings changes append a new version; name + * and description updates do not. Settings are merged with the current snapshot — + * omitted fields keep their existing values. + */ + update( + id: string, + body: RouterUpdateParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.patch(path`/v1/routers/${id}`, { body, ...options }); + } + + /** + * List Model Router configurations for the authenticated organization with + * cursor-based pagination. + */ + list( + query: RouterListParams, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/v1/routers', CursorPage, { query, ...options }); + } + + /** + * Delete a Model Router configuration. Deleted Model Routers cannot be used for + * generation. + */ + delete(id: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/v1/routers/${id}`, { + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + }); + } +} + +export type RouterListResponsesCursorPage = CursorPage; + +export interface RouterCreateResponse { + /** + * The Model Router's primary key ID (UUID). Use it to manage this router via the + * API; use the slug to reference the router in generation requests. + */ + id: string; + + /** + * When the Model Router was created. + */ + createdAt: string; + + /** + * An optional Model Router description. + */ + description: string | null; + + /** + * Human-friendly Model Router display name shown in the dev portal. Mutable, and + * not used to reference the router in requests. + */ + name: string; + + settings: RouterCreateResponse.Settings; + + /** + * Immutable slug used to reference this Model Router in generation requests (for + * example, production-video). Unique within the API project. The UUID id remains + * the canonical management identifier. + */ + slug: string; + + /** + * When the Model Router was last updated. + */ + updatedAt: string; + + /** + * Current settings version. Increments when settings change; name and description + * updates do not create a new version. + */ + version: number; +} + +export namespace RouterCreateResponse { + export interface Settings { + /** + * Settings JSON schema version used when this snapshot was written. + */ + schemaVersion: 1; + + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + maxCreditsPerGeneration?: Settings.MaxCreditsPerGeneration; + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + models?: Settings.Models; + + /** + * Soft preference among eligible models: cost, latency, or quality. + */ + optimizeFor?: 'cost' | 'latency' | 'quality'; + } + + export namespace Settings { + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + export interface MaxCreditsPerGeneration { + audio?: number; + + image?: number; + + video?: number; + } + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + export interface Models { + ids: Array; + + mode: 'allow_new_except' | 'allowlist_only'; + } + } +} + +export interface RouterRetrieveResponse { + /** + * The Model Router's primary key ID (UUID). Use it to manage this router via the + * API; use the slug to reference the router in generation requests. + */ + id: string; + + /** + * When the Model Router was created. + */ + createdAt: string; + + /** + * An optional Model Router description. + */ + description: string | null; + + /** + * Human-friendly Model Router display name shown in the dev portal. Mutable, and + * not used to reference the router in requests. + */ + name: string; + + settings: RouterRetrieveResponse.Settings; + + /** + * Immutable slug used to reference this Model Router in generation requests (for + * example, production-video). Unique within the API project. The UUID id remains + * the canonical management identifier. + */ + slug: string; + + /** + * When the Model Router was last updated. + */ + updatedAt: string; + + /** + * Current settings version. Increments when settings change; name and description + * updates do not create a new version. + */ + version: number; +} + +export namespace RouterRetrieveResponse { + export interface Settings { + /** + * Settings JSON schema version used when this snapshot was written. + */ + schemaVersion: 1; + + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + maxCreditsPerGeneration?: Settings.MaxCreditsPerGeneration; + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + models?: Settings.Models; + + /** + * Soft preference among eligible models: cost, latency, or quality. + */ + optimizeFor?: 'cost' | 'latency' | 'quality'; + } + + export namespace Settings { + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + export interface MaxCreditsPerGeneration { + audio?: number; + + image?: number; + + video?: number; + } + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + export interface Models { + ids: Array; + + mode: 'allow_new_except' | 'allowlist_only'; + } + } +} + +export interface RouterUpdateResponse { + /** + * The Model Router's primary key ID (UUID). Use it to manage this router via the + * API; use the slug to reference the router in generation requests. + */ + id: string; + + /** + * When the Model Router was created. + */ + createdAt: string; + + /** + * An optional Model Router description. + */ + description: string | null; + + /** + * Human-friendly Model Router display name shown in the dev portal. Mutable, and + * not used to reference the router in requests. + */ + name: string; + + settings: RouterUpdateResponse.Settings; + + /** + * Immutable slug used to reference this Model Router in generation requests (for + * example, production-video). Unique within the API project. The UUID id remains + * the canonical management identifier. + */ + slug: string; + + /** + * When the Model Router was last updated. + */ + updatedAt: string; + + /** + * Current settings version. Increments when settings change; name and description + * updates do not create a new version. + */ + version: number; +} + +export namespace RouterUpdateResponse { + export interface Settings { + /** + * Settings JSON schema version used when this snapshot was written. + */ + schemaVersion: 1; + + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + maxCreditsPerGeneration?: Settings.MaxCreditsPerGeneration; + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + models?: Settings.Models; + + /** + * Soft preference among eligible models: cost, latency, or quality. + */ + optimizeFor?: 'cost' | 'latency' | 'quality'; + } + + export namespace Settings { + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + export interface MaxCreditsPerGeneration { + audio?: number; + + image?: number; + + video?: number; + } + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + export interface Models { + ids: Array; + + mode: 'allow_new_except' | 'allowlist_only'; + } + } +} + +/** + * A named Model Router configuration. + */ +export interface RouterListResponse { + /** + * The Model Router's primary key ID (UUID). Use it to manage this router via the + * API; use the slug to reference the router in generation requests. + */ + id: string; + + /** + * When the Model Router was created. + */ + createdAt: string; + + /** + * An optional Model Router description. + */ + description: string | null; + + /** + * Human-friendly Model Router display name shown in the dev portal. Mutable, and + * not used to reference the router in requests. + */ + name: string; + + settings: RouterListResponse.Settings; + + /** + * Immutable slug used to reference this Model Router in generation requests (for + * example, production-video). Unique within the API project. The UUID id remains + * the canonical management identifier. + */ + slug: string; + + /** + * When the Model Router was last updated. + */ + updatedAt: string; + + /** + * Current settings version. Increments when settings change; name and description + * updates do not create a new version. + */ + version: number; +} + +export namespace RouterListResponse { + export interface Settings { + /** + * Settings JSON schema version used when this snapshot was written. + */ + schemaVersion: 1; + + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + maxCreditsPerGeneration?: Settings.MaxCreditsPerGeneration; + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + models?: Settings.Models; + + /** + * Soft preference among eligible models: cost, latency, or quality. + */ + optimizeFor?: 'cost' | 'latency' | 'quality'; + } + + export namespace Settings { + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + export interface MaxCreditsPerGeneration { + audio?: number; + + image?: number; + + video?: number; + } + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + export interface Models { + ids: Array; + + mode: 'allow_new_except' | 'allowlist_only'; + } + } +} + +export interface RouterCreateParams { + /** + * Immutable slug used to reference this Model Router in generation requests (for + * example, production-video). Unique within the API project. The UUID id remains + * the canonical management identifier. + */ + slug: string; + + /** + * An optional Model Router description. + */ + description?: string; + + /** + * Optional human-readable display name for this router. Defaults to the slug when + * omitted. + */ + name?: string; + + /** + * Model Router routing preferences. Defaults to cost-optimized allow-all when + * omitted. Modality is implied by the generate endpoint used with this Model + * Router. + */ + settings?: RouterCreateParams.Settings; +} + +export namespace RouterCreateParams { + /** + * Model Router routing preferences. Defaults to cost-optimized allow-all when + * omitted. Modality is implied by the generate endpoint used with this Model + * Router. + */ + export interface Settings { + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + maxCreditsPerGeneration?: Settings.MaxCreditsPerGeneration; + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + models?: Settings.Models; + + /** + * Soft preference among eligible models: cost, latency, or quality. + */ + optimizeFor?: 'cost' | 'latency' | 'quality'; + + /** + * Settings JSON schema version. Omit on write to use the current version; + * responses and stored snapshots always include it. + */ + schemaVersion?: 1; + } + + export namespace Settings { + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + export interface MaxCreditsPerGeneration { + audio?: number; + + image?: number; + + video?: number; + } + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + export interface Models { + ids: Array; + + mode: 'allow_new_except' | 'allowlist_only'; + } + } +} + +export interface RouterUpdateParams { + description?: string | null; + + /** + * Display name. The slug is immutable and cannot be changed after creation. + */ + name?: string; + + /** + * Nested merge: omitted settings fields keep their current values. When models is + * present, omitted models.mode or models.ids are preserved (sending only + * optimizeFor does not clear the model allowlist or credit ceiling). + */ + settings?: RouterUpdateParams.Settings; +} + +export namespace RouterUpdateParams { + /** + * Nested merge: omitted settings fields keep their current values. When models is + * present, omitted models.mode or models.ids are preserved (sending only + * optimizeFor does not clear the model allowlist or credit ceiling). + */ + export interface Settings { + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + maxCreditsPerGeneration?: Settings.MaxCreditsPerGeneration; + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + models?: Settings.Models; + + /** + * Soft preference among eligible models: cost, latency, or quality. + */ + optimizeFor?: 'cost' | 'latency' | 'quality'; + + /** + * Settings JSON schema version. Omit on write to use the current version; + * responses and stored snapshots always include it. + */ + schemaVersion?: 1; + } + + export namespace Settings { + /** + * Optional per-modality hard caps on credits for one generation. Models whose + * estimated cost for that modality exceeds the cap are excluded. + */ + export interface MaxCreditsPerGeneration { + audio?: number; + + image?: number; + + video?: number; + } + + /** + * When mode is allow_new_except, ids are excluded; when allowlist_only, ids are + * the only allowed values. Each id must be a known public video model name + * (unknown ids are rejected on create/update). + */ + export interface Models { + ids: Array; + + mode: 'allow_new_except' | 'allowlist_only'; + } + } +} + +export interface RouterListParams extends CursorPageParams {} + +export declare namespace Routers { + export { + type RouterCreateResponse as RouterCreateResponse, + type RouterRetrieveResponse as RouterRetrieveResponse, + type RouterUpdateResponse as RouterUpdateResponse, + type RouterListResponse as RouterListResponse, + type RouterListResponsesCursorPage as RouterListResponsesCursorPage, + type RouterCreateParams as RouterCreateParams, + type RouterUpdateParams as RouterUpdateParams, + type RouterListParams as RouterListParams, + }; +} diff --git a/src/resources/text-to-image.ts b/src/resources/text-to-image.ts index 650a785..208b49d 100644 --- a/src/resources/text-to-image.ts +++ b/src/resources/text-to-image.ts @@ -492,6 +492,12 @@ export declare namespace TextToImageCreateParams { | 'auto_1k' | 'auto_2k'; + /** + * When true, enable live web search so the model can use current brand, trend, or + * event context. Default false for deterministic output. + */ + grounding?: boolean; + /** * The number of images to generate. Increasing this number will affect the number * of credits consumed by the generation. diff --git a/src/version.ts b/src/version.ts index 37e598a..ac2d33f 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '4.10.0'; // x-release-please-version +export const VERSION = '4.11.0'; // x-release-please-version diff --git a/tests/api-resources/generate/video.test.ts b/tests/api-resources/generate/video.test.ts new file mode 100644 index 0000000..e46ea79 --- /dev/null +++ b/tests/api-resources/generate/video.test.ts @@ -0,0 +1,50 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import RunwayML from '@runwayml/sdk'; + +const client = new RunwayML({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource video', () => { + test('create: only required params', async () => { + const responsePromise = client.generate.video.create({ + configId: 'n6_', + input: {}, + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('create: required and optional params', async () => { + const response = await client.generate.video.create({ + configId: 'n6_', + input: { + aspectRatio: '16:9', + audio: true, + contentModeration: { publicFigureThreshold: 'auto' }, + duration: 2, + keyframes: [ + { + seconds: 0, + uri: 'https://example.com/file', + range: { end_seconds: 1, start_seconds: 0 }, + }, + ], + negativePrompt: 'negativePrompt', + promptText: 'x', + referenceAudio: [{ uri: 'https://example.com/file' }], + referenceImages: [{ role: 'first', uri: 'https://example.com/file' }], + referenceVideos: [{ role: 'source', uri: 'https://example.com/file' }], + resolution: '480p', + seed: 0, + }, + }); + }); +}); diff --git a/tests/api-resources/routers.test.ts b/tests/api-resources/routers.test.ts new file mode 100644 index 0000000..872f430 --- /dev/null +++ b/tests/api-resources/routers.test.ts @@ -0,0 +1,111 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import RunwayML from '@runwayml/sdk'; + +const client = new RunwayML({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource routers', () => { + test('create: only required params', async () => { + const responsePromise = client.routers.create({ slug: 'slug' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('create: required and optional params', async () => { + const response = await client.routers.create({ + slug: 'slug', + description: 'description', + name: 'x', + settings: { + maxCreditsPerGeneration: { + audio: 1, + image: 1, + video: 1, + }, + models: { ids: ['string'], mode: 'allow_new_except' }, + optimizeFor: 'cost', + schemaVersion: 1, + }, + }); + }); + + test('retrieve', async () => { + const responsePromise = client.routers.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('update', async () => { + const responsePromise = client.routers.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('update: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.routers.update( + '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + { + description: 'description', + name: 'x', + settings: { + maxCreditsPerGeneration: { + audio: 1, + image: 1, + video: 1, + }, + models: { ids: ['string'], mode: 'allow_new_except' }, + optimizeFor: 'cost', + schemaVersion: 1, + }, + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(RunwayML.NotFoundError); + }); + + test('list: only required params', async () => { + const responsePromise = client.routers.list({ limit: 1 }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('list: required and optional params', async () => { + const response = await client.routers.list({ limit: 1, cursor: 'x' }); + }); + + test('delete', async () => { + const responsePromise = client.routers.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +});