@blockrun/clawrouter 0.12.246 → 0.12.247
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 +1 -0
- package/dist/cli.js +128 -37
- package/dist/index.d.ts +7 -1
- package/dist/index.js +128 -37
- package/docs/image-generation.md +34 -23
- package/package.json +1 -1
- package/scripts/reinstall.sh +1 -1
- package/skills/clawrouter/SKILL.md +1 -1
- package/skills/imagegen/SKILL.md +9 -7
package/README.md
CHANGED
|
@@ -244,6 +244,7 @@ Generate images directly from chat with `/cr-imagegen`:
|
|
|
244
244
|
| Model | Provider | Price | Max Size |
|
|
245
245
|
| ---------------------------- | -------------------- | ------------ | --------- |
|
|
246
246
|
| `nano-banana` | Google Gemini Flash | $0.05/image | 1024x1024 |
|
|
247
|
+
| `banana-2` | Google Nano Banana 2 | $0.09/image | 1024x1024 |
|
|
247
248
|
| `banana-pro` | Google Gemini Pro | $0.10/image | 4096x4096 |
|
|
248
249
|
| `gpt-image` | OpenAI GPT Image 1 | $0.02/image | 1536x1024 |
|
|
249
250
|
| `gpt-image-2` | OpenAI GPT Image 2 | $0.06/image | 1536x1024 |
|
package/dist/cli.js
CHANGED
|
@@ -90816,25 +90816,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90816
90816
|
const modelMatch = imageArgs.match(/--model\s+(\S+)/);
|
|
90817
90817
|
if (modelMatch) {
|
|
90818
90818
|
const raw = modelMatch[1];
|
|
90819
|
-
|
|
90820
|
-
// dall-e-3 delisted upstream 2026-05-25 — legacy aliases route to
|
|
90821
|
-
// the OpenAI successor instead of a guaranteed 400.
|
|
90822
|
-
"dall-e-3": "openai/gpt-image-2",
|
|
90823
|
-
dalle3: "openai/gpt-image-2",
|
|
90824
|
-
dalle: "openai/gpt-image-2",
|
|
90825
|
-
"gpt-image": "openai/gpt-image-1",
|
|
90826
|
-
"gpt-image-1": "openai/gpt-image-1",
|
|
90827
|
-
"gpt-image-2": "openai/gpt-image-2",
|
|
90828
|
-
seedream: "bytedance/seedream-5-pro",
|
|
90829
|
-
banana: "google/nano-banana",
|
|
90830
|
-
"nano-banana": "google/nano-banana",
|
|
90831
|
-
"banana-pro": "google/nano-banana-pro",
|
|
90832
|
-
"nano-banana-pro": "google/nano-banana-pro",
|
|
90833
|
-
"grok-imagine": "xai/grok-imagine-image",
|
|
90834
|
-
"grok-imagine-pro": "xai/grok-imagine-image-pro",
|
|
90835
|
-
cogview: "zai/cogview-4"
|
|
90836
|
-
};
|
|
90837
|
-
imageModel = IMAGE_MODEL_ALIASES[raw] ?? raw;
|
|
90819
|
+
imageModel = Object.prototype.hasOwnProperty.call(IMAGE_MODEL_ALIASES, raw) ? IMAGE_MODEL_ALIASES[raw] : raw;
|
|
90838
90820
|
imagePrompt = imagePrompt.replace(/--model\s+\S+/, "").trim();
|
|
90839
90821
|
}
|
|
90840
90822
|
const sizeMatch = imageArgs.match(/--size\s+(\d+x\d+)/);
|
|
@@ -90852,11 +90834,13 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90852
90834
|
"",
|
|
90853
90835
|
"Models:",
|
|
90854
90836
|
" nano-banana Google Gemini Flash \u2014 $0.05/image",
|
|
90837
|
+
" banana-2 Google Nano Banana 2 \u2014 $0.09/image",
|
|
90855
90838
|
" banana-pro Google Gemini Pro \u2014 $0.10/image (up to 4K)",
|
|
90856
90839
|
" gpt-image OpenAI GPT Image 1 \u2014 $0.02/image",
|
|
90857
90840
|
" gpt-image-2 OpenAI GPT Image 2 \u2014 $0.06/image",
|
|
90858
90841
|
" seedream ByteDance Seedream 5 Pro \u2014 $0.045/image",
|
|
90859
90842
|
" grok-imagine xAI Grok Imagine \u2014 $0.02/image",
|
|
90843
|
+
" grok-imagine-pro xAI Grok Imagine Pro \u2014 $0.07/image",
|
|
90860
90844
|
" cogview Zhipu CogView-4 \u2014 $0.015/image",
|
|
90861
90845
|
"",
|
|
90862
90846
|
"Examples:",
|
|
@@ -90919,14 +90903,68 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90919
90903
|
size: imageSize,
|
|
90920
90904
|
n: 1
|
|
90921
90905
|
});
|
|
90906
|
+
const imagegenAbort = new AbortController();
|
|
90907
|
+
res.on("close", () => {
|
|
90908
|
+
if (!res.writableEnded) imagegenAbort.abort();
|
|
90909
|
+
});
|
|
90922
90910
|
const imageResponse = await payFetch(imageUpstreamUrl, {
|
|
90923
90911
|
method: "POST",
|
|
90924
90912
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
90925
|
-
body: imageBody
|
|
90913
|
+
body: imageBody,
|
|
90914
|
+
signal: imagegenAbort.signal
|
|
90926
90915
|
});
|
|
90927
|
-
|
|
90916
|
+
let imageResult = await imageResponse.json();
|
|
90917
|
+
let imageFailure;
|
|
90918
|
+
if (imageResponse.ok && imageResult.poll_url && imageResult.id && !imageResult.data?.length) {
|
|
90919
|
+
const apiOrigin = new URL(apiBase).origin;
|
|
90920
|
+
const pollUrl = imageResult.poll_url.startsWith("http") ? imageResult.poll_url : `${apiOrigin}${imageResult.poll_url}`;
|
|
90921
|
+
console.log(
|
|
90922
|
+
`[ClawRouter] /imagegen job submitted (id=${imageResult.id}), polling upstream \u2014 typical 30\u2013120s...`
|
|
90923
|
+
);
|
|
90924
|
+
const pollDeadline = Date.now() + 3e5;
|
|
90925
|
+
await new Promise((r2) => setTimeout(r2, 2e3));
|
|
90926
|
+
let completed2 = false;
|
|
90927
|
+
while (Date.now() < pollDeadline) {
|
|
90928
|
+
if (imagegenAbort.signal.aborted) {
|
|
90929
|
+
console.log(
|
|
90930
|
+
`[ClawRouter] Chat client disconnected \u2014 abandoning image poll (id=${imageResult.id})`
|
|
90931
|
+
);
|
|
90932
|
+
return;
|
|
90933
|
+
}
|
|
90934
|
+
const pollResp = await payFetch(pollUrl, {
|
|
90935
|
+
method: "GET",
|
|
90936
|
+
headers: { "user-agent": USER_AGENT },
|
|
90937
|
+
signal: imagegenAbort.signal
|
|
90938
|
+
});
|
|
90939
|
+
const pollText = await pollResp.text();
|
|
90940
|
+
let pollBody = {};
|
|
90941
|
+
try {
|
|
90942
|
+
pollBody = JSON.parse(pollText);
|
|
90943
|
+
} catch {
|
|
90944
|
+
imageFailure = `Non-JSON poll response (${pollResp.status}): ${pollText.slice(0, 200)}`;
|
|
90945
|
+
break;
|
|
90946
|
+
}
|
|
90947
|
+
if (pollResp.status === 202 || pollBody.status === "queued" || pollBody.status === "in_progress") {
|
|
90948
|
+
await new Promise((r2) => setTimeout(r2, 3e3));
|
|
90949
|
+
continue;
|
|
90950
|
+
}
|
|
90951
|
+
if (pollBody.status === "failed" || !pollResp.ok) {
|
|
90952
|
+
imageFailure = typeof pollBody.error === "string" ? pollBody.error : pollBody.error?.message ?? `Upstream image generation failed (HTTP ${pollResp.status})`;
|
|
90953
|
+
break;
|
|
90954
|
+
}
|
|
90955
|
+
imageResult = pollBody;
|
|
90956
|
+
completed2 = true;
|
|
90957
|
+
break;
|
|
90958
|
+
}
|
|
90959
|
+
if (!completed2 && !imageFailure) {
|
|
90960
|
+
imageFailure = "Image generation timed out after 5 minutes \u2014 the job may still complete upstream.";
|
|
90961
|
+
}
|
|
90962
|
+
}
|
|
90928
90963
|
let responseText;
|
|
90929
|
-
if (
|
|
90964
|
+
if (imageFailure) {
|
|
90965
|
+
responseText = `Image generation failed: ${imageFailure}`;
|
|
90966
|
+
console.log(`[ClawRouter] /imagegen error: ${imageFailure}`);
|
|
90967
|
+
} else if (!imageResponse.ok || imageResult.error) {
|
|
90930
90968
|
const errMsg = typeof imageResult.error === "string" ? imageResult.error : imageResult.error?.message ?? `HTTP ${imageResponse.status}`;
|
|
90931
90969
|
responseText = `Image generation failed: ${errMsg}`;
|
|
90932
90970
|
console.log(`[ClawRouter] /imagegen error: ${errMsg}`);
|
|
@@ -90946,9 +90984,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90946
90984
|
console.error(
|
|
90947
90985
|
`[ClawRouter] /imagegen: failed to upload data URI: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`
|
|
90948
90986
|
);
|
|
90949
|
-
lines.push(
|
|
90950
|
-
"Image generated but upload failed. Try again or use --model dall-e-3."
|
|
90951
|
-
);
|
|
90987
|
+
lines.push("Image generated but upload failed. Try again.");
|
|
90952
90988
|
}
|
|
90953
90989
|
} else {
|
|
90954
90990
|
lines.push(img.url);
|
|
@@ -92732,7 +92768,7 @@ data: [DONE]
|
|
|
92732
92768
|
});
|
|
92733
92769
|
}
|
|
92734
92770
|
}
|
|
92735
|
-
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, VIDEO_PRICING, PHONE_PRICING;
|
|
92771
|
+
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, IMAGE_MODEL_IDS, IMAGE_MODEL_SIZES, IMAGE_MODEL_ALIASES, VIDEO_PRICING, PHONE_PRICING;
|
|
92736
92772
|
var init_proxy = __esm({
|
|
92737
92773
|
"src/proxy.ts"() {
|
|
92738
92774
|
"use strict";
|
|
@@ -92877,9 +92913,20 @@ var init_proxy = __esm({
|
|
|
92877
92913
|
},
|
|
92878
92914
|
"bytedance/seedream-5-pro": {
|
|
92879
92915
|
default: 0.045,
|
|
92880
|
-
|
|
92916
|
+
// Full size list live-probed 2026-08-23 (gateway 402 quotes, base price):
|
|
92917
|
+
// the 2K portrait/landscape tiers bill at the 2048x2048 rate.
|
|
92918
|
+
sizes: {
|
|
92919
|
+
"1024x1024": 0.045,
|
|
92920
|
+
"1280x720": 0.045,
|
|
92921
|
+
"2048x1024": 0.045,
|
|
92922
|
+
"2048x2048": 0.09,
|
|
92923
|
+
"2304x1728": 0.09,
|
|
92924
|
+
"1728x2304": 0.09,
|
|
92925
|
+
"2848x1600": 0.09,
|
|
92926
|
+
"1600x2848": 0.09
|
|
92927
|
+
}
|
|
92881
92928
|
},
|
|
92882
|
-
"google/nano-banana": { default: 0.05 },
|
|
92929
|
+
"google/nano-banana": { default: 0.05, sizes: { "1024x1024": 0.05 } },
|
|
92883
92930
|
// Nano Banana 2 (Gemini 3.1 Flash imagegen, blockrun #329): $0.09/image at 1K.
|
|
92884
92931
|
"google/nano-banana-2": { default: 0.09, sizes: { "1024x1024": 0.09 } },
|
|
92885
92932
|
"google/nano-banana-pro": {
|
|
@@ -92900,6 +92947,30 @@ var init_proxy = __esm({
|
|
|
92900
92947
|
}
|
|
92901
92948
|
}
|
|
92902
92949
|
};
|
|
92950
|
+
IMAGE_MODEL_IDS = Object.freeze(Object.keys(IMAGE_PRICING));
|
|
92951
|
+
IMAGE_MODEL_SIZES = Object.freeze(
|
|
92952
|
+
[...new Set(Object.values(IMAGE_PRICING).flatMap((p) => Object.keys(p.sizes ?? {})))].sort()
|
|
92953
|
+
);
|
|
92954
|
+
IMAGE_MODEL_ALIASES = Object.freeze({
|
|
92955
|
+
// dall-e-3 delisted upstream 2026-05-25 — legacy aliases route to
|
|
92956
|
+
// the OpenAI successor instead of a guaranteed 400.
|
|
92957
|
+
"dall-e-3": "openai/gpt-image-2",
|
|
92958
|
+
dalle3: "openai/gpt-image-2",
|
|
92959
|
+
dalle: "openai/gpt-image-2",
|
|
92960
|
+
"gpt-image": "openai/gpt-image-1",
|
|
92961
|
+
"gpt-image-1": "openai/gpt-image-1",
|
|
92962
|
+
"gpt-image-2": "openai/gpt-image-2",
|
|
92963
|
+
seedream: "bytedance/seedream-5-pro",
|
|
92964
|
+
banana: "google/nano-banana",
|
|
92965
|
+
"nano-banana": "google/nano-banana",
|
|
92966
|
+
"banana-2": "google/nano-banana-2",
|
|
92967
|
+
"nano-banana-2": "google/nano-banana-2",
|
|
92968
|
+
"banana-pro": "google/nano-banana-pro",
|
|
92969
|
+
"nano-banana-pro": "google/nano-banana-pro",
|
|
92970
|
+
"grok-imagine": "xai/grok-imagine-image",
|
|
92971
|
+
"grok-imagine-pro": "xai/grok-imagine-image-pro",
|
|
92972
|
+
cogview: "zai/cogview-4"
|
|
92973
|
+
});
|
|
92903
92974
|
VIDEO_PRICING = {
|
|
92904
92975
|
"xai/grok-imagine-video": { pricePerSecond: 0.05, defaultDurationSeconds: 8 },
|
|
92905
92976
|
// Seedance rates re-synced 2026-08-08 from blockrun's models.ts after the
|
|
@@ -93402,8 +93473,8 @@ var init_registry = __esm({
|
|
|
93402
93473
|
name: "Image Generation",
|
|
93403
93474
|
partner: "BlockRun",
|
|
93404
93475
|
category: "Image & Video",
|
|
93405
|
-
shortDescription: "
|
|
93406
|
-
description: "Generate an image from a text prompt. Models available: google/nano-banana (default), google/nano-banana-pro (up to 4K), openai/gpt-image-1, openai/
|
|
93476
|
+
shortDescription: "9 image models (Nano Banana, GPT Image, ...)",
|
|
93477
|
+
description: "Generate an image from a text prompt. Models available: google/nano-banana (default), google/nano-banana-2, google/nano-banana-pro (up to 4K), openai/gpt-image-1, openai/gpt-image-2, bytedance/seedream-5-pro, xai/grok-imagine-image, xai/grok-imagine-image-pro, zai/cogview-4. Returns a local http://localhost:8402/images/<file>.png URL.",
|
|
93407
93478
|
proxyPath: "/images/generations",
|
|
93408
93479
|
method: "POST",
|
|
93409
93480
|
params: [
|
|
@@ -93416,7 +93487,7 @@ var init_registry = __esm({
|
|
|
93416
93487
|
{
|
|
93417
93488
|
name: "model",
|
|
93418
93489
|
type: "string",
|
|
93419
|
-
description: "Full model ID (e.g. 'google/nano-banana', 'openai/
|
|
93490
|
+
description: "Full model ID (e.g. 'google/nano-banana', 'openai/gpt-image-2'). Default: google/nano-banana.",
|
|
93420
93491
|
required: false
|
|
93421
93492
|
},
|
|
93422
93493
|
{
|
|
@@ -225359,6 +225430,7 @@ __export(index_exports, {
|
|
|
225359
225430
|
SpendControl: () => SpendControl,
|
|
225360
225431
|
VISIBLE_OPENCLAW_MODELS: () => VISIBLE_OPENCLAW_MODELS,
|
|
225361
225432
|
blockrunProvider: () => blockrunProvider,
|
|
225433
|
+
buildImageGenerationProvider: () => buildImageGenerationProvider,
|
|
225362
225434
|
buildPartnerTools: () => buildPartnerTools,
|
|
225363
225435
|
buildProviderModels: () => buildProviderModels,
|
|
225364
225436
|
calculateModelCost: () => calculateModelCost,
|
|
@@ -226122,12 +226194,23 @@ function buildImageGenerationProvider() {
|
|
|
226122
226194
|
id: "blockrun",
|
|
226123
226195
|
label: "BlockRun",
|
|
226124
226196
|
defaultModel: "google/nano-banana",
|
|
226197
|
+
// Must stay in sync with IMAGE_PRICING (proxy.ts). OpenClaw sends the
|
|
226198
|
+
// picked id straight to /v1/images/generations, which forwards the body
|
|
226199
|
+
// verbatim with no alias resolution, so a retired id here is a guaranteed
|
|
226200
|
+
// upstream 400. dall-e-3 (delisted 2026-05-25) and flux-1.1-pro (no
|
|
226201
|
+
// gateway entry) were dropped in v0.12.227 and had lingered here.
|
|
226202
|
+
// Kept as a hand-written array (not spread from IMAGE_MODEL_IDS) because
|
|
226203
|
+
// this is the picker's curated display order — default model first, which
|
|
226204
|
+
// IMAGE_PRICING declaration order does not give — and because the
|
|
226205
|
+
// lifecycle tests fully mock ./proxy.js. Set-equality is enforced by
|
|
226206
|
+
// src/index.image-provider.test.ts, which pins the two lists together.
|
|
226125
226207
|
models: [
|
|
226126
226208
|
"google/nano-banana",
|
|
226209
|
+
"google/nano-banana-2",
|
|
226127
226210
|
"google/nano-banana-pro",
|
|
226128
226211
|
"openai/gpt-image-1",
|
|
226129
|
-
"openai/
|
|
226130
|
-
"
|
|
226212
|
+
"openai/gpt-image-2",
|
|
226213
|
+
"bytedance/seedream-5-pro",
|
|
226131
226214
|
"xai/grok-imagine-image",
|
|
226132
226215
|
"xai/grok-imagine-image-pro",
|
|
226133
226216
|
"zai/cogview-4"
|
|
@@ -226142,20 +226225,28 @@ function buildImageGenerationProvider() {
|
|
|
226142
226225
|
// Only openai/gpt-image-1 supports edit server-side; OpenClaw's UI picks a
|
|
226143
226226
|
// compatible model at edit time via /v1/images/image2image.
|
|
226144
226227
|
edit: { enabled: true },
|
|
226228
|
+
// Union of every size the gateway accepts across the models above,
|
|
226229
|
+
// live-probed 2026-08-23 (the gateway validates size per-model BEFORE
|
|
226230
|
+
// payment and 400s unknown ones — 1216x832 / 1792x1024 / 1024x1792 were
|
|
226231
|
+
// accepted by no model and are gone with dall-e-3). Pinned against
|
|
226232
|
+
// IMAGE_MODEL_SIZES (proxy.ts) by src/index.image-provider.test.ts.
|
|
226145
226233
|
geometry: {
|
|
226146
226234
|
sizes: [
|
|
226147
226235
|
"512x512",
|
|
226148
226236
|
"768x768",
|
|
226149
226237
|
"768x1344",
|
|
226150
226238
|
"1024x1024",
|
|
226151
|
-
"
|
|
226239
|
+
"1024x1536",
|
|
226240
|
+
"1280x720",
|
|
226152
226241
|
"1344x768",
|
|
226153
226242
|
"1440x1440",
|
|
226154
226243
|
"1536x1024",
|
|
226155
|
-
"
|
|
226156
|
-
"
|
|
226157
|
-
"
|
|
226244
|
+
"1600x2848",
|
|
226245
|
+
"1728x2304",
|
|
226246
|
+
"2048x1024",
|
|
226158
226247
|
"2048x2048",
|
|
226248
|
+
"2304x1728",
|
|
226249
|
+
"2848x1600",
|
|
226159
226250
|
"4096x4096"
|
|
226160
226251
|
]
|
|
226161
226252
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1594,6 +1594,12 @@ declare function parseCallArgs(raw: string): {
|
|
|
1594
1594
|
from?: string;
|
|
1595
1595
|
language?: string;
|
|
1596
1596
|
};
|
|
1597
|
+
/**
|
|
1598
|
+
* Build the ImageGenerationProvider that registers BlockRun image models
|
|
1599
|
+
* with OpenClaw's native image generation UI.
|
|
1600
|
+
* Delegates to the local proxy (which handles x402 payment).
|
|
1601
|
+
*/
|
|
1602
|
+
declare function buildImageGenerationProvider(): ImageGenerationProviderPlugin;
|
|
1597
1603
|
declare const plugin: OpenClawPluginDefinition;
|
|
1598
1604
|
|
|
1599
|
-
export { type AggregatedStats, BALANCE_THRESHOLDS, BLOCKRUN_MODELS, type BalanceInfo, BalanceMonitor, type CachedLLMResponse, type CachedResponse, type CheckResult, DEFAULT_RETRY_CONFIG, DEFAULT_SESSION_CONFIG, type DailyStats, type DerivedKeys, EmptyWalletError, FileSpendControlStorage, InMemorySpendControlStorage, InsufficientFundsError, type InsufficientFundsInfo, type LowBalanceInfo, MODEL_ALIASES, OPENCLAW_MODELS, PARTNER_SERVICES, type PartnerServiceDefinition, type PartnerToolDefinition, type PaymentChain, type ProxyHandle, type ProxyOptions, RequestDeduplicator, ResponseCache, type ResponseCacheConfig, type RetryConfig, RpcError, type SessionConfig, type SessionEntry, SessionStore, type SolanaBalanceInfo, SolanaBalanceMonitor, SpendControl, type SpendControlOptions, type SpendControlStorage, type SpendLimits, type SpendRecord, type SpendWindow, type SpendingStatus, type SufficiencyResult, type UsageEntry, VISIBLE_OPENCLAW_MODELS, type WalletConfig, type WalletResolution, blockrunProvider, buildPartnerTools, buildProviderModels, clearStats, plugin as default, deriveAllKeys, deriveEvmKey, deriveSolanaKeyBytes, fetchWithRetry, formatDuration, formatStatsAscii, generateWalletMnemonic, getAgenticModels, getModelContextWindow, getPartnerService, getProxyPort, getSessionId, getStats, hashRequestContent, injectAuthProfile, injectModelsConfig, isAgenticModel, isBalanceError, isBlockrunWebSearchDisabled, isEmptyWalletError, isInsufficientFundsError, isRetryable, isRpcError, isValidMnemonic, loadPaymentChain, logUsage, parseCallArgs, resolveModelAlias, resolvePaymentChain, savePaymentChain, setupSolana, startProxy, syncAgentModelCache };
|
|
1605
|
+
export { type AggregatedStats, BALANCE_THRESHOLDS, BLOCKRUN_MODELS, type BalanceInfo, BalanceMonitor, type CachedLLMResponse, type CachedResponse, type CheckResult, DEFAULT_RETRY_CONFIG, DEFAULT_SESSION_CONFIG, type DailyStats, type DerivedKeys, EmptyWalletError, FileSpendControlStorage, InMemorySpendControlStorage, InsufficientFundsError, type InsufficientFundsInfo, type LowBalanceInfo, MODEL_ALIASES, OPENCLAW_MODELS, PARTNER_SERVICES, type PartnerServiceDefinition, type PartnerToolDefinition, type PaymentChain, type ProxyHandle, type ProxyOptions, RequestDeduplicator, ResponseCache, type ResponseCacheConfig, type RetryConfig, RpcError, type SessionConfig, type SessionEntry, SessionStore, type SolanaBalanceInfo, SolanaBalanceMonitor, SpendControl, type SpendControlOptions, type SpendControlStorage, type SpendLimits, type SpendRecord, type SpendWindow, type SpendingStatus, type SufficiencyResult, type UsageEntry, VISIBLE_OPENCLAW_MODELS, type WalletConfig, type WalletResolution, blockrunProvider, buildImageGenerationProvider, buildPartnerTools, buildProviderModels, clearStats, plugin as default, deriveAllKeys, deriveEvmKey, deriveSolanaKeyBytes, fetchWithRetry, formatDuration, formatStatsAscii, generateWalletMnemonic, getAgenticModels, getModelContextWindow, getPartnerService, getProxyPort, getSessionId, getStats, hashRequestContent, injectAuthProfile, injectModelsConfig, isAgenticModel, isBalanceError, isBlockrunWebSearchDisabled, isEmptyWalletError, isInsufficientFundsError, isRetryable, isRpcError, isValidMnemonic, loadPaymentChain, logUsage, parseCallArgs, resolveModelAlias, resolvePaymentChain, savePaymentChain, setupSolana, startProxy, syncAgentModelCache };
|
package/dist/index.js
CHANGED
|
@@ -90636,25 +90636,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90636
90636
|
const modelMatch = imageArgs.match(/--model\s+(\S+)/);
|
|
90637
90637
|
if (modelMatch) {
|
|
90638
90638
|
const raw = modelMatch[1];
|
|
90639
|
-
|
|
90640
|
-
// dall-e-3 delisted upstream 2026-05-25 — legacy aliases route to
|
|
90641
|
-
// the OpenAI successor instead of a guaranteed 400.
|
|
90642
|
-
"dall-e-3": "openai/gpt-image-2",
|
|
90643
|
-
dalle3: "openai/gpt-image-2",
|
|
90644
|
-
dalle: "openai/gpt-image-2",
|
|
90645
|
-
"gpt-image": "openai/gpt-image-1",
|
|
90646
|
-
"gpt-image-1": "openai/gpt-image-1",
|
|
90647
|
-
"gpt-image-2": "openai/gpt-image-2",
|
|
90648
|
-
seedream: "bytedance/seedream-5-pro",
|
|
90649
|
-
banana: "google/nano-banana",
|
|
90650
|
-
"nano-banana": "google/nano-banana",
|
|
90651
|
-
"banana-pro": "google/nano-banana-pro",
|
|
90652
|
-
"nano-banana-pro": "google/nano-banana-pro",
|
|
90653
|
-
"grok-imagine": "xai/grok-imagine-image",
|
|
90654
|
-
"grok-imagine-pro": "xai/grok-imagine-image-pro",
|
|
90655
|
-
cogview: "zai/cogview-4"
|
|
90656
|
-
};
|
|
90657
|
-
imageModel = IMAGE_MODEL_ALIASES[raw] ?? raw;
|
|
90639
|
+
imageModel = Object.prototype.hasOwnProperty.call(IMAGE_MODEL_ALIASES, raw) ? IMAGE_MODEL_ALIASES[raw] : raw;
|
|
90658
90640
|
imagePrompt = imagePrompt.replace(/--model\s+\S+/, "").trim();
|
|
90659
90641
|
}
|
|
90660
90642
|
const sizeMatch = imageArgs.match(/--size\s+(\d+x\d+)/);
|
|
@@ -90672,11 +90654,13 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90672
90654
|
"",
|
|
90673
90655
|
"Models:",
|
|
90674
90656
|
" nano-banana Google Gemini Flash \u2014 $0.05/image",
|
|
90657
|
+
" banana-2 Google Nano Banana 2 \u2014 $0.09/image",
|
|
90675
90658
|
" banana-pro Google Gemini Pro \u2014 $0.10/image (up to 4K)",
|
|
90676
90659
|
" gpt-image OpenAI GPT Image 1 \u2014 $0.02/image",
|
|
90677
90660
|
" gpt-image-2 OpenAI GPT Image 2 \u2014 $0.06/image",
|
|
90678
90661
|
" seedream ByteDance Seedream 5 Pro \u2014 $0.045/image",
|
|
90679
90662
|
" grok-imagine xAI Grok Imagine \u2014 $0.02/image",
|
|
90663
|
+
" grok-imagine-pro xAI Grok Imagine Pro \u2014 $0.07/image",
|
|
90680
90664
|
" cogview Zhipu CogView-4 \u2014 $0.015/image",
|
|
90681
90665
|
"",
|
|
90682
90666
|
"Examples:",
|
|
@@ -90739,14 +90723,68 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90739
90723
|
size: imageSize,
|
|
90740
90724
|
n: 1
|
|
90741
90725
|
});
|
|
90726
|
+
const imagegenAbort = new AbortController();
|
|
90727
|
+
res.on("close", () => {
|
|
90728
|
+
if (!res.writableEnded) imagegenAbort.abort();
|
|
90729
|
+
});
|
|
90742
90730
|
const imageResponse = await payFetch(imageUpstreamUrl, {
|
|
90743
90731
|
method: "POST",
|
|
90744
90732
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
90745
|
-
body: imageBody
|
|
90733
|
+
body: imageBody,
|
|
90734
|
+
signal: imagegenAbort.signal
|
|
90746
90735
|
});
|
|
90747
|
-
|
|
90736
|
+
let imageResult = await imageResponse.json();
|
|
90737
|
+
let imageFailure;
|
|
90738
|
+
if (imageResponse.ok && imageResult.poll_url && imageResult.id && !imageResult.data?.length) {
|
|
90739
|
+
const apiOrigin = new URL(apiBase).origin;
|
|
90740
|
+
const pollUrl = imageResult.poll_url.startsWith("http") ? imageResult.poll_url : `${apiOrigin}${imageResult.poll_url}`;
|
|
90741
|
+
console.log(
|
|
90742
|
+
`[ClawRouter] /imagegen job submitted (id=${imageResult.id}), polling upstream \u2014 typical 30\u2013120s...`
|
|
90743
|
+
);
|
|
90744
|
+
const pollDeadline = Date.now() + 3e5;
|
|
90745
|
+
await new Promise((r2) => setTimeout(r2, 2e3));
|
|
90746
|
+
let completed2 = false;
|
|
90747
|
+
while (Date.now() < pollDeadline) {
|
|
90748
|
+
if (imagegenAbort.signal.aborted) {
|
|
90749
|
+
console.log(
|
|
90750
|
+
`[ClawRouter] Chat client disconnected \u2014 abandoning image poll (id=${imageResult.id})`
|
|
90751
|
+
);
|
|
90752
|
+
return;
|
|
90753
|
+
}
|
|
90754
|
+
const pollResp = await payFetch(pollUrl, {
|
|
90755
|
+
method: "GET",
|
|
90756
|
+
headers: { "user-agent": USER_AGENT },
|
|
90757
|
+
signal: imagegenAbort.signal
|
|
90758
|
+
});
|
|
90759
|
+
const pollText = await pollResp.text();
|
|
90760
|
+
let pollBody = {};
|
|
90761
|
+
try {
|
|
90762
|
+
pollBody = JSON.parse(pollText);
|
|
90763
|
+
} catch {
|
|
90764
|
+
imageFailure = `Non-JSON poll response (${pollResp.status}): ${pollText.slice(0, 200)}`;
|
|
90765
|
+
break;
|
|
90766
|
+
}
|
|
90767
|
+
if (pollResp.status === 202 || pollBody.status === "queued" || pollBody.status === "in_progress") {
|
|
90768
|
+
await new Promise((r2) => setTimeout(r2, 3e3));
|
|
90769
|
+
continue;
|
|
90770
|
+
}
|
|
90771
|
+
if (pollBody.status === "failed" || !pollResp.ok) {
|
|
90772
|
+
imageFailure = typeof pollBody.error === "string" ? pollBody.error : pollBody.error?.message ?? `Upstream image generation failed (HTTP ${pollResp.status})`;
|
|
90773
|
+
break;
|
|
90774
|
+
}
|
|
90775
|
+
imageResult = pollBody;
|
|
90776
|
+
completed2 = true;
|
|
90777
|
+
break;
|
|
90778
|
+
}
|
|
90779
|
+
if (!completed2 && !imageFailure) {
|
|
90780
|
+
imageFailure = "Image generation timed out after 5 minutes \u2014 the job may still complete upstream.";
|
|
90781
|
+
}
|
|
90782
|
+
}
|
|
90748
90783
|
let responseText;
|
|
90749
|
-
if (
|
|
90784
|
+
if (imageFailure) {
|
|
90785
|
+
responseText = `Image generation failed: ${imageFailure}`;
|
|
90786
|
+
console.log(`[ClawRouter] /imagegen error: ${imageFailure}`);
|
|
90787
|
+
} else if (!imageResponse.ok || imageResult.error) {
|
|
90750
90788
|
const errMsg = typeof imageResult.error === "string" ? imageResult.error : imageResult.error?.message ?? `HTTP ${imageResponse.status}`;
|
|
90751
90789
|
responseText = `Image generation failed: ${errMsg}`;
|
|
90752
90790
|
console.log(`[ClawRouter] /imagegen error: ${errMsg}`);
|
|
@@ -90766,9 +90804,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90766
90804
|
console.error(
|
|
90767
90805
|
`[ClawRouter] /imagegen: failed to upload data URI: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`
|
|
90768
90806
|
);
|
|
90769
|
-
lines.push(
|
|
90770
|
-
"Image generated but upload failed. Try again or use --model dall-e-3."
|
|
90771
|
-
);
|
|
90807
|
+
lines.push("Image generated but upload failed. Try again.");
|
|
90772
90808
|
}
|
|
90773
90809
|
} else {
|
|
90774
90810
|
lines.push(img.url);
|
|
@@ -92552,7 +92588,7 @@ data: [DONE]
|
|
|
92552
92588
|
});
|
|
92553
92589
|
}
|
|
92554
92590
|
}
|
|
92555
|
-
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, VIDEO_PRICING, PHONE_PRICING;
|
|
92591
|
+
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, IMAGE_MODEL_IDS, IMAGE_MODEL_SIZES, IMAGE_MODEL_ALIASES, VIDEO_PRICING, PHONE_PRICING;
|
|
92556
92592
|
var init_proxy = __esm({
|
|
92557
92593
|
"src/proxy.ts"() {
|
|
92558
92594
|
"use strict";
|
|
@@ -92697,9 +92733,20 @@ var init_proxy = __esm({
|
|
|
92697
92733
|
},
|
|
92698
92734
|
"bytedance/seedream-5-pro": {
|
|
92699
92735
|
default: 0.045,
|
|
92700
|
-
|
|
92736
|
+
// Full size list live-probed 2026-08-23 (gateway 402 quotes, base price):
|
|
92737
|
+
// the 2K portrait/landscape tiers bill at the 2048x2048 rate.
|
|
92738
|
+
sizes: {
|
|
92739
|
+
"1024x1024": 0.045,
|
|
92740
|
+
"1280x720": 0.045,
|
|
92741
|
+
"2048x1024": 0.045,
|
|
92742
|
+
"2048x2048": 0.09,
|
|
92743
|
+
"2304x1728": 0.09,
|
|
92744
|
+
"1728x2304": 0.09,
|
|
92745
|
+
"2848x1600": 0.09,
|
|
92746
|
+
"1600x2848": 0.09
|
|
92747
|
+
}
|
|
92701
92748
|
},
|
|
92702
|
-
"google/nano-banana": { default: 0.05 },
|
|
92749
|
+
"google/nano-banana": { default: 0.05, sizes: { "1024x1024": 0.05 } },
|
|
92703
92750
|
// Nano Banana 2 (Gemini 3.1 Flash imagegen, blockrun #329): $0.09/image at 1K.
|
|
92704
92751
|
"google/nano-banana-2": { default: 0.09, sizes: { "1024x1024": 0.09 } },
|
|
92705
92752
|
"google/nano-banana-pro": {
|
|
@@ -92720,6 +92767,30 @@ var init_proxy = __esm({
|
|
|
92720
92767
|
}
|
|
92721
92768
|
}
|
|
92722
92769
|
};
|
|
92770
|
+
IMAGE_MODEL_IDS = Object.freeze(Object.keys(IMAGE_PRICING));
|
|
92771
|
+
IMAGE_MODEL_SIZES = Object.freeze(
|
|
92772
|
+
[...new Set(Object.values(IMAGE_PRICING).flatMap((p) => Object.keys(p.sizes ?? {})))].sort()
|
|
92773
|
+
);
|
|
92774
|
+
IMAGE_MODEL_ALIASES = Object.freeze({
|
|
92775
|
+
// dall-e-3 delisted upstream 2026-05-25 — legacy aliases route to
|
|
92776
|
+
// the OpenAI successor instead of a guaranteed 400.
|
|
92777
|
+
"dall-e-3": "openai/gpt-image-2",
|
|
92778
|
+
dalle3: "openai/gpt-image-2",
|
|
92779
|
+
dalle: "openai/gpt-image-2",
|
|
92780
|
+
"gpt-image": "openai/gpt-image-1",
|
|
92781
|
+
"gpt-image-1": "openai/gpt-image-1",
|
|
92782
|
+
"gpt-image-2": "openai/gpt-image-2",
|
|
92783
|
+
seedream: "bytedance/seedream-5-pro",
|
|
92784
|
+
banana: "google/nano-banana",
|
|
92785
|
+
"nano-banana": "google/nano-banana",
|
|
92786
|
+
"banana-2": "google/nano-banana-2",
|
|
92787
|
+
"nano-banana-2": "google/nano-banana-2",
|
|
92788
|
+
"banana-pro": "google/nano-banana-pro",
|
|
92789
|
+
"nano-banana-pro": "google/nano-banana-pro",
|
|
92790
|
+
"grok-imagine": "xai/grok-imagine-image",
|
|
92791
|
+
"grok-imagine-pro": "xai/grok-imagine-image-pro",
|
|
92792
|
+
cogview: "zai/cogview-4"
|
|
92793
|
+
});
|
|
92723
92794
|
VIDEO_PRICING = {
|
|
92724
92795
|
"xai/grok-imagine-video": { pricePerSecond: 0.05, defaultDurationSeconds: 8 },
|
|
92725
92796
|
// Seedance rates re-synced 2026-08-08 from blockrun's models.ts after the
|
|
@@ -93493,8 +93564,8 @@ var init_registry = __esm({
|
|
|
93493
93564
|
name: "Image Generation",
|
|
93494
93565
|
partner: "BlockRun",
|
|
93495
93566
|
category: "Image & Video",
|
|
93496
|
-
shortDescription: "
|
|
93497
|
-
description: "Generate an image from a text prompt. Models available: google/nano-banana (default), google/nano-banana-pro (up to 4K), openai/gpt-image-1, openai/
|
|
93567
|
+
shortDescription: "9 image models (Nano Banana, GPT Image, ...)",
|
|
93568
|
+
description: "Generate an image from a text prompt. Models available: google/nano-banana (default), google/nano-banana-2, google/nano-banana-pro (up to 4K), openai/gpt-image-1, openai/gpt-image-2, bytedance/seedream-5-pro, xai/grok-imagine-image, xai/grok-imagine-image-pro, zai/cogview-4. Returns a local http://localhost:8402/images/<file>.png URL.",
|
|
93498
93569
|
proxyPath: "/images/generations",
|
|
93499
93570
|
method: "POST",
|
|
93500
93571
|
params: [
|
|
@@ -93507,7 +93578,7 @@ var init_registry = __esm({
|
|
|
93507
93578
|
{
|
|
93508
93579
|
name: "model",
|
|
93509
93580
|
type: "string",
|
|
93510
|
-
description: "Full model ID (e.g. 'google/nano-banana', 'openai/
|
|
93581
|
+
description: "Full model ID (e.g. 'google/nano-banana', 'openai/gpt-image-2'). Default: google/nano-banana.",
|
|
93511
93582
|
required: false
|
|
93512
93583
|
},
|
|
93513
93584
|
{
|
|
@@ -225875,12 +225946,23 @@ function buildImageGenerationProvider() {
|
|
|
225875
225946
|
id: "blockrun",
|
|
225876
225947
|
label: "BlockRun",
|
|
225877
225948
|
defaultModel: "google/nano-banana",
|
|
225949
|
+
// Must stay in sync with IMAGE_PRICING (proxy.ts). OpenClaw sends the
|
|
225950
|
+
// picked id straight to /v1/images/generations, which forwards the body
|
|
225951
|
+
// verbatim with no alias resolution, so a retired id here is a guaranteed
|
|
225952
|
+
// upstream 400. dall-e-3 (delisted 2026-05-25) and flux-1.1-pro (no
|
|
225953
|
+
// gateway entry) were dropped in v0.12.227 and had lingered here.
|
|
225954
|
+
// Kept as a hand-written array (not spread from IMAGE_MODEL_IDS) because
|
|
225955
|
+
// this is the picker's curated display order — default model first, which
|
|
225956
|
+
// IMAGE_PRICING declaration order does not give — and because the
|
|
225957
|
+
// lifecycle tests fully mock ./proxy.js. Set-equality is enforced by
|
|
225958
|
+
// src/index.image-provider.test.ts, which pins the two lists together.
|
|
225878
225959
|
models: [
|
|
225879
225960
|
"google/nano-banana",
|
|
225961
|
+
"google/nano-banana-2",
|
|
225880
225962
|
"google/nano-banana-pro",
|
|
225881
225963
|
"openai/gpt-image-1",
|
|
225882
|
-
"openai/
|
|
225883
|
-
"
|
|
225964
|
+
"openai/gpt-image-2",
|
|
225965
|
+
"bytedance/seedream-5-pro",
|
|
225884
225966
|
"xai/grok-imagine-image",
|
|
225885
225967
|
"xai/grok-imagine-image-pro",
|
|
225886
225968
|
"zai/cogview-4"
|
|
@@ -225895,20 +225977,28 @@ function buildImageGenerationProvider() {
|
|
|
225895
225977
|
// Only openai/gpt-image-1 supports edit server-side; OpenClaw's UI picks a
|
|
225896
225978
|
// compatible model at edit time via /v1/images/image2image.
|
|
225897
225979
|
edit: { enabled: true },
|
|
225980
|
+
// Union of every size the gateway accepts across the models above,
|
|
225981
|
+
// live-probed 2026-08-23 (the gateway validates size per-model BEFORE
|
|
225982
|
+
// payment and 400s unknown ones — 1216x832 / 1792x1024 / 1024x1792 were
|
|
225983
|
+
// accepted by no model and are gone with dall-e-3). Pinned against
|
|
225984
|
+
// IMAGE_MODEL_SIZES (proxy.ts) by src/index.image-provider.test.ts.
|
|
225898
225985
|
geometry: {
|
|
225899
225986
|
sizes: [
|
|
225900
225987
|
"512x512",
|
|
225901
225988
|
"768x768",
|
|
225902
225989
|
"768x1344",
|
|
225903
225990
|
"1024x1024",
|
|
225904
|
-
"
|
|
225991
|
+
"1024x1536",
|
|
225992
|
+
"1280x720",
|
|
225905
225993
|
"1344x768",
|
|
225906
225994
|
"1440x1440",
|
|
225907
225995
|
"1536x1024",
|
|
225908
|
-
"
|
|
225909
|
-
"
|
|
225910
|
-
"
|
|
225996
|
+
"1600x2848",
|
|
225997
|
+
"1728x2304",
|
|
225998
|
+
"2048x1024",
|
|
225911
225999
|
"2048x2048",
|
|
226000
|
+
"2304x1728",
|
|
226001
|
+
"2848x1600",
|
|
225912
226002
|
"4096x4096"
|
|
225913
226003
|
]
|
|
225914
226004
|
}
|
|
@@ -226874,6 +226964,7 @@ export {
|
|
|
226874
226964
|
SpendControl,
|
|
226875
226965
|
VISIBLE_OPENCLAW_MODELS,
|
|
226876
226966
|
blockrunProvider,
|
|
226967
|
+
buildImageGenerationProvider,
|
|
226877
226968
|
buildPartnerTools,
|
|
226878
226969
|
buildProviderModels,
|
|
226879
226970
|
calculateModelCost,
|
package/docs/image-generation.md
CHANGED
|
@@ -51,16 +51,22 @@ The returned URL is a publicly hosted image, ready to use in Telegram, Discord,
|
|
|
51
51
|
|
|
52
52
|
## Models & Pricing
|
|
53
53
|
|
|
54
|
-
| Model ID
|
|
55
|
-
|
|
|
56
|
-
| `google/nano-banana`
|
|
57
|
-
| `google/nano-banana-
|
|
58
|
-
| `
|
|
59
|
-
| `openai/gpt-image-1`
|
|
60
|
-
| `
|
|
54
|
+
| Model ID | Shorthand | Price | Sizes | Provider |
|
|
55
|
+
| ---------------------------- | ------------------ | ------------------- | ---------------------------------------------------------------------------------- | --------------------- |
|
|
56
|
+
| `google/nano-banana` | `nano-banana` | $0.05/image | 1024×1024 | Google Gemini Flash |
|
|
57
|
+
| `google/nano-banana-2` | `banana-2` | $0.09/image | 1024×1024 | Google Nano Banana 2 |
|
|
58
|
+
| `google/nano-banana-pro` | `banana-pro` | $0.10–$0.15/image | 1024×1024, 2048×2048, 4096×4096 | Google Gemini Pro |
|
|
59
|
+
| `openai/gpt-image-1` | `gpt-image` | $0.02–$0.04/image | 1024×1024, 1536×1024, 1024×1536 | OpenAI GPT Image 1 |
|
|
60
|
+
| `openai/gpt-image-2` | `gpt-image-2` | $0.06–$0.12/image | 1024×1024, 1536×1024, 1024×1536 | OpenAI GPT Image 2 |
|
|
61
|
+
| `bytedance/seedream-5-pro` | `seedream` | $0.045–$0.09/image | 1024×1024, 1280×720, 2048×1024, 2048×2048, 2304×1728, 1728×2304, 2848×1600, 1600×2848 | ByteDance Seedream 5 |
|
|
62
|
+
| `xai/grok-imagine-image` | `grok-imagine` | $0.02/image | 1024×1024 | xAI Grok Imagine |
|
|
63
|
+
| `xai/grok-imagine-image-pro` | `grok-imagine-pro` | $0.07/image | 1024×1024 | xAI Grok Imagine Pro |
|
|
64
|
+
| `zai/cogview-4` | `cogview` | $0.015–$0.02/image | 512×512, 768×768, 1024×1024, 768×1344, 1344×768, 1440×1440 | Zhipu CogView-4 |
|
|
61
65
|
|
|
62
66
|
Default model: `google/nano-banana`.
|
|
63
67
|
|
|
68
|
+
> `openai/dall-e-3` was delisted upstream on 2026-05-25 and `black-forest/flux-1.1-pro` is no longer served; the legacy `dall-e-3` / `dalle` shorthands now route to `openai/gpt-image-2`. The gateway validates `size` per model **before** payment — sizes outside the lists above return an error and cost nothing. Slow models (notably `gpt-image-2`) can take longer than 30s; the proxy transparently polls the job for up to 5 minutes and still returns a single blocking response.
|
|
69
|
+
|
|
64
70
|
---
|
|
65
71
|
|
|
66
72
|
## API Reference
|
|
@@ -85,7 +91,7 @@ OpenAI-compatible endpoint. Route via ClawRouter proxy (`http://localhost:8402`)
|
|
|
85
91
|
created: number; // Unix timestamp
|
|
86
92
|
data: Array<{
|
|
87
93
|
url: string; // Publicly hosted image URL
|
|
88
|
-
revised_prompt?: string; // Model's rewritten prompt (
|
|
94
|
+
revised_prompt?: string; // Model's rewritten prompt (when the model provides one)
|
|
89
95
|
}>;
|
|
90
96
|
}
|
|
91
97
|
```
|
|
@@ -146,13 +152,13 @@ curl -X POST http://localhost:8402/v1/images/generations \
|
|
|
146
152
|
"n": 1
|
|
147
153
|
}'
|
|
148
154
|
|
|
149
|
-
#
|
|
155
|
+
# GPT Image 2 with landscape size ($0.12 — slow model, the proxy polls for you)
|
|
150
156
|
curl -X POST http://localhost:8402/v1/images/generations \
|
|
151
157
|
-H "Content-Type: application/json" \
|
|
152
158
|
-d '{
|
|
153
|
-
"model": "openai/
|
|
159
|
+
"model": "openai/gpt-image-2",
|
|
154
160
|
"prompt": "a serene Japanese garden in autumn",
|
|
155
|
-
"size": "
|
|
161
|
+
"size": "1536x1024",
|
|
156
162
|
"n": 1
|
|
157
163
|
}'
|
|
158
164
|
```
|
|
@@ -233,9 +239,9 @@ const response = await fetch(`${proxy.baseUrl}/v1/images/generations`, {
|
|
|
233
239
|
method: "POST",
|
|
234
240
|
headers: { "Content-Type": "application/json" },
|
|
235
241
|
body: JSON.stringify({
|
|
236
|
-
model: "
|
|
242
|
+
model: "bytedance/seedream-5-pro",
|
|
237
243
|
prompt: "a serene Japanese garden in autumn",
|
|
238
|
-
size: "
|
|
244
|
+
size: "2048x1024",
|
|
239
245
|
n: 1,
|
|
240
246
|
}),
|
|
241
247
|
});
|
|
@@ -335,7 +341,7 @@ When using ClawRouter with OpenClaw, generate and edit images directly from any
|
|
|
335
341
|
|
|
336
342
|
```
|
|
337
343
|
/cr-imagegen a dog dancing on the beach
|
|
338
|
-
/cr-imagegen --model
|
|
344
|
+
/cr-imagegen --model gpt-image-2 a futuristic city at sunset
|
|
339
345
|
/cr-imagegen --model banana-pro --size 2048x2048 mountain landscape
|
|
340
346
|
```
|
|
341
347
|
|
|
@@ -363,13 +369,18 @@ When using ClawRouter with OpenClaw, generate and edit images directly from any
|
|
|
363
369
|
|
|
364
370
|
### Model shorthands
|
|
365
371
|
|
|
366
|
-
| Shorthand
|
|
367
|
-
|
|
|
368
|
-
| `nano-banana`
|
|
369
|
-
| `banana-
|
|
370
|
-
| `
|
|
371
|
-
| `gpt-image`
|
|
372
|
-
| `
|
|
372
|
+
| Shorthand | Full ID |
|
|
373
|
+
| ------------------------------------ | ---------------------------- |
|
|
374
|
+
| `nano-banana`, `banana` | `google/nano-banana` |
|
|
375
|
+
| `banana-2`, `nano-banana-2` | `google/nano-banana-2` |
|
|
376
|
+
| `banana-pro`, `nano-banana-pro` | `google/nano-banana-pro` |
|
|
377
|
+
| `gpt-image`, `gpt-image-1` | `openai/gpt-image-1` |
|
|
378
|
+
| `gpt-image-2` | `openai/gpt-image-2` |
|
|
379
|
+
| `seedream` | `bytedance/seedream-5-pro` |
|
|
380
|
+
| `grok-imagine` | `xai/grok-imagine-image` |
|
|
381
|
+
| `grok-imagine-pro` | `xai/grok-imagine-image-pro` |
|
|
382
|
+
| `cogview` | `zai/cogview-4` |
|
|
383
|
+
| `dall-e-3`, `dalle3`, `dalle` (legacy) | `openai/gpt-image-2` |
|
|
373
384
|
|
|
374
385
|
---
|
|
375
386
|
|
|
@@ -377,6 +388,6 @@ When using ClawRouter with OpenClaw, generate and edit images directly from any
|
|
|
377
388
|
|
|
378
389
|
- **Local image caching** — All images (generated and edited) are cached locally at `~/.openclaw/blockrun/images/` and served via `http://localhost:8402/images/`. Both base64 data URIs and HTTP URLs from upstream are downloaded and replaced with localhost URLs.
|
|
379
390
|
- **Payment** — Each image costs the listed price in USDC, deducted from your wallet via x402. Make sure your wallet is funded before generating or editing.
|
|
380
|
-
- **
|
|
381
|
-
- **Size limits** —
|
|
391
|
+
- **Content policy** — OpenAI image models (GPT Image 1/2) apply OpenAI's content policy. Use `nano-banana` or `grok-imagine` for more flexibility with generation.
|
|
392
|
+
- **Size limits** — The gateway validates `size` per model before payment; a size outside the model's list returns an error and costs nothing. Check the table above before setting `--size`.
|
|
382
393
|
- **Image editing** — The `/v1/images/image2image` endpoint currently supports `openai/gpt-image-1` (default). The `image` and `mask` fields accept local file paths (`~/photo.png`, `/abs/path.png`), HTTP/HTTPS URLs, or base64 data URIs. ClawRouter handles file reading and URL downloading automatically. Supported formats: PNG, JPG/JPEG, WebP.
|
package/package.json
CHANGED
package/scripts/reinstall.sh
CHANGED
|
@@ -899,7 +899,7 @@ echo " /exclude add <model> → block a model from routing"
|
|
|
899
899
|
echo ""
|
|
900
900
|
echo "Image generation:"
|
|
901
901
|
echo " /imagegen <prompt> # default: nano-banana"
|
|
902
|
-
echo " /imagegen --model
|
|
902
|
+
echo " /imagegen --model gpt-image-2 <prompt> # GPT Image 2"
|
|
903
903
|
echo " /imagegen --model gpt-image <prompt> # GPT Image 1"
|
|
904
904
|
echo ""
|
|
905
905
|
echo "CLI commands:"
|
|
@@ -164,7 +164,7 @@ Realtime prices and historical OHLC across every asset class. The agent should c
|
|
|
164
164
|
|
|
165
165
|
| Tool | Purpose | Price |
|
|
166
166
|
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
|
|
167
|
-
| `blockrun_image_generation` |
|
|
167
|
+
| `blockrun_image_generation` | 9 image models — GPT Image 1/2, Nano Banana / 2 / Pro, Seedream 5 Pro, Grok Imagine / Pro, CogView-4 | $0.015–$0.15 / image |
|
|
168
168
|
| `blockrun_image_edit` | Edit / inpaint existing image (openai/gpt-image-1) | $0.02–$0.04 / image |
|
|
169
169
|
| `blockrun_video_generation` | Grok Imagine + ByteDance Seedance (1.5-pro / 2.0-fast / 2.0) at 720p with synced audio (t2v default), 5–10s, + OpenAI Sora 2 via Azure (`azure/sora-2`, 4/8/12s, t2v + i2v, rejects human faces in reference images). Seedance is token-priced upstream (~20,256 tokens/sec at the 720p+audio default — 2× the prior 480p rate); `image_url` (image-to-video) costs the same as t2v since 2026-06-01. Seedance 2.0 variants accept optional `real_face_asset_id` (`ta_…`) for BytePlus RealFace character-consistency — mutually exclusive with `image_url`. | $0.05/s (Grok); $0.10/s (Sora 2); Seedance ~$0.46–$1.49 per 5s clip |
|
|
170
170
|
|
package/skills/imagegen/SKILL.md
CHANGED
|
@@ -57,8 +57,9 @@ Display inline: ``
|
|
|
57
57
|
|
|
58
58
|
| Alias | Full ID | Price | Sizes | Best for |
|
|
59
59
|
| ------------------ | ---------------------------- | ------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
60
|
-
| `nano-banana` | `google/nano-banana` | $0.05 | 1024×1024
|
|
61
|
-
| `banana-
|
|
60
|
+
| `nano-banana` | `google/nano-banana` | $0.05 | 1024×1024 | Default — fast, cheap, good quality |
|
|
61
|
+
| `banana-2` | `google/nano-banana-2` | $0.09 | 1024×1024 | Gemini 3.1 Flash imagegen — sharper than nano-banana at 1K |
|
|
62
|
+
| `banana-pro` | `google/nano-banana-pro` | $0.10–$0.15 | 1024×1024, 2048×2048, 4096×4096 | High-res, large format |
|
|
62
63
|
| `gpt-image` | `openai/gpt-image-1` | $0.02–$0.04 | 1024×1024, 1536×1024, 1024×1536 | Budget option; supports editing |
|
|
63
64
|
| `gpt-image-2` | `openai/gpt-image-2` | $0.06–$0.12 | 1024×1024, 1536×1024, 1024×1536 | Photorealistic, reasoning-driven, text rendering (slow — proxy polls up to 5min); legacy `dalle` alias routes here |
|
|
64
65
|
| `seedream` | `bytedance/seedream-5-pro` | $0.045–$0.09 | up to 2848×1600 / 2304×1728 | Flagship quality, reference-image support |
|
|
@@ -79,10 +80,11 @@ Display inline: ``
|
|
|
79
80
|
|
|
80
81
|
**Choosing a size:**
|
|
81
82
|
|
|
82
|
-
- Default: `1024x1024`
|
|
83
|
-
- Portrait: `
|
|
84
|
-
- Landscape: `1536x1024` (gpt-image / gpt-image-2) or `
|
|
85
|
-
- High-res: `2048x2048`
|
|
83
|
+
- Default: `1024x1024` (the only size every model accepts)
|
|
84
|
+
- Portrait: `1024x1536` (gpt-image / gpt-image-2) or `1728x2304` (seedream)
|
|
85
|
+
- Landscape: `1536x1024` (gpt-image / gpt-image-2), `1344x768` (cogview), or `2048x1024` / `1280x720` (seedream)
|
|
86
|
+
- High-res: `2048x2048` / `4096x4096` with `banana-pro`; `2848x1600` with `seedream`
|
|
87
|
+
- The gateway validates size per model BEFORE payment and rejects unknown ones — do not invent sizes outside each model's list above
|
|
86
88
|
|
|
87
89
|
---
|
|
88
90
|
|
|
@@ -123,7 +125,7 @@ Response is identical to generation:
|
|
|
123
125
|
→ POST to `/v1/images/generations`, model `nano-banana`, prompt as given.
|
|
124
126
|
|
|
125
127
|
**User:** Generate a high-res portrait of a samurai
|
|
126
|
-
→ POST to `/v1/images/generations`, model `
|
|
128
|
+
→ POST to `/v1/images/generations`, model `seedream`, size `1728x2304`.
|
|
127
129
|
|
|
128
130
|
**User:** Edit this photo to add a sunset background: https://example.com/portrait.jpg
|
|
129
131
|
→ POST to `/v1/images/image2image`, model `gpt-image`, image = the URL, prompt = "add a warm sunset background".
|