ModelDispatcher
A reusable internal Python library that acts as a resilient AI Model Gateway/Router shared across applications.
Status: working library + demo. The core runs end-to-end (routing, fallback, quota, agent loop, onboarding), ships real OpenAI/Anthropic adapters, is covered by a behavioral test suite, and has an interactive FastAPI + React demo. See
ARCHITECTURE.mdfor the design anddemo/to run it in a browser.
What it does
- Strategy providers — every model backend implements one
ModelProviderinterface, so providers are hot-swappable. - Chain-of-Responsibility fallback — rate limits and exhaustion are intercepted and the request transparently escalates to the next candidate model.
- Native agent orchestration — a small, dependency-free tool-calling loop with explicit state management (no heavy agent framework).
- Triage & cost routing — cheap/free models for simple work, premium models reserved for complex reasoning.
- Token-aware multi-tenant quotas — pre-flight reservation + post-call reconciliation per tenant.
- Secure proxy perimeter — inbound validation and a credential-precedence chain.
- Two-stage onboarding — zero-setup free tier by default; when limits are hit,
a structured
402/429handoff payload drives a GUI key wizard.
Install
pip install "model-dispatcher[openai,anthropic,gemini]"
Each provider adapter is an optional extra — install only the ones you key. Not yet published to PyPI (or need a version ahead of the latest tag)? Pin to a git ref instead:
pip install "model-dispatcher[openai] @ git+https://github.com/joka-7/ModelDispatcher@v0.2.0"
The TypeScript client (@joka-7/modeldispatcher-client) is published to
GitHub Packages — see clients/typescript. It talks to
your own backend, which is what runs the Python gateway above.
For an app with no backend at all — a pure browser app doing
bring-your-own-key calls straight to a provider — see
clients/browser-agent
(@joka-7/modeldispatcher-browser-agent) instead: the same multi-provider
idea (Gemini/OpenAI/Anthropic/Groq/Ollama), running client-side with no
server and no vendor SDK required.
Quickstart
No API keys needed — this uses the keyless MockProvider:
pip install -e . # from a clone of this repo
python examples/basic_agent.py
from model_dispatcher import (
CompletionRequest, Message, ModelGateway, ProviderRegistry,
Role, TenantContext, TenantId, TenantQuota,
)
from model_dispatcher.providers import MockProvider # swap for OpenAIProvider, etc.
providers = ProviderRegistry()
providers.register(MockProvider("mock:free"))
gateway = ModelGateway.create(providers) # build once at startup
tenant = TenantContext(
tenant_id=TenantId("demo-user"),
quota=TenantQuota(requests_per_min=20, tokens_per_min=40_000, tokens_per_day=1_000_000),
)
request = CompletionRequest(
messages=(Message(role=Role.USER, content="Hello!"),),
tenant=tenant.tenant_id,
)
result = gateway.dispatch(request, tenant)
print(result.final_message.content)
See examples/basic_agent.py for the full
version with a tool the agent calls on its own.
Using it from another app
docs/USAGE.md is the integration guide: installing
into a Python backend, wiring the TypeScript client to a frontend, mapping
gateway errors onto HTTP responses, and pinning versions across multiple
consuming repos.
Layout
See ARCHITECTURE.md for the directory layout, class
blueprints, and algorithmic flows.
Development
pip install -e ".[dev]"
ruff check src tests
mypy --strict src
pytest
Requires Python >= 3.11.
Try it in a browser
docker build -t model-dispatcher-demo .
docker run --rm -p 8000:8000 model-dispatcher-demo # http://localhost:8000
The demo drives the real gateway through keyless mock providers, so you can watch
routing, fallback, quota meters, and the key-wizard handoff without any API keys.
See demo/README.md for the two-process dev setup.
Release files for model-dispatcher 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| model_dispatcher-0.3.0.tar.gz | 190.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| model_dispatcher-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 258.1 kB
Release files / model_dispatcher-0.3.0.tar.gz
| Download URL | model_dispatcher-0.3.0.tar.gz |
|---|---|
| Size | 190.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
706596c2de11903acdb5e862e1c98d62a61a323d0cfeb5fbfa28e686ec6009cf
|
|
BLAKE2b-256 checksum How to use checksums |
916b6bb5c5c7252cef39548cbc603646e01d997e5d406dabbe1ddfcf952e49a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency logRelease files / model_dispatcher-0.3.0-py3-none-any.whl
| Download URL | model_dispatcher-0.3.0-py3-none-any.whl |
|---|---|
| Size | 67.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ad42c6f931b90579d8b2bc909dd8ea4fc9d71399fadf55117cdc275b6f09d340
|
|
BLAKE2b-256 checksum How to use checksums |
d7432bd8eca710a58acca751a0a641958f3662ba76e67dc4b566d9b12ff4596c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency log