@howells/motif-sdk 1.2.0 → 1.3.1

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/image.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { generateImage, ImageModel } from 'ai';
2
- import { Result } from 'neverthrow';
3
-
1
+ import { ImageModel, generateImage } from "ai";
2
+ import { Result } from "neverthrow";
3
+ //#region src/errors.d.ts
4
4
  /**
5
5
  * `MotifError` and its coercion helper.
6
6
  *
@@ -10,23 +10,15 @@ import { Result } from 'neverthrow';
10
10
  * re-exports `MotifError` so the package's public surface is unchanged.
11
11
  */
12
12
  declare class MotifError extends Error {
13
- readonly status: number;
14
- readonly code?: string;
15
- /** fal's request-correlation id (from the `x-fal-request-id` header or the
16
- * error body). Ties a failure back to fal's dashboard/support. */
17
- readonly requestId?: string;
18
- constructor(message: string, status: number, code?: string, requestId?: string);
13
+ readonly status: number;
14
+ readonly code?: string;
15
+ /** fal's request-correlation id (from the `x-fal-request-id` header or the
16
+ * error body). Ties a failure back to fal's dashboard/support. */
17
+ readonly requestId?: string;
18
+ constructor(message: string, status: number, code?: string, requestId?: string);
19
19
  }
20
-
21
- /**
22
- * Public types for the provider-agnostic image generation + editing layer
23
- * (`@howells/motif-sdk/image`).
24
- *
25
- * This layer is additive: it sits alongside the fal-specific `FalClient`
26
- * surface and reuses the SDK's Result convention (`Result<T, MotifError>` — no
27
- * thrown exceptions). See docs/design/provider-agnostic-image-layer.md.
28
- */
29
-
20
+ //#endregion
21
+ //#region src/image/types.d.ts
30
22
  /**
31
23
  * Quality/latency tier. Resolves through a provider-aware tier→model map when no
32
24
  * explicit `model` id is given. `balanced` is the default when a tier is omitted.
@@ -42,10 +34,10 @@ type ImageProviderId = "google" | "openai" | "replicate" | "fal" | (string & Rec
42
34
  type ImageCostSource = "provider-metadata" | "table" | "unknown";
43
35
  /** Normalized per-call spend attached to every result. */
44
36
  interface ImageCost {
45
- /** Total USD for the call (all images), best-effort. */
46
- usd: number;
47
- /** Where the figure came from: the provider's metadata, the static table, or unknown. */
48
- source: ImageCostSource;
37
+ /** Total USD for the call (all images), best-effort. */
38
+ usd: number;
39
+ /** Where the figure came from: the provider's metadata, the static table, or unknown. */
40
+ source: ImageCostSource;
49
41
  }
50
42
  /**
51
43
  * Client configuration. Every provider key is optional and falls back to that
@@ -54,137 +46,137 @@ interface ImageCost {
54
46
  * credential `apiToken`, not `apiKey`.
55
47
  */
56
48
  interface MotifImageConfig {
57
- /** Provider used when a call does not specify one. Defaults to `google`. */
58
- defaultProvider?: ImageProviderId;
59
- /** Google provider overrides. `apiKey` falls back to `GOOGLE_GENERATIVE_AI_API_KEY`. */
60
- google?: {
61
- apiKey?: string;
62
- };
63
- /** OpenAI provider overrides. `apiKey` falls back to `OPENAI_API_KEY`. */
64
- openai?: {
65
- apiKey?: string;
66
- };
67
- /**
68
- * Replicate provider overrides. Replicate's SDK names the credential
69
- * `apiToken` (not `apiKey`); it falls back to `REPLICATE_API_TOKEN`.
70
- */
71
- replicate?: {
72
- apiToken?: string;
73
- };
74
- /** fal provider overrides. `apiKey` falls back to `FAL_KEY`. */
75
- fal?: {
76
- apiKey?: string;
77
- };
49
+ /** Provider used when a call does not specify one. Defaults to `google`. */
50
+ defaultProvider?: ImageProviderId;
51
+ /** Google provider overrides. `apiKey` falls back to `GOOGLE_GENERATIVE_AI_API_KEY`. */
52
+ google?: {
53
+ apiKey?: string;
54
+ };
55
+ /** OpenAI provider overrides. `apiKey` falls back to `OPENAI_API_KEY`. */
56
+ openai?: {
57
+ apiKey?: string;
58
+ };
59
+ /**
60
+ * Replicate provider overrides. Replicate's SDK names the credential
61
+ * `apiToken` (not `apiKey`); it falls back to `REPLICATE_API_TOKEN`.
62
+ */
63
+ replicate?: {
64
+ apiToken?: string;
65
+ };
66
+ /** fal provider overrides. `apiKey` falls back to `FAL_KEY`. */
67
+ fal?: {
68
+ apiKey?: string;
69
+ };
78
70
  }
