Dispatch a single atomic image generation. Sibling of `lamina_create` (the agentic router) — use this when you already know which model fits, or when no app fits the brief.
WORKFLOW: (1) `lamina_models_list({ modality: "image" })` → pick a model. (2) `lamina_models_describe({ modelId })` → read its flat `paramSchema`. (3) `lamina_generate_image({ model, prompt, params })` → dispatch, get runId. (4) `lamina_status({ runId, wait: true })` → poll until completed; the response has `output.url`.
ONE TOOL, BOTH OPERATIONS:
• Text-to-image — call with just `prompt` (and any text-mode params). The model id you picked is the only thing that selects the operation.
• Image-to-image (edit / remix / background-swap / etc.) — call the same tool, but include a source image in `params`. Hybrid models (nano-banana-pro, gpt-image-2, gemini-2.5-flash-image, seedream-4.5, flux-2-flex, nano-banana-2, gpt-image-1, gpt-image-1.5) flip to image-to-image automatically when `params.imageUrls` is a non-empty array (or `params.imageUrl` is set for single-source models like flux-pro-kontext). Edit-only models (bria-bg-remove, ideogram-character, ideogram-v3-remix/reframe/replace-background, flux-pro-kontext, ideogram-character-remix) only have image-to-image — `params.imageUrls`/`imageUrl` is required.
INPUTS:
• `model` (required): a model id from `lamina_models_list`. Don't invent it.
• `prompt` (required for most models; check `paramSchema.prompt.required` from `lamina_models_describe`; absent from `paramSchema` for prompt-less models like `bria-bg-remove` and `ideogram-v3-reframe`): natural-language brief; ≤2000 chars.
• `params` (model-specific): every key MUST be declared in the chosen model's `paramSchema` (call `lamina_models_describe` first). Unknown keys are rejected with a structured `invalid_params` error; each error has `field` + `allowed`/`range`/`got` so you can correct on retry. Omitted optional keys fall back to schema defaults.
• `webhookUrl` (optional): HTTPS URL. On terminal status Lamina POSTs `{runId, status, model, prompt, resolvedParams, output, errorMessage, completedAt}` HMAC-signed.
RESPONSE: `{runId, status: "queued"|"completed", model, mode, prompt, resolvedParams}`. `mode` is the resolved value ("text-to-image" | "image-to-image"). The `runId` is the fal_request_id — pass it to `lamina_status`.
SYNC vs ASYNC: identical contract. Vertex-backed models (`imagen-4.0-*`, `gemini-2.5-flash-image`) complete in seconds and return `status: "completed"` on the first poll. fal-backed models queue and take 5–60s. `lamina_status({ wait: true })` handles both transparently.
ERROR HANDLING: validation failures return `code` + `details.errors[]` with `field` + `error` + `allowed`/`range`/`got`. Common codes: `model_not_supported`, `mode_not_supported`, `invalid_params`, `dispatch_failed`.