{"_id":"@darksol/bankr-router","_rev":"3-3c5a6f9319f5424b783b0bed02fa21f6","name":"@darksol/bankr-router","dist-tags":{"latest":"1.2.2"},"versions":{"1.2.0":{"name":"@darksol/bankr-router","version":"1.2.0","license":"MIT","_id":"@darksol/bankr-router@1.2.0","maintainers":[{"name":"darksol","email":"chris00claw@gmail.com"}],"dist":{"shasum":"edd79a44406099b8557feb601ff3482a03e15b84","tarball":"https://registry.npmjs.org/@darksol/bankr-router/-/bankr-router-1.2.0.tgz","fileCount":18,"integrity":"sha512-EG6fYzFM5GFdmnDgaULEaoh0VThEYQnvNrbKrBeo0PS9Hvt/2wXX+Txq/k58yg6uosAqkLorOT16h+IpWx8sCg==","signatures":[{"sig":"MEQCIDOFYtfRlaC0TXAUrH853vnXViyppw0WZgo1GxS0WVPlAiAr3sPe+eIKLowpnt/0eXMPK8dBLojhG/8lnxyZRIQ2wA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":135376},"main":"dist/index.js","type":"module","gitHead":"cbf9a0492278af4db8f894a1962ff4da7f99ef85","scripts":{"test":"node --test --import tsx test/*.test.ts","build":"tsc -p tsconfig.json","start":"node dist/index.js","prepare":"npm run build"},"_npmUser":{"name":"darksol","email":"chris00claw@gmail.com"},"openclaw":{"extensions":["./dist/index.js"]},"_npmVersion":"11.8.0","description":"Local BANKR-only smart router plugin for OpenClaw","directories":{},"_nodeVersion":"24.13.1","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","typescript":"^5.7.3","@types/node":"^22.10.2"},"peerDependencies":{"openclaw":">=0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/bankr-router_1.2.0_1773617549945_0.6065649272759783","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@darksol/bankr-router","version":"1.2.1","license":"MIT","_id":"@darksol/bankr-router@1.2.1","maintainers":[{"name":"darksol","email":"chris00claw@gmail.com"}],"dist":{"shasum":"d5aea6af7463df861dc6be210740c0a020ca7a87","tarball":"https://registry.npmjs.org/@darksol/bankr-router/-/bankr-router-1.2.1.tgz","fileCount":18,"integrity":"sha512-d/Prkq0x8XMbMfaF4IDY7SuLfqU7CExL9Uzbqau85iKPpLQUzpJoSnvUGr1w/5PEPN3o6DbwJgepoSfTKSf0Cw==","signatures":[{"sig":"MEYCIQCVuz8ZM6CPmMQN0O70qNy7Rr/gssnU1RYGudDfwTxp/gIhALmcWi003bNgh5AzbrAYv2UO8DLGN0H/hxXB4gZUAmGA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":137487},"main":"dist/index.js","type":"module","gitHead":"f2aa9a5444e87c59fb18fb95c590e0fd06fc4bf3","scripts":{"test":"node --test --import tsx test/*.test.ts","build":"tsc -p tsconfig.json","start":"node dist/index.js","prepare":"npm run build"},"_npmUser":{"name":"darksol","email":"chris00claw@gmail.com"},"openclaw":{"extensions":["./dist/index.js"]},"_npmVersion":"11.8.0","description":"Local BANKR-only smart router plugin for OpenClaw","directories":{},"_nodeVersion":"24.13.1","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","openclaw":"^2026.3.13","typescript":"^5.7.3","@types/node":"^22.10.2"},"peerDependencies":{"openclaw":">=0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/bankr-router_1.2.1_1774126814045_0.9218642789958715","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"name":"@darksol/bankr-router","version":"1.2.2","description":"Local BANKR-only smart router plugin for OpenClaw","type":"module","main":"dist/index.js","scripts":{"build":"tsc -p tsconfig.json","start":"node dist/index.js","test":"node --test --import tsx test/*.test.ts","prepare":"npm run build"},"license":"MIT","peerDependencies":{"openclaw":">=0.4.0"},"openclaw":{"extensions":["./dist/index.js"]},"devDependencies":{"@types/node":"^22.10.2","openclaw":"^2026.3.13","tsx":"^4.19.0","typescript":"^5.7.3"},"gitHead":"f2aa9a5444e87c59fb18fb95c590e0fd06fc4bf3","_id":"@darksol/bankr-router@1.2.2","_nodeVersion":"24.13.1","_npmVersion":"11.8.0","dist":{"integrity":"sha512-tfKSF8+fglQt9YZkQd7tVt0ZydPCLB2xjRDyRqWtkgIZbKtFehtrr2d0lfgIbLNDPneqWsQcoWQZUgse95bFgA==","shasum":"f8979ad1c6307f739fe23b027fd50061aa77ee71","tarball":"https://registry.npmjs.org/@darksol/bankr-router/-/bankr-router-1.2.2.tgz","fileCount":19,"unpackedSize":142715,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDmxDIIDYKuC84m596rJZ7qH6273qUEpzqtBKB1Ak7K7wIgcO1HK1jUL55u2FUUfU6v2HEeXcKHuwQ4iGkAb/QNI40="}]},"_npmUser":{"name":"darksol","email":"chris00claw@gmail.com"},"directories":{},"maintainers":[{"name":"darksol","email":"chris00claw@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/bankr-router_1.2.2_1774477654302_0.43536006198883337"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-15T23:32:29.868Z","modified":"2026-03-25T22:27:34.581Z","1.2.0":"2026-03-15T23:32:30.117Z","1.2.1":"2026-03-21T21:00:14.186Z","1.2.2":"2026-03-25T22:27:34.444Z"},"license":"MIT","description":"Local BANKR-only smart router plugin for OpenClaw","maintainers":[{"name":"darksol","email":"chris00claw@gmail.com"}],"readme":"# Bankr Router\r\n\r\n![version](https://img.shields.io/badge/version-1.2.0-blue)\r\n![license](https://img.shields.io/badge/license-MIT-green)\r\n![node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)\r\n\r\nLocal smart router for [Bankr LLM Gateway](https://bankr.bot) requests inside [OpenClaw](https://openclaw.dev). Analyzes each prompt, selects the optimal Bankr model based on complexity, and routes inference upstream — saving cost without sacrificing quality.\r\n\r\n## Features\r\n\r\n- **Upstream Retry with Fallback** — If the selected model fails (5xx/timeout), automatically retries with the next model in the ranked chain\r\n- **Smart Context Layer** — Tier-aware context compression reduces token usage by up to 90% for cheap models\r\n- **Intelligent Routing** — 15-dimension scoring engine classifies prompts into SIMPLE / MEDIUM / COMPLEX / REASONING tiers\r\n- **Multilingual** — Keyword detection in 9 languages (EN, ZH, JA, RU, DE, ES, PT, KO, AR)\r\n- **Word-Boundary Matching** — `class` won't match `classification`, `let` won't match `letter`\r\n- **Streaming Support** — SSE passthrough for `stream: true` requests\r\n- **Config Caching** — Stat-based 5s TTL cache avoids re-parsing JSON on every request\r\n- **System Prompt De-Weighting** — Huge OpenClaw system prompts don't inflate routing scores\r\n- **Conversation Context** — Short follow-ups like \"yes do it\" inherit the previous tier\r\n- **Self-Improving Stats** — Tracks decisions, error rates, latency, and cost savings\r\n- **Structured Logging** — JSON logs to stderr + rotating file (~/.bankr-router/requests.log)\r\n- **Optional Auth** — Bearer token authentication via config\r\n- **Rate Limiting** — 100 req/min per IP (configurable)\r\n- **Request Timeout** — Configurable upstream timeout (default 60s) prevents hanging requests\r\n- **Enhanced Health Check** — Uptime, request count, and upstream reachability probe\r\n- **Four Routing Profiles** — `auto`, `eco`, `premium`, plus automatic agentic detection\r\n- **Zero Heavy Dependencies** — Built on `node:http`, `node:crypto`, `node:test`\r\n\r\n## Architecture\r\n\r\n```\r\n                              Bankr Router\r\n  Client ──►  ┌───────────────────────────────────────────┐\r\n               │                                           │\r\n  POST /v1/   │  Auth ─► Rate Limit ─► Parse Request      │\r\n  chat/       │                            │               │\r\n  completions │              ┌─────────────▼──────────┐    │\r\n               │              │   15-Dimension Scorer  │    │\r\n               │              │   (rules.ts)           │    │\r\n               │              │                        │    │\r\n               │              │  Token Count           │    │\r\n               │              │  Code Presence         │    │\r\n               │              │  Reasoning Markers     │    │\r\n               │              │  Technical Terms       │    │\r\n               │              │  Creative Markers      │    │\r\n               │              │  Multi-Step Patterns   │    │\r\n               │              │  Question Complexity   │    │\r\n               │              │  Agentic Detection     │    │\r\n               │              │  + 7 more dimensions   │    │\r\n               │              └────────────┬───────────┘    │\r\n               │                           │                │\r\n               │              ┌────────────▼───────────┐    │\r\n               │              │   Tier Selector        │    │\r\n               │              │   (selector.ts)        │    │\r\n               │              │                        │    │\r\n               │              │  SIMPLE ─► nano/flash  │    │\r\n               │              │  MEDIUM ─► deepseek    │    │\r\n               │              │  COMPLEX ─► sonnet     │    │\r\n               │              │  REASONING ─► opus     │    │\r\n               │              └────────────┬───────────┘    │\r\n               │                           │                │\r\n               │              ┌────────────▼───────────┐    │\r\n               │              │   Context Shaper       │    │\r\n               │              │   (context-shaper.ts)  │    │\r\n               │              │                        │    │\r\n               │              │  SIMPLE   ─► <2k tok   │    │\r\n               │              │  MEDIUM   ─► <8k tok   │    │\r\n               │              │  COMPLEX  ─► <32k tok  │    │\r\n               │              │  REASONING─► passthru  │    │\r\n               │              │                        │    │\r\n               │              │  LRU cache (500 slots) │    │\r\n               │              └────────────┬───────────┘    │\r\n               │                           │                │\r\n               │              Context ─► Learner ─► Logger  │\r\n               │                           │                │\r\n               └───────────────────────────┼────────────────┘\r\n                                           │\r\n                                           ▼\r\n                              Bankr LLM Gateway\r\n                              (llm.bankr.bot/v1)\r\n```\r\n\r\n## Quick Start\r\n\r\n### 1. Install\r\n\r\n```bash\r\ngit clone <this-repo>\r\ncd bankr-router\r\nnpm install\r\n```\r\n\r\n### 2. Configure OpenClaw\r\n\r\nAdd to your OpenClaw config (`~/.openclaw/openclaw.json`):\r\n\r\n```json\r\n{\r\n  \"plugins\": {\r\n    \"entries\": {\r\n      \"bankr-router\": {\r\n        \"spec\": \"/path/to/bankr-router\",\r\n        \"config\": {\r\n          \"host\": \"127.0.0.1\",\r\n          \"port\": 8787,\r\n          \"bankrProviderId\": \"bankr\",\r\n          \"routerProviderId\": \"bankr-router\"\r\n        }\r\n      }\r\n    }\r\n  },\r\n  \"models\": {\r\n    \"providers\": {\r\n      \"bankr-router\": {\r\n        \"baseURL\": \"http://127.0.0.1:8787/v1\",\r\n        \"apiKey\": \"local-router\"\r\n      }\r\n    },\r\n    \"defaultModel\": \"bankr-router/auto\"\r\n  }\r\n}\r\n```\r\n\r\n### 3. Start\r\n\r\n```bash\r\nopenclaw gateway restart\r\ncurl http://127.0.0.1:8787/health\r\n```\r\n\r\n## Configuration Reference\r\n\r\n| Setting | Type | Default | Description |\r\n|---------|------|---------|-------------|\r\n| `host` | string | `127.0.0.1` | Bind address |\r\n| `port` | number | `8787` | Listen port |\r\n| `openclawConfigPath` | string | `~/.openclaw/openclaw.json` | Path to OpenClaw config |\r\n| `bankrProviderId` | string | `bankr` | Provider ID in OpenClaw config |\r\n| `routerProviderId` | string | `bankr-router` | Router provider ID |\r\n| `authToken` | string | — | Optional bearer token for auth |\r\n| `rateLimitPerMinute` | number | `100` | Max requests per minute per IP |\r\n| `upstreamTimeoutMs` | number | `60000` | Timeout for upstream requests (ms) |\r\n| `maxRetries` | number | `2` | Max retry attempts with fallback models |\r\n\r\n### Environment Variables\r\n\r\n| Variable | Description |\r\n|----------|-------------|\r\n| `BANKR_LLM_KEY` | Override Bankr API key (usually from OpenClaw config) |\r\n| `BANKR_ROUTER_PORT` | Override listen port |\r\n| `BANKR_ROUTER_AUTH_TOKEN` | Enable bearer token auth |\r\n| `BANKR_ROUTER_RATE_LIMIT` | Override rate limit |\r\n\r\n## API Reference\r\n\r\n### `GET /health`\r\n\r\nHealth check with diagnostics (always unauthenticated).\r\n\r\n```json\r\n{\r\n  \"ok\": true,\r\n  \"name\": \"bankr-router\",\r\n  \"version\": \"1.2.0\",\r\n  \"upstream\": \"https://llm.bankr.bot/v1\",\r\n  \"upstreamReachable\": true,\r\n  \"uptime\": \"2.5h\",\r\n  \"totalRequests\": 147,\r\n  \"startedAt\": \"2026-03-15T18:00:00.000Z\"\r\n}\r\n```\r\n\r\n### `GET /v1/models`\r\n\r\nList available routing profiles.\r\n\r\n```json\r\n{\r\n  \"object\": \"list\",\r\n  \"data\": [\r\n    { \"id\": \"auto\", \"object\": \"model\", \"owned_by\": \"bankr-router\" },\r\n    { \"id\": \"eco\", \"object\": \"model\", \"owned_by\": \"bankr-router\" },\r\n    { \"id\": \"premium\", \"object\": \"model\", \"owned_by\": \"bankr-router\" }\r\n  ]\r\n}\r\n```\r\n\r\n### `POST /v1/chat/completions`\r\n\r\nOpenAI-compatible chat completions proxy. Routes to optimal Bankr model.\r\n\r\n- Set `model` to `auto`, `eco`, or `premium` for routing profiles\r\n- Set `model` to a specific model ID to bypass routing\r\n- Set `stream: true` for SSE streaming\r\n\r\nResponse headers:\r\n- `x-router-selected-model` — the model that handled the request (may differ from initial selection if retry occurred)\r\n- `x-router-context-shaped` — `true` if context shaping was applied\r\n- `x-router-context-ratio` — compression ratio (e.g., `0.15` = 85% reduction)\r\n- `x-router-version` — router version\r\n- `x-router-retries` — number of retry attempts (only present if >0)\r\n\r\n### `POST /v1/route`\r\n\r\nDiagnostic endpoint — returns routing decision without proxying.\r\n\r\n```json\r\n{\r\n  \"requestedModel\": \"auto\",\r\n  \"selectedModel\": \"deepseek-v3.2\",\r\n  \"tier\": \"MEDIUM\",\r\n  \"confidence\": 0.92,\r\n  \"savings\": 0.85\r\n}\r\n```\r\n\r\n### `GET /v1/stats`\r\n\r\nSelf-improving system stats.\r\n\r\n```json\r\n{\r\n  \"totalRequests\": 1247,\r\n  \"tierDistribution\": { \"SIMPLE\": 580, \"MEDIUM\": 412, \"COMPLEX\": 198, \"REASONING\": 57 },\r\n  \"avgConfidence\": 0.91,\r\n  \"modelUsage\": { \"gpt-5-nano\": 423, \"deepseek-v3.2\": 389, \"...\" : \"...\" },\r\n  \"errorRates\": { \"gpt-5-nano\": { \"total\": 423, \"errors\": 2, \"rate\": 0.005 } },\r\n  \"avgLatencyByModel\": { \"gpt-5-nano\": 145, \"deepseek-v3.2\": 310 },\r\n  \"estimatedSavings\": 12.47\r\n}\r\n```\r\n\r\n### `GET /v1/context/stats`\r\n\r\nContext shaping statistics.\r\n\r\n```json\r\n{\r\n  \"totalShaped\": 847,\r\n  \"totalOriginalTokens\": 2450000,\r\n  \"totalShapedTokens\": 620000,\r\n  \"totalTokensSaved\": 1830000,\r\n  \"avgCompressionByTier\": { \"SIMPLE\": 0.12, \"MEDIUM\": 0.35, \"COMPLEX\": 0.78, \"REASONING\": 1.0 },\r\n  \"cacheHitRate\": 0.23,\r\n  \"cacheSize\": 142,\r\n  \"cacheMaxSize\": 500\r\n}\r\n```\r\n\r\n## Smart Context Layer\r\n\r\nThe 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.\r\n\r\n### What it does\r\n\r\nAfter 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.\r\n\r\n### Why it matters\r\n\r\n- **Cost savings** — SIMPLE tier requests often carry 50k+ tokens of context. Shaping reduces this to <2k, cutting input cost by 90%+\r\n- **Faster responses** — Less input = faster time-to-first-token\r\n- **Better quality** — Small models perform better with focused context than with noise\r\n\r\n### How it works\r\n\r\n- **Pure heuristics** — Zero LLM calls for shaping. Extractive summarization only (first sentence extraction, code block preservation, URL preservation)\r\n- **Per-tier strategies** — Each tier has calibrated limits for exchanges, system prompts, tool messages, and images\r\n- **LRU caching** — Shaped contexts are cached (keyed by session + tier + message count) to avoid re-shaping identical conversations. Max 500 entries\r\n\r\n### Per-Tier Strategy\r\n\r\n| Tier | Exchanges Kept | System Prompt | Tool Messages | Images | Target |\r\n|------|---------------|---------------|---------------|--------|--------|\r\n| SIMPLE | Last 2 | Replace with minimal (if >500 chars) | Remove all | Remove all | <2k tokens |\r\n| MEDIUM | Last 8 | Truncate to 2000 chars | Last 2 exchanges | Last message | <8k tokens |\r\n| COMPLEX | Last 20 | Full | Last 5 exchanges | All | <32k tokens |\r\n| REASONING | All | Full | All | All | Passthrough (trim at 85% context window) |\r\n\r\n### Summarization approach\r\n\r\nOld messages beyond the exchange window are compressed using extractive summarization:\r\n- First sentence of each message is extracted\r\n- Code blocks (triple backtick) are preserved intact\r\n- URLs are preserved\r\n- System prompts: first N + last N chars (important parts are at start and end)\r\n- Old messages become: `[Previous context: user asked about X, assistant provided Y]`\r\n\r\n## Self-Improving System\r\n\r\nThe router passively tracks every routing decision:\r\n\r\n- **What's logged**: timestamp, prompt hash (first 8 chars SHA-256), tier, model, confidence, latency, upstream status\r\n- **Where**: `~/.bankr-router/decisions.json` (in-memory + disk)\r\n- **Stats**: Computed on demand via `GET /v1/stats` — tier distribution, error rates, average latency per model, cost savings\r\n- **Privacy**: Only prompt hashes are stored, never raw prompts\r\n\r\nThe system is read-only by design — it observes and reports but never rewrites routing config without user consent.\r\n\r\n## Conversation Context\r\n\r\nThe router maintains a sliding window of the last 5 messages per conversation:\r\n\r\n- Sessions are identified by `x-session-id` header, or hashed from the system prompt\r\n- Short follow-ups (\"yes\", \"do it\", \"ok go ahead\") inherit the previous conversation's tier\r\n- Prevents a \"yes\" after a complex coding discussion from routing to the cheapest model\r\n- LRU cache: max 1000 conversations\r\n\r\n## Routing Profiles\r\n\r\n| Profile | Description |\r\n|---------|-------------|\r\n| `auto` | Balanced cost/quality. Detects agentic tasks and upgrades automatically |\r\n| `eco` | Minimize cost. Favors flash/nano models |\r\n| `premium` | Maximize quality. Favors Claude/GPT-5.x models |\r\n\r\n## Testing\r\n\r\n```bash\r\nnpm test\r\n```\r\n\r\n92 tests covering:\r\n- Word-boundary keyword matching\r\n- Dimension scoring and tier classification\r\n- System prompt de-weighting\r\n- Routing decisions with mock catalogs\r\n- HTTP endpoints (health, models, route, stats)\r\n- Authentication and auth bypass\r\n- Decision logging and stats computation\r\n- Conversation context and follow-up detection\r\n- Context shaping per tier (SIMPLE, MEDIUM, COMPLEX, REASONING)\r\n- Context cache hit/miss behavior\r\n- Extractive summarization and token estimation\r\n- Edge cases (empty messages, single message, multi-part content)\r\n\r\n## Skill\r\n\r\nThis repo includes a reusable OpenClaw skill:\r\n\r\n```\r\nskills/bankr-router/SKILL.md\r\n```\r\n\r\n## Troubleshooting\r\n\r\n| Problem | Solution |\r\n|---------|----------|\r\n| **Unknown model: bankr-router/auto** | Ensure `models.providers` has `bankr-router` and `defaultModel` uses `bankr-router/auto` |\r\n| **Port already in use** | Change `port` in plugin config and update `baseURL` accordingly |\r\n| **Gateway restart loop** | Verify `openclaw.plugin.json` exists at plugin root and `spec` points to repo root |\r\n| **Router bypassed** | Check agent-specific overrides in `models.providers` or `~/.openclaw/agents/<agentId>/agent/models.json` |\r\n| **401 Unauthorized** | Set `BANKR_ROUTER_AUTH_TOKEN` env var or `authToken` in config, then pass `Authorization: Bearer <token>` |\r\n| **429 Too Many Requests** | Rate limited — wait for `Retry-After` seconds or increase `rateLimitPerMinute` |\r\n| **Stale config** | Config is cached for 5s. Modify the file and wait, or restart the server |\r\n\r\n## Contributing\r\n\r\n1. Fork and clone\r\n2. `npm install`\r\n3. Make changes in `src/`\r\n4. `npm run build && npm test`\r\n5. Submit a PR\r\n\r\n## Attribution & Lineage\r\n\r\nOriginally inspired by a routing concept from [TachikomaRed](https://github.com/tachikomared) & **smolemaru**. Darksol reviewed the original codebase and rebuilt it from v1.0.0 onward.\r\n\r\n### v1.0.0 — Built by **Darksol** 🌑\r\n\r\nFull rebuild of the routing engine with production-grade architecture:\r\n\r\n- 15-dimension scoring engine with tier-based routing\r\n- Word-boundary keyword matching (Latin + CJK/Arabic/Cyrillic)\r\n- Multilingual keyword detection (9 languages: EN, ZH, JA, RU, DE, ES, PT, KO, AR)\r\n- System prompt de-weighting (OpenClaw system prompts no longer pollute scores)\r\n- Conversation context awareness with short follow-up detection\r\n- Four routing profiles (auto, eco, premium) + automatic agentic detection\r\n- Self-improving learner with decision logging and stats\r\n- Streaming SSE passthrough\r\n- Structured JSON request logging with rotation (10MB max)\r\n- Stat-based config caching (5s TTL)\r\n- Rate limiting and optional bearer auth\r\n- OpenClaw plugin integration\r\n- 63 tests\r\n\r\n### v1.1.0 — Smart Context Layer\r\n\r\n- Tier-aware context compression (`context-shaper.ts`) — reduces token usage up to 90% for cheap models\r\n- Per-tier strategies: SIMPLE (<2k), MEDIUM (<8k), COMPLEX (<32k), REASONING (passthrough)\r\n- Extractive summarization (first-sentence extraction, code block + URL preservation) — zero LLM calls\r\n- LRU context cache (500 entries) keyed by session + tier + message count\r\n- `X-Router-Context-Shaped` and `X-Router-Context-Ratio` response headers\r\n- `GET /v1/context/stats` endpoint\r\n- Context shaping metrics in learner decision records\r\n- 22 new tests → 85 total\r\n\r\n### v1.2.0 — Resilience & Observability\r\n\r\n- Upstream retry with fallback chain — on 5xx/429/timeout, auto-retries next model in ranked chain\r\n- Configurable request timeout (`upstreamTimeoutMs`, default 60s)\r\n- Enhanced `/health` — uptime, total requests, upstream reachability probe\r\n- Dynamic version from `package.json` (no more hardcoded)\r\n- `X-Router-Version` and `X-Router-Retries` response headers\r\n- Published as `@darksol/bankr-router` on npm\r\n- 7 new tests → 92 total\r\n\r\n## License\r\n\r\nMIT\r\n\r\n---\r\n\r\nBuilt by **Darksol** 🌑. Original concept by TachikomaRed & smolemaru.\r\n","readmeFilename":"README.md"}