79
71
  /** Options for a text→image generation. */
80
72
  interface GenerateImageOptions {
81
- /** The text prompt. */
82
- prompt: string;
83
- /** Quality/latency tier. Ignored when `model` is set. */
84
- tier?: ImageTier;
85
- /** Explicit provider model id. Overrides `tier`. */
86
- model?: string;
87
- /** Provider override for this call. */
88
- provider?: ImageProviderId;
89
- /**
90
- * Aspect ratio, e.g. `"1:1"`. An alternative to {@link size}; pass one or the
91
- * other. If both are passed the provider decides which to honor and typically
92
- * surfaces a warning (see {@link MotifImageResult.warnings}).
93
- */
94
- aspectRatio?: `${number}:${number}`;
95
- /**
96
- * Explicit pixel size, e.g. `"1024x1024"`. An alternative to
97
- * {@link aspectRatio}; pass one or the other. If both are passed the provider
98
- * decides which to honor and typically surfaces a warning (see
99
- * {@link MotifImageResult.warnings}).
100
- */
101
- size?: `${number}x${number}`;
102
- /** Number of images to generate. */
103
- n?: number;
104
- /** Seed for reproducible generation, where the provider supports it. */
105
- seed?: number;
106
- /** Abort signal to cancel the in-flight request. */
107
- signal?: AbortSignal;
108
- /**
109
- * Extra HTTP headers forwarded to the provider request. Fal's non-retained IO
110
- * (paired with FalClient.deletePayloads) is
111
- * `headers: { "X-Fal-Store-IO": "0" }`.
112
- */
113
- headers?: Record<string, string>;
114
- /**
115
- * Provider-specific options, passed straight through to the underlying model
116
- * as body parameters. Outer key = provider name, inner key = option name.
117
- * Values must be JSON-representable; a non-JSON value (undefined, function,
118
- * bigint, symbol) makes the call fail with a `MotifError`.
119
- */
120
- providerOptions?: Record<string, Record<string, unknown>>;
73
+ /** The text prompt. */
74
+ prompt: string;
75
+ /** Quality/latency tier. Ignored when `model` is set. */
76
+ tier?: ImageTier;
77
+ /** Explicit provider model id. Overrides `tier`. */
78
+ model?: string;
79
+ /** Provider override for this call. */
80
+ provider?: ImageProviderId;
81
+ /**
82
+ * Aspect ratio, e.g. `"1:1"`. An alternative to {@link size}; pass one or the
83
+ * other. If both are passed the provider decides which to honor and typically
84
+ * surfaces a warning (see {@link MotifImageResult.warnings}).
85
+ */
86
+ aspectRatio?: `${number}:${number}`;
87
+ /**
88
+ * Explicit pixel size, e.g. `"1024x1024"`. An alternative to
89
+ * {@link aspectRatio}; pass one or the other. If both are passed the provider
90
+ * decides which to honor and typically surfaces a warning (see
91
+ * {@link MotifImageResult.warnings}).
92
+ */
93
+ size?: `${number}x${number}`;
94
+ /** Number of images to generate. */
95
+ n?: number;
96
+ /** Seed for reproducible generation, where the provider supports it. */
97
+ seed?: number;
98
+ /** Abort signal to cancel the in-flight request. */
99
+ signal?: AbortSignal;
100
+ /**
101
+ * Extra HTTP headers forwarded to the provider request. Fal's non-retained IO
102
+ * (paired with FalClient.deletePayloads) is
103
+ * `headers: { "X-Fal-Store-IO": "0" }`.
104
+ */
105
+ headers?: Record<string, string>;
106
+ /**
107
+ * Provider-specific options, passed straight through to the underlying model
108
+ * as body parameters. Outer key = provider name, inner key = option name.
109
+ * Values must be JSON-representable; a non-JSON value (undefined, function,
110
+ * bigint, symbol) makes the call fail with a `MotifError`.
111
+ */
112
+ providerOptions?: Record<string, Record<string, unknown>>;
121
113
  }
