Skip to main content

awerouter: Smart LLM Router aweskill companion

Route cheap/fast tasks to Flash, hard decisions to Pro.

Transparent same-protocol proxy that routes coding-agent requests by structural signals — no keyword guessing, no LLM classifier. Speaks Anthropic Messages, OpenAI Chat Completions, and OpenAI Responses.

English · 简体中文

Ko-fi

Version Python License

Status pip Platform Downloads Stars

Transparent proxy that splits coding-agent traffic across providers by cost and capability. Same-protocol passthrough — no translation.

Install

pip install awerouter

Quick Start

# 1. Init config (creates ~/.config/awerouter/{providers,routing}.json)
awerouter init

# 2. Interactively add a profile (writes both files, references stay consistent)
awerouter add
#    or edit by hand: providers.json for keys (${ENV_VAR}), routing.json for flash/pro

# 3. Start the daemon (profile name optional when only one exists)
awerouter serve [cc-router-1]     # shorthand: awerouter cc-router-1

# 4. Point CC at it — the serve banner prints both lines below
export ANTHROPIC_BASE_URL=http://127.0.0.1:20128
# aweswitch profile env: ANTHROPIC_MODEL=auto, _HAIKU_=flash, _OPUS_=pro

Let AI Agent Configure

If you are working in Claude Code, Codex, Cursor, or another coding agent, tell it:

Read https://github.com/mugpeng/awerouter/blob/main/README.ai.md and follow it to install and configure awerouter.

The agent will install the CLI, init config, help you add profiles, and install the awerouter skill via aweskill for ongoing routing management.

After setup, you can tell the agent things like:

"Add a stepfun flash provider and a pro profile." "List my awerouter profiles." "Tune longContextThreshold from my usage." "Explain my usage savings."

The agent can run read-only commands (list, show, config show, usage stats, usage calibrate, usage savings) and edit config, but it will not run awerouter serve — that starts a long-lived daemon. Start the daemon in your own terminal:

awerouter serve cc-router-1

awerouter skill

Install the awerouter skill via aweskill to let AI agents manage routing with natural language:

  • List, inspect, add, and edit routing profiles
  • Edit providers.json (endpoints/auth) and routing.json (strategy) separately
  • Read usage stats / usage calibrate / usage savings and suggest threshold changes
  • Guide environment-variable setup for ${ENV_VAR} auth references

After install, you can tell the agent things like "Add a GLM provider for the openai-chat group", "Raise longContextThreshold to 12000", or "Show me which provider handles my web_search traffic". The agent reads the config, makes changes, and verifies with awerouter config show / awerouter list.

Config

Two files in ~/.config/awerouter/ (override with AWEROUTER_CONFIG_DIR):

providers.json — endpoints + keys, grouped by wire protocol (redacted in config show):

{
  "anthropic": {
    "stepfun":   { "base_url": "https://api.stepfun.com/step_plan", "auth": "${STEPFUN_AUTH_TOKEN}" },
    "anthropic": { "base_url": "https://api.anthropic.com",          "auth": "${ANTHROPIC_KEY}" }
  },
  "openai-chat": {
    "stepfun": { "base_url": "https://api.stepfun.com/step_plan/v1", "auth": "${STEPFUN_AUTH_TOKEN}" }
  },
  "openai-responses": {
    "openai": { "base_url": "https://api.openai.com/v1", "auth": "${OPENAI_API_KEY}" }
  }
}

Three protocols are supported. base_url uses each native client's convention — copy it verbatim from your client config; awerouter appends the endpoint path the same way the native client would:

Protocol id base_url style Endpoint
anthropic ANTHROPIC_BASE_URL (no /v1) base_url + /v1/messages
openai-chat OPENAI_BASE_URL (includes version segment) base_url + /chat/completions
openai-responses OPENAI_BASE_URL (includes version segment) base_url + /responses

The same provider often uses a different path per protocol — GLM for instance: https://open.bigmodel.cn/api/coding/paas/v4 for chat completions but https://open.bigmodel.cn/api/v1 for responses. That's why each protocol group carries its own base_url.

The auth header is auto-detected from base_url: anthropic.comx-api-key (bare token); everyone else → Authorization (auto-prefixes Bearer ). No auth_header field needed unless the heuristic is wrong.

routing.json — strategy, no secrets (safe to commit):

{
  "settings": {
    "backgroundModel": "flash",
    "thinkModel": "pro",
    "webSearchModel": "pro"
  },
  "cc-router-1": {
    "protocol": "anthropic",
    "longContextThreshold": 8000,
    "destinations": {
      "flash": "stepfun,step-3.7-flash",
      "pro":   "anthropic,claude-opus-5"
    }
  }
}

settings is optional (defaults: flash/pro). It maps the model ids CC sends for the background (Haiku) and think (Opus) tiers, plus the webSearchModel destination for L1 web_search traffic (default pro). The main loop uses auto — routed by difficulty by L3. Set these in your aweswitch profile: ANTHROPIC_DEFAULT_HAIKU_MODEL=flash, ANTHROPIC_MODEL=auto, ANTHROPIC_DEFAULT_OPUS_MODEL=pro.

Keys reference ${ENV_VAR} syntax. Missing env vars die with a clear message at startup.

Profile-based routing: routing.json groups configs under profile ids (like aweswitch). awerouter serve <profile> starts one; with a single profile it auto-selects. protocol maps the profile to a providers.json group and decides which endpoint it serves — the serve banner prints the matching client env (ANTHROPIC_BASE_URL for Claude Code, OPENAI_BASE_URL / Codex wire_api for the openai protocols). Note: openai clients are single-model, so L2 tier labels effectively never fire for them — openai traffic routes by L1 + L3 with a flash default.

How It Routes

Three-layer first-match-wins pipeline, evaluated per request:

Layer Signal Decision
L1 Capability web_search tool in body settings.webSearchModel (default pro)
L2 Tier label model == c1/flash or c1/think flash / pro respectively
L3 Difficulty token count > threshold, or has image pro; else flash

CC's /model picker sets the tier model id (c1/flash / c1/pro / c1/think). awerouter reads it and routes accordingly — no keyword parsing, no LLM classifier.

Commands

awerouter init                        # create default config (= config init)
awerouter add                         # interactively add a profile (and new providers)
awerouter list                        # list profiles (name, protocol, flash, pro, threshold)
awerouter show [PROFILE]              # show one profile or all config (redacted)
awerouter serve [PROFILE] [--port 20128] [--host 127.0.0.1]
awerouter <PROFILE>                   # shorthand for serve PROFILE
awerouter config path | show | edit | init
awerouter usage [--since 7d] [--profile NAME]     # stats summary (default view)
awerouter usage stats [--clean]
awerouter usage tail [--lines 20]
awerouter usage calibrate
awerouter usage savings

All usage subcommands read the same request log; window options sit between usage and the subcommand (awerouter usage --since today savings).

usage stats aggregates the log per profile: label/destination/provider/model breakdowns with percentages, error and fallback counts, latency percentiles (first byte and total) per destination/provider/model, and estimated message tokens. --since accepts today, yesterday, 7d, or YYYY-MM-DD (local time); --profile restricts to one profile; --clean deletes the saved logs after a confirmation prompt. usage tail shows recent entries verbatim.

usage calibrate shows the message-token distribution of L3 traffic (the threshold-sensitive layer; messages only — system prompt and tools are excluded) and suggests candidate longContextThreshold values at p90/p95/p99. Run it after some real traffic, then edit routing.json.

usage savings is the token accounting view: how many message-input tokens each tier consumed and how many pro input tokens routing offloaded to flash vs a pro-only baseline. A cache-sensitivity section brackets the offload between "all cache reads" and "all full price" (Anthropic-style ~0.1x read / 1.25x write / 5-min TTL) and shows your switch cadence vs the TTL — a cache-warm pro-only baseline would have billed those tokens at cache-read prices. The output ends with ready-to-fill formulas using the measured token counts — substitute your providers' input prices (per 1M tokens) and read off the saved amount (output tokens, flash-side caching, and capability-mismatch turns are not modeled).

Troubleshooting

CC shows 502 status code (no body) right after launch — a shell proxy (Clash etc.) is hijacking loopback traffic. Requests to 127.0.0.1:20128 go into the proxy, whose 127.0.0.1 is itself, so nothing is listening and the proxy returns an empty 502. serve prints a warning when it detects this; fix it by exempting loopback in your shell config:

export no_proxy=127.0.0.1,localhost NO_PROXY=127.0.0.1,localhost

Then open a new terminal and relaunch CC.

Development

git clone https://github.com/mugpeng/awerouter
cd awerouter
pip install -e ".[dev]"
pytest

See docs/CONTRIBUTING.md for architecture notes, config semantics, and the release process.

Support

If awerouter saves you money, consider supporting it:

  • ⭐ Star the repo — it helps others find it.
  • Ko-fi — buy me a coffee.
  • 💬 WeChat — scan the QR code below.

WeChat Pay

awerouter is free and open source. Sponsors keep it maintained — thank you.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

awerouter-0.3.0.tar.gz (172.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

awerouter-0.3.0-py3-none-any.whl (33.6 kB view details)

Uploaded Python 3

File details

Details for the file awerouter-0.3.0.tar.gz.

File metadata

  • Download URL: awerouter-0.3.0.tar.gz
  • Upload date:
  • Size: 172.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.15

File hashes

Hashes for awerouter-0.3.0.tar.gz
Algorithm Hash digest
SHA256 20d0291bd1d9c60e20ae2110f5251aa88ef38a53f5158f969e62ed09a5ea1694
MD5 7e82161b303e005c3c6b4775ee5628bb
BLAKE2b-256 2069966ce25f53243b3a87b73693edcd7f0350f94b4f2d47e4883463142f4839

See more details on using hashes here.

File details

Details for the file awerouter-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: awerouter-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 33.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.15

File hashes

Hashes for awerouter-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3045d3623c82b85b9883769ce2c5cc4d29baea8a7cf8e0a5483e063d51d023a1
MD5 e50605665eb93abc68ecd43b59d4ab52
BLAKE2b-256 ab5a9035d235d7ae3cf566c59be3a800e4d5050d4953ee31bc6ce400b7b6961d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page