@fungi.computer/darkroom 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-media-contracts.d.ts +6 -2
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +1 -0
- package/dist/cloudflare/provider.js +32 -3
- package/dist/cost-estimate.js +3 -4
- package/dist/gateway-models.d.ts +10 -1
- package/dist/gateway-models.js +57 -8
- package/dist/index.d.ts +1 -3
- package/dist/index.js +29 -22
- package/dist/model-catalog.d.ts +18 -5
- package/dist/model-catalog.js +79 -11
- package/dist/video-providers/minimax.d.ts +1 -1
- package/dist/video-providers/minimax.js +3 -2
- package/docs/api/app-media-contracts.md +2 -1
- package/docs/api/browser.md +6 -0
- package/docs/api/index.md +81 -71
- package/package.json +2 -2
|
@@ -18,6 +18,7 @@ export declare const mediaModelsSchema: z.ZodLazy<z.ZodArray<z.ZodReadonly<z.Zod
|
|
|
18
18
|
readonly jpeg: "jpeg";
|
|
19
19
|
readonly webp: "webp";
|
|
20
20
|
}>>>;
|
|
21
|
+
maxPromptLength: z.ZodNumber;
|
|
21
22
|
input: z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
22
23
|
transport: z.ZodEnum<{
|
|
23
24
|
readonly json: "json";
|
|
@@ -28,6 +29,7 @@ export declare const mediaModelsSchema: z.ZodLazy<z.ZodArray<z.ZodReadonly<z.Zod
|
|
|
28
29
|
readonly own: "own";
|
|
29
30
|
}>;
|
|
30
31
|
maxDimension: z.ZodNullable<z.ZodNumber>;
|
|
32
|
+
maxDimensionDocumented: z.ZodBoolean;
|
|
31
33
|
defaultWidth: z.ZodNumber;
|
|
32
34
|
defaultHeight: z.ZodNumber;
|
|
33
35
|
steps: z.ZodEnum<{
|
|
@@ -87,8 +89,8 @@ export declare const mediaModelsSchema: z.ZodLazy<z.ZodArray<z.ZodReadonly<z.Zod
|
|
|
87
89
|
readonly ultrawide: "21:9";
|
|
88
90
|
readonly ultratall: "9:21";
|
|
89
91
|
}>;
|
|
92
|
+
supportsAudio: z.ZodBoolean;
|
|
90
93
|
defaultGenerateAudio: z.ZodNullable<z.ZodBoolean>;
|
|
91
|
-
maxPromptLength: z.ZodNumber;
|
|
92
94
|
referenceRoles: z.ZodReadonly<z.ZodArray<z.ZodEnum<{
|
|
93
95
|
readonly first: "first-frame";
|
|
94
96
|
readonly last: "last-frame";
|
|
@@ -302,6 +304,7 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodLazy
|
|
|
302
304
|
readonly jpeg: "jpeg";
|
|
303
305
|
readonly webp: "webp";
|
|
304
306
|
}>>>;
|
|
307
|
+
maxPromptLength: z.ZodNumber;
|
|
305
308
|
input: z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
306
309
|
transport: z.ZodEnum<{
|
|
307
310
|
readonly json: "json";
|
|
@@ -312,6 +315,7 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodLazy
|
|
|
312
315
|
readonly own: "own";
|
|
313
316
|
}>;
|
|
314
317
|
maxDimension: z.ZodNullable<z.ZodNumber>;
|
|
318
|
+
maxDimensionDocumented: z.ZodBoolean;
|
|
315
319
|
defaultWidth: z.ZodNumber;
|
|
316
320
|
defaultHeight: z.ZodNumber;
|
|
317
321
|
steps: z.ZodEnum<{
|
|
@@ -371,8 +375,8 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodLazy
|
|
|
371
375
|
readonly ultrawide: "21:9";
|
|
372
376
|
readonly ultratall: "9:21";
|
|
373
377
|
}>;
|
|
378
|
+
supportsAudio: z.ZodBoolean;
|
|
374
379
|
defaultGenerateAudio: z.ZodNullable<z.ZodBoolean>;
|
|
375
|
-
maxPromptLength: z.ZodNumber;
|
|
376
380
|
referenceRoles: z.ZodReadonly<z.ZodArray<z.ZodEnum<{
|
|
377
381
|
readonly first: "first-frame";
|
|
378
382
|
readonly last: "last-frame";
|
package/dist/browser.d.ts
CHANGED
package/dist/browser.js
CHANGED
|
@@ -17,7 +17,7 @@ export function estimate(settings, references) {
|
|
|
17
17
|
params.steps = settings.steps;
|
|
18
18
|
try {
|
|
19
19
|
if (isGatewayModel(settings.model))
|
|
20
|
-
return estimateGatewayMilliunits(settings);
|
|
20
|
+
return estimateGatewayMilliunits(settings, references);
|
|
21
21
|
return estimateImageMilliunits(settings.model, params);
|
|
22
22
|
}
|
|
23
23
|
catch (cause) {
|
|
@@ -53,6 +53,29 @@ function workersAiInput(payload) {
|
|
|
53
53
|
},
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* The one AI Gateway routing rule: a call keeps the host's gateway option only
|
|
58
|
+
* when its input is gateway-compatible.
|
|
59
|
+
* - A stream input never is. The binding's documented multipart input is a
|
|
60
|
+
* ReadableStream body
|
|
61
|
+
* (https://developers.cloudflare.com/changelog/2025-11-25-flux-2-dev-workers-ai/),
|
|
62
|
+
* and the gateway route rejects it: "AI Gateway does not support
|
|
63
|
+
* ReadableStreams yet".
|
|
64
|
+
* - An image or frame input never is. AI Gateway documents no request body
|
|
65
|
+
* limit (https://developers.cloudflare.com/ai-gateway/reference/limits/), yet
|
|
66
|
+
* it rejects a first-frame Seedance request (~700 KB data URI) with
|
|
67
|
+
* `7003: User Input Error` that succeeds on the direct binding.
|
|
68
|
+
* Metering stays correct either way: Media meters from its own estimate, not
|
|
69
|
+
* from gateway logs.
|
|
70
|
+
*/
|
|
71
|
+
function routedOptions(options, signal, input) {
|
|
72
|
+
const compatible = !input.stream && input.images === 0;
|
|
73
|
+
if (compatible || options === undefined)
|
|
74
|
+
return signal === undefined ? options : { ...options, signal };
|
|
75
|
+
const { gateway, ...direct } = options;
|
|
76
|
+
void gateway;
|
|
77
|
+
return signal === undefined ? direct : { ...direct, signal };
|
|
78
|
+
}
|
|
56
79
|
/** Retain the original provider failure alongside its bounded code and category. */
|
|
57
80
|
function providerFailure(model, cause) {
|
|
58
81
|
const provider = {
|
|
@@ -76,7 +99,10 @@ async function generateThroughGateway(ai, settings, references, signal, options,
|
|
|
76
99
|
let providerValue;
|
|
77
100
|
try {
|
|
78
101
|
const input = gatewayInput(settings, references, outputFormat);
|
|
79
|
-
providerValue = await ai.run(settings.model, input,
|
|
102
|
+
providerValue = await ai.run(settings.model, input, routedOptions(options, signal, {
|
|
103
|
+
stream: false,
|
|
104
|
+
images: references.length,
|
|
105
|
+
}));
|
|
80
106
|
}
|
|
81
107
|
catch (cause) {
|
|
82
108
|
throw providerFailure(settings.model, cause);
|
|
@@ -121,7 +147,10 @@ export async function generate(ai, settings, references, signal, options, fetchR
|
|
|
121
147
|
}
|
|
122
148
|
let providerValue;
|
|
123
149
|
try {
|
|
124
|
-
providerValue = await ai.run(settings.model, workersAiInput(providerInput),
|
|
150
|
+
providerValue = await ai.run(settings.model, workersAiInput(providerInput), routedOptions(options, signal, {
|
|
151
|
+
stream: providerInput.transport === "multipart",
|
|
152
|
+
images: references.length,
|
|
153
|
+
}));
|
|
125
154
|
}
|
|
126
155
|
catch (cause) {
|
|
127
156
|
throw providerFailure(settings.model, cause);
|
package/dist/cost-estimate.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { getMediaModel, MediaSettingsError } from "./model-catalog.js";
|
|
1
|
+
import { getMediaModel, MAX_REFERENCE_COUNT, MediaSettingsError, } from "./model-catalog.js";
|
|
2
2
|
import { neuronsToMilliunits } from "./neurons.js";
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
const TILE = 512;
|
|
5
5
|
const MAX_DIMENSION = 4_096;
|
|
6
|
-
const MAX_REFERENCES = 4;
|
|
7
6
|
const imageParamsSchema = z.lazy(() => z
|
|
8
7
|
.object({
|
|
9
8
|
width: z.number().int().min(1).max(MAX_DIMENSION),
|
|
@@ -16,7 +15,7 @@ const imageParamsSchema = z.lazy(() => z
|
|
|
16
15
|
height: z.number().int().min(1).max(MAX_DIMENSION),
|
|
17
16
|
})
|
|
18
17
|
.strict())
|
|
19
|
-
.max(
|
|
18
|
+
.max(MAX_REFERENCE_COUNT)
|
|
20
19
|
.optional(),
|
|
21
20
|
})
|
|
22
21
|
.strict());
|
|
@@ -34,7 +33,7 @@ const checked = (modelId, params) => {
|
|
|
34
33
|
if (model === undefined)
|
|
35
34
|
throw new MediaSettingsError(`Image cost unknown for model "${modelId}"`);
|
|
36
35
|
if (references.length > model.input.maxReferences)
|
|
37
|
-
return invalid(`${modelId}
|
|
36
|
+
return invalid(`${modelId} accepts at most ${String(model.input.maxReferences)} references`);
|
|
38
37
|
const normalized = {
|
|
39
38
|
width: candidate.width,
|
|
40
39
|
height: candidate.height,
|
package/dist/gateway-models.d.ts
CHANGED
|
@@ -13,11 +13,20 @@ export type MediaUnits = Readonly<{
|
|
|
13
13
|
/** Billing units for validated settings; video bills its requested length. */
|
|
14
14
|
export declare function mediaUnits(settings: MediaGenerationSettings): MediaUnits;
|
|
15
15
|
/** Milliunits (1 cent = 1,000) of provider cost, rounded up. */
|
|
16
|
-
export declare function estimateGatewayMilliunits(settings: MediaGenerationSettings
|
|
16
|
+
export declare function estimateGatewayMilliunits(settings: MediaGenerationSettings, references: readonly Readonly<{
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
}>[]): number;
|
|
17
20
|
/** The provider JSON body for one validated gateway generation. */
|
|
18
21
|
export declare function gatewayInput(settings: MediaGenerationSettings, references?: readonly MediaReferenceBytes[], outputFormat?: "png" | "jpeg" | "webp"): import("./video-providers/minimax.js").MinimaxGatewayInput | import("./video-providers/unified.js").UnifiedGatewayInput | {
|
|
19
22
|
prompt: string;
|
|
20
23
|
size: string;
|
|
21
24
|
quality: string;
|
|
22
25
|
output_format: "png" | "jpeg" | "webp";
|
|
26
|
+
} | {
|
|
27
|
+
images: string[];
|
|
28
|
+
prompt: string;
|
|
29
|
+
size: string;
|
|
30
|
+
quality: string;
|
|
31
|
+
output_format: "png" | "jpeg" | "webp";
|
|
23
32
|
};
|
package/dist/gateway-models.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getMediaModel, MediaSettingsError } from "./model-catalog.js";
|
|
2
2
|
import { validateMediaGenerationSettings, estimateVideoMilliunits, } from "./index.js";
|
|
3
|
+
import { imageDataUri } from "./video-providers/reference-encoding.js";
|
|
3
4
|
import { videoProviderAdapters, } from "./video-providers/index.js";
|
|
4
5
|
export const isGatewayModel = (id) => id === "openai/gpt-image-2" || getMediaModel(id)?.kind === "video";
|
|
5
6
|
/** Billing units for validated settings; video bills its requested length. */
|
|
@@ -28,33 +29,81 @@ const gptImageOutputTokens = new Map([
|
|
|
28
29
|
["1024x1536", 1_584],
|
|
29
30
|
["1536x1024", 1_568],
|
|
30
31
|
]);
|
|
31
|
-
/**
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* USD per million tokens: text input, image input and image output, as
|
|
34
|
+
* Cloudflare publishes them for this exact model.
|
|
35
|
+
* https://developers.cloudflare.com/ai/models/openai/gpt-image-2/
|
|
36
|
+
*/
|
|
37
|
+
const gptImageRates = { input: 5, inputImage: 8, outputImage: 30 };
|
|
38
|
+
/**
|
|
39
|
+
* Upper bound on the image input tokens one reference adds. OpenAI publishes
|
|
40
|
+
* no input-token rule for gpt-image-2, which always reads inputs at high
|
|
41
|
+
* fidelity, so this applies the GPT Image high-fidelity rule OpenAI does
|
|
42
|
+
* publish (images-vision guide, GPT Image 1): fit within 2048 px, cap the
|
|
43
|
+
* short side at 512 px, 65 base + 129 per 512 px tile, plus 4,160 extra
|
|
44
|
+
* tokens for a square image or 6,240 for any other aspect.
|
|
45
|
+
* https://developers.openai.com/api/docs/guides/images-vision
|
|
46
|
+
* Community measurements put gpt-image-2 at most 1,536 image tokens per
|
|
47
|
+
* input, so this bound over-bills rather than under-bills; lower it only
|
|
48
|
+
* against real gateway input-token counts.
|
|
49
|
+
*/
|
|
50
|
+
function gptImageReferenceTokens(reference) {
|
|
51
|
+
const fit = Math.min(1, 2048 / Math.max(reference.width, reference.height));
|
|
52
|
+
const short = Math.min(reference.width, reference.height) * fit;
|
|
53
|
+
const scale = fit * Math.min(1, 512 / short);
|
|
54
|
+
const tiles = Math.ceil((reference.width * scale) / 512) *
|
|
55
|
+
Math.ceil((reference.height * scale) / 512);
|
|
56
|
+
const aspect = reference.width === reference.height ? 4_160 : 6_240;
|
|
57
|
+
return 65 + 129 * tiles + aspect;
|
|
58
|
+
}
|
|
33
59
|
const sizeOf = (settings) => `${String(settings.width)}x${String(settings.height)}`;
|
|
34
60
|
/** Milliunits (1 cent = 1,000) of provider cost, rounded up. */
|
|
35
|
-
export function estimateGatewayMilliunits(settings) {
|
|
61
|
+
export function estimateGatewayMilliunits(settings, references) {
|
|
36
62
|
if (settings.model === "openai/gpt-image-2") {
|
|
37
63
|
const output = gptImageOutputTokens.get(sizeOf(settings));
|
|
38
64
|
if (output === undefined)
|
|
39
65
|
throw new MediaSettingsError("unsupported GPT Image 2 size");
|
|
40
|
-
|
|
41
|
-
|
|
66
|
+
if (references.length !== (settings.references?.length ?? 0))
|
|
67
|
+
throw new MediaSettingsError("resolved references must match every admitted reference");
|
|
68
|
+
// A bound on prompt tokens: at most one token per character, plus one
|
|
69
|
+
// text token OpenAI is observed to add per input image.
|
|
70
|
+
const input = settings.prompt.length + references.length;
|
|
71
|
+
const inputImage = references.reduce((sum, reference) => sum + gptImageReferenceTokens(reference), 0);
|
|
42
72
|
// tokens * USD/M * 100,000 milliunits/USD / 1,000,000 = tokens * rate / 10
|
|
43
|
-
return Math.ceil((output * gptImageRates.outputImage +
|
|
73
|
+
return Math.ceil((output * gptImageRates.outputImage +
|
|
74
|
+
input * gptImageRates.input +
|
|
75
|
+
inputImage * gptImageRates.inputImage) /
|
|
76
|
+
10);
|
|
44
77
|
}
|
|
45
78
|
if (getMediaModel(settings.model)?.kind === "video")
|
|
46
79
|
return estimateVideoMilliunits(settings);
|
|
47
80
|
throw new MediaSettingsError(`${settings.model} is not a gateway model`);
|
|
48
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* One `images[]` entry for `openai/gpt-image-2`: a base64 data URI of a png,
|
|
84
|
+
* jpeg or webp image (Cloudflare's published input schema).
|
|
85
|
+
* https://developers.cloudflare.com/ai/models/openai/gpt-image-2/
|
|
86
|
+
*/
|
|
87
|
+
function gptImageReference(reference) {
|
|
88
|
+
if (reference.format === "gif")
|
|
89
|
+
throw new MediaSettingsError("openai/gpt-image-2 accepts png, jpeg or webp reference images, not gif");
|
|
90
|
+
return imageDataUri(reference);
|
|
91
|
+
}
|
|
49
92
|
/** The provider JSON body for one validated gateway generation. */
|
|
50
93
|
export function gatewayInput(settings, references = [], outputFormat = "png") {
|
|
51
|
-
if (settings.model === "openai/gpt-image-2")
|
|
52
|
-
|
|
94
|
+
if (settings.model === "openai/gpt-image-2") {
|
|
95
|
+
const body = {
|
|
53
96
|
prompt: settings.prompt,
|
|
54
97
|
size: sizeOf(settings),
|
|
55
98
|
quality: "medium",
|
|
56
99
|
output_format: outputFormat,
|
|
57
100
|
};
|
|
101
|
+
if (references.length !== (settings.references?.length ?? 0))
|
|
102
|
+
throw new MediaSettingsError("resolved references must match every admitted reference");
|
|
103
|
+
if (references.length === 0)
|
|
104
|
+
return body;
|
|
105
|
+
return { ...body, images: references.map(gptImageReference) };
|
|
106
|
+
}
|
|
58
107
|
const checked = validateMediaGenerationSettings({
|
|
59
108
|
...settings,
|
|
60
109
|
references: settings.references?.map((reference) => ({ ...reference })),
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { type MediaVideoReferenceRole, type MediaVideoModelId, type MediaVideoResolution, type MediaVideoAspectRatio } from "./model-catalog.js";
|
|
3
3
|
export { mediaFailureStageSchema } from "./execution-error.js";
|
|
4
|
-
export { getMediaModel, listMediaModels, mediaModelInputSchema, mediaModelSchema, mediaRequestedImageFormatSchema, mediaModels, mediaModelTierSchema, MediaSettingsError, mediaVideoModelIdSchema, mediaVideoResolutionSchema, mediaVideoAspectRatioSchema, mediaVideoReferenceRoleSchema, mediaVideoFormatSchema, mediaVideoSchema, } from "./model-catalog.js";
|
|
4
|
+
export { MAX_MEDIA_PROMPT_LENGTH, getMediaModel, MAX_REFERENCE_COUNT, listMediaModels, mediaModelInputSchema, mediaModelSchema, mediaRequestedImageFormatSchema, mediaModels, mediaModelTierSchema, MediaSettingsError, mediaVideoModelIdSchema, mediaVideoResolutionSchema, mediaVideoAspectRatioSchema, mediaVideoReferenceRoleSchema, mediaVideoFormatSchema, mediaVideoSchema, } from "./model-catalog.js";
|
|
5
5
|
export type { MediaModel, MediaModelInput, MediaModelTier, MediaVideoModelId, MediaVideoResolution, MediaVideoAspectRatio, MediaVideoReferenceRole, MediaVideoModel, MediaVideoFormat, } from "./model-catalog.js";
|
|
6
6
|
/** A reference file selected by the host, with its destination identity and path. */
|
|
7
7
|
export type MediaReference = Readonly<{
|
|
@@ -80,8 +80,6 @@ export declare const viewDimensionSchema: z.ZodLazy<z.ZodNumber>;
|
|
|
80
80
|
* a lossy JPEG, so a viewer can step the dimension down to meet a byte budget.
|
|
81
81
|
*/
|
|
82
82
|
export type ImageViewFitter = (bytes: Uint8Array, maxDimension: number) => Promise<FittedReferenceImage>;
|
|
83
|
-
/** Maximum reference files in one generation request. */
|
|
84
|
-
export declare const MAX_REFERENCE_COUNT = 4;
|
|
85
83
|
/** Maximum reference width and height sent to inference, in pixels. */
|
|
86
84
|
export declare const MAX_REFERENCE_DIMENSION = 512;
|
|
87
85
|
/** Maximum decoded bytes per reference image. */
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { reportCatchFailure } from "./failure.js";
|
|
3
|
-
import { getMediaModel, MediaSettingsError, mediaVideoModelIdSchema, mediaVideoResolutionSchema, mediaVideoAspectRatioSchema, mediaVideoReferenceRoleSchema, } from "./model-catalog.js";
|
|
3
|
+
import { getMediaModel, MAX_REFERENCE_COUNT, MediaSettingsError, mediaVideoModelIdSchema, mediaVideoResolutionSchema, mediaVideoAspectRatioSchema, mediaVideoReferenceRoleSchema, MAX_MEDIA_PROMPT_LENGTH, } from "./model-catalog.js";
|
|
4
4
|
export { mediaFailureStageSchema } from "./execution-error.js";
|
|
5
|
-
export { getMediaModel, listMediaModels, mediaModelInputSchema, mediaModelSchema, mediaRequestedImageFormatSchema, mediaModels, mediaModelTierSchema, MediaSettingsError, mediaVideoModelIdSchema, mediaVideoResolutionSchema, mediaVideoAspectRatioSchema, mediaVideoReferenceRoleSchema, mediaVideoFormatSchema, mediaVideoSchema, } from "./model-catalog.js";
|
|
5
|
+
export { MAX_MEDIA_PROMPT_LENGTH, getMediaModel, MAX_REFERENCE_COUNT, listMediaModels, mediaModelInputSchema, mediaModelSchema, mediaRequestedImageFormatSchema, mediaModels, mediaModelTierSchema, MediaSettingsError, mediaVideoModelIdSchema, mediaVideoResolutionSchema, mediaVideoAspectRatioSchema, mediaVideoReferenceRoleSchema, mediaVideoFormatSchema, mediaVideoSchema, } from "./model-catalog.js";
|
|
6
6
|
/** The long-edge bounds a viewer may ask for when fitting an image to look at. */
|
|
7
7
|
export const MIN_VIEW_DIMENSION = 256;
|
|
8
8
|
/** Maximum long-edge size accepted by an image viewer, in pixels. */
|
|
9
9
|
export const MAX_VIEW_DIMENSION = 512;
|
|
10
10
|
/** Decode a viewer long-edge size within the supported pixel bounds. */
|
|
11
11
|
export const viewDimensionSchema = z.lazy(() => z.number().int().min(MIN_VIEW_DIMENSION).max(MAX_VIEW_DIMENSION));
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/** Reference images in one video request: every verified video model's catalog value. */
|
|
13
|
+
const MAX_VIDEO_REFERENCE_COUNT = 4;
|
|
14
14
|
/** Maximum reference width and height sent to inference, in pixels. */
|
|
15
15
|
export const MAX_REFERENCE_DIMENSION = 512;
|
|
16
16
|
/** Maximum decoded bytes per reference image. */
|
|
@@ -42,8 +42,8 @@ export const mediaGenerationSettingsSchema = z
|
|
|
42
42
|
.object({
|
|
43
43
|
/** Provider catalog model identifier. */
|
|
44
44
|
model: z.string().min(1).max(256),
|
|
45
|
-
/** Generation prompt. */
|
|
46
|
-
prompt: z.string().min(1).max(
|
|
45
|
+
/** Generation prompt; each model's `maxPromptLength` is enforced on top of this ceiling. */
|
|
46
|
+
prompt: z.string().min(1).max(MAX_MEDIA_PROMPT_LENGTH),
|
|
47
47
|
/** Requested image width or nominal video selector, not decoded MP4 dimensions. */
|
|
48
48
|
width: z.number().int().min(1).max(5_040),
|
|
49
49
|
/** Requested image height or nominal video selector, not decoded MP4 dimensions. */
|
|
@@ -116,6 +116,8 @@ function normalizeGenerationSettings(input, normalize) {
|
|
|
116
116
|
if (model === undefined)
|
|
117
117
|
throw new MediaSettingsError(`unknown Media model "${modelId}"`);
|
|
118
118
|
const prompt = requiredString(input.prompt, "prompt");
|
|
119
|
+
if (prompt.length > model.maxPromptLength)
|
|
120
|
+
throw new MediaSettingsError(`${model.id} prompt is ${String(prompt.length)} characters; its limit is ${String(model.maxPromptLength)}`);
|
|
119
121
|
const maximumDimension = model.video === null ? 4_096 : 5_040;
|
|
120
122
|
const width = boundedInteger(input.width, "width", 1, maximumDimension);
|
|
121
123
|
const height = boundedInteger(input.height, "height", 1, maximumDimension);
|
|
@@ -142,8 +144,6 @@ function normalizeGenerationSettings(input, normalize) {
|
|
|
142
144
|
durationSeconds = boundedInteger(input.durationSeconds ?? model.video.defaultSeconds, "durationSeconds", model.video.minSeconds, model.video.maxSeconds);
|
|
143
145
|
if (!model.video.durations.includes(durationSeconds))
|
|
144
146
|
throw new MediaSettingsError(`${model.id} accepts durationSeconds ${model.video.durations.join(", ")}`);
|
|
145
|
-
if (prompt.length > model.video.maxPromptLength)
|
|
146
|
-
throw new MediaSettingsError(`${model.id} prompt exceeds ${String(model.video.maxPromptLength)} characters`);
|
|
147
147
|
}
|
|
148
148
|
let steps;
|
|
149
149
|
if (input.steps !== undefined && model.input.steps === "fixed")
|
|
@@ -194,20 +194,27 @@ function normalizeGenerationSettings(input, normalize) {
|
|
|
194
194
|
role: reference.role ?? mediaVideoReferenceRoleSchema.enum.first,
|
|
195
195
|
}));
|
|
196
196
|
const roles = references.map((reference) => reference.role);
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
const refused = roles.find((role) => role === undefined || !video.referenceRoles.includes(role));
|
|
198
|
+
if (refused !== undefined || roles.includes(undefined))
|
|
199
|
+
throw new MediaSettingsError(refused === "last-frame"
|
|
200
|
+
? `${model.label} has no last frame`
|
|
201
|
+
: `${model.label} does not take ${String(refused)} images`);
|
|
199
202
|
const first = roles.filter((role) => role === "first-frame").length;
|
|
200
203
|
const last = roles.filter((role) => role === "last-frame").length;
|
|
201
204
|
const referenceCount = roles.filter((role) => role === "reference").length;
|
|
202
|
-
if (first > 1 ||
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
205
|
+
if (first > 1 || last > 1)
|
|
206
|
+
throw new MediaSettingsError(video.referenceRoles.includes("last-frame")
|
|
207
|
+
? `${model.label} takes one first frame and one last frame`
|
|
208
|
+
: `${model.label} takes one first frame`);
|
|
209
|
+
if (last > 0 && first !== 1)
|
|
210
|
+
throw new MediaSettingsError("A last frame needs a first frame as well");
|
|
211
|
+
if (referenceCount > 0 && first + last > 0)
|
|
212
|
+
throw new MediaSettingsError("Frames and references cannot be mixed; use a first/last frame or references");
|
|
213
|
+
if (referenceCount > video.maxReferenceImages)
|
|
214
|
+
throw new MediaSettingsError(`${model.label} takes up to ${String(video.maxReferenceImages)} reference images`);
|
|
215
|
+
if (referenceCount > 0 &&
|
|
216
|
+
!video.referenceResolutions.includes(format.resolution))
|
|
217
|
+
throw new MediaSettingsError(`${model.label} takes reference images only at ${video.referenceResolutions.join(", ")}`);
|
|
211
218
|
}
|
|
212
219
|
}
|
|
213
220
|
if (references !== undefined)
|
|
@@ -225,8 +232,8 @@ export const mediaVideoReferenceSchema = z.lazy(() => z.strictObject({
|
|
|
225
232
|
export const mediaVideoSelectionSchema = z.lazy(() => z.strictObject({
|
|
226
233
|
/** Verified catalog model identifier. */
|
|
227
234
|
model: mediaVideoModelIdSchema,
|
|
228
|
-
/** Trimmed prompt;
|
|
229
|
-
prompt: z.string().min(1).max(
|
|
235
|
+
/** Trimmed prompt; the selected model's `maxPromptLength` is enforced on top of this ceiling. */
|
|
236
|
+
prompt: z.string().min(1).max(MAX_MEDIA_PROMPT_LENGTH),
|
|
230
237
|
/** Model-specific resolution, default 720p. */
|
|
231
238
|
resolution: mediaVideoResolutionSchema.optional(),
|
|
232
239
|
/** Model-specific aspect, default 16:9. */
|
|
@@ -239,7 +246,7 @@ export const mediaVideoSelectionSchema = z.lazy(() => z.strictObject({
|
|
|
239
246
|
/** Up to four references, with provider-specific roles and mode limits. */
|
|
240
247
|
references: z
|
|
241
248
|
.array(mediaVideoReferenceSchema)
|
|
242
|
-
.max(
|
|
249
|
+
.max(MAX_VIDEO_REFERENCE_COUNT)
|
|
243
250
|
.optional(),
|
|
244
251
|
}));
|
|
245
252
|
/** Validate supported model/size/duration/reference combinations before authority or billing admission. */
|
package/dist/model-catalog.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export declare const mediaModelInputSchema: z.ZodLazy<z.ZodReadonly<z.ZodObject<
|
|
|
40
40
|
readonly own: "own";
|
|
41
41
|
}>;
|
|
42
42
|
maxDimension: z.ZodNullable<z.ZodNumber>;
|
|
43
|
+
maxDimensionDocumented: z.ZodBoolean;
|
|
43
44
|
defaultWidth: z.ZodNumber;
|
|
44
45
|
defaultHeight: z.ZodNumber;
|
|
45
46
|
steps: z.ZodEnum<{
|
|
@@ -55,6 +56,11 @@ export declare const mediaModelInputSchema: z.ZodLazy<z.ZodReadonly<z.ZodObject<
|
|
|
55
56
|
referenceField: z.ZodNullable<z.ZodString>;
|
|
56
57
|
maxReferences: z.ZodNumber;
|
|
57
58
|
}, z.core.$strict>>>;
|
|
59
|
+
/**
|
|
60
|
+
* Schema ceiling for reference lists: the largest per-model limit. Each model's
|
|
61
|
+
* own `maxReferences` / `maxReferenceImages` is enforced after parsing.
|
|
62
|
+
*/
|
|
63
|
+
export declare const MAX_REFERENCE_COUNT = 16;
|
|
58
64
|
/** Verified Unified AI video identifiers; no inferred family aliases. */
|
|
59
65
|
export declare const mediaVideoModelIdSchema: z.ZodEnum<{
|
|
60
66
|
/** Seedance 2.0. */
|
|
@@ -110,7 +116,7 @@ export type MediaVideoAspectRatio = z.output<typeof mediaVideoAspectRatioSchema>
|
|
|
110
116
|
export declare const mediaVideoReferenceRoleSchema: z.ZodEnum<{
|
|
111
117
|
/** First frame; required when a last frame is supplied. */
|
|
112
118
|
readonly first: "first-frame";
|
|
113
|
-
/** Last frame, supported by Seedance only. */
|
|
119
|
+
/** Last frame, supported by Seedance only (`last_frame_image`). */
|
|
114
120
|
readonly last: "last-frame";
|
|
115
121
|
/** One image in Seedance reference-image mode. */
|
|
116
122
|
readonly reference: "reference";
|
|
@@ -226,12 +232,12 @@ export declare const mediaVideoSchema: z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
|
226
232
|
/** Portrait ultrawide. */
|
|
227
233
|
readonly ultratall: "9:21";
|
|
228
234
|
}>;
|
|
235
|
+
supportsAudio: z.ZodBoolean;
|
|
229
236
|
defaultGenerateAudio: z.ZodNullable<z.ZodBoolean>;
|
|
230
|
-
maxPromptLength: z.ZodNumber;
|
|
231
237
|
referenceRoles: z.ZodReadonly<z.ZodArray<z.ZodEnum<{
|
|
232
238
|
/** First frame; required when a last frame is supplied. */
|
|
233
239
|
readonly first: "first-frame";
|
|
234
|
-
/** Last frame, supported by Seedance only. */
|
|
240
|
+
/** Last frame, supported by Seedance only (`last_frame_image`). */
|
|
235
241
|
readonly last: "last-frame";
|
|
236
242
|
/** One image in Seedance reference-image mode. */
|
|
237
243
|
readonly reference: "reference";
|
|
@@ -268,6 +274,11 @@ export declare const mediaVideoSchema: z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
|
268
274
|
}, z.core.$strict>>>;
|
|
269
275
|
/** Immutable video capability and price metadata. */
|
|
270
276
|
export type MediaVideoModel = z.output<typeof mediaVideoSchema>;
|
|
277
|
+
/**
|
|
278
|
+
* Structural ceiling for any prompt on the wire. Each model's own
|
|
279
|
+
* `maxPromptLength` is the real bound; no model may exceed this ceiling.
|
|
280
|
+
*/
|
|
281
|
+
export declare const MAX_MEDIA_PROMPT_LENGTH = 32000;
|
|
271
282
|
/** Public wire grammar for a catalog entry returned by the Media owner. */
|
|
272
283
|
export declare const mediaModelSchema: z.ZodReadonly<z.ZodObject<{
|
|
273
284
|
id: z.ZodString;
|
|
@@ -296,6 +307,7 @@ export declare const mediaModelSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
296
307
|
/** WebP image encoding. */
|
|
297
308
|
readonly webp: "webp";
|
|
298
309
|
}>>>;
|
|
310
|
+
maxPromptLength: z.ZodNumber;
|
|
299
311
|
input: z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
300
312
|
transport: z.ZodEnum<{
|
|
301
313
|
/** JSON provider input. */
|
|
@@ -310,6 +322,7 @@ export declare const mediaModelSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
310
322
|
readonly own: "own";
|
|
311
323
|
}>;
|
|
312
324
|
maxDimension: z.ZodNullable<z.ZodNumber>;
|
|
325
|
+
maxDimensionDocumented: z.ZodBoolean;
|
|
313
326
|
defaultWidth: z.ZodNumber;
|
|
314
327
|
defaultHeight: z.ZodNumber;
|
|
315
328
|
steps: z.ZodEnum<{
|
|
@@ -399,12 +412,12 @@ export declare const mediaModelSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
399
412
|
/** Portrait ultrawide. */
|
|
400
413
|
readonly ultratall: "9:21";
|
|
401
414
|
}>;
|
|
415
|
+
supportsAudio: z.ZodBoolean;
|
|
402
416
|
defaultGenerateAudio: z.ZodNullable<z.ZodBoolean>;
|
|
403
|
-
maxPromptLength: z.ZodNumber;
|
|
404
417
|
referenceRoles: z.ZodReadonly<z.ZodArray<z.ZodEnum<{
|
|
405
418
|
/** First frame; required when a last frame is supplied. */
|
|
406
419
|
readonly first: "first-frame";
|
|
407
|
-
/** Last frame, supported by Seedance only. */
|
|
420
|
+
/** Last frame, supported by Seedance only (`last_frame_image`). */
|
|
408
421
|
readonly last: "last-frame";
|
|
409
422
|
/** One image in Seedance reference-image mode. */
|
|
410
423
|
readonly reference: "reference";
|
package/dist/model-catalog.js
CHANGED
|
@@ -26,7 +26,11 @@ export const mediaModelTierSchema = z.enum({
|
|
|
26
26
|
/** Media's provider catalog: Workers AI images plus gateway image and video models. */
|
|
27
27
|
export const mediaModelInputSchema = z.lazy(() => z
|
|
28
28
|
.strictObject({
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Provider input transport. Multipart is the binding's documented
|
|
31
|
+
* ReadableStream body, which AI Gateway cannot carry, so multipart models
|
|
32
|
+
* run without the gateway option (see cloudflare/provider.ts).
|
|
33
|
+
*/
|
|
30
34
|
transport: z.enum({
|
|
31
35
|
/** JSON provider input. */
|
|
32
36
|
json: "json",
|
|
@@ -42,6 +46,8 @@ export const mediaModelInputSchema = z.lazy(() => z
|
|
|
42
46
|
}),
|
|
43
47
|
/** Maximum accepted dimension in pixels, or null when unbounded by this model. */
|
|
44
48
|
maxDimension: z.number().int().positive().nullable(),
|
|
49
|
+
/** Whether the provider's own page documents `maxDimension`; false for host caps. */
|
|
50
|
+
maxDimensionDocumented: z.boolean(),
|
|
45
51
|
/** Default output width in pixels. */
|
|
46
52
|
defaultWidth: z.number().int().positive(),
|
|
47
53
|
/** Default output height in pixels. */
|
|
@@ -65,6 +71,11 @@ export const mediaModelInputSchema = z.lazy(() => z
|
|
|
65
71
|
maxReferences: z.number().int().nonnegative(),
|
|
66
72
|
})
|
|
67
73
|
.readonly());
|
|
74
|
+
/**
|
|
75
|
+
* Schema ceiling for reference lists: the largest per-model limit. Each model's
|
|
76
|
+
* own `maxReferences` / `maxReferenceImages` is enforced after parsing.
|
|
77
|
+
*/
|
|
78
|
+
export const MAX_REFERENCE_COUNT = 16;
|
|
68
79
|
/** Verified Unified AI video identifiers; no inferred family aliases. */
|
|
69
80
|
export const mediaVideoModelIdSchema = z.enum({
|
|
70
81
|
/** Seedance 2.0. */
|
|
@@ -114,7 +125,7 @@ export const mediaVideoAspectRatioSchema = z.enum({
|
|
|
114
125
|
export const mediaVideoReferenceRoleSchema = z.enum({
|
|
115
126
|
/** First frame; required when a last frame is supplied. */
|
|
116
127
|
first: "first-frame",
|
|
117
|
-
/** Last frame, supported by Seedance only. */
|
|
128
|
+
/** Last frame, supported by Seedance only (`last_frame_image`). */
|
|
118
129
|
last: "last-frame",
|
|
119
130
|
/** One image in Seedance reference-image mode. */
|
|
120
131
|
reference: "reference",
|
|
@@ -158,10 +169,10 @@ export const mediaVideoSchema = z.lazy(() => z
|
|
|
158
169
|
defaultResolution: mediaVideoResolutionSchema,
|
|
159
170
|
/** Aspect selected when omitted. */
|
|
160
171
|
defaultAspectRatio: mediaVideoAspectRatioSchema,
|
|
172
|
+
/** Whether the model documents a `generate_audio` choice. */
|
|
173
|
+
supportsAudio: z.boolean(),
|
|
161
174
|
/** Audio default, or null when not documented and left to the provider. */
|
|
162
175
|
defaultGenerateAudio: z.boolean().nullable(),
|
|
163
|
-
/** Prompt bound: provider bound for Seedance, retained host bound for Veo. */
|
|
164
|
-
maxPromptLength: z.number().int().positive(),
|
|
165
176
|
/** Frame or reference roles this provider accepts. */
|
|
166
177
|
referenceRoles: z.array(mediaVideoReferenceRoleSchema).readonly(),
|
|
167
178
|
/** Reference-image mode count; first/last frame mode has its own grammar. */
|
|
@@ -183,6 +194,13 @@ export const mediaVideoSchema = z.lazy(() => z
|
|
|
183
194
|
.readonly(),
|
|
184
195
|
})
|
|
185
196
|
.readonly());
|
|
197
|
+
/**
|
|
198
|
+
* Structural ceiling for any prompt on the wire. Each model's own
|
|
199
|
+
* `maxPromptLength` is the real bound; no model may exceed this ceiling.
|
|
200
|
+
*/
|
|
201
|
+
export const MAX_MEDIA_PROMPT_LENGTH = 32_000;
|
|
202
|
+
/** Prompt cap kept for models whose provider documents no prompt limit. */
|
|
203
|
+
const UNDOCUMENTED_PROMPT_LENGTH = 2_048;
|
|
186
204
|
/** Public wire grammar for a catalog entry returned by the Media owner. */
|
|
187
205
|
export const mediaModelSchema = z
|
|
188
206
|
.strictObject({
|
|
@@ -201,6 +219,11 @@ export const mediaModelSchema = z
|
|
|
201
219
|
tier: mediaModelTierSchema,
|
|
202
220
|
/** Verified provider encodings; an empty list refuses pinned formats. */
|
|
203
221
|
outputFormats: z.array(mediaRequestedImageFormatSchema).max(3).readonly(),
|
|
222
|
+
/**
|
|
223
|
+
* Maximum prompt length in characters for this model: the provider's
|
|
224
|
+
* documented limit, or the retained 2,048 host cap where none is documented.
|
|
225
|
+
*/
|
|
226
|
+
maxPromptLength: z.number().int().positive().max(MAX_MEDIA_PROMPT_LENGTH),
|
|
204
227
|
/** Model-native input options and reference limits. */
|
|
205
228
|
input: mediaModelInputSchema,
|
|
206
229
|
/**
|
|
@@ -271,8 +294,12 @@ function videoModel(id, label, tier, provider, rates) {
|
|
|
271
294
|
formats,
|
|
272
295
|
defaultResolution: "720p",
|
|
273
296
|
defaultAspectRatio: "16:9",
|
|
297
|
+
// Seedance documents `generate_audio` without a default; Veo documents
|
|
298
|
+
// `generate_audio` with default true.
|
|
299
|
+
// https://developers.cloudflare.com/ai/models/bytedance/seedance-2.0/
|
|
300
|
+
// https://developers.cloudflare.com/ai/models/google/veo-3.1/
|
|
301
|
+
supportsAudio: true,
|
|
274
302
|
defaultGenerateAudio: seedance ? null : true,
|
|
275
|
-
maxPromptLength: seedance ? 2000 : 2048,
|
|
276
303
|
referenceRoles: Object.freeze(seedance
|
|
277
304
|
? mediaVideoReferenceRoleSchema.options
|
|
278
305
|
: [mediaVideoReferenceRoleSchema.enum.first]),
|
|
@@ -292,6 +319,10 @@ function videoModel(id, label, tier, provider, rates) {
|
|
|
292
319
|
id,
|
|
293
320
|
label,
|
|
294
321
|
tier,
|
|
322
|
+
// Seedance: the provider's own 2,000-character bound (retained from the
|
|
323
|
+
// earlier video contract).
|
|
324
|
+
// Veo documents no character limit; keep the retained 2,048 host cap.
|
|
325
|
+
maxPromptLength: seedance ? 2_000 : UNDOCUMENTED_PROMPT_LENGTH,
|
|
295
326
|
kind: "video",
|
|
296
327
|
video,
|
|
297
328
|
sizes: Object.freeze(formats.map(({ width, height }) => `${String(width)}x${String(height)}`)),
|
|
@@ -299,6 +330,7 @@ function videoModel(id, label, tier, provider, rates) {
|
|
|
299
330
|
transport: "json",
|
|
300
331
|
dimensions: "own",
|
|
301
332
|
maxDimension: Math.max(...formats.map(({ width, height }) => Math.max(width, height))),
|
|
333
|
+
maxDimensionDocumented: false,
|
|
302
334
|
defaultWidth: 1280,
|
|
303
335
|
defaultHeight: 720,
|
|
304
336
|
steps: "fixed",
|
|
@@ -358,10 +390,15 @@ function minimaxVideoModel() {
|
|
|
358
390
|
// Not merely undocumented: the schema has no audio field at all, so the
|
|
359
391
|
// dispatcher refuses an explicit generateAudio choice outright.
|
|
360
392
|
defaultGenerateAudio: null,
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
//
|
|
364
|
-
|
|
393
|
+
supportsAudio: false,
|
|
394
|
+
// The vendor page documents `first_frame` and `reference_image` roles only;
|
|
395
|
+
// it names no last frame.
|
|
396
|
+
referenceRoles: Object.freeze([
|
|
397
|
+
mediaVideoReferenceRoleSchema.enum.first,
|
|
398
|
+
mediaVideoReferenceRoleSchema.enum.reference,
|
|
399
|
+
]),
|
|
400
|
+
// The vendor page documents up to nine; this stays at the conservative
|
|
401
|
+
// verified value of four until the gateway schema is confirmed.
|
|
365
402
|
maxReferenceImages: 4,
|
|
366
403
|
referenceResolutions: Object.freeze(resolutions),
|
|
367
404
|
prices: Object.freeze([
|
|
@@ -382,6 +419,8 @@ function minimaxVideoModel() {
|
|
|
382
419
|
id: mediaVideoModelIdSchema.enum.minimaxH3Max,
|
|
383
420
|
label: "MiniMax H3 Max",
|
|
384
421
|
tier: "balanced",
|
|
422
|
+
// 7,000 characters per the vendor page cited above.
|
|
423
|
+
maxPromptLength: 7_000,
|
|
385
424
|
kind: "video",
|
|
386
425
|
video,
|
|
387
426
|
sizes: Object.freeze(formats.map(({ width, height }) => `${String(width)}x${String(height)}`)),
|
|
@@ -389,6 +428,7 @@ function minimaxVideoModel() {
|
|
|
389
428
|
transport: "json",
|
|
390
429
|
dimensions: "own",
|
|
391
430
|
maxDimension: Math.max(...formats.map(({ width, height }) => Math.max(width, height))),
|
|
431
|
+
maxDimensionDocumented: false,
|
|
392
432
|
defaultWidth: defaultFormat.width,
|
|
393
433
|
defaultHeight: defaultFormat.height,
|
|
394
434
|
steps: "fixed",
|
|
@@ -404,6 +444,8 @@ function minimaxVideoModel() {
|
|
|
404
444
|
const models = Object.freeze([
|
|
405
445
|
freezeModel({
|
|
406
446
|
id: "@cf/black-forest-labs/flux-1-schnell",
|
|
447
|
+
// 2,048 characters: input schema maxLength at developers.cloudflare.com/workers-ai/models/flux-1-schnell/.
|
|
448
|
+
maxPromptLength: 2_048,
|
|
407
449
|
outputFormats: Object.freeze(["jpeg"]),
|
|
408
450
|
tier: "draft",
|
|
409
451
|
label: "Flux 1 Schnell — cheap/fast sketches",
|
|
@@ -411,6 +453,7 @@ const models = Object.freeze([
|
|
|
411
453
|
transport: "json",
|
|
412
454
|
dimensions: "none",
|
|
413
455
|
maxDimension: null,
|
|
456
|
+
maxDimensionDocumented: false,
|
|
414
457
|
defaultWidth: 1024,
|
|
415
458
|
defaultHeight: 768,
|
|
416
459
|
steps: "steps",
|
|
@@ -422,12 +465,15 @@ const models = Object.freeze([
|
|
|
422
465
|
}),
|
|
423
466
|
freezeModel({
|
|
424
467
|
id: "@cf/black-forest-labs/flux-2-klein-4b",
|
|
468
|
+
// Workers AI documents no prompt maxLength for this model; keep the 2,048 host cap.
|
|
469
|
+
maxPromptLength: UNDOCUMENTED_PROMPT_LENGTH,
|
|
425
470
|
tier: "balanced",
|
|
426
471
|
label: "Flux 2 Klein 4b — balanced default",
|
|
427
472
|
input: {
|
|
428
473
|
transport: "multipart",
|
|
429
474
|
dimensions: "own",
|
|
430
475
|
maxDimension: 1920,
|
|
476
|
+
maxDimensionDocumented: false,
|
|
431
477
|
defaultWidth: 1024,
|
|
432
478
|
defaultHeight: 768,
|
|
433
479
|
steps: "fixed",
|
|
@@ -439,12 +485,15 @@ const models = Object.freeze([
|
|
|
439
485
|
}),
|
|
440
486
|
freezeModel({
|
|
441
487
|
id: "@cf/black-forest-labs/flux-2-klein-9b",
|
|
488
|
+
// Workers AI documents no prompt maxLength for this model; keep the 2,048 host cap.
|
|
489
|
+
maxPromptLength: UNDOCUMENTED_PROMPT_LENGTH,
|
|
442
490
|
tier: "premium",
|
|
443
491
|
label: "Flux 2 Klein 9b — higher quality flux-2",
|
|
444
492
|
input: {
|
|
445
493
|
transport: "multipart",
|
|
446
494
|
dimensions: "own",
|
|
447
495
|
maxDimension: 1920,
|
|
496
|
+
maxDimensionDocumented: false,
|
|
448
497
|
defaultWidth: 1024,
|
|
449
498
|
defaultHeight: 768,
|
|
450
499
|
steps: "fixed",
|
|
@@ -456,12 +505,15 @@ const models = Object.freeze([
|
|
|
456
505
|
}),
|
|
457
506
|
freezeModel({
|
|
458
507
|
id: "@cf/black-forest-labs/flux-2-dev",
|
|
508
|
+
// Workers AI documents no prompt maxLength for this model; keep the 2,048 host cap.
|
|
509
|
+
maxPromptLength: UNDOCUMENTED_PROMPT_LENGTH,
|
|
459
510
|
tier: "max",
|
|
460
511
|
label: "Flux 2 Dev — best detailed quality, expensive",
|
|
461
512
|
input: {
|
|
462
513
|
transport: "multipart",
|
|
463
514
|
dimensions: "own",
|
|
464
515
|
maxDimension: 1920,
|
|
516
|
+
maxDimensionDocumented: false,
|
|
465
517
|
defaultWidth: 1024,
|
|
466
518
|
defaultHeight: 768,
|
|
467
519
|
steps: "steps",
|
|
@@ -473,12 +525,16 @@ const models = Object.freeze([
|
|
|
473
525
|
}),
|
|
474
526
|
freezeModel({
|
|
475
527
|
id: "@cf/leonardo/lucid-origin",
|
|
528
|
+
// Workers AI documents no prompt maxLength for this model; keep the 2,048 host cap.
|
|
529
|
+
maxPromptLength: UNDOCUMENTED_PROMPT_LENGTH,
|
|
476
530
|
tier: "premium",
|
|
477
531
|
label: "Leonardo Lucid Origin — premium prompt adherence",
|
|
478
532
|
input: {
|
|
479
533
|
transport: "json",
|
|
480
534
|
dimensions: "own",
|
|
535
|
+
// https://developers.cloudflare.com/workers-ai/models/lucid-origin/ (width/height maximum)
|
|
481
536
|
maxDimension: 2500,
|
|
537
|
+
maxDimensionDocumented: true,
|
|
482
538
|
defaultWidth: 1120,
|
|
483
539
|
defaultHeight: 1120,
|
|
484
540
|
steps: "num_steps",
|
|
@@ -490,12 +546,16 @@ const models = Object.freeze([
|
|
|
490
546
|
}),
|
|
491
547
|
freezeModel({
|
|
492
548
|
id: "@cf/leonardo/phoenix-1.0",
|
|
549
|
+
// Workers AI documents no prompt maxLength for this model; keep the 2,048 host cap.
|
|
550
|
+
maxPromptLength: UNDOCUMENTED_PROMPT_LENGTH,
|
|
493
551
|
tier: "balanced",
|
|
494
552
|
label: "Leonardo Phoenix 1.0 — best prompt adherence",
|
|
495
553
|
input: {
|
|
496
554
|
transport: "json",
|
|
497
555
|
dimensions: "own",
|
|
556
|
+
// https://developers.cloudflare.com/workers-ai/models/phoenix-1.0/ (width/height range)
|
|
498
557
|
maxDimension: 2048,
|
|
558
|
+
maxDimensionDocumented: true,
|
|
499
559
|
defaultWidth: 1024,
|
|
500
560
|
defaultHeight: 1024,
|
|
501
561
|
steps: "num_steps",
|
|
@@ -509,6 +569,8 @@ const models = Object.freeze([
|
|
|
509
569
|
// image model and ByteDance's video model return a result URL, not bytes.
|
|
510
570
|
freezeModel({
|
|
511
571
|
id: "openai/gpt-image-2",
|
|
572
|
+
// 32,000 characters: OpenAI's Images API reference gives GPT image models a 32000-character prompt limit.
|
|
573
|
+
maxPromptLength: 32_000,
|
|
512
574
|
outputFormats: Object.freeze(["png", "jpeg", "webp"]),
|
|
513
575
|
tier: "premium",
|
|
514
576
|
label: "GPT Image 2 — strong text and layout, premium",
|
|
@@ -517,13 +579,19 @@ const models = Object.freeze([
|
|
|
517
579
|
transport: "json",
|
|
518
580
|
dimensions: "own",
|
|
519
581
|
maxDimension: 1536,
|
|
582
|
+
maxDimensionDocumented: false,
|
|
520
583
|
defaultWidth: 1024,
|
|
521
584
|
defaultHeight: 1024,
|
|
522
585
|
steps: "fixed",
|
|
523
586
|
maxSteps: null,
|
|
524
587
|
defaultSteps: null,
|
|
525
|
-
|
|
526
|
-
|
|
588
|
+
// Cloudflare documents `images[]` (base64 strings or data URIs, 1-16
|
|
589
|
+
// entries, routed to OpenAI's /v1/images/edits) for this exact model:
|
|
590
|
+
// https://developers.cloudflare.com/ai/models/openai/gpt-image-2/
|
|
591
|
+
// OpenAI's own page shows multipart `image[]` without stating a cap, so
|
|
592
|
+
// 16 is Cloudflare's published schema limit, the route Prints calls.
|
|
593
|
+
referenceField: "images",
|
|
594
|
+
maxReferences: 16,
|
|
527
595
|
},
|
|
528
596
|
}),
|
|
529
597
|
videoModel(mediaVideoModelIdSchema.enum.seedance, "Seedance 2.0", "balanced", "seedance", [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { VideoProviderAdapter } from "./types.js";
|
|
2
2
|
/** MiniMax's documented `content[]` image role, distinct from our neutral one. */
|
|
3
|
-
export type MinimaxReferenceRole = "first_frame" | "
|
|
3
|
+
export type MinimaxReferenceRole = "first_frame" | "reference_image";
|
|
4
4
|
/** One MiniMax `content[]` entry, exactly as its schema documents it. */
|
|
5
5
|
export type MinimaxContentItem = {
|
|
6
6
|
type: "text";
|
|
@@ -13,7 +13,6 @@ const minimaxResolutionWire = {
|
|
|
13
13
|
/** Our neutral reference role to MiniMax's documented `content[]` role. */
|
|
14
14
|
const minimaxRoleWire = {
|
|
15
15
|
"first-frame": "first_frame",
|
|
16
|
-
"last-frame": "last_frame",
|
|
17
16
|
reference: "reference_image",
|
|
18
17
|
};
|
|
19
18
|
/** MiniMax's documented task wrapper: `{task: {status, content: {url}}}`,
|
|
@@ -34,7 +33,9 @@ export const minimaxVideoAdapter = {
|
|
|
34
33
|
];
|
|
35
34
|
references.forEach((image, index) => {
|
|
36
35
|
const role = checked.references?.[index]?.role;
|
|
37
|
-
const wireRole = role === undefined
|
|
36
|
+
const wireRole = role === undefined || role === "last-frame"
|
|
37
|
+
? undefined
|
|
38
|
+
: minimaxRoleWire[role];
|
|
38
39
|
if (wireRole === undefined)
|
|
39
40
|
throw new MediaSettingsError("video reference role was not admitted");
|
|
40
41
|
content.push({
|
|
@@ -31,6 +31,7 @@ const mediaModelsSchema: ZodLazy<ZodArray<ZodReadonly<ZodObject<{
|
|
|
31
31
|
jpeg: "jpeg";
|
|
32
32
|
webp: "webp";
|
|
33
33
|
}>>>;
|
|
34
|
+
maxPromptLength: ZodNumber;
|
|
34
35
|
input: ZodLazy<ZodReadonly<ZodObject<{
|
|
35
36
|
transport: ZodEnum<{
|
|
36
37
|
json: ...;
|
|
@@ -64,7 +65,6 @@ const mediaModelsSchema: ZodLazy<ZodArray<ZodReadonly<ZodObject<{
|
|
|
64
65
|
defaultResolution: ZodEnum<...>;
|
|
65
66
|
defaultAspectRatio: ZodEnum<...>;
|
|
66
67
|
defaultGenerateAudio: ZodNullable<...>;
|
|
67
|
-
maxPromptLength: ZodNumber;
|
|
68
68
|
referenceRoles: ZodReadonly<...>;
|
|
69
69
|
maxReferenceImages: ZodNumber;
|
|
70
70
|
referenceResolutions: ZodReadonly<...>;
|
|
@@ -367,6 +367,7 @@ const appMediaModelsOutcomeSchema: ZodUnion<readonly [ZodLazy<ZodArray<ZodReadon
|
|
|
367
367
|
jpeg: ...;
|
|
368
368
|
webp: ...;
|
|
369
369
|
}>>>;
|
|
370
|
+
maxPromptLength: ZodNumber;
|
|
370
371
|
input: ZodLazy<ZodReadonly<ZodObject<{
|
|
371
372
|
transport: ...;
|
|
372
373
|
dimensions: ...;
|
package/docs/api/browser.md
CHANGED
|
@@ -156,3 +156,9 @@ Read and decode one Media host failure at the browser HTTP boundary.
|
|
|
156
156
|
`"AiInternalError"` \| `"TypeError"` \| `"AbortError"` \| `"TimeoutError"` \|
|
|
157
157
|
`"Error"`; `code`: `number` \| `null`; \}\> \| `Readonly`\<\{ `category`:
|
|
158
158
|
`"result_download"`; `status`: `number`; \}\>; \} \| `null`\>
|
|
159
|
+
|
|
160
|
+
## References
|
|
161
|
+
|
|
162
|
+
### MAX\_MEDIA\_PROMPT\_LENGTH
|
|
163
|
+
|
|
164
|
+
Re-exports [MAX_MEDIA_PROMPT_LENGTH](index.md#max_media_prompt_length)
|
package/docs/api/index.md
CHANGED
|
@@ -1101,7 +1101,6 @@ const mediaVideoSchema: ZodLazy<ZodReadonly<ZodObject<{
|
|
|
1101
1101
|
ultratall: "9:21";
|
|
1102
1102
|
}>;
|
|
1103
1103
|
defaultGenerateAudio: ZodNullable<ZodBoolean>;
|
|
1104
|
-
maxPromptLength: ZodNumber;
|
|
1105
1104
|
referenceRoles: ZodReadonly<ZodArray<ZodEnum<{
|
|
1106
1105
|
first: "first-frame";
|
|
1107
1106
|
last: "last-frame";
|
|
@@ -1133,6 +1132,17 @@ Verified video parameters and provider costs, checked 2026-10-11.
|
|
|
1133
1132
|
|
|
1134
1133
|
---
|
|
1135
1134
|
|
|
1135
|
+
### MAX\_MEDIA\_PROMPT\_LENGTH
|
|
1136
|
+
|
|
1137
|
+
```ts
|
|
1138
|
+
const MAX_MEDIA_PROMPT_LENGTH: 32000 = 32_000;
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
Structural ceiling for any prompt on the wire. Each model's own
|
|
1142
|
+
`maxPromptLength` is the real bound; no model may exceed this ceiling.
|
|
1143
|
+
|
|
1144
|
+
---
|
|
1145
|
+
|
|
1136
1146
|
### mediaModelSchema
|
|
1137
1147
|
|
|
1138
1148
|
```ts
|
|
@@ -1154,6 +1164,7 @@ const mediaModelSchema: ZodReadonly<ZodObject<{
|
|
|
1154
1164
|
jpeg: "jpeg";
|
|
1155
1165
|
webp: "webp";
|
|
1156
1166
|
}>>>;
|
|
1167
|
+
maxPromptLength: ZodNumber;
|
|
1157
1168
|
input: ZodLazy<ZodReadonly<ZodObject<{
|
|
1158
1169
|
transport: ZodEnum<{
|
|
1159
1170
|
json: "json";
|
|
@@ -1205,7 +1216,6 @@ const mediaModelSchema: ZodReadonly<ZodObject<{
|
|
|
1205
1216
|
ultratall: "9:21";
|
|
1206
1217
|
}>;
|
|
1207
1218
|
defaultGenerateAudio: ZodNullable<ZodBoolean>;
|
|
1208
|
-
maxPromptLength: ZodNumber;
|
|
1209
1219
|
referenceRoles: ZodReadonly<ZodArray<ZodEnum<...>>>;
|
|
1210
1220
|
maxReferenceImages: ZodNumber;
|
|
1211
1221
|
referenceResolutions: ZodReadonly<ZodArray<ZodEnum<...>>>;
|
|
@@ -1290,19 +1300,19 @@ Validate caller settings and apply retained model defaults.
|
|
|
1290
1300
|
|
|
1291
1301
|
#### Parameters
|
|
1292
1302
|
|
|
1293
|
-
| Parameter | Type | Description
|
|
1294
|
-
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1295
|
-
| `raw` | \{ `model`: `string`; `prompt`: `string`; `width`: `number`; `height`: `number`; `steps?`: `number`; `durationSeconds?`: `number`; `resolution?`: `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio?`: `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `generateAudio?`: `boolean`; `references?`: `object`[]; \} | -
|
|
1296
|
-
| `raw.model` | `string` | Provider catalog model identifier.
|
|
1297
|
-
| `raw.prompt` | `string` | Generation prompt.
|
|
1298
|
-
| `raw.width` | `number` | Requested image width or nominal video selector, not decoded MP4 dimensions.
|
|
1299
|
-
| `raw.height` | `number` | Requested image height or nominal video selector, not decoded MP4 dimensions.
|
|
1300
|
-
| `raw.steps?` | `number` | Model-specific inference step count.
|
|
1301
|
-
| `raw.durationSeconds?` | `number` | Requested video length in whole seconds.
|
|
1302
|
-
| `raw.resolution?` | `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"` | Video resolution; must match the nominal width/height selector.
|
|
1303
|
-
| `raw.aspectRatio?` | `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"` | Video aspect; must match the nominal width/height selector.
|
|
1304
|
-
| `raw.generateAudio?` | `boolean` | Video audio selection.
|
|
1305
|
-
| `raw.references?` | `object`[] | Host-authorized reference images.
|
|
1303
|
+
| Parameter | Type | Description |
|
|
1304
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
1305
|
+
| `raw` | \{ `model`: `string`; `prompt`: `string`; `width`: `number`; `height`: `number`; `steps?`: `number`; `durationSeconds?`: `number`; `resolution?`: `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio?`: `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `generateAudio?`: `boolean`; `references?`: `object`[]; \} | - |
|
|
1306
|
+
| `raw.model` | `string` | Provider catalog model identifier. |
|
|
1307
|
+
| `raw.prompt` | `string` | Generation prompt; each model's `maxPromptLength` is enforced on top of this ceiling. |
|
|
1308
|
+
| `raw.width` | `number` | Requested image width or nominal video selector, not decoded MP4 dimensions. |
|
|
1309
|
+
| `raw.height` | `number` | Requested image height or nominal video selector, not decoded MP4 dimensions. |
|
|
1310
|
+
| `raw.steps?` | `number` | Model-specific inference step count. |
|
|
1311
|
+
| `raw.durationSeconds?` | `number` | Requested video length in whole seconds. |
|
|
1312
|
+
| `raw.resolution?` | `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"` | Video resolution; must match the nominal width/height selector. |
|
|
1313
|
+
| `raw.aspectRatio?` | `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"` | Video aspect; must match the nominal width/height selector. |
|
|
1314
|
+
| `raw.generateAudio?` | `boolean` | Video audio selection. |
|
|
1315
|
+
| `raw.references?` | `object`[] | Host-authorized reference images. |
|
|
1306
1316
|
|
|
1307
1317
|
#### Returns
|
|
1308
1318
|
|
|
@@ -1322,19 +1332,19 @@ Validate path-only selections without inventing a Computer identity.
|
|
|
1322
1332
|
|
|
1323
1333
|
#### Parameters
|
|
1324
1334
|
|
|
1325
|
-
| Parameter | Type | Description
|
|
1326
|
-
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1327
|
-
| `raw` | \{ `model`: `string`; `prompt`: `string`; `width`: `number`; `height`: `number`; `steps?`: `number`; `durationSeconds?`: `number`; `resolution?`: `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio?`: `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `generateAudio?`: `boolean`; `references?`: `object`[]; \} | -
|
|
1328
|
-
| `raw.model` | `string` | Provider catalog model identifier.
|
|
1329
|
-
| `raw.prompt` | `string` | Generation prompt.
|
|
1330
|
-
| `raw.width` | `number` | Requested image width or nominal video selector, not decoded MP4 dimensions.
|
|
1331
|
-
| `raw.height` | `number` | Requested image height or nominal video selector, not decoded MP4 dimensions.
|
|
1332
|
-
| `raw.steps?` | `number` | Model-specific inference step count.
|
|
1333
|
-
| `raw.durationSeconds?` | `number` | Requested video length in whole seconds.
|
|
1334
|
-
| `raw.resolution?` | `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"` | Video resolution; must match the nominal width/height selector.
|
|
1335
|
-
| `raw.aspectRatio?` | `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"` | Video aspect; must match the nominal width/height selector.
|
|
1336
|
-
| `raw.generateAudio?` | `boolean` | Video audio selection.
|
|
1337
|
-
| `raw.references?` | `object`[] | Host-authorized reference images.
|
|
1335
|
+
| Parameter | Type | Description |
|
|
1336
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
1337
|
+
| `raw` | \{ `model`: `string`; `prompt`: `string`; `width`: `number`; `height`: `number`; `steps?`: `number`; `durationSeconds?`: `number`; `resolution?`: `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio?`: `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `generateAudio?`: `boolean`; `references?`: `object`[]; \} | - |
|
|
1338
|
+
| `raw.model` | `string` | Provider catalog model identifier. |
|
|
1339
|
+
| `raw.prompt` | `string` | Generation prompt; each model's `maxPromptLength` is enforced on top of this ceiling. |
|
|
1340
|
+
| `raw.width` | `number` | Requested image width or nominal video selector, not decoded MP4 dimensions. |
|
|
1341
|
+
| `raw.height` | `number` | Requested image height or nominal video selector, not decoded MP4 dimensions. |
|
|
1342
|
+
| `raw.steps?` | `number` | Model-specific inference step count. |
|
|
1343
|
+
| `raw.durationSeconds?` | `number` | Requested video length in whole seconds. |
|
|
1344
|
+
| `raw.resolution?` | `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"` | Video resolution; must match the nominal width/height selector. |
|
|
1345
|
+
| `raw.aspectRatio?` | `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"` | Video aspect; must match the nominal width/height selector. |
|
|
1346
|
+
| `raw.generateAudio?` | `boolean` | Video audio selection. |
|
|
1347
|
+
| `raw.references?` | `object`[] | Host-authorized reference images. |
|
|
1338
1348
|
|
|
1339
1349
|
#### Returns
|
|
1340
1350
|
|
|
@@ -1358,7 +1368,7 @@ or billing admission.
|
|
|
1358
1368
|
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
1359
1369
|
| `raw` | \{ `model`: \| `"bytedance/seedance-2.0"` \| `"bytedance/seedance-2.0-fast"` \| `"bytedance/seedance-2.0-mini"` \| `"google/veo-3.1"` \| `"google/veo-3.1-fast"` \| `"minimax/h3-max"`; `prompt`: `string`; `resolution?`: `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio?`: `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `durationSeconds?`: `number`; `generateAudio?`: `boolean`; `references?`: `object`[]; \} | - |
|
|
1360
1370
|
| `raw.model` | \| `"bytedance/seedance-2.0"` \| `"bytedance/seedance-2.0-fast"` \| `"bytedance/seedance-2.0-mini"` \| `"google/veo-3.1"` \| `"google/veo-3.1-fast"` \| `"minimax/h3-max"` | Verified catalog model identifier. |
|
|
1361
|
-
| `raw.prompt` | `string` | Trimmed prompt;
|
|
1371
|
+
| `raw.prompt` | `string` | Trimmed prompt; the selected model's `maxPromptLength` is enforced on top of this ceiling. |
|
|
1362
1372
|
| `raw.resolution?` | `"480p"` \| `"720p"` \| `"768p"` \| `"1080p"` \| `"4k"` | Model-specific resolution, default 720p. |
|
|
1363
1373
|
| `raw.aspectRatio?` | `"16:9"` \| `"4:3"` \| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"` | Model-specific aspect, default 16:9. |
|
|
1364
1374
|
| `raw.durationSeconds?` | `number` | Whole seconds; Seedance 4–12, Veo exactly 4/6/8, MiniMax H3 Max 5–15. |
|
|
@@ -1531,6 +1541,7 @@ function listMediaModels(): readonly Readonly<{
|
|
|
1531
1541
|
kind: "image" | "video";
|
|
1532
1542
|
tier: "draft" | "balanced" | "premium" | "max";
|
|
1533
1543
|
outputFormats: readonly ("png" | "jpeg" | "webp")[];
|
|
1544
|
+
maxPromptLength: number;
|
|
1534
1545
|
input: Readonly<{
|
|
1535
1546
|
transport: "json" | "multipart";
|
|
1536
1547
|
dimensions: "none" | "own";
|
|
@@ -1560,7 +1571,6 @@ function listMediaModels(): readonly Readonly<{
|
|
|
1560
1571
|
defaultAspectRatio:
|
|
1561
1572
|
"16:9" | "4:3" | "1:1" | "3:4" | "9:16" | "21:9" | "9:21";
|
|
1562
1573
|
defaultGenerateAudio: boolean | null;
|
|
1563
|
-
maxPromptLength: number;
|
|
1564
1574
|
referenceRoles: readonly ("first-frame" | "last-frame" | "reference")[];
|
|
1565
1575
|
maxReferenceImages: number;
|
|
1566
1576
|
referenceResolutions: readonly (
|
|
@@ -1581,26 +1591,26 @@ List all image and video models in catalog order.
|
|
|
1581
1591
|
|
|
1582
1592
|
readonly `Readonly`\<\{ `id`: `string`; `label`: `string`; `kind`: `"image"` \|
|
|
1583
1593
|
`"video"`; `tier`: `"draft"` \| `"balanced"` \| `"premium"` \| `"max"`;
|
|
1584
|
-
`outputFormats`: readonly (`"png"` \| `"jpeg"` \| `"webp"`)[];
|
|
1585
|
-
`
|
|
1586
|
-
`"
|
|
1587
|
-
`defaultHeight`: `number`; `steps`: `"steps"`
|
|
1588
|
-
|
|
1589
|
-
`referenceField`: `string` \| `null`; `maxReferences`:
|
|
1590
|
-
readonly `string`[] \| `null`; `video`: \|
|
|
1591
|
-
`
|
|
1592
|
-
readonly `number`[]; `provider`: `"seedance"` \| `"veo"`
|
|
1593
|
-
`formats`: readonly `Readonly`\<\{ `resolution`: `"480p"` \|
|
|
1594
|
-
`"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio`: `"16:9"` \| `"4:3"`
|
|
1595
|
-
\| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `width`: `number`;
|
|
1596
|
-
`number`; \}\>[]; `defaultResolution`: `"480p"` \| `"720p"` \|
|
|
1597
|
-
`"1080p"` \| `"4k"`; `defaultAspectRatio`: `"16:9"` \| `"4:3"` \|
|
|
1598
|
-
`"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `defaultGenerateAudio`:
|
|
1599
|
-
\| `null`; `
|
|
1600
|
-
|
|
1601
|
-
`
|
|
1602
|
-
|
|
1603
|
-
|
|
1594
|
+
`outputFormats`: readonly (`"png"` \| `"jpeg"` \| `"webp"`)[];
|
|
1595
|
+
`maxPromptLength`: `number`; `input`: `Readonly`\<\{ `transport`: `"json"` \|
|
|
1596
|
+
`"multipart"`; `dimensions`: `"none"` \| `"own"`; `maxDimension`: `number` \|
|
|
1597
|
+
`null`; `defaultWidth`: `number`; `defaultHeight`: `number`; `steps`: `"steps"`
|
|
1598
|
+
\| `"num_steps"` \| `"fixed"`; `maxSteps`: `number` \| `null`; `defaultSteps`:
|
|
1599
|
+
`number` \| `null`; `referenceField`: `string` \| `null`; `maxReferences`:
|
|
1600
|
+
`number`; \}\>; `sizes`: readonly `string`[] \| `null`; `video`: \|
|
|
1601
|
+
`Readonly`\<\{ `minSeconds`: `number`; `maxSeconds`: `number`; `defaultSeconds`:
|
|
1602
|
+
`number`; `durations`: readonly `number`[]; `provider`: `"seedance"` \| `"veo"`
|
|
1603
|
+
\| `"minimax"`; `formats`: readonly `Readonly`\<\{ `resolution`: `"480p"` \|
|
|
1604
|
+
`"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio`: `"16:9"` \| `"4:3"`
|
|
1605
|
+
\| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `width`: `number`;
|
|
1606
|
+
`height`: `number`; \}\>[]; `defaultResolution`: `"480p"` \| `"720p"` \|
|
|
1607
|
+
`"768p"` \| `"1080p"` \| `"4k"`; `defaultAspectRatio`: `"16:9"` \| `"4:3"` \|
|
|
1608
|
+
`"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `defaultGenerateAudio`:
|
|
1609
|
+
`boolean` \| `null`; `referenceRoles`: readonly (`"first-frame"` \|
|
|
1610
|
+
`"last-frame"` \| `"reference"`)[]; `maxReferenceImages`: `number`;
|
|
1611
|
+
`referenceResolutions`: readonly (`"480p"` \| `"720p"` \| `"768p"` \| `"1080p"`
|
|
1612
|
+
\| `"4k"`)[]; `prices`: readonly `Readonly`\<\{ `resolution`: `"480p"` \|
|
|
1613
|
+
`"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `silentMilliunitsPerSecond`:
|
|
1604
1614
|
`number`; `audioMilliunitsPerSecond`: `number`; \}\>[]; \}\> \| `null`; \}\>[]
|
|
1605
1615
|
|
|
1606
1616
|
---
|
|
@@ -1615,6 +1625,7 @@ function getMediaModel(id):
|
|
|
1615
1625
|
kind: "image" | "video";
|
|
1616
1626
|
tier: "draft" | "balanced" | "premium" | "max";
|
|
1617
1627
|
outputFormats: readonly ("png" | "jpeg" | "webp")[];
|
|
1628
|
+
maxPromptLength: number;
|
|
1618
1629
|
input: Readonly<{
|
|
1619
1630
|
transport: "json" | "multipart";
|
|
1620
1631
|
dimensions: "none" | "own";
|
|
@@ -1645,7 +1656,6 @@ function getMediaModel(id):
|
|
|
1645
1656
|
defaultAspectRatio:
|
|
1646
1657
|
"16:9" | "4:3" | "1:1" | "3:4" | "9:16" | "21:9" | "9:21";
|
|
1647
1658
|
defaultGenerateAudio: boolean | null;
|
|
1648
|
-
maxPromptLength: number;
|
|
1649
1659
|
referenceRoles: readonly ("first-frame" | "last-frame" | "reference")[];
|
|
1650
1660
|
maxReferenceImages: number;
|
|
1651
1661
|
referenceResolutions: readonly (
|
|
@@ -1673,26 +1683,26 @@ Find a model by provider identifier, returning undefined when it is absent.
|
|
|
1673
1683
|
|
|
1674
1684
|
\| `Readonly`\<\{ `id`: `string`; `label`: `string`; `kind`: `"image"` \|
|
|
1675
1685
|
`"video"`; `tier`: `"draft"` \| `"balanced"` \| `"premium"` \| `"max"`;
|
|
1676
|
-
`outputFormats`: readonly (`"png"` \| `"jpeg"` \| `"webp"`)[];
|
|
1677
|
-
`
|
|
1678
|
-
`"
|
|
1679
|
-
`defaultHeight`: `number`; `steps`: `"steps"`
|
|
1680
|
-
|
|
1681
|
-
`referenceField`: `string` \| `null`; `maxReferences`:
|
|
1682
|
-
readonly `string`[] \| `null`; `video`: \|
|
|
1683
|
-
`
|
|
1684
|
-
readonly `number`[]; `provider`: `"seedance"` \| `"veo"`
|
|
1685
|
-
`formats`: readonly `Readonly`\<\{ `resolution`: `"480p"` \|
|
|
1686
|
-
`"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio`: `"16:9"` \| `"4:3"`
|
|
1687
|
-
\| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `width`: `number`;
|
|
1688
|
-
`number`; \}\>[]; `defaultResolution`: `"480p"` \| `"720p"` \|
|
|
1689
|
-
`"1080p"` \| `"4k"`; `defaultAspectRatio`: `"16:9"` \| `"4:3"` \|
|
|
1690
|
-
`"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `defaultGenerateAudio`:
|
|
1691
|
-
\| `null`; `
|
|
1692
|
-
|
|
1693
|
-
`
|
|
1694
|
-
|
|
1695
|
-
|
|
1686
|
+
`outputFormats`: readonly (`"png"` \| `"jpeg"` \| `"webp"`)[];
|
|
1687
|
+
`maxPromptLength`: `number`; `input`: `Readonly`\<\{ `transport`: `"json"` \|
|
|
1688
|
+
`"multipart"`; `dimensions`: `"none"` \| `"own"`; `maxDimension`: `number` \|
|
|
1689
|
+
`null`; `defaultWidth`: `number`; `defaultHeight`: `number`; `steps`: `"steps"`
|
|
1690
|
+
\| `"num_steps"` \| `"fixed"`; `maxSteps`: `number` \| `null`; `defaultSteps`:
|
|
1691
|
+
`number` \| `null`; `referenceField`: `string` \| `null`; `maxReferences`:
|
|
1692
|
+
`number`; \}\>; `sizes`: readonly `string`[] \| `null`; `video`: \|
|
|
1693
|
+
`Readonly`\<\{ `minSeconds`: `number`; `maxSeconds`: `number`; `defaultSeconds`:
|
|
1694
|
+
`number`; `durations`: readonly `number`[]; `provider`: `"seedance"` \| `"veo"`
|
|
1695
|
+
\| `"minimax"`; `formats`: readonly `Readonly`\<\{ `resolution`: `"480p"` \|
|
|
1696
|
+
`"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `aspectRatio`: `"16:9"` \| `"4:3"`
|
|
1697
|
+
\| `"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `width`: `number`;
|
|
1698
|
+
`height`: `number`; \}\>[]; `defaultResolution`: `"480p"` \| `"720p"` \|
|
|
1699
|
+
`"768p"` \| `"1080p"` \| `"4k"`; `defaultAspectRatio`: `"16:9"` \| `"4:3"` \|
|
|
1700
|
+
`"1:1"` \| `"3:4"` \| `"9:16"` \| `"21:9"` \| `"9:21"`; `defaultGenerateAudio`:
|
|
1701
|
+
`boolean` \| `null`; `referenceRoles`: readonly (`"first-frame"` \|
|
|
1702
|
+
`"last-frame"` \| `"reference"`)[]; `maxReferenceImages`: `number`;
|
|
1703
|
+
`referenceResolutions`: readonly (`"480p"` \| `"720p"` \| `"768p"` \| `"1080p"`
|
|
1704
|
+
\| `"4k"`)[]; `prices`: readonly `Readonly`\<\{ `resolution`: `"480p"` \|
|
|
1705
|
+
`"720p"` \| `"768p"` \| `"1080p"` \| `"4k"`; `silentMilliunitsPerSecond`:
|
|
1696
1706
|
`number`; `audioMilliunitsPerSecond`: `number`; \}\>[]; \}\> \| `null`; \}\> \|
|
|
1697
1707
|
`undefined`
|
|
1698
1708
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fungi.computer/darkroom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"author": "Levi <levi@technomancy.dev>",
|
|
5
5
|
"description": "Media generation, durable output retention and provenance with host-owned authority and billing",
|
|
6
6
|
"type": "module",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"exifreader": "4.46.0",
|
|
60
60
|
"@fungi.computer/ts-webp": "0.1.6",
|
|
61
61
|
"@xmldom/xmldom": "0.9.12",
|
|
62
|
-
"@fungi.computer/agar": "0.
|
|
62
|
+
"@fungi.computer/agar": "0.4.0",
|
|
63
63
|
"@fungi.computer/capnweb": "0.12.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|