122
114
  /** Options for a multi-image edit (images in → image out), with an optional mask. */
123
115
  interface EditImageOptions {
124
- /**
125
- * Input images. Each entry is raw bytes (`Uint8Array`) or a string. A string
126
- * may be base64, a `data:` URL, OR a remote `http(s)://` URL. Remote URLs are
127
- * FETCHED by the provider — and on some providers (e.g. OpenAI) that fetch
128
- * happens from the local process running this SDK. Callers that accept
129
- * untrusted URLs should fetch and validate the bytes themselves before
130
- * passing them here (SSRF / local-network exposure otherwise).
131
- */
132
- images: (Uint8Array | string)[];
133
- /** Natural-language edit instruction. */
134
- instruction: string;
135
- /**
136
- * Optional mask constraining the edited region. Same accepted forms as
137
- * {@link EditImageOptions.images} (bytes, base64, `data:` URL, or a remote
138
- * `http(s)://` URL that the provider fetches — see the images note on
139
- * untrusted URLs). When multiple images are passed, the mask applies to
140
- * `images[0]`.
141
- */
142
- mask?: Uint8Array | string;
143
- /** Quality/latency tier. Ignored when `model` is set. */
144
- tier?: ImageTier;
145
- /** Explicit provider model id. Overrides `tier`. */
146
- model?: string;
147
- /** Provider override for this call. */
148
- provider?: ImageProviderId;
149
- /** Number of images to generate. */
150
- n?: number;
151
- /** Seed for reproducible generation, where the provider supports it. */
152
- seed?: number;
153
- /** Abort signal to cancel the in-flight request. */
154
- signal?: AbortSignal;
155
- /**
156
- * Extra HTTP headers forwarded to the provider request. Fal's non-retained IO
157
- * (paired with FalClient.deletePayloads) is
158
- * `headers: { "X-Fal-Store-IO": "0" }`.
159
- */
160
- headers?: Record<string, string>;
161
- /** Provider-specific options (see {@link GenerateImageOptions.providerOptions}). */
162
- providerOptions?: Record<string, Record<string, unknown>>;
116
+ /**
117
+ * Input images. Each entry is raw bytes (`Uint8Array`) or a string. A string
118
+ * may be base64, a `data:` URL, OR a remote `http(s)://` URL. Remote URLs are
119
+ * FETCHED by the provider — and on some providers (e.g. OpenAI) that fetch
120
+ * happens from the local process running this SDK. Callers that accept
121
+ * untrusted URLs should fetch and validate the bytes themselves before
122
+ * passing them here (SSRF / local-network exposure otherwise).
123
+ */
124
+ images: (Uint8Array | string)[];
125
+ /** Natural-language edit instruction. */
126
+ instruction: string;
127
+ /**
128
+ * Optional mask constraining the edited region. Same accepted forms as
129
+ * {@link EditImageOptions.images} (bytes, base64, `data:` URL, or a remote
130
+ * `http(s)://` URL that the provider fetches — see the images note on
131
+ * untrusted URLs). When multiple images are passed, the mask applies to
132
+ * `images[0]`.
133
+ */
134
+ mask?: Uint8Array | string;
135
+ /** Quality/latency tier. Ignored when `model` is set. */
136
+ tier?: ImageTier;
137
+ /** Explicit provider model id. Overrides `tier`. */
138
+ model?: string;
139
+ /** Provider override for this call. */
140
+ provider?: ImageProviderId;
141
+ /** Number of images to generate. */
142
+ n?: number;
143
+ /** Seed for reproducible generation, where the provider supports it. */
144
+ seed?: number;
145
+ /** Abort signal to cancel the in-flight request. */
146
+ signal?: AbortSignal;
147
+ /**
148
+ * Extra HTTP headers forwarded to the provider request. Fal's non-retained IO
149
+ * (paired with FalClient.deletePayloads) is
150
+ * `headers: { "X-Fal-Store-IO": "0" }`.
151
+ */
152
+ headers?: Record<string, string>;
153
+ /** Provider-specific options (see {@link GenerateImageOptions.providerOptions}). */
154
+ providerOptions?: Record<string, Record<string, unknown>>;
163
155
  }
164
156
  /** A single generated image, mirroring the AI SDK's `GeneratedFile`. */
165
157
  interface MotifImageFile {
166
- uint8Array: Uint8Array;
167
- base64: string;
168
- mediaType: string;
158
+ uint8Array: Uint8Array;
159
+ base64: string;
160
+ mediaType: string;
169
161
  }
170
162
  /** Normalized result of a generate/edit call. */
171
163
  interface MotifImageResult {
172
- /** Generated images. */
173
- images: MotifImageFile[];
174
- /** Normalized per-call cost + provenance. */
175
- cost: ImageCost;
176
- /** Resolved provider. */
177
- provider: ImageProviderId;
178
- /** Resolved model id. */
179
- model: string;
180
- /** Provider correlation id, where the provider surfaces one. */
181
- requestId?: string;
182
- /**
183
- * Degraded-success warnings from the provider (a requested setting was
184
- * ignored or adjusted — e.g. passing both `size` and `aspectRatio`). Each is a
185
- * readable string. Omitted entirely when the provider returned none.
186
- */
187
- warnings?: readonly string[];
164
+ /** Generated images. */
165
+ images: MotifImageFile[];
166
+ /** Normalized per-call cost + provenance. */
167
+ cost: ImageCost;
168
+ /** Resolved provider. */
169
+ provider: ImageProviderId;
170
+ /** Resolved model id. */
171
+ model: string;
172
+ /** Provider correlation id, where the provider surfaces one. */
173
+ requestId?: string;
174
+ /**
175
+ * Degraded-success warnings from the provider (a requested setting was
176
+ * ignored or adjusted — e.g. passing both `size` and `aspectRatio`). Each is a
177
+ * readable string. Omitted entirely when the provider returned none.
178
+ */
179
+ warnings?: readonly string[];
188
180
  }
189
181
  /**
190
182
  * Picks the winning candidate for a {@link MotifImageClient.bestOfN} call.
@@ -197,14 +189,14 @@ interface MotifImageResult {
197
189
  * is not required.
198
190
  */
199
191
  type ImageJudge = (candidates: readonly MotifImageResult[], context: {
200
- readonly prompt?: string;
201
- readonly instruction?: string;
192
+ readonly prompt?: string;
193
+ readonly instruction?: string;
202
194
  }) => Promise<{
203
- index: number;
204
- reason?: string;
195
+ index: number;
196
+ reason?: string;
205
197
  }> | {
206
- index: number;
207
- reason?: string;
198
+ index: number;
199
+ reason?: string;
208
200
  };
209
201
  /**
210
202
  * Options for a best-of-N generation. Extends either {@link GenerateImageOptions}
@@ -212,120 +204,94 @@ type ImageJudge = (candidates: readonly MotifImageResult[], context: {
212
204
  * `images` selects the edit path — with the candidate count and an optional judge.
213
205
  */
214
206
  type BestOfNOptions = (GenerateImageOptions | EditImageOptions) & {
215
- /** How many candidates to generate (>= 1). */
216
- n: number;
217
- /** Chooses the winner. Omit → candidate 0 wins. */
218
- judge?: ImageJudge;
207
+ /** How many candidates to generate (>= 1). */
208
+ n: number;
209
+ /** Chooses the winner. Omit → candidate 0 wins. */
210
+ judge?: ImageJudge;
219
211
  };
220
212
  /** Result of a {@link MotifImageClient.bestOfN} call. */
221
213
  interface BestOfNResult {
222
- /** The winning candidate (its single-image {@link MotifImageResult}). */
223
- best: MotifImageResult;
224
- /** The index of `best` within `candidates`. */
225
- chosenIndex: number;
226
- /** Judge's rationale, if it returned one. */
227
- reason?: string;
228
- /** All successful candidates, in generation order. */
229
- candidates: readonly MotifImageResult[];
230
- /** Total USD across all candidates that were generated (successes only). */
231
- totalCostUsd: number;
214
+ /** The winning candidate (its single-image {@link MotifImageResult}). */
215
+ best: MotifImageResult;
216
+ /** The index of `best` within `candidates`. */
217
+ chosenIndex: number;
218
+ /** Judge's rationale, if it returned one. */
219
+ reason?: string;
220
+ /** All successful candidates, in generation order. */
221
+ candidates: readonly MotifImageResult[];
222
+ /** Total USD across all candidates that were generated (successes only). */
223
+ totalCostUsd: number;
232
224
  }
233
225
  /** The provider-agnostic image client. Every method returns a Result — no throws. */
234
226
  interface MotifImageClient {
235
- /** Text→image generation. */
236
- generate: (opts: GenerateImageOptions) => Promise<Result<MotifImageResult, MotifError>>;
237
- /** Multi-image edit (with optional mask). */
238
- edit: (opts: EditImageOptions) => Promise<Result<MotifImageResult, MotifError>>;
239
- /**
240
- * Generate N candidates (in parallel) and pick the best via an optional
241
- * injectable judge. Discriminates generate vs edit by the presence of
242
- * `images`. Returns the winner plus all successful candidates and total spend.
243
- */
244
- bestOfN: (opts: BestOfNOptions) => Promise<Result<BestOfNResult, MotifError>>;
227
+ /** Text→image generation. */
228
+ generate: (opts: GenerateImageOptions) => Promise<Result<MotifImageResult, MotifError>>;
229
+ /** Multi-image edit (with optional mask). */
230
+ edit: (opts: EditImageOptions) => Promise<Result<MotifImageResult, MotifError>>;
231
+ /**
232
+ * Generate N candidates (in parallel) and pick the best via an optional
233
+ * injectable judge. Discriminates generate vs edit by the presence of
234
+ * `images`. Returns the winner plus all successful candidates and total spend.
235
+ */
236
+ bestOfN: (opts: BestOfNOptions) => Promise<Result<BestOfNResult, MotifError>>;
245
237
  }
246
-
247
- /**
248
- * Internal dependency-injection seam for the image layer.
249
- *
250
- * These types are INTERNAL: they are consumed by `createMotifImage`'s `deps`
251
- * parameter and by the offline tests, but they are deliberately NOT re-exported
252
- * from the public `@howells/motif-sdk/image` subpath, so they never appear in
253
- * `dist/image.d.ts`. Import them from `./deps` inside the package (and from
254
- * `../src/image/deps` in tests).
255
- */
256
-
238
+ //#endregion
239
+ //#region src/image/deps.d.ts
257
240
  /** A model resolver: builds an AI SDK `ImageModel` for a (provider, model, key). */
258
241
  type ResolveImageModel = (provider: ImageProviderId, modelId: string, apiKey?: string) => ImageModel;
259
242
  /** Internal dependency-injection seam (default: real `generateImage` + adapters). */
260
243
  interface MotifImageDeps {
261
- generateImage?: typeof generateImage;
262
- resolveModel?: ResolveImageModel;
244
+ generateImage?: typeof generateImage;
245
+ resolveModel?: ResolveImageModel;
263
246
  }
264
-
265
- /**
266
- * Provider registry for the image layer.
267
- *
268
- * Each provider (google, openai, replicate, fal) contributes exactly one
269
- * {@link ImageProviderAdapter}. The dispatch functions in `index.ts` and the
270
- * cost lookup in `cost.ts` read the registry by id, so adding a provider is a
271
- * single registry entry — not new branches spread across generate/edit/cost.
272
- */
273
-
247
+ //#endregion
248
+ //#region src/image/provider.d.ts
274
249
  /**
275
250
  * A single image provider. A thin wrapper over the provider's `@ai-sdk/*` image
276
251
  * model, plus the metadata the layer needs to route by tier, resolve keys, and
277
252
  * meter spend.
278
253
  */
279
254
  interface ImageProviderAdapter {
280
- /** Provider id, matching the key it is registered under in {@link PROVIDERS}. */
281
- readonly id: ImageProviderId;
282
- /** Tier → model id map, used when a call does not pass an explicit `model`. */
283
- readonly tierModels: Readonly<Record<ImageTier, string>>;
284
- /** Env var read for the API key when no key is supplied in config. */
285
- readonly apiKeyEnv: string;
286
- /**
287
- * Build the AI SDK `ImageModel` for a model id. Prefers the passed `apiKey`,
288
- * else the adapter's `apiKeyEnv`. Throws `MotifError` when neither is present
289
- * (callers translate this into a `Result.err`). Building a model performs no
290
- * network I/O.
291
- */
292
- readonly resolveModel: (modelId: string, apiKey?: string) => ImageModel;
293
- /**
294
- * Static per-model USD/**image** table (best-effort; cited per adapter). This
295
- * is multiplied by the returned image count to form the call total.
296
- *
297
- * Cost contract: if an adapter instead surfaces a cost on
298
- * `result.providerMetadata` (the preferred source; see
299
- * {@link costFromProviderMetadata}), that value MUST already be the **call
300
- * total** across all `n` images — NOT a per-image figure. `priceUsdByModel`
301
- * is per-image; `providerMetadata.cost` is the whole call. These two paths
302
- * intentionally differ, so an adapter must not populate a per-image number
303
- * into `providerMetadata.cost`.
304
- */
305
- readonly priceUsdByModel: Readonly<Record<string, number>>;
255
+ /** Provider id, matching the key it is registered under in {@link PROVIDERS}. */
256
+ readonly id: ImageProviderId;
257
+ /** Tier → model id map, used when a call does not pass an explicit `model`. */
258
+ readonly tierModels: Readonly<Record<ImageTier, string>>;
259
+ /** Env var read for the API key when no key is supplied in config. */
260
+ readonly apiKeyEnv: string;
261
+ /**
262
+ * Build the AI SDK `ImageModel` for a model id. Prefers the passed `apiKey`,
263
+ * else the adapter's `apiKeyEnv`. Throws `MotifError` when neither is present
264
+ * (callers translate this into a `Result.err`). Building a model performs no
265
+ * network I/O.
266
+ */
267
+ readonly resolveModel: (modelId: string, apiKey?: string) => ImageModel;
268
+ /**
269
+ * Static per-model USD/**image** table (best-effort; cited per adapter). This
270
+ * is multiplied by the returned image count to form the call total.
271
+ *
272
+ * Cost contract: if an adapter instead surfaces a cost on
273
+ * `result.providerMetadata` (the preferred source; see
274
+ * {@link costFromProviderMetadata}), that value MUST already be the **call
275
+ * total** across all `n` images — NOT a per-image figure. `priceUsdByModel`
276
+ * is per-image; `providerMetadata.cost` is the whole call. These two paths
277
+ * intentionally differ, so an adapter must not populate a per-image number
278
+ * into `providerMetadata.cost`.
279
+ */
280
+ readonly priceUsdByModel: Readonly<Record<string, number>>;
306
281
  }
307
282
  /**
308
283
  * The provider registry. Every id in {@link ImageProviderId}'s closed part maps
309
284
  * to its adapter; the open union tail means a lookup can still miss, so access
310
285
  * goes through {@link getProviderAdapter}.
311
286
  */
312
- declare const PROVIDERS: Record<ImageProviderId, ImageProviderAdapter>;
287
+ export declare const PROVIDERS: Record<ImageProviderId, ImageProviderAdapter>;
313
288
  /**
314
289
  * Look up an adapter by provider id, throwing a `MotifError` for an unknown
315
290
  * provider (callers catch this into a `Result.err`).
316
291
  */
317
- declare function getProviderAdapter(provider: ImageProviderId): ImageProviderAdapter;
318
-
319
- /**
320
- * Google (Gemini) provider adapter.
321
- *
322
- * Builds a Vercel AI SDK `ImageModel` from `@ai-sdk/google`. Building a model
323
- * performs no network I/O — the request only happens when `generateImage`
324
- * invokes `model.doGenerate`. Gemini supports both text→image generation and
325
- * multi-image-in → image-out editing (with an optional mask), which is the core
326
- * operation this layer normalizes.
327
- */
328
-
292
+ export declare function getProviderAdapter(provider: ImageProviderId): ImageProviderAdapter;
293
+ //#endregion
294
+ //#region src/image/google.d.ts
329
295
  /**
330
296
  * Tier → Gemini image model id.
331
297
  *
@@ -333,111 +299,46 @@ declare function getProviderAdapter(provider: ImageProviderId): ImageProviderAda
333
299
  * consumer, see the design doc). `gemini-2.5-flash-image` is the proven-reachable
334
300
  * floor; the preview ids may require allowlist/tier access.
335
301
  */
336
- declare const GOOGLE_TIER_MODELS: Readonly<Record<ImageTier, string>>;
302
+ export declare const GOOGLE_TIER_MODELS: Readonly<Record<ImageTier, string>>;
337
303
  /** Env var read for the Google API key when `apiKey` is not supplied in config. */
