llm-router
Ecosystem role and current integration status: component roadmap. The public cross-repository plan is owned by the Agentic Security Harness ecosystem roadmap.
A tiny, dependency-light async LLM router with role tiers and per-call cost logging.
One call() interface for the tested OpenAI-compatible request shape and a
separate Yandex AI Studio path. Provider compatibility depends on each endpoint's
current API contract and must be verified before use.
The public library demonstrates a cheap-to-chief routing pattern with offline tests. It does not publish or verify a production deployment claim. No SDKs or models are hardcoded in the routing logic.
The repository now publishes a source-owned, offline invocation-receipt contract and is
therefore contract_only in the ecosystem. Its source tree builds the unique distribution
candidate agentic-llm-router==0.2.0, imported as llm_router. It is not yet published or
automatically activated by Harness.
Supply-chain boundary: the generic PyPI name
llm-routerbelongs to another project. Do not install or declare that coordinate for this repository. The only planned public distribution coordinate isagentic-llm-router.
Why
In agentic systems most LLM calls are cheap bulk work (extract, classify, filter) and a few are high-stakes (the final decision). Paying flagship prices for everything is wasteful; juggling provider SDKs is annoying. llm-router gives you:
- Role tiers —
cheap/mid/chief/audit, each mapped to a model via env. Route volume tocheap, escalate only candidates tochief. - Provider flexibility — a custom
OPENAI_BASE_URLcan target endpoints that implement the tested request/response contract; Yandex AI Studio has a separate path. Provider identity, terms, availability, and exact compatibility are external gates. - Per-call cost — every call returns token counts and cost in USD + a configurable local currency (set
LLM_FX/LLM_CCY). Aggregate the dicts to a budget log. - Budget helpers — aggregate usage records, check a daily cap, and estimate savings
versus sending the same tokens to the
chiefmodel. - Resilience — retries on
429/5xxwith exponential backoff. - Canonical receipt contract — strict, digest-bound attempt, usage, pricing, and FX evidence without credentials, endpoints, prompts, output text, response bodies, or exception messages.
Features
- Single
async call(role, system, user) -> (text | None, usage)interface. - Four configurable role tiers, models set per provider via env.
- OpenAI-compatible and Yandex AI Studio providers.
json_mode=True→ addsresponse_format={"type":"json_object"}(OpenAI-compatible).- Cost estimation from an override-able price table (
LLM_PRICE_<MODEL>_IN/OUT_USD_PER_1M). - Budget helpers for logs you own:
summarize_usage,budget_status, andbuild_savings_report. - Zero secrets cached at import — all config read live from env.
- ~150 LOC, one runtime dependency (
aiohttp).
Install
git clone https://github.com/krivonosoff161/llm-router
cd llm-router
python -m build
python -m pip install dist/agentic_llm_router-0.2.0-py3-none-any.whl
For editable development use python -m pip install -e .[dev]. Requires Python 3.9+.
CI builds and installs the exact wheel on Linux and Windows. Harness main declares a
source-only router extra using the unique agentic-llm-router distribution name, but
this package is not on PyPI and published Harness v1.3.0 metadata does not contain that
extra. Public pip install agentic-security-harness[router] support is therefore
unavailable; package publication and newer Harness package metadata remain separate release gates.
Quickstart
import asyncio
from llm_router import call
async def main():
text, usage = await call("cheap", "You are concise.", "Name 3 primary colors.")
print(text)
print(usage) # {provider, model, role, input_tokens, output_tokens,
# total_tokens, cost_usd, cost_local, currency}
asyncio.run(main())
Set at least a provider + key first (see Configuration). For OpenAI:
export OPENAI_API_KEY=sk-...
Providers
| Provider | Set | Auth |
|---|---|---|
| OpenAI | LLM_PROVIDER=openai (default), OPENAI_API_KEY |
Bearer |
| Alibaba Qwen | OPENAI_BASE_URL=<dashscope compatible-mode/v1> + OPENAI_API_KEY |
Bearer |
| OpenRouter / Together / Ollama / vLLM | OPENAI_BASE_URL=<their /v1> + OPENAI_API_KEY |
Bearer |
| Yandex AI Studio | LLM_PROVIDER=yandex, YANDEX_API_KEY, YANDEX_FOLDER_ID |
Api-Key |
The base URL must NOT include
/chat/completions— the router appends it. Yandex requiresYANDEX_FOLDER_ID(or an explicitYANDEX_<ROLE>_MODEL); otherwisemodel_forraises a clear configuration error (fail-fast) instead of sending an empty model.
Roles
from llm_router import call, model_for
model_for("cheap") # -> e.g. "gpt-4o-mini" (or your LLM_CHEAP_MODEL)
model_for("chief") # -> e.g. "gpt-4o"
# pattern: cheap for volume, chief only when it matters
facts, u1 = await call("cheap", EXTRACT_PROMPT, raw_text)
if looks_important(facts):
verdict, u2 = await call("chief", DECIDE_PROMPT, facts, json_mode=True)
Cost logging
text, usage = await call("cheap", sys, user)
# usage["cost_usd"] -> e.g. 0.0001
# usage["cost_local"] -> cost_usd * LLM_FX
# usage["currency"] -> LLM_CCY (e.g. "RUB")
Append each usage to a JSONL file and you have a per-call budget log. Prices come from a small built-in table and are illustrative — override per model:
export LLM_PRICE_GPT_4O_MINI_IN_USD_PER_1M=0.15
export LLM_PRICE_GPT_4O_MINI_OUT_USD_PER_1M=0.60
Summarize a batch of usage records:
from llm_router import summarize_usage, budget_status, build_savings_report
usages = [u1, u2] # dicts returned by call()
print(summarize_usage(usages).as_dict())
print(budget_status(usages, limit_usd=1.00).as_dict())
print(build_savings_report(usages, counterfactual_role="chief").as_dict())
LLM_BUDGET_USD_DAY can be used as a default budget cap for budget_status(...).
The router stays stateless; you decide where the JSONL budget log lives.
Canonical invocation receipts
router-invocation-receipt-v1.0 is a separate offline
interchange surface for already-observed sanitized values. It uses canonical UTF-8 JSON,
domain-separated content identities, contiguous attempt accounting, strict token totals,
and integer nano-unit cost arithmetic. Pricing and FX inputs bind caller-supplied source
artifact digests; those digests are evidence references, not authenticity proofs.
The receipt builder never calls a provider and the existing call() return value is
unchanged. A receipt contains digests of request, response, output, model, and producer
identity—not their raw bytes. It always declares invoice_authoritative=false and
operational_authority=none.
Deterministic hashes are content-minimizing, not anonymizing: they remain linkable and can be guessed when the source space is small. A receipt is not automatically safe to publish.
from llm_router import InvocationAttemptV1
attempt = InvocationAttemptV1(
attempt_index=1,
outcome="network_error",
http_status=None,
reason_code="provider.network_error",
response_payload_sha256=None,
)
# Supply only already-observed sanitized values; see docs/invocation-receipt.md.
Configuration (env)
| Variable | Default | Purpose |
|---|---|---|
LLM_PROVIDER |
openai |
openai (compatible) or yandex |
OPENAI_API_KEY |
— | key for the OpenAI-compatible endpoint |
OPENAI_BASE_URL |
https://api.openai.com/v1 |
point at Alibaba/OpenRouter/Ollama/... |
LLM_CHEAP_MODEL / LLM_MID_MODEL / LLM_CHIEF_MODEL / LLM_AUDIT_MODEL |
gpt-4o-mini / gpt-4o-mini / gpt-4o / gpt-4o | role → model |
YANDEX_API_KEY, YANDEX_FOLDER_ID |
— | Yandex AI Studio |
YANDEX_<ROLE>_MODEL |
wraps gpt://<folder>/<name>/latest |
override a Yandex role model URI |
LLM_FX |
1.0 |
USD → local currency multiplier |
LLM_CCY |
USD |
local currency label |
LLM_DEFAULT_TIMEOUT |
60 |
per-call timeout (s) |
LLM_MAX_RETRIES |
2 |
retries on 429/5xx |
LLM_PRICE_<MODEL>_IN/OUT_USD_PER_1M |
from table | override price per model |
LLM_BUDGET_USD_DAY |
unset | optional cap used by budget helpers |
See .env.example.
Examples & tests
python examples/basic.py # one call
python examples/role_tiers.py # cheap vs chief + cost
python -m pytest -q # offline unit tests (no network)
What each example shows and what it does not prove: examples/README.md.
Docs
- Component roadmap — source-owned ecosystem role, platform evidence, historical projections, and integration gates.
- Project map — modules, what exists today vs not included, reviewer checklist.
- Use cases — who this is for, practical workflows, limitations.
- Operating model — role budgets, usage records, escalation gates, and residual risk.
- Invocation receipt V1 — canonical codec, attempt state machine, fixed-point arithmetic, privacy boundary, and non-claims.
- Harness ecosystem roadmap — the canonical public ordering for cross-repository integration work.
Limitations / non-goals
- Chat completions only (no streaming, embeddings, tools/function-calling, vision — kept intentionally small).
- One system + one user message per call (no multi-turn history helper).
- The price table is illustrative; confirm real prices with your provider.
- Not a full framework — it's a focused routing + cost-logging utility you drop into your own agent loop.
- Not the portfolio flagship, policy authority, or security boundary. Larger systems own their own validation, authorization, storage, and safety rules.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agentic_llm_router-0.2.0.tar.gz.
File metadata
- Download URL: agentic_llm_router-0.2.0.tar.gz
- Upload date:
- Size: 25.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1a73bd38ff8e35b5892e5f6d9e0c1230bfe50ae1d6eaa7829d9ef75ad22f8f6
|
|
| MD5 |
14d1c924aa41e8e2cfd8537c7b12f785
|
|
| BLAKE2b-256 |
55eaf382f3b788aa42cc60befcc5625e2632050708631d3dd66bad803fe5a5ad
|
Provenance
The following attestation bundles were made for agentic_llm_router-0.2.0.tar.gz:
Publisher:
release-package.yml on krivonosoff161/llm-router
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentic_llm_router-0.2.0.tar.gz -
Subject digest:
f1a73bd38ff8e35b5892e5f6d9e0c1230bfe50ae1d6eaa7829d9ef75ad22f8f6 - Sigstore transparency entry: 2640099537
- Sigstore integration time:
-
Permalink:
krivonosoff161/llm-router@f5d999aebea1c53b79ae20736684a3cbbb77b4f6 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/krivonosoff161
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-package.yml@f5d999aebea1c53b79ae20736684a3cbbb77b4f6 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file agentic_llm_router-0.2.0-py3-none-any.whl.
File metadata
- Download URL: agentic_llm_router-0.2.0-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
231f7ca654b09cc6220291a6f219f42380a99fd1759ba63dea12c6258822d124
|
|
| MD5 |
1492ce1ce73689d938a3f9b59c57cd11
|
|
| BLAKE2b-256 |
ae29400a3ed8e4f9cbc27e0bfcaa6a40bb455b2c608fbf165ca31f08c46a113e
|
Provenance
The following attestation bundles were made for agentic_llm_router-0.2.0-py3-none-any.whl:
Publisher:
release-package.yml on krivonosoff161/llm-router
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentic_llm_router-0.2.0-py3-none-any.whl -
Subject digest:
231f7ca654b09cc6220291a6f219f42380a99fd1759ba63dea12c6258822d124 - Sigstore transparency entry: 2640099562
- Sigstore integration time:
-
Permalink:
krivonosoff161/llm-router@f5d999aebea1c53b79ae20736684a3cbbb77b4f6 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/krivonosoff161
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-package.yml@f5d999aebea1c53b79ae20736684a3cbbb77b4f6 -
Trigger Event:
workflow_dispatch
-
Statement type: