@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 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 | 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) |
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 | 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 |
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 | 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 |
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-k2.7",
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 — K2.7 is the featured flagship on BlockRun (added 2026-06-13,
34511
- // commit cd3d79b; K2.6 marked hidden/superseded, K2.5 hidden). Bare aliases now
34512
- // resolve to K2.7 (same $0.95/$4.00 price as K2.6 — AT-COST, zero margin). Explicit
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 K2.7 — Moonshot's flagship (added 2026-06-13). 256K context, multi-modal
35296
- // (image + VIDEO input), returns reasoning_content. Served via BlockRun's OpenRouter
35297
- // credit pool (slug moonshotai/kimi-k2.7-code) failing over to direct Moonshot.
35298
- // AT-COST pricing ($0.95/$4.00 = OpenRouter COGS, zero margin) — same as K2.6.
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 gpt = openClaw.calls.length + anthropic.calls.length + gemini.calls.length === 0 ? extractGptCalls(content) : { calls: [], matches: [] };
82184
- const toolCalls = [...openClaw.calls, ...anthropic.calls, ...gemini.calls, ...gpt.calls];
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-k2.7",
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 — K2.7 is the featured flagship on BlockRun (added 2026-06-13,
301
- // commit cd3d79b; K2.6 marked hidden/superseded, K2.5 hidden). Bare aliases now
302
- // resolve to K2.7 (same $0.95/$4.00 price as K2.6 — AT-COST, zero margin). Explicit
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 K2.7 — Moonshot's flagship (added 2026-06-13). 256K context, multi-modal
1086
- // (image + VIDEO input), returns reasoning_content. Served via BlockRun's OpenRouter
1087
- // credit pool (slug moonshotai/kimi-k2.7-code) failing over to direct Moonshot.
1088
- // AT-COST pricing ($0.95/$4.00 = OpenRouter COGS, zero margin) — same as K2.6.
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 gpt = openClaw.calls.length + anthropic.calls.length + gemini.calls.length === 0 ? extractGptCalls(content) : { calls: [], matches: [] };
82004
- const toolCalls = [...openClaw.calls, ...anthropic.calls, ...gemini.calls, ...gpt.calls];
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/clawrouter",
3
- "version": "0.12.228",
3
+ "version": "0.12.230",
4
4
  "description": "Smart LLM router — save 85% on inference costs. 55+ models (8 free), one wallet, x402 micropayments.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
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('$HOME/.openclaw/extensions/clawrouter/node_modules/viem/accounts/index.js');
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
- if [ "$OPENCLAW_INSTALL_RECOVERABLE" = "1" ]; then
555
- LATEST_VER=$(npm view @blockrun/clawrouter@latest version 2>/dev/null || echo "")
556
- if [ -z "$LATEST_VER" ]; then
557
- echo " ✗ Could not resolve latest ClawRouter version from npm"
558
- exit 1
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
- if [ ! -f "$PLUGIN_DIR/package.json" ]; then
562
- echo " ✗ ClawRouter package.json missing after npm fallback"
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 [ -d "$PLUGIN_DIR" ] && [ -f "$PLUGIN_DIR/package.json" ]; then
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 "$PLUGIN_DIR"
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 = '$SCRIPT_DIR/../src/top-models.json';
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('$HOME/.openclaw/extensions/clawrouter/node_modules/viem/accounts/index.js');
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 | $0.015–$0.15 / image |
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
 
@@ -55,16 +55,16 @@ Display inline: `![generated image](http://localhost:8402/images/abc123.png)`
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
 
@@ -31,7 +31,7 @@
31
31
  "zai/glm-5",
32
32
  "minimax/minimax-m3",
33
33
  "minimax/minimax-m2.7",
34
- "moonshot/kimi-k2.7",
34
+ "moonshot/kimi-k3",
35
35
  "deepseek/deepseek-v4-pro",
36
36
  "deepseek/deepseek-chat",
37
37
  "deepseek/deepseek-reasoner",