Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Generate images via OpenAI, Google, OpenRouter, DashScope, Jimeng, Seedream, and Replicate APIs with batch support.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/providers/openrouter.test.ts
1import assert from "node:assert/strict";2import test from "node:test";34import type { CliArgs } from "../types.ts";5import {6buildContent,7buildRequestBody,8extractImageFromResponse,9getAspectRatio,10getImageSize,11validateArgs,12} from "./openrouter.ts";1314const GEMINI_MODEL = "google/gemini-3.1-flash-image-preview";15const GEMINI_25_MODEL = "google/gemini-2.5-flash-image";16const GPT_5_IMAGE_MODEL = "openai/gpt-5-image";17const OPENROUTER_AUTO_MODEL = "openrouter/auto";18const FLUX_MODEL = "black-forest-labs/flux.2-pro";1920function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {21return {22prompt: null,23promptFiles: [],24imagePath: null,25provider: null,26model: null,27aspectRatio: null,28size: null,29quality: null,30imageSize: null,31imageApiDialect: null,32referenceImages: [],33n: 1,34batchFile: null,35jobs: null,36json: false,37help: false,38...overrides,39};40}4142test("OpenRouter request body uses image_config and string content for text-only prompts", () => {43const args = makeArgs({ aspectRatio: "16:9", quality: "2k" });44const body = buildRequestBody("hello", GEMINI_MODEL, args, []);4546assert.deepEqual(body.image_config, {47image_size: "2K",48aspect_ratio: "16:9",49});50assert.deepEqual(body.provider, {51require_parameters: true,52});53assert.deepEqual(body.modalities, ["image", "text"]);54assert.equal(body.stream, false);55assert.equal(body.messages[0].content, "hello");56});5758test("OpenRouter request body keeps text+image modalities for current text+image models", () => {59for (const model of [GEMINI_MODEL, GEMINI_25_MODEL, GPT_5_IMAGE_MODEL, OPENROUTER_AUTO_MODEL]) {60const body = buildRequestBody("hello", model, makeArgs({ quality: "2k" }), []);6162assert.deepEqual(body.image_config, {63image_size: "2K",64});65assert.deepEqual(body.provider, {66require_parameters: true,67});68assert.deepEqual(body.modalities, ["image", "text"]);69assert.equal(body.messages[0].content, "hello");70}71});7273test("OpenRouter request body uses image-only modalities for image-only models under CLI defaults", () => {74const body = buildRequestBody("hello", FLUX_MODEL, makeArgs({ quality: "2k" }), []);7576assert.deepEqual(body.image_config, {77image_size: "2K",78});79assert.deepEqual(body.provider, {80require_parameters: true,81});82assert.deepEqual(body.modalities, ["image"]);83assert.equal(body.stream, false);84assert.equal(body.messages[0].content, "hello");85});8687test("OpenRouter helper omits image_config when no size or quality is passed", () => {88const body = buildRequestBody("hello", FLUX_MODEL, makeArgs(), []);8990assert.equal(body.image_config, undefined);91assert.equal(body.provider, undefined);92assert.deepEqual(body.modalities, ["image"]);93assert.equal(body.stream, false);94assert.equal(body.messages[0].content, "hello");95});9697test("OpenRouter request body keeps multimodal array content when references are provided", () => {98const content = buildContent("hello", ["data:image/png;base64,abc"]);99assert.ok(Array.isArray(content));100assert.deepEqual(content[0], { type: "text", text: "hello" });101assert.deepEqual(content[1], {102type: "image_url",103image_url: { url: "data:image/png;base64,abc" },104});105});106107test("OpenRouter size and aspect helpers infer supported values", () => {108assert.equal(getImageSize(makeArgs()), null);109assert.equal(getImageSize(makeArgs({ quality: "normal" })), "1K");110assert.equal(getImageSize(makeArgs({ size: "2048x1024" })), "2K");111assert.equal(getAspectRatio(GEMINI_MODEL, makeArgs({ size: "1600x900" })), "16:9");112assert.equal(getAspectRatio(GEMINI_MODEL, makeArgs({ size: "1024x4096" })), "1:4");113assert.equal(getAspectRatio(GEMINI_25_MODEL, makeArgs({ size: "1600x900" })), "16:9");114assert.equal(getAspectRatio(FLUX_MODEL, makeArgs({ size: "1024x4096" })), null);115});116117test("OpenRouter validates explicit aspect ratios and inferred size ratios against model support", () => {118assert.doesNotThrow(() =>119validateArgs(GEMINI_MODEL, makeArgs({ aspectRatio: "1:4" })),120);121assert.doesNotThrow(() =>122validateArgs(GEMINI_MODEL, makeArgs({ size: "1024x4096" })),123);124assert.throws(125() => validateArgs(GEMINI_25_MODEL, makeArgs({ aspectRatio: "1:4" })),126/does not support aspect ratio 1:4/,127);128assert.throws(129() => validateArgs(FLUX_MODEL, makeArgs({ aspectRatio: "1:4" })),130/does not support aspect ratio 1:4/,131);132assert.throws(133() => validateArgs(GEMINI_MODEL, makeArgs({ size: "2048x1024" })),134/does not support size 2048x1024 \(aspect ratio 2:1\)/,135);136});137138test("OpenRouter response extraction supports inline image data and finish_reason errors", async () => {139const bytes = await extractImageFromResponse({140choices: [141{142message: {143images: [144{145image_url: {146url: `data:image/png;base64,${Buffer.from("hello").toString("base64")}`,147},148},149],150},151},152],153});154assert.equal(Buffer.from(bytes).toString("utf8"), "hello");155156await assert.rejects(157() =>158extractImageFromResponse({159choices: [160{161finish_reason: "error",162native_finish_reason: "MALFORMED_FUNCTION_CALL",163message: { content: null },164},165],166}),167/finish_reason=MALFORMED_FUNCTION_CALL/,168);169});170