@ahwanulm/amrouter
v1.2.3
Published
Unified AI router with 160+ providers, RTK+Caveman compression, auto fallback, MCP/A2A, desktop, PWA, and OpenAI-compatible APIs.
Downloads
105
Maintainers
Readme
AmRouter
Unified AI Router — One endpoint, 160+ providers, automatic fallback.
Website · Documentation · Contributing · Changelog · Security
Overview
AmRouter is a self-hosted AI gateway that unifies access to 160+ LLM providers (OpenAI, Anthropic, Google, Groq, Mistral, local models, and more) behind a single OpenAI-compatible API. It ships with intelligent routing, automatic failover, request caching, rate limiting, and a full-featured management dashboard — all in a single Next.js application.
Point your existing SDKs at AmRouter and stop worrying about which provider is down, rate-limited, or most cost-effective for the current request.
Acknowledgment. AmRouter builds on the foundations of the earlier OmniRoute project. It is a refinement — consolidating the core routing engine, hardening the resilience model, and extending provider coverage, MCP/A2A tooling, and the management dashboard. Credit to the original OmniRoute authors for the groundwork that made this possible.
Key Features
- Drop-in OpenAI compatibility — works with the OpenAI SDK, Cursor, Cline, Codex, and any OpenAI-compatible client
- Multi-protocol translation — bidirectional conversion between OpenAI, Anthropic Claude, and Google Gemini request/response formats
- Responses API transformer — seamlessly converts between the Responses API and Chat Completions formats
- 13 routing strategies — priority, weighted, round-robin, P2C, cost-optimized, context-optimized, LKGP, auto, and more
- Resilience runtime — per-provider circuit breakers, per-connection cooldowns, and per-model lockouts with lazy recovery
- RTK + Caveman compression — aggressive payload compression for faster responses and lower egress
- MCP server built in — 29 tools across 10 scopes, served over 3 transports (stdio, HTTP, SSE)
- A2A agent protocol — JSON-RPC 2.0 agent-to-agent server with a pluggable skill registry
- Persistent memory — conversational memory layer you can reuse across sessions
- Management dashboard — usage analytics, key management, provider health, request inspector, and live logs
- OAuth token refresh — background scheduler keeps OAuth-based providers authenticated automatically
- Desktop app — Electron build targets for Windows, macOS, and Linux
- Secure by default — AES-256-GCM credential encryption, Zod-validated inputs, strict upstream header denylist
Quick Start
Prerequisites
- Node.js
>=20.20.2 <21,>=22.22.2 <23, or>=24 <27 - npm 10+
Install from npm
npm install -g @ahwanulm/amrouterRun
amrouter # start the server (opens the dashboard automatically)
amrouter --no-open # start without opening the browser
amrouter --headless # run quietly in the background (no interactive menu)
amrouter --port 20128 # use a custom port
amrouter --verbose # show full server logsThen open http://localhost:20128 and sign in with the initial password printed in your terminal on first boot.
Everyday commands
amrouter doctor # quick health check
amrouter providers available # list supported providers
amrouter providers list # list configured providers
amrouter setup # interactive guided setup
amrouter update # check npm for a newer version and install it
amrouter uninstall --force # remove the local data directory (npm uninstall step is printed next)
amrouter-reset-password # reset the admin password
amrouter --help # full help
amrouter --version # show installed versionConfiguration
AmRouter reads environment variables from ~/.amrouter/.env (auto-created from .env.example on first run). For production, generate strong secrets before first boot:
openssl rand -base64 48 # JWT_SECRET
openssl rand -hex 32 # API_KEY_SECRETAdd them to ~/.amrouter/.env, then start amrouter.
Usage Example
AmRouter exposes an OpenAI-compatible endpoint. Any OpenAI SDK works unchanged — just swap the base URL.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "http://localhost:20128/v1",
apiKey: "amr_your_key_here",
});
const response = await client.chat.completions.create({
model: "gpt-4o-mini", // or a combo id, e.g. "combo:my-fallback"
messages: [{ role: "user", content: "Hello!" }],
stream: true,
});
for await (const chunk of response) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}Architecture
Client
│
▼
/v1/chat/completions ─ CORS ─ Zod ─ Auth ─ Policy ─ Injection guard
│
▼
handleChatCore() ─ cache ─ rate-limit ─ combo routing?
│
▼
resolveComboTargets() → handleSingleModel() per target
│
▼
translateRequest() → getExecutor() → executor.execute()
│ │
│ ▼
│ fetch() upstream + retry/backoff
▼
response translation → SSE stream or JSON
│
▼
Responses API transformer (when applicable)| Layer | Location | Purpose |
| ------------- | ----------------------- | ------------------------------------------ |
| API routes | src/app/api/v1/ | Next.js App Router entry points |
| Handlers | open-sse/handlers/ | Request processing (chat, embeddings, etc) |
| Executors | open-sse/executors/ | Provider-specific HTTP dispatch |
| Translators | open-sse/translator/ | OpenAI ↔ Claude ↔ Gemini format conversion |
| Transformer | open-sse/transformer/ | Responses API ↔ Chat Completions |
| Services | open-sse/services/ | Combo routing, rate limits, caching |
| Database | src/lib/db/ | 22 SQLite domain modules (WAL) |
| Domain/Policy | src/domain/ | Policy engine, cost rules, fallback logic |
| MCP server | open-sse/mcp-server/ | 29 tools, 3 transports, 10 scopes |
| A2A server | src/lib/a2a/ | JSON-RPC 2.0 agent protocol |
| Skills | src/lib/skills/ | Extensible skill framework |
| Memory | src/lib/memory/ | Persistent conversational memory |
Monorepo layout: src/ (Next.js 16 app), open-sse/ (streaming engine workspace), electron/ (desktop), tests/, bin/ (CLI).
For a deep architectural tour, see AGENTS.md and CLAUDE.md.
Resilience Model
AmRouter has three independent failure-isolation layers so one bad key or one bad model never takes down a whole provider:
| Mechanism | Scope | Example trigger |
| ----------------------- | ------------------------------ | ------------------------- |
| Circuit breaker | Whole provider (e.g. openai) | Repeated 5xx / timeout |
| Connection cooldown | One account / API key | Single key hits 429 |
| Model lockout | Provider + connection + model | Per-model quota exhausted |
All three use lazy recovery — expired states self-refresh on read, so dashboards and combo candidate builders always reflect reality.
Scripts
| Command | What it does |
| ------------------------ | ---------------------------------------------- |
| npm run dev | Dev server at http://localhost:20128 |
| npm run build | Production build (Next.js standalone) |
| npm run start | Start the production server |
| npm run lint | ESLint across the repo |
| npm run typecheck:core | TypeScript check |
| npm run test | Unit tests (Node.js native runner) |
| npm run test:coverage | Unit tests with 60% coverage gate |
| npm run test:vitest | MCP / autoCombo / cache suites |
| npm run test:e2e | Playwright end-to-end tests |
| npm run test:all | Full test matrix |
| npm run check | lint + test |
| npm run check:cycles | Detect circular dependencies |
| npm run electron:dev | Run dev server + Electron shell |
| npm run electron:build | Build the desktop app for the current platform |
Testing
| Suite | Command |
| ------------------------ | -------------------------------------------------------- |
| Unit (all) | npm run test:unit |
| Single file | node --import tsx/esm --test tests/unit/<file>.test.ts |
| Vitest (MCP, autoCombo) | npm run test:vitest |
| Integration | npm run test:integration |
| E2E (Playwright) | npm run test:e2e |
| Protocol E2E (MCP + A2A) | npm run test:protocols:e2e |
| Ecosystem | npm run test:ecosystem |
| Coverage gate (≥60%) | npm run test:coverage |
Any PR changing production code in src/, open-sse/, electron/, or bin/ must include or update tests.
Configuration
Core environment variables (see .env.example for the full list):
| Variable | Description |
| ------------------ | ----------------------------------------------- |
| PORT | Server port (default 20128) |
| DATA_DIR | Data + SQLite location (default ~/.amrouter/) |
| JWT_SECRET | Dashboard session signing secret |
| API_KEY_SECRET | AES-256-GCM key for credential encryption |
| INITIAL_PASSWORD | First-run admin password |
| REQUIRE_API_KEY | Require clients to pass an AmRouter key |
| APP_LOG_LEVEL | trace · debug · info · warn · error |
Deployment
- Docker —
docker compose up -d(seedocker-compose.ymlanddocker-compose.prod.yml) - Fly.io — ready-made
fly.tomlincluded - Standalone Node —
npm run build && npm run start - Desktop (Electron) —
npm run electron:build:{win,mac,linux}
Protocols
- OpenAI-compatible REST — Chat Completions, Responses, Embeddings, Models, Files
- Anthropic Messages — native
/v1/messagessurface with translation - Gemini
generateContent— accepted and translated - MCP (Model Context Protocol) — 29 tools across 10 scopes, over stdio / HTTP / SSE
- A2A (Agent-to-Agent) — JSON-RPC 2.0 with a DB-backed skill registry
Security
- No
eval()/new Function()/ implied eval — enforced by ESLint - All inputs validated with Zod schemas
- Credentials encrypted at rest (AES-256-GCM)
- Strict upstream header denylist (
src/shared/constants/upstreamHeaders.ts) - OAuth tokens refreshed by a background scheduler
Found a vulnerability? See SECURITY.md.
Contributing
We welcome pull requests. Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md first.
Branch naming: feat/…, fix/…, refactor/…, docs/…, test/…, chore/…
Commit style: Conventional Commits — e.g. feat(db): add circuit breaker
Husky enforces lint-staged, doc-sync, and an any budget on pre-commit, plus unit tests on pre-push.
License
MIT © 2026 diegosouzapw, ahwanulm
