# OpenSmartRoute documentation > OpenSmartRoute is an open-source router that sits between your team, your apps and the AI models they use. For every request it picks the most cost-effective model, agent or tool that meets your quality rules, keeps personal data and secrets out of the prompt before it is sent, and shows why it chose what it did. Upload last month's bill and see what you would have saved. Every published page of https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs as Markdown, in reading order. The short index is https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/llms.txt. ---

OpenSmartRoute

# OpenSmartRoute > **An open, intelligent route to the right decision, solution, or destination.**

Release PyPI Python 3.10+ Container image License: Apache-2.0 Typed Zero runtime dependencies Coverage >= 89%

OpenSmartRoute is an open-source **AI decision control plane**. For each request it picks the best **LLM, agent harness, skill, persona, tool, workflow or human**, honours hard constraints (privacy, region, budget, latency), explains the choice, executes the resulting plan and **learns from every outcome**. The core is pure Python with zero runtime dependencies. ```mermaid flowchart LR R([request]) --> G["guard
redact PII"] G --> S["signals
< 1 ms"] S --> P["policy
hard constraints"] P --> ST["strategies + ensemble utility
rules, capability, similarity, bandit, LLM judge"] ST --> D["decision
trace + plan"] D --> X["execute
compact prompt, persona -> skill -> model + tools / agent / tool / human"] X -. outcomes .-> ST ``` ## Why - **Everything is a route target.** One `RouteTarget` contract for models, agent harnesses, SKILL.md packages, personas, MCP tools, workflows and human queues; one policy layer; one learning loop. - **Plans, not just picks.** `route(plan=True)` composes persona, skill, model and the tools the model may call; `run()` executes the plan - tool calls the model makes to offered tools included - and records an `Outcome` per participant. An instructions-only skill or persona runs on the plan's model with its body disclosed in the system prompt. - **Fewer tokens before the call.** `estimate()` quotes tokens, cost, latency and quality per candidate (calibrated against billed tokens), and every model call is compacted first - whitespace, repeated log lines and stale history go, code and words stay - with the saving reported as `tokens_saved`. - **Keeps itself current.** A running router follows the marketplace (new skills and tools land in the catalogue on a schedule), the self-improvement loop reads vendor blogs and release feeds for new models, and IDEs reach the marketplace through the local MCP server. - **Constraints are never traded off.** PII, data boundary, region, tenant, cost and latency SLOs are filtered before any score is computed, with the rejection reason in the trace. Redacted PII is restored only for targets allowed to hold it; every other target, and every log, sees placeholders. - **Learns in production.** Thompson bandits, Item Response Theory, Bradley-Terry preferences, LinUCB, Markov lookahead, task-level credit assignment, drift detection and forgetting. - **Honest evaluation.** Baselines, oracle, label-noise floor, paraphrase robustness, calibration (ECE, Brier, conformal sets), off-policy estimators, public benchmark presets. - **Secure by design.** Learned and heuristic guards against rerouting gadgets and prompt injection, PII redaction, resource limits, signed MCP manifests, encrypted state, hash-chained audit. - **Enterprise-ready.** Builder, middleware, telemetry / state / audit ports, Redis and SQL stores, shadow and A/B routing with SPRT, tenant fair share, async facade, container image and Helm chart. ## Install The `osr` command line and the Python package ship together. On Linux and macOS: ```bash curl -LsSf https://opensmartroute.ai/install.sh | sh ``` On Windows (PowerShell): ```powershell powershell -ExecutionPolicy ByPass -c "irm https://opensmartroute.ai/install.ps1 | iex" ``` The installer puts `osr` in an isolated environment (uv, pipx or a private venv - whichever is available, never the system Python) and adds it to your PATH. `OSR_VERSION=2.1.0` pins a release, `OSR_EXTRAS=all` installs every optional dependency, `OSR_INSTALLER=uv|pipx|venv` forces a backend and `OSR_NO_MODIFY_PATH=1` leaves your shell configuration alone. The scripts are install.sh (`install.sh`) and install.ps1 (`install.ps1`) in this repository and in the `dist` artifact of every release pipeline run. If you already manage Python tools yourself: ```bash uv tool install 'opensmartroute[yaml,server]' # or: pipx install 'opensmartroute[yaml,server]' pip install opensmartroute # library only, zero runtime dependencies pip install 'opensmartroute[yaml]' # + YAML catalogues and rules pip install 'opensmartroute[server]' # + FastAPI server and OpenAI-compatible proxy pip install 'opensmartroute[embeddings]' # + sentence-transformers similarity pip install 'opensmartroute[fast]' # + numpy-accelerated SLM training (pure Python otherwise) pip install 'opensmartroute[tiktoken]' # + exact OpenAI tokenisation for estimates pip install 'opensmartroute[otel]' # + OpenTelemetry telemetry pip install 'opensmartroute[crypto]' # + AES-GCM encrypted state pip install 'opensmartroute[tensorflow]' # + Keras token-count and routing-head models (large; not in `all`) pip install 'opensmartroute[all]' # everything above except tensorflow (+ the dev tools) ``` `osr doctor` reports what the installation has: interpreter, package, extras, the bundled routing model, the sign-in and (with `--targets`) whether a catalogue loads. Container image: `crosrua2c6onyidguw.azurecr.io/opensmartroute:` ([deploy/README.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/deploy.md)). From a checkout: `pip install -e '.[dev]'`. Then sign in. The hosted platform (community or enterprise edition) uses a browser hand-shake; a self-hosted `osr serve` accepts a token you generate yourself: ```bash osr login # opens https://opensmartroute.ai/cli/authorize osr login --url https://osr.example.com # your own platform deployment osr login --url http://router:8000 --token osr_local_... # self-hosted server (see `osr serve --generate-token`) osr whoami # workspace, plan, edition, key ``` Credentials live in `~/.config/opensmartroute/credentials.json` (`%APPDATA%\opensmartroute` on Windows), one profile per `--profile`; `OSR_API_URL` / `OSR_API_KEY` override them in CI. ## Quick start Three lines, nothing configured - a router in your process over the built-in starter catalogue (the one `osr route` uses without `--targets`): ```python from opensmartroute import Router router = Router.starter() print(router.route("Prove that sqrt(2) is irrational, step by step.").target.id) # llm-frontier ``` Or the hosted platform (or your own `osr serve`) over HTTP, with the key `osr login` saved or `OSR_API_KEY`: ```python from opensmartroute import OpenSmartRoute osr = OpenSmartRoute() d = osr.route("Refund order #123, the customer is upset", objective={"cost": 0.4, "quality": 0.6}) print(d.target_id, d.confidence, d.explanation) osr.feedback(d, success=True, quality=0.9) # the learners improve on your traffic print(osr.ask("What is the capital of France?")) # OpenAI-compatible chat, the router picks the model ``` Timeouts, retries with `Retry-After`, typed errors that never carry the key, and no key over plain `http://` to a public host - see [docs/SDK.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/SDK.md). Your own catalogue, in full: ```python from opensmartroute import (Router, TargetRegistry, RouteTarget, TargetKind, Capabilities, TargetConstraints, Outcome) registry = TargetRegistry([ RouteTarget("llm-small", TargetKind.LLM, capabilities=Capabilities(max_complexity=0.45), cost={"usd_per_1k_tokens": 0.0002}, latency_ms=300, quality_prior=0.55, examples=["Hi, how are you?", "What is the capital of France?"]), RouteTarget("llm-frontier", TargetKind.LLM, capabilities=Capabilities(min_complexity=0.5, domains=["math", "coding"]), cost={"usd_per_1k_tokens": 0.015}, latency_ms=2500, quality_prior=0.93, examples=["Prove the theorem step by step."]), RouteTarget("llm-onprem", TargetKind.LLM, # the only target allowed to see private data constraints=TargetConstraints(regions=["eu"], data_boundary="private", pii_allowed=True), cost={"usd_per_1k_tokens": 0.004}, latency_ms=900, quality_prior=0.7), RouteTarget("human", TargetKind.HUMAN, capabilities=Capabilities(actions=["escalate"], tags=["safety"]), cost={"usd_per_1k_tokens": 0.5}, latency_ms=300_000), ]) router = Router(registry) d = router.route("Prove that sqrt(2) is irrational, step by step.") print(d.target.id, f"{d.confidence:.2f}") # llm-frontier, with the calibrated confidence print(d.trace.explain()) # per-strategy scores and rationales router.learn(Outcome(request_id=d.request_id, target_id=d.target.id, success=True, quality=0.9, cost_usd=0.002, latency_ms=1800, domains=d.trace.signals.domains)) ``` Hard constraints and a per-request objective - the policy filters before anything is scored, and the trace says who was rejected and why: ```python from opensmartroute import RouteRequest, RequestConstraints, Objective req = RouteRequest("Summarize this patient intake note.", constraints=RequestConstraints(region="eu", data_boundary="private", max_cost_per_1k=0.005), objective=Objective(quality=1.0, cost=0.5, latency=0.1, quality_floor=0.6)) d = router.route(req) print(d.target.id) # llm-onprem print(d.trace.policy_rejections) # {'llm-small': 'data boundary public < required private', ...} ``` When no target is admissible the router raises `NoRouteError` (`details["rejections"]` carries the same map) instead of guessing. Catalogue and rules from YAML, evaluated and served from the command line: ```bash osr -t examples/targets.yaml -r examples/rules.yaml route "I want a refund for order #123" --plan osr -t examples/targets.yaml -r examples/rules.yaml eval examples/eval_dataset.jsonl --frontier export OSR_LLM_BASE_URL=https://api.openai.com/v1 OSR_LLM_API_KEY=sk-... # any OpenAI-compatible endpoint osr -t examples/targets.yaml -r examples/rules.yaml serve # http://127.0.0.1:8000/docs ``` `serve` routes without a provider; `OSR_LLM_BASE_URL` (OpenAI, Azure, vLLM, Ollama, OpenRouter, ...) is what lets `/v1/chat/completions` and `router.run()` actually run the chosen model. Wiring real providers, executing plans with `router.run()`, agent harnesses, SKILL.md and MCP catalogues, the decorator SDK and the enterprise builder are covered step by step in [docs/GUIDE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/GUIDE.md). ## What it routes | Kind | Examples | Executed by | |---|---|---| | `llm` | model endpoints, per reasoning effort or token budget | OpenAI-compatible client or any callable | | `agent` | coding, research and support harnesses with tools and memory | callable, HTTP or subprocess harness | | `skill` | deterministic capabilities, SKILL.md packages | your function; instructions disclosed to the model | | `persona` | system-prompt layers composed on top of the primary target | `run()` prompt composition | | `tool` | MCP or function tools, with schema-aware matching | tool call - as the routed target, or offered to the plan's model as a function it may call | | `workflow` | fixed multi-step pipelines | workflow engine | | `human` | queues and experts with Erlang-C capacity maths | ticketing or hand-off; also the abstention target | Catalogues load from YAML or JSON, MCP `tools/list` payloads, A2A agent cards, SKILL.md and persona directories and vLLM semantic-router configurations; the router plugs into LangGraph and Agent Framework graphs as a node and into any chat loop as an OpenAI tool. ## How it decides 1. **Signals** (under 1 ms): task type, domains, complexity, reasoning need, PII, language, modality, history; optional verbalised difficulty, cheap-draft features and hidden-state probes. 2. **Policy**: hard constraints filter targets before any scoring. 3. **Strategies**: rules, capability fit, example similarity, task table, Thompson and LinUCB bandits, IRT, Bradley-Terry, Markov lookahead, multi-turn history embeddings, learning-to-defer, edge/cloud tiers, token budgets, auctions, user adaptation and an LLM judge consulted only below a confidence threshold; optionally a routing SLM (`RouterSLM`) distilled from the whole ensemble that keeps improving on its own from outcomes, public routing datasets, a live model catalogue and the article feeds you point it at - a trained one ships inside the package (`--slm bundled`, `RouterBuilder.with_slm()`), so an on-prem install starts warm ([guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/GUIDE.md#the-routing-slm-and-the-self-improvement-loop)). 4. **Utility**: confidence-weighted ensemble, then `w_q * quality - w_c * norm(cost) - w_l * norm(latency)` with a hard quality floor; temperature scaling and conformal candidate sets calibrate the confidence; the router abstains when nothing is safe enough. 5. **After the answer**: cascades and self-escalation stop or reroute on response-side uncertainty (semantic entropy, P(True), streaming competence posterior); mixture-of-agents aggregation and permanent hand-off policies cover agentic trajectories. Formulas and citations: [docs/MATH.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/MATH.md), [docs/RESEARCH.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/RESEARCH.md). ## Production ```python from opensmartroute import RouteRequest, RequestConstraints from opensmartroute.enterprise import RouterBuilder, MetricsTelemetry, FileAuditSink, TenantMiddleware from opensmartroute.security import GuardMiddleware app = (RouterBuilder(registry) .with_defaults().with_auto_learning(state_dir=".osr-state") .with_health(latency_slo_ms=3000) .with_middleware(GuardMiddleware(redact=True), TenantMiddleware({"acme": {"deny_targets": ["llm-frontier"]}, "globex": {"data_boundary": "on_prem"}})) .with_telemetry(MetricsTelemetry()).with_audit(FileAuditSink("audit.jsonl")) .build()) req = RouteRequest("Prove that sqrt(2) is irrational.", constraints=RequestConstraints(tenant="acme")) d = app.route(req) # guard -> tenant -> policy -> strategies; audited and measured print(d.target.id, app.health_snapshot()) # app.run(req) executes the plan and records the Outcome once targets carry handlers # (`attach_chat_handlers`, agent harnesses, MCP tools - docs/GUIDE.md); without one it raises ExecutionError. ``` Routing overhead is 4.6 ms p50 with the default strategies and 7.4 ms with every learner enabled on the 27-target `examples/targets.yaml` with its rules (the repository's benchmark, 300 requests, CPython 3.11 on a Windows laptop, re-measured 2026-10-09; the continuous build fails when p95 passes 50 ms); retrieve-then-rank keeps it flat for thousands of tools ([measurements](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/GUIDE.md#10-routing-latency)). `osr serve` (or `create_app(app)` with the router above) exposes a FastAPI app and an OpenAI-compatible proxy (`/v1/chat/completions` with streaming and tool calling, `/v1/responses`, `/v1/embeddings`, `/v1/models`), the Anthropic Messages API (`/v1/messages`) and an MCP endpoint (`/mcp`): point the official OpenAI or Anthropic SDK at it with `model="osr/auto"` and keep the rest of the code; guard and tenant violations return 400, no admissible target 422, an unreachable provider 503 and a failing target falls back to the next candidate. Circuit breakers open on provider failures and recover on their own; learner state survives restarts from `state_dir` or a Redis / SQL store. Deployment references: [deploy/README.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/deploy.md), [docs/ENTERPRISE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/ENTERPRISE.md). ## Hosted platform platform/ (`platform/README.md`) packages the router as a service from two container images: `osr-platform-api` (FastAPI: self-serve signup with hashed API keys, plans and quotas, usage metering, the metered `/api/v1/route` family with the full trace, per-tenant constraints and workspace policy, the audit trail, per-request traces and a live event stream, and the OpenAI-compatible `/v1/chat/completions` proxy - one process, or one container per domain behind a gateway) and `osr-platform-web` (Next.js: landing page, the rendered documentation, pricing, a live playground and the account dashboard with activity, events, governance and health pages; it proxies `/api` and `/v1` so the browser only talks to one origin). `OSR_PLATFORM_EDITION=community` runs the core `Router`; `enterprise` runs the builder above with auto-learning, health, guard, metrics, a hash-chained audit log and per-tenant constraints. The Azure solution template deploys everything to Azure Container Apps with Azure OpenAI ([docs/INSTALL.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/INSTALL.md)); the reference deployment is https://opensmartroute.ai. The end-user guide is [docs/PLATFORM.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PLATFORM.md); the REST API reference is generated from the platform's OpenAPI document. ```bash curl -s -XPOST $OSR/api/v1/signup -H 'content-type: application/json' -d '{"email":"you@example.com"}' curl -s $OSR/api/v1/route -H "authorization: Bearer $KEY" -H 'content-type: application/json' \ -d '{"text":"Prove that sqrt(2) is irrational."}' ``` From TypeScript or JavaScript, the client on npm - `npm install @opensmartroute/sdk` ([platform/sdk-ts](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/sdk-typescript.md)) - wraps the same endpoints and the OpenAI-compatible `/v1` surface with streaming, zero runtime dependencies, Node 20+ / Deno / Bun / edge / browser: ```ts import { OpenSmartRoute } from "@opensmartroute/sdk"; const osr = new OpenSmartRoute({ baseUrl: "https://opensmartroute.ai", apiKey: process.env.OSR_API_KEY! }); const decision = await osr.route({ text: "Prove that sqrt(2) is irrational.", top_k: 3 }); ``` ## Security Routing is a control plane; its integrity is a security property. `InputGuard` combines a heuristic and a learned detector for confounder gadgets that reroute queries, an injection-risk scorer, PII redaction and prompt sanitisation for the LLM judge. Per-task resource limits, an origin policy for sensitive tool parameters, signed MCP manifests, AES-GCM state, content-free logs and hash-chained audit complete the model. CI runs `ruff -S`, `mypy`, `bandit`, `pip-audit` and the `osr safety` red-team suite. Threat model: [docs/SECURITY.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/SECURITY.md). Reporting: [SECURITY.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/security-policy.md). ## Documentation The user documentation is a searchable, versioned site at https://opensmartroute.ai/docs (built from these files at release time, with a REST API reference generated from the platform's OpenAPI document). It covers the hosted platform, the Python SDK and the pip package; the internal planning, go-to-market, brand and sales documents below stay in the repository only. | Document | Contents | |---|---| | [docs/QUICKSTART_PLATFORM.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/QUICKSTART_PLATFORM.md) | Platform quickstart: workspace and key, first `/api/v1/route` call, the OpenAI-compatible endpoint, feedback | | [docs/QUICKSTART_SDK.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/QUICKSTART_SDK.md) | Python SDK quickstart: install, describe targets, route, constraints and objectives, learning, the CLI | | [docs/INSTALL.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/INSTALL.md) | Install the platform yourself: Azure Marketplace offer, Docker Compose on your own servers (on-premises, air-gapped), first sign-in, custom domain, upgrade and backup | | [docs/USE_CASES.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/USE_CASES.md) | Real-world use cases by industry: nine complete, working catalogues (healthcare, banking, legal, retail support, engineering, HR, marketing, travel, analytics) with the requests, the routed target and the reason - every decision verified on every change | | [docs/GUIDE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/GUIDE.md) | User guide: targets, routing, execution, providers, learning, SDK, enterprise builder, research-track modules, CLI, latency, layout | | [docs/PLATFORM.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PLATFORM.md) | Platform guide: authentication, `/api/v1/route`, execution, the OpenAI-compatible endpoint, feedback, plans and quotas, organizations, tenants, governance, observability (traces, events, readiness), the MCP server, dashboard | | [docs/PLATFORM_JOURNEYS.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PLATFORM_JOURNEYS.md) | Platform journeys: who uses the platform, what each plan unlocks (feature-to-page map), the website, dashboard and console navigation, the new user step by step, existing-user tasks by role, plan changes, and offboarding checklists for a person leaving a team, a person leaving the platform and a team shutting a workspace down | | [docs/MODELS.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/MODELS.md) | Model server: host open-weight models on your own hardware (CPU or CUDA) behind the Ollama and OpenAI APIs - pulls from ollama.com and Hugging Face, Ollama's on-disk store, always-warm residency with a fit check, admission queue, metrics, settings, use with the platform | | [docs/MARKETPLACE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/MARKETPLACE.md) | Marketplace: find, install, buy and publish agents, skills, personas, prompts and stack templates; ratings, review lifecycle, `osr stack` | | [docs/MCP.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/MCP.md) | Cost estimates (`estimate`, `POST /api/v1/estimate`), recommended models per use case and the MCP server for VS Code, Cursor, Claude, Windsurf and agents | | [docs/PUBLISHING.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PUBLISHING.md) | Content publishing for your website: your feeds and briefs become posts written through the router as your workspace's requests, delivered to your site (signed webhook, WordPress, Ghost) or pulled as RSS; `/api/v1/content`, the `content_*` MCP tools and the dashboard page | | [docs/EXTENSION.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/EXTENSION.md) | Browser extension (Chrome, Edge, Firefox): the pre-send advisor on ChatGPT, Claude, Gemini, Copilot and Perplexity - task and tokens, PII redaction, model hints, on-device or platform quotes, analysis policy, device sign-in | | [docs/DESKTOP.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/DESKTOP.md) | Desktop app (Windows, macOS, Linux): the routed command bar over any application - shortcut, the selection read and pasted back, on-device checks, connecting a workspace, installing the extension into every browser, updates, privacy, troubleshooting | | [docs/VSCODE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/VSCODE.md) | VS Code extension: the routing panel for the selection - task, language, tokens, personal data, the recommended model and its cost - and Ask / Explain / Rewrite in place through the router; device sign-in, what is sent, settings | | [docs/OFFICE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/OFFICE.md) | Word add-in: the pane beside the document - task, language, size, personal data, the recommended model and its cost for the selected passage - and Ask / Explain / Summarise / Rewrite / Proofread through the router; the manifest, sideloading and admin-centre deployment, sign-in, what is sent | | [docs/SDK.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/SDK.md) | API reference for the decorator SDK, components and settings | | [docs/REFERENCE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/REFERENCE.md) | Generated API reference: every module and exported name | | [docs/ARCHITECTURE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/ARCHITECTURE.md) | Request path, module boundaries, performance envelope | | [docs/ENTERPRISE.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/ENTERPRISE.md) | Ports, stores, middleware, shadow and A/B, multi-replica operation | | [docs/COMPATIBILITY.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/COMPATIBILITY.md) | Compatibility matrix: every model provider, client, agent framework and adapter the router connects to, how, and how each connection was verified (continuous tests, a dated live run, or the OpenAI-compatible protocol alone) | | [docs/OBSERVABILITY.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/OBSERVABILITY.md) | Tracing and observability: spans and events for every stage, sinks (memory, metrics, log, file, OpenTelemetry), `/events`, `/trace`, `/metrics`, `OSR_OBSERVABILITY_*`; the platform's per-workspace `/api/v1/trace`, `/api/v1/events`, `/api/v1/status` and dashboard pages | | [docs/MATH.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/MATH.md) | Every formula the router uses, with derivations | | [docs/AGENT_ENGINEERING.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/AGENT_ENGINEERING.md) | Prompt, harness, context, memory and agent engineering, integrations, guardrails and evals: where each lives in the SDK and the platform; the prompt registry; trace export to Langfuse and OTLP/OpenInference (Arize Phoenix, TruLens); datasets in Ragas / DeepEval / Langfuse shape | | [docs/RESEARCH.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/RESEARCH.md) | Literature survey and the idea-to-module map | | [docs/SECURITY.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/SECURITY.md) | Threat model and hardening checklist | | [docs/SECURITY_REVIEW.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/SECURITY_REVIEW.md) | External security review pack: scope, trust boundaries, evidence, reviewer questions, review log | | docs/ROADMAP.md (`docs/ROADMAP.md`) | Per-version exit criteria and status | | [docs/RELEASES.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/RELEASES.md) | Versions, channels and releases: the one version every artifact carries, stable releases vs developer previews from `main`, how to read the build a deployment runs, unreleased changes, how a release is cut | | docs/PLATFORM_PLAN.md (`docs/PLATFORM_PLAN.md`) | Platform strategy: agentic routing, Open Capability Manifest, marketplace, editions and pricing | | docs/MODEL_SERVING_PLAN.md (`docs/MODEL_SERVING_PLAN.md`) | Plan for OSR Models: our own model hosting server (store, registry, engine lifecycle, Ollama- and OpenAI-compatible API) and the scalable inference gateway and fleet controller over llama.cpp and vLLM engines; research summary, architecture, phases, verification | | docs/GO_TO_MARKET.md (`docs/GO_TO_MARKET.md`) | Go-to-market plan; the sales enablement kit lives in docs/sales/ (`docs/sales/README.md`) | | [spec/ocm/README.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/ocm.md) | Open Capability Manifest specification and JSON Schema | | [deploy/README.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/deploy.md) | Container image, Helm chart, reference deployments | | platform/README.md (`platform/README.md`) | Hosted platform: `api/` (FastAPI) and `web/` (Next.js), playground, API keys, plans, editions, `OSR_PLATFORM_*` settings, Azure deployment | | docs/BRAND.md (`docs/BRAND.md`) | Logo system and naming conventions | .claude/skills/ (`.claude/skills`) ships Agent-Skills packages that teach coding assistants how to use and extend the project; they are also valid routing targets (`osr skills` validates them) and each one is published on the documentation site under `/docs/skills/`. Coding agents working in this repository start from AGENTS.md (`AGENTS.md`). ## Roadmap | Release | Theme | Status | |---|---|---| | 0.3 | Real integrations: OpenAI-compatible client, adapters, config loaders | Shipped | | 0.4 | Learned signals and honest evaluation | Shipped | | 0.5 | Target representations, effort and personalisation | Shipped | | 0.6 | Multi-step and agentic routing | Shipped | | 0.7 | Catalogue interop and discovery at scale | Shipped | | 0.8 | Operations, risk control and economics | Shipped | | 0.9 | Security hardening of the control plane | Shipped | | 1.0 | Stable API, reference deployments, security review pack | Shipped | | 1.1, 1.2 | Hosted platform: organizations, tenants, billing, marketplace, support, e-mail, operator console | Shipped | Every item in the research track is implemented on `main` with tests; a version is **Complete** when its measured exit criterion is published (8/8 met) and **Shipped** when it is in a tagged release - the current release is 2.1.0 ([CHANGELOG.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/changelog.md)). 1.0 means what the repository can prove: frozen public API with a deprecation path, published performance envelope, reference deployments, security controls with a red-team suite in CI and a published review pack ([docs/SECURITY_REVIEW.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/SECURITY_REVIEW.md)), the public leaderboard run ([examples/leaderboard/results](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/leaderboard-results.md), produced by the recipe in [examples/leaderboard](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/leaderboard.md)) and consecutive releases without a breaking change (0.4.0 through 2.1.0, additions only). Adoption evidence - an independent security report, accepted leaderboard listings, two production users (ADOPTERS.md (`ADOPTERS.md`)) - is tracked, never claimed, and the release tooling refuses a release while a readiness row is open. Details in docs/ROADMAP.md (`docs/ROADMAP.md`) and [CHANGELOG.md](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/changelog.md). ## Contributing Issues and pull requests are welcome; see CONTRIBUTING.md (`CONTRIBUTING.md`). CI runs `ruff`, `mypy`, `bandit` and `pytest` on CPython 3.10 to 3.13 on Linux and 3.12 on Windows, a routing-accuracy gate and the safety suite on the example catalogue, and builds the distribution and the container image; a weekly security run (also on every push) runs `bandit` over the SDK and the platform, `pip-audit` and `npm audit` over the dependencies and the `osr safety` red-team suite. The test suite has no mocks of the router itself: the end-to-end suite drives the shipped example catalogue through an in-process OpenAI-compatible provider fleet over HTTP, a real MCP server subprocess over stdio, the CLI, the FastAPI service, provider outages with breaker recovery, agentic multi-round loops and concurrent traffic. Releases are automated: a release pull request bumps the version and rolls the changelog; merging it and running the release process tags, publishes to PyPI (`twine check --strict`, project-scoped token) and pushes the image. ## License Apache-2.0 --- # Platform quickstart Route your first request through the hosted platform in about five minutes: create a workspace, get an API key, ask the router for a decision, let it execute the answer, and report how it went. Every call shown here is documented in full in the [platform guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PLATFORM.md) and in the REST API reference at `/docs/api`. ```mermaid flowchart LR APP["Your app (OpenAI client, model=auto)"] --> API["POST /v1/chat/completions"] API --> AUTH["API key, plan, quota and budget"] AUTH --> RT["Router.route()"] RT --> EXE["Chosen provider or target executes"] EXE --> RESP["Answer + X-OSR-Target + token usage"] RESP --> LOOP["Metered, traced, learners updated"] ``` ## 1. Create a workspace and an API key Sign up at [opensmartroute.ai/platform/signup](https://opensmartroute.ai/platform/signup) with GitHub, Google, Microsoft or an email address. Signup creates a personal workspace on the **free** plan and issues an API key. :::warning[The API key is shown once] Copy it into a secret manager immediately - it cannot be retrieved again later. You can create, rename, rotate and revoke more keys on the keys page of the dashboard at any time. ::: Authenticate with either a copied key or the CLI browser hand-shake: ::::tabs :::tab[API key header] Send the key with every request in either header: ```http Authorization: Bearer osr_... X-API-Key: osr_... ``` ::: :::tab[CLI sign-in] ```bash curl -LsSf https://opensmartroute.ai/install.sh | sh # Windows: irm https://opensmartroute.ai/install.ps1 | iex osr login # opens the browser, mints a key for this machine osr whoami # workspace, plan, edition behind the stored credential ``` ::: :::: ## 2. Route a request `POST /api/v1/route` returns a decision: the chosen target, the confidence, ranked alternatives, the signals the router extracted and a human-readable explanation. Nothing is executed yet. The examples use the hosted API origin `https://api.opensmartroute.ai`; the site origin (`https://opensmartroute.ai/api/v1/...`, the form the dashboard's quick-start card shows) answers the same requests, and a self-hosted deployment uses its own URL. ::::tabs :::tab[curl] ```bash curl -s https://api.opensmartroute.ai/api/v1/route \ -H "Authorization: Bearer $OSR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"text": "Prove that sqrt(2) is irrational.", "top_k": 3}' ``` ::: :::tab[TypeScript] ```bash npm install @opensmartroute/sdk ``` ```ts import { OpenSmartRoute } from "@opensmartroute/sdk"; const osr = new OpenSmartRoute({ baseUrl: "https://opensmartroute.ai", apiKey: process.env.OSR_API_KEY! }); const decision = await osr.route({ text: "Prove that sqrt(2) is irrational.", top_k: 3 }); console.log(decision.target.id, decision.confidence, decision.explanation); ``` ::: :::tab[Python] ```bash pip install opensmartroute ``` ```python import os, httpx r = httpx.post( "https://api.opensmartroute.ai/api/v1/route", headers={"Authorization": f"Bearer {os.environ['OSR_API_KEY']}"}, json={"text": "Prove that sqrt(2) is irrational.", "top_k": 3}, ) print(r.json()["target"]["id"], r.json()["confidence"]) ``` ::: :::: ```json { "request_id": "7f3c...", "target": {"id": "llm-frontier", "kind": "llm", "name": "Frontier model"}, "confidence": 0.81, "alternatives": [{"id": "llm-mid", "kind": "llm", "utility": 0.62}], "signals": {"complexity": 0.74, "domains": ["math"], "reasoning_need": 0.9, "contains_pii": false}, "explanation": "llm-frontier: high reasoning need, math domain, quality weight dominates ..." } ``` Two request fields cover most needs: - `objective` trades quality, cost and latency per request: `{"objective": {"quality": 1.0, "cost": 0.5}}` prefers cheaper targets whenever quality allows. - `constraints` are hard limits, never traded off: `{"constraints": {"max_cost_per_1k": 0.005, "data_boundary": "private"}}` removes every target that stores data less strictly or costs more, and the response's `policy_rejections` says which target was dropped and why. The full field tables - history, context, tenant, kinds, plans - are in the [platform guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PLATFORM.md#2-route-a-request). ## 3. Get the answer, not just the decision The simplest way is the OpenAI-compatible endpoint: point any OpenAI SDK at `/v1` and set `model` to `auto`. The router chooses the target per request, runs it and returns a standard `chat.completion` whose `model` field is the target that answered; set `stream: true` and each provider token is relayed as it arrives. ::::tabs :::tab[Python] ```python from openai import OpenAI client = OpenAI(base_url="https://api.opensmartroute.ai/v1", api_key=OSR_API_KEY) reply = client.chat.completions.create( model="auto", messages=[{"role": "user", "content": "Write a haiku about routing."}], ) print(reply.model) # the target the router chose, e.g. "llm-small" print(reply.choices[0].message.content) ``` ::: :::tab[Node.js] ```javascript import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.opensmartroute.ai/v1", apiKey: process.env.OSR_API_KEY }); const reply = await client.chat.completions.create({ model: "auto", messages: [{ role: "user", content: "Write a haiku about routing." }], }); console.log(reply.model); // the target the router chose console.log(reply.choices[0].message.content); ``` ::: :::tab[curl] ```bash curl -s https://api.opensmartroute.ai/v1/chat/completions \ -H "Authorization: Bearer $OSR_API_KEY" -H "Content-Type: application/json" \ -d '{"model": "auto", "messages": [{"role": "user", "content": "Write a haiku about routing."}]}' ``` ::: :::: Decision metadata (request id, confidence, alternatives, cost) rides along in an `opensmartroute` object that other clients ignore. A `models` list makes the router choose among your candidates and fall back down the list when a target fails. On the **pro** plan and above, `POST /api/v1/route` with `"execute": true` does the same for any target kind - agents, skills, tools - and returns the output in `result`. ### Name a model instead of `auto` Every model the platform sells by the token is on the [storefront](/models?view=offers), with the price your workspace pays per million tokens, and in `GET /v1/models` under its catalogue id (`openai/gpt-4.1-mini`). | `model` | The router | |---|---| | `"auto"` | chooses across the whole catalogue. | | `"openai/gpt-4.1-mini"` | chooses among the providers serving that model, by price, health and learned quality. | | `"openai/gpt-4.1-mini@azure"` | uses that one endpoint. | ```python reply = client.chat.completions.create( model="openai/gpt-4.1-mini", messages=[{"role": "user", "content": "Write a haiku about routing."}], extra_body={"provider": {"data_collection": "deny", "sort": "price"}}, # optional: steer the endpoint ) print(reply.model) # the endpoint that answered: "openai/gpt-4.1-mini@azure" print( reply.model_extra["opensmartroute"]["charge_usd"] ) # what the call cost you; the same figure lands on the usage row ``` The `provider` object takes `order`, `only`, `ignore`, `data_collection`, `sort` and `max_price`, as on OpenRouter. The [platform guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PLATFORM.md#models-by-the-token-offers-prices-credits-and-provider-preferences) covers the full set, the pay-as-you-go plan, per-key spend limits and how operators list models. ## 4. Report the outcome The learners (Bradley-Terry, IRT, LinUCB) improve on your own traffic when you tell the platform how an answer turned out (every plan, the free one included): ```bash curl -s https://api.opensmartroute.ai/api/v1/feedback \ -H "Authorization: Bearer $OSR_API_KEY" -H "Content-Type: application/json" \ -d '{"request_id": "7f3c...", "target_id": "llm-frontier", "success": true, "quality": 0.9}' ``` The dashboard has the same form without curl: expand a row on the activity page and report good or poor, a quality score and, optionally, the target that would have done better. ## FAQ ::::accordions :::accordion[What does the free plan include?] Routing decisions (`POST /api/v1/route`) with the full trace, the OpenAI-compatible endpoint, outcome feedback and your own provider keys, metered against a monthly quota of 15,000 requests (30 per minute, 2 API keys, 5 seats). Plans (`plan` / `execute` for agents, skills and tools), a bigger quota with overage instead of a stop, tenants, statistics, audit and SSO come with the paid tiers - see the pricing page or `GET /api/v1/info`. ::: :::accordion[Do I bring my own provider keys?] Yes, on every plan. The platform routes and meters; you connect your own provider credentials under *Model providers* so the answer is billed to you by the provider and never leaves your account boundary. ::: :::accordion[Can I pay for models by the token instead?] Yes. The **pay as you go** plan has no monthly fee and no request quota: buy credits on the billing page and call any model on the [storefront](/models?view=offers) at the price shown - `model: "openai/gpt-4.1"` routes among the providers serving it, `"openai/gpt-4.1@azure"` pins one. Requests stop with `402` when the credits run out; per-key spend limits cap what one integration may charge. ::: :::accordion[How do I see why a target was chosen?] Every `POST /api/v1/route` response carries `signals`, `alternatives` and an `explanation`, and `policy_rejections` lists any target a hard constraint removed. The activity page shows the same trace per request. ::: :::accordion[Can I self-host instead?] Yes. The same router ships as a zero-dependency library and as `osr serve`. Start with the [Python SDK quickstart](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/QUICKSTART_SDK.md) or [Deploy with Docker and Helm](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/deploy.md). ::: :::: ## Where next - [Platform guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PLATFORM.md) - authentication, organizations, tenants, budgets, traces, errors. - [MCP server and cost estimates](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/MCP.md) - put the router inside VS Code, Cursor or Claude. - [Marketplace](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/MARKETPLACE.md) - shared agents, skills, personas, prompts and stack templates. - [Python SDK quickstart](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/QUICKSTART_SDK.md) - the same router as a zero-dependency library. --- # Python SDK quickstart Route between models, agents, skills, tools and humans inside your own process in about five minutes. The core package has zero runtime dependencies; everything here runs offline. The [user guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/GUIDE.md) continues where this page stops - real providers, plans, learning, the enterprise builder. :::tip[Everything here runs offline] No API keys and no network calls are needed. Sections 2 to 5 build on each other - paste them into one file in order and run it - the router is deterministic, so you get the same decisions shown here. ::: ## 1. Install ::::tabs :::tab[pip] ```bash pip install opensmartroute ``` The core package has **zero runtime dependencies**. ::: :::tab[Extras] ```bash pip install 'opensmartroute[yaml]' # + YAML catalogues and rules pip install 'opensmartroute[server]' # + FastAPI server and OpenAI-compatible proxy pip install 'opensmartroute[fast]' # + numpy-accelerated SLM training pip install 'opensmartroute[all]' # every extra (yaml, server, fast, embeddings, tiktoken, otel, crypto, dev) ``` `osr doctor` tells you what is installed and what a missing extra needs. ::: :::tab[CLI installer] ```bash curl -LsSf https://opensmartroute.ai/install.sh | sh ``` On Windows PowerShell: ```powershell irm https://opensmartroute.ai/install.ps1 | iex ``` Installs the `osr` command line together with the package. ::: :::: ## 2. Describe your targets A target is anything a request can be sent to. Declare what each one is good at, what it costs and how fast it is; the router does the rest. ```python from opensmartroute import Router, TargetRegistry, RouteTarget, TargetKind, Capabilities, Outcome, TargetConstraints registry = TargetRegistry( [ RouteTarget( "llm-small", TargetKind.LLM, capabilities=Capabilities(max_complexity=0.45), cost={"usd_per_1k_tokens": 0.0002}, latency_ms=300, quality_prior=0.55, examples=["Hi, how are you?", "What is the capital of France?"], ), RouteTarget( "llm-frontier", TargetKind.LLM, capabilities=Capabilities(min_complexity=0.5, domains=["math", "coding"]), cost={"usd_per_1k_tokens": 0.015}, latency_ms=2500, quality_prior=0.93, examples=["Prove the theorem step by step."], ), RouteTarget( "llm-onprem", TargetKind.LLM, capabilities=Capabilities(domains=["general"]), constraints=TargetConstraints(regions=["eu"], data_boundary="private", pii_allowed=True), cost={"usd_per_1k_tokens": 0.001}, latency_ms=1200, quality_prior=0.7, ), RouteTarget( "human", TargetKind.HUMAN, capabilities=Capabilities(actions=["escalate"], tags=["safety"]), cost={"usd_per_1k_tokens": 0.5}, latency_ms=300_000, ), ] ) ``` Catalogues also load from YAML or JSON files, MCP `tools/list` payloads, A2A agent cards, SKILL.md and persona directories - see the [user guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/GUIDE.md#1-targets). With a `targets.yaml` (and optionally a `rules.yaml`) on disk - the repository ships a pair under `examples/` - the whole setup is one line (YAML files need `pip install 'opensmartroute[yaml]'`, JSON needs nothing): ```python from opensmartroute import Router router = Router.from_files("targets.yaml", "rules.yaml", state_dir=".osr-state") # state_dir keeps what it learns ``` ## 3. Route ```python router = Router(registry) d = router.route("Prove that sqrt(2) is irrational, step by step.") print(d.target.id, f"{d.confidence:.2f}") # llm-frontier 0.89 print(d.trace.explain()) # per-strategy scores and rationales ``` Every decision carries a trace: which signals were extracted, which targets policy rejected and why, how each strategy scored the rest. Nothing is a black box. :::note[The trace is the audit trail] `d.trace.explain()` prints the whole decision - signals, policy rejections and per-strategy scores. Keep it in your logs and every route is reproducible and defensible after the fact. ::: Every `route()` call runs the same five stages - the trace records each one: ```mermaid flowchart TB R["router.route(request)"] --> SIG["Signals: complexity, domains, intent, PII"] SIG --> POL{"Policy: hard constraints + rules"} POL -->|rejected| REJ["trace.policy_rejections"] POL -->|admissible| STR["Strategies score each candidate"] STR --> ENS["Ensemble to utility, weighted by the objective"] ENS --> DEC["Decision: target, confidence, alternatives, trace"] ``` ## 4. Constraints and objectives Hard constraints are filtered before any scoring - they are never traded off against quality. The objective sets the trade-off between quality, cost and latency per request. A note with private patient data only clears the on-prem target; the public models are excluded before scoring begins. :::warning[Constraints are hard, objectives are soft] A `RequestConstraints` violation removes a target from consideration entirely - it is never bought back by a strong quality score. `Objective` weights only rank the targets that already comply. ::: ```python from opensmartroute import RouteRequest, RequestConstraints, Objective req = RouteRequest( "Summarize this patient intake note.", constraints=RequestConstraints(region="eu", data_boundary="private", max_cost_per_1k=0.005), objective=Objective(quality=1.0, cost=0.5, latency=0.1), ) d = router.route(req) print(d.target.id) # llm-onprem print(d.trace.policy_rejections) # {'llm-small': 'data boundary public < required private', ...} ``` ## 5. Close the loop Report how the routed answer went and the router's learners (bandits, IRT, Bradley-Terry) shift future decisions toward what actually works for your traffic: ```python router.learn( Outcome( request_id=d.request_id, target_id=d.target.id, success=True, quality=0.9, cost_usd=0.002, latency_ms=1800, domains=d.trace.signals.domains, ) ) ``` Attach handlers to targets and `router.run(req)` executes the chosen target or plan and records the outcomes itself - wiring real providers is the [user guide's fourth chapter](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/GUIDE.md#4-real-providers). ## 6. The same thing from the command line Without `--targets` the `route`, `estimate`, `serve`, `targets` and `mcp` commands use a built-in starter catalogue (`llm-small`, `llm-frontier`, `llm-onprem`, with two rules), so the first command works straight after the install; `osr stack init --out stack.json` writes that catalogue to disk to edit, and `-t stack.json -r stack.json` routes through your copy. The repository's `examples/` folder holds the richer YAML pair used below. ```bash osr route "Prove that sqrt(2) is irrational" # built-in starter catalogue, no files needed osr -t examples/targets.yaml -r examples/rules.yaml route "I want a refund for order #123" --plan osr -t examples/targets.yaml -r examples/rules.yaml estimate "Summarise this contract" # tokens, cost, quality per candidate osr -t examples/targets.yaml -r examples/rules.yaml eval examples/eval_dataset.jsonl --frontier export OSR_LLM_BASE_URL=https://api.openai.com/v1 OSR_LLM_API_KEY=sk-... # the provider `serve` executes on osr -t examples/targets.yaml -r examples/rules.yaml serve # http://127.0.0.1:8000/docs osr -t examples/targets.yaml mcp # MCP server for your IDE, marketplace tools included ``` Routing needs no provider. Execution does: `OSR_LLM_BASE_URL` names any OpenAI-compatible endpoint (OpenAI, Azure OpenAI, vLLM, Ollama, OpenRouter, ...) and `OSR_LLM_API_KEY` its key; without them the served `/v1/chat/completions` answers 503 because no target has a handler, and routing still works. `osr serve` exposes the same `/route`, `/feedback` and `/mcp` endpoints as the hosted platform and the same `/v1` surface: OpenAI `chat/completions` (streaming, tool calling), `responses`, `embeddings`, `moderations`, `audio/speech`, `audio/transcriptions`, `images/generations` and the Anthropic `messages` API - point the official OpenAI or Anthropic SDK at it with `model="osr/auto"` (or `"auto"`), an MCP client at `/mcp`, or the TypeScript client (`npm install @opensmartroute/sdk`, `apiPrefix: ""`). Every model call is compacted first (repeated lines, stray whitespace and stale history go; the saving is reported as `tokens_saved`), `--marketplace-refresh 86400` keeps the served catalogue in step with the marketplace, and `--guard --redact-pii --output-guard redact --health --audit audit.jsonl` turns on the hardening the [deploy guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/deploy.md) describes. ## FAQ ::::accordions :::accordion[Do I need API keys or a network connection?] No. The core package is offline and deterministic - it decides *where* a request should go. You only add provider credentials when you attach real handlers and call `router.run()`. ::: :::accordion[How does the router pick a target?] It extracts signals (complexity, domains, intent, PII), filters targets that fail the hard constraints, scores the rest with an ensemble of strategies, and combines the scores into a utility weighted by your `Objective`. `d.trace.explain()` shows every step. ::: :::accordion[Can it route to more than models?] Yes. A `RouteTarget` can be an LLM, an agent, a skill, a tool or a human - the `TargetKind`. The same scoring picks the best target of any kind, and `RequestConstraints(allowed_kinds=...)` limits it when you need to. ::: :::accordion[Does it learn from outcomes?] Yes. `router.learn(Outcome(...))` feeds the bandit, IRT and Bradley-Terry learners so future decisions shift toward what actually works on your traffic. It is optional and off until you call it. ::: :::: ## Where next - [User guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/GUIDE.md) - targets, rules, providers, plans, learning, the CLI, latency numbers. - [SDK guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/SDK.md) - decorators, settings, error handling, threading, extension points. - [Enterprise builder](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/ENTERPRISE.md) - middleware, telemetry, stores, shadow and A/B rollout. - [Deploy with Docker and Helm](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/deploy.md) - run `osr serve` on your own infrastructure. - [TypeScript SDK](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/sdk-typescript.md) - call `osr serve` or the platform from Node, Deno, Bun, edge and browsers. - [Platform quickstart](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/QUICKSTART_PLATFORM.md) - the hosted version of everything above. --- # Install the platform The **hosted platform** at [opensmartroute.ai](https://opensmartroute.ai) needs no installation - sign up, create a key, follow the [platform quickstart](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/QUICKSTART_PLATFORM.md). This page is for running the **whole platform yourself**: the routing API with its OpenAI-compatible endpoint, the web app (public site, dashboard, operator console), the routing SLM service and the state behind them. The same images and the same `OSR_PLATFORM_*` settings run everywhere; only the way they are started differs. | Where | How | For | |---|---|---| | Azure, from the portal | [Azure Marketplace](#azure-marketplace) - the solution template with a wizard, one resource group, no tooling (the same template deploys from the published package until the listing is live) | Teams that want the platform in their own subscription | | Your own servers or any cloud VM | [Docker Compose](#your-own-servers-docker-compose) - PostgreSQL, Redis, Kafka and the platform as containers, from the published Compose bundle | On-premises, air-gapped, other clouds | | Kubernetes | [`osr serve` Helm chart](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/deploy.md) for the router alone; the platform on Kubernetes runs the same containers as Compose | Sidecar / control-plane routing without the hosted-platform surfaces | Every file named on this page - the Compose bundle, the Helm chart, the Marketplace package and its two files, the checksums of the PyPI release - is on the **[downloads page](https://opensmartroute.ai/downloads)** with its version and SHA-256; the stable links `https://opensmartroute.ai/download/` always resolve to the current release and `https://opensmartroute.ai/download/latest.json` lists them for scripts. The source repository is private; nothing here needs it. Just the Python library or the `osr` command line: [README - Install](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/readme.md#install). Calling the platform from TypeScript or JavaScript: `npm install @opensmartroute/sdk` ([TypeScript SDK](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/sdk-typescript.md)). ## What you get Every install path deploys the same product: - `osr-platform-api` - the FastAPI platform: `POST /api/v1/route`, the OpenAI-compatible `/v1` proxy, MCP server, accounts, keys, workspaces, tenants, governance, marketplace, billing, notifications, support tickets and the operator API. In cluster mode it also runs once per domain (docs, rankings, marketplace, providers, onboarding, accounts, billing, admin, mcp, openai, routing) behind the API gateway, plus the routing SLM service. - `osr-platform-web` - the Next.js web app: the public site and documentation, `/platform` (sign-in, dashboard, playground, publish flow) and `/platform/admin` (the operator console). - State: PostgreSQL (always), Redis and Kafka (cluster mode), a data volume for the audit chain and the routing SLM. - Model providers: open-weight models through Ollama by default - on Azure the template runs the curated set as its own container apps (CPU) or one serverless-GPU server and maps every tier and specialist target to it, with Ollama Cloud for the frontier open weights when you give it a key; Azure OpenAI deployments only when you switch them on (`azureOpenAiEnabled`). Anything OpenAI-compatible everywhere (connected in the console under *Providers*, or by workspaces with their own keys under *Model providers*). Release images: `crosrua2c6onyidguw.azurecr.io/osr-platform-api:2.1.0` and `crosrua2c6onyidguw.azurecr.io/osr-platform-web:2.1.0` (anonymous pull; `:latest` follows the newest release, `:` the newest patch). The web image is built without a baked hostname: it reads `OSR_PUBLIC_WEB_URL` at run time and the browser uses the origin it is talking to, so one image serves any domain. ## Azure Marketplace The offer **OpenSmartRoute platform** is an Azure Application (solution template): it deploys into a resource group of your subscription, you own every resource, nothing is shared with the publisher and there is no software charge on the Azure bill - you pay the Azure resources it creates. **Listing status.** The offer package is the Partner Center submission; until the listing is live the offer does not appear in a Marketplace search. The same template deploys today from the published package - `mainTemplate.json` and `createUiDefinition.json` from the [downloads page](https://opensmartroute.ai/downloads) - with the same wizard when you use the portal's *Deploy a custom template*, or from the command line: ```bash curl -fsSLO https://opensmartroute.ai/download/marketplace-template # opensmartroute-mainTemplate-.json az group create -n rg-osr -l centralindia az deployment group create -g rg-osr -f opensmartroute-mainTemplate-*.json \ -p adminUsername=admin adminPassword='' platformEdition=enterprise clusterMode=false ``` Every wizard field below is a parameter of that template (`az deployment group what-if` lists them with their descriptions); the outputs, first sign-in, custom-domain, upgrade and backup steps are identical. ### Deploy 1. In the Azure portal open *Marketplace*, search for **OpenSmartRoute**, choose the plan and *Create* (or *Deploy a custom template* -> *Build your own template in the editor* -> *Load file* with the downloaded `mainTemplate.json`, then *Edit UI definition* with `createUiDefinition.json`). 2. **Basics** - subscription, a new or existing resource group, the region (Container Apps must be offered there - and Azure OpenAI with the default `gpt-4.1` family when you switch those deployments on), a deployment name, the first **operator username and password** (the console sign-in), the edition (Enterprise: tenants, audit, statistics, persisted learners; Community: the lightest footprint). 3. **Size and state** - *Cluster mode* (Redis + Kafka, the API split into domain services scaled on demand; off = one API replica with PostgreSQL only, right for a trial) and *Managed state* (Azure Database for PostgreSQL with point-in-time restore, Azure Cache for Redis, Event Hubs - recommended for production; off = state containers on Azure Files, cheapest). 4. **Hostnames** - leave empty to use the Container Apps hostnames, or enter your web and API hostnames (and let the template create the Azure DNS zone). TLS certificates are issued in a second run once DNS resolves (below). 5. **E-mail** - Microsoft 365 (an Entra app registration with the application permission `Mail.Send`, sending as the From mailbox), Azure Communication Services or SMTP for verification, reset, invitation, alert, usage-report and support-ticket mail; the first transport set wins in that order. Without a transport every message waits in the console's *Mail* page; nothing is lost. 6. **Models and learning** - the self-hosted model server (Ollama, CPU or serverless GPU; on by default, it answers every tier), an Ollama Cloud key for the frontier open weights, Azure OpenAI deployments (off by default), the autopilot (retrain the routing model from your own feedback) and the marketplace catalogue refresh. 7. **Sign-in and access** - password sign-in, self-serve signups per IP (0 = operators create every workspace), SSO providers, a static admin token for scripts, public `/metrics`. 8. **Images and billing** - the release to deploy and the registry to pull from (yours, after mirroring), Stripe for self-serve paid plans. 9. *Review + create*. A cluster-mode deployment takes about ten minutes; the first Ollama start pulls about 16 GB of weights in the background. The deployment's **Outputs** tab lists `webUrl`, `platformUrl`, `adminLoginUrl`, `apiUrl`, the hostnames and static IP for your DNS records, the `asuid` verification id and, when enabled, the Azure OpenAI endpoint. ### First sign-in 1. Open `adminLoginUrl` (`/platform/admin/login`) and sign in with the operator username and password from Basics. The console shows the deployment's health, users, workspaces, plans, providers and the support desk. 2. *Providers*: the Ollama model server the template started is connected and every tier (`llm-small`, `llm-mid`, `llm-frontier`, `llm-onprem`) and specialist target already executes on it - Qwen3.5 4B on a CPU profile, the dedicated-node models (GLM-4.7-Flash, gpt-oss-20b) on a dedicated profile, gpt-oss-120b / DeepSeek-V4-Flash through Ollama Cloud when a key was given. Add OpenAI, Azure OpenAI, Anthropic, Bedrock, Vertex, vLLM or any OpenAI-compatible endpoint here, or let workspaces bring their own keys. 3. Open `webUrl`, *Sign up* (or create the workspace from the console when self-serve signup is off), create an API key and route a request - [platform quickstart](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/QUICKSTART_PLATFORM.md) with `OSR_API_URL=`. 4. `osr login --url ` signs the command line in to your deployment. ### Custom domain (two runs) 1. First run with your hostnames entered and *Issue TLS certificates* off: the apps bind the hostnames without TLS. 2. Create the DNS records from the outputs: `CNAME -> webHostname`, `CNAME -> apiHostname` (an apex domain gets `A -> staticIp`), and `TXT asuid. -> domainVerificationId` for each hostname. If the template created the zone, delegate the domain to `dnsNameServers` instead - the records are already there. 3. Run the deployment again (*Redeploy* on the deployment, same values) with *Issue TLS certificates* on. Azure issues free managed certificates and the hostnames answer over HTTPS. ### Upgrade, backup, remove - **Upgrade**: redeploy with a newer *OpenSmartRoute release* (image tag). The database schema migrates itself at start-up - the same numbered ledger, pre-upgrade backup on the data share (`backups/pre-upgrade-*.jsonl.gz`) and downgrade rules as under *Operate* below; state lives in PostgreSQL and on the data share, never in the containers. When an upgrade replaces the database container itself, the new replica waits for the previous one to shut down before it opens the database (Container Apps runs both for a moment); expect the API to pause for up to a minute. - **Backup**: a nightly job writes a logical database backup to the deployment's backup share (14 days kept). Managed state adds point-in-time restore on the server. Restore: load the newest archive into a fresh database with `psql`, then restart the API. - **Remove**: delete the resource group. Nothing is left outside it. ### Sizing and cost (Azure list prices, rough) | Configuration | Monthly Azure cost | Suits | |---|---|---| | Community, cluster mode off, Azure Files state | ~40-70 USD (Container Apps consumption, storage, Log Analytics) + model usage | Trial, a team | | Enterprise, cluster mode, Azure Files state | ~150-250 USD | Production without SLA requirements | | Enterprise, cluster mode, managed state (B1ms PostgreSQL, C0 Redis, 1 TU Event Hubs) | ~250-400 USD | Production with backups, SLAs, HA options | | + Ollama on serverless GPU (T4) | pay per second of GPU while replicas run | Private / specialist models without cloud keys | Model usage runs on the self-hosted Ollama apps (part of the Container Apps figure; a serverless GPU is billed per second while replicas run) and, when you connect them, on Ollama Cloud or a closed-model provider at their own prices; the dashboard's *Savings* page shows what routing saved against always calling the frontier model. ## Your own servers (Docker Compose) Runs on any host with Docker Engine 24+ (Linux, or Docker Desktop for a workstation): on-premises, air-gapped, or a VM in any cloud. Minimum 4 vCPU / 8 GiB / 40 GB disk for the platform; add what your models need if you run them on the same host. ### 1. Get the stack Download the Compose bundle of the current release - `docker-compose.yml`, `.env.example` and the Ollama overlays in the layout this page uses - and unpack it: ```bash curl -fsSLO https://opensmartroute.ai/download/compose # opensmartroute-compose-.zip unzip opensmartroute-compose-*.zip && cd opensmartroute-*/ cp platform/.env.example platform/.env ``` The bundle's `.env.example` already names the images of its own release; the stack runs from the published images and needs no source. ### 2. Configure Edit `platform/.env`: the passwords and the session secret (all of them - the defaults are placeholders), the public URLs of the web app and the API as your users will reach them, the release images, and the e-mail transport. Everything is documented in the file; the same variables are explained in platform/README.md (`platform/README.md`). ### 3. Start ```bash docker compose -f platform/docker-compose.yml --env-file platform/.env pull docker compose -f platform/docker-compose.yml --env-file platform/.env run --rm api python -m osr_platform.app --check docker compose -f platform/docker-compose.yml --env-file platform/.env up -d curl -fsS http://localhost:8080/readyz # every check ok once PostgreSQL is up and the schema is created ``` The `--check` line is the configuration preflight: it reads `.env` the way the API will and lists what is still a placeholder or inconsistent - the shipped passwords, a session secret missing on a multi-replica stack, public URLs still on `localhost`, e-mail confirmation required without a mail transport, a providers file that is not in the container - each with the variable that fixes it, and exits non-zero on an error. The same findings are logged at start-up and shown on the console's *Health* page. Web `http://localhost:3000`, operator console `http://localhost:3000/platform/admin/login` (the operator username and password from `.env`), API `http://localhost:8080/api/v1/info`. `OSR_API_IMAGE` / `OSR_WEB_IMAGE` in `.env` name the release images; a checkout of the source can leave them empty to build locally (`up -d --build`). **Just the router with a dashboard?** `platform/docker-compose.minimal.yml` starts four containers - PostgreSQL, Redis, one API process serving every domain, the web app - with `OSR_PLATFORM_PROFILE=minimal`: accounts, keys, routing, the OpenAI-compatible `/v1` proxy, MCP, billing and the console, and none of the jobs a hosted deployment runs for itself (blog writer, newsletter, growth engine, marketplace harvest). No Kafka, no separate SLM trainer. The same `.env` applies; switch to `docker-compose.yml` later without migrating anything - both stacks use the same database schema. ### 4. Connect models The stack has no cloud account. Either connect providers in the console under *Providers* (any OpenAI-compatible endpoint: OpenAI, Azure OpenAI, Anthropic through a gateway, vLLM, Ollama, ...) or start the on-prem model server next to it - the `llm` profile of the same Compose file - and point the router at its providers file: ```bash # in platform/.env: # COMPOSE_PROFILES=llm # OSR_PLATFORM_PROVIDERS=/config/providers.ollama.yaml docker compose -f platform/docker-compose.yml --env-file platform/.env up -d # on an NVIDIA host add the GPU overlay: docker compose -f platform/docker-compose.yml -f deploy/compose/ollama.gpu.yaml --env-file platform/.env up -d ``` The `ollama` service pulls the curated open weights of deploy/compose/providers.ollama.yaml (`deploy/compose/providers.ollama.yaml`) (Qwen 3.5, Qwen2.5-Coder, GLM-OCR, TranslateGemma, DeepSeek-R1, a Qwen3 embedding model; `OSR_OLLAMA_MODELS` trims the list on a small machine) and that file maps the private / specialist targets to it - `deploy/compose` is mounted at `/config` in every platform container, which is why the path above works. `OSR_PLATFORM_PROVIDERS` points the API at a providers file for anything else. ### 5. Put it behind TLS Terminate TLS in your reverse proxy (nginx, Caddy, Traefik, an ingress) in front of ports 3000 (web) and 8080 (API), set `OSR_PLATFORM_WEB_URL` / `OSR_PLATFORM_BASE_URL` to the public `https://` origins, and remove the host port mappings you do not want exposed. Several API replicas share PostgreSQL / Redis / Kafka: `docker compose up -d --scale api=3` behind the proxy, exactly what the Azure template does. ### Operate - **Backups**: `docker compose -f platform/docker-compose.yml exec postgres pg_dump -U osr osr | gzip > osr-$(date +%F).sql.gz` (and `osr_telemetry`); restore with `psql` into a fresh volume. Without `pg_dump` at hand, the API container does it from its own connection: `docker compose ... run --rm api python -m osr_platform.maintenance backup /data/backups/osr-$(date +%F).jsonl.gz` writes every row of every table as one gzip file, `... restore --yes` (API stopped) empties the tables and loads it back in one transaction. - **Upgrade**: set the new tag in `.env`, `pull`, `run --rm api python -m osr_platform.app --check`, `up -d`. The schema is a numbered ledger (`schema_migrations`): the new release applies the migrations it knows and the database has not run yet, in order, and records each with the release that wrote it - `python -m osr_platform.maintenance schema` shows the ledger, applied and pending. Before a pending migration that is not additive runs on a database that already holds data, the API writes a backup to `/backups/pre-upgrade--