@howells/motif-sdk 6.0.0 → 7.1.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/README.md CHANGED
@@ -34,7 +34,7 @@ Every Task function returns `Result<TaskOutput, MotifError>` from `neverthrow` a
34
34
 
35
35
  ## Curated Models and Tiers
36
36
 
37
- The Task client curates 24 generation Models, with separate rankings for generation and editing. Both follow Arena, read 29 October 2026. `TASKS.generate` and `TASKS.vary` expose the current choices, Tiers and evidence in `basis` and `rankedAt`. A generation with `references` uses the editing ranking.
37
+ The Task client curates 23 generation Models, with separate rankings for generation and editing. Both follow Arena, read 29 October 2026. `TASKS.generate` and `TASKS.vary` expose the current choices, Tiers and evidence in `basis` and `rankedAt`. Sunburst and Flare run GPT Image 2.6; Arena has not scored 2.6 yet, so their benchmarks are the GPT Image 2.5 scores, and each carries a `note` saying so. A generation with `references` uses the editing ranking.
38
38
 
39
39
  | Tier | Generation default | Editing default |
40
40
  | -------------------- | ------------------ | ----------------- |
@@ -42,11 +42,11 @@ The Task client curates 24 generation Models, with separate rankings for generat
42
42
  | `balanced` (default) | Nano Banana 2.1 | Grok Image 2 |
43
43
  | `fast` | Nano Banana 2 Lite | Grok |
44
44
 
45
- These are the first choices when the request's capabilities and available keys permit them. Explicit Models, Looks and pins take precedence. Selected specialists remain for typography, transparency, control and inexpensive drafts. Archived predecessors remain available through explicit Models, pins and existing Looks, including `flux2-dev` for streaming.
45
+ These are the first choices when the request's capabilities and available keys permit them. Explicit Models, Looks and pins take precedence. Selected specialists remain for typography, transparency, control and inexpensive drafts.
46
46
 
47
47
  Nano Banana 2.1 (`banana21`) supports up to 14 References and 1K/2K/4K output, with no 0.5K output. Its balanced placement uses preliminary Arena evidence. Sunburst and Flare run GPT Image 2.6 on fal and default to `quality: "max"`; `params: { quality: "high" }` with an explicit `model` overrides it. Both also return an animated GIF (`outputFormat: "gif"`, with `params.frame_count` and `params.frame_duration_ms`) or, from text, an SVG (`outputFormat: "svg"`), and take `markup`: a transparent PNG of arrows, circles and notes the size of the image being edited, which guides a vary or an edit with References. Asking for a format or markup limits the choice to Models that support it. The direct provider image layer described below has its own adapter capabilities and chooses no Model.
48
48
 
49
- Token-billed Task plans, including Sunburst, Flare, Nano Banana 2.1, Banana Lite and MAI 2.5, report `cost: { usd: null, basis: "unknown" }`; a published representative price is not an exact total. The [curation audit](https://github.com/howells/motif/blob/main/docs/research/image-model-curation-2026-10-07.md) records the current rankings, specialist roles and provider coverage gaps.
49
+ Token-billed Task plans, including Sunburst, Flare, Nano Banana 2.1, Banana Lite and MAI 2.5, report `cost: { usd: null, basis: "unknown" }`; a published representative price is not an exact total.
50
50
 
51
51
  Pass `onProgress(status, queuePosition)` to hear fal's queue state while a run waits: `"queued"` with its place in line, then `"processing"`, then `"completed"` (or `"failed"`). Passing it sends the run through fal's queue, since only the queue reports state. Models without streaming report state, not a percentage.
52
52
 
@@ -73,7 +73,7 @@ if (plan.isOk()) {
73
73
 
74
74
  ## Stream a Task
75
75
 
76
- `stream(task, input, options?)` opens a direct inference stream on the resolved route. Streaming is explicitly supported for GPT Image 1.5 and FLUX.2 Dev, including their edit routes. Other routes return `STREAMING_UNSUPPORTED` before any provider request; Motif never substitutes another model or retries a stream.
76
+ `stream(task, input, options?)` opens a direct inference stream on the resolved route. Streaming is explicitly supported for GPT Image 1.5, including its edit route. Other routes return `STREAMING_UNSUPPORTED` before any provider request; Motif never substitutes another model or retries a stream.
77
77
 
78
78
  ```ts
79
79
  const controller = new AbortController();
@@ -100,7 +100,7 @@ Events use `images`, `progress` or `provider` types. Images carry the same `Task
100
100
 
101
101
  The handle exposes `plan`, optional `requestId` and `abort()`. Consume its events once. Abort, iterator exit and the overall deadline close local consumption; this does not guarantee cancellation of provider work or a refund. There is no queue submission, reconnection or retry. `plan()` remains a normal execution plan, so its `queued` flag describes `run()`, not `stream()`.
102
102
 
103
- For a local checkout, `node packages/motif-sdk/examples/stream.mjs --dry-run` prints the resolved request without a provider call. Running it without `--dry-run` spends provider credits; it requires `FAL_KEY` and a built SDK. The runner is a repository example, not a packaged public API.
103
+ For a local checkout, `node packages/motif-sdk/examples/stream.mjs` prints the resolved request without a provider call. Adding `--run` spends provider credits; it requires `FAL_KEY` and a built SDK. The runner is a repository example, not a packaged public API.
104
104
 
105
105
  ## Main Exports
106
106
 
package/dist/image.d.ts CHANGED
@@ -1,11 +1,25 @@
1
+ /**
2
+ * `@howells/motif-sdk/image` — provider-agnostic image generation + editing.
3
+ *
4
+ * ESM-only subpath export, built on the Vercel AI SDK image interface
5
+ * (`generateImage`, `@ai-sdk/*`). The caller names the provider and model;
6
+ * reuses the SDK's Result convention (`Result<T, MotifError>` — no
7
+ * thrown exceptions). Gemini is reached through OpenRouter.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { createMotifImage } from "@howells/motif-sdk/image";
12
+ *
13
+ * const img = createMotifImage({ defaultProvider: "openrouter" });
14
+ * const r = await img.generate({ model: "gemini-3.1-flash-image", prompt: "a bare concrete wall" });
15
+ * if (r.isOk()) console.log(r.value.images[0].mediaType, r.value.cost);
16
+ * ```
17
+ */
1
18
  import { ImageModel, generateImage } from "ai";
2
19
  import { Result } from "neverthrow";
3
- //#region src/types.d.ts
4
20
  /** ─── Configuration ──────────────────────────────────────────── */
5
21
  /** The network seam: a `fetch`-shaped function. */
6
22
  type FalFetch = (url: string, init: RequestInit) => Promise<Response>;
7
- //#endregion
8
- //#region src/errors.d.ts
9
23
  /**
10
24
  * `MotifError` and its coercion helper.
11
25
  *
@@ -24,8 +38,6 @@ declare class MotifError extends Error {
24
38
  readonly details?: Record<string, unknown>;
25
39
  constructor(message: string, status: number, code?: string, requestId?: string, details?: Record<string, unknown>);
26
40
  }
27
- //#endregion
28
- //#region src/image/types.d.ts
29
41
  /**
30
42
  * Image provider id. All four Phase 1b adapters are implemented
31
43
  * (`openrouter`, `openai`, `replicate`, `fal`); the type keeps an open union tail so
@@ -240,8 +252,6 @@ interface MotifImageClient {
240
252
  */
241
253
  bestOfN: (opts: BestOfNOptions) => Promise<Result<BestOfNResult, MotifError>>;
242
254
  }
243
- //#endregion
244
- //#region src/image/deps.d.ts
245
255
  /** A model resolver: builds an AI SDK `ImageModel` for a (provider, model, key). */
246
256
  type ResolveImageModel = (provider: ImageProviderId, modelId: string, apiKey?: string, fetch?: FalFetch) => ImageModel;
247
257
  /** Internal dependency-injection seam (default: real `generateImage` + adapters). */
@@ -249,8 +259,6 @@ interface MotifImageDeps {
249
259
  generateImage?: typeof generateImage;
250
260
  resolveModel?: ResolveImageModel;
251
261
  }
252
- //#endregion
253
- //#region src/image/provider.d.ts
254
262
  /**
255
263
  * A single image provider. A thin wrapper over the provider's `@ai-sdk/*` image
256
264
  * model, plus the metadata the layer needs to resolve keys and meter spend.
@@ -292,24 +300,14 @@ export declare const PROVIDERS: Record<ImageProviderId, ImageProviderAdapter>;
292
300
  * provider (callers catch this into a `Result.err`).
293
301
  */
294
302
  export declare function getProviderAdapter(provider: ImageProviderId): ImageProviderAdapter;
295
- //#endregion
296
- //#region src/image/openrouter.d.ts
297
303
  /** Env var read for the OpenRouter API key when `apiKey` is not supplied in config. */
298
304
  export declare const OPENROUTER_API_KEY_ENV = "OPENROUTER_API_KEY";
299
- //#endregion
300
- //#region src/image/openai.d.ts
301
305
  /** Env var read for the OpenAI API key when `apiKey` is not supplied in config. */
302
306
  export declare const OPENAI_API_KEY_ENV = "OPENAI_API_KEY";
303
- //#endregion
304
- //#region src/image/replicate.d.ts
305
307
  /** Env var read for the Replicate API token when `apiToken` is not in config. */
306
308
  export declare const REPLICATE_API_KEY_ENV = "REPLICATE_API_TOKEN";
307
- //#endregion
308
- //#region src/image/fal.d.ts
309
309
  /** Env var read for the fal key when `apiKey` is not supplied in config. */
310
310
  export declare const FAL_API_KEY_ENV = "FAL_KEY";
311
- //#endregion
312
- //#region src/image/cost.d.ts
313
311
  /**
314
312
  * Extract a provider-reported total cost from a `generateImage` result's
315
313
  * `providerMetadata`, if the provider surfaces a numeric `cost`. The shape is
@@ -323,8 +321,6 @@ export declare function providerPricePerImageUsd(provider: ImageProviderId, mode
323
321
  * then the static table (× image count), then unknown.
324
322
  */
325
323
  export declare function costForImages(provider: ImageProviderId, modelId: string, providerMetadata: unknown, imageCount: number): ImageCost;
326
- //#endregion
327
- //#region src/image/index.d.ts
328
324
  /**
329
325
  * Create a provider-agnostic image client.
330
326
  *
@@ -333,5 +329,4 @@ export declare function costForImages(provider: ImageProviderId, modelId: string
333
329
  * and the built-in provider adapters; tests inject fakes here to run offline.
334
330
  */
335
331
  export declare function createMotifImage(config?: MotifImageConfig, deps?: MotifImageDeps): MotifImageClient;
336
- //#endregion
337
332
  export type { BestOfNOptions, BestOfNResult, EditImageOptions, GenerateImageOptions, ImageCost, ImageCostSource, ImageJudge, ImageProviderAdapter, ImageProviderId, MotifImageClient, MotifImageConfig, MotifImageFile, MotifImageResult };