338
- declare const GOOGLE_API_KEY_ENV = "GOOGLE_GENERATIVE_AI_API_KEY";
339
-
340
- /**
341
- * OpenAI (gpt-image) provider adapter.
342
- *
343
- * Builds a Vercel AI SDK `ImageModel` from `@ai-sdk/openai`. Building a model
344
- * performs no network I/O — the request only happens when `generateImage`
345
- * invokes `model.doGenerate`.
346
- */
347
-
304
+ export declare const GOOGLE_API_KEY_ENV = "GOOGLE_GENERATIVE_AI_API_KEY";
305
+ //#endregion
306
+ //#region src/image/openai.d.ts
348
307
  /** Tier → OpenAI image model id (all tiers → the single gpt-image model). */
349
- declare const OPENAI_TIER_MODELS: Readonly<Record<ImageTier, string>>;
308
+ export declare const OPENAI_TIER_MODELS: Readonly<Record<ImageTier, string>>;
350
309
  /** Env var read for the OpenAI API key when `apiKey` is not supplied in config. */
351
- declare const OPENAI_API_KEY_ENV = "OPENAI_API_KEY";
352
-
353
- /**
354
- * Replicate provider adapter.
355
- *
356
- * Builds a Vercel AI SDK `ImageModel` from `@ai-sdk/replicate`. Building a model
357
- * performs no network I/O — the request only happens when `generateImage`
358
- * invokes `model.doGenerate`.
359
- *
360
- * NOTE: Replicate's SDK names the credential option `apiToken` (not `apiKey`),
361
- * and reads `REPLICATE_API_TOKEN` from the environment.
362
- */
363
-
310
+ export declare const OPENAI_API_KEY_ENV = "OPENAI_API_KEY";
311
+ //#endregion
312
+ //#region src/image/replicate.d.ts
364
313
  /** Tier → Replicate model id (all tiers → FLUX 1.1 Pro Ultra for now). */
365
- declare const REPLICATE_TIER_MODELS: Readonly<Record<ImageTier, string>>;
314
+ export declare const REPLICATE_TIER_MODELS: Readonly<Record<ImageTier, string>>;
366
315
  /** Env var read for the Replicate API token when `apiToken` is not in config. */
367
- declare const REPLICATE_API_KEY_ENV = "REPLICATE_API_TOKEN";
368
-
369
- /**
370
- * fal provider adapter.
371
- *
372
- * Builds a Vercel AI SDK `ImageModel` from `@ai-sdk/fal`. Building a model
373
- * performs no network I/O — the request only happens when `generateImage`
374
- * invokes `model.doGenerate`. This is the lightweight fal *image* adapter; the
375
- * richer `FalClient` fal client (queue, upload, upscale, rmbg, video, tools)
376
- * is a separate, later fold (design doc §8, phase 1d).
377
- *
378
- * ENDPOINT QUIRK (Phase 0): fal's gpt-image endpoint wants `image_size` as a
379
- * STRING enum (e.g. "1024x1024"), passed at generate time via
380
- * `providerOptions.fal.image_size` — NOT the AI SDK's generic `size` object.
381
- * This adapter does NOT auto-inject it; callers pass `providerOptions` when they
382
- * need a specific size. Example:
383
- * img.generate({
384
- * provider: "fal",
385
- * tier: "balanced",
386
- * prompt: "...",
387
- * providerOptions: { fal: { image_size: "1024x1024" } },
388
- * });
389
- */
390
-
316
+ export declare const REPLICATE_API_KEY_ENV = "REPLICATE_API_TOKEN";
317
+ //#endregion
318
+ //#region src/image/fal.d.ts
391
319
  /**
392
320
  * Tier → fal model id. For fal, explicit `model:` endpoint ids are the primary
393
321
  * path (any fal endpoint resolves via passthrough); this tier map is a
394
322
  * convenience covering the two most common (FLUX Pro Ultra + gpt-image).
395
323
  */
396
- declare const FAL_TIER_MODELS: Readonly<Record<ImageTier, string>>;
324
+ export declare const FAL_TIER_MODELS: Readonly<Record<ImageTier, string>>;
397
325
  /** Env var read for the fal key when `apiKey` is not supplied in config. */
