@darksol/bankr-router
v1.2.2
Published
Local BANKR-only smart router plugin for OpenClaw
Downloads
21
Readme
Bankr Router
Local smart router for Bankr LLM Gateway requests inside OpenClaw. Analyzes each prompt, selects the optimal Bankr model based on complexity, and routes inference upstream — saving cost without sacrificing quality.
Features
- Upstream Retry with Fallback — If the selected model fails (5xx/timeout), automatically retries with the next model in the ranked chain
- Smart Context Layer — Tier-aware context compression reduces token usage by up to 90% for cheap models
- Intelligent Routing — 15-dimension scoring engine classifies prompts into SIMPLE / MEDIUM / COMPLEX / REASONING tiers
- Multilingual — Keyword detection in 9 languages (EN, ZH, JA, RU, DE, ES, PT, KO, AR)
- Word-Boundary Matching —
classwon't matchclassification,letwon't matchletter - Streaming Support — SSE passthrough for
stream: truerequests - Config Caching — Stat-based 5s TTL cache avoids re-parsing JSON on every request
- System Prompt De-Weighting — Huge OpenClaw system prompts don't inflate routing scores
- Conversation Context — Short follow-ups like "yes do it" inherit the previous tier
- Self-Improving Stats — Tracks decisions, error rates, latency, and cost savings
- Structured Logging — JSON logs to stderr + rotating file (~/.bankr-router/requests.log)
- Optional Auth — Bearer token authentication via config
- Rate Limiting — 100 req/min per IP (configurable)
- Request Timeout — Configurable upstream timeout (default 60s) prevents hanging requests
- Enhanced Health Check — Uptime, request count, and upstream reachability probe
- Four Routing Profiles —
auto,eco,premium, plus automatic agentic detection - Zero Heavy Dependencies — Built on
node:http,node:crypto,node:test
Architecture
Bankr Router
Client ──► ┌───────────────────────────────────────────┐
│ │
POST /v1/ │ Auth ─► Rate Limit ─► Parse Request │
chat/ │ │ │
completions │ ┌─────────────▼──────────┐ │
│ │ 15-Dimension Scorer │ │
│ │ (rules.ts) │ │
│ │ │ │
│ │ Token Count │ │
│ │ Code Presence │ │
│ │ Reasoning Markers │ │
│ │ Technical Terms │ │
│ │ Creative Markers │ │
│ │ Multi-Step Patterns │ │
│ │ Question Complexity │ │
│ │ Agentic Detection │ │
│ │ + 7 more dimensions │ │
│ └────────────┬───────────┘ │
│ │ │
│ ┌────────────▼───────────┐ │
│ │ Tier Selector │ │
│ │ (selector.ts) │ │
│ │ │ │
│ │ SIMPLE ─► nano/flash │ │
│ │ MEDIUM ─► deepseek │ │
│ │ COMPLEX ─► sonnet │ │
│ │ REASONING ─► opus │ │
│ └────────────┬───────────┘ │
│ │ │
│ ┌────────────▼───────────┐ │
│ │ Context Shaper │ │
│ │ (context-shaper.ts) │ │
│ │ │ │
│ │ SIMPLE ─► <2k tok │ │
│ │ MEDIUM ─► <8k tok │ │
│ │ COMPLEX ─► <32k tok │ │
│ │ REASONING─► passthru │ │
│ │ │ │
│ │ LRU cache (500 slots) │ │
│ └────────────┬───────────┘ │
│ │ │
│ Context ─► Learner ─► Logger │
│ │ │
└───────────────────────────┼────────────────┘
│
▼
Bankr LLM Gateway
(llm.bankr.bot/v1)Quick Start
1. Install
git clone <this-repo>
cd bankr-router
npm install2. Configure OpenClaw
Add to your OpenClaw config (~/.openclaw/openclaw.json):
{
"plugins": {
"entries": {
"bankr-router": {
"spec": "/path/to/bankr-router",
"config": {
"host": "127.0.0.1",
"port": 8787,
"bankrProviderId": "bankr",
"routerProviderId": "bankr-router"
}
}
}
},
"models": {
"providers": {
"bankr-router": {
"baseURL": "http://127.0.0.1:8787/v1",
"apiKey": "local-router"
}
},
"defaultModel": "bankr-router/auto"
}
}3. Start
openclaw gateway restart
curl http://127.0.0.1:8787/healthConfiguration Reference
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| host | string | 127.0.0.1 | Bind address |
| port | number | 8787 | Listen port |
| openclawConfigPath | string | ~/.openclaw/openclaw.json | Path to OpenClaw config |
| bankrProviderId | string | bankr | Provider ID in OpenClaw config |
| routerProviderId | string | bankr-router | Router provider ID |
| authToken | string | — | Optional bearer token for auth |
| rateLimitPerMinute | number | 100 | Max requests per minute per IP |
| upstreamTimeoutMs | number | 60000 | Timeout for upstream requests (ms) |
| maxRetries | number | 2 | Max retry attempts with fallback models |
Environment Variables
| Variable | Description |
|----------|-------------|
| BANKR_LLM_KEY | Override Bankr API key (usually from OpenClaw config) |
| BANKR_ROUTER_PORT | Override listen port |
| BANKR_ROUTER_AUTH_TOKEN | Enable bearer token auth |
| BANKR_ROUTER_RATE_LIMIT | Override rate limit |
API Reference
GET /health
Health check with diagnostics (always unauthenticated).
{
"ok": true,
"name": "bankr-router",
"version": "1.2.0",
"upstream": "https://llm.bankr.bot/v1",
"upstreamReachable": true,
"uptime": "2.5h",
"totalRequests": 147,
"startedAt": "2026-03-15T18:00:00.000Z"
}GET /v1/models
List available routing profiles.
{
"object": "list",
"data": [
{ "id": "auto", "object": "model", "owned_by": "bankr-router" },
{ "id": "eco", "object": "model", "owned_by": "bankr-router" },
{ "id": "premium", "object": "model", "owned_by": "bankr-router" }
]
}POST /v1/chat/completions
OpenAI-compatible chat completions proxy. Routes to optimal Bankr model.
- Set
modeltoauto,eco, orpremiumfor routing profiles - Set
modelto a specific model ID to bypass routing - Set
stream: truefor SSE streaming
Response headers:
x-router-selected-model— the model that handled the request (may differ from initial selection if retry occurred)x-router-context-shaped—trueif context shaping was appliedx-router-context-ratio— compression ratio (e.g.,0.15= 85% reduction)x-router-version— router versionx-router-retries— number of retry attempts (only present if >0)
POST /v1/route
Diagnostic endpoint — returns routing decision without proxying.
{
"requestedModel": "auto",
"selectedModel": "deepseek-v3.2",
"tier": "MEDIUM",
"confidence": 0.92,
"savings": 0.85
}GET /v1/stats
Self-improving system stats.
{
"totalRequests": 1247,
"tierDistribution": { "SIMPLE": 580, "MEDIUM": 412, "COMPLEX": 198, "REASONING": 57 },
"avgConfidence": 0.91,
"modelUsage": { "gpt-5-nano": 423, "deepseek-v3.2": 389, "..." : "..." },
"errorRates": { "gpt-5-nano": { "total": 423, "errors": 2, "rate": 0.005 } },
"avgLatencyByModel": { "gpt-5-nano": 145, "deepseek-v3.2": 310 },
"estimatedSavings": 12.47
}GET /v1/context/stats
Context shaping statistics.
{
"totalShaped": 847,
"totalOriginalTokens": 2450000,
"totalShapedTokens": 620000,
"totalTokensSaved": 1830000,
"avgCompressionByTier": { "SIMPLE": 0.12, "MEDIUM": 0.35, "COMPLEX": 0.78, "REASONING": 1.0 },
"cacheHitRate": 0.23,
"cacheSize": 142,
"cacheMaxSize": 500
}Smart Context Layer
The killer feature: tier-aware context compression that shapes conversation history based on the routing decision. Cheap models don't get blasted with 100k tokens they don't need.
What it does
After the router selects a tier and model, the context shaper compresses the messages array to fit the target model's capabilities. This reduces token usage (and cost) without losing the information the model actually needs.
Why it matters
- Cost savings — SIMPLE tier requests often carry 50k+ tokens of context. Shaping reduces this to <2k, cutting input cost by 90%+
- Faster responses — Less input = faster time-to-first-token
- Better quality — Small models perform better with focused context than with noise
How it works
- Pure heuristics — Zero LLM calls for shaping. Extractive summarization only (first sentence extraction, code block preservation, URL preservation)
- Per-tier strategies — Each tier has calibrated limits for exchanges, system prompts, tool messages, and images
- LRU caching — Shaped contexts are cached (keyed by session + tier + message count) to avoid re-shaping identical conversations. Max 500 entries
Per-Tier Strategy
| Tier | Exchanges Kept | System Prompt | Tool Messages | Images | Target | |------|---------------|---------------|---------------|--------|--------| | SIMPLE | Last 2 | Replace with minimal (if >500 chars) | Remove all | Remove all | <2k tokens | | MEDIUM | Last 8 | Truncate to 2000 chars | Last 2 exchanges | Last message | <8k tokens | | COMPLEX | Last 20 | Full | Last 5 exchanges | All | <32k tokens | | REASONING | All | Full | All | All | Passthrough (trim at 85% context window) |
Summarization approach
Old messages beyond the exchange window are compressed using extractive summarization:
- First sentence of each message is extracted
- Code blocks (triple backtick) are preserved intact
- URLs are preserved
- System prompts: first N + last N chars (important parts are at start and end)
- Old messages become:
[Previous context: user asked about X, assistant provided Y]
Self-Improving System
The router passively tracks every routing decision:
- What's logged: timestamp, prompt hash (first 8 chars SHA-256), tier, model, confidence, latency, upstream status
- Where:
~/.bankr-router/decisions.json(in-memory + disk) - Stats: Computed on demand via
GET /v1/stats— tier distribution, error rates, average latency per model, cost savings - Privacy: Only prompt hashes are stored, never raw prompts
The system is read-only by design — it observes and reports but never rewrites routing config without user consent.
Conversation Context
The router maintains a sliding window of the last 5 messages per conversation:
- Sessions are identified by
x-session-idheader, or hashed from the system prompt - Short follow-ups ("yes", "do it", "ok go ahead") inherit the previous conversation's tier
- Prevents a "yes" after a complex coding discussion from routing to the cheapest model
- LRU cache: max 1000 conversations
Routing Profiles
| Profile | Description |
|---------|-------------|
| auto | Balanced cost/quality. Detects agentic tasks and upgrades automatically |
| eco | Minimize cost. Favors flash/nano models |
| premium | Maximize quality. Favors Claude/GPT-5.x models |
Testing
npm test92 tests covering:
- Word-boundary keyword matching
- Dimension scoring and tier classification
- System prompt de-weighting
- Routing decisions with mock catalogs
- HTTP endpoints (health, models, route, stats)
- Authentication and auth bypass
- Decision logging and stats computation
- Conversation context and follow-up detection
- Context shaping per tier (SIMPLE, MEDIUM, COMPLEX, REASONING)
- Context cache hit/miss behavior
- Extractive summarization and token estimation
- Edge cases (empty messages, single message, multi-part content)
Skill
This repo includes a reusable OpenClaw skill:
skills/bankr-router/SKILL.mdTroubleshooting
| Problem | Solution |
|---------|----------|
| Unknown model: bankr-router/auto | Ensure models.providers has bankr-router and defaultModel uses bankr-router/auto |
| Port already in use | Change port in plugin config and update baseURL accordingly |
| Gateway restart loop | Verify openclaw.plugin.json exists at plugin root and spec points to repo root |
| Router bypassed | Check agent-specific overrides in models.providers or ~/.openclaw/agents/<agentId>/agent/models.json |
| 401 Unauthorized | Set BANKR_ROUTER_AUTH_TOKEN env var or authToken in config, then pass Authorization: Bearer <token> |
| 429 Too Many Requests | Rate limited — wait for Retry-After seconds or increase rateLimitPerMinute |
| Stale config | Config is cached for 5s. Modify the file and wait, or restart the server |
Contributing
- Fork and clone
npm install- Make changes in
src/ npm run build && npm test- Submit a PR
Attribution & Lineage
Originally inspired by a routing concept from TachikomaRed & smolemaru. Darksol reviewed the original codebase and rebuilt it from v1.0.0 onward.
v1.0.0 — Built by Darksol 🌑
Full rebuild of the routing engine with production-grade architecture:
- 15-dimension scoring engine with tier-based routing
- Word-boundary keyword matching (Latin + CJK/Arabic/Cyrillic)
- Multilingual keyword detection (9 languages: EN, ZH, JA, RU, DE, ES, PT, KO, AR)
- System prompt de-weighting (OpenClaw system prompts no longer pollute scores)
- Conversation context awareness with short follow-up detection
- Four routing profiles (auto, eco, premium) + automatic agentic detection
- Self-improving learner with decision logging and stats
- Streaming SSE passthrough
- Structured JSON request logging with rotation (10MB max)
- Stat-based config caching (5s TTL)
- Rate limiting and optional bearer auth
- OpenClaw plugin integration
- 63 tests
v1.1.0 — Smart Context Layer
- Tier-aware context compression (
context-shaper.ts) — reduces token usage up to 90% for cheap models - Per-tier strategies: SIMPLE (<2k), MEDIUM (<8k), COMPLEX (<32k), REASONING (passthrough)
- Extractive summarization (first-sentence extraction, code block + URL preservation) — zero LLM calls
- LRU context cache (500 entries) keyed by session + tier + message count
X-Router-Context-ShapedandX-Router-Context-Ratioresponse headersGET /v1/context/statsendpoint- Context shaping metrics in learner decision records
- 22 new tests → 85 total
v1.2.0 — Resilience & Observability
- Upstream retry with fallback chain — on 5xx/429/timeout, auto-retries next model in ranked chain
- Configurable request timeout (
upstreamTimeoutMs, default 60s) - Enhanced
/health— uptime, total requests, upstream reachability probe - Dynamic version from
package.json(no more hardcoded) X-Router-VersionandX-Router-Retriesresponse headers- Published as
@darksol/bankr-routeron npm - 7 new tests → 92 total
License
MIT
Built by Darksol 🌑. Original concept by TachikomaRed & smolemaru.
