@shop-os/modelkit 0.1.7 → 0.1.9

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.
@@ -0,0 +1,479 @@
1
+ import { ImageModel, experimental_generateVideo } from 'ai';
2
+
3
+ /**
4
+ * Canonical vocabulary shared by every adapter. Adapters translate these
5
+ * values to provider field names and casing; callers never do.
6
+ */
7
+
8
+ /** The AI SDK video model spelling: a catalog id or a provider video model instance. */
9
+ type VideoModel = Parameters<typeof experimental_generateVideo>[0]["model"];
10
+ type AspectRatio = "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "4:5" | "5:4" | "21:9" | "9:21" | "97:30" | "adaptive";
11
+ type ImageSize = "512" | "1K" | "2K" | "4K";
12
+ type VideoResolution = "360p" | "480p" | "720p" | "768p" | "1080p" | "2k" | "4k";
13
+ /** "xhigh" and "max" exist only on gpt-image-2.5; gpt-image-2 rejects them at the provider. */
14
+ type ImageQuality = "auto" | "low" | "medium" | "high" | "xhigh" | "max";
15
+ type OutputFormat = "png" | "jpeg" | "webp";
16
+ /**
17
+ * A media input. `label` is a caption the adapter emits as a text part right
18
+ * before the media where the provider takes interleaved content (Gemini image,
19
+ * Omni), so a prompt can address "Image 2" or "the brand logo" by name.
20
+ */
21
+ type MediaRef = {
22
+ url: string;
23
+ label?: string;
24
+ } | {
25
+ bytes: Uint8Array;
26
+ mime: string;
27
+ label?: string;
28
+ };
29
+ /** Caller-driven Topaz upscale controls; see the topaz row and TopazImageInput. */
30
+ interface UpscaleOptions {
31
+ enhanceModel?: string;
32
+ subjectDetection?: string;
33
+ faceEnhancement?: boolean;
34
+ faceEnhancementCreativity?: number;
35
+ faceEnhancementStrength?: number;
36
+ }
37
+ type ModelType = "text" | "image" | "video" | "audio" | "upscale" | "bg-remove";
38
+ type Lifecycle = "active" | "hidden" | "deprecated" | "retired";
39
+ type AdapterId = "ai-sdk-text" | "google-image" | "openai-image" | "google-genai" | "ark" | "fal" | "replicate" | "prodia" | "higgsfield" | "xai-video";
40
+ /** Gemini image safety threshold, per category, sent only when the caller opts in. */
41
+ type ImageSafetySetting = {
42
+ category: string;
43
+ threshold: string;
44
+ };
45
+ interface ImageRequest {
46
+ model: string;
47
+ prompt: string;
48
+ references?: MediaRef[];
49
+ aspectRatio?: AspectRatio;
50
+ size?: ImageSize;
51
+ exactSize?: string;
52
+ quality?: ImageQuality;
53
+ seed?: number;
54
+ count?: number;
55
+ outputFormat?: OutputFormat;
56
+ /** Upscale factor for upscaler rows; adapters map it to the provider's field. */
57
+ scaleFactor?: number;
58
+ /** Gemini image safety thresholds. Off (provider default) unless supplied. */
59
+ safetySettings?: ImageSafetySetting[];
60
+ /** Sampling temperature where the provider exposes one for images (Gemini). */
61
+ temperature?: number;
62
+ /** Upscaler controls beyond `scaleFactor`/`outputFormat` (Topaz). */
63
+ upscale?: UpscaleOptions;
64
+ }
65
+ /**
66
+ * What a caller passes to generateImage. Same field names as the AI SDK's
67
+ * generateImage where the concept matches: `n`, `size` as `WxH`, `abortSignal`,
68
+ * `providerOptions`. The model is a catalog id or alias, or an AI SDK image
69
+ * model instance that runs through the SDK unchanged.
70
+ */
71
+ interface ImageCallOptions extends Omit<ImageRequest, "model" | "size"> {
72
+ model: ImageModel;
73
+ /** Alias of `count`. */
74
+ n?: number;
75
+ /** Catalog tier or an exact `WxH` size (alias of `exactSize`). */
76
+ size?: ImageSize | `${number}x${number}`;
77
+ abortSignal?: AbortSignal;
78
+ /** Reaches the provider only for AI SDK model instances; catalog rows carry their own. */
79
+ providerOptions?: ProviderOptions;
80
+ }
81
+ interface VideoRequest {
82
+ model: string;
83
+ prompt: string;
84
+ firstFrame?: MediaRef;
85
+ lastFrame?: MediaRef;
86
+ sourceVideo?: MediaRef;
87
+ referenceImages?: MediaRef[];
88
+ referenceVideos?: MediaRef[];
89
+ referenceAudios?: MediaRef[];
90
+ aspectRatio?: AspectRatio;
91
+ resolution?: VideoResolution;
92
+ durationSeconds?: number;
93
+ generateAudio?: boolean;
94
+ seed?: number;
95
+ negativePrompt?: string;
96
+ cfgScale?: number;
97
+ promptExpansion?: "fast" | "balanced" | "quality";
98
+ /** Provider watermark toggle (Seedance). */
99
+ watermark?: boolean;
100
+ /** Provider-side safety checker toggle (fal MiniMax). Provider default when unset. */
101
+ safetyChecker?: boolean;
102
+ mode?: "standard" | "pro";
103
+ }
104
+ /**
105
+ * What a caller passes to generateVideo. `duration` is the AI SDK spelling of
106
+ * `durationSeconds`. An AI SDK video model instance runs through
107
+ * `experimental_generateVideo` and is exposed as a settled job.
108
+ */
109
+ interface VideoCallOptions extends Omit<VideoRequest, "model"> {
110
+ model: VideoModel;
111
+ /** Alias of `durationSeconds`. */
112
+ duration?: number;
113
+ abortSignal?: AbortSignal;
114
+ /** Reaches the provider only for AI SDK model instances; catalog rows carry their own. */
115
+ providerOptions?: ProviderOptions;
116
+ }
117
+ interface AudioRequest {
118
+ model: string;
119
+ prompt: string;
120
+ /** Lyria: optional reference image. MMAudio: the video to score. */
121
+ references?: MediaRef[];
122
+ sourceVideo?: MediaRef;
123
+ negativePrompt?: string;
124
+ durationSeconds?: number;
125
+ seed?: number;
126
+ /** Music models: no vocals. */
127
+ instrumental?: boolean;
128
+ /** Cancellation; combined with CallContext.signal before dispatch. */
129
+ abortSignal?: AbortSignal;
130
+ }
131
+ interface AudioResult {
132
+ audio: {
133
+ bytes: Uint8Array;
134
+ mime: string;
135
+ } | {
136
+ url: string;
137
+ expiresAt?: Date;
138
+ };
139
+ /** Lyria returns lyrics as text parts next to the audio. */
140
+ text?: string;
141
+ usage: UsageEvent;
142
+ raw?: JsonValue;
143
+ }
144
+ /** An AI SDK file part ready for generateText/generateObject, e.g. a video for understanding. */
145
+ interface MediaPart {
146
+ type: "file";
147
+ data: string | Uint8Array;
148
+ mediaType: string;
149
+ /** Set when the bytes were uploaded to a provider file store (Gemini Files API). Call `cleanup` after the request. */
150
+ cleanup?: () => Promise<void>;
151
+ }
152
+ type RequiredInput = "firstFrame" | "sourceVideo" | "references";
153
+ type SupportedOption = "seed" | "quality" | "negativePrompt" | "cfgScale" | "generateAudio" | "promptExpansion" | "lastFrame" | "count" | "outputFormat" | "scaleFactor" | "safetySettings" | "temperature" | "upscale" | "watermark" | "safetyChecker" | "instrumental";
154
+ interface ReferenceLimits {
155
+ images?: number;
156
+ videos?: number;
157
+ audios?: number;
158
+ total?: number;
159
+ /** Provider rejects a request whose only references are audio. */
160
+ audioOnly?: boolean;
161
+ }
162
+ interface ModelConstraints {
163
+ aspectRatios?: AspectRatio[];
164
+ sizes?: ImageSize[];
165
+ resolutions?: VideoResolution[];
166
+ durations?: {
167
+ min: number;
168
+ max: number;
169
+ } | number[];
170
+ /** Curated UI choices when `durations` is a range; `resolveOptions` ignores it. */
171
+ durationPresets?: number[];
172
+ /** Curated quality choices for rows whose `supports` includes "quality". */
173
+ qualityOptions?: string[];
174
+ /**
175
+ * Exact pixel size per aspect ratio for rows an app must size verbatim
176
+ * (gpt-image-2 keeps its historic WxH contract); callers pass it as `exactSize`.
177
+ */
178
+ exactSizes?: Record<string, string>;
179
+ references?: ReferenceLimits;
180
+ requires?: RequiredInput[];
181
+ supports?: SupportedOption[];
182
+ /** Ratio is dropped, with a warning, when one of these inputs is present. */
183
+ ratioIgnoredWith?: ("firstFrame" | "sourceVideo")[];
184
+ }
185
+ /** JSON-compatible value. Provider options and raw payloads carry these, never `unknown`. */
186
+ type JsonPrimitive = string | number | boolean | null;
187
+ type JsonValue = JsonPrimitive | JsonValue[] | {
188
+ [key: string]: JsonValue;
189
+ };
190
+ type JsonObject = {
191
+ [key: string]: JsonValue;
192
+ };
193
+ /**
194
+ * Options handed to the provider untouched, keyed by provider name like the AI SDK's
195
+ * providerOptions: { anthropic: { thinking: ... } }. Values are JSON without null.
196
+ */
197
+ type ProviderOptionValue = string | number | boolean | ProviderOptionValue[] | {
198
+ [key: string]: ProviderOptionValue;
199
+ };
200
+ type ProviderOptions = {
201
+ [provider: string]: {
202
+ [key: string]: ProviderOptionValue;
203
+ };
204
+ };
205
+ type UsageUnit = "tokens" | "images" | "seconds" | "reported_cost_usd" | "compute_seconds";
206
+ type UsageModality = "TEXT" | "IMAGE" | "VIDEO" | "AUDIO";
207
+ type PricingKind = "token" | "image_size" | "video_per_second" | "flat";
208
+ /** What a model picker shows for a row. Free of any surface-specific ids. */
209
+ interface CatalogDisplay {
210
+ /** Vendor as the UI names it: "google", "openai", "meta", "bytedance", "xai", "kuaishou", ... */
211
+ provider: string;
212
+ /** One or two sentences for the picker card. */
213
+ description: string;
214
+ /** CDN URL of the vendor or model logo. */
215
+ logo?: string;
216
+ /** Chat picker cost bucket: 1 = cheapest tier (Haiku/Flash/mini), 2 = Sonnet class, 3 = Opus/Pro/frontier. */
217
+ costTier?: 1 | 2 | 3;
218
+ /** Chat picker highlight flag. */
219
+ recommended?: boolean;
220
+ /**
221
+ * Picker position: lower comes first; rows without one keep catalog order
222
+ * after the ordered ones. Set it to surface a new model at the top.
223
+ */
224
+ sortOrder?: number;
225
+ }
226
+ /** Capability flags a UI keys off. Absent means false / unknown. */
227
+ interface CatalogCapabilities {
228
+ /** Image rows: generates from a prompt alone. */
229
+ imageGenerate?: boolean;
230
+ /** Image rows: edits or conditions on reference images. */
231
+ imageEdit?: boolean;
232
+ /** Video rows: takes an existing video as the thing to edit or extend. */
233
+ acceptsSourceVideo?: boolean;
234
+ /** Video rows: first/last frames and reference images are mutually exclusive inputs. */
235
+ framesExcludeReferences?: boolean;
236
+ /** Text rows. `reasoning`: the model streams reasoning the UI should surface. */
237
+ reasoning?: boolean;
238
+ vision?: boolean;
239
+ tools?: boolean;
240
+ structuredOutput?: boolean;
241
+ contextWindow?: number;
242
+ }
243
+ interface CatalogModel {
244
+ /** Canonical id. Equals the pricing key in pro-backend credit_pricing_* tables. */
245
+ id: string;
246
+ aliases: string[];
247
+ label: string;
248
+ type: ModelType;
249
+ adapter: AdapterId;
250
+ /** Id the provider expects, e.g. dola-seedream-5-0-pro-260628. */
251
+ providerModelId: string;
252
+ lifecycle: Lifecycle;
253
+ replacedBy?: string;
254
+ /**
255
+ * "catalog" = offered in product pickers (Creative Studio, chat, Space Builder);
256
+ * "internal" = callable by id only.
257
+ */
258
+ exposure: "catalog" | "internal";
259
+ constraints: ModelConstraints;
260
+ defaults: Partial<Omit<ImageRequest, "model" | "prompt"> & Omit<VideoRequest, "model" | "prompt"> & Omit<AudioRequest, "model" | "prompt"> & {
261
+ temperature?: number;
262
+ }>;
263
+ /** Provider options merged under the caller's; text rows carry their reasoning / thinking tuning here. */
264
+ providerOptions?: ProviderOptions;
265
+ /**
266
+ * `slug` and `providerLabel` keep an app's historic usage-event names for a
267
+ * row (e.g. cowork emits `image_gen_<slug>` from provider `<providerLabel>`);
268
+ * absent means the app derives them from the id and display.provider.
269
+ */
270
+ usage: {
271
+ unit: UsageUnit;
272
+ modality: UsageModality;
273
+ slug?: string;
274
+ providerLabel?: string;
275
+ };
276
+ pricingKind: PricingKind;
277
+ /** Required on every `active` row so a picker can render it without a hand-written catalog. */
278
+ display?: CatalogDisplay;
279
+ capabilities?: CatalogCapabilities;
280
+ }
281
+ interface Warning {
282
+ code: "ratio_coerced" | "ratio_dropped" | "size_coerced" | "resolution_coerced" | "duration_coerced" | "references_trimmed" | "option_ignored";
283
+ message: string;
284
+ field: string;
285
+ from?: unknown;
286
+ to?: unknown;
287
+ }
288
+ interface ImageBytes {
289
+ bytes: Uint8Array;
290
+ mime: string;
291
+ }
292
+ /** An image with the AI SDK `GeneratedFile` accessors next to the kit's `bytes`/`mime`. */
293
+ interface GeneratedImage extends ImageBytes {
294
+ readonly uint8Array: Uint8Array;
295
+ readonly base64: string;
296
+ readonly mediaType: string;
297
+ }
298
+ /** What an adapter returns. */
299
+ interface ImageResult {
300
+ images: ImageBytes[];
301
+ usage: UsageEvent;
302
+ raw?: unknown;
303
+ /** The provider URL the images were downloaded from, when the provider hands one back. */
304
+ outputUrl?: string;
305
+ }
306
+ /** What generateImage returns: the adapter result plus `image`, SDK accessors and warnings. */
307
+ interface ImageCallResult extends ImageResult {
308
+ image: GeneratedImage;
309
+ images: GeneratedImage[];
310
+ warnings: Warning[];
311
+ }
312
+ interface VideoResult {
313
+ video: {
314
+ url: string;
315
+ expiresAt?: Date;
316
+ } | {
317
+ bytes: Uint8Array;
318
+ mime: string;
319
+ };
320
+ usage: UsageEvent;
321
+ raw?: unknown;
322
+ }
323
+ interface VideoCallJob extends VideoJob {
324
+ warnings: Warning[];
325
+ }
326
+ interface VideoJob {
327
+ jobId: string;
328
+ poll(): Promise<{
329
+ status: "pending" | "running" | "succeeded" | "failed";
330
+ raw?: unknown;
331
+ }>;
332
+ result(opts?: {
333
+ pollIntervalMs?: number;
334
+ timeoutMs?: number;
335
+ signal?: AbortSignal;
336
+ }): Promise<VideoResult>;
337
+ }
338
+ interface UsageEvent {
339
+ /** Canonical catalog id, never the provider id. */
340
+ model: string;
341
+ provider: string;
342
+ modality: UsageModality;
343
+ unit: UsageUnit;
344
+ quantity: number;
345
+ imageSize?: ImageSize;
346
+ imageQuality?: ImageQuality;
347
+ resolution?: VideoResolution;
348
+ durationSeconds?: number;
349
+ inputTokens?: number;
350
+ outputTokens?: number;
351
+ reportedCostUsd?: number;
352
+ raw?: unknown;
353
+ }
354
+ type ProviderKeyName = "openai" | "anthropic" | "google" | "xai" | "perplexity" | "deepseek" | "moonshot" | "minimax" | "ark" | "fal" | "replicate" | "prodia" | "higgsfield" | "cloudflare";
355
+ type ProviderKeys = Partial<Record<ProviderKeyName, string>> & {
356
+ /** Higgsfield needs the pair; both switch together. */
357
+ higgsfieldSecret?: string;
358
+ /** Bedrock runtime credentials for Anthropic models when routing.anthropic = "bedrock". */
359
+ aws?: {
360
+ accessKeyId: string;
361
+ secretAccessKey: string;
362
+ region: string;
363
+ sessionToken?: string;
364
+ };
365
+ };
366
+ interface Routing {
367
+ /** Text models: direct provider or the Cloudflare AI Gateway. */
368
+ text?: "direct" | "cloudflare";
369
+ /** Anthropic chat via Bedrock (us. prefixed ids) or the Anthropic API. */
370
+ anthropic?: "direct" | "bedrock";
371
+ /** fal from geo-blocked regions goes through the Cloudflare passthrough. */
372
+ fal?: "direct" | "cloudflare-passthrough";
373
+ cloudflare?: {
374
+ accountId: string;
375
+ gatewayId: string;
376
+ };
377
+ }
378
+ /** Regional or proxy endpoints for providers whose base url is configurable. */
379
+ interface AdapterEndpoints {
380
+ /** Ark (Seedream images, Seedance videos). Defaults to the BytePlus ap-southeast endpoint. */
381
+ ark?: string;
382
+ }
383
+ interface ModelKitConfig {
384
+ keys: {
385
+ pro: ProviderKeys;
386
+ enterprise?: ProviderKeys;
387
+ };
388
+ routing?: Routing;
389
+ /** Provider base-url overrides; unset entries use each adapter's documented default. */
390
+ endpoints?: AdapterEndpoints;
391
+ /** Called once per completed provider call. */
392
+ onUsage?: (event: UsageEvent) => void | Promise<void>;
393
+ /** Extra or replacement catalog rows, merged by id. */
394
+ catalogOverride?: CatalogModel[];
395
+ fetch?: typeof fetch;
396
+ logger?: Pick<Console, "debug" | "info" | "warn" | "error">;
397
+ }
398
+ interface CallContext {
399
+ /** "enterprise" picks keys.enterprise when every key for the provider is set, else falls back to pro. */
400
+ tier?: "pro" | "enterprise";
401
+ signal?: AbortSignal;
402
+ onUnsupported?: "error" | "coerce";
403
+ }
404
+
405
+ declare class Catalog {
406
+ private readonly byId;
407
+ private readonly byAlias;
408
+ constructor(models: CatalogModel[]);
409
+ add(model: CatalogModel): void;
410
+ /** Resolves a canonical id or any historical alias. */
411
+ resolveId(idOrAlias: string): string | undefined;
412
+ get(idOrAlias: string): CatalogModel | undefined;
413
+ require(idOrAlias: string): CatalogModel;
414
+ list(filter?: {
415
+ type?: ModelType;
416
+ lifecycle?: Lifecycle[];
417
+ }): CatalogModel[];
418
+ /** Merge rows by id. Used for catalogOverride. */
419
+ withOverrides(rows: CatalogModel[]): Catalog;
420
+ }
421
+
422
+ /** Seeded from Cowork, Space Builder and trigger-workflows. See catalog/*.ts. */
423
+ declare const MODELS: CatalogModel[];
424
+
425
+ declare const IMAGE_MODELS: CatalogModel[];
426
+
427
+ declare const VIDEO_MODELS: CatalogModel[];
428
+
429
+ declare const TEXT_MODELS: CatalogModel[];
430
+
431
+ declare const OTHER_MODELS: CatalogModel[];
432
+
433
+ type OnUnsupported = "error" | "coerce";
434
+ interface ResolveResult<T> {
435
+ request: T;
436
+ warnings: Warning[];
437
+ }
438
+ /** Nearest supported ratio in the same orientation bucket, else nearest overall, by log distance. */
439
+ declare function nearestAspectRatio(requested: AspectRatio, supported: AspectRatio[]): AspectRatio;
440
+ declare function resolveImageOptions(model: CatalogModel, request: ImageRequest, onUnsupported?: OnUnsupported): ResolveResult<ImageRequest>;
441
+ declare function resolveVideoOptions(model: CatalogModel, request: VideoRequest, onUnsupported?: OnUnsupported): ResolveResult<VideoRequest>;
442
+ declare function resolveAudioOptions(model: CatalogModel, request: AudioRequest, onUnsupported?: OnUnsupported): ResolveResult<AudioRequest>;
443
+
444
+ /** Provider body or the lifted detail (Gemini blockReason, fal body.detail). */
445
+ type ProviderErrorBody = string | JsonValue;
446
+ type ModelKitErrorCode = "unknown_model" | "unsupported_option" | "missing_input" | "content_blocked" | "provider_rejected" | "timeout" | "auth" | "network" | "rate_limited";
447
+ interface ModelKitErrorInit {
448
+ code: ModelKitErrorCode;
449
+ message: string;
450
+ provider?: string;
451
+ model?: string;
452
+ status?: number;
453
+ body?: ProviderErrorBody;
454
+ cause?: unknown;
455
+ retryable?: boolean;
456
+ }
457
+ declare class ModelKitError extends Error {
458
+ readonly code: ModelKitErrorCode;
459
+ readonly provider: string | undefined;
460
+ readonly model: string | undefined;
461
+ readonly status: number | undefined;
462
+ readonly body: ProviderErrorBody | undefined;
463
+ readonly retryable: boolean;
464
+ constructor(init: ModelKitErrorInit);
465
+ }
466
+ declare function isModelKitError(err: unknown): err is ModelKitError;
467
+
468
+ /**
469
+ * Browser-safe catalog subpath (`@shop-os/modelkit/catalog`).
470
+ *
471
+ * Catalog rows, the option resolver and error types only. No adapters, no
472
+ * client, no key handling, no text helpers and no provider SDKs, so the
473
+ * bundle is safe to ship to browsers (Space Builder pickers, vibe-shared).
474
+ */
475
+
476
+ /** Resolve caller options against a catalog row, dispatching on `model.type`. */
477
+ declare function resolveOptions(model: CatalogModel, request: ImageRequest | VideoRequest | AudioRequest, onUnsupported?: OnUnsupported): ResolveResult<ImageRequest | VideoRequest | AudioRequest>;
478
+
479
+ export { type AdapterEndpoints, type AdapterId, type AspectRatio, type AudioRequest, type AudioResult, type CallContext, Catalog, type CatalogCapabilities, type CatalogDisplay, type CatalogModel, type GeneratedImage, IMAGE_MODELS, type ImageBytes, type ImageCallOptions, type ImageCallResult, type ImageQuality, type ImageRequest, type ImageResult, type ImageSafetySetting, type ImageSize, type JsonObject, type JsonPrimitive, type JsonValue, type Lifecycle, MODELS, type MediaPart, type MediaRef, type ModelConstraints, type ModelKitConfig, ModelKitError, type ModelKitErrorCode, type ModelKitErrorInit, type ModelType, OTHER_MODELS, type OnUnsupported, type OutputFormat, type PricingKind, type ProviderErrorBody, type ProviderKeyName, type ProviderKeys, type ProviderOptionValue, type ProviderOptions, type ReferenceLimits, type RequiredInput, type ResolveResult, type Routing, type SupportedOption, TEXT_MODELS, type UpscaleOptions, type UsageEvent, type UsageModality, type UsageUnit, VIDEO_MODELS, type VideoCallJob, type VideoCallOptions, type VideoJob, type VideoModel, type VideoRequest, type VideoResolution, type VideoResult, type Warning, isModelKitError, nearestAspectRatio, resolveAudioOptions, resolveImageOptions, resolveOptions, resolveVideoOptions };