398
- declare const FAL_API_KEY_ENV = "FAL_KEY";
399
-
400
- /**
401
- * Per-call cost tracking for the image layer.
402
- *
403
- * Preference order:
404
- * 1. A cost surfaced by the provider on `result.providerMetadata` (most image
405
- * providers do NOT surface one today, so this is usually absent).
406
- * 2. A static per-model table, owned per-adapter (`priceUsdByModel`) and read
407
- * from the provider registry (see sources in each adapter).
408
- * 3. Unknown → `{ usd: 0, source: "unknown" }`.
409
- */
410
-
326
+ export declare const FAL_API_KEY_ENV = "FAL_KEY";
327
+ //#endregion
328
+ //#region src/image/cost.d.ts
411
329
  /**
412
330
  * Extract a provider-reported total cost from a `generateImage` result's
413
331
  * `providerMetadata`, if the provider surfaces a numeric `cost`. The shape is
414
332
  * `{ [provider]: { ...; cost?: number } }`. Returns undefined otherwise.
415
333
  */
416
- declare function costFromProviderMetadata(providerMetadata: unknown): number | undefined;
334
+ export declare function costFromProviderMetadata(providerMetadata: unknown): number | undefined;
417
335
  /**
418
336
  * Normalized per-call cost for a generation. Prefers a provider-metadata cost,
419
337
  * then the static table (× image count), then unknown.
420
338
  */
421
- declare function costForImages(provider: ImageProviderId, modelId: string, providerMetadata: unknown, imageCount: number): ImageCost;
422
-
423
- /**
424
- * `@howells/motif-sdk/image` — provider-agnostic image generation + editing.
425
- *
426
- * ESM-only subpath export, built on the Vercel AI SDK image interface
427
- * (`generateImage`, `@ai-sdk/*`). Additive to the fal-specific `FalClient`
428
- * surface; reuses the SDK's Result convention (`Result<T, MotifError>` — no
429
- * thrown exceptions). Google (Gemini) is the only provider in Phase 1a.
430
- *
431
- * @example
432
- * ```ts
433
- * import { createMotifImage } from "@howells/motif-sdk/image";
434
- *
435
- * const img = createMotifImage({ defaultProvider: "google" });
436
- * const r = await img.generate({ tier: "fast", prompt: "a bare concrete wall" });
437
- * if (r.isOk()) console.log(r.value.images[0].mediaType, r.value.cost);
438
- * ```
439
- */
440
-
339
+ export declare function costForImages(provider: ImageProviderId, modelId: string, providerMetadata: unknown, imageCount: number): ImageCost;
340
+ //#endregion
341
+ //#region src/image/index.d.ts
441
342
  /**
442
343
  * Create a provider-agnostic image client.
443
344
  *
@@ -445,6 +346,6 @@ declare function costForImages(provider: ImageProviderId, modelId: string, provi
445
346
  * @param deps - INTERNAL testing seam. Defaults to the real AI SDK `generateImage`
446
347
  * and the built-in provider adapters; tests inject fakes here to run offline.
447
348
  */
448
- declare function createMotifImage(config?: MotifImageConfig, deps?: MotifImageDeps): MotifImageClient;
449
-
450
- export { type BestOfNOptions, type BestOfNResult, type EditImageOptions, FAL_API_KEY_ENV, FAL_TIER_MODELS, GOOGLE_API_KEY_ENV, GOOGLE_TIER_MODELS, type GenerateImageOptions, type ImageCost, type ImageCostSource, type ImageJudge, type ImageProviderAdapter, type ImageProviderId, type ImageTier, type MotifImageClient, type MotifImageConfig, type MotifImageFile, type MotifImageResult, OPENAI_API_KEY_ENV, OPENAI_TIER_MODELS, PROVIDERS, REPLICATE_API_KEY_ENV, REPLICATE_TIER_MODELS, costForImages, costFromProviderMetadata, createMotifImage, getProviderAdapter };
349
+ export declare function createMotifImage(config?: MotifImageConfig, deps?: MotifImageDeps): MotifImageClient;
350
+ //#endregion
351
+ export type { BestOfNOptions, BestOfNResult, EditImageOptions, GenerateImageOptions, ImageCost, ImageCostSource, ImageJudge, ImageProviderAdapter, ImageProviderId, ImageTier, MotifImageClient, MotifImageConfig, MotifImageFile, MotifImageResult };