@blockrun/clawrouter 0.12.228 → 0.12.230
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 +49 -48
- package/dist/cli.js +106 -14
- package/dist/index.js +106 -14
- package/package.json +1 -1
- package/scripts/update.sh +122 -30
- package/skills/clawrouter/SKILL.md +2 -2
- package/skills/imagegen/SKILL.md +9 -9
- package/src/top-models.json +1 -1
package/README.md
CHANGED
|
@@ -207,12 +207,12 @@ Choose your routing strategy with `/model <profile>`:
|
|
|
207
207
|
Request → Weighted Scorer (15 dimensions) → Tier → Best Model → Response
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
-
| Tier | ECO Model
|
|
211
|
-
| --------- |
|
|
212
|
-
| SIMPLE | free/mistral-large-3-675b (**FREE**)
|
|
213
|
-
| MEDIUM | gemini-3.1-flash-lite ($0.25/$1.50)
|
|
214
|
-
| COMPLEX | gemini-3.1-flash-lite ($0.25/$1.50)
|
|
215
|
-
| REASONING | deepseek-reasoner ($0.20/$0.40)
|
|
210
|
+
| Tier | ECO Model | AUTO Model | PREMIUM Model |
|
|
211
|
+
| --------- | ------------------------------------ | ------------------------------- | ---------------------------- |
|
|
212
|
+
| SIMPLE | free/mistral-large-3-675b (**FREE**) | gemini-2.5-flash ($0.30/$2.50) | kimi-k2.7 ($0.95/$4.00) |
|
|
213
|
+
| MEDIUM | gemini-3.1-flash-lite ($0.25/$1.50) | kimi-k2.7 ($0.95/$4.00) | gpt-5.3-codex ($1.75/$14.00) |
|
|
214
|
+
| COMPLEX | gemini-3.1-flash-lite ($0.25/$1.50) | gemini-3.1-pro ($2/$12) | claude-opus-4.8 ($5/$25) |
|
|
215
|
+
| REASONING | deepseek-reasoner ($0.20/$0.40) | deepseek-reasoner ($0.20/$0.40) | claude-sonnet-4.6 ($3/$15) |
|
|
216
216
|
|
|
217
217
|
**Blended average: $2.05/M** vs $25/M for Claude Opus = **92% savings**
|
|
218
218
|
|
|
@@ -230,16 +230,16 @@ Generate images directly from chat with `/cr-imagegen`:
|
|
|
230
230
|
|
|
231
231
|
> The slash command is `/cr-imagegen` to avoid colliding with Telegram channel commands. Typing `/imagegen` in chat still works for backward compatibility.
|
|
232
232
|
|
|
233
|
-
| Model | Provider
|
|
234
|
-
| ---------------------------- |
|
|
235
|
-
| `nano-banana` | Google Gemini Flash
|
|
236
|
-
| `banana-pro` | Google Gemini Pro
|
|
237
|
-
| `gpt-image` | OpenAI GPT Image 1
|
|
238
|
-
| `gpt-image-2` | OpenAI GPT Image 2
|
|
239
|
-
| `seedream` | ByteDance Seedream 5
|
|
240
|
-
| `xai/grok-imagine-image` | xAI Grok Imagine
|
|
241
|
-
| `xai/grok-imagine-image-pro` | xAI Grok Imagine Pro
|
|
242
|
-
| `zai/cogview-4` | Zhipu CogView-4
|
|
233
|
+
| Model | Provider | Price | Max Size |
|
|
234
|
+
| ---------------------------- | -------------------- | ------------ | --------- |
|
|
235
|
+
| `nano-banana` | Google Gemini Flash | $0.05/image | 1024x1024 |
|
|
236
|
+
| `banana-pro` | Google Gemini Pro | $0.10/image | 4096x4096 |
|
|
237
|
+
| `gpt-image` | OpenAI GPT Image 1 | $0.02/image | 1536x1024 |
|
|
238
|
+
| `gpt-image-2` | OpenAI GPT Image 2 | $0.06/image | 1536x1024 |
|
|
239
|
+
| `seedream` | ByteDance Seedream 5 | $0.045/image | 2848x1600 |
|
|
240
|
+
| `xai/grok-imagine-image` | xAI Grok Imagine | $0.02/image | 1024x1024 |
|
|
241
|
+
| `xai/grok-imagine-image-pro` | xAI Grok Imagine Pro | $0.07/image | 1024x1024 |
|
|
242
|
+
| `zai/cogview-4` | Zhipu CogView-4 | $0.015/image | 1440x1440 |
|
|
243
243
|
|
|
244
244
|
## Video Generation
|
|
245
245
|
|
|
@@ -388,38 +388,39 @@ No Surf account, no API key — settles directly to Surf's Base treasury in USDC
|
|
|
388
388
|
|
|
389
389
|
### Budget Models (under $0.001/request)
|
|
390
390
|
|
|
391
|
-
| Model
|
|
392
|
-
|
|
|
393
|
-
| free/mistral-large-3-675b
|
|
394
|
-
| free/deepseek-v4-flash
|
|
395
|
-
| free/seed-oss-36b
|
|
396
|
-
| free/nemotron-3-nano-omni-30b-a3b-reasoning
|
|
397
|
-
| free/mistral-nemotron
|
|
398
|
-
| free/step-3.7-flash
|
|
399
|
-
| free/nemotron-nano-9b-v2
|
|
400
|
-
| free/nemotron-nano-12b-v2-vl
|
|
401
|
-
| openai/gpt-5-nano
|
|
402
|
-
| openai/gpt-4.1-nano
|
|
403
|
-
| google/gemini-2.5-flash-lite
|
|
404
|
-
| openai/gpt-4o-mini
|
|
405
|
-
| xai/grok-4-fast
|
|
406
|
-
| xai/grok-4-fast-reasoning
|
|
407
|
-
| xai/grok-4-1-fast
|
|
408
|
-
| openai/gpt-5-mini
|
|
409
|
-
| deepseek/deepseek-chat
|
|
410
|
-
| deepseek/deepseek-reasoner
|
|
411
|
-
| deepseek/deepseek-v4-pro
|
|
412
|
-
| zai/glm-5
|
|
413
|
-
| zai/glm-5-turbo
|
|
414
|
-
| minimax/minimax-m3
|
|
415
|
-
| minimax/minimax-m2.7
|
|
416
|
-
| minimax/minimax-m2.5
|
|
417
|
-
| google/gemini-2.5-flash
|
|
418
|
-
| openai/gpt-4.1-mini
|
|
419
|
-
| google/gemini-3.5-flash
|
|
420
|
-
| google/gemini-3-flash-preview
|
|
421
|
-
| moonshot/kimi-k2.5
|
|
422
|
-
| moonshot/kimi-k2.7
|
|
391
|
+
| Model | Input $/M | Output $/M | ~$/request | Context | Features |
|
|
392
|
+
| ------------------------------------------- | --------: | ---------: | ---------: | ------- | -------------------------------------------- |
|
|
393
|
+
| free/mistral-large-3-675b | **FREE** | **FREE** | **$0** | 131K | 675B general flagship, default free model |
|
|
394
|
+
| free/deepseek-v4-flash | **FREE** | **FREE** | **$0** | 1M | reasoning + coding, huge context |
|
|
395
|
+
| free/seed-oss-36b | **FREE** | **FREE** | **$0** | 131K | coding |
|
|
396
|
+
| free/nemotron-3-nano-omni-30b-a3b-reasoning | **FREE** | **FREE** | **$0** | 256K | reasoning, **vision** (text+img+video+audio) |
|
|
397
|
+
| free/mistral-nemotron | **FREE** | **FREE** | **$0** | 131K | instruction following |
|
|
398
|
+
| free/step-3.7-flash | **FREE** | **FREE** | **$0** | 131K | reasoning |
|
|
399
|
+
| free/nemotron-nano-9b-v2 | **FREE** | **FREE** | **$0** | 131K | fast lightweight generalist |
|
|
400
|
+
| free/nemotron-nano-12b-v2-vl | **FREE** | **FREE** | **$0** | 131K | vision (text + image) |
|
|
401
|
+
| openai/gpt-5-nano | $0.05 | $0.40 | $0.0002 | 128K | tools |
|
|
402
|
+
| openai/gpt-4.1-nano | $0.10 | $0.40 | $0.0003 | 128K | tools |
|
|
403
|
+
| google/gemini-2.5-flash-lite | $0.10 | $0.40 | $0.0003 | 1M | tools |
|
|
404
|
+
| openai/gpt-4o-mini | $0.15 | $0.60 | $0.0004 | 128K | tools |
|
|
405
|
+
| xai/grok-4-fast | $0.20 | $0.50 | $0.0004 | 131K | tools |
|
|
406
|
+
| xai/grok-4-fast-reasoning | $0.20 | $0.50 | $0.0004 | 131K | reasoning, tools |
|
|
407
|
+
| xai/grok-4-1-fast | $0.20 | $0.50 | $0.0004 | 131K | tools |
|
|
408
|
+
| openai/gpt-5-mini | $0.25 | $2.00 | $0.0011 | 200K | tools |
|
|
409
|
+
| deepseek/deepseek-chat | $0.20 | $0.40 | $0.0003 | 1M | tools (V4 Flash chat) |
|
|
410
|
+
| deepseek/deepseek-reasoner | $0.20 | $0.40 | $0.0003 | 1M | reasoning, tools (V4 Flash thinking) |
|
|
411
|
+
| deepseek/deepseek-v4-pro | $0.435 | $0.87 | $0.0007 | 1M | reasoning, agentic, tools (V4 flagship) |
|
|
412
|
+
| zai/glm-5 | $0.60 | $1.92 | $0.0013 | 200K | tools |
|
|
413
|
+
| zai/glm-5-turbo | $1.20 | $4.00 | $0.0026 | 200K | tools |
|
|
414
|
+
| minimax/minimax-m3 | $0.30 | $1.20 | $0.0008 | 1M | reasoning, agentic, tools |
|
|
415
|
+
| minimax/minimax-m2.7 | $0.30 | $1.20 | $0.0008 | 205K | reasoning, agentic, tools |
|
|
416
|
+
| minimax/minimax-m2.5 | $0.30 | $1.20 | $0.0008 | 205K | reasoning, agentic, tools |
|
|
417
|
+
| google/gemini-2.5-flash | $0.30 | $2.50 | $0.0014 | 1M | vision, tools |
|
|
418
|
+
| openai/gpt-4.1-mini | $0.40 | $1.60 | $0.0010 | 128K | tools |
|
|
419
|
+
| google/gemini-3.5-flash | $0.50 | $3.00 | $0.0018 | 1M | reasoning, vision, tools (thinking built-in) |
|
|
420
|
+
| google/gemini-3-flash-preview | $0.50 | $3.00 | $0.0018 | 1M | vision |
|
|
421
|
+
| moonshot/kimi-k2.5 | $0.60 | $3.00 | $0.0018 | 262K | reasoning, vision, agentic, tools |
|
|
422
|
+
| moonshot/kimi-k2.7 | $0.95 | $4.00 | $0.0025 | 262K | reasoning, vision, agentic, tools |
|
|
423
|
+
| moonshot/kimi-k3 | $3.00 | $15.00 | $0.0110 | 1M | reasoning, vision, agentic, tools |
|
|
423
424
|
|
|
424
425
|
### Mid-Range Models ($0.001–$0.01/request)
|
|
425
426
|
|
package/dist/cli.js
CHANGED
|
@@ -34295,7 +34295,7 @@ var init_top_models = __esm({
|
|
|
34295
34295
|
"zai/glm-5",
|
|
34296
34296
|
"minimax/minimax-m3",
|
|
34297
34297
|
"minimax/minimax-m2.7",
|
|
34298
|
-
"moonshot/kimi-
|
|
34298
|
+
"moonshot/kimi-k3",
|
|
34299
34299
|
"deepseek/deepseek-v4-pro",
|
|
34300
34300
|
"deepseek/deepseek-chat",
|
|
34301
34301
|
"deepseek/deepseek-reasoner",
|
|
@@ -34507,13 +34507,16 @@ var init_models = __esm({
|
|
|
34507
34507
|
deepseek: "deepseek/deepseek-chat",
|
|
34508
34508
|
"deepseek-chat": "deepseek/deepseek-chat",
|
|
34509
34509
|
reasoner: "deepseek/deepseek-reasoner",
|
|
34510
|
-
// Kimi / Moonshot —
|
|
34511
|
-
//
|
|
34512
|
-
//
|
|
34510
|
+
// Kimi / Moonshot — K3 is the featured flagship on BlockRun (added 2026-07-17; K2.7
|
|
34511
|
+
// hidden/superseded, K2.6 hidden, K2.5 hidden). K3 is ~5x K2.7's price ($3/$15 vs
|
|
34512
|
+
// $0.95/$4.00), so the BARE aliases deliberately STAY on K2.7 — repointing them to K3
|
|
34513
|
+
// would silently ~5x every generic-`kimi` quote and break per-call-cap wallets (mirrors
|
|
34514
|
+
// blockrun's own alias decision). Address the flagship explicitly via "kimi-k3". Explicit
|
|
34513
34515
|
// pins for "kimi-k2.6" / "kimi-k2.5" still resolve to those exact models (K2.5 is a
|
|
34514
34516
|
// cost-stability opt-in at $0.60/$3.00). NVIDIA-hosted K2.5 was retired 2026-04-21.
|
|
34515
34517
|
kimi: "moonshot/kimi-k2.7",
|
|
34516
34518
|
moonshot: "moonshot/kimi-k2.7",
|
|
34519
|
+
"kimi-k3": "moonshot/kimi-k3",
|
|
34517
34520
|
"kimi-k2": "moonshot/kimi-k2.7",
|
|
34518
34521
|
"kimi-k2.7": "moonshot/kimi-k2.7",
|
|
34519
34522
|
"kimi-k2.6": "moonshot/kimi-k2.6",
|
|
@@ -35292,10 +35295,29 @@ var init_models = __esm({
|
|
|
35292
35295
|
agentic: true,
|
|
35293
35296
|
toolCalling: true
|
|
35294
35297
|
},
|
|
35295
|
-
// Kimi
|
|
35296
|
-
//
|
|
35297
|
-
//
|
|
35298
|
-
//
|
|
35298
|
+
// Kimi K3 — Moonshot's flagship (blockrun added 2026-07-17, live-probed same day).
|
|
35299
|
+
// 2.8T-param open MoE, 1M context, image + text input, returns reasoning_content.
|
|
35300
|
+
// Priced at COGS + BlockRun's 5% margin: users pay ~$3.15/$15.75 per 1M; the fields
|
|
35301
|
+
// here store the raw $3.00/$15.00 COST (server applies margin at billing). ~5x K2.7,
|
|
35302
|
+
// so the generic `kimi` alias deliberately stays on K2.7 — address k3 explicitly.
|
|
35303
|
+
{
|
|
35304
|
+
id: "moonshot/kimi-k3",
|
|
35305
|
+
name: "Kimi K3",
|
|
35306
|
+
version: "k3",
|
|
35307
|
+
inputPrice: 3,
|
|
35308
|
+
outputPrice: 15,
|
|
35309
|
+
contextWindow: 1048576,
|
|
35310
|
+
maxOutput: 65536,
|
|
35311
|
+
reasoning: true,
|
|
35312
|
+
vision: true,
|
|
35313
|
+
agentic: true,
|
|
35314
|
+
toolCalling: true
|
|
35315
|
+
},
|
|
35316
|
+
// Kimi K2.7 — previous-gen flagship (added 2026-06-13); superseded by K3 + hidden on
|
|
35317
|
+
// BlockRun 2026-07-17 but kept routable. 256K context, multi-modal (image + VIDEO
|
|
35318
|
+
// input), returns reasoning_content. Served via BlockRun's OpenRouter credit pool
|
|
35319
|
+
// (slug moonshotai/kimi-k2.7-code) failing over to direct Moonshot. AT-COST pricing
|
|
35320
|
+
// ($0.95/$4.00 = OpenRouter COGS, zero margin) — same as K2.6.
|
|
35299
35321
|
{
|
|
35300
35322
|
id: "moonshot/kimi-k2.7",
|
|
35301
35323
|
name: "Kimi K2.7",
|
|
@@ -82159,6 +82181,65 @@ function extractGptCalls(content) {
|
|
|
82159
82181
|
}
|
|
82160
82182
|
return { calls: [], matches: [] };
|
|
82161
82183
|
}
|
|
82184
|
+
function deriveRequestTools(tools) {
|
|
82185
|
+
if (!Array.isArray(tools)) return [];
|
|
82186
|
+
const derived = [];
|
|
82187
|
+
for (const raw of tools) {
|
|
82188
|
+
const fn = raw?.function;
|
|
82189
|
+
const name = fn?.name;
|
|
82190
|
+
if (typeof name !== "string" || name.trim() === "") continue;
|
|
82191
|
+
const params = fn?.parameters;
|
|
82192
|
+
const props = isPlainObject(params?.properties) ? Object.keys(params.properties) : [];
|
|
82193
|
+
const required = Array.isArray(params?.required) ? params.required.filter((r2) => typeof r2 === "string") : [];
|
|
82194
|
+
derived.push({ name: name.trim(), propKeys: new Set(props), required });
|
|
82195
|
+
}
|
|
82196
|
+
return derived;
|
|
82197
|
+
}
|
|
82198
|
+
function keyMatchesParam(key2, propKeys) {
|
|
82199
|
+
if (propKeys.has(key2)) return true;
|
|
82200
|
+
if (key2 === "cmd" && propKeys.has("command")) return true;
|
|
82201
|
+
if (key2 === "command" && propKeys.has("cmd")) return true;
|
|
82202
|
+
return false;
|
|
82203
|
+
}
|
|
82204
|
+
function requiredSatisfied(tool, blobKeys) {
|
|
82205
|
+
return tool.required.every(
|
|
82206
|
+
(r2) => blobKeys.has(r2) || r2 === "command" && blobKeys.has("cmd") || r2 === "cmd" && blobKeys.has("command")
|
|
82207
|
+
);
|
|
82208
|
+
}
|
|
82209
|
+
function resolveKimiTool(prose, blob, tools) {
|
|
82210
|
+
const blobKeys = Object.keys(blob);
|
|
82211
|
+
if (prose) {
|
|
82212
|
+
const named = tools.filter(
|
|
82213
|
+
(t) => new RegExp(`(?:^|[^A-Za-z0-9_])${escapeRegExp2(t.name)}(?:[^A-Za-z0-9_]|$)`).test(prose)
|
|
82214
|
+
);
|
|
82215
|
+
if (named.length === 1) return named[0].name;
|
|
82216
|
+
}
|
|
82217
|
+
if (blobKeys.length === 0) return null;
|
|
82218
|
+
const keySet = new Set(blobKeys);
|
|
82219
|
+
const sigMatches = tools.filter(
|
|
82220
|
+
(t) => blobKeys.every((k) => keyMatchesParam(k, t.propKeys)) && requiredSatisfied(t, keySet)
|
|
82221
|
+
);
|
|
82222
|
+
return sigMatches.length === 1 ? sigMatches[0].name : null;
|
|
82223
|
+
}
|
|
82224
|
+
function escapeRegExp2(s3) {
|
|
82225
|
+
return s3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
82226
|
+
}
|
|
82227
|
+
function extractKimiCalls(content, tools) {
|
|
82228
|
+
if (tools.length === 0) return { calls: [], matches: [] };
|
|
82229
|
+
const trailing = findTrailingJsonObject(content);
|
|
82230
|
+
if (!trailing || !isPlainObject(trailing.parsed)) return { calls: [], matches: [] };
|
|
82231
|
+
if (typeof trailing.parsed.name === "string" && trailing.parsed.name.trim() !== "") {
|
|
82232
|
+
return { calls: [], matches: [] };
|
|
82233
|
+
}
|
|
82234
|
+
const prose = content.slice(0, trailing.start).trim();
|
|
82235
|
+
const name = resolveKimiTool(prose, trailing.parsed, tools);
|
|
82236
|
+
if (!name) return { calls: [], matches: [] };
|
|
82237
|
+
const start = prose === "" ? 0 : trailing.start;
|
|
82238
|
+
return {
|
|
82239
|
+
calls: [makeCall(name, normalizeGptArgs(trailing.parsed))],
|
|
82240
|
+
matches: [{ start, end: content.length }]
|
|
82241
|
+
};
|
|
82242
|
+
}
|
|
82162
82243
|
function stripRanges(content, ranges) {
|
|
82163
82244
|
if (ranges.length === 0) return content;
|
|
82164
82245
|
const sorted = [...ranges].sort((a, b) => a.start - b.start);
|
|
@@ -82173,15 +82254,23 @@ function stripRanges(content, ranges) {
|
|
|
82173
82254
|
cleaned += content.slice(cursor);
|
|
82174
82255
|
return cleaned;
|
|
82175
82256
|
}
|
|
82176
|
-
function extractTextualToolCalls(content) {
|
|
82257
|
+
function extractTextualToolCalls(content, options) {
|
|
82177
82258
|
if (!content) {
|
|
82178
82259
|
return { toolCalls: [], cleanedContent: "" };
|
|
82179
82260
|
}
|
|
82180
82261
|
const openClaw = extractOpenClawCalls(content);
|
|
82181
82262
|
const anthropic = extractAnthropicCalls(content);
|
|
82182
82263
|
const gemini = extractGeminiCalls(content);
|
|
82183
|
-
const
|
|
82184
|
-
const
|
|
82264
|
+
const tagBasedCount = openClaw.calls.length + anthropic.calls.length + gemini.calls.length;
|
|
82265
|
+
const gpt = tagBasedCount === 0 ? extractGptCalls(content) : { calls: [], matches: [] };
|
|
82266
|
+
const kimi = tagBasedCount + gpt.calls.length === 0 ? extractKimiCalls(content, deriveRequestTools(options?.tools)) : { calls: [], matches: [] };
|
|
82267
|
+
const toolCalls = [
|
|
82268
|
+
...openClaw.calls,
|
|
82269
|
+
...anthropic.calls,
|
|
82270
|
+
...gemini.calls,
|
|
82271
|
+
...gpt.calls,
|
|
82272
|
+
...kimi.calls
|
|
82273
|
+
];
|
|
82185
82274
|
if (toolCalls.length === 0) {
|
|
82186
82275
|
return { toolCalls: [], cleanedContent: content };
|
|
82187
82276
|
}
|
|
@@ -82189,7 +82278,8 @@ function extractTextualToolCalls(content) {
|
|
|
82189
82278
|
...openClaw.matches,
|
|
82190
82279
|
...anthropic.matches,
|
|
82191
82280
|
...gemini.matches,
|
|
82192
|
-
...gpt.matches
|
|
82281
|
+
...gpt.matches,
|
|
82282
|
+
...kimi.matches
|
|
82193
82283
|
]);
|
|
82194
82284
|
return { toolCalls, cleanedContent };
|
|
82195
82285
|
}
|
|
@@ -85964,6 +86054,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
85964
86054
|
const debugMode = debugHeadersEnabledFromEnv() && req.headers["x-clawrouter-debug"] !== "false";
|
|
85965
86055
|
let routingDecision;
|
|
85966
86056
|
let hasTools = false;
|
|
86057
|
+
let requestTools;
|
|
85967
86058
|
let hasVision = false;
|
|
85968
86059
|
let isStreaming = false;
|
|
85969
86060
|
let modelId = "";
|
|
@@ -86001,6 +86092,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
86001
86092
|
requestSummaryForStore = summarizeRequest(promptText);
|
|
86002
86093
|
}
|
|
86003
86094
|
hasTools = Array.isArray(parsed.tools) && parsed.tools.length > 0;
|
|
86095
|
+
requestTools = parsed.tools;
|
|
86004
86096
|
const rawLastContent = lastUserMsg?.content;
|
|
86005
86097
|
const lastContent = typeof rawLastContent === "string" ? rawLastContent : Array.isArray(rawLastContent) ? rawLastContent.filter((b) => b.type === "text").map((b) => b.text ?? "").join(" ") : "";
|
|
86006
86098
|
if (sessionId && parsedMessages.length > 0) {
|
|
@@ -87544,7 +87636,7 @@ data: [DONE]
|
|
|
87544
87636
|
let toolCalls = choice.message?.tool_calls ?? choice.delta?.tool_calls;
|
|
87545
87637
|
const rawContent = choice.message?.content ?? choice.delta?.content ?? "";
|
|
87546
87638
|
if (!endsWithToolCalls && (!toolCalls || toolCalls.length === 0) && rawContent) {
|
|
87547
|
-
const extracted = extractTextualToolCalls(rawContent);
|
|
87639
|
+
const extracted = extractTextualToolCalls(rawContent, { tools: requestTools });
|
|
87548
87640
|
if (extracted.toolCalls.length > 0) {
|
|
87549
87641
|
toolCalls = extracted.toolCalls;
|
|
87550
87642
|
}
|
|
@@ -87757,7 +87849,7 @@ data: [DONE]
|
|
|
87757
87849
|
}
|
|
87758
87850
|
continue;
|
|
87759
87851
|
}
|
|
87760
|
-
const extracted = extractTextualToolCalls(message.content);
|
|
87852
|
+
const extracted = extractTextualToolCalls(message.content, { tools: requestTools });
|
|
87761
87853
|
if (extracted.toolCalls.length > 0) {
|
|
87762
87854
|
message.tool_calls = extracted.toolCalls;
|
|
87763
87855
|
message.content = "";
|
package/dist/index.js
CHANGED
|
@@ -85,7 +85,7 @@ var init_top_models = __esm({
|
|
|
85
85
|
"zai/glm-5",
|
|
86
86
|
"minimax/minimax-m3",
|
|
87
87
|
"minimax/minimax-m2.7",
|
|
88
|
-
"moonshot/kimi-
|
|
88
|
+
"moonshot/kimi-k3",
|
|
89
89
|
"deepseek/deepseek-v4-pro",
|
|
90
90
|
"deepseek/deepseek-chat",
|
|
91
91
|
"deepseek/deepseek-reasoner",
|
|
@@ -297,13 +297,16 @@ var init_models = __esm({
|
|
|
297
297
|
deepseek: "deepseek/deepseek-chat",
|
|
298
298
|
"deepseek-chat": "deepseek/deepseek-chat",
|
|
299
299
|
reasoner: "deepseek/deepseek-reasoner",
|
|
300
|
-
// Kimi / Moonshot —
|
|
301
|
-
//
|
|
302
|
-
//
|
|
300
|
+
// Kimi / Moonshot — K3 is the featured flagship on BlockRun (added 2026-07-17; K2.7
|
|
301
|
+
// hidden/superseded, K2.6 hidden, K2.5 hidden). K3 is ~5x K2.7's price ($3/$15 vs
|
|
302
|
+
// $0.95/$4.00), so the BARE aliases deliberately STAY on K2.7 — repointing them to K3
|
|
303
|
+
// would silently ~5x every generic-`kimi` quote and break per-call-cap wallets (mirrors
|
|
304
|
+
// blockrun's own alias decision). Address the flagship explicitly via "kimi-k3". Explicit
|
|
303
305
|
// pins for "kimi-k2.6" / "kimi-k2.5" still resolve to those exact models (K2.5 is a
|
|
304
306
|
// cost-stability opt-in at $0.60/$3.00). NVIDIA-hosted K2.5 was retired 2026-04-21.
|
|
305
307
|
kimi: "moonshot/kimi-k2.7",
|
|
306
308
|
moonshot: "moonshot/kimi-k2.7",
|
|
309
|
+
"kimi-k3": "moonshot/kimi-k3",
|
|
307
310
|
"kimi-k2": "moonshot/kimi-k2.7",
|
|
308
311
|
"kimi-k2.7": "moonshot/kimi-k2.7",
|
|
309
312
|
"kimi-k2.6": "moonshot/kimi-k2.6",
|
|
@@ -1082,10 +1085,29 @@ var init_models = __esm({
|
|
|
1082
1085
|
agentic: true,
|
|
1083
1086
|
toolCalling: true
|
|
1084
1087
|
},
|
|
1085
|
-
// Kimi
|
|
1086
|
-
//
|
|
1087
|
-
//
|
|
1088
|
-
//
|
|
1088
|
+
// Kimi K3 — Moonshot's flagship (blockrun added 2026-07-17, live-probed same day).
|
|
1089
|
+
// 2.8T-param open MoE, 1M context, image + text input, returns reasoning_content.
|
|
1090
|
+
// Priced at COGS + BlockRun's 5% margin: users pay ~$3.15/$15.75 per 1M; the fields
|
|
1091
|
+
// here store the raw $3.00/$15.00 COST (server applies margin at billing). ~5x K2.7,
|
|
1092
|
+
// so the generic `kimi` alias deliberately stays on K2.7 — address k3 explicitly.
|
|
1093
|
+
{
|
|
1094
|
+
id: "moonshot/kimi-k3",
|
|
1095
|
+
name: "Kimi K3",
|
|
1096
|
+
version: "k3",
|
|
1097
|
+
inputPrice: 3,
|
|
1098
|
+
outputPrice: 15,
|
|
1099
|
+
contextWindow: 1048576,
|
|
1100
|
+
maxOutput: 65536,
|
|
1101
|
+
reasoning: true,
|
|
1102
|
+
vision: true,
|
|
1103
|
+
agentic: true,
|
|
1104
|
+
toolCalling: true
|
|
1105
|
+
},
|
|
1106
|
+
// Kimi K2.7 — previous-gen flagship (added 2026-06-13); superseded by K3 + hidden on
|
|
1107
|
+
// BlockRun 2026-07-17 but kept routable. 256K context, multi-modal (image + VIDEO
|
|
1108
|
+
// input), returns reasoning_content. Served via BlockRun's OpenRouter credit pool
|
|
1109
|
+
// (slug moonshotai/kimi-k2.7-code) failing over to direct Moonshot. AT-COST pricing
|
|
1110
|
+
// ($0.95/$4.00 = OpenRouter COGS, zero margin) — same as K2.6.
|
|
1089
1111
|
{
|
|
1090
1112
|
id: "moonshot/kimi-k2.7",
|
|
1091
1113
|
name: "Kimi K2.7",
|
|
@@ -81979,6 +82001,65 @@ function extractGptCalls(content) {
|
|
|
81979
82001
|
}
|
|
81980
82002
|
return { calls: [], matches: [] };
|
|
81981
82003
|
}
|
|
82004
|
+
function deriveRequestTools(tools) {
|
|
82005
|
+
if (!Array.isArray(tools)) return [];
|
|
82006
|
+
const derived = [];
|
|
82007
|
+
for (const raw of tools) {
|
|
82008
|
+
const fn = raw?.function;
|
|
82009
|
+
const name = fn?.name;
|
|
82010
|
+
if (typeof name !== "string" || name.trim() === "") continue;
|
|
82011
|
+
const params = fn?.parameters;
|
|
82012
|
+
const props = isPlainObject(params?.properties) ? Object.keys(params.properties) : [];
|
|
82013
|
+
const required = Array.isArray(params?.required) ? params.required.filter((r2) => typeof r2 === "string") : [];
|
|
82014
|
+
derived.push({ name: name.trim(), propKeys: new Set(props), required });
|
|
82015
|
+
}
|
|
82016
|
+
return derived;
|
|
82017
|
+
}
|
|
82018
|
+
function keyMatchesParam(key2, propKeys) {
|
|
82019
|
+
if (propKeys.has(key2)) return true;
|
|
82020
|
+
if (key2 === "cmd" && propKeys.has("command")) return true;
|
|
82021
|
+
if (key2 === "command" && propKeys.has("cmd")) return true;
|
|
82022
|
+
return false;
|
|
82023
|
+
}
|
|
82024
|
+
function requiredSatisfied(tool, blobKeys) {
|
|
82025
|
+
return tool.required.every(
|
|
82026
|
+
(r2) => blobKeys.has(r2) || r2 === "command" && blobKeys.has("cmd") || r2 === "cmd" && blobKeys.has("command")
|
|
82027
|
+
);
|
|
82028
|
+
}
|
|
82029
|
+
function resolveKimiTool(prose, blob, tools) {
|
|
82030
|
+
const blobKeys = Object.keys(blob);
|
|
82031
|
+
if (prose) {
|
|
82032
|
+
const named = tools.filter(
|
|
82033
|
+
(t) => new RegExp(`(?:^|[^A-Za-z0-9_])${escapeRegExp2(t.name)}(?:[^A-Za-z0-9_]|$)`).test(prose)
|
|
82034
|
+
);
|
|
82035
|
+
if (named.length === 1) return named[0].name;
|
|
82036
|
+
}
|
|
82037
|
+
if (blobKeys.length === 0) return null;
|
|
82038
|
+
const keySet = new Set(blobKeys);
|
|
82039
|
+
const sigMatches = tools.filter(
|
|
82040
|
+
(t) => blobKeys.every((k) => keyMatchesParam(k, t.propKeys)) && requiredSatisfied(t, keySet)
|
|
82041
|
+
);
|
|
82042
|
+
return sigMatches.length === 1 ? sigMatches[0].name : null;
|
|
82043
|
+
}
|
|
82044
|
+
function escapeRegExp2(s3) {
|
|
82045
|
+
return s3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
82046
|
+
}
|
|
82047
|
+
function extractKimiCalls(content, tools) {
|
|
82048
|
+
if (tools.length === 0) return { calls: [], matches: [] };
|
|
82049
|
+
const trailing = findTrailingJsonObject(content);
|
|
82050
|
+
if (!trailing || !isPlainObject(trailing.parsed)) return { calls: [], matches: [] };
|
|
82051
|
+
if (typeof trailing.parsed.name === "string" && trailing.parsed.name.trim() !== "") {
|
|
82052
|
+
return { calls: [], matches: [] };
|
|
82053
|
+
}
|
|
82054
|
+
const prose = content.slice(0, trailing.start).trim();
|
|
82055
|
+
const name = resolveKimiTool(prose, trailing.parsed, tools);
|
|
82056
|
+
if (!name) return { calls: [], matches: [] };
|
|
82057
|
+
const start = prose === "" ? 0 : trailing.start;
|
|
82058
|
+
return {
|
|
82059
|
+
calls: [makeCall(name, normalizeGptArgs(trailing.parsed))],
|
|
82060
|
+
matches: [{ start, end: content.length }]
|
|
82061
|
+
};
|
|
82062
|
+
}
|
|
81982
82063
|
function stripRanges(content, ranges) {
|
|
81983
82064
|
if (ranges.length === 0) return content;
|
|
81984
82065
|
const sorted = [...ranges].sort((a, b) => a.start - b.start);
|
|
@@ -81993,15 +82074,23 @@ function stripRanges(content, ranges) {
|
|
|
81993
82074
|
cleaned += content.slice(cursor);
|
|
81994
82075
|
return cleaned;
|
|
81995
82076
|
}
|
|
81996
|
-
function extractTextualToolCalls(content) {
|
|
82077
|
+
function extractTextualToolCalls(content, options) {
|
|
81997
82078
|
if (!content) {
|
|
81998
82079
|
return { toolCalls: [], cleanedContent: "" };
|
|
81999
82080
|
}
|
|
82000
82081
|
const openClaw = extractOpenClawCalls(content);
|
|
82001
82082
|
const anthropic = extractAnthropicCalls(content);
|
|
82002
82083
|
const gemini = extractGeminiCalls(content);
|
|
82003
|
-
const
|
|
82004
|
-
const
|
|
82084
|
+
const tagBasedCount = openClaw.calls.length + anthropic.calls.length + gemini.calls.length;
|
|
82085
|
+
const gpt = tagBasedCount === 0 ? extractGptCalls(content) : { calls: [], matches: [] };
|
|
82086
|
+
const kimi = tagBasedCount + gpt.calls.length === 0 ? extractKimiCalls(content, deriveRequestTools(options?.tools)) : { calls: [], matches: [] };
|
|
82087
|
+
const toolCalls = [
|
|
82088
|
+
...openClaw.calls,
|
|
82089
|
+
...anthropic.calls,
|
|
82090
|
+
...gemini.calls,
|
|
82091
|
+
...gpt.calls,
|
|
82092
|
+
...kimi.calls
|
|
82093
|
+
];
|
|
82005
82094
|
if (toolCalls.length === 0) {
|
|
82006
82095
|
return { toolCalls: [], cleanedContent: content };
|
|
82007
82096
|
}
|
|
@@ -82009,7 +82098,8 @@ function extractTextualToolCalls(content) {
|
|
|
82009
82098
|
...openClaw.matches,
|
|
82010
82099
|
...anthropic.matches,
|
|
82011
82100
|
...gemini.matches,
|
|
82012
|
-
...gpt.matches
|
|
82101
|
+
...gpt.matches,
|
|
82102
|
+
...kimi.matches
|
|
82013
82103
|
]);
|
|
82014
82104
|
return { toolCalls, cleanedContent };
|
|
82015
82105
|
}
|
|
@@ -85784,6 +85874,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
85784
85874
|
const debugMode = debugHeadersEnabledFromEnv() && req.headers["x-clawrouter-debug"] !== "false";
|
|
85785
85875
|
let routingDecision;
|
|
85786
85876
|
let hasTools = false;
|
|
85877
|
+
let requestTools;
|
|
85787
85878
|
let hasVision = false;
|
|
85788
85879
|
let isStreaming = false;
|
|
85789
85880
|
let modelId = "";
|
|
@@ -85821,6 +85912,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
85821
85912
|
requestSummaryForStore = summarizeRequest(promptText);
|
|
85822
85913
|
}
|
|
85823
85914
|
hasTools = Array.isArray(parsed.tools) && parsed.tools.length > 0;
|
|
85915
|
+
requestTools = parsed.tools;
|
|
85824
85916
|
const rawLastContent = lastUserMsg?.content;
|
|
85825
85917
|
const lastContent = typeof rawLastContent === "string" ? rawLastContent : Array.isArray(rawLastContent) ? rawLastContent.filter((b) => b.type === "text").map((b) => b.text ?? "").join(" ") : "";
|
|
85826
85918
|
if (sessionId && parsedMessages.length > 0) {
|
|
@@ -87364,7 +87456,7 @@ data: [DONE]
|
|
|
87364
87456
|
let toolCalls = choice.message?.tool_calls ?? choice.delta?.tool_calls;
|
|
87365
87457
|
const rawContent = choice.message?.content ?? choice.delta?.content ?? "";
|
|
87366
87458
|
if (!endsWithToolCalls && (!toolCalls || toolCalls.length === 0) && rawContent) {
|
|
87367
|
-
const extracted = extractTextualToolCalls(rawContent);
|
|
87459
|
+
const extracted = extractTextualToolCalls(rawContent, { tools: requestTools });
|
|
87368
87460
|
if (extracted.toolCalls.length > 0) {
|
|
87369
87461
|
toolCalls = extracted.toolCalls;
|
|
87370
87462
|
}
|
|
@@ -87577,7 +87669,7 @@ data: [DONE]
|
|
|
87577
87669
|
}
|
|
87578
87670
|
continue;
|
|
87579
87671
|
}
|
|
87580
|
-
const extracted = extractTextualToolCalls(message.content);
|
|
87672
|
+
const extracted = extractTextualToolCalls(message.content, { tools: requestTools });
|
|
87581
87673
|
if (extracted.toolCalls.length > 0) {
|
|
87582
87674
|
message.tool_calls = extracted.toolCalls;
|
|
87583
87675
|
message.content = "";
|
package/package.json
CHANGED
package/scripts/update.sh
CHANGED
|
@@ -16,6 +16,96 @@ WALLET_FILE="$HOME/.openclaw/blockrun/wallet.key"
|
|
|
16
16
|
WALLET_BACKUP=""
|
|
17
17
|
PLUGIN_BACKUP=""
|
|
18
18
|
CONFIG_BACKUP=""
|
|
19
|
+
ACTIVE_PACKAGE_DIR=""
|
|
20
|
+
|
|
21
|
+
NPM_PREFIX="$(npm config get prefix 2>/dev/null || echo "")"
|
|
22
|
+
if [ -n "$NPM_PREFIX" ] && [ -d "$NPM_PREFIX/bin" ]; then
|
|
23
|
+
PATH="$NPM_PREFIX/bin:$PATH"
|
|
24
|
+
export PATH
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
find_clawrouter_package_dir() {
|
|
28
|
+
node <<'NODE'
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const os = require('os');
|
|
31
|
+
const path = require('path');
|
|
32
|
+
|
|
33
|
+
const home = os.homedir();
|
|
34
|
+
const candidates = [
|
|
35
|
+
{ packagePath: path.join(home, '.openclaw', 'extensions', 'clawrouter', 'package.json'), priority: 0 },
|
|
36
|
+
{ packagePath: path.join(home, '.openclaw', 'npm', 'node_modules', '@blockrun', 'clawrouter', 'package.json'), priority: 2 },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const projectsDir = path.join(home, '.openclaw', 'npm', 'projects');
|
|
40
|
+
try {
|
|
41
|
+
for (const name of fs.readdirSync(projectsDir)) {
|
|
42
|
+
candidates.push({
|
|
43
|
+
packagePath: path.join(projectsDir, name, 'node_modules', '@blockrun', 'clawrouter', 'package.json'),
|
|
44
|
+
priority: 1,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
} catch {}
|
|
48
|
+
|
|
49
|
+
function versionParts(version) {
|
|
50
|
+
return String(version || '').split(/[.-]/).slice(0, 3).map((part) => Number.parseInt(part, 10) || 0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function compareVersions(a, b) {
|
|
54
|
+
const left = versionParts(a);
|
|
55
|
+
const right = versionParts(b);
|
|
56
|
+
for (let i = 0; i < 3; i++) {
|
|
57
|
+
if (left[i] !== right[i]) return left[i] - right[i];
|
|
58
|
+
}
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let best = null;
|
|
63
|
+
for (const candidate of candidates) {
|
|
64
|
+
try {
|
|
65
|
+
const stat = fs.statSync(candidate.packagePath);
|
|
66
|
+
const pkg = JSON.parse(fs.readFileSync(candidate.packagePath, 'utf8'));
|
|
67
|
+
if (pkg?.name !== '@blockrun/clawrouter') continue;
|
|
68
|
+
const versionOrder = best ? compareVersions(pkg.version, best.pkg.version) : 1;
|
|
69
|
+
if (
|
|
70
|
+
!best ||
|
|
71
|
+
versionOrder > 0 ||
|
|
72
|
+
(versionOrder === 0 &&
|
|
73
|
+
(candidate.priority < best.priority ||
|
|
74
|
+
(candidate.priority === best.priority && stat.mtimeMs > best.mtimeMs)))
|
|
75
|
+
) {
|
|
76
|
+
best = { ...candidate, pkg, mtimeMs: stat.mtimeMs };
|
|
77
|
+
}
|
|
78
|
+
} catch {}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (best) console.log(path.dirname(best.packagePath));
|
|
82
|
+
NODE
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
sync_cli_shim() {
|
|
86
|
+
local package_dir="$1"
|
|
87
|
+
if [ -z "$package_dir" ] || [ ! -f "$package_dir/dist/cli.js" ]; then
|
|
88
|
+
echo " ⚠ Could not update CLI shim: ClawRouter CLI not found"
|
|
89
|
+
return 1
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
local prefix
|
|
93
|
+
prefix=$(npm config get prefix 2>/dev/null || echo "")
|
|
94
|
+
if [ -z "$prefix" ]; then
|
|
95
|
+
echo " ⚠ Could not update CLI shim: npm prefix unavailable"
|
|
96
|
+
return 1
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
local bin_dir="$prefix/bin"
|
|
100
|
+
mkdir -p "$bin_dir"
|
|
101
|
+
rm -f "$bin_dir/clawrouter"
|
|
102
|
+
cat >"$bin_dir/clawrouter" <<EOF
|
|
103
|
+
#!/bin/sh
|
|
104
|
+
exec node "$package_dir/dist/cli.js" "\$@"
|
|
105
|
+
EOF
|
|
106
|
+
chmod +x "$bin_dir/clawrouter"
|
|
107
|
+
echo " ✓ CLI shim updated: $bin_dir/clawrouter → $package_dir/dist/cli.js"
|
|
108
|
+
}
|
|
19
109
|
|
|
20
110
|
cleanup_backups() {
|
|
21
111
|
if [ -n "$PLUGIN_BACKUP" ] && [ -d "$PLUGIN_BACKUP" ]; then
|
|
@@ -93,6 +183,7 @@ echo ""
|
|
|
93
183
|
|
|
94
184
|
# Pre-flight: fail fast if config is corrupt
|
|
95
185
|
validate_config
|
|
186
|
+
ACTIVE_PACKAGE_DIR=$(find_clawrouter_package_dir)
|
|
96
187
|
|
|
97
188
|
echo "→ Checking wallet..."
|
|
98
189
|
|
|
@@ -105,7 +196,7 @@ if [ -f "$WALLET_FILE" ]; then
|
|
|
105
196
|
# Derive wallet address via node (viem is available post-install)
|
|
106
197
|
WALLET_ADDRESS=$(node -e "
|
|
107
198
|
try {
|
|
108
|
-
const { privateKeyToAccount } = require('
|
|
199
|
+
const { privateKeyToAccount } = require(require.resolve('viem/accounts', { paths: ['$ACTIVE_PACKAGE_DIR'] }));
|
|
109
200
|
const acct = privateKeyToAccount('$WALLET_KEY');
|
|
110
201
|
console.log(acct.address);
|
|
111
202
|
} catch {
|
|
@@ -551,41 +642,42 @@ force_install_from_npm() {
|
|
|
551
642
|
return 1
|
|
552
643
|
}
|
|
553
644
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
645
|
+
LATEST_VER=$(npm view @blockrun/clawrouter@latest version 2>/dev/null || echo "")
|
|
646
|
+
if [ -z "$LATEST_VER" ]; then
|
|
647
|
+
echo " ✗ Could not resolve latest ClawRouter version from npm"
|
|
648
|
+
exit 1
|
|
649
|
+
fi
|
|
650
|
+
|
|
651
|
+
ACTIVE_PACKAGE_DIR=$(find_clawrouter_package_dir)
|
|
652
|
+
INSTALLED_VER=""
|
|
653
|
+
if [ -n "$ACTIVE_PACKAGE_DIR" ] && [ -f "$ACTIVE_PACKAGE_DIR/package.json" ]; then
|
|
654
|
+
INSTALLED_VER=$(node -e "try{const p=require('$ACTIVE_PACKAGE_DIR/package.json');console.log(p.version);}catch{console.log('');}" 2>/dev/null || echo "")
|
|
655
|
+
fi
|
|
656
|
+
|
|
657
|
+
if [ "$OPENCLAW_INSTALL_RECOVERABLE" = "1" ] || [ -z "$INSTALLED_VER" ] || [ "$INSTALLED_VER" != "$LATEST_VER" ]; then
|
|
658
|
+
if [ -n "$INSTALLED_VER" ] && [ "$INSTALLED_VER" != "$LATEST_VER" ]; then
|
|
659
|
+
echo " ⚠️ OpenClaw installed v${INSTALLED_VER} but latest is v${LATEST_VER}"
|
|
559
660
|
fi
|
|
560
661
|
force_install_from_npm "$LATEST_VER"
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
exit 1
|
|
564
|
-
fi
|
|
565
|
-
INSTALLED_VER=$(node -e "try{const p=require('$PLUGIN_DIR/package.json');console.log(p.version);}catch{console.log('');}" 2>/dev/null || echo "")
|
|
566
|
-
if [ -z "$INSTALLED_VER" ]; then
|
|
567
|
-
echo " ✗ Could not verify ClawRouter version after npm fallback"
|
|
568
|
-
exit 1
|
|
569
|
-
fi
|
|
570
|
-
echo " ✓ ClawRouter v${INSTALLED_VER} installed"
|
|
571
|
-
trap - EXIT INT TERM
|
|
572
|
-
elif [ -d "$PLUGIN_DIR" ] && [ -f "$PLUGIN_DIR/package.json" ]; then
|
|
573
|
-
INSTALLED_VER=$(node -e "try{const p=require('$PLUGIN_DIR/package.json');console.log(p.version);}catch{console.log('');}" 2>/dev/null || echo "")
|
|
574
|
-
LATEST_VER=$(npm view @blockrun/clawrouter@latest version 2>/dev/null || echo "")
|
|
575
|
-
if [ -n "$LATEST_VER" ] && [ -n "$INSTALLED_VER" ] && [ "$INSTALLED_VER" != "$LATEST_VER" ]; then
|
|
576
|
-
echo " ⚠️ openclaw installed v${INSTALLED_VER} (cached) but latest is v${LATEST_VER}"
|
|
577
|
-
force_install_from_npm "$LATEST_VER" || true
|
|
578
|
-
fi
|
|
579
|
-
INSTALLED_VER=$(node -e "try{const p=require('$PLUGIN_DIR/package.json');console.log(p.version);}catch{console.log('?');}" 2>/dev/null || echo "?")
|
|
580
|
-
echo " ✓ ClawRouter v${INSTALLED_VER} installed"
|
|
662
|
+
ACTIVE_PACKAGE_DIR=$(find_clawrouter_package_dir)
|
|
663
|
+
INSTALLED_VER=$(node -e "try{const p=require('$ACTIVE_PACKAGE_DIR/package.json');console.log(p.version);}catch{console.log('');}" 2>/dev/null || echo "")
|
|
581
664
|
fi
|
|
582
665
|
|
|
666
|
+
if [ -z "$ACTIVE_PACKAGE_DIR" ] || [ -z "$INSTALLED_VER" ]; then
|
|
667
|
+
echo " ✗ Could not verify ClawRouter install"
|
|
668
|
+
exit 1
|
|
669
|
+
fi
|
|
670
|
+
|
|
671
|
+
echo " ✓ ClawRouter v${INSTALLED_VER} installed at $ACTIVE_PACKAGE_DIR"
|
|
672
|
+
sync_cli_shim "$ACTIVE_PACKAGE_DIR"
|
|
673
|
+
trap - EXIT INT TERM
|
|
674
|
+
|
|
583
675
|
# ── Step 4c: Ensure all dependencies are installed ────────────
|
|
584
676
|
# openclaw's plugin installer may skip native/optional deps like @solana/kit.
|
|
585
677
|
# Run npm install in the plugin directory to fill any gaps.
|
|
586
|
-
if [ -
|
|
678
|
+
if [ -n "$ACTIVE_PACKAGE_DIR" ] && [ -f "$ACTIVE_PACKAGE_DIR/package.json" ]; then
|
|
587
679
|
echo "→ Installing dependencies (Solana, x402, etc.)..."
|
|
588
|
-
run_dependency_install "$
|
|
680
|
+
run_dependency_install "$ACTIVE_PACKAGE_DIR"
|
|
589
681
|
fi
|
|
590
682
|
|
|
591
683
|
# ── Step 5: Verify wallet survived ─────────────────────────────
|
|
@@ -724,7 +816,7 @@ const os = require('os');
|
|
|
724
816
|
const fs = require('fs');
|
|
725
817
|
const path = require('path');
|
|
726
818
|
const configPath = path.join(os.homedir(), '.openclaw', 'openclaw.json');
|
|
727
|
-
const topModelsPath = '$
|
|
819
|
+
const topModelsPath = path.join('$ACTIVE_PACKAGE_DIR', 'src', 'top-models.json');
|
|
728
820
|
|
|
729
821
|
if (!fs.existsSync(configPath)) {
|
|
730
822
|
console.log(' No config file found, skipping');
|
|
@@ -1025,7 +1117,7 @@ if [ -f "$WALLET_FILE" ]; then
|
|
|
1025
1117
|
FINAL_KEY=$(cat "$WALLET_FILE" | tr -d '[:space:]')
|
|
1026
1118
|
FINAL_ADDRESS=$(node -e "
|
|
1027
1119
|
try {
|
|
1028
|
-
const { privateKeyToAccount } = require('
|
|
1120
|
+
const { privateKeyToAccount } = require(require.resolve('viem/accounts', { paths: ['$ACTIVE_PACKAGE_DIR'] }));
|
|
1029
1121
|
console.log(privateKeyToAccount('$FINAL_KEY').address);
|
|
1030
1122
|
} catch { console.log('(run /wallet in OpenClaw to see your address)'); }
|
|
1031
1123
|
" 2>/dev/null || echo "(run /wallet in OpenClaw to see your address)")
|
|
@@ -135,7 +135,7 @@ Rules handle ~~80% of requests in <1ms. Only ambiguous queries hit the LLM class
|
|
|
135
135
|
|
|
136
136
|
## Available Models
|
|
137
137
|
|
|
138
|
-
55+ models including: gpt-5.6-terra [balanced, stable default], gpt-5.6-sol [flagship], gpt-5.6-luna [cost-efficient], gpt-5.5, gpt-5.4, gpt-4o, o3, claude-fable-5, claude-opus-4.8, claude-opus-4.7, claude-opus-4.5, claude-sonnet-5, claude-sonnet-4.6, gemini-3.1-pro, gemini-2.5-flash, deepseek-v4-pro, deepseek-chat, grok-4.5, grok-4.3, grok-build-0.1, kimi-k2.7, and 8 free NVIDIA models (mistral-large-3-675b [default, 675B flagship], deepseek-v4-flash [1M context], seed-oss-36b [coding], nemotron-3-nano-omni-30b-a3b-reasoning [vision], mistral-nemotron, step-3.7-flash, nemotron-nano-9b-v2, nemotron-nano-12b-v2-vl [vision]).
|
|
138
|
+
55+ models including: gpt-5.6-terra [balanced, stable default], gpt-5.6-sol [flagship], gpt-5.6-luna [cost-efficient], gpt-5.5, gpt-5.4, gpt-4o, o3, claude-fable-5, claude-opus-4.8, claude-opus-4.7, claude-opus-4.5, claude-sonnet-5, claude-sonnet-4.6, gemini-3.1-pro, gemini-2.5-flash, deepseek-v4-pro, deepseek-chat, grok-4.5, grok-4.3, grok-build-0.1, kimi-k3 [1M ctx flagship], kimi-k2.7, and 8 free NVIDIA models (mistral-large-3-675b [default, 675B flagship], deepseek-v4-flash [1M context], seed-oss-36b [coding], nemotron-3-nano-omni-30b-a3b-reasoning [vision], mistral-nemotron, step-3.7-flash, nemotron-nano-9b-v2, nemotron-nano-12b-v2-vl [vision]).
|
|
139
139
|
|
|
140
140
|
## Built-in Agent Tools
|
|
141
141
|
|
|
@@ -158,7 +158,7 @@ Realtime prices and historical OHLC across every asset class. The agent should c
|
|
|
158
158
|
|
|
159
159
|
| Tool | Purpose | Price |
|
|
160
160
|
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
|
|
161
|
-
| `blockrun_image_generation` | 8 image models — GPT Image 1/2, Nano Banana / Pro, Seedream 5 Pro, Grok Imagine / Pro, CogView-4
|
|
161
|
+
| `blockrun_image_generation` | 8 image models — GPT Image 1/2, Nano Banana / Pro, Seedream 5 Pro, Grok Imagine / Pro, CogView-4 | $0.015–$0.15 / image |
|
|
162
162
|
| `blockrun_image_edit` | Edit / inpaint existing image (openai/gpt-image-1) | $0.02–$0.04 / image |
|
|
163
163
|
| `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 |
|
|
164
164
|
|
package/skills/imagegen/SKILL.md
CHANGED
|
@@ -55,16 +55,16 @@ Display inline: ``
|
|
|
55
55
|
|
|
56
56
|
### Model Selection
|
|
57
57
|
|
|
58
|
-
| Alias | Full ID | Price | Sizes | Best for
|
|
59
|
-
| ------------------ | ---------------------------- | ------------ | ------------------------------- |
|
|
60
|
-
| `nano-banana` | `google/nano-banana` | $0.05 | 1024×1024, 1216×832, 1024×1792 | Default — fast, cheap, good quality
|
|
61
|
-
| `banana-pro` | `google/nano-banana-pro` | $0.10–$0.15 | up to 4096×4096 | High-res, large format
|
|
62
|
-
| `gpt-image` | `openai/gpt-image-1` | $0.02–$0.04 | 1024×1024, 1536×1024, 1024×1536 | Budget option; supports editing
|
|
58
|
+
| Alias | Full ID | Price | Sizes | Best for |
|
|
59
|
+
| ------------------ | ---------------------------- | ------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
60
|
+
| `nano-banana` | `google/nano-banana` | $0.05 | 1024×1024, 1216×832, 1024×1792 | Default — fast, cheap, good quality |
|
|
61
|
+
| `banana-pro` | `google/nano-banana-pro` | $0.10–$0.15 | up to 4096×4096 | High-res, large format |
|
|
62
|
+
| `gpt-image` | `openai/gpt-image-1` | $0.02–$0.04 | 1024×1024, 1536×1024, 1024×1536 | Budget option; supports editing |
|
|
63
63
|
| `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
|
-
| `seedream` | `bytedance/seedream-5-pro` | $0.045–$0.09 | up to 2848×1600 / 2304×1728 | Flagship quality, reference-image support
|
|
65
|
-
| `grok-imagine` | `xai/grok-imagine-image` | $0.02 | 1024×1024 | xAI Grok image style
|
|
66
|
-
| `grok-imagine-pro` | `xai/grok-imagine-image-pro` | $0.07 | 1024×1024 | Grok high-quality
|
|
67
|
-
| `cogview` | `zai/cogview-4` | $0.015–$0.02 | 512×512 to 1440×1440 | Cheapest — Zhipu CogView
|
|
64
|
+
| `seedream` | `bytedance/seedream-5-pro` | $0.045–$0.09 | up to 2848×1600 / 2304×1728 | Flagship quality, reference-image support |
|
|
65
|
+
| `grok-imagine` | `xai/grok-imagine-image` | $0.02 | 1024×1024 | xAI Grok image style |
|
|
66
|
+
| `grok-imagine-pro` | `xai/grok-imagine-image-pro` | $0.07 | 1024×1024 | Grok high-quality |
|
|
67
|
+
| `cogview` | `zai/cogview-4` | $0.015–$0.02 | 512×512 to 1440×1440 | Cheapest — Zhipu CogView |
|
|
68
68
|
|
|
69
69
|
**Choosing a model:**
|
|
70
70
|
|