Releases: BlockRunAI/ClawRouter
v0.12.146
New Feature
Every routed response now carries a `usage.cost` breakdown.
Users on `blockrun/auto` previously had no visible signal of which model actually answered or how much each call cost. Now every response includes:
```json
{
"model": "google/gemini-2.5-flash",
"usage": {
"prompt_tokens": 120,
"completion_tokens": 80,
"total_tokens": 200,
"cost": {
"total": 0.00023,
"input": 0.000018,
"output": 0.000048,
"baseline": 0.00618,
"savings_pct": 96,
"model": "google/gemini-2.5-flash",
"tier": "SIMPLE"
}
}
}
```
What OpenClaw users see (no OpenClaw changes required)
- `/usage full` footer now shows session cost totals that increase as you chat
- `/stats`-style reports aggregate cost per model and per day
- Works automatically — OpenClaw's `session-cost-usage` module already parses the standard `usage.cost.{total,input,output}` fields
Extra metadata (forward-compat)
`baseline`, `savings_pct`, `model`, and `tier` are non-standard fields that current OpenClaw ignores. Future OpenClaw UI work can render them as an inline per-message badge (e.g. `via free/glm-4.7 · $0.0023 · saved 96%`) without any ClawRouter changes.
No context pollution
`usage` is OpenAI metadata — LLMs never see it when the conversation history is replayed. Safe to emit on every turn.
Technical details
- Uses ACTUAL upstream token counts (not pre-request estimates) via `calculateModelCost()`
- Server margin and MIN_PAYMENT_USD floor are applied consistently to both `total` and `baseline`
- Streaming responses emit a final OpenAI `include_usage`-format chunk before `[DONE]`
- Non-streaming responses always overwrite the top-level `model` field (some upstreams omit it)
- 9 new unit tests in `src/proxy.cost.test.ts`
Reported by
This feature was driven by user feedback that "auto" didn't feel transparent — users couldn't tell if it was actually saving money or just a black box.
v0.12.145
Improvements
- eco/premium null fallback (router/strategy.ts): when `ecoTiers` or `premiumTiers` is set to `null`, fall back to regular `tiers` instead of dropping into auto routing. Preserves the eco/premium profile semantics even when the special tier set is disabled.
- provider.ts: `setActiveProxy` now accepts `null` (used by the deactivate path).
- debug-command test: 2s client-side timeout so the test no longer hangs on slow upstream.
- CI green: prettier formatting cleanup in `src/index.ts` and `src/index.lifecycle.test.ts`.
v0.12.144
Bug Fixes
`/model` command now actually switches the model.
When a user ran `/model blockrun/free/glm-4.7` in OpenClaw, the bot's next response often still claimed to be the previously pinned model (typically Sonnet). The model wasn't really switching — it was being silently overridden by ClawRouter's session pinning, which was designed to prevent mid-task model switching but was too aggressive.
What changed
- `SessionEntry` now carries a `userExplicit` flag.
- When ClawRouter receives an explicit non-profile model (e.g. `blockrun/free/glm-4.7`, `anthropic/claude-opus-4.6`), it pins the session with `userExplicit=true`.
- Routing-profile requests (`blockrun/auto`, `blockrun/eco`, etc.) respect a user-explicit pin unconditionally — no tier-rank comparison, no escalation. The user's intent wins.
- The flag is sticky across fallback re-pins; it can only be cleared when the session expires.
User-visible impact
`/model ` actually switches the model, and the choice persists across follow-up messages even when OpenClaw reverts to sending `blockrun/auto` in subsequent chat completions.
v0.12.143
v0.12.142
Bug Fixes (#147)
User routing config in openclaw.json was silently ignored.
OpenClaw calls `register()` twice during gateway startup. The first call runs in a pre-gateway phase before `openclaw.json` has been parsed, so `api.pluginConfig` is empty. The previous `proxyAlreadyStarted` guard caused the proxy to start with `DEFAULT_ROUTING_CONFIG` on that first call, then the second call (the one with the user's actual `plugins.entries.clawrouter.config.routing`) bailed out as a no-op.
Result: any custom `routing`, `walletKey`, `maxCostPerRun`, etc. defined in `openclaw.json` was silently ignored.
Fix
- When `pluginConfig` is empty on a `register()` call, defer proxy startup for 250ms instead of starting immediately.
- If a second `register()` call arrives within that window with a populated `pluginConfig`, it cancels the deferred timer and starts the proxy with the real config.
- If no second call ever arrives (user has no plugin config at all), the timer fires and the proxy starts with defaults — no deadlock.
Reported by @jeegankones in #147.
v0.12.141
Bug Fixes (#148)
Fixes two related bugs that prevented users from customizing agent routing via `routingConfig`:
-
Custom tier sets weren't merged. `mergeRoutingConfig` only deep-merged `tiers`, ignoring `agenticTiers`, `ecoTiers`, and `premiumTiers`. Users defining custom `agenticTiers` had no effect on routing — agent requests always used the defaults.
-
`overrides.agenticMode: false` didn't disable agentic tiers. `hasToolsInRequest` was OR'ed in unconditionally, so any request with tools (i.e. every agent request) still routed through `agenticTiers`.
Changes
- `mergeRoutingConfig`: deep-merges `agenticTiers`/`ecoTiers`/`premiumTiers` (per-tier override), and `null` explicitly disables a tier set
- `agenticMode` now has clear three-state semantics:
- `true` → force agentic tiers
- `false` → disable agentic tiers entirely (even with tools)
- `undefined` → auto-detect via tools/agenticScore (default)
- `agenticTiers`/`ecoTiers`/`premiumTiers` types now accept `null`
- Regression tests for both bugs
Reported by @jeegankones in #148.
v0.12.140
Bug Fixes
- Fix doctor on Solana chain —
npx @blockrun/clawrouter doctorwas hardcoding an EVM signer and sending test requests toblockrun.airegardless of the user's configured payment chain. On Solana users, it produced a misleading `Payment verification failed` error showing an EVM payer address that didn't match their actual Solana wallet.
Now doctor registers the Solana scheme and routes to `sol.blockrun.ai` when `paymentChain=solana`.
v0.12.139
Bug Fixes
- Fix baseUrl overwrite after plugin install — OpenClaw's async config persistence was overwriting the correct local proxy URL (
127.0.0.1:8402) with the remoteblockrun.ai/apifallback. Root cause:provider.tsmodels getter returned the remote URL before proxy startup; OpenClaw serialized that intoopenclaw.json. Now always returns the local proxy URL. (reported by Cheetah) - Post-install baseUrl verification —
update.shandreinstall.shnow re-verify and fixbaseUrlafteropenclaw plugins install, not just before.
Improvements
- Added GLM models to allowlist —
zai/glm-5,zai/glm-5.1,zai/glm-5-turbonow appear in OpenClaw's/modelpicker. (reported by Aston)
v0.12.92 — Fix multi-turn chat for reasoning models (continue.dev #135)
Bug Fix: Existing chat always fails in continue.dev (#135)
Root cause
moonshot/kimi-k2.5 (primary MEDIUM-tier model in blockrun/auto) is a reasoning model that requires reasoning_content on all assistant messages in multi-turn history — not just tool-call messages. When continue.dev sent an existing chat, the plain-text assistant message from the previous turn was missing reasoning_content, causing a 400 from the model.
Since that 400 didn't match any PROVIDER_ERROR_PATTERNS, isProviderError=false and the fallback loop broke on the first attempt. All models failed → SSE error sent → OpenAI SDK in continue.dev threw "Unexpected error".
New chats (no assistant history) were unaffected — only existing chats broke.
Fixes
normalizeMessagesForThinking— now addsreasoning_content: ""to all assistant messages (not just tool-call ones) when targeting a reasoning model- SSE error format — error events now always use
{"error":{...}}OpenAI wrapper; raw upstream JSON was previously forwarded as-is, hiding the real error message PROVIDER_ERROR_PATTERNS— addedreasoning_content.*missingas a safety net for proper fallback
Verification
- E2E: 3-turn SSE streaming test passed (turn 2 was the broken case)
- Unit: 7 new regression tests for
normalizeMessagesForThinking - Full suite: 364/364 passing
Update
npx @blockrun/clawrouter@latest
v0.12.90 — Fix empty-turn fallback for eco/agentic requests
What's Fixed
Empty turn responses now trigger model fallback
Problem: Under the eco profile (and sometimes auto), agentic clients like Roo Code would receive silent empty responses — the model returned HTTP 200 with no content and no tool calls, just finish_reason: stop. The proxy treated this as success and forwarded the empty turn to the client, causing the agent to loop or stall.
Root cause: Models like gemini-3.1-flash-lite sometimes refuse complex agentic requests (large Roo Code tool schemas) by producing a zero-output response instead of an error. ClawRouter's degraded-response detector didn't catch this pattern, so it never fell back to the next model.
Fix: detectDegradedSuccessResponse now flags responses where:
choices[0].message.contentis empty and- no
tool_callsand finish_reason === "stop"
These are treated as degraded response: empty turn → fallback fires → next model in chain is tried automatically.
Upgrade
npm i -g @blockrun/clawrouter@latest