Changelog
Release notes for every version.
All notable changes to the OpenSmartRoute platform, SDK and apps are documented here. The format follows Keep a Changelog; versions follow SemVer.
These notes are written for the people who use the product: what changed, what it means for you and what, if anything, to do. The engineering detail lives behind each release's diff link. A change that answers a customer's request ends with Requested by customers - if you asked for something, this is where you see it land.
Unreleased
2.1.0 - 2026-10-15
Added
-
The loop closes: prompt versions with their numbers, answers screened on the way out, and the scores other evaluation tools compute come back. Every prompt version now shows how it did - requests, cost, latency, the share of answers people rated good and their mean quality - so moving production to a new version is a decision with figures (the Prompts page). A workspace or tenant policy can screen every answer before the customer sees it (output guard: flag, redact or block leaked keys, personal data and injected instructions; streamed answers are held until screened; the finding rides on the answer, the header and the usage row). Scores from Ragas, DeepEval, Langfuse, TruLens or Arize on a downloaded dataset upload back, appear as an imported-scores run and become outcomes on the logged requests they grade.
-
Prompts out of the code, and traces into your observability tool. A workspace prompt registry keeps the instructions requests use as immutable versions deployed by label - move production to a new version and every request naming it changes, nothing else does; {{variable}} placeholders with defaults, chat prompts whose examples become the history, a preview with the variables filled in, and the version that shaped each request in its trace and on the response. Trace export adds Langfuse and OpenTelemetry destinations to the request-log export, so Langfuse, Arize Phoenix, Arize AX, TruLens or any collector shows every routed request as a trace with its generation, token counts, cost and your reported outcomes as scores. Evaluation datasets download in the shape Ragas, DeepEval and Langfuse datasets read.
-
Refer a team: give credits, get credits. Every workspace has a referral link (Refer a team in the dashboard: copy it, share it, or e-mail it with a line in your words). A team that signs up through it is recorded as your referral; once it has confirmed its address and made its first successful request, both wallets are credited - $5 to you and $5 to them by default, as settings an operator changes at run time, with a cap per referrer. You see the teams you invited by initials only; a team that came through a referral sees who invited it and when its welcome credit arrives. Self-referrals and second accounts do not count, a workspace is referred once, and every credit is idempotent across replicas. Operators follow the programme on the console's Referrals page: who invited whom, what qualified, what was paid.
-
The registration bot that mints an address per account is refused on sight. Nine "Hermes 57ffe3"-style accounts arrived in a day, each from a fresh random subdomain of a temporary-inbox host (
q3ztzslrq8-7@we7d6.cc.cd), so no domain rule caught up. The signup guard now scores the shape of a registration - digits woven into the address, a letters-and-digits subdomain, a word-and-hex name - and refuses what adds up to a machine (block_generated, on by default;tom4ever@gmail.compasses);cc.cdjoins the temporary-inbox list and the per-domain daily cap counts by the registered domain, soa.cc.cdandb.cc.cdare one registrant. On the Users page, Block their e-mail domains and Block their addresses clear a page of spam in one move - a blocklist rule per registered domain or address and the users disabled - lifted again on the Access page. -
The routing model is measured on wording it never saw. A new held-out set (
examples/eval_heldout.jsonl, 117 everyday asks that name every target of the reference catalogue) scores the bundled routing model and the router on phrasing that is in none of their training data, and the SDK's test suite keeps the model from shipping if it falls below the bar or makes the router worse there. The first measurement was the point: the shipped model routed the labelled set 70/70 and these rows at 0.49 - below the router without it. The trainer prints the held-out score and the model file records it (meta.heldout). -
The routing model learns on a real embedding model.
OSR_SLM_EMBEDDER=openai:<model>@<base_url>adds any OpenAI-compatible embeddings endpoint to the routing SLM as frozen dense features - the embedding model your deployment already serves, Azure OpenAI or OpenAI - with no extra to install; the SLM's head then learns on what a sentence transformer knows a prompt means while the hashed features keep the surface cues. The Azure and Compose stacks point the SLM service at the deployment's own embedding model by default, so nothing leaves the environment; the promoted file names the embedder and every replica rebuilds the same client, and a request the endpoint cannot embed in time is scored by the other strategies alone (OSR_SLM_EMBEDDER_API_KEY_ENV,OSR_SLM_EMBEDDER_TIMEOUT_S). The packaged model stays dependency-free. -
Everyday phrasings for every task type.
signals.corpus.NATURAL_PROMPTSgives each of the twenty-five task types a few dozen ways people really ask - terse chat, office English, pasted context, typos, a second language - and the synthetic corpus (synthesize_dataset,synthetic_rows) emits them next to the templates, so the signal classifier and the routing model learn wording the lexicon never produces. -
A caller can name the task.
context["task_type"]on a request (an ontology type -translation,document_intelligence...) overrides the lexicon's reading of the actions (signals.TaskHintSignal,apply_task_hint): a form that knows it collects a translation routes as one whatever the person typed. -
Who may sign up: a blocklist, a temporary-inbox policy and a bot trap. Operators can refuse registrations from an e-mail address or a whole domain (subdomains included) with a reason and an expiry, on every door - the sign-up form, sign-in with a provider, a change of address and SCIM provisioning. A policy refuses well-known throw-away inboxes (on by default),
+tagaliases, addresses outside an approved list of domains, and more sign-ups from one domain a day than you allow, freemail excepted. The form carries a hidden field only bots fill, can ask for a Turnstile or hCaptcha check, and an address refused too often in an hour is blocked for a day. The Access control page shows the week's refusals by reason and domain, with block it and a would this address get in? check; the log keeps a hash of the address, never the address. -
The response cache now catches rewordings, and the policy dialog edits everything. With
response_cache_mode: "similar"a chat request that asks the same question in other words - a capital letter, a comma, a typo, a "please" - is answered from the answer you already paid for, as long as the model, the earlier turns and the options match and the two questions are at least as alike as the threshold you set (response_cache_similarity, default 85%); the hit says so ("match": "similar",X-OSR-Cache-Similarity). It is surface similarity, not meaning, so the threshold is yours to place. The policy dialog gains the cache mode and a Providers block - try first / only / never, tie-breaker, price ceilings, no data collection, zero retention only - so no policy key is "set through the API" any more. -
Access control, announcements and four-eyes approvals in the operator console. Access control blocks an address or range with a reason and an expiry, pauses customer traffic for maintenance - reads can keep working while writes and routing wait, operators and the status page are never blocked - and revokes API keys across workspaces by filter, with a dry run first and a reason on the record. Announcements put a notice above the dashboard for everyone, for the workspaces on chosen plans or for named workspaces, with a window, a severity and a link, dismissible per person or not, and can open an in-app notification in those workspaces. Approvals make the sensitive actions you name - deleting a workspace, changing its plan, an emergency revocation, the maintenance switch - wait for a second operator, who approves or rejects them with a note; both names end up in the audit log.
-
Personal and health data, decided before any model sees it. The new
data_protectionpolicy - per workspace or per tenant - says what happens to a request carrying personal or health data: detect (today's behaviour: only targets allowed to see it may answer), mask (every value becomes a labelled placeholder such as<EMAIL_1>or<MRN_1>in the turn and the history, so the request may run anywhere; targets allowed to see the data still get the originals, and the answer - streamed too - comes back with the values restored unless you say otherwise), block (refused before any spend, naming the kinds found, never the values) or off. The detector now knows medical record, NPI, DEA, Medicare and insurance numbers, ICD-10 codes and dates of birth next to e-mail, phone, card, passport and national ids.X-OSR-Data-Protectionsays which mode acted; the usage row keeps the kinds found, never a value. -
Two more key limits, and request ids that reach the provider.
tokens_per_minutecaps what one key may send and receive in a sliding minute, charged with the request's token bound before any provider is called, so a burst is refused rather than billed;allowed_ipspins a key to the addresses or CIDR blocks it may be used from - the address past your proxies, never a header the caller wrote - and refuses the rest with403. TheX-Request-Idyou send (or the platform's own) and your W3Ctraceparentare now forwarded to the provider that answers, so one id follows a request from your logs through the platform into the provider's; the chat endpoint now keeps your request id the way/api/v1/routealways did. -
Zero data retention as a provider preference.
zdr: truein a request's provider preferences (or the workspace's defaults) uses only endpoints whose provider has declared that it keeps nothing - an endpoint with no stated data policy is skipped, the provider has to say so. -
The reseller's desk, and keyless Azure.
GET /api/v1/admin/offers/deskputs every offer's two prices side by side - what the deployment pays the provider per million tokens (a contract row when there is one, else the list price) and what a workspace on the public tariff is charged - with the margin per unit, the week's requests, realised cost, charge and margin, and a list of the offers that lose money. A provider's credential may beidentity://https://cognitiveservices.azure.com: no key at all, the platform's managed identity mints the token for Azure OpenAI and Azure AI Foundry on every refresh; the console offers it as a preset, next to a new Hugging Face Inference Providers preset. -
The dashboard pages behind this release's APIs. Everything below that shipped as an endpoint now has its screen. MCP servers in the sidebar: connect a server, pick its approval mode, see its health and its tools as the router sees them for your key, sync, disable or remove it. Governance -> Data: the response cache (entries, hits, the window, Clear) and the request-log export (destinations, rows sent, Export now, pause, remove). Evaluation -> Kept datasets and Answer judge, with Add to dataset and Judge this answer on a kept request's row in Activity.
-
The policy and key dialogs show every setting the API takes. The policy dialog gains How requests are answered - model aliases, the response-cache window, conversation stickiness, the default objective and the answer judge - and the key dialog gains the headers every request must carry and the MCP tools a key may reach, both shown on the key afterwards.
-
Operators see what a workspace connected. The console's workspace page has a Connected beyond providers card - the workspace's MCP servers with health and approval, its request-log export destinations with rows sent, the response cache in force and what the answer judge graded this week - and prints the workspace policy in words instead of raw JSON.
-
Fair share on the Governance page. On a deployment that runs fair share across tenants, Governance -> Controls shows the window and the soft / hard multiples, how many requests were steered to cheaper targets or capped, and each tenant's requests and dominant share - the figures the API already returned and no page showed.
-
The console does what the admin API allows. An open incident can be edited in place (title, severity, components - the banner and the feed follow) instead of being closed and reopened; every price-book version has What it froze, the prices and rules the version pinned and the raw snapshot, so a disputed charge is read against the rules in force when it was computed; the workspace page's traffic card switches between 7, 30 and 90 days. Each was an endpoint the API served that no page used.
-
A VS Code extension page. /vscode says what the panel shows for a selection, the four commands, what is sent and what never is, and installs from the Marketplace, Open VSX or the .vsix - or says plainly that this deployment has not published a build yet. In the Product menu, the footer, the sitemap and the downloads chooser; the models page now leads on to the rankings, the status page and the trust centre.
-
Your own MCP servers' tools in the routing pool. Connect the MCP servers your team already runs - a ticketing server, a database agent, a vendor's hosted server - on the workspace's MCP servers API and their tools become routing targets named
server:tool: a chat completion or a decision may pick one the way it picks a model, under the same policy, trace and metering, and a plan may give one a tool slot next to the model that answers. An approval mode per server says what runs by itself (auto, read only - only tools the server marks read-only -, manual - listed and ranked, never run), themcp_toolskey limit narrows what one API key may reach, tool descriptions that read like instructions to the model are dropped, and the tool list is kept so routing never waits on the server.GET|POST /api/v1/workspace/mcp-servers,.../{id}/sync,.../{id}/tools. -
An answer judge: the grade becomes the outcome. Turn on
judgein the workspace policy and a reproducible share of the answers your users receive is graded by a model of your choosing - 0 to 10 with a reason - after the answer has left. The grade lands where a hand-reported outcome lands, so the learners, the rankings and the replay comparison use it without knowing the difference, every verdict keeps its reason onGET /api/v1/evaluations/judge, and Judge this answer grades one kept request on demand. Judging is a metered call of its own, bounded bymax_per_day, never charged to the request it grades. -
The Google Gemini API on the same key.
POST /v1beta/models/{model}:generateContent,:streamGenerateContentand:countTokensserve the Gemini API the Google GenAI SDKs and the Gemini CLI speak - contents, system instructions, function declarations, images, streaming - over the routed chat path, withx-goog-api-keyaccepted as the key and Google's error envelope.modelisautoor any target, as everywhere else. -
A response cache for identical requests.
response_cache_ttl_sin the workspace policy answers an identical chat request the workspace already paid for from the store - zero tokens and cost on its row,X-OSR-Cache: hiton the response - for up to seven days; a caller shortens, bypasses or opts an answer out per request,GET /api/v1/cacheshows what the hits saved andDELETEempties it. -
Model aliases, session affinity and a project tag.
aliasesin the policy maps the model names your clients already send to a target, a catalogue model, an offer or a preset, so a code base moves to the router without a search-and-replace;session_affinitykeeps a conversation on the target that served its previous turn while that target stays healthy and allowed;X-OSR-Projecton any request is recorded on the usage row and broken out in the usage summary asby_project- a cost centre without a tenant. -
Keys that demand headers, and a PagerDuty channel. The
required_headerskey limit refuses a request that does not carry the headers you name (a ticket id, a cost centre) with428; apagerdutynotification channel opens one incident per alert episode and resolves it when the alert clears. -
Rerank, repaired JSON and the answer's cache.
POST /v1/rerankorders documents against a query in the Cohere / Jina shape from any embeddings provider; an answer requested as JSON that a model left almost right - a fence, a trailing comma, a bracket cut bymax_tokens- is closed with the smallest edit (opensmartroute.json_repairedmarks it), the missing suffix sent as one more delta on a stream; calls to Anthropic now carry prompt-cache breakpoints on the tool list, a long system prompt and the conversation prefix, so agent loops pay cache-read rates for what they resend, and the cached token counts come back inusage. -
Datasets from production, and a build gate. Add to dataset saves logged requests - by id, or a window filtered by outcome and target - as a kept evaluation dataset, the target that answered a good outcome as its label, downloadable as the JSONL
osr evalreads and evaluable again on today's pool (/api/v1/evaluations/datasets). The repository ships a composite GitHub Action and a pasteable workflow that fail a build when routing accuracy drops below a floor, locally or on the hosted workspace. -
Provider credentials by reference, request-log export, and a mock provider. A provider key may be
keyvault://<vault>/<secret>(read with the container's managed identity when the client is built, cached five minutes, shown whole in the console) orenv://NAME, so the secret never enters the platform database. A workspace exports its request log continuously to its own storage - an Azure Blob container, or any HTTPS endpoint as JSONL batches (Splunk, Datadog, a Kafka proxy) - with a cursor, optional payloads and Export now (/api/v1/workspace/log-export).{"kind": "mock"}in the providers file is a provider that answers deterministically without a network, streams, embeds and fails on cue - for tests, demos and automated builds. -
osr runandosr migrate.osr run claude-code(Codex, the Gemini CLI, aider, OpenCode; Cursor, Continue, Zed, LibreChat and Open WebUI through their settings) launches a coding agent with the router as its model endpoint and the saved sign-in as its key -/integrationson the site has a page per tool.osr migrate litellm config.yamlturns a LiteLLM proxy configuration into a catalogue, a providers map and the aliases that keep callers' model names working, and lists what is left to do by hand. -
Two pages and a figure. /compare/bifrost places the router next to Maxim AI's Bifrost gateway on the same documentation-review method as the other comparisons; /shadow-ai speaks to the team whose company data goes into AI tabs nobody governs; /benchmark now prints the routing overhead - single-digit milliseconds per decision with every strategy on, held there by the build.
-
A frontend-design playbook with the design gap register. The osr-frontend-design skill describes the web app's design system as built - tokens, type scale, material, icons, motion, themes - the instruments that check a page against it, and a register of the open design gaps measured on the current build (over-long page descriptions, an unbalanced console navigation, duplicated icons, raw colours outside the kit, no page search in the console) with the evidence and the check that proves each one closed.
-
A migration page: change one URL, keep your code. /migrate shows, for each client a team already runs - the OpenAI Python and Node clients, the Anthropic SDK, LangChain, the Vercel AI SDK and plain HTTP - the call as it is today next to the same call pointed at the router, with the one-line diff a reviewer would write. Below it: what changes in the answer (the model that answered and the
opensmartrouteblock), what stays the same, what you gain and how you roll back, the three commands that verify the first routed request, and how candidates, weights and limits ride along in the request. Linked from the home page's third step, the Developers menu and the footer. -
Shadow routing: try a policy on your live traffic before you serve it. Start a candidate on the Evaluation page - different weights for quality, price and speed, targets it must not use - and every request your workspace routes is routed a second time under it, inside the same pool and limits. Nothing from the candidate is served, executed or charged; what you read is the agreement between the two decisions, the spend delta, the quality and latency estimates, where traffic would move and what the candidate would have refused, with a plain-words verdict once a few dozen requests are in. Promote writes the candidate into the workspace policy - and because that is a policy change, every quality gate you keep runs again on it.
GET /api/v1/shadow,POST /api/v1/shadow,POST /api/v1/shadow/promote. -
A default objective in the workspace policy.
objectivein the policy (weights forquality,cost,latency,quality_floor) is the objective of every request that sets none; a request's own objective still wins. It is what promoting a shadow candidate writes, and it can be set by hand like any other policy key. -
A pilot, as a page and as a request. /pilot describes the 2-4 week pilot the way the charter does - the baseline finance signs, a week in shadow, a canary share, the ramp, and success criteria the product measures itself - and Talk to sales has a pilot option (
interest: pilot), prefilled from the page. -
A compatibility matrix. One page lists every model provider, client, agent framework and adapter the router connects to, how, and how each connection was verified - by the tests on every change, by a dated live run, or by the OpenAI-compatible protocol alone. A test holds the page to the code, so a new provider preset or adapter cannot ship without its row.
-
A privacy data-flow and retention review. The security review pack gains a section that names every store of personal data on the hosted platform, where it leaves to (model providers, mail, Stripe, identity providers, the GeoIP service, analytics) and how long each store is kept, with the defaults held to the code by a test; its two open findings are listed with it.
-
Operators manage the self-hosted model servers from the console. A new Model servers page under Platform lists every on-premises model server the catalogue points at - whether it answers, the engine and version it runs, what sits in memory, what is pulled but idle and which targets map to each model - and lets an operator pull a new model (progress shown while it downloads), warm one into memory, unload it or remove a model nothing routes to, with every action in the audit trail. The same is available over the admin API for scripts. The on-premises model server itself now reads every model the Ollama library publishes (some carry per-layer settings as lists) and waits long enough for a slow reasoning answer instead of cutting it off at five minutes.
-
The notices that were still missing. A fresh set of two-factor recovery codes sends a security note (the old ones stopped working); the owners hear when what an API key may do changes - its scopes, budgets, rate or allowed targets, in plain words, the secret untouched - and when a member leaves by themselves; every member, the one who did it included, hears when an owner deletes the organization and that their own workspace is untouched. Every one of them sits in the console's mail gallery, reads at an eighth-grade level and can be sent to yourself first.
-
Nothing waits or breaks unannounced. A request the router handed to a human queue now reaches the owners by e-mail when no channel listens for hand-offs - the request's first lines, why a person was chosen, how many wait, the link to answer - at most once an hour each. A long-lived API key with an end date announces itself a week before it stops working, once, with the date in the owner's time zone and what to do about it.
Changed
- The routing model learns from the router, not from the capability fit alone. The synthetic corpus can now be labelled by the reference ensemble - rules, capability fit, cost and quality priors together (
synthetic_rows(router=...), the bundled trainer's default) - where the capability fit alone left near-ties between generalists that sent a quarter of the everyday prompts to the on-prem model. The bundled model is retrained on that corpus plus the multicloud benchmark prompts, and a fifth of the everyday phrasings are held out of its probe so its temperature is fitted on unseen wording: it no longer answers at p=0.9 while wrong. - The routing model speaks as loudly as it is right. In the ensemble
SLMStrategyreports its calibrated top probability as its confidence (the old term saturated at 1.0 for any trained model) and scales it by its measured held-out skill when the file carries one. - The action lexicon reads more of how people write. Self-harm, threats, harassment and "put me through" are escalations; a screenshot, a photo of a receipt or a whiteboard, "I attached the PNG" are documents to read, not images to draw; "read this aloud", "an mp3", "a calm voice" are speech; "transcript", "podcast", "who said what" are transcription; "sql", "write a query", "the repo", "open a PR" are code; "current weather", "who won", "official docs", "give me the link" are web searches; "executive summary", "condense", "main themes" are summaries; "cover letter", "thank-you note", "help me reply" are writing. On the held-out set the router without the model went from 0.66 to 0.84; the labelled set stays at 69/70.
- The self-hosted models cost less and answer as fast. On a dedicated CPU profile the deployment now packs models that fit together onto one always-warm server per node (
ollamaNodeGroups,OSR_OLLAMA_NODE_GROUPS): every model stays resident and preloaded in its own runner, so a short OCR or embedding call runs beside a long reasoning answer instead of waiting for it. The default keeps the two 22 GiB models on nodes of their own, groups the reasoning, translation, OCR and embedding models on a third, and leaves the busiest writing model its own replica that scales out on bursts - three nodes and one replica where there were four and four, about 1,500 dollars a month less for the same warm models. The web and platform apps are sized to a week of measurements, and model servers a deployment no longer declares are retired after it (OSR_OLLAMA_PRUNE=falsekeeps them). - Database storage without a per-write bill.
OSR_STATE_FILES_PREMIUM=truekeeps the PostgreSQL, Kafka and Redis data on a Premium file share account - billed per provisioned gigabyte, no transaction meters, lower latency - and a guided script copies the data across with the databases stopped before the switch. The container registry now purges untagged images and tags older than thirty days every week, keeping the three newest of each image to roll back to. - The quality floor is a floor. A request whose
quality_floorno candidate reaches is refused with every candidate's quality in the rejections - or served by the configured fallback target - instead of quietly getting the least-bad candidate. Multi-round escalation keeps your own floor: when its raised floor finds nobody, the step takes the best candidate under yours rather than ending the trajectory. - Routing overhead, measured again and held there. The published figures are today's: 4.6 ms p50 with the default strategies and 7.4 ms with every learner on the 27-target example catalogue, and from now on every change is measured before it ships - the overhead cannot drift up unnoticed.
- The models page reads as one table again. The routing-targets view fits a laptop screen without sideways scrolling: the kind sits under the target's name, a Status column says answers here or decision only in words, and a Runs as column names the model behind the target and the endpoint that serves it (
qwen3.5:4b via ollama-qwen3-5-4b) where it used to print raw provider labels for some rows and vendor names for others. Latency no longer wraps mid-unit and is marked measured or declared; Fastest is the lowest latency measured here over the window, so the strip cannot award it to a model that took two minutes to answer. The hero says in two sentences what the page is, and its figures are the deployment's own: targets, how many answer here, requests routed.
Fixed
- The confirmation link finishes. Opening the e-mail confirmation link in a browser that was signed in could leave the page on "Confirming your email…" for good: the address was confirmed on the server, but the session loading in the background re-ran the step and threw the answer away. The page now holds on to its one request and shows "Email confirmed" with the way to the dashboard.
- An unconfirmed address personalises nothing. Until the e-mail address is confirmed a session and the workspace's keys are refused everywhere but the confirmation step - the REST API, the OpenAI-compatible
/v1proxy and the MCP server alike. The public endpoints that personalise their answer for a key (the quote at/api/v1/estimate, the site assistant) used to recognise an unconfirmed key and give it the workspace's limits; they now treat it as no key at all. - Brand colours no longer serve as text on their own tint, and every card heading sits under the page title. The accessibility audit measured brand violet and brand blue on their own badges at 4.42 and 4.28 - under the 4.5 text floor in the light theme - so the badge kit, the model and vendor pills, the marketplace chips, the price-trend badge, the business summary and the lettered vendor marks now use the darker text twins of both colours (5.6 and 5.5), and pink, sky and rose tones the dark theme never remapped become themed red and blue. A card title is an h2 by default, so every dashboard and console page reads h1 then h2 instead of skipping a level (147 cards), and an icon in a flex row keeps its size next to a long label on a phone. The design guard now flags brand-as-text pairings and any hue the themes do not remap.
- Throw-away stacks register their scripted users again. The signup guard's generated-address score (digits woven into the address, long local parts, consonant runs) refused the addresses the end-to-end suites mint on a reserved testing domain, at random depending on the timestamp. On a deployment that accepts those domains (
OSR_PLATFORM_SIGNUP_TEST_DOMAINS=true) the shape score is skipped for them alone; every other rule, and every real domain, is judged as before. - Saving the policy no longer wipes what the form did not show. The policy dialog sent only the eleven constraint fields, so a promoted shadow objective, the model aliases, the judge and the cache window were silently removed by the next edit of a budget or a deny list. The dialog now edits those keys itself and carries the rest (provider preferences, data protection) through a save untouched.
- The status page no longer announces an outage over a board of green lights. The headline is the platform's own verdict from its sampled components; a failed probe from the visitor's browser (a rate limit on a busy page, a blip on the way) shows as a note under the headline and only replaces it with "not answering" when the board on screen is itself minutes old and cannot be refreshed. A model endpoint the deployment has retired drops off the board as soon as its last check is stale instead of sitting there as no longer configured / No data yet for a day (a day's grace remains only while the sampler itself is silent), and a group's badge counts the rows that are operational, not every row.
- One platform version in every footer. The Platform badge is the release on every page - the static documentation pages and the request-rendered marketing pages read the same number from the first byte, where the docs showed
v2.0.0beside a marketing footerv2.0.1-preview.49- and a deployment running ahead of its release names the build in its own developer preview 2.0.1-preview.49 badge. - Pay as you go in the plan comparison. The comparison table on the pricing page has a column for the prepaid plan - no monthly fee, no quota, tokens from credits, sign up and buy credits - next to Free, Pro, Team and Enterprise, where the plan appeared only as a card above the table.
- Pricing questions are in the page. The pricing FAQ is rendered as native disclosures, so every answer is in the HTML for search engines, reader mode and a browser without JavaScript, collapsed to the first question as before; the support assistant's header names what it does while it checks which model is on duty, and gives up on that check after eight seconds instead of staying on a placeholder.
- Three domain services were being killed a minute after every start. The providers, onboarding and billing services ran on half a gigabyte while every domain process - the whole API image - sits at 600-800 MB once warm; each was OOM-killed about a minute after starting, the revision never left Activating, the gateway timed out on their paths and the status monitor opened "not answering" incidents for them. They now get the same 1 GiB as their peers in the hosted deployment template.
- The pricing page and the platform guide quote the same enterprise overage. The plan card and the comparison table print the per-100k rate the catalogue carries for the enterprise plan (with or by agreement) where they used to say only by agreement.
- The web server's own calls to the API are in the operations telemetry. Every call a server-rendered public page makes to the API is filed as a dependency under its request id (one per cache refresh, not per visitor), and a call that got no answer or an error is also one line in the container log - so a page that rendered without its catalogue, rankings or statistics is seen from the web tier, where before only a browser's own calls were.
- A page that fails to render is seen by operations, and the person gets one line to act on. The error boundaries of the public site, the documentation, sign-in, the dashboard and the console swallowed the error before the browser telemetry could see it; each now files it with Application Insights under the page's operation, named by the boundary that caught it, and shows the same sentence everywhere - Reference … - quote it to support - where the reference is the one the server log carries. A dead address is filed as
page.not_foundwith the page that linked to it. - Four accessibility slips on the dashboard. The operator-view banner's secondary text and the unread-notification count now meet the contrast floor in both themes, a request row's expand control is a real button a keyboard can reach, and the controls chips on the Impact page are a proper list.
- Every page opens on one sentence, and the console is easier to find your way around. Each dashboard and console page now starts with a single sentence saying what it shows, with the method behind More about this page instead of a paragraph truncated mid-thought (37 pages). The console's sidebar is regrouped by the question an operator brings - deployment, customers, money, models and routing, content and growth, messages and access - with five to eight rows a group and a distinct icon per page, and its header search is now the command palette: type "margin" to land on Finance, or a name to search the records. Status colours that ignored the dark theme (a hand-picked green or amber on nineteen chips and dots) now follow it.
- Every dashboard and console page says what it is for. The sidebar tooltips and the dashboard's command palette carry a one-line plain-language answer to "what is this page for?" next to each label (Impact - cost saved, requests served and personal data kept in - the page to show your manager; Go live - the checklist a deployment passes before it serves customers), the palette matches on it, and both overviews end with a Where to go map of every page in the sidebar's order - so a newcomer finds Governance by typing "rules" and an operator learns what Offers or Syndication are without opening them.
- A replica leaving no longer spends its last seconds on tracebacks. On Container Apps a terminating replica loses its outbound network the moment it is signalled, so its background loops met "connection refused" from a database that was fine, waited out the eight-second "server restarting" ladder and logged a stack trace each - several times per rollout, across the fleet. The stop signal now stops the periodic loops at once and a reconnect attempted while the process drains does not wait.
- The deployment's own jobs name the provider they spent on. The editorial, growth and showcase writers and the support assistant recorded their requests without the provider, the upstream model or the token split - on the hosted deployment that was 94 % of the provider cost, unattributable to any provider in the Finance page and priced from a flat estimate. Their rows now carry the same fields as a customer's.
- Provider cost and customer charge come from the same tariff. When the provider price book prices a model, the usage row's
cost_usdis now the book's cost rather than the routing catalogue's flat per-token estimate - on the live path and when the repricing pass prices a row after the fact - so the margin the Finance page shows is the margin the books define (a model sold at list price plus markup had shown a negative margin against a higher estimate). - The same fact learned by two requests at once no longer fails the second. The knowledge graph wrote a fact as a delete followed by an insert, so two concurrent chats teaching the workspace the same thing raced into a duplicate-key error (logged, the chat still answered without the graph's context). A fact is now written in one upsert statement.
qwen3.5:4bstays on the Ollama image. The ollama.comqwen3.5:4bblob is an Ollama export that llama.cpp cannot read (threerope.dimension_sectionswhere the engine requires four), so on a deployment switched to the OpenSmartRoute model server every chat pinned to it -llm-small,llm-onprem,writer-small,support-agenton the default catalogue - failed to load the model and answered 503.ollamaModelImagesnow keeps that app on the Ollama image, like the four other blobs the pinned engine lacks.- Redacted request logs also mask credentials. With
log_payloads: redacted, a pasted API key, cloud or repository token or private key is replaced by a placeholder like the personal data beside it; before, only the personal data was masked. - The data export carries what the router remembers.
GET /api/v1/me/exportnow includes the workspace's conversations with their turns and its remembered facts (workspace.memory), which the privacy policy had promised and the export had left out. - The drawing behind a page is seen on every page. The status page and the long-form pages (support, privacy, terms) no longer paint the whole page opaque over it, and the alternating bands of a story page are a frosted tint of their colour rather than a solid cut-off; the tall "before" bar of the cost drawing is fainter so it never reads as a slab behind the copy. Under reduced motion the request journey's three scenes now show their resolved state (the redacted key, the ranking, the trace) instead of an empty pane; every line of small print on the pricing, security, services, live-facts and provider pages is capped at a readable measure; and a long provider name on the traffic drawing yields before its share on a phone.
- Small design corrections across the public site. The downloads table scrolls inside its frame on a phone instead of widening the page; the models explorer shows cards on a phone where the table could not fit; the live rankings fold targets with nothing in the window behind one Show n targets link instead of listing a wall of zeros; the model distinctions name the declared fastest model and show the observed figure beside it; the vendor strip says n models rather than a bare count; live counters keep their badge beside the figure; plan prices print as whole dollars; and the smallest print on the home page is no longer below the size the rest of the site allows.
2.0.0 - 2026-10-09
Added
- Use cases read as one arc. Each card on the use-cases index now tells the story a buyer wants in order - the problem, the routing strategy (the first rule), the models it routes between, what changes - and ends on what a month of such requests keeps, from a live quote of a request of that kind; the quotes go out one at a time so six cards never trip the public rate limit, and a kept share is never rounded up to a full hundred.
- The pricing page says which plan fits. A calculator under the plans takes a monthly volume and names the cheapest subscription whose quota covers it - or the plan with overage, or sales once every self-serve plan would run over - with the month's fee, the seats and keys it buys, and every other plan priced at that volume (a hard cap struck through; pay as you go listed by the token, since it has no fee to compare). Beside it, a live quote from the public catalogue projects what routing keeps at that volume and the net after the fee.
- The ROI calculator starts from your own ledger. Signed in with routed traffic, the calculator fills itself from the workspace's last thirty days of savings - the baseline cost projected to a month as the spend, the measured saving as the rate, every request eligible - and says so, with a way back to the example workload. Without a ledger the example stays, marked as such.
- Your own model server. The platform ships its own model host: open-weight models on your hardware - CPU or NVIDIA GPU - behind the Ollama and OpenAI APIs (chat, completions, embeddings, Responses, Anthropic Messages), so every client and provider preset works with a base-URL change. It pulls from ollama.com and Hugging Face into Ollama's own on-disk store (an existing store is served as-is), loads a model only when its memory footprint fits and never evicts a busy model for a cold one, admits as many generations as a model has slots and answers the rest with
503and a retry hint, applies a model's system prompt and parameters, and exposes metrics per model. The Compose stacks run it as thellmprofile; the Azure template's model apps take it throughOSR_OLLAMA_IMAGE. Guide: docs/MODELS. - The product is the picture behind every page. The public site no longer leans on a wash of colour alone: behind each page the router is drawn large and faint - requests entering, the router reading them, the candidates fanning out with the pick on a lit wire - in one of six families chosen by what the page is about. Pricing, ROI, the estimate and the comparisons stand on a quality-against-cost chart; observability, status and rankings on a span waterfall and a latency wave; security, trust and the legal pages on a request descending through identity, policy and the gateway; agents, MCP and the marketplace on a supervisor and its agents; enterprise, solutions, vendors and downloads on a mesh around the router; the reading pages on a quiet grid. It follows the theme, keeps the copy quiet, recedes as you scroll and holds still under reduced motion.
- The playground says why, strategy by strategy. Under the chosen target a Why this target card lists every strategy that voted - your rules, capability match, similar past requests, what was learned from outcomes and from context, conversation state, difficulty fit, live health - each as a bar against the best score any candidate got from it, with the strategy's own words; the alternatives show their utility gap and the strategy each one lost on, and the refusals are grouped by cause. Every number is in the decision the router returned.
- The model catalogue awards four distinctions. A strip above the explorer names the language model with the highest quality prior, the best value (the highest prior at or below the catalogue's median price), the cheapest per token and the fastest (observed where there was traffic, declared otherwise), with the figure behind each; the same badges sit on those models' rows and cards. Embedding, transcription and speech models never compete - they do not answer.
- Sign-ins say where they came from, and a new country is announced. Every browser session and account event now records the place behind its address - Lisbon, Portugal - when the deployment resolves places from a country header its ingress sets (
OSR_PLATFORM_GEOIP_HEADER) or a geolocation service (OSR_PLATFORM_GEOIP_SERVICE, a preset or your own URL template;OSR_PLATFORM_GEOIP_TOKENfor its key); both are also under Runtime configuration, private addresses are never looked up and a lookup never holds a sign-in for more than two seconds. The new sign-in notice now also goes out for a sign-in from a country none of the account's recent sessions came from, even on a known device, and names the place; under Sign-in alerts on the account page a person can ask to hear about every sign-in. Guide: docs/PLATFORM Sign-in locations and alerts. - Operators see where an account signs in from, and can forget it. The user page in the console gains Sign-in places: every place the account was signed in from in the last ninety days with its addresses, devices, number of sign-ins and first and last time - one device in several places is a traveller, a new place on a new device a takeover. The deployment audit log shows the place of every event, filters by country, searches places, exports them in the CSV and says how places are resolved. Forget addresses removes every address and place recorded about one person while keeping the events, for a privacy request; the retention sweep does the same for rows older than
OSR_PLATFORM_NETWORK_DATA_RETENTION_DAYS(a year by default). - Quality gates: the router is checked against your prompts after every change, and you hear the day it slips. An evaluation says how good the router is on your prompts today; a gate keeps that dataset and asks again - every six hours and the moment the workspace policy changes - whether it is still as good after the catalogue moved, a provider was swapped or a model retired. Keep any labelled dataset as a gate from the Evaluation page with the accuracy it must not fall below; the first pass sets the baseline, every later pass is a kept report one click away, and a pass under the floor or more than five points under the baseline files a warning in the workspace inbox with the report attached - and a recovery notice once it passes again. Nothing is executed or metered. Guide: docs/PLATFORM Evaluation.
- The operators' own sign-ins and actions are on the record, with their place. A console sign-in, a failed one, a refused second-factor code and a sign-out are now written to the audit log with the address and the place they came from (before, they only passed over the event bus), and every operator action carries the address and place of the console session it was made from - so a change can be read back to where the operator sat. A console sign-in from a browser or a country the operator has not used in ninety days is flagged as
operator.new_device/operator.new_locationand filed in the console's bell for every operator to see; the Operators page shows each session's place beside its address. - A routing lab, and the decision drawn. A new page, /routing-lab, lets a visitor type a request, set what matters (quality, price, speed) and the hard limits a team would set - a price cap, a latency cap, a region, a data boundary, personal data - plus a soft latency target, and watch the router pick live from the public catalogue, with no account. The decision is drawn as a graph: the request on the left, the router in the middle, the candidates on the right, the pick on a lit wire the request flows along, the runner-up as the dashed fallback and what policy refused folded into one struck node. Beside it, Why this model places the pick on five axes against the field it won, with the strategies' own reasons, the alternatives it beat and the refusals grouped by cause, and a monthly projection prices the choice at your volume.
- Every use-case page opens on a live decision. Each use case now quotes a request of its kind against the public catalogue and shows the same graph and Why this model card, with what that volume of requests costs routed against the dearest candidate.
- Agent frameworks, wired in a few lines. The SDK page gains a section for LangChain, LangGraph, CrewAI, LlamaIndex, Semantic Kernel and AutoGen / Microsoft Agent Framework, each with its real mark, the install line and the snippet that routes it - through the OpenAI-compatible endpoint with the model set to auto, or with the router inside the graph where the framework allows - carrying this deployment's own base URL.
- Connect your IDE to the MCP server with your organization's sign-in, and run models as yourself. The MCP endpoint is now an OAuth 2.1 resource server: a client without a key is pointed at the standard protected-resource document, signs you in at your identity provider (Microsoft Entra or any OpenID Connect issuer) and comes back with a token the platform verifies against the issuer's keys and maps to your account, so no API key has to live in an editor config. A provider whose credential is
obo:<scope>instead of a key - Azure OpenAI or Azure AI Foundry behind Entra, a corporate gateway - is called on behalf of the person asking: the platform exchanges their token for one with that scope (Entra on-behalf-of or RFC 8693), caches it per person and scope, and writes every exchange to the audit log without token material. Settings default from the Microsoft single sign-on provider. - The MCP transport is complete. Sessions (
initializehands out a signed id,DELETEends it, another workspace's id or an ended one answers 404), streamed replies with progress and log notifications when the client asks for an event stream, a notification stream that announces changes to the catalogue and your tools (resumable with the last event id), a browser-origin guard against DNS rebinding and a check of the protocol-version header.askreports its three steps as progress. The same works through the site's own/mcpaddress: the session and stream headers travel through, the sign-in metadata names the address you used, and Integrations offers the key-less configuration when your deployment has an identity provider. - The self-hosted server speaks the same MCP transport.
osr servenow hands out a session id oninitializebound to the access token that asked, streams progress and log notifications before the result when the client accepts an event stream, announces catalogue changes - a marketplace sync, a new target - on its notification stream, refuses foreign browser origins (OSR_SERVER_MCP_ORIGINSnames the allowed ones) and unknown protocol revisions, and ends a session onDELETE /mcp. The description it serves says so (server_notifications,sessions), so a client can tell before connecting. - The VS Code extension reaches the stores. Each release is now submitted to the Visual Studio Marketplace and to Open VSX - the registry VSCodium, Cursor and Windsurf read - as soon as the deployment holds the store tokens, so the editor installs and updates it like any other extension; the downloads page links the listings once they exist and keeps offering the
.vsixfor a manual install. - Sign in with one tap. When the deployment publishes a Google client id, a signed-out visitor sees Google's small account prompt on the public pages and the sign-in and sign-up pages; choosing an account signs them in in place - with a toast on a public page, or straight on to where they were going from the sign-in pages - and a first sign-up lands on the page that shows the new API key once, like the redirect flow. Deployments without Google sign-in load nothing.
- The dashboard menu is arranged by the question you bring. Today (overview, activity, human queue, notifications), Money (usage, savings, AI spend, impact, plan and billing), Connect (keys, providers, integrations, apps), Rules and proof (governance, audit trail, tenants, health), People (members, workspace, account, support, feedback) and, last, Advanced for the seldom-visited tooling (evaluation, learning, events, memory, content, marketplace listings) - the daily pages come first and billing sits with the money it explains. A page your plan does not include now shows three lines of what it would show you - per-tenant budgets, live circuit breakers, the hash-chained records - beside the plan that unlocks it, instead of a lock alone.
- The first hour is easier to find your way through. The playground now opens on the request box and the Route button instead of a banner, so the first thing on screen is the thing to try. The getting-started card leads with one labelled action - Create a key, Route a request, Rate a decision - the whole row of each open step is a link, and a milestone that happens by itself (coming back another day) no longer carries a button. The dashboard menu shows a Setup 3 of 5 - Next: ... line at the top until setup is complete, so the next step is one click from every page; on Activity the human fields and the trace come first and the raw record sits behind Raw record, and the sign-up password field says what happens without one.
- Every page now makes the business case, in the buyer's words. A For the business section on the home page, every landing, solution, marketplace and story page and the pricing, models, rankings, compare, security, enterprise and downloads pages shows three outcomes with the fact behind each and the page that proves it - the benchmark saving, budgets per workspace, tenant and key, the savings ledger, redaction before a prompt leaves, the audit trail, the open licence - and answers the questions a budget owner, a security lead or a buyer brings, published as FAQ structured data. Which outcomes a page shows follows what it is about: cost pages talk money, security pages talk risk, procurement pages talk vendors.
- Fewer controls on the first screen of a list page. Activity and Events open with the search box, one Filters button and the export; the endpoint, target, key, tenant, stage, kind and level filters sit behind that button, which counts how many are set and keeps them open with a Clear while any narrows the list. The refresh cadence on Events and Learning is one small Refresh menu instead of a row of segments, and the playground shows three examples under the request box with the rest behind 4 more. Nothing was removed - the same filters, exports and cadences are one click away, out of the way until wanted.
- The knowledge graph has a page. The Memory page now shows the workspace's knowledge graph, which until now could only be reached through the API: the switch and the context budget, every fact you may see in plain words - You work at Acme, llm-small covers legal - with who or what stated it, its confidence, search and a delete per row, and Forget all about me for your personal facts. Behind four folds: add a fact by hand, forget that ... as you would say it in a chat, a preview of exactly what the model would be told for a message you type, and the export of the graph as JSON-LD, N-Triples, GraphML or Cypher with Train now for the link predictor where the deployment supports it.
- The TypeScript client reaches memory and the knowledge graph in two calls.
osr.memoryreads and switches what the routed chat remembers, adds or forgets a fact and lists or deletes conversations;osr.knowledgelists, adds and removes facts, says forget that ..., previews the context for a message, asks for suggestions, exports the graph and trains the predictor - the same routes the Memory page uses, typed from the API document. - The busiest operator pages are split by the question you bring. Growth opens on the engine and its runs, with Where signups come from, Search (keywords, Search Console, IndexNow), Advertising and Outreach (lifecycle campaigns, LinkedIn) as tabs; Finance opens on the margin watch and the revenue charts, with Pricing (rules, price book, a quote, versions), Credits and Providers (balances, invoices, reconciliation) beside it; Analytics opens on the traffic, with Before the signup and After the signup as their own views; Configuration puts the settings table first and folds retention, test data and overrides below it. Every tab is in the address, so a reload or a shared link opens the same view, and nothing was removed.
- Screens take their shape from the kit, not from a stack of boxes. A row's actions sit behind one menu button with the destructive one set apart (members, invitations, growth keywords and campaigns); the configuration groups fold one by one and its filter is a two-way toggle; governance findings on the Impact page open one at a time with the fix behind each, and the platform's own findings fold under their score; the notifications inbox is a list with an icon tile per severity; long lists page by number instead of a bare previous/next; a target id in the activity log shows the catalogue's card on hover - kind, price, speed, quality, what it covers; the setup line in the menu shows the whole checklist on hover; the knowledge graph's export is one button with the format inside; and the playground routes on Ctrl+Enter, with the shortcut shown beside the button.
- Ask about your usage. The dashboard overview reads the week back in plain words: a headline, then findings - cost against the window before with the targets that moved it, a day far above the average, failures, speed, one target carrying almost everything, savings against the baseline, spend the extension saw outside the router - each with the evidence and the page that acts on it. Type a question (why did my cost go up, is anything slower, where could I save) or pick one of the suggested ones and the answer comes from the same findings. Nothing is a model's guess: every sentence is computed from the workspace's own metered requests, so asking twice gives the same answer; the API serves it as
GET /api/v1/insightsandPOST /api/v1/insights/ask, and the TypeScript client asosr.insights.findings()andosr.insights.ask(). - Small things that were missing from the shell. On a phone the dashboard has a bottom bar - Home, Activity, Usage, Keys and the full menu - so the daily pages are one thumb away. While a promotion is live, one line above the public site's header says what it is, for whom and until when, with a link to the plans; close it and it stays closed in that browser. The playground remembers the last requests you routed on this device as chips under the box and copies a link to the current request for a colleague. The sales form offers three business days and a time in your own time zone for a call - a preference the team confirms by e-mail, not a booking the page pretends to hold.
- Search and the campaigns speak the same business language. Phrases such as AI cost optimization, FinOps for AI, AI governance platform, enterprise AI gateway and avoid vendor lock-in join every page's search keywords according to its route, and the paid campaigns seed from the commercial subset with the page each phrase should land on - so what the ads bid on and what the landing page says agree, and the guides the growth engine writes may link to the savings calculator, the bill import, the benchmark and the security, observability and enterprise pages.
- The dashboard opens with the business view. Once a workspace has routed, the overview carries a For the business card: one sentence in money - what the router kept in the last 30 days against sending everything to the model the team used before, and how many requests were answered - then four tiles (kept, spent with providers, answered, typical wait), each with the clause that says what it counts, and the step to take next. A fold explains what is counted, what the baseline is and what is left out, so a budget owner can read the page without the documentation; every figure is provider cost or a count from the activity log, exportable from the savings page.
- Glass on every layer that floats, across the whole platform. Menus, popovers, selects, dialogs, sheets and toasts in the dashboard, the operator console, the playground and the site are now frosted panes lit at the top edge; the sticky bars and the sidebar rails of the dashboard and the console are glass over the page, with the active item and the documentation tree's current page as a lit pane; the active tab, range segment or single-choice toggle is a pane of glass that slides to the choice, and a glass pane answers a fine pointer with a soft light that follows it. Workspace and operator sign-in open on the same lit stage as the public pages, and the playground's chat, decision and comparison panels sit on glass. Every pane turns opaque for anyone who has switched transparency effects off, and the light and the slide hold still under reduced motion.
- The smaller controls take the same material. Progress bars and sliders run in a sunk track with a glossed indicator, the slider thumb is a glass lens that grows under the finger, radio rings and key caps are small glass tiles, the open accordion row and the current page of a pagination rest on a lit pane, avatars carry a glass rim, empty states sit on a faint pane with a dashed edge, and tooltips keep the lit top edge every pane has. Keyboard focus rings are untouched: the material reaches a focusable control through fill, border and scale only.
- The last paper panes become glass. In the dashboard and the console, the panes a page draws by hand - the search and page strips above a list, the outcome form under an activity row, the workspace switcher, the overview's link tiles, a chart's tooltip, the welcome tour - are the same frosted panes as the kit's cards, and the status filters on the handoffs, support and feedback pages are the kit's toggle chips. On the public site the small controls the pane rule skipped - the chips on the downloads page, the glossary and use-case pills, the footer's chips and install line, the back-to-top button, the feedback widget's tiles - are glass pills, as are the hairline grids, the install tiles and the tracks tab strips slide in. Every one of these panes turns opaque for anyone who has switched transparency effects off.
- The public site reads as one story, on glass. Every page of the site now renders its cards and panes as liquid glass - translucent over the page's wash, lit at the top edge, lifting a little under the pointer, still in both themes and for anyone who prefers reduced motion - and every story page ends on the same closing band: one sentence, the free-plan line, and three chips you can check (open source, the trace of every decision, live status). The rankings, providers, services, status, downloads, what-is-live and model pages, which ended without a next step, now close the same way. A test on the file tree keeps it so: a public page must open on one question, show evidence rather than adjectives and offer a way forward, or be listed with the reason it does not.
- Every section arrives with the reader, and no band is forced dark any more. Headings, rows of cards and the panes of every public page glide into place as they cross the bottom of the viewport, driven by the scroll itself rather than a timer - they move as fast as you scroll, settle a third of the way up and are never left invisible after a fast scroll or an anchor jump; reduced motion removes the move. The photograph bands and the stage heroes (bill, enterprise, security, trust, playground) no longer sit on a black pane: the picture stays bright and the copy stands on glass - frosted paper in the light theme, smoked in the dark one.
- The home page opens on one claim, and every story page ends on a next step. The home page opens on one centred claim, one sentence and two actions, then the live routing decision as the product shot, then the product in three plain steps. Pricing, compare, models, marketplace, estimate, ROI, vendors, enterprise, desktop, extension and contact each end on a closing step written for that page.
- One colour system, in glass. Every chip, badge, toned alert, status row and icon tile across the site, the dashboard and the console now takes its colour from the theme as a translucent tint of the brand or status hue it stands for, with the same lit edge and frost as every other pane - so the blues, greens and ambers of the interface are glass in the dark theme too instead of pastel islands, and a label on a tint keeps its contrast in both themes. Nothing moved and nothing was renamed; the meaning of the colours moved into the design system.
- Glass you can see through, on every control. Buttons, fields, selects, toggles, cards and tables across the whole platform - the public site, the dashboard, the console, sign-in and the documentation - are now panes of one material: a thin frosted fill, a bright rim where the edge catches the light, a deeper blur that keeps colour, a gloss across the dark buttons and a soft glow instead of a hard ring on focus. Behind the whole page a slow field of the brand's light drifts, so every pane has something to refract wherever it stands. It stills for anyone who prefers reduced motion, and every pane turns opaque for anyone who prefers reduced transparency.
- A hundred new pages computed from the model catalogue, and a bigger glossary. Every notable model now has head-to-head pages against its nearest rivals and its closest sibling (
/models/vs/...): the verdicts a buyer wants first - cheaper, stronger, longer context, newer, which abilities differ - the specification side by side, what three typical monthly workloads cost on each, and the routing rule that uses the pair. Twelve best models for a task pages (/models/best-for/..., from coding and agents to vision, self-hosting and free) rank the live catalogue by the index that measures the task among the models that qualify, name the best value and the cheapest, and show the rule that sends hard requests to the strongest. The glossary gains twelve terms, from semantic routing to the routing trace; everything is linked from the model catalogue and listed in the sitemap. - Search campaigns close the loop with the ad network. Every campaign the growth engine creates now carries a tracking suffix, so a click arrives with the campaign and keyword named and the signup counts towards it in the funnel and the budget allocator; the bulk CSV exports carry the same addresses. With a conversion action configured, signups that arrived through a Google click are reported back to Google Ads as offline conversions - once each - so its bidding learns from real signups. A sync now also reconciles the keywords and replaces copy rewritten in the console, instead of pushing only status and budget. The growth console gains a Report conversions step (Growth in the platform documentation).
- Every public page keeps the same search contract - and a test enforces it. Each page of the site now ships a search snippet cut at a word within 160 characters (the page keeps its full lead on screen), a title with the site name, a canonical address, social cards, breadcrumb structured data, a unique title and description and a place in the sitemap, which also lists each blog category; filtered and paginated marketplace, kind and blog views tell engines to follow but not index them, so only the clean address ranks. Pages built from the live catalogue - models, vendors, listings, posts, newsletter issues and the sitemap itself - serve their last good copy or a retryable server error during an API outage, never a 404 that would drop them from the index. A test on the file tree checks every page, so a new landing cannot ship without the contract (Growth in the platform documentation).
- Every catalogue model says whether it runs here. The model catalogue's last column and each model page carry one of three labels with its meaning on hover: Catalogue (indexed in the reference catalogue, nothing on this deployment answers as it), Available here (a target or a provider endpoint answers as it, no request in the window yet) or Live here (it carried requests). A target's q 0.93 is now OSR quality prior - the router's own starting estimate, moved by your outcomes, not a benchmark - and its latency is Observed when this deployment measured it or Declared when the figure is the catalogue's.
GET /api/v1/factsadds the targets that carried traffic this week, the provider kinds the platform can connect against those configured here and those that carried traffic, and whether the routing SLM and the autopilot are implemented and whether they are switched on. - The comparisons say how they were scored. Every comparison page and the index print the date the capability tables were last checked against each product's public documentation and that the scores are a documentation review, not benchmark or performance results; the LiteLLM and build-it-yourself summaries describe the documented capability instead of a slogan. The home page links to exactly what the platform stores, and the desktop page's privacy heading says that the sensitive checks run on your computer and a message leaves only when you press Enter.
- Security claims in three columns: checkable today, in progress, not claimed. The security and trust pages carry one table: open source under Apache-2.0, the published threat model, the red-team suite and the automated scans on every change, the hash-chained audit trail and the no-payload-storage default are the first group; an independent security review and SOC 2 Type I are named as in progress - the review pack is prepared, no third-party review has been completed; HIPAA, ISO 27001 and PCI DSS are stated as not claimed. The observability page now promises an explainable trace for every decision, kept for the retention you set, instead of nothing you cannot replay.
- The router's own numbers say what they are. Every confidence on the public site - the home page demo, the playground decision, the blog's routing credit - reads routing confidence, with its meaning on hover: how clearly the chosen target won the ranking, not the odds the answer is right. The estimator's quality column carries the matching note. The Live badge on the home page and the status page shows when the numbers were fetched, and the what-is-live page prints the exact time its facts were computed.
- A page for the Open Capability Manifest.
/open-capability-manifestexplains the one open format for a routable capability - a model, an agent, a skill, a persona, a tool, a workflow, a human queue or a destination - with the fields, the validator and a manifest you can copy; linked from the footer under Developers. The home page now says what is open (the router, the SDKs, the server, the adapters, the controls, the evaluation tooling, the platform API and the web app), names the three ways to run it - library, sidecar, control plane - and states that prompts and answers are not stored by default. The marketplace is introduced as Discover routable AI capabilities, and the pricing page spells out what counts as a request and what never does. - A page that says what is live, and what every number means.
/whats-liveis computed from the running platform when you open it: each capability with its real status here (live, limited with the reason, or not on this deployment), the public figures sorted into their classes - a reference-catalogue count, a storefront, this deployment's executable targets, lifetime activity, an index of imported marketplace listings - and a provider table that keeps three different claims apart: the SDK supports it, this deployment has it configured, traffic went through it. It also lists what the site deliberately does not claim: customer case studies, certifications, an executable catalogue, marketplace adoption.GET /api/v1/factsserves the same numbers with their classes, so every page can agree. - Examples are marked as examples. The ROI calculator opens with an Example workload badge that turns into Your numbers when you change an input, the business case says so until then; the bill section's export is labelled an invented example; every industry rule file is a reference configuration, not a customer's set-up; the desktop and extension demos say which parts are staged (the people, chats and drafts) and which are live (the quote, the checks); the observability trace is labelled illustrative and no longer names a provider this deployment does not run. The estimator's Quality column is now the Routing quality score - the router's own 0-1 estimate for your prompt, explained, not a benchmark.
- The routing SLM says when the autopilot is off. On the services page and
GET /api/v1/servicesthe Routing SLM and autopilot entry is Limited, not Live, when the trained model votes but autonomous retraining is switched off on the deployment - with the reason in words. The home page's marketplace tile counts indexed AI resources and no longer puts an install count next to a six-digit index of imported listings. - One answer to "which version is current?".
/version(and/releases/latest) lists the release the platform runs, the web app, the Python and TypeScript packages and the Helm chart - versioned together - and the published builds of the installer bundle, the desktop app and the browser extension, each with its build date and whether it is at the current release. The Downloads page reads the same source and says in words when an installer still lags the release instead of printing two different numbers; the extension's caption now reads extension v1.8.0 so it is not mistaken for the platform's version. A deployment that runs a developer preview names the newest published release as current and says it runs ahead of it - on Downloads,/versionand the footer's first paint alike - rather than calling the unreleased version current and every installer late. - A page for each chat site the extension runs on, and for each app the desktop bar is used over.
/extension/chatgpt,/extension/claude,/extension/gemini,/extension/copilotand/extension/perplexitysay where the card appears on that site, what the site itself does not show and what the card catches there, with the install buttons and a live quote of a draft you would recognise./desktop/word,/desktop/outlook,/desktop/slack,/desktop/vscodeand/desktop/teamsdo the same for the command bar - the three things people do with it in that app and why it rather than the app's own assistant. - One page explains AI routing and links every page that goes deeper.
/ai-routingdefines the term, shows a request routed, and links the nine pages on each kind of routing - model, agent, gateway, cost, open source, automatic selection, abstraction layer, MCP and enterprise - so the whole topic reads from one place./ai-governancesays how a router enforces the rules the risk team writes - data boundaries, budgets, PII, the audit trail - and where to see it. The other spellings people type (/ai-agent-router,/agent-routing,/benchmarks,/leaderboard,/build-vs-buy-ai-router,/industries) now land on the one page that answers them. - Six industries have their own page.
/use-cases/customer-support,/coding,/finance,/healthcare,/legaland/retaileach give the situation in the reader's words, what changes with a router, what happens to one request, the starting rules in YAML and the way in;/use-caseslists them. The pages appear in the footer under Industries and under Solutions › Use cases. - A glossary that can be quoted.
/glossarydefines LLM router, AI routing, AI gateway, agent routing, model selection, MCP, LLM cost, routing policy and model fallback - each a one-sentence definition, the longer explanation, the questions people ask, the pages on this site that do the thing and the neighbouring terms. Every definition is marked up for search engines as a defined term with its questions. - Page titles now say what the page is for. The ROI page is the AI cost savings calculator, the estimator the LLM cost calculator, the rankings page Best AI models, the extension an AI prompt cost and privacy checker, the desktop app an AI assistant for every desktop app, and security AI security and governance - the words a person types, where the product's own names used to be.
- The home page says why you need a router before it shows you one. A Why a router section now follows the hero: the hand-rolled
if/elseevery application grows and the six things that change under it, against one API, one policy layer and every model; what a request can be sent to - models, agents, skills, tools, workflows, people; and seven reasons, each linking to its proof. A band near the end states the open-source facts (Apache-2.0, one package for Community and Enterprise with no source-code split, the install lines) and the path a request takes before anything leaves your device. The hero now promises the lowest-cost model that satisfies your quality, policy and latency requirements, with two actions: Try OpenSmartRoute free and See your potential savings. - Small numbers stay off the public pages. A deployment's own counters - requests routed, requests today, workspaces, marketplace listings and installs - appear only once they pass a traction floor (10,000 requests, 1,000 a day, 100 workspaces, 100 installs). Below it the hero shows the benchmark saving, the time to a decision and the size of the catalogue, and the product tiles say what is true at any size. The tiles are introduced as surfaces of one decision engine, and the desktop and extension pages say they run on the same engine as the router behind the API.
- Four more pages for the questions people search.
/why-ai-router,/ai-gateway,/automatic-model-selectionand/ai-model-abstraction-layerjoin the use-case pages in the footer and under Solutions › Prove it./compareopens with one capability matrix across OpenRouter, LiteLLM, Portkey and OpenSmartRoute, from the same verdicts as the per-product pages./rankingsis now titled as an AI model leaderboard - cost, intelligence, coding, agentic performance and price - with what the router actually picks beneath. - Every catalogue model page names its alternatives.
/models/<vendor>/<model>lists cheaper models within five intelligence-index points, stronger models by index with their price, and where the router puts this model - written from the catalogue's numbers, not the vendor's page. - The buyer's pages lead with the step, not the detail. The developer page opens with an existing OpenAI client pointed at the router (
model: "auto") and the decision that comes back - no application rewrite. The industries page shows what happens to a request (PHI detected, external models removed, on-prem model answers, decision logged) before the YAML. The solutions index shows three proofs per reader and sends the rest to their page; pricing says Not sure? Start free; the ROI page ends with Route a sample of your traffic and No credit card, and both it and the bill section link to how a saving is measured. - The native Mac and Windows apps keep themselves up to date. Both apps ask the downloads page for a newer native build at launch and once a day (Settings › About › Check for updates automatically; the shared
autoUpdatekey inmanaged.jsonpins it) and say so on the island and in Settings › About. Download fetches the build and checks its published SHA-256. On Windows Install and restart runs the installer silently: the app quits, the exe is replaced and the app comes back with your settings and key (an every-account install asks for an administrator's approval; the portable exe gets the new file beside it). On the Mac Install and relaunch swaps the new app in for the running one, or opens the disk image to drag when your account cannot write where the app sits. Nothing is installed without a click. Guide: Desktop app. - The home page routes your request while you watch. The hero's illustration is now the router itself: type a request or pick one of three, press Route it, and read the real decision from the public catalogue - the model picked, how sure the router was, what the request costs, the alternatives it weighed and what each would have cost - with a link to the full trace in the playground. No account needed. The hero and the documentation now say what it is in the first words: an open-source AI model router.
- The benchmark is a page. Benchmark publishes what the router did on 150 real prompts against every model answered directly: 89% less spent than always using the frontier model at a higher blind-judged quality, and the two use cases where the frontier model still judged higher. It also carries the RouterBench results - including the policy that beats the router on accuracy - and the commands that reproduce every figure.
- Seven pages answer the questions people type into a search engine. LLM router, AI model router, open-source LLM router, LLM cost optimization, AI agent routing, MCP router and enterprise AI router each get a page with the problem in the reader's words, how the router answers it, a request to route, the benchmark figure that applies and the way in. The
/<product>-alternativeaddresses land on the comparison pages. - The routing SLM reads long prompts where they ask, and decides faster. A prompt over
OSR_SLM_MAX_TOKENSused to be cut to its head and tail, so a request buried in a pasted document was never read. The encoder now reads it through a reading window (ReadingWindow): a share of the budget for the head and the tail (OSR_SLM_WINDOW_HEAD/_TAIL), the rest for the most instruction-like sentences of the middle, plus an ask view of the asking sentences alone (OSR_SLM_WINDOW_ASK). On 70 requests buried in thousand-word documents, 63-69 now route acceptably instead of 7-44; short prompts are unchanged, andexplainshows theaskit read. A served encoder also caches the lastOSR_SLM_ENCODE_CACHE(512) prompts, so a repeated prompt scores in 130 µs instead of 735 µs;osr slm infoshows the window. Guide: the user guide, Where a transformer helps. - Your Python declarations ride along with
osr serveandosr route.osr --components my_components serve(repeatable;my_components:setupalso callssetup(registry)), orOSR_SERVER_COMPONENTSfor the container, imports the module so its@tool,@handler,rule(),@guardand hook declarations join the router built from your catalogue - handlers bound to the catalogue's targets, rules merged into the rules strategy, a guard or hook turning the served router into the hardened one so they run. A module that cannot be imported stops the command with its name. In code the same step isosr.components.apply(router). - The TypeScript SDK has the same one-liners as the Python one.
osr.route("text", { objective })takes the request text first and the other fields second,osr.run("text")routes and executes in one call,osr.ask("prompt", { system })answers through the router withmodel: "auto"and returns the text, andosr.feedback(decision, { success: true, quality: 0.9 })reads the request and target ids from the decisionroute()returned. The object forms keep working unchanged. - The Python SDK routes in one line and takes the rest as decorators.
osr.route("..."),osr.run("..."), theirawait-able twinsosr.aroute/osr.arun, andosr.feedback(decision_or_result, success=True)work straight after your declarations: the registry builds its router on first use and rebuilds it when you register more.osr.rule("pii-stays-home", prefer=["onprem"], pin=True, contains_pii=True)declares a rule in code (a mistyped condition is an error, not a rule that matches everything),@osr.handler("gpt-4o")gives a catalogue's targets code afterosr.components.load("targets.yaml"),@osr.guardrefuses or rewrites a request before routing,@osr.on_decision/@osr.on_outcome/@osr.on_errorare one-function hooks, and@osr.llm,@osr.persona,@osr.humanjoin the target shorthands, with the docstring body as the target's instructions. Guide: docs/SDK. - Every blog post says how OpenSmartRoute helps with the news it reports. Each article now carries a How OpenSmartRoute helps section, written for that story, in front of What to do: what a team that routes its requests through the router gains from a release, a benchmark, a price change or a safety finding, and what it would set up - a new model as one catalogue entry, a rule that keeps personal data at home,
osr evalon the team's own prompts, the savings ledger. A card under the section takes the reader to the playground, the catalogue and the set-up guide. The writer plans the section in the brief, writes it from a fixed list of product facts and nothing else, and writes it on its own when the article skipped it; posts published before today receive it on the next poll, and Add product sections on the console does them in bulk. Workspace publications are untouched. - The Python package talks to the platform in three lines.
from opensmartroute import OpenSmartRoute; osr = OpenSmartRoute(); d = osr.route("...")- the key and the address come fromOSR_API_KEY/OSR_API_URLor from whatosr loginsaved, and the same client speaks to a self-hostedosr serve. The decision carriestarget_id,confidence,explanationand an executed answer'stext;osr.feedback(d, success=True)closes the loop,osr.ask()andosr.chat(stream=True)answer through the router,osr.estimate()quotes without a key. Every call has a timeout, transient failures are retried with backoff, errors are typed and never carry the key, and a key is refused over plainhttp://to a public host unless you say the network is trusted.Router.starter()is the in-process counterpart: a working router with nothing configured. Guide: docs/SDK. - The TypeScript SDK retries and refuses clear-text keys on its own.
@opensmartroute/sdknow retries a connection failure, a 408, a 429 or a 502-504 twice with backoff (maxRetries;Retry-Afterhonoured up to a minute, a final 4xx never retried, a stream only before its first byte, a pending retry cancelled by yourAbortSignal), and refuses to send an API key over plainhttp://to a public host unlessallowInsecureHttp: truesays the network is trusted - loopback, private addresses and in-network names such asrouterorosr.internalstay allowed.isPrivateHost()is exported for your own checks. - The first
osr routeworks straight after the install.osr route "...",osr estimate,osr serve,osr targetsandosr mcpno longer stop with --targets is required: without a catalogue they route through a built-in starter - a small fast model, a frontier model and an on-premises one, with the two rules that keep personal data at home and send hard requests to the frontier - and say so on the first line, withosr stack init --out stack.jsonto write that catalogue to disk and-t stack.json -r stack.jsonto route through your own copy. The container does the same:docker run -p 8000:8000 <image>with nothing mounted at/confignow answers/routeinstead of exiting with config file not found (anOSR_TARGETSpath set by hand must still exist). The Helm chart keeps asking for a real catalogue, as before. - The newsletter comes morning and evening. Daily readers now get a second issue at 18 their time with the posts written since the morning one ("3 new posts since this morning"); a day with nothing new sends no evening mail. Weekly readers are not affected. Operators set the hour, or turn the evening issue off with
-1, at/platform/admin/settings(OSR_PLATFORM_NEWSLETTER_EVENING_HOUR). - Twenty-six more news sources. The blog now follows Mistral, Ollama, NVIDIA, PyTorch, Cloudflare, AWS, Weights & Biases, Weaviate, Qdrant, Lightning AI, Ai2, Chip Huyen, Jay Alammar, Phil Schmid, Sebastian Ruder, SemiAnalysis, Machine Learning Mastery, Analytics Vidhya, Last Week in AI, AI Supremacy, Ben's Bites, InfoQ, SiliconANGLE, Unite.AI, ZDNET and The Register - each checked to fetch and parse. A running deployment picks the new ones up on its next start; a feed you deleted is not added back.
- Every post leaves with its keywords, and Google hears about it at once. A post written without keywords gets them from its own text the moment it is saved (no longer only on the next growth pass), the meta description is cut at a word instead of mid-word, and a newly published post goes to IndexNow within a minute while the sitemap is sent to Google Search Console and Bing Webmaster Tools again (at most hourly) so Google re-reads it for the new address. A Google News sitemap of the last two days' posts (
/blog/news-sitemap.xml, with keywords and the lead image) is named inrobots.txtand submitted alongside. - The platform submits itself to the search engines and keeps its directory listings honest. The new Search and directories page of the console shows what every engine received - IndexNow the moment a page is public, the sitemap to Google Search Console and Bing Webmaster Tools daily, new addresses to Bing's URL API within its quota - and Google's own verdict on whether the pages that matter are indexed, refreshed weekly. Below it, the register of the software, AI-tool, open-source and package directories a product like this belongs in, with a listing kit written once through the router (tagline, descriptions at the forms' lengths, categories, tags, logos, links, each with a copy button), submission by e-mail where a directory takes it, and verification of every listing on its schedule - live, or missing when it disappears - with the visits and signups each brought. Guide: docs/PLATFORM.
- Every failure in Application Insights now says why, and where it came from. A refused request carries the reason the platform gave (the message of a
400, the fields a422named), a failed database statement carries the error's type and message beside the statement (never the bound values), and every request carries the caller's user agent and the page it was made from (origin and path, never a query string) - so a rejected upload, a flood of404s on one address or a job that failed every five minutes can be traced to its cause from the portal alone; the access log says the same. The guide's Monitoring section lists what arrives. - A model that did not answer in time says so, and is not asked twice. A self-hosted model that ran past its budget used to fail as connection failed after a second attempt that doubled the wait; the error now reads timed out after 180 s with the budget it ran out of - in the trace, the activity page and the monitoring - and the call moves to the router's fallback at once instead of retrying the same prompt on the same busy server.
- OpenSmartRoute for Microsoft Word. A pane beside the document, in Word for Windows, Mac and the web: select a passage and it tells you what it is - the writing task, the language, the words and tokens, whether it carries personal data - and what the router would do with it: the recommended model, what the request costs, what the cheapest and the best model would cost instead, and a month of such requests. Ask, Explain and Summarise show the answer in the pane with Insert below; Rewrite in place and Proofread in place replace the selection (Undo takes it back); Good / Not good teaches the router. Personal data is redacted before a request leaves and restored in the answer. Sign in with a code approved in the browser, or paste a key. Install from the manifest the site writes for its own address (
/office/manifest.xml), by upload or from the Microsoft 365 admin centre. Guide: docs/OFFICE. - OpenSmartRoute for Visual Studio Code. Select code or text in the editor and the new OpenSmartRoute panel tells you on the spot what it is - the task, the language, the tokens, whether it holds personal data - and what the router would do with it: the recommended model, what this request costs, what the cheapest and the best model would cost instead, and a month of such requests. Ask a question about the selection (Ctrl+Alt+O), Explain it, or Rewrite it in place, and the answer comes back through the router with the model, the price and the time under it; Good / Not good teaches the router. The analysis runs on your machine; personal data is redacted before a request leaves and restored in the answer. Sign in from the editor with a code approved in the browser, or paste the token of a self-hosted server. The .vsix is on the downloads page (
/download/vscode). Guide: docs/VSCODE. - The browser extension helps in every text field out of the box. Until now the writing widget stayed on the five chat sites unless you switched Help in every text field on and answered the browser's permission prompt. It is on from the start now: on any site the widget follows the field you type in - a plain text box, a text input, a rich editor (also inside a frame or a web component), a WYSIWYG frame in design mode - so mail, documents, tickets, forms and CMS editors get the pill, the score, the redaction and the commands without setup. The browser names the site access once at install (Firefox asks the first time). Only the field you type in is read, never the page around it. The power button turns it off for a site, Only these domains narrows it, the switch in Settings turns it off everywhere, and a Revoke row takes the site access back.
- The browser extension works in Google Docs. A document is a site of its own, on out of the box. Docs paints the page on a canvas and the browser's selection is always empty, so the extension reads what you selected from the hidden frame Docs types into, puts the selection toolbar over the highlighted lines and the pill at the edge of the page. Select a passage: Summarise, Explain, Rewrite, Translate and your own commands hand it to the sidebar; the card reads it - personal details, slips, the model the request deserves - and Redact, Fix and Use this write the result back over the selection the way a paste does (when Docs refuses the paste, the text goes to the clipboard and the card says to press Ctrl+V). Summarise this page in the sidebar reads the whole document; nothing is read from pixels, nothing is sent until you ask. Chrome, Edge, Firefox; Safari reads the selection alone.
- Every paid plan is free for 90 days - no card, no payment. Pro, Team and Enterprise now start with a 90-day trial the moment you pick them: the plan is yours at once, nothing is charged, no payment method is asked for, and the workspace simply returns to Free when the trial ends unless you subscribe - with a reminder three days before. The trial works on a deployment without Stripe as well. It is one per workspace; you can move it between plans while it runs - the other plan cards then quote the days you have left, not a fresh trial - and Subscribe now pays whenever you want to keep the plan. The pricing page and the plan cards say "90-day free trial - no card, no payment", and the number of days follows each plan, so an operator who shortens one plan's trial sees that reflected everywhere.
- Measure the router on your own prompts before you trust it with them. The new Evaluation page of the dashboard (and
POST /api/v1/evaluations) takes the labelled datasetosr evalreads - one JSON line per prompt with the target it should go to, several that would do, or a score per target - and routes every row on your workspace's own pool, under your policy, tenants, allow and deny lists, installed listings and providers. Nothing is executed and nothing is metered: a run calls no model, costs nothing and leaves no event in your history. The newest 50 reports are kept per workspace; the datasets never are. Start from the sample dataset the catalogue builds for you. Guide: docs/PLATFORM. - Every evaluation figure comes with its comparison. The report says how often the router picked your target (with the interval that many rows deserve), the quality it reached, what the mix costs against always using the dearest model it could have chosen, how honest its confidence is, where every row went and which labelled rows it got wrong - and puts the policies every router must beat (random, always the cheapest, always the strongest, always the dearest) on the same rows beside it. Sweep the cost weight to see accuracy against spend on your own prompts.
- Replay your own traffic through today's router. With request logging on, the second tab of the Evaluation page (
POST /api/v1/evaluations/replay) sends the prompts you kept through the router as it is now - with everything it learned from your outcomes and every catalogue or rule change since - and compares each decision with the target that answered then: what would move and where, what the same tokens would cost at the new targets, and whether the router keeps the answers your team accepted and moves the ones it rejected. Every request links to its trace. osr eval --remoteruns your dataset on the platform. The same JSON-lines file the command reads locally can be sent to the signed-in workspace instead: the platform routes every row under your policy, providers and installed listings, prints the headline, the misroutes and the baselines in the terminal, keeps the run on the Evaluation page, and--min-accuracystill fails the build when the number is not good enough. The TypeScript client has it asclient.evaluations.- Telling the router how it did is now one click, right where the answer lands. Under every decision and every chat answer in the playground a small Was this the right choice? offers Good or Poor; one click records the outcome and the router learns from it. Until now the only place to report an outcome was the activity page's full form, and over the last month one workspace in nine that got an answer ever reported one. The getting-started checklist's Report an outcome step now leads to the playground, where the request you just made is waiting for the click; the activity page keeps the full form for an exact quality score and naming a target that would have done better.
- More seats on every plan. Free workspaces now hold 5 members (was 3), pay as you go 10 (was 5), Pro 25 (was 10), Team 100 (was 50) and Enterprise 1,000 (was 500) - pending invitations included, as before.
- The dashboard says thank you when you get somewhere. Each getting-started step you complete between two visits is acknowledged in one line - First request routed - the trace shows why that target won. Finishing the setup, and reaching every value milestone, each show an all set card once: what you achieved, the next milestone, and the pages where the value now shows (Savings, Learning, Impact). It is not repeated on the next visit.
- One e-mail the first time a model really answers you. Your first answer came through carries your workspace's own figures - the target the router chose, requests routed and answered, what was kept against the dearest model you used - and the one ask that makes the next answer better: mark it Good or Poor. Sent once to the owners, in the getting started category with one-click unsubscribe; operators see it as
first_valueamong the lifecycle campaigns and can switch it off. - Every money moment now writes to you. When you pick a paid plan and its free trial starts, the owners get Your
trial has started - until when, that no card was taken, what happens at the end - and when the trial runs out, Yourtrial has ended says the workspace is back on the free plan with its keys, history and settings intact. Credits that land on the wallet, by a purchase or an automatic top-up, send a receipt with the amount and the balance; a refund says what went back to the card; and when an invoice we could not collect is finally paid, Payment received closes the loop the payment-failed note opened. Credits running low or spent, and a budget nearly used, now reach the owners by e-mail when the workspace has no alert channel, as the quota notice already did. Each also appears in the workspace inbox, and the plan changes ride the event webhooks. - The bell and the mailbox cover the rest of what happens to your account. A rotated API key is mailed to the owners (the old secret stopped working at once) and filed in the inbox, as are changed key scopes or limits, a member leaving, ownership handed over, and a request waiting in a human queue until someone answers it. A sign-in with a two-factor recovery code sends a security note with how many codes are left; replacing the codes and removing password sign-in are noted too, with the ways the account still opens.
- The rest of your account's security events now reach the bell too. A sign-in from an unknown device already appeared there; so do the others now - your password changed or reset, the second factor switched on or off, too many wrong passwords tried against your address, a sign-in method added or removed, and the ones worth knowing about most: an operator of the deployment resetting your second factor, signing you out of every browser, or closing and re-opening your account. Each is yours alone, invisible to other members and to the operator console, and links to the page where you can act on it. The account page says where they arrive, and the platform guide lists every one of them.
- What happens to the workspace now reaches everyone who works in it. A key minted or revoked, someone joining, a role changed, a member removed, the plan moving - until now only the owners were mailed, so the developer who lives in the dashboard learned about a revoked key from a
401. All of it is in the workspace's notifications now, with who did it and a link to the page that shows it; a revoked key and a removed member are marked as warnings. These stay inside the workspace they belong to, and somebody who leaves does not take them along. - Pick your newsletter topics before you subscribe. The newsletter page now shows the five topics - models, LLMs, agents, research, AI - ticked; untick what you do not want and the first issue already arrives cut to your choice. Every topic ticked means everything, and the last one cannot be unticked (that would be leaving, which has its own link). You can still change it later from the preferences link in any issue.
- Following a feed works from any address. On the Content page paste the feed's URL or the home page of a blog: the platform looks at it once, finds the feed the page advertises (or the usual
/feed,/rss.xml,/atom.xml), names it after its own title, remembers its site and says how many entries it holds - Check shows that, with the newest headlines, before you follow. A page without a feed is refused with the reason; an address that does not answer is followed with the error on its row and tried again on every pass. Feeds can be renamed, given a category (a tag on every post from them), paused and fetched now. Agents getcontent_list_feedsandcontent_fetch_feed;content_add_feedaccepts a page too. The console's Feeds tab does the same look (POST /api/v1/admin/content/feeds/preview). Guide: docs/PUBLISHING. - A feed reader can pull your posts without a key. Your workspace RSS at
/api/v1/content/feed.xmlnow answers to a feed token in its address (?token=) as well as to the API key, because a feed reader or a static-site build cannot send a header. The complete link sits under Destinations on the Content page with a copy button; Replace link (admins,POST /api/v1/content/feed/token) retires the old one at once. The token reads published posts and nothing else. - Your workspace's posts are full articles, written for your publication. Posts from your feeds and from a brief are now written the way the platform's own blog is: a brief first (title, summary, key points, why it matters, an outline), then the article from that outline in plain Markdown, continued once when it stops short - but addressed to your publication, readers, tone and language, never to the platform's blog, and from your notes when you sent a brief. The editorial profile has a new Article length (300-4,000 words; empty = the platform's default of 2,000), the Writer card says the length in use, and each post's routing carries both passes and the measured length. Guide: docs/PUBLISHING.
- Your workspace's posts reach your own social accounts too. The destinations of the Content page gain the same networks as kinds, with the same credential fields and schedule: add your LinkedIn page, X account, Discord server or Dev.to profile next to your website and every post you publish is shared there when its schedule allows - linked to the post on your site when the editorial profile names one. Guide: docs/PUBLISHING.
- The blog writes full articles of its own, not rewritten excerpts. Every story from the news feeds now becomes a long-form article: the writer reads the source page, asks the model for the brief first - title, summary, key points, why it matters, an outline of six to nine sections, tags and keywords - then writes the article from that outline in plain Markdown, 1,500 to 2,000 words by default, and continues a draft that stops short once from where it ended. Both passes are metered requests of the editorial workspace and graded for the learners, and the post's routing carries them and the measured length; a model that cannot produce 400 words leaves the brief's text or the attributed excerpt and says so. Target, minimum and source size are operator-editable (
OSR_PLATFORM_CONTENT_ARTICLE_WORDSand its companions); the post page lists the sections as In this article. Guide: docs/PLATFORM. - Each article shows how it was made, in three tabs. The card under a post's byline opens on Decision - the model that wrote it, why that one was picked, what it cost, how long it took - and adds Waterfall, a bar for every pass the writer made (the brief, then each writing pass) scaled to the slowest, so you can see where the time and the money went; and Evaluation, the grade each pass was given, the reading level of the finished text (Flesch-Kincaid: grade 9 reads like a ninth-grade textbook) and its length against the minimum, which says so when a post came up short. The grade is the one the router learns from: it is now kept on the post itself, not only on the learner. The tabs move with the arrow keys, and every figure stays in the page for a reader without JavaScript and for a search engine. A post that no model wrote still says so in one line.
- Every article the blog publishes goes out to your social networks, chat channels and blogs. The new Syndication page of the console (
/platform/admin/social) holds the channels: a LinkedIn profile or company page, an X account, a Facebook page, Threads, Mastodon, Bluesky, a subreddit; a Discord webhook or a Telegram channel; and the platforms the article itself is re-posted to with a canonical link - Dev.to, Hashnode, Medium, Blogger, Tumblr, WordPress, Ghost, or any site through a signed webhook. Pick the network and the form asks for exactly the credentials it needs; they are stored encrypted and never shown again. A LinkedIn channel can post with the connection the Growth page made, which then stands down so nothing goes out twice. Guide: docs/PLATFORM. - Each channel posts on a schedule you set. Share the moment an article is published, or only inside a posting window - weekdays, hours, your time zone - with a minimum gap and a daily cap, so three articles published within a minute land an hour apart instead of flooding a feed. A cadence re-shares the newest article not shared in 30 days every N hours, a template shapes the message, blog platforms can receive drafts. Share any post on chosen channels now or at a chosen time with your own text, send a test, retry or cancel a share, and read every network's answer and permalink on the share log. The Automation page lists the syndication scheduler next to the other jobs, with Run now; the Growth page says when its own LinkedIn cadence stands down in favour of a syndication channel.
- The answers in the desktop walk-through are written by the router. The tour on the home and desktop pages types a draft into Teams, Outlook, Word, Slack, VS Code, Notes, a terminal and a browser and shows the answer landing. The quotes were always real; the answers were lines written by hand, because a public page has no workspace to run a model with. Now the platform answers every draft itself, through the same routing, metering and grading path as its blog and its guides, once a day - and the page shows that answer with the model that wrote it and what it cost (
GET /api/v1/showcase); the "who answered and what it cost" card reads the same record, so no model name, price or time on the page is typed in. A draft with a phone number or an API key is answered in the redacted form the app sends, and where the platform has not answered a draft yet the tour says so instead of inventing one. - Operators change the site's photographs from the console. The new Photographs page lists every picture the public site shows - caption, crop focus, photographer, licence and the pages it is on - and lets an operator replace any of them with an upload (sized for the site automatically), move the crop with two sliders over a live preview, correct a caption or a credit, or put the shipped picture back. The pages pick a change up within a minute or two, the credit under the picture follows it, and every change is in the audit log with who made it. The page-not-found and error pages now carry a picture too: a brand placeholder (a gradient with the mark, no credit) that the console lists first under Placeholders to fill, so a deployment can put its own photograph there. Guide: docs/PLATFORM, operator console.
- Uploaded photographs are served from object storage. With a storage container configured (the Azure deployment provisions one and writes to it with the platform's own identity - no key to keep) each picture an operator uploads is stored under a content-addressed name with a year-long cache, and the pages embed its storage address: the storage account serves the picture, never the API or the database, and the site's image optimiser caches every size for a year. Without a container the pictures stay in the database as before. The Photographs page says which applies and moves pictures uploaded before the container existed into storage with one click.
- See where visitors leave before they sign up - and from which pages the ones who sign up came. The console's Analytics page gains Before the signup: the visitor journey: distinct anonymous visitors of the public site through visited, looked at the price or the docs, opened the signup form, started typing, signed up, with the conversion of each step; the signup attempts that failed and why (address already registered, terms not accepted, the per-address limit, a rejected address or password, a server error); the landing pages and referrers with their signup rate; the calls to action clicked. The events are first-party and anonymous - a random id that lives in the browser tab, stored hashed, no cookie, no IP, no e-mail - and the signup joins the visitor to the new workspace.
- Ask the people who do not sign up, and the ones who signed up but never started. The pricing and signup pages offer one question to a visitor who is not signing up today - What is holding you back? - with a short list of reasons (just looking, unclear value, price, security review, needs single sign-on, a missing feature, wants to self-host, not sure the project is established) and an optional line; the thanks link to the page that answers the reason. The dashboard's getting-started card asks a workspace that has not routed a request yet What is in your way? and points at the page that removes the obstacle. The console shows the answers aggregated and in the people's own words, and every stuck workspace carries its answer - or, when it did not answer, what the platform can see: unconfirmed e-mail, no API key, failed first calls, no executable model.
- Operators hear about every registration. One message goes to
OSR_PLATFORM_SIGNUP_RECIPIENTS(falling back to the support and then the report addresses) for each new account, whether it came from the signup form or a first sign-in with an identity provider. It carries who registered, the workspace, how they signed in, whether the provider vouched for the address, where they came from when the signup was tagged, and a link to their page in the console. Somebody signing in again is not a registration and stays quiet, and a deployment that would rather read the count in the daily digest setsOSR_PLATFORM_NOTIFY_SIGNUPS=false. - One trace from the click to the database in Application Insights. On an Azure deployment the web app now reports to the same Application Insights resource as the API: a page view per navigation, the Core Web Vitals, uncaught errors, every call to the API and the moments that matter (signing up, signing in, starting a checkout, an answer in the playground, an outcome reported, an evaluation run). Each call carries a request id the API answers under, so the end-to-end view reads page view, call, request, routing, provider call - and now the SQL statements the request ran, each a dependency named by its table, so a slow page can be followed to the statement that made it slow. Nothing a person typed travels: URLs are reduced to a few known query keys, the only ids are request, session and workspace. The operator's Health page shows what was sent. Guide: docs/PLATFORM Monitoring.
- Open-weight models by default on Azure. The Azure template no longer creates Azure OpenAI deployments unless you ask (
OSR_AZURE_OPENAI_ENABLED=true): every tier of the catalogue -llm-small,llm-mid,llm-frontierincluded - answers on the self-hosted Ollama server (Qwen3.5 4B on CPU; GLM-4.7-Flash and gpt-oss-20b lift the upper tiers on a dedicated or GPU profile; gpt-oss-120b and DeepSeek-V4-Flash through Ollama Cloud when you bring a key), so no request leaves for a closed model unless an operator connects one. The Marketplace wizard and the Compose example start the same way. Guide: docs/INSTALL. - A quiet switch for routing that is not traffic. The SDK gains
untraced(): inside the block every span and event is a no-op for whichever tracer it uses, so a benchmark, a dry run or an evaluation never lands in your event store or metrics next to the real requests. Guide: docs/OBSERVABILITY. - Every package the project ships carries the same brand. The TypeScript SDK, the VS Code extension, the browser extension, the desktop app, the Helm chart, both container images and the deployment and platform guides now open with the OpenSmartRoute lockup - the one that turns to its reverse face when the reader's theme is dark - and declare the same licence, home page and support address, so a reader who lands on any one of them knows whose it is and where to get help. The images say what they are and who makes them, the chart carries the mark so its catalogue entry is no longer a grey square, and the Marketplace listing gets its gallery banner. That listing also stops linking a source repository nobody outside the project can open: it points at the support page instead.
Changed
- The product and solution pages carry no blank corners. A pane in a row of three ends where its text ends instead of stretching to its tallest neighbour with an empty bottom; a fifth proof on a reader's page takes the whole row rather than leaving a hole beside it; the industries list stops at its last industry; the service groups fill their last row; the use-cases page's "by what you are trying to do" row is complete with the AI gateway page; and the MCP page says what each of the nine content tools does instead of "the guide describes it".
- The call to action is the brand blue, not ink. Every primary button, the pricing tiles' recommended ring and the numbered steps on the extension, desktop and marketplace pages use one brand blue (white text on a cobalt; a saturated blue in the dark), so a light page no longer carries rows of black slabs and a dark page's buttons stay readable. Filled buttons are solid - a hairline of light along the top edge, a shadow no wider than the button, no gradient or halo; a disabled one is a tint of the fill with blue words instead of white on a washed blue that could not be read; link-buttons take the same surface rules. The pricing tiles are glass on both themes instead of one black island.
- The mark keeps its face on a blue button and behind every closing band. The OpenSmartRoute mark on a blue button has a version of its own - white ring, destinations in pale teal, blue and violet - where the positive mark used to vanish into the fill and the one-colour mark gave up its three hues. The same mark, faint and in its colours, is the watermark behind the footer and behind every closing band (it was a grey silhouette in the footer alone); the icon plates on the bill formats, contact channels, observability surfaces, bring-your-bill steps, decision path and target kinds take the header menu's hues by position instead of one grey tile each.
- The home page's three acts play out on their own cards. They no longer hang from a route line that showed through the glass; each card plays its act instead - a pasted key is flagged and swapped for a placeholder while the price appears, three candidates are priced, one is struck out by policy and the best value wins, and the trace is written line by line. The animation loops every eight seconds and shows its resolved frame, still, under reduced motion. The glass sheen no longer slides across cards and the hero lenses drift a shorter path - the motion stays, the restlessness goes.
- Selected chips are blue, and the providers page explains itself. A pressed filter chip, the rankings tabs, the open-weights toggle, the first-place rank badges and the walk strip take the blue tint with blue words instead of an ink slab. The public providers page opens with the three things a provider does for a workspace - bring the keys you already pay for, the router spends each where it is cheapest, every answer names who answered and what it cost - and lists each provider as a card with the vendors it serves, a plain-language kind, its models and this week's traffic; internal hostnames no longer appear on a public page.
- The home page's live decision shows its work. Press Route and the four moments play in order on a rail - Read, Policy, Priced, Picked: what the router read (task, tokens, a complexity bar, whether personal data was found), how many candidates policy refused before any price was read, every allowed candidate priced as a bar against the dearest, then the pick with its confidence, cost, latency and saving and what the trace would carry had the request been sent. The workings fold away with Show / Hide, a replay button runs them again, and reduced motion lands on the finished decision. Every number is still the real quote.
- The home page is seven sections, no two the same shape. Twelve sections had become a scroll of identical four-card grids; the outcomes, the four audiences, the open-source band and the business case now live on their own pages (the Solutions menu, /why-ai-router, /open-source-llm-router, /security) and the page runs promise with a live decision -> the vendors -> how one request moves, acted out -> where the engine reaches you -> the code -> your own bill -> price and start. The products section shows the two products people use by hand - the extension's card with its price line and personal-data flag, the desktop shortcut and its verdict line - drawn at size on solid tiles, with the six surfaces for builders as one line each beneath. A third shorter than before.
- The observability page shows a trace, not a list about one. Under the five stages sits the dashboard's own span waterfall rendering an example request in the router's real span and event names -
guard.input,routewithroute.signals,route.policyandroute.rank,plan,execute,output_guard,learn.outcome- every row openable to its attributes, with the timings marked as illustrative and a link to route your own. The home page's closing band carries the three proof chips (open source, every decision explained, live status) and the four audiences it used to spell out in sections of their own. - The site has a motion language, and it explains the product. One loop - a request enters, the router reads it, candidates light, the losers fade, the pick carries the request - drawn in SVG wires and liquid-glass nodes, timed by CSS so it costs nothing and plays without JavaScript: the tournament beside the three steps of every landing page (/why-ai-router and its kin), the failover and this week's real traffic shares on the providers page, the inspection chain (identity, personal data, injection guard, policy, model) in the security hero, the hub of integrations on the SDK page, and a branded three-node loader while the live decision is quoted. Every scene says it is illustrative; under reduced motion each shows its resolved state. The trace waterfall's timeline is a group, not a list of buttons, for assistive technology.
- Three more scenes in the motion language. The bill section opens on before and after - the same traffic as bars per model size, the two totals counting up and the saving between them (this deployment's own totals once it has routed real traffic, an illustrative pair until then); the enterprise page's architecture builds as the reader scrolls - applications, gateway, router, models, then the security, observability and governance layers - and takes itself apart scrolling back; the agent-routing page's three steps sit beside a supervisor fanning work to three agents whose calls all pass the one router. Scene wires no longer break into dashes on a stretched canvas (a Chromium quirk of non-scaling dashed strokes), sit behind the glass pills, and end where a pill begins.
- No more ink slabs for a selection. The last places that marked the chosen thing with a black pill take the blue tint with blue words or the call-to-action fill: the pricing page's Most popular badge and its ring, the
inkbadge tone (available here, the task type, the trace's target), the feedback widget's kind and status trail, the notification centre's and the social scheduler's day and family chips, the console's plan feature chips, the reasons in the blocker and why-not prompts, the SSO wizard's done steps, the marketplace publish wizard's current step, the filter bar's and constraint builder's counts, the trace view's step numbers, the playground's own bubbles and Stop button, the desktop and extension demos' Redact, Send and OS pickers, and the toast action button. - The request leaves the page. The footer's last line is now a route rule: a hairline that carries one slow blue request from left to right under the copyright row, the same motion language as the scenes above it. Every filled call-to-action button with an arrow answers a hover with the arrow sliding one step and a single highlight crossing the button behind it - one beat, no bounce. Both are plain hairline and plain button under
prefers-reduced-motion. - The routing lab reads as one page. The constraint builder stays in view while the decision and the Why-this-model card scroll beside it; the "same body" section pairs the heading and the three rules with the route request and a map of where each control lands in it (
objective.quality / cost / latency,constraints.max_cost_per_1k,max_latency_ms,preferred_max_latency_ms,region,data_boundary,contains_pii,monthly_requests, each marked weight, hard, soft or estimate) instead of a short code pane beside a tall stack of cards; the page carries the route drawing rather than the cost chart's bars; section spacing is tightened. - One source for the trial and the version. The pricing FAQ's trial answer and the pilot page's cost answer now take the trial length, the plans it covers and whether a card is needed from the plan catalogue (
/api/v1/info.plans) like the plan cards and the hero do, so no page can say a different number of days; the footer's version badge names its component (Platform v2.0.1-preview.12) so it is never read as the SDK's, the extension's or the desktop app's version. - Search works again on the public pages. Opening Ctrl/Cmd+K and typing anything that matched a page took the whole page to its error boundary ("This page could not be rendered"): the palette rendered a page's icon as a child instead of as a component. The icon slot now treats any component object as a component.
- Placeholders in the documentation render as words. Six passages wrote a placeholder as an angle-bracketed word outside code (Quoted by
, Replace in , Your trial ends on , What's new in ); the documentation site rendered each as an unknown HTML element, so the word vanished and the browser console logged it. They are prose now. - The narrowest phones and wide desktops are checked too. Every public, dashboard and console page is now checked on the narrowest phone still in use and on a wide desktop, as well as on a tablet and a laptop. The first pass on narrow phones found two collisions, both fixed: the header's search icon sat over the wordmark on every public page (it now waits for a slightly wider screen; Ctrl/Cmd+K still opens it), and the hero proof strip's Live · 08 PM stamp painted over the figure beside it (on the narrowest phones the time yields and stays in the tooltip).
- The two scroll-built drawings stay alive once built. The savings comparison on the home page and the architecture on the enterprise page build as they scroll into view and then stood still; a reader who arrived after the build saw a static picture. Each now keeps one slow request on the clock: a dot crossing from the old bill to the routed one while the saved pill breathes as it lands, and a request descending the architecture column, lighting each wire and tier in turn. Both vanish entirely under reduced motion.
- The cost drawing's bill reads as a chart. Behind the pricing, estimate, bill and ROI pages the tall "before" column is now an outline on a faint wash - the spend that did not happen - standing with the filled routed column on a visible floor with end ticks, instead of two slabs cut off above the fold.
- No column ends in empty space. A walk over every public page measured two-column sections whose columns differed by more than a screen's worth and fixed each: the home page's Get started now shows the request and what comes back (the chat completion with its
opensmartrouteblock) beside the three steps; the enterprise Talk to sales column lists what the reply contains - the plan's own availability and support commitments and the pilot - beside the form; the explainer pages' decision drawing and the glossary's On this site list ride along while the text is read; the marketplace kind pages fold three highlights into the title column instead of a near-empty card; and the newsletter preferences page opened without its link now explains what the link is for and where to subscribe or read. - The home page's decision keeps being made. Until you touch it, the live demo in the hero walks through its example requests on its own - a rewrite, a code fix, a hard analysis - routing each for real and replaying the four moments (read, policy, priced, picked) every few seconds, so what the router does is seen rather than described. It waits while your pointer rests on it, while it is off screen or in a background tab, stops for good at your first click or keystroke, and does not run under reduced motion.
- Page analytics reach Google Analytics again. The site's content security policy allowed
*.analytics.google.combut GA4 posts its page views to the bareanalytics.google.com, which a wildcard does not cover, so every visit was blocked at the browser and logged as a policy violation in the console. Both forms are allowed now; nothing else in the policy changes. - Quieter service logs around the event bus. The Kafka driver narrated every idle reconnect (a dozen lines per service every two minutes) and printed a traceback for every socket reset - most of them from a replica being retired during a deploy, whose network goes before its process does. The platform now holds the driver's own loggers at warning while the bus runs and mutes them while it shuts down; failures are still counted and reported through the bus's health, one warning a minute.
- Every self-hosted model runs on the OpenSmartRoute model server. Five models of the curated set - Qwen3.5, gpt-oss, GLM-4.7-Flash, GLM-OCR and TranslateGemma - were still served by the Ollama image because their ollama.com downloads are Ollama's own conversions that a standard llama.cpp cannot read. A model can now be pulled from one place and stored under another name (
osr-models pull qwen3.5:4b=hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M, the same form inPOST /api/pulland in the list of models a server pulls at start), and the Azure deployment's newollamaModelSourcesmaps those five tags to stock GGUF weights on Hugging Face - the catalogue, the console and the providers endpoint keep seeingqwen3.5:4b, only the file behind it changes. The compose stacks pull the same sources; the per-model image exception stays for anyone who wants it. - Answers before the signup button. The home page ends with the ten questions developers ask - is it free, how are the models charged, do you store my prompts, how does it decide, what if a provider is down, how is the saving measured, does it work with Cursor and Claude Code, can I run it myself, who is behind this. Each answer is written from the live plan catalogue and ends on the page that proves it; search engines get the same text as structured data.
- The security review, answered up front. The claims ledger on the security page grew to seventeen statements a reviewer checks - single sign-on and SCIM provisioning, two-factor sign-in, provider keys from a vault, data boundary pinned by policy, personal data caught on the device, public status and the availability SLA, container-image signing still in progress - and opens with its count. The trust centre offers it all as one dated procurement pack to download, with the service levels per plan, the status at that moment, the legal versions in force and the full security review; Enterprise quotes the count and offers a 30-minute demo beside talk-to-sales.
- How the money works, in plain words and in machine-readable form. Pricing now states the fee model - the plan fee buys decisions, your own providers bill you with no markup, models the deployment sells are paid at the card rate with the provider's list price beside it - and publishes itself as Markdown and as JSON for scripts and assistants. The ROI calculator leads with the year-one net saving per scenario, and the proof page shows how often the packages are downloaded, with the source and the date.
- Every screen fits a phone. A sweep of all 160 pages at six screen widths, from the smallest phone to a wide desktop: the promotion bar wraps instead of cutting its link off the edge, the downloads table and the Health page no longer make the page scroll sideways, key-figure labels inside a card are no longer squeezed to a word per line, the status legend drops under its dates, charts sit beside each other only when the card is wide enough, and every standalone link or text button is tall enough for a thumb to land on. The guard that runs on every change now checks for these too.
- Code panes are coloured. Comments, strings, numbers, keywords, shell flags,
$VARIABLESand JSON keys take the brand hues on every code pane of the site, in the SDK showcase and in the playground's JSON view. - The home page says where to get the router, not just npm. Under the licence pill a row of chips names every channel - PyPI and npm with the release number, the browser extension and the desktop app with their own published build numbers, the VS Code extension, the MCP server with its tool count, and self-hosting - each linking to its page or registry; the release number itself links to the downloads page. Every chip carries the real logo in its brand colour, and a chip that stands for several products shows them all: Chrome, Edge and Firefox on the extension, Windows, macOS and Linux on the desktop app (the visitor's own in front), Claude and Cursor beside the MCP mark, Docker and Helm for self-hosting. A figure appears only when the deployment can prove it.
- Every product on the site is shown by its own logo. Wherever a page names Python, TypeScript, npm, VS Code, Docker, Helm, Kubernetes, Cursor, Windsurf, Claude Code, OpenAI, Anthropic, LangGraph, the MCP protocol, Slack, Teams, a browser, an operating system or a model vendor, it carries that product's real mark in its brand colour instead of a generic glyph: the SDK page and its integrations list, the code tabs, the documentation entry cards, the downloads table, the MCP client configurations, the Integrations and Apps panels in the dashboard, the notification channels, the provider empty states and the header menus (whose icons now each take a colour of their own).
- The catalogue pages open the same way. Models, providers, services, the marketplace and the three rankings pages share one opening: the heading on the left, the page's figures on the right as rows of one glass pane - the number, what it counts and over which window and scope on every row - instead of three bare numbers hanging under the heading or a centred title over a grid of counters. The marketplace's call-to-action buttons sit under its heading; the pane follows the heading at full width on a phone.
- The header menus open across the whole page. Product, Solutions and Developers each drop a panel as wide as the header, on the page's own grid: the group's name, one line about it and the featured card (the browser extension with Add to Chrome, Who is it for?) in a rail on the left, then the links as equal columns of at most five entries - a longer section flows into balanced sub-columns - so the three panels are the same shape and every column lines up. Solutions is regrouped into Who it is for, Where it fits and Prove it; every description is one short line. On a smaller desktop the rail becomes a band across the top so the columns keep their width.
- Every public number now says what it counts and over which window. The home page counters, the rankings, the models page, the status page and the marketplace each label their figures - all time · public deployment, last 7 days · this deployment, last 90 days · every workspace, reference catalogue · not traffic - so a visitor no longer meets 730, 752, 680 and 2.3K requests on four pages and wonders which is real. The status page says why its two request totals differ.
- The marketplace tells native listings and the imported ecosystem apart. The header shows what publishers listed here directly next to what the platform indexes from the open registries (and how many), instead of one six-digit listings figure next to a handful of installs. Imported listings without substance of their own - no README to speak of, no install, no rating, no mark - are kept out of the sitemap and carry noindex until they earn it; native listings are always indexed.
- Plain headlines on the pages people search for. The home page opens with Automatically choose the right AI model for every request and a paragraph that says what the router weighs and what happens when a provider fails; the models page is an AI model directory and routing catalogue that keeps the reference catalogue and this deployment's active routing targets apart; the rankings page separates live routing activity from the benchmark leaderboard and says a few hundred requests are not a verdict on the models; observability, security and enterprise lead with what you get and keep the former lines as supporting copy. The competitor comparisons keep one memorable phrase and state the others as plain differences. Pricing opens with the prices and the card-less trial, read from the plan catalogue.
- The blog writes fewer, better-spread posts. However many feeds deliver, the writer turns at most six entries a day into posts (
OSR_PLATFORM_CONTENT_POSTS_PER_DAY, editable at/platform/admin/settings, 0 = no limit), newest first and spread over the day's polls, so the blog grows steadily and both newsletter issues have news. - The home page is eight sections instead of twelve, and each product page says one thing per screen. Two live mock-ups, a second how it works, the model landscape, the marketplace kinds and the news each have a page of their own, so the home page now reads: the promise with one row of live counters, one request through the router, your bill, the code, eight product tiles, the vendors, who it is for, start - half the scroll, without the twelve estimate calls the mock-ups made. The desktop page folds the app picker into the hero; the extension page puts the browsers and supported sites under the hero and the install steps once, at the end. The Add to Chrome card waits until you scroll past the first screen, so it never covers the hero's call to action.
- The home page is twelve sections instead of twenty. The live counters, the same traffic, two bills comparison, the visibility-and-control panes, the industry rules, the routing-model deep dive and the editions table repeated what the hero, the request journey and the pages written for those readers already say (status, savings, enterprise, solutions, the documentation). They are gone from the home page, which now reads: what it is, one request through it, your bill, the code, the products, the vendors, the marketplace, who it is for, how it works, the model landscape, the news, start. The enterprise page's who runs it section, with nobody named yet, is headed by what you can check instead of by the absence.
- The website says in plain words what the product is. The home page now opens with The right AI model for every request. Cheaper, safer and explained and a first paragraph that says what OpenSmartRoute is - an open-source router between your team, your apps and the AI models they use - and what it does for each request; the same line sits on the sign-in pages and in the footer. The four promises under it, the model landscape, the routing model, the audience band, the pricing band and the vendor and comparison pages drop their riddles ("quality per dollar is not a straight line", "an artefact, not an impression") for sentences a first-time visitor understands, the savings counter is labelled saved by routing, and a traffic rise beyond tenfold reads 10x+ instead of +>999%.
- The terms of service were updated for the card-free trial (version 2026-10-01, effective 1 November 2026). The trial clause now says what the plans do: a free trial is granted once per workspace without a payment method and ends by returning the workspace to the free plan unless a subscription was started before; only a trial a plan states as requiring a card converts to the paid plan at its end. Nothing else in the terms or the privacy notice changed. The new version is on the terms page with its effective date, and account holders are told in the dashboard before it applies, as the notice promises.
- The desktop, extension and releases guides describe the product, not how it is built and tested. The passages about build runs, test suites, probes and internal settings are gone from the published pages; what remains is what you can install, configure, sign and troubleshoot, with a short build-from-source note for operators who need one. On the documentation index each agent skill now has a one-line description instead of a paragraph, and the sales playbook - an internal document - is no longer listed among the agent skills on the site or published as a marketplace listing.
- The last plain pages got their photograph. Sign-in, sign-up and the account pages (password reset, e-mail verification, invitations, the CLI and the e-mail preferences) show a picture beside the form - a different one for each of the three - as does the operator console's sign-in, the playground's opening band, the publish page before you sign in, and the terms and privacy pages, and the documentation's front page opens on a photograph beside its title. The industries page and the comparison pages got pictures of their own instead of sharing one with a neighbour. The pictures come from a second source (Unsplash, under its licence) next to the Pexels ones the rest of the site uses, every photographer is credited under the picture, and hero pictures now load eagerly so the first paint no longer waits for them.
- The site footer carries the brand as a watermark. The one-colour mark sits large and faint in the corner and the name runs across the base of every page in the wordmark's own face, in both the light and the dark theme. It is decoration only: screen readers skip it, nothing shifts or widens, and the lockup, the install line, the version badges, the newsletter box, the navigation and the legal row read exactly as before.
Fixed
- Every marketplace page of the sitemap answers again. The sitemap lists the marketplace in pages of 5 000 listings, and from the first marketplace page on each one answered with a server error: picking the indexable listings read the README and the manifest of every row it passed, which took the catalogue 6-10 s a page at 285k listings - longer than the site gives the catalogue. The catalogue now keeps those listings in an index of their own (built in the background at the next start), tidies the table after a large import so that index is read on its own, and answers a page in milliseconds; the sitemap allows a catalogue page the time it needs meanwhile, and IndexNow and the search consoles get the whole sitemap again.
- Desktop: a conversation the workspace would not delete stays, and the window says why. Deleting a conversation in the main window removed it from this device even when the request to the workspace failed or timed out, so it came back from the workspace on the next refresh as if nothing had happened. The conversation is now removed here only once the workspace has let it go; otherwise it stays in the sidebar and the window names the reason (The conversation was not deleted on the workspace (… failed (503)); it stays here - try again). One already gone from the workspace (deleted on another client) is removed as before.
- A provider whose key should come from an environment variable nobody set says so. The check used to send the request without a credential and report the upstream's answer - Azure's Access denied due to invalid subscription key or wrong API endpoint - which pointed at the key when the cause was the variable (typically a deployment that dropped the provider and took its variable with it). The check now reports credential $AZURE_OPENAI_API_KEY is not set in this environment. In the console a provider the deployment file retired shows why it is disabled, and its last error is labelled as the check before it was disabled, dated, rather than as a current failure.
- The blog's "how this blog is made" band shows its two commands again. The request and the
execute: trueflag were written in the pane's own colour since the band became glass and read as blank; inline code on every photograph band is now a small chip in the theme's ink, and the photo credit sits inside the band instead of being cut at its edge. - Two labels read more clearly on glass. A blue chip on a glass card (a listing's kind, a model's tag, a plan on the trust page) now writes its words in a deeper blue, in the dark theme the blue, violet and red chips take a lighter tone and the muted text is a shade lighter, so every label meets the contrast the rest of the site meets - including on the status page's check rows; the brand hues themselves, the fills and the marks are unchanged.
- The public site's scroll entrances now play in every browser. Section headings and card rows glide into place as you scroll on Chrome and Edge, where the browser drives the move from the scroll position itself; on Firefox and older Safari those pages arrived with no motion at all while a few wrapped panes still animated. The same move now runs there as a transition the moment each pane crosses into view, a pane already on screen is shown at once, and the entrance is removed under reduced motion as before. Checked on twenty public pages with scroll-driven animations switched off.
- The native desktop apps find their next developer-preview build again. The native Mac app's update checker did not compile in the preview build, and the native Windows and Mac apps' launch checks asked the downloads page for a stable build while a preview copy only follows the preview channel, so no preview build of either app shipped. Both are repaired; a preview copy is offered the next preview, a release copy the next release, as the documentation says.
- Public pages no longer wait seconds for their numbers. Every visit to the home page, What is live, the models storefront or the rankings re-scanned the whole request table - the lifetime latency, the workspaces that route, the week's traffic per model - in each service that answered, and on a busy deployment those scans slowed every other query too, so What is live often said Facts unavailable. The scans now run once per window for the whole deployment (
OSR_PLATFORM_STATS_ROLLUP_S, two minutes, editable at/platform/admin/settings); every service reads the stored figures, a stale copy is served at once while one process refreshes it, and the lifetime request counts stay live. health()works through the site's address.https://opensmartroute.ai/healthzanswered the site's page-not-found; the SDKs default to that host for everything else (/api/v1,/v1and/mcpare passed to the API there) so an uptime check orosr.health()written against the documented address failed. The site now passes/healthzto the API like the rest.- A fresh
osr servetells a chat call how to attach a model. With the starter catalogue and no model behind it,/v1/chat/completionsfailed with target llm-small has no handler (502). It now answers 503 with the fix in the message - start the server withOSR_LLM_BASE_URL(andOSR_LLM_API_KEY) pointing at an OpenAI-compatible endpoint, or give the targets handlers - and says that routing works without one. - The browser extension, the desktop app and the VS Code extension report a refused call at once. Since the TypeScript SDK began retrying a 429 or a 5xx on its own, the browser extension's card kept its Reading your draft state while the SDK waited out a Retry-After of up to a minute underneath it, and the side panel's Try again never appeared because the retry had already succeeded unseen. The three apps now turn the SDK's retries off: the card's own back-off, the panel's Try again and the bar's message are the retry, and they show the moment the platform answers.
- osr --help says where to start, and the desktop page leads with one download. The command list of thirty sub-commands now ends with a start here block - route, estimate, serve, your own catalogue, login, doctor - and the address of the quickstart. The desktop download page shows the one installer recommended for your system and folds the portable, native, admin and other-architecture files under Other downloads instead of listing up to nine files side by side.
- Replacing a photograph on the public site asks for nothing but the picture. The console's form insisted on a photographer for every new picture and on a caption written as one capitalised sentence without a full stop, and refused a source page that was not
https://. Caption, photographer, source page and licence are now all optional (the caption is free text up to 200 characters; a source page, when given, is any web address). A picture uploaded without a photographer shows no credit line - it is never credited to the photographer of the picture it replaced. The pages show a replaced picture on their next load rather than up to a minute later, each card links the pages the picture is on, and the confirmation says it is published. - A replaced photograph can no longer point a visitor at another site. The public picture address redirected to whatever the row stored and the container setting took any https address, so a restored row or a mistyped setting could send visitors elsewhere. The setting now only accepts an Azure Blob container, a stored address outside it is never handed out, and the site's picture route passes such a redirect on instead of re-serving the bytes. A refused container, or one with no credential to sign uploads, is named on the Photographs page and in the start-up check instead of falling back to the database silently; the upload form says what is wrong with a caption, a source page or a file before it sends anything, and moving old pictures to storage no longer brings back one that was reset.
- A database outage answers 503, retry shortly instead of a bare 500. While PostgreSQL restarted or ran crash recovery every request failed as a server error, which told callers the request was wrong. Such a moment now answers 503 with a
Retry-Afterof five seconds on every service, so SDKs and the gateway retry on their own, and the monitoring records it as the outage it was. - What the internet asks for is no longer counted as a platform failure. Probes for
/.env, a wrong key, a listing that is gone and a link checker'sHEADwere a third of the failed requests in the monitoring, hiding the real ones. The API now answersHEADlikeGETwithout a body (it refused it with 405), has arobots.txton its own host, and reports a 4xx as the caller's result rather than its own failure - the status code and the reason are still on every row. The website stops asking the API for/marketplace/null, a link crawlers kept from an old page, and the extension's options page forgets a workspace key the platform has revoked instead of failing on it every time it opens. - A storage blink under PostgreSQL no longer fails requests for longer than it lasts. When the network share holding the database stalled for a moment, the server's backends lost their file handles, answered every statement with could not seek to end of file … Bad file descriptor and the server restarted itself; a page view or a signup in that minute got an error, and the connection that had hit it kept failing afterwards. Such a connection is now replaced at once and the statement replayed on the new one, a reconnect waits a few seconds for the server to finish recovering instead of giving up, and the site's anonymous visitor beacon never fails a page whatever the database says.
- Blog articles are written in full again. The writer's article pass asked a self-hosted model for 2,000 words in one answer and waited for the whole of it; on CPU that takes longer than the provider's three-minute limit, so every pass was given up with nothing and the post went out as the brief's few lines or the feed excerpt. Every writer pass is now streamed - the limit applies to the wait for the next words, not the whole article - and the document reader (an OCR specialist whose actions are read and extract) is no longer a candidate to write anything.
- Replacing a site photograph while keeping its credit no longer fails. The Photographs console sent only the fields the operator had changed, so an upload that kept the shipped photographer's name arrived without one and the API refused it with a new picture needs its photographer named (a 400 the operator could do nothing about). A new picture now always travels with its photographer, source page and licence, and the form says so before it sends when the name is empty.
- A news post built from a feed entry whose title ends in a full stop no longer ends in two. The fallback summary Source published Title. kept the title's own punctuation and read "Title.." on the home page's news band; the title's closing mark is dropped before the sentence is finished.
- A provider the deployment stops naming stops being used. Dropping a cloud provider from a deployment's provider file takes its credential with it, yet its models stayed on offer and every request routed to one failed with authentication failed until someone noticed. The platform now disables such a provider at start-up (its offers and mappings stay, and it comes back the day the file names it again); providers added in the console are never touched.
- A database connection cut mid-statement healed itself only half the time. When the network closed a connection while a reply was on its way, every later statement on that connection failed with another command is already in progress - a background job in one service failed every five minutes for a day. Such a connection is now replaced and the statement replayed once, and the old socket is closed at once rather than left to the garbage collector.
- Application Insights no longer counts a replica checking itself as traffic. Every readiness probe routes a sentence through the engine, and each of those routings left three events and a dependency row in the monitoring - about a million rows a day across the services, drowning the real decisions and paid for by the byte. The probe's own routing is left out now; what you see under
customEventsanddependenciesis what callers did. - An event-bus connection left idle no longer fills the log with resets. Managed brokers, the gateways in front of them and the network in front of a self-hosted broker on Azure Container Apps all hang up on a connection idle for about four minutes, while the Kafka driver holds one for nine: on a quiet topic the next read met a socket the other side had closed, and every service logged
Connection reset by peeror Connection lost: socket disconnected on the clock. Nothing was ever lost - the producer retries and the consumer rebuilds - but the noise buried real errors. The clients now let an idle connection go first, whatever the broker's protocol, afterOSR_PLATFORM_KAFKA_CONNECTIONS_MAX_IDLE_MS(three minutes by default;0leaves the question to the driver). - The background sweeps survive a database connection the server dropped. When PostgreSQL closed an idle connection (a restart, a load balancer cutting a quiet flow), a statement outside a transaction was already replayed on a fresh connection, but a transaction block was not: the finance sweep, which opens every pass by expiring dead spend holds inside one, failed pass after pass with server closed the connection unexpectedly until the process was restarted, and wallets, unpriced rows and expired holds waited with it. Beginning a transaction on a dropped connection now reopens it first, so one lost connection costs one pass, not the night; and a connection quiet for four minutes is replaced before its next statement, ahead of the server's ten-minute idle cut, so the sweeps no longer meet it as an error at all.
- A greeting no longer drags a translation skill and a web search into its plan. "Hi" or "Say hello in one word" was answered with a plan of five parts - the model, a persona, the translate skill and two tools - because each companion had a good record on other requests. Each companion is a request of its own, run and paid for, and the translate skill on a greeting is how an answer once read like a code object. A skill or a tool now joins a plan only when the request names it: an action or a domain it declares, a need for fresh facts for a web tool, or a text close to its own examples. A greeting gets a model and, at most, a persona; a summary request keeps its summariser, a data question keeps its SQL tool.
- Reading a screenshot or a photographed form goes to the OCR model again. The example catalogue's rule sent a picture to the OCR reader only when the request was recognised as extraction; "read the text in this screenshot" and "digitise the handwritten form in the attached photo" are recognised as reading, so the picture-generation rule caught them and pinned them to the image generator. The rule now accepts either verb; on the hand-labelled reference set the router alone goes from 66 to 68 of 70 and, with the packaged routing model, from 68 to 70 of 70. Generating a picture still goes to the image tool.
- Quotes no longer recommend an embedding model. A cost quote for a text request could name an embedding model as the recommended, cheapest pick - it is priced per token and cheapest of all, but it returns vectors, not an answer. Quotes and the recommended-models page now keep embedding, transcription and speech models out, as the chat endpoint already did.
- The playground's ranked list shows latency as a readable duration. The expected latency next to each candidate was a raw number of seconds with a long fraction; it reads 420 ms or 1.2 s now, like everywhere else on the dashboard.
- The VS Code extension shows the model and the cost of a streamed answer. While an answer streamed into the editor the decision - which model wrote it, what it cost, how long it took - was dropped and the panel showed none of it; it now reads the decision the last chunk carries, the same way the browser extension and the Word pane do.
- "Open it again" on the desktop welcome screen shows the code it opened. The link started a fresh sign-in in the browser but left the previous code on screen, so the two could disagree. It now restarts the sign-in the way the Settings window does: a new code on screen, the same one in the tab.
- The downloads page states what is true about Safari and signing. The browser list said Safari - soon no matter what the deployment had published; it now reads the release manifest, like the extension page does, and says Safari the moment a Mac app or store listing exists. The desktop install steps told everyone to expect SmartScreen and Gatekeeper prompts; the desktop release now records whether its installers were signed and notarised, and those steps appear only for the builds where the prompt will actually show.
- The desktop walk-through on the site once showed a list of numbers as an "answer". The platform writes the walk-through's answers through its own router, and for one draft the router had picked an embedding model - a model that returns vectors, not text - so the "Teams" scene pasted 1,536 decimals into the chat. Embedding, transcription and speech models are now out of every platform writer's reach (the walk-through, the content writer, the newsletter), an answer that is not prose is never shown or learned from, and the page itself refuses one should it ever arrive.
- The walk-throughs on the desktop and extension pages now explain themselves. Under each demo a strip names the steps as they happen - Press the shortcut · Type the request · Checked here first · Router picks a model · Answer, price, time · Lands in the app (for the extension You type · Read on your device · Redact · Model and price · You send) - with one plain sentence per step, so anyone can follow what is happening and an engineer sees where the on-device work ends and the router begins. Each answer carries a sentence on why this model: the kind of request, how heavy it is, what the pick saves against the dearest model that could have done it, and whether personal details were replaced first. The scenes carry everyday names - Notes → action items, Pasted API key, Debug step by step - and the small print under the desktop demo now says what is true: the answers are real.
- The counters on the home page only go up now. The tokens processed, decisions made, amount kept and the top targets on the site were summed from the request rows each time, so the daily retention sweep, a workspace that was deleted and the move of the platform's own writing jobs out of the headline each made the numbers fall. They are now kept in a ledger that every request adds to and nothing subtracts from, with the month it started counting shown under them. A deployment that already has traffic starts the ledger from the totals it has today.
- Blog pictures are kept on the platform, not borrowed from the source. The picture on a post, in the list and in the newsletter was loaded straight from the publisher's site, so a publisher that moved or removed its image left a blank tile, and every reader's browser told that publisher which post they were reading. The platform now downloads each post's picture when the post is written, brings it to web size (no wider than 1,600 pixels, a tenth of the weight of a publisher's original) and copies the older ones a few at a time; the site serves them itself at
/blog/<post>/imageand keeps each one for a day, so twenty readers opening the blog at once no longer send twenty requests per picture to the platform. Until a copy exists the address still points at the source, so nothing goes blank in the meantime. Operators can copy the rest at once from the console. - A model's deployment address on the site leads to the model's page, not to a soft "not found". Links of the form
/models/openai/gpt-4o@azure- the id a deployment answers to - rendered an empty page with a 200 behind it; they now redirect with a real 308 to the reference model's page, and the sitemap lists only the model cards the site actually serves (45 dead addresses removed), so search engines stop indexing blanks.
Security
- The operator sign-in page no longer describes the deployment to whoever finds it. Before anyone had signed in, the console's login screen listed the edition and platform version, the SDK version and target count, the learning mode, the storage back ends (PostgreSQL, Redis, the event bus and whether it is clustered), the SSO providers and mail and billing switches, and the name and placement of every service behind the gateway - a map of what to attack, handed to an unauthenticated visitor. The page is now static and says only who it is for, and the public
GET /api/v1/infoit read from no longer carries the storage back ends, the event topics, the service topology or the mail transport either: those are operator facts and live onGET /api/v1/admin/overviewandGET /api/v1/admin/services, behind an operator session. The console's overview shows all of it once you are signed in. - A page cannot press the browser extension's buttons for you. The widget, the card and the selection toolbar live in shadow roots on pages the extension does not control, and a page's own script could reach them and fire synthetic clicks and keystrokes at Rewrite, Fix, Use this or a command - running requests on your workspace (your quota, your activity log) with text the page chose, or taking router output into its own field. Now that the widget is on every site by default this mattered: every one of the extension's surfaces now acts only on input the browser raised for you and drops anything a script dispatched, verified end to end.
- The desktop app moved from Electron 33 to Electron 42. Electron 33 reached the end of its support and carried a list of unpatched flaws - among them a context-isolation bypass, header injection in custom protocol handlers, path-validation bypasses and several use-after-free bugs. The app, its installers and its checks run unchanged on the supported release.
- Dependency updates across the web app, the browser extension, the desktop app, the TypeScript client and the VS Code extension for the advisories of the last weeks: DOMPurify (DOM XSS through a detached subtree) in the site, extract-zip (symlink path traversal) and fast-uri in the desktop build chain, js-yaml in the client's code generator, brace-expansion in every lint chain. The Python packages of the API image audit clean; the development environment's PyJWT and urllib3 are on their fixed releases.
- The Word add-in's manifest is written for the configured public address only. It used to take the address from the request's forwarded
Hostheader, which an ingress that passes the header through would let a stranger choose; the request's host is used only while no public address is configured (a local run). - Next.js updated to 16.3.8 for a critical advisory. Versions 16.2.0 to 16.3.5 carry a remote-code-execution
flaw in
next/og(GHSA-vcvr-r3jv-pc5j), the image route the site uses to draw the card a shared link unfurls into - a public endpoint, so this was reachable. Anyone running the web app from source should take this release; the hosted platform is already on it.
1.10.0 - 2026-09-30
Added
- The newsletter follows the topics you choose, and every topic has its own RSS feed. From the preferences link in any issue you can tick the topics you want - models, LLMs, agents, research, AI in general - and the daily or weekly issue arrives cut to those posts, with a subject and opener written for what you get; on a day with nothing in your topics no e-mail comes at all. Subscribing from a blog category page signs you up for that category alone, and you can widen it any time. Each category and each tag of the blog is also a feed of its own (
/blog/feed.xml?category=agents), so a feed reader can follow one subject. - A sign-in you did not make now reaches you in the product, not only by e-mail. The platform already wrote to you when your account was opened on a device it had not seen before; that notice now also appears in the dashboard bell, with the browser and system, the method, the address and the time on your own clock, and a link straight to the page where you can end that session and change your password. A mailbox can be filtered, forwarded or shared - the bell is where you already are. These account notices are yours alone: another member of your organization does not see them, they follow you from one workspace to the next, and the operators of the deployment do not see them in the console either. Filter them with Account in the inbox.
- Real photographs on the marketing site. Every public page - the home page, the solutions, pricing, enterprise, security and developer pages, the models, vendors, blog, status, rankings, marketplace, comparison, support and newsletter pages and each model, vendor and listing detail - now carries a photograph of people at work: beside a light hero, behind a dark hero under an ink scrim, or as one full-width band per page. The thirty-four pictures are real Pexels photographs of professionals, developers, finance teams and data-centre engineers, kept sharp for a full-width band on a retina laptop and lifted to a clean bright tone where the frame was dark; each is credited with its photographer and licence and described for screen readers. The copy stands on the ink side and the people on the other; on a phone the picture sits above the copy.
- Every public page now opens on the brand, and shares as the brand. The picture a link to any page unfurls into on social networks and in chat apps used to be a plain gradient with a coloured square; it is now the OpenSmartRoute lockup on the mark's own dark ground, with the mark's geometry - one request fanning to three destinations - drawn beside the page's title, so a shared link is recognisably ours before anyone reads it. Pages that did not open on a story hero - pricing, models, providers, downloads, rankings, the newsletter, the comparisons, the blog, the marketplace and the legal pages among them - now open on the same quiet brand wash as the rest of the site, in both themes. Page titles and search keywords say what the product does instead of borrowing other companies' product names; the catalogue, vendor and comparison pages still name vendors because they are about them.
- A native Windows app, beside the native Mac app.
OpenSmartRoute-<version>-win-x64-native.exe(and-win-arm64-native.exe) installs the same command bar, main window, settings, writing assistant and island as the Mac app: Mica and Acrylic on Windows 11, the system accent on every action, no administrator prompt,/Sand/ALLUSERSfor administrators, upgrades in place; the-native-portable.exebeside it is the bare exe. Ctrl+Shift+Space opens the bar over the app in front; the selection is read and the answer pasted back through Windows' own accessibility layer, so nothing has to be granted, and the writing assistant uses Windows' own spell checker in every language you have installed. The key is sealed with your Windows account, an organisation'smanaged.jsonis the same file the Electron app reads, and both Windows apps can run side by side. - Teams inside an organization, with leads who run their own people and keys. Until now every key, tenant and invitation went through a workspace admin. The Members page now carries Teams: group members into a team, bind it to a tenant so its keys, budgets and spend are its own, and name a lead who adds and removes the team's people and mints, renames, rotates and revokes its keys without the admin role. Each key remembers its team; each member's teams show beside their name; the API keys dialog offers the teams you may mint for; the Tenants page names the teams running under each tenant; operators see a workspace's teams in the console, and Download my data carries them. Leaving drops your team memberships; deleting a team hands its keys back to the workspace; deleting the organization drops its teams. Requested by customers.
- Roles say what they actually allow. The role help on Members claimed only owners handle billing; the checkout, the billing portal and cancellation have always been open to admins too. The copy now matches the API, and the documentation's role table gained the actions that were missing from it.
- The packaged routing model can no longer fall behind the catalogue it was trained on. The model that ships inside the package is trained by hand, so a target added, removed, repriced or re-described in the reference catalogue could leave it routing against a set that no longer exists, with nothing to say so. Every release now compares the two and names the target that moved; rewording a persona's instructions - which the router never reads - does not call for retraining.
- A streamed answer that stops arriving now ends instead of hanging. The TypeScript SDK's
timeoutMscovers the wait for the response headers only - once they arrive it no longer applies, so a connection that went quiet mid-answer left the caller waiting for ever with no error and no tokens. Every stream (chat completions, the Responses API, the Messages API) now gives up afterstreamIdleMsof silence between events and says the answer stopped arriving, with whatever did arrive already delivered. The default is five minutes - the same budget the platform keeps for a first byte, so a model that thinks for a long time is never cut off - and a call can set its own or pass0to wait indefinitely. - The go-live checklist now watches the backups. A scheduled job that quietly stops writing is invisible: the hosted platform ran five nights on a database dump that aborted on one corrupt row, and nothing on the platform said so. The checklist carries the age of the newest archive beside every other promise - fine under 30 hours, action beyond that, and blocked when the directory holds nothing at all or the newest archive has passed a week. Point
OSR_PLATFORM_BACKUP_DIRat the archive share (the hosted deployment mounts it read-only on the API) to switch it on; a deployment that backs up another way is not asked. - The desktop app now offers its writing assistant when you first open it. The assistant was finished - it watches the field you are typing in through the operating system's accessibility layer, checks spelling and grammar on your own machine, and fixes a slip in place - but it shipped switched off and was named only in Settings, so almost nobody ever met it. First run now offers it as a step, on any system that can read a focused field, saying plainly that the checks happen on that computer and that terminals and password fields are never read. It stays off until you turn it on: nothing starts watching because you clicked past a screen.
- A go-live checklist for operators. The console's new Go live page reads the deployment the way a buyer meets it: every promise the public site makes - the payment account can take money, plans can be bought, overage is invoiced, tax is calculated at checkout, e-mail reaches people, inquiries reach someone, models answer, the terms and privacy notice have a published version, connections are encrypted, the status page is live, every audit chain verifies, no offer is priced above the vendor's list price - is checked against the live configuration and reads holds, action, blocked or recommended, with what the customer is told, where the site says it, what the deployment does today and what to change. The verdict (Not ready to sell, Ready to sell, with caveats, Ready to sell) heads the console overview, so the operator finds a broken promise before a customer does.
- A native Mac app for macOS 15 and later. Beside the Electron build, drawn with Liquid Glass on macOS 26 and weighing about a megabyte: the same command bar over any app - the on-device verdict, Redact, the streamed answer, the decision and Paste into - the main window with the workspace's conversations, models and usage, sign-in with the browser and the key sealed in the Keychain, the same managed settings file as the Electron app, and
osr://ask?text=…&send=1for Shortcuts and launchers. The on-premises router option is shown only to Pro (or higher) workspaces or under a managed file; everyone else talks to the hosted platform. Signed and notarised like the Electron build; the downloads page labels the universal disk image native app (macOS 15+). - The Mac writing assistant says what OpenSmartRoute notices, not only spelling. It watches the field you type in, in any app (Office, Teams, Slack, Mail, Notes, browsers, editors, the ChatGPT and Claude desktop apps), checks the text on the Mac with the system dictionary and grammar checker plus the shared rules, and writes fixes in place. Beyond slips it flags an API key or a card number about to leave - Redact swaps it for a placeholder in the field itself - shouting, a chat message grown into an essay, a question to answer, and in an AI assistant's composer the token estimate and the tier with Route it. Nothing is redacted or sent without a click.
- The island. A live activity that continues the MacBook notch (a tab at the top edge on other displays): one line while the router thinks, the decision when the answer lands, what the assistant found in the field you are in, fixes and redactions as they are written, the sign-in code to approve. Move the pointer up to it for the actions - Copy, Paste into the app, Stop, Redact, Fix all, Undo, Ask, Workspace. Colours follow the system accent and the OpenSmartRoute mark is drawn natively for the menu bar, the bar and the island.
- A trust page for procurement. One page you can send before legal review: live status and the 90-day share of requests answered, what each plan commits to for availability and support and how the platform measures it, the data-processing agreement clause by clause, every subprocessor with its location and what it sees, the security overview with the plain statement that no certification is claimed yet, and the legal documents in force with their versions. The addresses people guess - SLA, DPA, subprocessors, about - lead there, and the talk to sales form arrives prefilled when you ask for the agreement.
- Six more comparison pages. Cloudflare AI Gateway, Kong AI Gateway, Helicone, Not Diamond, Martian and Unify join OpenRouter, LiteLLM and Portkey: where each wins, where the router does, the capability rows and a way to use them together with commands that run.
- "Who else uses it" is answered on the enterprise page. Production users and evaluating teams are listed as they agree to be named; until then the page says that nobody is listed yet and points at what a buyer can check instead - the status page, the changelog and a request of their own in the playground.
Changed
- A learned routing model is held to the hand-labelled reference set. The routing model that keeps learning from your traffic could promote itself on traffic of one kind until it routed everything like that kind - its own scores said 95 %, the labelled reference rows said 23 of 70, and the whole router got worse for it. The reference set now ships inside the package: a new model version that loses labelled rows is refused whatever its own score says, and at start the served model is compared with the packaged one and replaced when it fell below. Deployments with a catalogue of their own are unaffected.
- The routing model can now learn from your traffic without losing what it knew. With the labelled floor in place, a model trained on one workspace's requests learned them perfectly - every holdout row won - and forgot the reference set (44 of 70 rows), so the floor refused it, every cycle, and no workspace or deployment model was ever promoted again. The reference rows now train every challenger alongside your traffic (about a quarter of the batch,
OSR_SLM_LABELLED_REHEARSAL); the same challenger keeps 69 of the 70 reference rows while it learns yours, and is promoted. The holdout it is judged on is still your own traffic, and the floor still holds. - A routing decision costs the server less. Under a full-platform load test one API replica routed about 19 requests a second; the same replica now routes about 31. Three things were slower than they needed to be on every decision: the similarity strategy recomputed figures that never change, the contextual bandit solved each candidate's arithmetic three times where once is enough and now keeps the answer until the candidate learns something new, and the tamper-evident audit chain opened, locked and closed its file for every record - on the hosted platform that file is on a network share, where the open and the close are what cost. On Linux the chain file now stays open between records and is reopened only when it was rotated or removed underneath; the chain, its verification and the rotation behave exactly as before.
- A softer, smoother feel across the web app, especially by touch. A tap acts at once (no double-tap wait, no grey flash over the tapped control); the small controls - icon buttons, row actions, close marks - answer a finger from a full finger-sized area without changing size, and table rows get a little more room under a finger. A card that is a link lifts gently under the pointer; folding cards and Advanced sections unfold instead of snapping; loading placeholders show a soft travelling sheen rather than pulsing; switching between light and dark cross-fades the whole page where the browser supports it. Everything stands still for anyone who has asked their system for reduced motion.
- The phone view finished. The home page's routing picture is drawn again for a narrow screen - the hub and the five target cards sit close, at full type size, instead of the desktop picture shrunk until its labels were unreadable. The plan comparison on the pricing page keeps the row label in place while the plan columns scroll under a finger. The floating Help button no longer covers the Copy button and the row actions at the right edge on a phone, where Help lives in the menu, nor in the dashboard on a laptop, where the header already carries it; Back to top moves down with it. The last pulsing placeholders and the hand-styled hover states on story, listing, post and support cards now share the one soft lift.
- The console's Terms and privacy page publishes a newer text. It now says when the page text is newer than the published version and publishes it.
- The router ranks self-hosted models on what they really do. A model on a CPU server writes about five words a second: a one-line answer in ten seconds, an article in minutes. The catalogue described it as fast and dear, so the router sent almost nothing to the self-hosted models and quotes and time limits read a figure nobody had measured. Every routing process now reads the speed and the billed price of its models from the requests they actually answered - a fixed part and a per-word part, so a slow model keeps the short requests it is good for and loses long drafts - and the estimate, the
max_latency_mslimit and the health check all use the same expectation. A catalogue may declarelatency_per_token_msitself. The declared figures stay visible next to the measured ones on every target. - The savings baseline is a model you actually used. The saving on the Savings and Impact pages, the trace, the usage report and the public figures is now measured against the dearest model your own executed requests ran on, not the dearest model in the catalogue; a workspace that only ever used a small model reads an honest zero with the sentence that says why and where to pick the model it used before routing. Every figure names its baseline. Requested by customers.
- Pricing says what happens at checkout. Prices are stated as US dollars excluding tax, with the tax for your country calculated and shown at checkout and itemised on the invoice (a tax id you enter appears on it - the checkout now asks for one on subscriptions as well as credit purchases), and the cancellation and refund rule is one sentence under the plans. A new answer explains what the free plan can run: decisions and chat, while execution from the routing API and plans are Pro and up.
- Quotes name the model that answers. When a target runs a local model the catalogue cannot identify, the estimate, the use-case picks and the rankings now show the provider's own model name instead of nothing.
- Pages settle in reading order. Dashboard and console pages now arrive card by card - summary tiles rise in sequence and charts fade in once their numbers are ready - and the marketing site shows everything above the fold at once instead of waiting for scripts, revealing the rest as you scroll (a jump to an anchor never leaves a section invisible). Anyone with reduce motion switched on sees every page fully drawn on first paint.
Fixed
- The browser extension fell a release behind without anyone being told. Release 1.9.0 shipped the SDK, the npm package, the desktop app and the hosted platform at 1.9.0 while the extension page went on offering 1.8.0: Mozilla's review of the Firefox package outlasted the wait the publishing step allowed, and that one wait took the Chrome, Edge and Safari packages and the version pointer down with it. Signing can no longer hold a release back - the other browsers and the pointer publish, and publishing the same release again fetches the signed Firefox package from Mozilla instead of submitting the version a second time, which Mozilla refuses. A release now counts as complete only once the extension, the desktop app and the hosted platform have been read back at the new version, so a channel left on an older version is named instead of going unnoticed.
- Search engines were only ever shown 761 of the site's addresses. The sitemap is split into files because the marketplace alone has more than a hundred thousand listings, but every file answered with the same first one, so the listing files, and all but the newest hundred blog posts, were never submitted. Each file is now its own: the site's pages, documentation, model and vendor pages first, then every blog post including the archive, then the marketplace - more than 260,000 addresses in all - and a page carries a modification date only when it has a real one. The IndexNow push, which told Bing and the engines that share its protocol about new blog posts only, now also submits every page, documentation, comparison, model and vendor address the sitemap lists, once each. The home page's search snippet is a sentence that fits a result instead of a paragraph cut off mid-way.
- The home page weighed two megabytes before a single picture. The live demos on it quote a dozen drafts on the server, and the whole answer for each - every strategy's score, the reasoning, the token split for each of ninety candidates - was sent along to the browser. The demos now receive only what they show (who the candidate is, what it costs, how fast it is, where it ranks, for the picks and the best-ranked dozen), and the model landscape sends its list across once without the vendor blurbs. The page is now under a megabyte; the demos look and behave the same.
- Sign-ups through GitHub, Google or Microsoft now carry their acquisition source. The first touch the site remembers (campaign, referrer, landing page) travelled with an e-mail sign-up but not with a sign-on through GitHub, Google, Microsoft or another provider, so the funnel's split by source undercounted every channel that brings developers who click a sign-on button. Both sign-on paths now carry it, recorded only when the sign-in creates the user, and the sign-up form reports attempts and the reason a sign-up failed alongside the successes.
- A page with a photograph could sit "loading" for minutes. The pictures were offered in AVIF as well as WebP, and making an AVIF of a full-size photograph took the web server two to five seconds a size - and one that never finished left its address dead until the next restart, so every page carrying that picture kept its loading indicator going while the text was long since readable. Pictures are served as WebP only (the sources already are), resized in a fraction of a second and kept for a day once made.
- The blog's "keep reading" sheet no longer covers the subscribe form. The sheet is pinned to the bottom edge, which is exactly where the newsletter form in the footer lands once you scroll down - so the one action it asks for was the one action it blocked. It now steps aside whenever a newsletter form is on screen, and returns when you scroll away from it.
- Every page walked on a phone, and what it turned up fixed. The industries page said 0 industries; it now shows the count. The MCP server and observability pages showed
·and├─where a middle dot and tree lines belonged. The price frontier chart piled seven model names into its dear corner; labels now keep their distance on the price axis and a phone shows three. The console's feedback, legal, mail, rankings, reports, settings, users and workspaces tables and the marketplace rankings board keep their first columns and status on a phone and bring the rest back from tablet width; the public providers table pins the target name while its nine columns scroll. Two feedback stat cards showed a sentence at display size; the sign-up form starts under the header; the footer newsletter field is a full line; the rankings tabs sit on one row. - Arithmetic sent to the chat endpoint is answered by the calculator again. A built-in tool only answers an OpenAI-shaped chat when the router is confident it is what the request asked for; below that mark the chat is routed again without tools, so a failing model pool cannot turn "say hi" into a list of search results. Once the catalogue's prices were calibrated against the real model cards, the calculator's confidence on some questions settled a hair under that mark and a small model answered the sum instead - slower, priced per token and less exact. A tool that has already parsed the request now counts as a fit whatever the score says, so
12 * 37 plus 5 percentcomes back from the calculator; a greeting still holds no arithmetic, so the protection is unchanged. - A wrong address keeps you where you were. A documentation link to a page that was renamed dropped you on a bare "page not found" with no sidebar; a failure inside the operator console or the sign-in flow showed the site's generic error page. Each part of the site now answers in its own shell: the docs keep the tree and the search and say the document may have been renamed, the console keeps its navigation and points at readiness and search, the sign-in pages keep the sign-in and sign-up buttons, and every one of them carries the error reference to quote to support.
- Proofread in the browser extension keeps your words. Proofread showed the slips it would fix, but Apply pasted the model's whole answer - and a small model, asked to correct, rewrites: a greeting appears, what I don't understand becomes which figures are unclear, your tone becomes its tone. The extension now applies exactly the listed corrections to your own draft; whatever else the model wrote is discarded and the note says so. A suggested change that is not in your draft is left out rather than guessed. The rewrite and command prompts also ask for your point of view and forms of address, with no added pleasantries.
- The browser extension no longer asks for access to your own machine. Every published package declared your computer's local addresses (
localhostand127.0.0.1) alongside the hosted platform, so the install prompt asked for access to the reader's own computer and the one-click connect bar appeared on any site they happened to be developing. Those addresses were only ever meant for the automated browser checks; they are now baked into that build alone, and a store package reacheshttps://opensmartroute.aiand nothing else. A self-hosted platform - a localosr serveincluded - still works: enter its address in Settings and the browser asks you to allow that one origin. Every shipped package is now checked for a local address before release, so it cannot come back. - A free trial no longer collects a card where Stripe cannot charge yet. Stripe refuses a paid checkout on an account that has not finished activation, but it accepts a trial ($0 today), so a buyer could type a card into a Pro trial that would have been cancelled at trial end without a word. The platform now reads the account before every checkout - plan, trial, credits or listing - and answers Payments are not open on this deployment yet the same way for all of them; the operator's Finance alert and the go-live checklist say a trial is refused too.
- A chat answer no longer echoes a skill's raw result. When a plan ran a skill on a model (the translate skill on a small model, for example), the skill's result was written into the model's instructions as an internal object -
ChatResult(text=…)- and could be echoed to the customer as the answer. The skill's text is what reaches the model now. - The friendly-support persona no longer greets a "hello" with an apology. Its instructions told the model to acknowledge the customer's frustration first, whatever was asked; it now does so only when something has gone wrong for the customer and never assumes a problem that was not mentioned.
- A date or a timestamp in an answer is no longer flagged as a phone number. The PII detector treated any run of ten digits, spaces and dashes as a phone, so an answer that mentioned 2026-09-28 08 or a unix timestamp raised answers carried PII on the dashboard and got redacted where the output guard redacts. Phones now need seven digits and are told apart from ISO dates, decimals, version strings and IP addresses; every real phone format still counts.
- A missed database backup is a critical alert. The nightly backup of the hosted platform failed for two days on a damaged row and nothing on the platform said so. The backup job now records every finished archive; when the newest is older than 36 hours the operator console's Health page and the operator notifier raise The database has not been backed up. Customers never see it.
- No more twenty-minute waits on a model that was never loaded. Several Ollama servers sharing one model store each listed every model on the disk, so the storefront sold every model on every server while only the mapped one was resident; a chat routed to the wrong server waited for a cold load of tens of gigabytes and failed. An Ollama server now offers only the models it is mapped to run, List models skips the rest and says so, every sync pauses an offer that points at a server which does not run the model and writes the reason in its notes, and a per-model server is recognised as Ollama by name or port too, so it is kept warm.
- One audit trail per replica. Two replicas of the API appending to a single chain file on a network share broke the hash chain (a file lock is not honoured across hosts), so the compliance posture of every workspace showed a broken audit trail after each deployment. On a clustered deployment each replica writes its own chain, the audit views merge them, and the go-live checklist shows whether every chain verifies.
- Sessions survive a deployment with several replicas. The shared session secret is now provisioned with the infrastructure (kept from the running deployment, generated once when absent), so sign-ins are honoured by every replica and the preflight no longer reports it missing.
- The desktop app's Overview no longer forgets what you have spent. Its headline figures were a sum of the conversations kept on that computer, so they fell back to zero whenever the local history was trimmed to its limit, cleared, or dropped at sign-out - and they never showed tokens at all. Overview now reads the requests, tokens and spend your workspace counted over the last 30 days across every client, the same figures as Usage, so they match the dashboard and survive anything that happens to the local history. Without a connected workspace it still falls back to the answers kept on that computer and says which it is showing.
- The site tells the truth when routing cost more than the direct bill. The landing page's two bills section and the usage band showed $0 saved in green with the routed bar pinned to full width when the routed traffic had in fact cost more than sending everything to the baseline model. Both now say $X more than the direct bill in amber, draw the dearer bill as the taller bar, and explain that dearer targets were chosen where a request's policy or quality bar asked for them.
- Marketplace cards read as plain text and price a model honestly. A model imported from a catalogue could show its description's raw Markdown (
built on [Kimi K3](https://openrouter.ai/...)) and every model was labelled Free although it is metered by the token; summaries are stored and shown as plain text and models say By the token (the install itself is free). - Trend pills no longer paint the models list red. A fall in a model's traffic week over week is not a failure; it now reads muted, a rise reads in the brand blue, and first period with traffic became new with the explanation on hover.
- Rankings default to requests while the window has no token counts. Before, the leaderboard showed every row at 0 and 0 %.
- The hero washes end softly. On the story pages, the trust page and the enterprise page the hero wash ended in a hard horizontal edge; it now fades out.
- The blog's featured post shows its whole picture. A diagram was cropped to a white rectangle; it now shows in full over a blurred wash.
- The status page's daily bars read against a date. The chart gained a date axis and a legend line.
- The desktop page's app tiles always show Watch it here. The link appeared only on hover, which a phone has none of.
- The hero's two actions line up on a phone. They now stack to the same width.
- The dashboard shows a customer their own alerts, not the operator's. A workspace's Overview and Health carried The Stripe account cannot take payments: nobody can buy a plan or credits and the markup on the storefront's models - deployment money alerts that belong on the operator console. They no longer appear on any customer surface.
- Health calls a failing target failing. A target whose every call had failed still wore a green healthy badge (its breaker had not tripped yet) under a header reading all healthy; the badge now says failing or degraded from the observed rate and the header counts targets failing every call. An executed request that failed on every target now names them - llm-onprem could not answer (host does not resolve); no other target could take the request - instead of the adapter's bare sentence.
- Small dashboard slips are fixed. The Savings baseline select cut a long model name mid-word; the console's price book wrapped model ids letter by letter; the sidebar's navigation ended in a cut-off row where it scrolls under the account footer; on a phone the What's new title was cut to two words and the Getting started card pushed Take the tour onto its own line.
- A Stripe account that cannot take payments is named, not hidden behind an error. The live Stripe account had never finished activation, so Stripe refused every checkout and a buyer clicking Upgrade read Stripe's developer sentence behind a 502. The operator now sees a critical deployment alert (The Stripe account cannot take payments: nobody can buy a plan or credits) naming what is missing, read live from the account and cleared within the hour of fixing it; a buyer who tries meanwhile reads Payments are not open on this deployment yet - the operators have been alerted. Contact sales to buy in the meantime. on both the plan and the credits checkout.
- Two phone and tablet layouts no longer overflow. The status page headline wraps on a small phone instead of pushing the page sideways, and the SLM console's service and model details stack their labels above their values until the side column is wide enough for two columns.
Security
- Browser-hardening headers on every response, and browsers told to stay on https. The web app sends
Strict-Transport-Securityand, in a production build, aContent-Security-Policythat allows the page's own scripts, styles and images plus Google sign-in, Google Analytics when configured and the Stripe pages the billing flows open - nothing else - and that forbids framing,<base>hijacking and plug-ins. The API, whose responses had none of these, sendsX-Content-Type-Options: nosniff,X-Frame-Options: DENYandReferrer-Policy: no-referreron every response andStrict-Transport-Securitywhen its public URL is https. Neither origin sent HSTS before. - The runtime images carry a current
pip. The Python base image ships apipwith a dozen published advisories; the platform never runs it, but a container scan reports it all the same. The platform API image, theosr serveimage and the development image upgrade it at build time;pip-auditinside the image now reports nothing. - The self-hosted stack refuses to start on the passwords printed in this repository. The compose file defaulted the operator password, the database password and the session secret to
change-me-…, and the example environment file shipped the same values ready to copy. Anyone who ran the documented command on a public host got a workingadminaccount whose password is in the open. There are no defaults any more: compose stops with a line naming the variable to set, and the example file leaves each one empty. - Nothing test-shaped is left in what we publish. The browser extension's DevTools panel carried a demo mode that invented OpenAI and Anthropic calls and an entry point for feeding it rows - both compiled into the bundle sent to the stores. The desktop app registered three internal channels that exist only so an automated check can open the bar or a window. All of them are now built only into the test builds that need them: the published extension and the installed app carry neither, and every released bundle is checked for them before it goes out, so a sample row or an injection hook cannot return quietly.
- The Helm chart refuses two installs that look fine and are not. It shipped an example catalogue - a cheap model, a frontier model and a human queue, with invented prices - as the default value, so
helm installwith no catalogue produced a router that priced and chose real traffic against targets that do not exist. Andingress.enabledput the API on a hostname while access tokens were empty and not required, publishing an open router. Both now stop the install with a line naming what to set: your own catalogue (or an existing ConfigMap), and a token (orauth.allowAnonymousIngress=trueif an open API is genuinely what you want). Nothing changes for an install that already passes a catalogue and a token.
1.9.0 - 2026-09-23
Added
- The router understands five more kinds of work. Searching the live web, reading a scanned or photographed document (OCR), finding the cause of an incident from logs and traces, driving a browser (open the portal, log in, fill the form, download) and acting on the desktop (rename, move, paste, type into the window in front) are now task types of their own; a target can declare search, OCR and browse actions and the observability, science and education domains, and the browser extension's on-device analysis knows them too. The reference catalogue gains a web search tool that really searches (DuckDuckGo and Wikipedia without a key, SearXNG or Brave when configured), a browser and desktop automation agent and an SRE agent.
- A routing model trained on all of it, with persona and skill slots. The packaged model is retrained on the widened catalogue and 70 labelled examples (0.97 holdout accuracy, up from 0.93) and now carries persona and skill slot models, so a composed plan picks which persona speaks and which skill instructs with a learned ranking from the first request (0.99 on both).
- A human queue is a last resort. Without an explicit ask to escalate, a human target's capability fit is halved, so a queue with a high quality prior no longer wins plain questions - which had also skewed a fifth of the model's training labels towards it.
- Real users only on a real site. A deployment that refuses reserved testing domains at signup (
example.com,*.test,*.local, the default) now refuses them at the operator's doors too - a workspace or user created from the console, a member added by e-mail - and its retention sweep removes any such test data that still got in, conversations and memories included, with a record on the audit trail. The console's Test data card says so and still purges at once. - The routing SLM learns the plan, not only the answer. Besides which target answers, the model now keeps a separate learned ranking for each plan slot - persona, skill, tool - trained on the outcomes credited to that slot, saved with the primary model and promoted or rolled back with it. When the router fills a slot, the SLM votes with that role's ranking (a marketplace skill with a record is learned like a catalogue one) and stays silent for a role it has no ranking for. The platform feeds it: its own assessment of a composed answer is recorded for every companion with its role,
POST /api/v1/feedbacktakesrole(and accepts a skill or persona a plan discovered without an install), and each training cycle reports the slots it trained; tune it withOSR_SLM_SLOT_MIN_ROWSandOSR_SLM_SLOT_ROLES. - The IDE's
routetool routes against your marketplace pool. The MCProutetool used to see the deployment catalogue alone; it now sees your workspace's installs and, for a plan, the skills and personas the marketplace discovers for the request - the same pool asPOST /api/v1/route. - Every menu entry is a page. The site's header and footer no longer point into the middle of another page. Each reader has a page of their own -
/solutions/finance,/solutions/platform,/solutions/security,/solutions/developer- with the question they arrive with, the five things they can open today and what they leave with;/solutions/industriesholds the industryrules.yamlfiles with the catalogue they name;/billis Bring your bill with this deployment's own saving as the reference;/contactis the one home of Talk to sales with the other channels beside it (the pricing buttons, the plan picker and the support page send you there;/salesredirects). The footer gained a Solutions column, and Agent skills opens the marketplace's skills instead of a section of the docs index. - Content publishing for your website. Your workspace can follow its own RSS or Atom feeds, or send a brief (a topic, your notes, the page it is about), and get posts written through the router as your own metered requests - with the model, the cost and the companions on each post. Review them on the new Content dashboard page or publish automatically, then deliver them to your site: a signed webhook any site or CMS can receive, a WordPress site (application password) or a Ghost publication (Admin API key), with a delivery log that retries and a Send a test button; or pull them from
GET /api/v1/content/postsand your own RSS atGET /api/v1/content/feed.xml. An agent does the same through thecontent_*tools on your MCP server. See Content publishing for your website. - Your own commands, in the extension and the desktop app. Save a prompt once - Reply in my tone, Turn into a post, Explain for a newcomer - and run it with one click from the selection toolbar, the right-click menu, the writing widget's commands popover and the desktop command bar (a starter on the empty bar, a quick action under attached text). Write
{{selection}}where the text goes;{{page}},{{title}},{{url}},{{app}}and{{language}}are filled too ({{page}}and{{url}}in the browser only, so such a command stays off the desktop bar), and a prompt that names none of them gets the text quoted under it. Settings › Commands lists, edits and deletes them, says where each appears and seeds three examples; new commands reach open tabs at once. An organisation can pin the list (commandsin the extension's managed policy and the desktop'smanaged.json). - Answer in one language. Settings › Commands › Answer in asks every routed answer - sidebar, commands, desktop bar and main window - for the language you name (empty keeps the language of the question); an organisation can pin it as
answerLanguage. - Export a conversation as Markdown. The download icon in the sidebar's header and on a conversation in the desktop app's main window writes the conversation - who said what, the target and the price under each answer, the attached text quoted - to a
.mdfile. It is built where the conversation is shown; nothing is uploaded. - Desktop app: the chrome a native app owes its users. Right-click works everywhere: Undo / Redo / Cut / Copy / Paste / Paste and Match Style / Delete / Select All on a field (greyed by what the field allows), the system spell checker's suggestions and Add to dictionary over a misspelt word, Copy / Ask about "…" / Search the web for "…" on a selection in an answer, Open link in browser / Copy link address on a link. The composers are spell-checked by the checker the system already has (Windows and macOS; nothing is downloaded). The Dock menu on macOS and the taskbar's Jump List on Windows offer Ask from Anywhere, New Conversation and Settings… while the window is closed, and the main window reopens maximised when it was left maximised.
- The marketplace helps with requests nobody installed anything for. Every plan now offers the router the published skills and personas whose listing matches the request's domains and salient words, so a verified skill shapes an answer without anyone browsing the marketplace first. The router's quality floor still decides whether a discovered companion is used, it never answers on its own, and the decision names every marketplace part under
marketplacewithinstalled: true|false. By default only listings an operator marked verified are discovered, because a discovered skill's instructions reach a prompt its workspace did not choose; themarketplace_discoverypolicy key (verified,all,off) changes that per workspace andOSR_PLATFORM_MARKETPLACE_DISCOVERYsets the deployment default. Agents and tools still need an install. Requested by customers. - Resold models never sell below cost, and the console flags a price above list. A new pricing rule,
min_margin({"pct": 5}), floors every quote at the provider's rate plus that margin after all markups and promotions - a tariff typed under a contract rate or a 100 % giveaway can no longer produce a loss. Two deployment alerts watch the books: Margin names any model whose requests of the last day were charged below provider cost (critical) or under the gross margin set byOSR_PLATFORM_MARGIN_ALERT_PCT(warning, default 5 %), and Above list price counts, per provider, the enabled offers whose storefront rate per million tokens exceeds the vendor's own list price and names the worst one. Both appear on the console health page and in the alert stream next to the provider-balance alert, and refresh the moment a price or rule changes. - The Finance console answers "am I making money on every model" above the fold. A Margin watch card shows the money alerts (
GET /api/v1/admin/finance/alerts) or the one line saying every priced request of the last day covered its cost, no offer is above list and no prepaid balance is low. Adding a rule explains each kind next to its parameters, and ending a rule or price row, settling a provider invoice or switching a workspace's billing mode now asks for the reason in a proper dialog (labelled, focus-trapped, Escape cancels) instead of a browser prompt - the reason still lands in the audit log with before and after. - The status page is now a real one.
/statusused to show whether the API answered at that moment. It now shows every component the platform samples itself - the API's readiness, the database, the cache, the event bus, e-mail delivery, each domain service, the web app and every model provider - with ninety days of per-day uptime, the last check's latency, what was actually served each day (requests and platform failures), and incidents: operators open and update them from the console health page, and when a core component fails three checks in a row the monitor opens one on its own and resolves it when the component recovers. Everything is public JSON (GET /api/v1/status/board,GET /api/v1/status/incidents) and an RSS feed you can subscribe to (GET /api/v1/status/feed). - The status page says when its own checks have stopped. A corrupt database index silenced the sampler on the hosted platform for twenty hours while the banner still read "operational" over a page of unknowns. The board now carries the monitor's heartbeat - when it last sampled, whether that is stale and the last pass's error; once no check has been recorded for three intervals the banner says Checks are not running - state unknown and operators get a critical alert on the console health page and through their channels.
- List prices in the books follow the vendors. Every model-catalogue refresh now rewrites the catalogue-sourced rows of the price books (a changed rate closes the old row and opens a new one, freezing a new price version and an audit entry) - so a vendor raising or cutting a list price reaches the customer charge and the margin alerts on its own, instead of waiting for someone to press Seed from catalogue. Contract and manual rows are never touched.
- Stopping a replica drops no request. On its stop signal a platform process now answers
503 drainingon/readyzwhile it keeps accepting forOSR_PLATFORM_DRAIN_Sseconds (default 10), so the load balancer moves new traffic to the other replicas first; the requests in flight - a long streamed completion included - then getOSR_PLATFORM_GRACEFUL_SHUTDOWN_Sseconds (default 120) to finish. The Azure template keeps at least two API replicas in cluster mode (apiMinReplicas,OSR_PLATFORM_API_MIN_REPLICAS), probes readiness every five seconds and sets the termination grace period to cover both windows, so deploys, scale-ins and node moves are invisible to callers. - Security researchers and procurement teams find the disclosure contact.
/.well-known/security.txt(RFC 9116) answers with the security address, the policy page, the canonical address and an expiry.
Changed
- Desktop app: the update log is in the diagnostics. What the updater did - the feed it read, the version it found, the installer it started on Restart to update - now lands in
diagnostics.lognext to the app's other lines, so Copy diagnostics in Settings shows why an update did or did not apply. A Restart to update asked while nothing is downloaded is noted there too instead of doing nothing silently.
Fixed
- Nobody could buy credits - and, once tax was asked for, nobody could buy a plan. Every checkout that asks Stripe to compute tax was refused because the Stripe account has no head office address yet: credits answered a bare 500, plan upgrades a 502. A checkout is now created again without the tax fields when Stripe refuses tax, so the buyer pays the list price and can pay at all; the operator sees a critical Stripe Tax is not configured alert on Health and Finance until the address and registrations are set in Stripe, and a Stripe refusal for any other reason is a readable error with Stripe's words, not a 500.
- The overage line on Checkout is named. Stripe Checkout listed OpenSmartRoute Pro ... $490 / year and, right under it, OpenSmartRoute Pro ... $0.0001 per unit - the metered overage price shared the plan's product. Every metered line now has its own product (OpenSmartRoute Pro - extra requests, unit request; ... - metered usage), and an existing overage price is moved over on the next run.
- Your compliance score is about your workspace. The governance posture used to score a workspace on the platform's own settings - guards, the audit chain, tracing - so a minutes-old workspace could open at 43/100 with a broken deployment audit chain as its top finding and no SSO on a plan that does not include SSO. Every finding now says whose it is; the score counts only what the workspace can change (keys, budget, policy reach, tenant boundaries, SSO when the plan has it), and the platform's own findings are listed apart as what the platform reports about itself with their own score, on the Governance page and in the compliance report.
- A chat is never answered by a search result. When every model was down,
POST /v1/chat/completionswithautocould fall through to a built-in tool and return a web-search result list as the assistant message, with a 200. A tool still answers a chat when the router picks it for the request (arithmetic goes to the calculator), but a tool is never the fallback for a model, agent, skill or persona that failed, and when every model this workspace could run has its circuit breaker open the chat answers503naming them withRetry-After- so an OpenAI client retries or falls back instead of showing a search page to a person. - A plan gate now says what is missing and where to get it. Executing a request on the Free plan used to answer
plan 'free' does not include 'plan', which reads as a broken product. The answer now names the feature in plain words, keeps the feature id for scripts, and points at the cheapest plan on your billing ladder that includes it: the Free plan does not include executing requests and plans (persona -> skill -> model) ('plan'); Pro and up include it (/platform/dashboard/billing) - or talk to sales for a sales-led plan. - Links in the newsletter open again. Every link in an issue goes through the click counter, which answers a redirect; the website's API proxy dropped the redirect's destination on the way to the browser, so a click on a post, a source or Read on the blog landed on an empty page. The destination now travels with the answer (the same fix lets the LinkedIn sign-in for the console come back to the right page), and every issue gains View this issue in your browser: a public page (
/newsletter/issues/{issue},GET /api/v1/newsletter/issues/{issue}) with the same posts the mail carried, keyed by the issue and not by the reader, so it is never tracked and holds nothing about anyone. - A broken audit chain is alerted and can be closed out on the record. Chains forked before the file-lock fix (and any chain with a removed or edited line) now raise a critical deployment alert on the console and workspace Health pages, and the compliance finding explains what it means instead of printing the raw file position. A superadmin resolves it from the console's Health page - Archive and start a new chain, with a mandatory reason (
POST /api/v1/admin/audit/rotate): the broken file is kept beside the new one as<file>.<stamp>.archivedand never edited, and the new chain opens with a record naming the archive, the problem, the reason and the operator; the action is also in the operator audit log.GET /api/v1/admin/healthcarries the chain status. A self-hosted router's file audit sink rotates the same way withFileAuditSink.rotate(). - Circuit-breaker tiles show the observed success rate. The meter used to show the Wilson lower bound, so a target with three successful calls read "≥ 44%" next to a green healthy badge. The meter now shows the observed rate with the failed count, and the lower bound - what the breaker acts on - is the confidence line underneath, marked few calls yet under twenty calls.
- Dashboard tables fit a phone. Activity and Events no longer force a desktop-wide table that has to be scrolled sideways; the columns a phone can do without (level, duration, request id; tokens and last-used per key; variance, loss, encoder, reasons) fold away on narrow screens, and the Events time column shows the clock only. Page descriptions whose first sentence overran the fold (Memory, Spend, Impact, Content, Health, Learning) are split so the folded header ends on a full stop. Support filter chips are capitalised like Feedback's, and both pages show the shared API error alert with Retry instead of a bare message.
- The audit chain no longer forks when a second writer appends to the same file. The file audit sink kept the hash of its last line in memory, so a second replica on the same volume, a reloaded worker finishing a request or a second sink in one process each hung their record off a hash the file had already moved past - and the governance page and compliance report then reported a broken chain ("prev mismatch") that nobody had tampered with. Every append now takes an exclusive file lock and, when the file grew since the sink's last write, continues from the line on disk; resuming reads only the file's tail instead of the whole chain.
- Dashboard details on a phone. Collapsible section titles ("When traffic happens") wrap instead of being cut off; the service-level "met" / "no tickets yet" badge drops under its sentence instead of squeezing it to one letter per line; plan entitlements keep the check mark on the same line as the feature. Governance counts "metered requests" like the Usage page (a decision is metered, an execution is not the same thing), compliance findings and the report read "1 key" / "2 keys" instead of "key(s)", and the optional two-factor sign-in for operators is reported by the operator's preflight, not as a finding on a customer's compliance posture the customer cannot act on.
- Every irreversible action on the dashboard asks in the platform's own dialog. Removing a member, cancelling the plan, erasing stored prompts, deleting a notification channel, a post, a feed or a destination, archiving a listing and removing password sign-in used the browser's bare confirm box; each now opens a dialog naming what goes away and what stays, with the destructive button marked as such. Handing a workspace to another member no longer asks you to type "admin, member or leave"; the dialog offers the three roles with what each means. The operator console follows: deleting a user, workspace, tenant, provider, offer, operator, post, feed, subscriber or draft, resetting someone's two-factor sign-in, returning a plan or setting to the deployment's value, purging test data or old rows, sending a newsletter and the bulk user actions ask in the same dialog.
- A slot model ranks the companions that were actually graded. The first skill-slot fit on the hosted service ranked the catalogue's three skills and never the writers' own
seo-writerandeditorial-writer, because the model knew those ids only from an older corpus. The graded outcomes now decide what competes for a slot, and the reported fit is honest when the constant predictor is already perfect - 1 when the model matches it, 0 when it does not, never 1 for a model that is wrong on every row. Replayed on the production log, the skill slot now puts a search-optimised guide onseo-writerat 0.92. - A discovered persona no longer loses the slot to a 500 ms default. A manifest that declares no latency turned into a target at 500 ms whatever its kind, so a marketplace persona with the better quality prior (0.70) lost the persona slot to a catalogue persona (0.65) on latency it never had. An instructions-only persona or skill with no endpoints now defaults to 0 ms like the catalogue's own; a declared value and every endpoint-backed kind keep theirs.
- Prompts are discovered too. The seeded meeting-to-decisions, bug-report-triage and their kind never reached a plan: discovery searched skills and personas only, and every seeded prompt takes its input through a
{{variable}}. A published prompt with at most one variable is now offered as an instructions-only skill (prompt:<slug>, the placeholder standing for the user's message, latency 0, prior 0.55); one with several stays a template.POST /api/v1/feedbackaccepts such an id for the companion the request discovered. - Figures the pages held but never drew. The Finance console charts revenue against provider cost per day with the gross margin as a line and ranks the selected breakdown (provider, model, workspace or plan) above its table; the operator's workspace detail shows the customer's 30-day traffic and where it went, the same chart the customer sees; the Growth console draws the signup funnel (signed up, verified, routed, paying), signups per channel and activation / retention per signup week; Tenants shows each tenant's share of this month's requests and spend; API keys shows which key carries the traffic before one is rotated or revoked; Governance ranks the guard verdicts of the last day; Services ranks probe latency across the fleet.
- The operator reads why a request routed where it did. The console's request log held the outcome of every request but not the decision behind it - the operator had to open the customer's workspace to see a trace. Each row now has Trace: the same decision story, spans, usage and outcomes the workspace sees, read-only (an operator's opinion never trains a customer's learners), naming the workspace it belongs to and recorded in the operator audit log with that workspace. A link that names a request (
?request_id=) opens the trace at once; clicking a target narrows the log to it (the API'stargetfilter, until now unreachable from the page). A user's history and the audit log print nested details (the legal versions accepted at signup) as JSON instead of[object Object], and the user page's header actions wrap on a phone instead of running off the screen. - The home page hero renders cleanly. The routing illustration clipped the glow of the chosen card and the bottom counter and showed its own rectangle against the hero wash; it now spills its shadows like the rest of the page. The live extension card printed the server's date and re-rendered on arrival when the reader's day differed; it renders the reader's date only in the browser. Hairline-divided strips (the four promises, the MCP tools, the marketplace kinds) fade in as one instead of showing their divider colour as a grey slab while the tiles were still hidden below the fold.
- API error messages read as sentences on every page. The API's reasons are written as lower-case log lines ("this link is invalid or has expired; request a new one"); shown to a person they now start with a capital and end with a full stop, and the expired-confirmation page says how to get a new link instead of quoting the log.
- A marketplace listing published by someone else opens read-only. Opening another publisher's listing from the dashboard showed a full editor whose every save would have been refused; it now says who publishes it and links to the marketplace page.
- Marketplace tag chips count the kind you are browsing. On the skills page a chip could claim more listings than the page had, because it counted every kind; each per-kind page now counts its own.
- Imported listings never break a sentence mid-word. A harvested description cut at a fixed length left summaries such as "and application state into"; the summary now ends on a sentence or a whole word.
- Browser sessions say "Chrome on Windows". The operator console showed the raw user-agent string, cut off at the column edge; every session table now names the browser and system, with the raw string as a tooltip.
- Small things on the public pages. The estimate tool's Get quote button sits under the request; the downloads page has a jump row per audience; the model page explains its price and success figures instead of restating them; the comparison table fits its last column; the SDK install commands wrap instead of being cut; the bill page shows real cents; a vendor's lowest price says what it is per; the dashboard keeps its last row clear of the Help button.
- The Feedback page and API answer again on split deployments.
/api/v1/product-feedback(bugs, ideas and improvements a workspace sends and follows) was served by the accounts service but not forwarded by the API gateway, so the dashboard page said "Not Found". It is forwarded now, and the check that every service route is reachable through the gateway works again. - Operator newsletter campaigns reach the readers who signed up on the site. A campaign went to the hand-added list only; the confirmed readers from the blog's subscribe form were never mailed. Both lists receive it now, one copy per address, and the Newsletter console shows how many of each.
- The public success rate and request counters leave the platform's own jobs out. Requests the platform's own editorial and growth writers made before they were labelled as the platform's counted as customer failures; the public rankings and status figures now leave them out.
- The status page no longer reports the website down on a compose stack. The monitor probed the public web address from inside the API container, where it points at the API itself;
OSR_PLATFORM_WEB_PROBE_URLnames the address to probe from the API's network and the compose files set it. - A plan is named the way it is sold everywhere. Pay as you go read "Payg" on the dashboard home, the plan card, the gated-feature notices, the operator console, coupons and the sales form; a prepaid plan is priced "by the token", not "free" with a "hard cap".
- A page a plan does not include explains itself. Health, Audit trail and Tenants on a plan without the feature showed a bare warning; they now say what the page would show, which plan includes it and take an owner to the plans, or tell a member who can change it.
- Numbers and labels that misled. The Events page showed the deployment-wide count of stored spans as if it were the workspace's; a fresh workspace saw "378k persisted". The reports console said "last pass: never" above fifty sent digests when the scheduler ran in another process. The admin content and SLM cards mixed two figures in one value. A model id as a Writer figure is set in smaller type. Field hints too long for the label row are helper text under the control instead of being cut off. Plain copy replaces environment-variable names on the Learning page a workspace user sees.
- Placement and empty states in the operator console. Coupons open their form from the page header; offers, leads and notifications get an empty state with one clear next step; a paused writer is named on the automation board; the rankings tables stack until the window is wide enough.
- A writing model that is down no longer floods the deployment's error rate. When the platform's own writers (guides, ad copy, news drafts) could not reach their model, one cycle metered a failed request per keyword and campaign - about a hundred failures a minute on the deployment overview. A writer now pauses for fifteen minutes after three consecutive failures and the pass ends there; the keywords it did not reach keep their turn for the next cycle instead of being marked as tried for the week.
- One primary action per screen. The Providers, API keys and Governance pages showed the same primary button twice - in the page header and again inside the empty state; the empty state's copy is now secondary. The playground's Route button sits directly under the request, above the fold, with the options after it.
- Small usability fixes across the dashboard and console. The billing card with no subscription offers See plans; the Savings empty state opens the playground; the Activity page's tracing badge says whether traces are on rather than how many events sit in a buffer; a long page description folds on a whole sentence and never drops a clause (
.envwas read as the end of a sentence); the operator overview turns the seven-day error count red above five percent and links it to the failed requests; the Support console tells the operator when nobody is e-mailed about new tickets, with a link to Settings, instead of hiding it under the Oldest open figure; the sign-in page no longer promises single sign-on on a deployment without it; the signup form's small print is separated from the sentence you agree to; percentages read5%throughout. - The local development stack installs every dependency the platform declares. The compose stack's API image kept a hand-written package list that had fallen behind the platform's own manifest, so a PDF invoice import failed there while it worked on a deployment. The image now installs from the manifest, like the production image does.
- The Activity page works on a deployment upgraded from an earlier version. A column added to the schema after a database had recorded its first migration never reached that database, so on every existing deployment
GET /api/v1/activity- the Activity page - failed with a database error. The additive columns are now brought up to date on every start; versioned migrations keep their ledger. - A provider failure no longer strips the plan from the answer. When the model chosen for an executed request failed and the router fell back to another, the fallback ran without the plan: the plan mode came back empty and the skills and personas the workspace had installed were left out of the answer. The fallback is now re-planned around the next model - the same mode, the same companions, only the failed model swapped - and the failure is charged to the model that failed, not to the skill whose instructions it was running.
- Money on the dashboards prints its real value. A cost below a hundredth of a cent used to read
$0.0000; it now shows its significant digits ($0.000013), chart axes make room for the widest tick instead of clipping the leading$, and no tick prints in scientific notation. - The site and the dashboards fit a phone and a tablet. The home page's routing illustration scales down as one piece instead of stacking its cards on top of each other; the most-routed list, the recommended-model tiles and the industry rules no longer spill past the screen edge; key-figure rows go two abreast on a phone rather than a long single column, and never five abreast on a tablet; the dashboard header keeps the page title readable by moving the secondary tools into the sidebar below tablet width; long e-mails, ids and variable names wrap inside their card; form labels, card titles and search boxes yield to the space they have instead of pushing past it.
- Charts and tiles no longer paint over each other. Ranked bars and meters on Usage, Health and Learning kept a hint on top of the target id or dropped it on narrow cards; histogram labels overlapped; circuit-breaker tiles wrapped their latency figures across three lines; the system-status facts spilled out of their card. Each now lays out cleanly at desktop and phone widths.
- Tables keep their identifiers and their last columns. Target ids, latencies and channel names no longer break mid-word, wide tables show a visible sideways scrollbar, and the console's Users and Workspaces lists keep the status and action columns on a laptop screen instead of pushing them off the card.
- Small dashboard corrections. The footer's "Back to top" no longer hides under the floating Help button; the account avatar in the sidebar is drawn at its intended size; the Integrations card's icon no longer drops under the title; the Quick-start snippet shows an API key prefix rather than the browser session; counts are pluralised ("1 outcome", "1 executed request"); the Account page's sign-in card no longer tells a password-only deployment to connect a provider; a support level with no answered tickets reads "waiting for a first answer" instead of "missed"; the Providers table says "only your endpoint" where it said "not executable on the platform"; configuration switches carry their human label; the Apps page's command-line card spans the full width.
- A planned request's outcome now trains the routing SLM. The router remembered one pending decision per request, so on any request routed with a plan the last slot scored overwrote the primary's and the primary's outcome was lost - the served model never learned online from planned traffic. Decisions are now kept per request and slot, and slot outcomes no longer leak into the primary training corpus, where a persona graded well used to be learned as an answer.
- A tenant-pinned API key is now the isolation boundary it was documented to be. A key minted for one tenant could read the whole workspace's activity, traces, events, usage, savings, audit, members and providers, grade other tenants' requests, and - through
POST /api/v1/keys,PUT /api/v1/policyandPUT /api/v1/tenants- mint an unpinned key, rewrite the policy or edit the other tenants. Such a key now routes, executes and reports outcomes as its tenant, reads only its tenant's rows (another tenant's request id is404,?tenant=<other>is403) and is refused every workspace-management call with403andX-Key-Tenant. The MCPfeedbacktool also checks the request belongs to the caller and records the outcome likePOST /api/v1/feedbackdoes. - Naming a model nobody serves is a
501with the fix in it.model: "llm-mid"(or a candidate list) whose targets no platform or workspace provider executes answered502 target llm-mid has no handler, as if an upstream had failed; it now says the target is not executable on this deployment and where to map it. - A pinned model whose breaker is open answers
503withRetry-After, not422. Once a provider had failed enough times for its circuit to open, a request pinned to that model (or a candidate list made only of tripped targets) came back as422 no admissible target- a client error for what is an outage of the target. It now says which candidates are unavailable and why (llm-mid (circuit open)) and when the breaker probes again. - A provider failure that re-routed a request is its own event. Whenever a target's handler failed and the request went to the next executable one, the events explorer's "fallbacks" and the trace's decision story now show it - the target it left, the one it went to, the error and the attempt - apart from the low-confidence fallback that routing itself chooses.
osr stack apply registry://<slug>works without--registry. The reference now resolves against the configured marketplace (OSR_MARKETPLACE_URL, default the hosted platform), as the marketplace page says;--registrystill points one command at another deployment.- The
osrcommands report a configuration mistake as one line. Inosr audit,osr eval,osr ope,osr safetyandosr export-ocm, an unknown--baselineid (or an unreadable dataset) printed a Python traceback; it is nowerror: baseline target 'x' is not in the cataloguewith exit status 1, like every other command. - An installed listing is in the routing pool at once, on every replica. Until now each API replica kept a workspace's installed targets for 30 seconds and only the replica that served the install forgot them, so right after Install the targets list and the plan could keep showing nothing. Every replica now checks the workspace's install stamp before trusting what it cached.
- Small screens and small things on the web app. The activity table shows the clock instead of the full date on a phone and hides the endpoint badge there, so the routed target is readable in one glance; a marketplace readme's headings no longer compete with the page title (one top-level heading per page); tab strips wider than a phone start at their first tab instead of hiding it; dashboard tabs keep their own title (
Governance · Dashboard · OpenSmartRoute) instead of falling back to "Dashboard"; and an error the dashboard can explain (confirm your e-mail, not in your plan, key scope) now leads with the explanation and keeps the API's own sentence as small print. The marketplace pages, the playground and the Installed tab say in plain words what installing and verifying mean for routing.
1.8.0 - 2026-09-21
Added
- The bill analysis reads the invoice itself. Drop the PDF invoice from OpenAI, Anthropic, OpenRouter, Mistral, Azure, Google Cloud or AWS - or paste its text - and the platform reads the issuer, the billing period and every line naming a model with an amount (
GPT-4o input tokens 12,345,678 $2.50 / 1M $30.86), then prices it like any export: what the invoice bills against what the router's target would have charged for the same tokens, quantities read as tokens where stated and backed out at list price otherwise. Totals, tax, credits and payments are not usage; the notes say when the model lines do not add up to the total, which currency the invoice bills in, and that every line is dated at the start of the period. The page is a drop zone that names the file it holds, the guidance says where each provider keeps its invoice and export, and an OpenAI invoice joins the samples. - Self-hosted upgrades, downgrades and backups are now something the platform does. Every start-up applies the schema changes the database has not seen yet and records each with the release that wrote it;
python -m osr_platform.maintenance schemashows applied and pending. Before the first change runs on a database that already holds data, the API backs up every table on its own (OSR_PLATFORM_PRE_UPGRADE_BACKUP,OSR_PLATFORM_BACKUPS_KEEP);maintenance backup <file>andrestore <file> --yesdo the same by hand withoutpg_dump. A downgrade starts with a warning when every newer change was additive and is refused, naming the release to run or the backup to restore, when one was not. SwitchingOSR_PLATFORM_EDITIONis a restart; the first start after a switch explains it in the log and on the console's Health page. The install guide's Operate section spells out each step. - The router understands everyday asks. Fix the spelling, proofread, shorten, reply to this e-mail, read this aloud, voice memo, embeddings and bullet points now reach the right kind of target instead of a frontier model or a document reader, and five bullet points for my manager is no longer read as asking for a human - only asking to speak to one is. The bundled routing model is retrained on these requests.
- Operators see and control every message the platform sends. The console's Mail page shows every kind of message - welcome, confirmations, sign-in notices, reports, alerts, release notes, support mail - as a customer sees it, with the plain-text version and a Send me this sample button. Each lifecycle campaign (trial ending, upgrade offer, release notes, the apps note) has an on/off switch on the Growth page; switched off, it sends nothing and never piles up.
- Sign-in notices keep the account's owner informed. A sign-in from a browser and system the account has not used in 90 days sends New sign-in to your account - when, how, the device and the address - with Review sessions and the reset link. Eight wrong passwords in a minute send Failed sign-in attempts once a day (nobody got in). Adding or removing a sign-in method sends a note too. These are security mail and always sent; the Account page now shows each session's address.
- The apps say hello, and the platform reminds you they exist. The person who connects the browser extension or the desktop app receives one note on what it does - and that the workspace records counts, never text. A workspace that has routed for three days without either app hears once what the two do for the team and where to get them (Getting started mail, switchable).
- Bring the bill you already pay and see what routing would have saved. Under AI spend › Your provider bill, upload the usage or cost export your provider already gives you - OpenAI, Anthropic, Azure OpenAI, Google Cloud, AWS Bedrock, OpenRouter, Mistral, Cohere, xAI, DeepSeek, Groq, Together, LiteLLM, Langfuse, LangSmith, Helicone, or any CSV, JSON or Excel file with a date, a model and token or amount columns. Every line is priced twice - what you paid and what the router's pick would have cost - and the result reads as a plain story with charts and the line-by-line detail; download it as CSV, Excel or PDF, or Try a sample export first. Only dates, model names and numbers are read; nothing else in the file is stored. Scripts get the same figures from
POST /api/v1/usage/importsandGET /api/v1/usage/report. See Bill analysis in the platform guide. - Install the desktop app and the browser extension for a whole organisation. The Windows installer now offers Anyone who uses this computer (silently:
/S /ALLUSERS) and takes amanaged.jsonbeside it as the pinned settings for every account; macOS gains a.pkgfor any MDM, with a privacy profile that grants Accessibility and Automation so nobody clicks through the prompts. The extension page ships a policy kit that writes the Windows registry file, the macOS profile, Firefox'spolicies.json, the Linux files and the value for Google Admin and Intune from your settings, and the all-users desktop installer registers the extension for every account with/EXTENSIONS=all. Documented under Installing for an organisation in both guides. - Six new pages answer the questions buyers bring. Solutions (who it is for, in their words, with the proof behind each promise), Security, Observability, SDKs and API, the MCP server (this deployment's live description and a ready configuration for VS Code, Cursor, Claude Code, Windsurf and Claude Desktop) and Enterprise (editions, rollout to every desk, the plan's measured availability and the sales form). The header's new Solutions and Developers menus, the footer and the sitemap lead to them; /contact and /sales open the sales form.
Changed
- The landing page tells one story, for the budget owner and the engineer alike. It now opens on what a person gets - Spend less on every AI request. Safe before it leaves, explained after - and follows one request through three acts: checked and corrected on the device, routed to the cheapest target that clears the bar without breaking a rule, explained and priced afterwards, each with a one-line reading for engineers and a link to the surface that proves it. New sections explain the bill import in three steps, pair observability with organisation and policy control, show the seven marketplace kinds with live counts and put the newest AI news on the page.
- The command bar explains itself. The field has a Send button (Stop while an answer streams), the preference row is labelled Prefer with Best quality spelt out, and five starters each do a whole task - Fix, Summarise or Explain what I copied attach your last copy and send it, Write an email and Translate something put an opening in the field. A signed-out bar says up front that answers need a sign-in (the personal-detail checks do not); a signed-in one names the workspace.
- The writing assistant reaches more Mac apps, and never flattens a document. Mail, the rich editors of Chrome, Edge, Teams, Slack, VS Code and other Chromium or Electron apps, and Office's document are now visible to it; where an app lets a slip be selected but not written, the fix is pasted over the selection. A document, note or mail is never rewritten whole any more: a fix that cannot go in place is reported as failed rather than replace a formatted document with plain text. Plain fields (chat composers, forms, subject lines, Notepad) work as before.
- The desktop app talks to OpenSmartRoute unless a Pro workspace says otherwise. Pointing it at an on-premises router -
osr serveon this machine, a self-hosted platform, a proxy in your network - now needs a workspace on Pro or higher: signing in with one grants the licence on that computer, and only then do the router address, Local osr serve and the API style in Settings › Workspace accept a change. A router set up earlier keeps its settings but gets no answers until the licence arrives or Use OpenSmartRoute is pressed; an address pinned by your organisation's managed file is exempt. - A warmer look and quieter motion everywhere. Light pages sit on cream with charcoal text and the dark theme is a warm charcoal with ivory text - on the site, the dashboard, the console, the documentation, the extension, the desktop window and in e-mail. One warm accent takes the rare accent button, the focus ring and the current page in the sidebars; every colour pairing meets the accessibility contrast floor. Icons answer a hover the way they point, and reduce motion in your system settings switches all of it off.
- Blog posts open with the key points. Every post carries three or four key points - concrete facts from the source - above the article and on each newsletter card, next to Why it matters and, where the source allows, What to do.
- The newsroom follows twice as many sources. The curated feed list grows from 23 to about 50 verified sources across model vendors, research labs, practitioners and the press; Add the curated feeds on the console's Feeds tab adds the ones a deployment is missing.
- Release notes and e-mails you can read at a glance. The what's-new mail opens with Nothing to do on your side and an In short list, then groups every change under New, Changed, Fixed, Security and On the way out with a one-line meaning for each; the dashboard's What's new card uses the same labels. Every message the platform sends carries a coloured band naming its kind - Security, Alert, Account, Getting started, Release notes, Newsletter, Support - and each switch under Account › E-mail lists the messages it controls.
- The changelog says what changed for you, not how we built it. These notes are written for the people who use the product - what changed, what it means, what to do - and the engineering detail stays behind each release's diff link. A change that answers a customer's request ends with Requested by customers: the What's new card and the release mail badge it, and it heads that section's highlights.
- The header names each page once, and section links land where you can read them. Product holds what you get - the apps, playground, marketplace, security, observability, services - beside models and prices, and Bring your bill leads to the explanation instead of a sign-in wall; Solutions lists the four people it is for (budget owners, platform teams, security teams, developers), industries and enterprise, with the ways to prove it; Developers pairs the guides with the ways to ship. No page appears twice, no menu repeats its own name, the footer no longer shows two different "Security" links, and an anchored section such as Security teams or Talk to sales opens below the sticky header instead of hidden under it.
- No link on the public site ends at a bare sign-in form. The Solutions, Security, Enterprise and Observability pages, the landing page and the extension page "prove" a promise by linking to the workspace page that keeps it - which, for a visitor without an account, was a login screen. Signed out, a proof now opens the public page that explains the same thing (the guide's governance or tenants section, the security model, the traffic comparison), and an action such as Analyse a bill or Open the governance report creates a free account first and lands on that page; signed in, every link opens the workspace page as before.
- Every catalogue page says what it is for in plain words. Models, providers, vendors, rankings and listings now read available here instead of "routable" and personal data instead of "PII", carry an honest note when no provider is connected yet, and the two "Meta" vendor cards are told apart.
- The ROI calculator prices the fee from the plans on sale. It offered a "savings share" nobody can buy; it now takes the plan fee from this deployment's catalogue (or a custom amount), names its inputs in plain words and points at the bill analysis as the quickest source of the two figures that decide the outcome.
- The extension, desktop, sign-up and footer copy carry the site's own promise. Spend less, safe before it leaves, explained after - in place of router vocabulary; the comparison tables name the bill analysis and the two apps.
- Marketplace listings show installs and reviews only once they mean something. Until there are enough to mean something, the counts stay off the card.
- The support page gains an On this page list. Each section of the support page is one click away from the top.
- The terms of service and the privacy notice describe the platform as it is. Both are rewritten against the product: how a plan change (immediate, prorated) and a cancellation (end of period) are billed, pay-as-you-go credits that do not expire, the four places request text is kept - conversations with memory on, remembered facts, human hand-offs, an opted-in request log - and how to delete each, your own model providers, what the browser extension and desktop app send (counts, never text), the enterprise availability target measured at
GET /api/v1/sla, the self-serve Delete my account and the Your data export, and retention by plan. Each page opens with an On this page list and the data tables read as cards on a phone; the new versions take effect after the notice period the terms promise. The pricing FAQ now answers how plan changes and refunds work. - Generalist models are never "off-domain", and a tool gets slack past its band. A target that serves the
generaldomain used to be penalised on any specialised text, so a translation of a medical letter could go to the human queue instead of the translator; it now gets the mild generalist fit. A tool's out-of-scope penalty starts a little beyond its complexity band (OSR_CAPABILITY_TOOL_BAND_TOLERANCE, 0.1) instead of the moment the estimate crosses it. Expect a generalist mid tier to sit closer to the frontier model on specialised text than before.
Fixed
- The documentation index and the API reference read well on every screen. The index uses the whole reading column instead of leaving a gutter for a table of contents it does not have, opens with a plain-language lead and four pick your path cards, and lists every section of the catalogue with a description and its pages. In the REST API reference, endpoint paths wrap at their slashes instead of mid-word. Nothing scrolls sideways on a phone.
- Every page of the public site was checked for truth, type and layout. Titles and descriptions say what a person gets rather than how the router works, and claims that had drifted from the product were corrected: the services page no longer says every service is free (tenants, audit and SSO are plan-gated), the extension page follows the plan's retention rather than a fixed 90 days, the desktop copy no longer promises Safari before its App Store listing, the marketplace says free listings publish straight away, the rankings page no longer draws its charts twice and a made-up "70% of spend" figure is gone. Every page opens at the same title size, no text is smaller than the readable floor, footnotes sit inside a reading measure, the pay-as-you-go button reads Buy credits, and Talk to sales lands on the enterprise form with the plan preselected.
- The changelog page shows its characters correctly. A few garbled characters on the changelog page are fixed.
- A long account name no longer breaks the header. Signed in, the header shows the avatar alone - the name appears on hover and at the top of the menu - and the menu fits any screen. On a phone the navigation sheet opens with the account's name and address under the logo.
- An organization's own sign-in connection no longer leaves the address unconfirmed. Members arriving through an organization's Microsoft, GitHub or GitLab connection were shown email unverified and sent a confirmation link, or blocked by the confirmation gate, because the trust in those providers did not follow the organization's connection. It does now; a generic OpenID Connect issuer that says nothing about the address still leaves it unconfirmed.
- Everyone is welcomed on their first sign-in, whatever the way in. The welcome message went out after the signup form only; a person whose first contact was a provider button, an operator-created user or a password-reset link never received it. The first sign-in now sends it once - and the confirmation link as well when nobody vouched for the address.
- The browser extension's toolbar icon shows and hides the sidebar on Chrome and Edge. Clicking the icon opened a small popup and, for a new user, nothing opened the sidebar at all. The icon now toggles the sidebar the way the browser's own side panels do; the overview (account, this page's switch, today's figures, updates) opens from the account chip in the sidebar's header. Firefox and Safari keep the overview on the icon.
- A model that went away mid-answer no longer passes as an empty or half answer. A provider stream that closed before it finished used to be returned as a clean answer and metered as a success. It is now an interruption: before the first token the request is re-routed like any failure; after it, the client is told in the stream.
- A slow answer is no longer reported as "OpenSmartRoute took too long". The desktop command bar and the browser extension cut answers off after 15-20 seconds while the platform allows a model up to five minutes to start answering, so a slow model was blamed on us. Both now wait out the platform's own budget on the one call that legitimately waits and keep failing fast everywhere else; Stop is still one key away.
- The Windows uninstaller no longer leaves the program behind after an in-app update. It now waits for the app's background processes to release the executable before deleting, so nothing is left in the program folder.
- The quota bar on Plan and billing speaks to screen readers again. It is announced as "4,210 of 5,000 requests this month".
- Spreading traffic across identical deployments no longer favours a lone deployment. A target with no sibling could outrank the deployment the spread had just drawn, on nothing; every candidate is now weighed alike and only the draw moves the ranking.
1.7.0 - 2026-09-19
Added
- The router can keep a knowledge graph of what worked for whom. The SDK records typed, sourced, weighted and expiring facts about the people who ask, the targets that answer, the topics that come up and the pages consulted; a fact stated twice grows in weight, facts nobody confirms decay, the graph stays bounded, persists to JSONL and forgets on request. It reads and writes JSON-LD 1.1, RDF N-Triples, GraphML and Neo4j Cypher, and becomes a NetworkX graph when networkx is installed, without depending on any of them. Facts are learned by rules, not a model: from a person's own words, the catalogue, each routing decision and outcome, and the hits of a live web search. Switch it on with
RouterBuilder.with_knowledge(). - The model is told what it needs to know, within a token budget. Before each routed request the router chooses, ranks and trims what the model should know - about the user, relevant knowledge, live web context - into a budget of 600 tokens by default (the
OSR_KNOWLEDGE_*settings), and the trace accounts for every line placed or dropped. Aknowledgestrategy (weightOSR_WEIGHTS_KNOWLEDGE, 0.6) prefers targets that worked on the request's task type and domains, and abstains until it has enough outcomes. - The graph can predict links nobody declared (TensorFlow). With the
tensorflowextra the SDK trains an embedding of every entity and predicate in the graph and then answers with numpy alone: which domain a target is probably good at though nobody said so, which entities are similar, how plausible a fact is, with hits@10 and MRR to measure it. Personal facts are left out of training. The model saves to a small file or a database row, and attached to the graph it backs the graph's suggestions, which otherwise count what peers of the same type carry. - One knowledge graph per workspace on the platform. The platform runs the graph around every routed chat: facts are learned from the message and the relevant knowledge placed before routing (personal facts only when conversation memory is off, which already carries them), and the request's topics, the target that answered and any web citations are recorded after; the answer carries the accounting. A person's facts are never shown to another person in the same organization.
/api/v1/knowledgemanages settings and facts, forgets, previews the context, suggests, exports as JSON-LD, N-Triples, GraphML or Cypher and trains the link predictor; it is the twelfth domain service (OSR_PLATFORM_KNOWLEDGE_URL, port 8102). EveryOSR_PLATFORM_KNOWLEDGE_MAINTAIN_S(3600 s) stale facts decay, expired citations go and each workspace's link predictor is refitted where TensorFlow is on the image. - Long pages fold. Secondary sections - the usage heatmap, the health page's HTTP routes and raw snapshot, the stdio bridge and tool list under Integrations, the account signals under Savings, and in the console the finance price versions, provider invoices and reconciliation, the growth engine's Search Console queries, engine runs and IndexNow submissions - are folded cards that keep their title, a one-line summary (a count, the version in force) and their action in view, and remember your choice per card in the browser. The finance create forms (a rule, a price row, a provider account, an invoice) sit behind Add ... rows instead of standing open under every table.
- Every signed-in page ends the same way. The operator console gets the footer the dashboard already had - edition, version and operator, the operator guide, self-hosting, API reference, changelog, status and security - and both footers carry Back to top; the floating one appears after half a screen of scrolling instead of a whole one.
- Every request from every client is one traceable row. The TypeScript SDK sends a client request id (
X-Request-Id) and a W3Ctraceparenton every call by default (trace: falseturns it off; your ownrequestIdortraceparentis continued), and every result and stream exposestraceId. The platform joins the request's spans to your trace and uses a well-formed client id as the decision'srequest_id- the one/feedbackand/trace/{id}take; malformed values are ignored. The browser extension and the desktop app send the same headers on their own calls (the desktop also sends the workspace tenant), and their answered by line links to the request's trace on the dashboard - decision, spans, outcome - so you can go from an answer to why it was routed that way in one click. - The blog asks readers in. A visitor who is not signed in and reads on - a few seconds on
/blogor a post, or a third of the page - sees a sheet at the foot of the page: Keep reading with a free account, with one-click sign-in through Google, Microsoft, GitHub or your company's identity provider, an e-mail field pre-filled on the signup form, and the sign-in link, each returning you to the page. Where new accounts join the daily newsletter by default (OSR_PLATFORM_NEWSLETTER_SIGNUP_DEFAULT) the sheet says so, and a reader who signs in through a provider is a confirmed reader at once. The text is never held back: Not now keeps the sheet away for a week, a subscription or a signed-in browser hides it for good, and it waits for the cookie banner. After sign-in the welcome page offers Back to the post or Continue where you left off. The extension's prompt stays off the blog. - The dashboard opens on your own question, and the first screen is calmer. A new workspace lands on the getting-started checklist next to the quick start (no marketing banner inside the product), an active one on its figures; chart cards that would be empty are one honest "nothing routed yet" card with the playground action until the first request. What's new is one row - version, first highlight, the notes link, Got it - with the highlights behind a toggle instead of a full-width panel above the numbers. A search button in the header (Ctrl K) jumps to any dashboard page by name or by what people call it ("token", "upgrade", "invite"), then to models and documentation. Long page introductions fold behind More about this page.
- Dashboard cards and tables fit a phone. Stat cards sit two to a row on a phone with smaller type and no decorative icon, and the quota bar inside the card no longer repeats the figure the card already shows. The activity table keeps time, endpoint, target, latency, outcome and status at every width and moves requested model, domain, complexity, tokens and cost into the expanded row on narrower screens. The header's monthly-quota figure links to plan and billing.
- The playground asks only for the request, and a 403 says why. The playground asks for the request and Route; cost and latency weights, candidates, tenant and constraints sit behind Objective and constraints, whose closed row states the current values. A 403 because your e-mail address is not confirmed now says "Confirm your e-mail address first", with the link to send it again, instead of "Permission needed" - the browser can now tell the three kinds of 403 apart. The support page's empty state no longer duplicates the primary button.
- Ownership of an organization is transferred in one step.
POST /api/v1/workspace/transferwith the new owner'suser_idandkeep_role(adminby default,member,ownerto share, orleaveto hand over and go) - owner only, audited and in the e-mail digests, both people e-mailed. The crown button on Members does the same; before, an owner had to promote the other person and then demote themself. - Fair share across workspaces and tenants on enterprise deployments. With
OSR_PLATFORM_FAIR_SHARE=truea workspace or tenant taking more thanOSR_PLATFORM_FAIR_SHARE_SOFT(1.5) times its share over the fair-share window (300 s) is steered to cheaper targets, and above the hard multiple (3) premium targets are capped for it; the trace records each throttle and cap.GET /api/v1/governancereports the window, the counters and your own shares only, andcontrols.fair_sharesays whether it is on. Previously the documentation mentioned fair share but nothing enforced it. - The operator tenant index acts.
/platform/admin/tenantsedits a tenant's configuration in place (JSON, validated like a workspace policy) and deletes tenants, through the existingPUT|DELETE /api/v1/admin/accounts/{id}/tenants/{slug}; it used to send operators to the workspace page. - The routing model reads the conversation. A follow-up ("why?", "shorter please", "and what about the edge cases?") is routed together with the last user turns of the request's history; a request that stands on its own words ("translate this into French" after a coding chat) still routes alone. Training and evaluation rows carry the conversation, follow-up and topic-switch conversations can be built from any labelled rows, and the trainer reports the three slices separately (
--followups,--switches,--labelled-weight,--min-feature-count). The bundled model is retrained on 1 830 synthetic rows, their follow-ups and the weighted labelled rows with a 128-token attention window: 0.98 holdout accuracy on plain prompts, follow-ups and topic switches alike at ECE 0.01. - The routing model learns from outcomes by reinforcement. The online update is now a policy-gradient step on the model's own prediction - reward minus a per-target running baseline - weighted by how likely the model itself was to make the pick the router made, and capped, so traffic routed by the whole ensemble trains the model without bias. The outcome you report carries the router's logged propensity (
propensity), filled from the request memory when the router learns. Theonline_policysetting isreinforceby default;supervisedkeeps the previous label update. The strategy's status reports the policy in force and the last advantage. - Live web context for requests that depend on facts that change. A new freshness signal scores how much a request needs current facts (news, prices, weather, scores, "latest", "today", an explicit "look it up", this year's date), and the capability strategy nudges targets tagged
web,searchorbrowsing. Web grounding searches such requests - DuckDuckGo, Hugging Face and Brave as before, now also keyless Wikipedia and a self-hosted SearXNG (SEARXNG_URL) - screens every hit with the injection lexicon and hands the rest to the model as a Live web context block, recorded in the trace; force or disable it per request withcontext["web"]; results are cached per query and a failed search never fails the request. Switch it on withRouterBuilder.with_web_grounding(),harden(web_grounding=True)orosr serve --web-grounding(OSR_SERVER_WEB_GROUNDING). - The TensorFlow routing head reads the conversation and remembers outcomes. With
context=Trueit routes follow-ups with their history, keeps every outcome in a bounded replay memory and fine-tunes on it between full fits - good outcomes as positives, bad ones as reward-weighted mass on the other targets; the memory is saved beside the model. - Five newer routing datasets among the known sources.
arena-expert-5k(2025 domain-expert battles),search-arena-7k(search-augmented models, with tier rules for their names),repochat-arena,llama3-70b-battlesandroutellm-mmlujoin the known dataset sources, verified against the Hugging Face datasets server; conversation columns stored as lists or as Python text are parsed. - Every list reads the same way. Every list the API returns whole - in the dashboard members and invitations (now one list), the audit trail, hand-off and support tickets, feedback, events, the leaderboards, API keys (status filter: active, used this week, never used, expired, scoped, limited), usage per tenant, the per-target table, observed spend, the impact report's tables, marketplace listings and installs; in the console operators, coupons, leads, offers, digests, listings, runs, the whole price book (not the first 200), wallets, invoices, growth keywords, campaigns, all search queries (not the first 100), posts, model mappings, ranking runs and the lists on the workspace and user pages - gets a search box, role and status filters and a count once longer than a handful, and a pager (10 / 25 / 50 / 100 a page) once longer than a page; an empty result says so with a clear link.
- Forms show the essentials first. What most people never change folds behind one More options row that states what is set inside while closed: a support ticket asks for the subject and what happened (category, priority and the request id behind the row); a coupon asks for the code, the trial length and the plan (redemption cap, deadline, description and auto-apply behind it).
- The routing model's file is about a quarter of its size. Model weights are stored as per-row integers - int8 by default (
OSR_SLM_QUANTIZE_BITS=8, a fifth of the bytes of the floats it replaces, about 0.5 % weight error), packed int4 (4, a tenth) or floats (0) - and dequantised on load, so inference is unchanged.osr slm quantize FILE --bits 8|4|0 [--out] [--check rows.jsonl]re-encodes a file and reports size, weight error and top-1 agreement;osr slm train --quantize BITSsets the width of a trained file;osr slm infoshows the quantisation. Quantised files carry format 2 (an older package refuses them with a clear error); older float files load unchanged. The packaged model shrank from 2.15 MB to 0.58 MB with identical top-1 picks on the example dataset. - The Model providers page is rebuilt around configuring, not reading.
/platform/dashboard/providershas three tabs. Your providers connects an endpoint through a dialog: pick the provider from a logo grid (Azure OpenAI, OpenAI, Anthropic, Bedrock, Vertex AI and Gemini first), fill in what its URL asks for (resource, region, project - the URL is assembled and shown, or edited by hand), paste the key, and set the key header, extra headers, timeout, retries and notes under Advanced; the connection is checked on save and the models the endpoint reports appear on the card. Each card shows health with the time of the check, the masked key, timeout, retries, headers and mapped targets; Edit changes every stored field and replaces or removes the key - before, only the key and the enabled flag could change. Removing a provider or unmapping a target asks for confirmation. - Targets are mapped from one searchable list. The Targets tab lists every model and tool the router can choose from with where it runs for this workspace (yours, platform, not executable), searchable and filterable, with Map, Change and Unmap per row; the mapping dialog groups targets by where they run, offers the reported models and takes a system prompt and JSON request defaults. Included with the platform folds the deployment's providers per provider instead of a wall of chips.
- Governance and Tenants are split into tabs and edited in a dialog.
/platform/dashboard/governancehas Overview (spend, quota, reachable targets, the policy in words, compliance posture), Controls, Budgets and Audit and keys; the policy is edited in a dialog whose eleven fields sit in four sections - where requests may run, cost and latency limits, budgets, privacy - with the executable targets offered as one-click chips under the allow and deny boxes, inline validation (negative numbers, a preferred latency above the hard cap, a target both allowed and denied) and the saved policy shown as readable rows (Region eu,Daily budget $5.00) instead ofkey=valuebadges./platform/dashboard/tenantsuses the same dialog plus the slug, checked against the taken ones, and a Usage and setup tab with totals and the curl example. - The Workspace page has tabs, and SSO is set up in three steps.
/platform/dashboard/workspacehas General, Single sign-on and Leave or delete, creates an organization in a dialog and sets up SSO in three steps: pick the provider from a logo grid, paste the client credentials next to the redirect URI to register, decide who gets in with domain, default role and group-to-role rows instead of agroup = roletext box. Every destructive action on these pages - remove the policy, delete a tenant, remove SSO, leave the organization - asks in a dialog instead of the browser's confirm box. - Forty-eight more settings are editable from the console.
GET /api/v1/admin/settingsmarks themeditable: the router's decision cache and the/v1/responsesconversation store, spending reservations, the routing model's reload and per-workspace training thresholds, provider reload and keep-warm, the gateway timeout, the rankings and marketplace harvest cadences and limits, blog and newsletter behaviour, the growth engine (interval, posts per day, auto-publish, writer targets, keywords, IndexNow, the paid-search budget, LinkedIn sharing), the finance, overage and trial sweeps, the launch coupon and the Application Insights export - each with its kind, bounds and whether a change is live or waits for a restart. - The run-time configuration travels as one document.
GET /api/v1/admin/settings/exportreturns every override as{"overrides": {...}}for version control;PUT /api/v1/admin/settingsapplies such a document to another deployment in one step - every value is checked first and one refused value stops the import with the list of problems, otherwise the reply names what changed, what was already so, whatreplace: trueremoved and which changes wait for a restart; the import is one audit entry. The console's Configuration page gains an Overrides as code card with Export and Apply. - A one-line router from your catalogue files.
Router.from_files(targets, rules=None, state_dir=None, **kwargs)builds a router over atargets.yamlor.jsoncatalogue and an optionalrules.yaml;state_dirpersists the bandit state and the feedback log, and every other keyword reaches the router. osr doctorchecks the installation and says what to do. It reports the interpreter, the package and where it is installed from, every optional extra with itspip installline, the bundled routing model, the config directory, the sign-in (--profile) and, with--targets/--rules, whether the catalogue loads.--jsonfor scripts; exit 1 when something required is missing.- The MCP
routetool carries the whole request. Beside objective, constraints, kinds, plan and top_k it takesexclude(an agent handing the request back),context,historyandsession_id, thetenantconstraint and theenergy/carbonobjective weights - everything the router accepts. With a marketplace hook it also takesmarketplace: [slug, ...]: those listings are considered as candidates for that one request, and fill the plan's slots, without being installed; the result lists them undermarketplace_candidates.asktakes the samecontext/session_id. - The local
osr mcpcan answer, not only decide. When something in the catalogue can run - an LLM behindOSR_LLM_BASE_URL, an A2A agent or an MCP server with a bound endpoint - the stdio server offersask: route with a plan, execute, learn, and return the answer, tokens, cost and the plan's steps, the wayosr serveand the platform already did.logging/setLevelis honoured and advertised. - Conversations live on the platform and continue from any client. Start one with
osr.conversation: trueonPOST /v1/chat/completions, then send only each new message withosr.conversation_id; the platform prepends the last twelve turns verbatim and a rolling summary of everything older, so a thread never outgrows the model, never re-sends itself, survives a reinstall and continues from any client of the workspace (GET /api/v1/conversations, rename, delete,POST .../split). Every answer says whether the question looked like a change of subject (topic_shift) and whether the conversation was resumed after hours. The desktop app lists the workspace's conversations next to its own (renames and deletions reach every client) and offers Move to a new chat on a topic change; the browser extension's side panel does the same, so a chat survives closing the browser. - Long-term memory, learned from what you say. The platform learns by rules from what you state - name, employer, role, location, language, preferences, tools, projects, "remember that ..." - places it in front of later requests when it matters and removes it with "forget ..." (
GET/POST/PATCH/DELETE /api/v1/memory;PUT /api/v1/memory/settingsswitches it off). Nothing is inferred, and nothing is shared between a personal workspace, a user inside an organization or an API key. The desktop app confirms what was remembered under the answer and has a Settings › Memory section, the browser extension's settings page gains the same section, and the dashboard's Memory page (/platform/dashboard/memory) lists memories (pause, forget, add) and conversations with where each started. - The desktop app's main window shows the workspace's usage and the writing assistant. Usage (Ctrl+3) is what the workspace counted across every client: requests over 7 / 30 / 90 days, how many answered without an error, provider cost, how many came from this app, one bar per day, the split by app and by target, and the newest requests one by one (when, from where, what answered, cost, time, result, your rating), read live from
GET /api/v1/usageandGET /api/v1/activity. Writing (Ctrl+4) is the assistant as a page: on or off, checks and fixes done, autopilot, what it checks, and every application it has met with its own switch. Activity rows now carryapp, the client that sent the request (X-OSR-App). In-place fixes in Chromium apps (Edge, Chrome, Slack, Teams) wait until the slip is selected before pasting, so the text no longer lands at the old caret. - The desktop writing assistant can fix sure slips on its own, per application. Settings › Autopilot (off by default) applies the sure fixes once you pause - a misspelling the dictionary corrects with one or two letters and, with spelling and grammar, the rule set too; style advice is never applied alone. The badge reads N fixed and opens to Undo; a fix you take back is never applied automatically again, and at most two rounds run on one pause. Settings › Apps lists every application the assistant has met (kind, checks, fixes, last seen) with one switch each that wins over its kind; the badge's Off for this app now turns off that app alone.
- Organisations pin desktop settings with one managed file. One read-only file (
%ProgramData%\OpenSmartRoute\managed.json,/Library/Application Support/OpenSmartRoute/managed.json,/etc/opensmartroute/managed.jsonor the path inOSR_DESKTOP_MANAGED_SETTINGS) fixes the platform address, tenant, policy, updates, activity logging, selection and clipboard reading and any writing-assistant field for every account; pinned controls show Set by your organisation, and your own values come back when the file goes. On Windows the bar now reads the selected text through UI Automation before falling back to Copy (no clipboard side effects in Word or Outlook), and field reads normalise line breaks, so Notepad's alternating line endings no longer look like typing. - The browser extension remembers several workspaces. Connect a second workspace with Add (popup) or Add another (Settings) and the profile keeps both: a Workspace selector appears in the popup, Settings › Workspace lists them with Use and a forget button, the card's quote row says which one priced the draft (From Acme), and Sign out leaves only that key - another remembered workspace takes over, so a revoked or expired key no longer signs you out of everything. The list follows Stay signed in the way the key does.
- The DevTools panel filters by vendor and model, and the analysis policy has two levels. The panel gains vendor and model filter chips (the totals follow the filter - the tab's model mix at a glance), an empty state that says what to do and a Nothing matches state. The analysis policy has the two levels the documentation always described - nothing leaves the browser, or the draft goes for a price; the third value
route, which never gated anything, is read asquote, and a managed policy that still says it is accepted. - The desktop app checks your writing in every application. Settings › Check my writing as I type, in every app watches the text field that has the focus - a mail, a chat message, a document, a form in the browser - through the operating system's accessibility layer (UI Automation on Windows, the AX API on macOS, AT-SPI on Linux; no key is pressed, nothing is typed on its own) and, when you pause, checks the text on this computer: spelling with the dictionary you already have (the Windows spell checker with every installed language and your custom words, the macOS spell checker,
hunspell/aspellon Linux), grammar with a rule set (doubled words, spacing around punctuation, sentence capitals, I, a / an, alot, could of, your welcome, their is, its a, missing apostrophes, day and month names) and style advice (long sentences, repeated punctuation). - Fixes land in place, and private fields are never read. A badge at the field's corner counts the fixes and opens into the list with the dictionary's other spellings, Apply, Ignore (remembered), Fix all and Improve with AI, which hands the text to the command bar - the only path on which it leaves the computer - whose answer then replaces the checked text whole, not at the caret. Each fix replaces just its own slip; the rest of the document, its formatting, the caret and the undo history stay. Where an app has no text ranges the whole text is written back and the clipboard restored. Password fields, read-only text, address and search bars, terminals and any kind of app you switch off are never read; code editors are off by default. On Linux (
python3-pyatspi, X11 and Wayland) Settings says what to install when the bindings or the accessibility bus are missing. - Real grammar checks in the browser extension's writing card and the desktop bar. The sixteen-pattern typo list is replaced by a grammar checker that finds slips with exact positions, one rule per finding, never inside code, links, paths or addresses, and Fix writing applies them in rounds, since a fix can uncover the next.
- The desktop app names the app in front on Hyprland and Sway. On Wayland the command bar used to know the active window only on KDE; it now reads it on Hyprland and Sway as well.
- The operator console has its own tour, and every figure explains itself. The first sign-in through the console form opens a six-step tour of the overview - the grouped navigation, the eight deployment figures, the search box, sign-in configuration, storage and scaling, the operator guide - remembered per operator and replayable from Take the tour (or
?tour=1). The overview's figures, and those on Governance, Events, Learning, Model providers, Impact and Health, carry an i that says what is counted. The overview's sign-in card now points at Settings, where signup and password sign-in are switched, instead of environment variables. - A guided tour and plain explanations on the dashboard. The first arrival from signup opens a six-step tour of the overview - the sidebar, the figures, the getting-started checklist, the quick start, the header tools and the account menu - each step spotlighting the real element, keyboard-driven, on a phone as a bottom card; it is remembered per person and replays from Take the tour on the getting-started card (or
?tour=1). Every figure on the overview, Usage and Savings carries an i that says exactly what is counted (which calls, which window, what "provider cost" and "baseline" include). - Application Insights on Azure, off everywhere else. Every platform process - the API gateway, each domain service, the routing-model service - exports to Azure Monitor Application Insights when it holds a connection string and runs on Azure: requests (route, status, latency, workspace), dependencies (every router span and provider call), custom events (the routing events, never prompt text), traces and exceptions, all under the request's operation id so the end-to-end view and the application map line up; batched off the request path with bounded retries and no new dependency. The Azure template and the Marketplace offer create a workspace-based resource (parameter or wizard checkbox
applicationInsights, azdOSR_APPLICATION_INSIGHTS) and setAPPLICATIONINSIGHTS_CONNECTION_STRINGandOSR_PLATFORM_CLOUD=azureon every container. - The monitoring export is configurable and visible on the Health page.
OSR_PLATFORM_APPINSIGHTS=auto|on|offdecides (auto= a connection string is present and the host is Azure;on= anywhere the string is set, for a self-hosted stack reporting into a subscription), withOSR_PLATFORM_CLOUD,OSR_PLATFORM_APPINSIGHTS_CONNECTION_STRING, a sample rate over whole operations and switches for events and logs. The console's Health page shows the export andcontrols.application_insightssays whether it is on. The platform's own telemetry store,/metricsand the Health page are unchanged and remain the primary surfaces (Monitoring in the platform guide and the install guide). - Configuration preflight for self-hosted and cloud installs.
python -m osr_platform.app --checkprints what is wrong with the environment before the first request - the placeholder passwords of.env.example, a missing session secret on a multi-replica stack, public URLs still onlocalhostor plainhttp, e-mail confirmation required with no mail transport, a providers or targets file that is not in the container, a routing-model service without an event bus, Application Insights forced on without a connection string - each with the variable that fixes it; exit 1 on an error for deployment steps to gate on. Every process logs the same findings at start-up and the console's Health page lists them. A badOSR_PLATFORM_EDITION,OSR_PLATFORM_PROFILE,OSR_PLATFORM_APPINSIGHTSorOSR_PLATFORM_CLOUDvalue prints oneerror:line (exit 2) instead of a traceback. - Two-factor authentication for everyone, not only operators. Under Account › Two-factor authentication a person with a password enrols an authenticator app (the key and an
otpauth://link, confirmed with a first code; eight single-use recovery codes shown once; other browsers signed out), replaces the recovery codes or turns the factor off with password and code. Signing in with the password then asks for the code - the sign-in page has the step, with a recovery-code fallback - and a password-reset link no longer bypasses it: the new password is saved, the code is still due. Every change is e-mailed as a security notice. Operators see the state on the user page and Reset two-factor for someone who lost the phone; sessions end and the person is told. - Two-factor authentication in the API.
POST /api/v1/auth/mfa/setup|enable|verify|recovery-codesandDELETE /api/v1/auth/mfa;/auth/password/loginand/auth/password/resetanswermfa_requiredwith achallenge;mfa_enabled,mfa_enabled_atandrecovery_codes_leftsit on the user object; operators reset withPATCH /api/v1/admin/users/{id}and{"mfa_reset": true}. - Platform configuration is managed from the console.
/platform/admin/settingsno longer only lists what the environment set: the tunable settings - signup and sign-in policy, the operator two-factor policy, plan and pricing defaults, spending bounds, digest and support recipients, newsletter and blog publishing, marketplace review, cache and retention windows, trusted proxies, the output guard - are edited in place by a superadmin (switch, bounded number, choice, list or text) and reset to the deployment's value with one click. Each entry says where its value comes from (default, environment or override), who changed it and when, and whether the change is live or takes full effect after a restart. - Overrides apply at once, everywhere, and survive restarts.
PUT|DELETE /api/v1/admin/settings/{name}check the value against the setting's kind and bounds, apply it to the running process at once and write to the audit log; every other process (API replicas, domain services) adopts the change withinOSR_PLATFORM_PROVIDERS_RELOAD_S. Overrides survive restarts and win over the environment; secrets, storage and service topology stay read-only. - The plan catalogue is managed from the console too.
/platform/admin/planslets a superadmin edit a plan in place - monthly and per-minute quotas, keys, tenants and members, prices, overage, trial, SLA, support tier, features and description - throughPATCH|DELETE /api/v1/admin/plans/{name}: checked field by field, stored as a run-time override merged ontoOSR_PLATFORM_PLAN_OVERRIDES, in force at once for every workspace on the plan and adopted by every process; customised and env badges say where a plan's values come from and Reset returns it to the deployment's definition. Every change is audited. - Send feedback from any page, with the evidence attached. The dashboard header has a Send feedback button (and a page,
/platform/dashboard/feedback): a bug, a feature idea, an improvement or praise about the page you are on. The browser attaches what the team needs to reproduce it and you cannot easily describe - the page, browser and viewport, the platform version and plan, the last console errors and the last API calls with their request ids (never a request body, never a key: anything that looks like one is redacted in the browser and again on the API) - and up to three screenshots, captured from the screen, pasted or uploaded. Every item gets a reference (FB-00012) and a confirmation e-mail. - Feedback is triaged in the console, and you hear back. Operators work it at
/platform/admin/feedback- new, reviewing, planned, in progress, shipped, declined; answers, internal notes, assignment, the screenshots and the diagnostics with request ids linked to the request log - and every status change and every answer is e-mailed to you with the note quoted (category Feedback you sent, switchable) and shown in the workspace inbox. API:GET|POST /api/v1/product-feedback,GET /api/v1/product-feedback/{key},POST .../comments,GET .../attachments/{id}; operators/api/v1/admin/product-feedback. - People are told what happens to their account. Whoever sent an invitation hears when it is accepted; a member whose role changes or who is removed from a workspace receives a note saying who did it; an operator signing a person out everywhere, disabling or re-enabling their sign-in triggers a security or account notice to that person. Until now these were audit entries only.
- Every endpoint the platform serves now has a screen. The playground gains Embeddings, voice and images:
POST /v1/embeddings,/v1/moderations,/v1/images/generations,/v1/audio/speechand/v1/audio/transcriptionsfrom the browser, with the targets of your catalogue that can serve each, the target that answered, the request id and the equivalentcurl(/platform/playground?mode=media). The operator console shows the test data an automated check left behind (users and workspaces on reserved testing domains) with a superadmin Delete all test data on the Configuration page, and the content page exposes Add the curated feeds and Fetch missing images - operations that existed only as API calls before. - Registered people read the newsletter by default.
POST /api/v1/signupfiles the address as a pending reader without a second confirmation mail; the account's own proof of the address - the confirmation link, a password reset, an accepted invitation, an identity provider that vouches for it or an operator marking it verified - confirms the reader with a consent record. The signup form says so next to the terms, the welcome mail says where to turn it off, and the Account › E-mail switch shows after e-mail confirmation until then. An address that unsubscribed is never re-enrolled and a reader who confirmed through the form is left alone.OSR_PLATFORM_NEWSLETTER_SIGNUP_DEFAULT=falserestores form-only enrolment;GET /api/v1/inforeportsnewsletter_signup_default. - What this deployment offers, as a page and an endpoint.
GET /api/v1/servicesand the/servicespage list every first-party capability - routing, the OpenAI-compatible proxy, quotes, plans, learning, the routing model, your own providers, human hand-off, the MCP server, traces, savings, governance, tenants and audit, alerts, usage digests, support, the marketplace, the model catalogue, the blog, the newsletter, single sign-on, billing, the CLI, self-hosting, the browser extension and the desktop app - computed from the deployment's state at the time of the call, withstatus(live,limitedwith the reason, oroff), the realendpoint,access, the cheapestplanthat includes it,docs,pageand livefacts. The welcome mail and every newsletter issue link to the page. The TypeScript SDK gainsclient.services()with typed results.
Changed
- The browser extension and the desktop app wear the site's editorial palette. Surfaces and text move to warm cream (light) and charcoal (dark) neutrals, and one warm clay accent replaces the blue-cyan gradient on everything you can press or follow: primary and accent buttons, the send control and the avatar, switches, links, focus rings, the composer's focus outline, the streaming caret, the spinner and the toolbar badge. Count pills invert with the scheme instead of hard white. The three brand hues stay on the mark, the tier badge, the pick labels and informational chips. The desktop's windows paint the new paper before the content loads. The extension and desktop guides describe the shared look.
import opensmartrouteis a quarter faster. About 400 ms down to 300 ms on Windows: the async router andasyncioload on first use, and plugin discovery imports its machinery only when it runs.pip install 'opensmartroute[all]'now includestiktoken(TensorFlow stays an explicit[tensorflow]opt-in); the install guide lists every extra with the same words.- The routing model's attention window defaults to 128 tokens. It was 64; the window is stored per model file, and prediction cost is unchanged on prompts under the window.
- The browser extension's card is quiet by default. It opens by itself only when there is a reason to interrupt - personal details or a key in the draft, a jailbreak pattern, a held send, a model that will not do what the draft needs or is near its context limit, or a cheaper fitting model that saves at least a cent on the request. Slips, tips and prices wait in the pill, which on the chat sites now shows a count of things worth a look before sending (empty when there is nothing) instead of a score that was always on screen; closing the card keeps it closed for that draft. The edge tab no longer appears on the chat sites (the shortcut and the popup still open the sidebar there). A clean draft on a fitting model shows nothing but an empty pill; personal details open the card.
- Savings are shown as money against the model you picked. Inside the card the tips that are not mistakes (audience, format, a vague ask) sit behind one line, N tips for a better answer; the saving is shown only as money against the model the site has actually selected (saves $0.012 vs GPT-5 Thinking), never as a percentage against the dearest option; the wordmark left the footer, which now names who quoted (Quoted by and the workspace).
- The desktop app's main window is a desktop application, not a phone screen. The sections and the conversations live in a proper sidebar - New chat, Chat / Models / Overview, then every past conversation grouped by day with a search field, rename in place (double-click or the pencil) and an inline "Delete this conversation?" instead of a silent bin - with the workspace and Settings in its footer; the bottom dock and the sliding sheet are gone, the composer is docked under the transcript and the window title names the conversation in view. On macOS the Dock icon appears while the main window is open. The Overview lists the most recent conversations and no longer decorates a count with a sparkle.
- The desktop app has an application menu with the usual shortcuts. File: New Conversation Ctrl+N, Ask from Anywhere, Settings, Quit; Edit: the standard roles - without which copy and paste did not work on macOS - plus Find Conversation Ctrl+K and Focus Composer Ctrl+L; View: Chat / Models / Overview Ctrl+1-3, Toggle Sidebar Ctrl+B, Appearance, zoom, full screen; Help: Documentation F1, Dashboard, Copy Diagnostics, Check for Updates, About. Esc stops an answer.
- The decision under an answer is one quiet line, and every surface says Sign in. Target, provider, whether it fell back, cost, time and tokens trimmed are one line rather than four pills, and the invented-looking "87% sure" chip is gone - from the desktop main window, the command bar (whose "(quick)" suffix, an on-device guess beside the router's real decision, is gone too), the browser extension's side panel and the website's desktop previews. Settings hints are one sentence each, every surface says Sign in rather than Connect, and the welcome window says what each step does in one sentence and no longer discusses store listings that are not live yet.
Fixed
- The nightly database backup runs again. Every code change to the database paths started a fresh dump of production on top of the nightly one, so the backup share filled up and the job died with No space left on device. The job now keeps one archive per database per day and prunes before it dumps; a dump is taken on the nightly schedule and on a manual run, while a code change verifies today's archive instead of making another.
- A slow first token no longer cuts off a streamed answer in the desktop app. The desktop app gives a slow first token the same patience as every other streamed answer, and the TypeScript SDK's types now cover the conversation, memory and run-time configuration endpoints.
- Provider and offer writes need the
provider_managerrole, as documented. Creating, editing, deleting and checking a provider endpoint, mapping targets to it and listing, changing or removing offers accepted any operator token; they now needprovider_manager(superadmins and the static admin token pass), and reads stay open to every operator. The documentation now says organization SSO is owner-only (which the API and UI always enforced) and that remove member is the workspace-level way to cut someone's access. - A free, instant tool no longer wins a request it cannot do. With the frontier model excluded, Prove sqrt(2) is irrational went to the calculator tool: its penalty for an action it does not offer was the same as a generalist model's off-domain one, and zero cost and 5 ms latency did the rest. The capability strategy now treats a tool as the narrow executor it is - asked for an action it does not offer, or for more than its complexity band, it takes an extra penalty (
OSR_CAPABILITY_TOOL_OFF_SCOPE_PENALTY, default 0.35) and the request goes to a model that can reason; a real calculation still routes to the calculator. Example-catalogue accuracy 0.94. - Catalogues from
osr marketplace syncrun their agents and tools after a restart. The manifests were converted without binding their endpoints, so an A2A agent or MCP server that executed fine in the process that synced it became instructions-only once loaded from the file. Catalogue files, single manifests and manifest directories now bindhttp,a2aandmcpendpoints on load; nothing is contacted until the router picks the target, and an endpoint the handlers refuse is recorded in the target's metadata. - MCP tool failures are tool results, not protocol errors. No admissible target, a provider that is down, a marketplace listing that does not exist and every other SDK error now come back as
isErrorcontent the model can read, instead of a JSON-RPC-32603. - A file-backed feedback log is written from the first line. The router treated an empty feedback store as absent and replaced it with an in-memory one, so
osr ... --state DIRand any router given a fresh file-backed store never wrotefeedback.jsonl. It now replaces only a missing store.osr servewithout theserverextra prints thepip installline instead of a traceback. - The Human queue explains a deferral in words a person can act on. A ticket's Why it deferred was the router's raw explanation - signal values, candidate counts and a strategy dump - stretched across the card. The API now stores a few plain sentences instead: what the request reads as, who policy ruled out and why, how the human target ranked against the runner-up, which strategies carried it and which targets failed before the router re-routed there. The page (
/platform/dashboard/handoffs) shows the request and those reasons side by side with a link to the full trace, three figures (waiting with the oldest wait, answered, handed to people), Waiting / Answered / Cancelled tabs, a quality choice in words (Solved ... Could not help much), Send answer, a confirmed Cancel ticket and an empty state that opens the playground with an escalation prompt. - A request that declares
contains_pii: falseis not redacted after all. The guard's redactor ran on every request and set the flag back to true when it found an address, so the platform's own writers, which mark their public material (news feeds, documentation) as not-PII, still lost every public model to PII not allowed on this target and failed dozens of times an hour. The guard now honours an explicitfalse- the caller vouches for the text - and leaves an unset flag to the redactor. - Console screens that read as unfinished. Automation said every component answered while the content writer had failed on its last hundred runs - the board now counts a job whose writer's last decision failed, or that reports an error, as needing attention and prints the reason with the policy rejections; the Posts header on Content collapsed to a one-letter-wide title under its toolbar (the toolbar sits under the title now); the Analytics cost axis read
0.00five times and the latency axis0 us(every money and duration axis now uses a tick-aware formatter); Finance labelled decision-only rows(none)(now no provider (decision only)); the Services cards cut no networ... and shared wit.... - Console fields and filters that spilled out of their cards. Terms and privacy pushed Send notice out of the card (the published date moved under the version, the button is short); the Audit log filters orphaned Workspace id on a second row and wrapped 30 min ago over three lines, as did a user page's history; the workspace page's Region field ran past the card.
- More console cards kept inside their edges. Health's circuit-breaker grid drew a success >= 100% tile with 0 us latency for every target that had never been called - only called or tripped targets get a tile now, the rest are one collapsed line ("N targets in rotation with no calls yet"), and a target without a budget says none set rather than an infinity sign; the Offers table lost its status switch and delete button off the right edge (provider, upstream id and data policy fold into one cell); Tenants printed each tenant's configuration as a JSON blob (chips now, like the workspace page); the Marketplace Sources card ran a 14-item list off its card (top three, the rest behind the info icon); Model rankings said runs 15 s after start under a schedule that was off; Feedback's Kinds card carried the support-recipients hint.
- Figures and greetings that were wrong by a little. Headline cost figures (Provider cost, Spend today, the finance cards) showed
$0.00for sub-cent spend that the tables beside them listed as$0.0011; they use the adaptive precision now. A pending invitation said expires just now and the automation board next run just now for moments in the future; relative times now read in 15 min / in 6 h / in 7 d. The workspace page greeted an owner with You are a owner. Converting a personal workspace into an organization left the person's fresh personal workspace with an empty name; it is named after them, as at signup. - The browser extension repeats the platform's reason for a refusal. A run with a real workspace key on the live sites found what the mocked pages could not. A
403said this workspace does not allow that whatever the platform's reason was; it now repeats the reason - the e-mail confirmation gate, a plan feature with See plans, a disabled workspace. A key without a cached workspace record (seeded by policy, an older install) showed the platform's hostname as the workspace; the record is re-read from/api/v1/mewhen it is missing or over an hour old, so a rename or a plan change reaches the popup and the sidebar and a revoked key signs out. The sidebar's workspace chip was cut to four characters beside the wordmark; the mark alone stands for the brand in a narrow panel. - Writing commands and rewrites come back clean. A free command's result began with the triple quotes the prompt used as a delimiter; the prompt now uses tags and the answer is cleaned of tags, triple quotes and an echoed Text: label as it streams. Rewrite failed with a parse error when the model copied a quoted word from the draft unescaped, or stopped mid-list; the parser now recovers the complete rewrites. The commands popover could grow past the top of the window as a result streamed and sat on top of the card; it is capped to the room on the side it opened and folds the card while it is up.
- The card on ChatGPT keeps to its size, and a dead stream says so. The card on ChatGPT's empty page filled the whole height above the composer, covered the site's header, clipped Quoted by your wor into the sidebar link and claimed saves 100%; it is capped at 62% of the window, the footer truncates with an ellipsis and savings top out at 99%. A stream that died after the router had named the model said Could not reach opensmartroute.ai; it now says the model did not finish and offers to send again.
- A cold self-hosted model no longer times the whole answer out. The Ollama providers on Azure Container Apps were given 300 s per call while the ingress closes any response at 240 s: a model still loading at that point took the client's connection down with nothing sent, and the platform's fallback never ran. The providers now give up at 180 s, so the fallback answers inside the budget.
- The self-hosted Compose install works as the guide describes. The install guide told self-hosters to add the Ollama providers file as a Compose overlay - it is a providers file, not a Compose file - and the Compose stack had no model server at all. The stack now has an
llmprofile (Ollama plus a model pull; the GPU overlay still applies) and mounts the providers files at/configin every platform container, soOSR_PLATFORM_PROVIDERS=/config/providers.ollama.yamlworks as documented. Theapicontainer has a health check and the web app waits for it in both Compose files; the console path is/platform/admin/logineverywhere; the minimal Compose file takes the same mail transport variables as the full one;.env.exampledocuments the sign-up posture (e-mail confirmation, test domains), the Microsoft 365 transport and the monitoring knobs. - The soft latency target works again.
osr route --constraint preferred_max_latency_ms=...listed the key in its own help text and then refused it (exit 2), because the constraint and the tail-latency scoring it drives were lost after 1.0.preferred_max_latency_msis back as a soft target scored against each target's observed p90 once five calls are in its rolling window (the moving average before that, then the declared latency), so a target with a good mean and a bad tail is penalised without being excluded - the hardmax_latency_msstill drops it. The health snapshot and the platform's Health page show p50 / p90 / p99 latency per target again, the MCProutetool accepts the key, and workspace and tenant policy carry it (the stricter of request and policy wins) with a field on the Governance and Tenants pages. - An outcome names the plan it belongs to. The outcome's plan id was declared "so slots can be credited jointly" but nothing ever wrote it; every outcome of an executed composition now carries the plan's id (
persona:x+skill:y>llm-mid: the slots in order, then the primary; none when the primary ran alone), and the learning events report it. - The subprocess agent harness forwards the conversation. It was the one harness that dropped the history (the callable and HTTP harnesses pass it on), so a command-line agent answering the third turn never saw the first two. Prior turns now precede the task on stdin as a
role: contenttranscript under a heading ("Conversation so far:"by default; set the heading to none to keep the task-only stdin). - Generated client types import cleanly again. Two request bodies sharing a name made the OpenAPI document emit module-qualified schema names, which broke every client importing
FeedbackInfrom the generated types (the TypeScript SDK). The product-feedback body is nowProductFeedbackInand the two operator refresh bodiesRankingsRefreshInandContentRefreshIn; a check keeps schema names stable from now on.
Security
- Dependency floors raised above the releases pip-audit flags.
python-multipart>=0.0.31andcryptography>=46.0.7(SDKserverandcryptoextras, the platform and the Docker images) andmarkdown>=3.8.1(the platform). Fresh installs already resolved to fixed releases; pinned environments now do too.
1.6.0 - 2026-09-17
Added
- The SDK sizes a self-hosted model server before you deploy it. The SDK now does the arithmetic Ollama and llama.cpp do internally - weights from parameters and quantisation, the KV cache from layers, heads, context and parallel slots, tokens per second from memory bandwidth and cores, and the cold-load time from the model store's read rate. A planner packs a set of models onto hosts, shrinks a model that does not fit, names what fits nowhere and writes the
OLLAMA_MAX_LOADED_MODELS,OLLAMA_NUM_PARALLEL,OLLAMA_CONTEXT_LENGTH,OLLAMA_KV_CACHE_TYPE,OLLAMA_KEEP_ALIVEandOLLAMA_MAX_QUEUElines that pin that set. A dependency-free Ollama client reads model shapes, the store and what is loaded now, and loads or evicts a model on demand. The CLI isosr capacity plan | show | ps; defaults come from theOSR_INFERENCE_*settings. - Self-hosted models answer from memory, not from the disk. The slow part of an answer from an open model on the platform was waiting for its weights to be read from the share after a deploy or an idle spell. Model servers now load their set as soon as it is pulled and keep it resident, and the platform asks every self-hosted Ollama provider what it holds on each health pass and loads any mapped model that is missing (
OSR_PLATFORM_PROVIDERS_KEEP_WARM_MAX, set per hardware profile on Azure; a server that maps more models than it can hold is left alone).GET /api/v1/providersgainsproviders[].loadedandmodels[].warm, so a client - and the operator's Check - can see which targets answer without a cold load. - A streamed answer starts flowing before the model speaks.
stream: trueused to hold the whole response until the first token, so a model that was loading or working through a long prompt on a CPU looked dead for minutes and an idle timeout could cut it off with nothing sent. The response now waits for the first token for at mostOSR_SERVER_STREAM_FIRST_TOKEN_WAIT_S(15 s) - early failures keep their HTTP status as before - then opens the stream and sends a keepalive comment everyOSR_SERVER_STREAM_KEEPALIVE_S(10 s) until tokens arrive; a failure after that point is reported in the stream as anerrorevent. The Responses and Anthropic dialects, the platform gateway, the playground and the TypeScript client all pass the keepalives through and surface that error. - Mail that bounces for good is never sent again. An address the transport rejects permanently goes on a suppression list and is never written to again by any message, and Azure Communication Services delivery reports (
POST /api/v1/email/events/acs, on withOSR_PLATFORM_MAIL_EVENTS_TOKEN) mark every sent message delivered, bounced, spam or quarantined and suppress the bad addresses too. Operators see the list on the mail page, add complaints by hand and allow an address again (/api/v1/admin/mail/suppressions); the delivery outcome shows on each row and in/metrics(osr_mail_*).OSR_PLATFORM_MAIL_POSTAL_ADDRESSprints the sender's postal address in every footer. - Owners hear about keys and plan changes. The workspace owner is now told when an API key is created or revoked and when the plan changes.
- Newsletter readers shape their own subscription. Every issue links to a preferences page of your own (
/newsletter/preferences): daily or weekly (one digest onOSR_PLATFORM_NEWSLETTER_WEEKLY_DAY), your time zone, what is stored, and an erase button that deletes the record. Confirmation records the consent (moment, IP, browser, wording), and each issue reports how many distinct readers opened and clicked it - a beacon and a click redirect keyed by a hashed reader id, kept 180 days, off withOSR_PLATFORM_NEWSLETTER_TRACKING=false. - The desktop app has a proper window, not just a pop-up bar. Open OpenSmartRoute in the tray (or the dock on macOS) opens a resizable window that remembers its place and size. Overview shows the connected workspace, how many conversations and answers are kept on this computer and what they cost, which targets answered you and what the catalogue holds; Chat keeps the conversation, with past ones down the side, Markdown answers with copy buttons on code blocks, and on each the target and provider that answered, the router's confidence, the cost and the time, with Copy, Regenerate and two rating buttons; Models shows the catalogue the router picks from - price per million tokens in and out, context window, typical reply time, benchmark and how each has done on your own traffic - sortable by most capable, cheapest, fastest or most used. The command bar is unchanged.
- The browser extension and the desktop app log what they did to your workspace. Most of what the two apps do - a draft checked before sending, personal details redacted, a writing fix, an answer pasted back - never reached the router. Each app now posts them a few minutes later (
POST /api/v1/usage/activity); the Apps page shows counts per kind and site, tokens handled on-device, what the card's picks saved and a daily series. An event is a kind, a hostname, a count and a figure - there is no field for text and the platform refuses one. Your plan decides what is kept - 7 days and 5 000 events a day on Free, 30 days and 50 000 on Pay as you go and Pro, 90 days and 500 000 on Team, a year with no daily cap on Enterprise; a custom retention wins - and both apps have a Log my activity to the workspace switch (on by default) that administrators can pin. - The two operator tools a self-hosted platform needs ship with it. Setting up Stripe and importing a pre-1.1 SQLite database used to be described as files you were expected to already have; they are now real commands installed alongside the API -
osr-platform-stripe-setupandosr-platform-import-sqlite- and work inside the API container exactly as the platform guide describes. - Updating the desktop app by running the new installer is a supported path. Downloading the new installer and running it over the copy you have keeps your settings, the workspace you connected, your chat history and the browser extensions, replaces the application and leaves a single entry in Apps & features - the way to update a machine with no internet, or to roll a version out with your own tooling (
/Son Windows, the package manager on Linux). The desktop guide gains a section on updating offline and across a fleet, including where to pre-seedsettings.jsonbefore anyone signs in. - Every e-mail reads plainly, and the newsletter says why each story matters. All customer-facing messages - welcome, confirmation, billing, reports, alerts, the newsletter and support replies - were rewritten in plain language: short sentences, everyday words, one action, and a line on why you received it. Each newsletter card now carries a Why it matters line, the reading time and the source, and a story is only published when it comes with a real picture.
- Real, confirmed people only. E-mail confirmation is now required before a workspace can use the API or dashboard: until the address is confirmed the dashboard shows the confirmation step and API calls are refused with a clear header. Signups from reserved testing domains are refused, and accounts that never confirm are removed after 14 days together with their unused workspace.
- Every platform event can reach your channels. Webhook, Slack and Teams channels can subscribe to the complete set of event families the platform publishes - including billing invoice events and the full hand-off lifecycle - and the platform guide documents each one.
- Scheduled e-mail follows each person's own clock. Users and newsletter readers carry a time zone (picked up from the browser, changeable under Account › E-mail): usage digests, the daily newsletter, reminders and release notes arrive in the recipient's local daytime instead of at a fixed universal hour.
Changed
- The public counters count customers, not the platform talking to itself. The deployment's own jobs - the blog writer, the growth engine, the support assistant - now route as the apps
platform-editorial,platform-growthandplatform-support, andGET /api/v1/stats/publicleaves them out of every headline number (requests, tokens, workspaces routing, savings, most-routed targets), reporting what it excluded underinternal. The homepage band shows the median time to answer (p50_latency_ms) instead of a mean that a handful of cold local-model runs could drag to minutes, and its footnote says that first-party traffic is left out. On a deployment whose own writer ran on $0 local models, "99 % saved" was arithmetic, not evidence. - The playground quotes without an account. A signed-out visitor gets the real cost estimator (
POST /api/v1/estimate, which was always public) on/platform/playground; routing and answers still need a key. The sign-in card reads the free plan's limits fromGET /api/v1/inforather than quoting a number ("500 a day") no plan actually has, so the homepage promise - no account needed for a quote - is now true. - Confidence comes with its meaning. The decision panel labels the calibrated confidence - Clear winner, Likely best, Close call (near-tied capable candidates) or Low confidence - using the runner-up's utility margin, so a correct pick among three similar models no longer reads as a shrug.
- The enterprise availability figure is described as what it is. The plan catalogue, the pricing page, the billing plan picker, the support page and the platform guide call the 99.9 % a monthly availability target with service credits in the agreement, measured by the platform itself, rather than an SLA the single-region hosted stack cannot underwrite on its own. The platform journeys guide gains a Not offered, on any plan table (SAML, SCIM, Batch API, languages other than English, multi-region residency, an SLA below Enterprise) with the supported alternative for each.
- Support windows are dated, not positional. An earlier minor keeps security fixes for 90 days after the minor that superseded it shipped, and the security policy names the end date for each line. The releases page states the cadence (minors at most weekly, patches as needed) and the PyPI classifier now reads Production/Stable, which the frozen public API and this window justify.
- Production can be pinned to stable releases. A stable build (one made from its release tag) always deploys; a developer preview from the main line deploys unless the deployment sets
OSR_DEPLOY_PREVIEWS=false, in which case production moves only on release tags. The hosted platform therefore ends up on the stamped stable build after every release instead of the preview built in between. - A minimal profile for self-hosters.
OSR_PLATFORM_PROFILE=minimalserves every route and starts none of the first-party jobs (blog writer, newsletter, growth engine, marketplace harvest);GET /api/v1/inforeports the profile. The minimal compose file (docker-compose.minimal.yml) is the four-container stack - PostgreSQL, Redis, one API, the web app - for "the router with a dashboard", documented in the install guide. - Plan and billing is four short screens instead of one long one. The page used to stack thirteen sections on top of each other - alerts, the trial, the subscription, entitlements, the service level, the quota bar, five plan cards, invoices, credits, the usage table, a coupon form and an operator snippet - so answering "what did we spend?" meant scrolling past everything else. It is now four tabs, each answering one question: Overview (what this workspace is on and whether it is within it), Plans (what else it could be on), Credits (what it has spent and what is left) and Invoices (what was billed). Every tab is a link of its own (
?view=credits), and a return from Stripe opens the one that explains what just happened. Invoices are a screen in their own right, with a plain sentence instead of a blank card when a deployment issues none. - Documentation cards read whole, not cut off. Every card on the documentation index carries a short, front-loaded description that survives its two-line cut instead of stopping mid-sentence, stale wording is gone, plain-text cards no longer show literal backtick characters, and the changelog and the generated API reference - documents people scan, not read - no longer carry a misleading "41 min read" badge.
- Desktop: the browser extension installs in two clicks on Chrome and Edge. Chrome and Edge only install extensions from their stores, and while those listings are pending the app said "not available yet" and opened the download page, leaving a zip to find, unpack and keep safe. Get the browser extension now downloads the package, unpacks it into a folder of the app's own, puts that folder on the clipboard and opens each browser on its extensions page, so what remains is Developer mode, Load unpacked and paste; removing the extension deletes the folder again. Chrome and Edge install an unlisted extension silently only on a managed device, so that is the shortest path a personal computer allows; Firefox is unchanged, as its package is signed by Mozilla, and once the store listings are live the same button registers the extension and the browser asks once to enable it.
- Talk to sales is a link of its own, and the pricing page shows the path to production. The footer now links Talk to sales directly; the enterprise path previously started only on the pricing table or under Support. The pricing page gained From signing up to production: the six steps a workspace goes through, each with the API call behind it (
POST /api/v1/auth/verify/send,/api/v1/keys,/api/v1/route,GET /api/v1/workspace/providers,POST /v1/chat/completions,GET /api/v1/quota), so it matches the checklist the dashboard then tracks. The sales section of the support page states what the plan adds, what to tell us and what happens next, and takes the plan name, the availability SLA and the support response time from the deployment's own plan catalogue - the same numbers a workspace measures atGET /api/v1/sla- rather than prose that can drift. - The ROI calculator explains itself. It says it opens with an example workload, so it is usable before you have any figures of your own, and explains what the traffic file for a routing audit contains and that the replay runs on your own machine without executing anything or sending it anywhere - with an offer to run it with you.
- The documentation speaks to users, not about our development. Every published page was reviewed end to end: internal build and release mechanics, private source paths, test-suite names and deployment tooling are gone from the install guide, the platform guide, the extension and desktop guides, the marketplace and releases pages and the security review pack, and each page now describes what the product does and how to use it. The roadmap and contributing pages, which are development planning material, left the documentation site (the changelog and the versions-and-channels page remain the Releases section), and the development playbooks about the project itself no longer appear on the documentation site or as marketplace listings - a deployment that had published them archives those listings on its next start. The seven product-facing agent skills stay published.
- Learning state survives an outage of its store. A state store that cannot be read leaves the in-memory learners exactly as they are instead of blanking them, a failed save is retried once the store answers again, and a failing store is left alone for a cool-down so feedback never waits on it.
- SQL-backed state stores are more robust. A failed statement rolls back cleanly, a dropped connection is rebuilt and the statement replayed once, and PostgreSQL and MySQL connection URLs now work everywhere a state store is accepted.
- A request never waits for the event stream. Event publishing is fully asynchronous behind a bounded queue, so a slow or unreachable broker no longer adds time to routing, chat or feedback calls.
- The marketplace catalogue stays fast at any size. Browse filters, counts and facets are served from indexes and short-lived caches computed off the request path, and search input is matched literally and bounded, so no query can scan the whole catalogue.
- The routing model reports honest confidence. Calibration is smoothed so the served model no longer claims certainty on prompts unlike anything it has seen; promotions, rollbacks and reloads always move the model as a whole; a failed write never leaves a broken model file; and a challenger must earn a real improvement before it replaces the champion.
- Every signed-in screen names itself. Browser tabs, history entries and bookmarks now show each page's own title. A screen-by-screen pass also fixed phone-width layout collisions, latency charts that clipped large values (they read
1.2sand5.5mnow) and several small accessibility gaps. - A self-hosted target reports the model that really runs. A target written for a hosted model but served by a local runtime (Ollama) no longer shows that hosted model's maker and prices in routes, the catalogue, quotes and rankings when the local model is unknown to the reference catalogue; the runtime and model that answered are shown instead.
Fixed
- The README's Python runs as written. Its constraints example asked for an EU, private-boundary target from a registry that had none and failed with no route on the second copy-paste; the registry now carries an on-prem target and the comment shows the rejections the trace really prints. The production example ran targets that had no handlers and failed; it now routes and says what running an answer needs. A hard-coded confidence (
0.97) that the current router does not produce is gone, the performance envelope names its catalogue and machine, and the quick start exportsOSR_LLM_BASE_URLandOSR_LLM_API_KEYbeforeosr serveso the first/v1/chat/completionsdoes not answer 503. - The Azure Marketplace template deploys with plain Contributor rights. The template created a container registry and a role assignment for it on every deployment, although a customer deployment pulls the published images and never uses that registry - and writing a role assignment needs rights most customers' operators do not have, so the deployment failed before it began. The registry is now created only for a deployment that builds its own images; the Marketplace path skips it, and the plan gates (key caps, the plan feature for
execute) enforce exactly as documented. - A refund now reaches the workspace's credits. The platform has always credited a refund back to the wallet when Stripe reports one, but
osr-platform-stripe-setupcreated the webhook endpoint without thecharge.refundedevent, so on a deployment set up with it Stripe never told the platform and the money left the card while the ledger still showed the credits as bought. The event is registered with the other six; an existing endpoint gains it the next time the setup runs. - What a workspace spent by the token can now reach its invoice. The API priced every request, stored the charge and could report it to a Stripe dollar meter, but nothing ever created that meter or a price to bill it on, and a subscription only carried the overage item, so the charges never appeared on an invoice.
osr-platform-stripe-setup --usage-meter-eventnow creates the meter (one unit is one cent) and a metered price per plan, and a checkout or a plan change carries that item next to the overage one. Deployments that sell flat plans are unchanged: withoutOSR_PLATFORM_STRIPE_USAGE_METER_EVENTnothing is added. - Building the web images no longer sends a gigabyte of stale output to the builder.
docker compose up --buildanddocker compose watchshipped old build directories to the builder before it could start; the build contexts now leave them out. - Desktop: a settings file written by a deployment script is no longer ignored. The app read
settings.json,auth.jsonandthreads.jsonwith a strict JSON parse, so a file carrying a byte-order mark - what PowerShell'sUTF8encoding and many Windows editors write, and the likely shape of a configuration pre-seeded onto a machine - was treated as unreadable and silently replaced by defaults on the next save. The mark is now skipped, and a file that genuinely cannot be read is kept as<name>.corrupt-<timestamp>next to the original instead of being overwritten. - Desktop: uninstalling on Windows leaves nothing of yours behind. The app registers itself for
osr://links on every start and the uninstaller left that behind, so a link clicked after removal pointed at a file that no longer existed; the sealed sign-in and the saved conversations stayed on the disk too. The uninstaller now removes the link handler, the browser registrations, the workspace key and the conversations with the app; preferences stay, so a reinstall still knows which platform to talk to, and an update keeps you signed in. - Desktop: the command bar opens as soon as you press the shortcut. Opening the bar waited for the operating system to name the app in front before the window was even created. The window now loads while that probe runs, and macOS answers it in one call, so the bar is on screen while the context is still being gathered instead of after it.
- A recovered fallback now teaches the router. When a target answers a request another one has just failed, it beat it on that request - but that comparison was thrown away. The winning outcome now records which target it was preferred over, so the Bradley-Terry preference learner - an ensemble member with a weight of its own - finally has observations; in production it had exactly zero after nine days and 171 failed attempts.
- The platform's own assessment of an answer is kept. Almost nobody calls
POST /api/v1/feedback, so the judgement the execution already made - a handler's own quality, the implicit reading of a refused, truncated or empty answer, or a recovered fallback's comparison - is now written against the request, visible inGET /api/v1/activityandGET /api/v1/trace/{id}like any reported outcome, and published on thefeedbacktopic the SLM service trains from. "Nothing wrong found" is still not an assessment, but it is no longer thrown away when it carries a comparison. A platform job that grades its own output now publishes the grade for every target that shaped the answer (the plan's skill and persona), not only the model. GET /api/v1/learningreports the deployment, not one replica. The per-target outcome statistics came from the in-memory feedback store of whichever process answered the call - in production it showed 25 outcomes where 539 had been recorded, every target at a success rate of 1.0, and the two targets with by far the most evidence missing entirely. They are now read from the recorded outcomes of every workspace overOSR_PLATFORM_LEARNING_FEEDBACK_DAYS(30) days and carry the pairwisewinsandlossesas well.- Two dead ends on the public pages are gone. The comparison pages asked for corrections "as work items in the project" and the ROI page pointed at a sales kit "in the repository", neither of which a visitor can reach; both now name a real channel.
1.5.0 - 2026-09-16
Added
- Browser extension: answers stream and the composer is redesigned. A typed instruction arrives token by token: the result panel opens the instant you send, the first words replace the placeholder, and Stop keeps what has arrived. The composer is one rounded field with the send arrow inside it (
Entersends,Shift+Enterbreaks a line), and the Rewrite menu shows its variants as they arrive. The writing help now also reaches the embedded editors that classic rich-text fields use, so the widget appears in far more places. - Playground answers stream. Get an answer paints the reply token by token with a caret, Stop keeps the partial answer, and the routing line (model, confidence, tokens, cost) lands with the final chunk.
- Every workspace sees what the platform executes for it. The providers page opens with Included with the platform: the deployment's own model providers, each with its live health and the target-to-model pairs it runs, so a new workspace knows it needs nothing connected to get an answer. Provider health is re-checked on a timer, so the status shown is never stale.
- Activity names the provider and model that answered. Every activity row and trace carries the provider, the upstream model and the charge, on screen and in the CSV export, so the whole chain from request to decision, execution, usage and feedback names its executor.
- Browser extension: theme-aware icon, updates and the Firefox listing. The toolbar icon follows the browser's light or dark chrome, and the extension's own pages can be pinned to light, dark or system. The popup names the running build and, when a newer build of the same channel is published, shows an update card linking to it; the signed Firefox package updates itself like a store install, and store installs keep updating through their store. The Firefox Add-ons listing appears on the extension page as soon as it is live.
- Browser extension: a writing widget in every text field. A small pill in the field's corner offers three controls: a commands popover that runs any instruction on your selection or the whole field (rewrite variants with the changed words marked, fix spelling and grammar, shorten, summarise, translate, draft a reply, continue writing) with Insert, Replace and Copy and the model and cost that answered; a 0-100 writing score computed on the device (spelling, clarity, delivery, style, privacy); and a per-site switch with Disable until next visit and Disable forever. Settings gained allow and block lists (
*.example.comcovers subdomains) that administrators can pin per profile, the sidebar gained idea tiles, session history and a Suggestions tab with one-click fixes, and a two-step welcome opens after install. - Platform journeys guide. A new documentation page walks every audience through the platform: what each plan unlocks with a feature-to-page map, the navigation, a new user's first day step by step, everyday tasks by role, and plan-change and offboarding checklists, with the API call behind every step.
- Desktop app and browser extension: a long list of polish items. Both apps render answers as safely sanitised Markdown with per-block Copy, repaint only the streaming turn, offer Stop while an answer streams and explain errors in plain words with one action. The extension gained Redact and send on a held draft with Undo, a Connect row on rate limits, forced-colours support, managed-storage policies for fleets, localisation and an update notice; the desktop app gained thread history with retention, Regenerate, a pin that keeps the bar open, themes, a shortcut reset, smoother device-code sign-in and a first-open tour.
- Self-hosted models: the best open weights per job, plus Ollama Cloud and voice. The self-hosted server runs Qwen 3.5 for private chat and writing, GLM-OCR for document reading, TranslateGemma for translation, DeepSeek-R1 for visible reasoning, GLM-4.7-Flash for code, Qwen3-Embedding for embeddings and
gpt-oss:20b. Anollama.comAPI key upgrades the coding, research and gpt-oss targets to the frontier open weights through Ollama Cloud. Image generation and transcription run on the cloud tiers, and the self-hosted speech server (Whisper and Kokoro) serves speech-to-text and text-to-speech by default. Target mappings created by the deployment now follow the deployment when models change; an operator's own mappings always stay. - Desktop app: Linux parity and keys sealed at rest. The command bar works under Wayland, Start when I sign in works on Linux, the workspace key is sealed with the operating system's own key store, and uninstalling on Windows removes the browser registrations the installer created.
- Auto top-up for pay-as-you-go wallets. Keep a card on file when buying credits and set a rule - amount and threshold - so the wallet is topped up before it runs out. A declined card raises an alert instead of retrying in a loop, and every priced answer carries the remaining balance in a response header so a client can top up before hitting the limit.
- Dashboard: Impact and Apps pages, and an Insights group. Impact is the value report: provider cost saved against the baseline, success rate, personal data protected and the governance score, then the same figures per API key, tenant or client app, with CSV export. Apps puts the browser extension and the desktop app inside the portal with install buttons, connection state and traffic per client. The extension's report is now called AI spend.
- Desktop app documentation and an Apps section on the documentation site. The end-user guide covers install per system, the command bar, working inside the app in front, privacy, updates and troubleshooting.
- Console: Automation page. Operators see every schedule the deployment runs for itself - cadence, owning service, state - and can trigger any job now.
Changed
- Desktop app: the answer experience is rebuilt. The bar names the model as soon as the router has decided, before the first word, streams the answer behind a caret with shimmer placeholders until the first token, shows a thinking line when a reasoning model is working, and settles into decision chips: target, provider and upstream model, confidence, cost, latency.
- Desktop app: the app in front is recognised properly. Apps are named the way their makers name them, their icon appears on the context card and on Paste into …, and the quick actions follow the app: editors get Explain code and Write tests, mail gets Draft a reply, chat gets Recap.
- Every self-hosted model on CPU is its own always-warm server. On CPU hosting profiles each model now runs as its own service with the model pinned in memory, so a request never waits for another target's weights to load; previously models shared one server and evicted each other, and answers could take minutes of load time for seconds of inference. The large-model set now holds only the models that earn dedicated capacity on CPU (the mixture-of-experts coder,
gpt-oss:20band the visible-reasoning research model); the dense mid-size chat upgrades are served on GPU profiles instead, and their targets answer with the fast 4B model in seconds. The embedding target uses the stronger 2560-dimension model on every profile. - Self-hosted chat targets answer instead of thinking the budget away. Thinking models now spend the caller's token budget on the answer, not on hidden reasoning, except the reasoning-by-design targets, which keep their visible chain of thought. A request that sets its own reasoning effort always wins.
- The usage digest is a value report. The daily, weekly and monthly e-mail leads with what routing saved in the window, compares every figure with the previous window, shows where requests came from, what the guard protected and what changed in the workspace, and is redesigned so a phone shows it without shrinking.
Fixed
- A provider whose host does not resolve fails at once. An executed request against a stopped self-hosted provider used to wait through retries before answering; a host that does not resolve now fails immediately and the router moves on.
- The promoted routing model is the one served. A background refresh could overwrite the promoted routing model with a blank one on every replica; promoting a model is now the only thing that changes it.
- Browser extension editing and sidebar reliability. Rich editors keep their normal Enter behaviour and inline formatting during analysis and redaction, switching fields resets stale state, an open sidebar resumes pending work after connecting and keeps unsent drafts, and its composer stays on screen in narrow panels.
- Apps page: the installers download. The page now reads the live release manifests per request, so the install buttons always offer the published builds for your browser and system: x64 first on Windows, ARM only when the browser reports an ARM CPU.
- Windows: fresh installs no longer crash, and self-update works. An installer bug could crash any first install, and updates were refused as unsigned. Both are fixed.
- macOS: updates say why they are off, and downloads open. Without an Apple Developer ID the Updates section explains the limitation and points at the downloads page instead of failing, and the downloaded app now opens after the one-time Open Anyway instead of reporting itself damaged.
- Browser extension on Firefox opens its real sidebar. Firefox opens the sidebar instead of a plain tab, and the device sign-in names your actual browser.
- Browser extension sign-in finishes on time. The sign-in check honours the browser's minimum timer and both sign-in requests carry a timeout, so a stalled platform can no longer leave Connect a workspace spinning forever.
- Browser extension with a self-hosted platform. Saving a platform address other than the hosted one now asks the browser for permission to reach it; previously every request was silently blocked and the card only said "failed to fetch".
- The extension notices an expired workspace token. A revoked key or deleted workspace signs the extension out with a clear message instead of showing a routing error on every draft.
- The changelog page renders cleanly. Version headings no longer break the page, and angle-bracket placeholders in the notes display as text.
- Clearer error on a bare install. Training the optional neural models without the TensorFlow extra now raises a message naming the exact pip extra to install.
1.4.0 - 2026-09-14
Added
- OpenSmartRoute Desktop for Windows, macOS and Linux. A tray app with one global shortcut opens a command bar: type, and the same on-device checks as the browser extension give a one-line verdict with Redact; press Enter and the answer streams from the router with the decision chips under it (routed to X · 87% sure · $0.002) plus Copy and thumbs that feed the learners. Balanced, Cheapest, Best and Fastest set the objective. Settings hold the workspace connection, the shortcut recorder, start at sign-in, a per-browser extension installer and background updates that apply on quit. The first run offers Add to my browsers, which registers the extension in every browser it finds and records what it did so it can be undone.
- The desktop app works inside the app you are in. When the shortcut fires, the bar knows which app is in front - Word, Outlook, Slack, VS Code, a browser - reads the text you selected there, offers Explain, Summarise, Rewrite, Fix grammar, Shorten and Translate, and every answer gains Paste into …, naming that app, which hands focus back and pastes where the cursor was. Terminals are never read, and the bar says why.
- A landing page for the desktop app.
/desktopshows the app in use - a realistic desktop with the bar answering over Teams, Word, Slack, VS Code and more, quoted live from the platform - plus feature cards, install steps per operating system with sizes and checksums, and a fleet-install section. - Models by the token: an OpenRouter-style marketplace on the platform. An offer is one catalogue model served by one provider endpoint (
openai/gpt-4.1@azure). Callers can name a catalogue id and let the router pick the endpoint, or pin one; provider preferences (order, only, ignore, price caps) fold into the routing decision. The storefront shows the vendor list price next to your price for every model and endpoint, and the price shown before a call equals the charge after it. A pay-as-you-go plan joins the ladder - no monthly fee, prepaid credits, per-key spend limits - and operators list, pause and re-point offers from the console. - One version, two channels. Every artifact - platform, SDKs, browser extension, desktop app - carries the same release version. A tagged release is the stable channel; anything newer is a developer preview with its own label, visible in the site footer, on the API's version endpoints and in every app's About. Stable installs only update to the next stable release, and the releases guide explains how to read the build on every surface.
- Browser extension: one verdict, plain words, details only when they matter. The card leads with a single line anyone can read - Looks good to send, 2 personal details in your draft, An API key is in your draft - and keeps the details folded unless there is something to act on. Each detail is one sentence with at most one button (Redact, Fix, Trim, Connect). The model row says in words whether the site's selected model fits, is more than the draft needs (naming the lighter option and its price) or may not be enough.
- Opt-in request logging. The platform stores no request text by default; a workspace that wants it can set logging to redacted (personal data masked before storage) or full per policy or tenant. Logged pairs appear on the trace and in the activity drawer, are included in the data export, follow the usage retention and can be erased in one click. The governance posture flags the setting.
- The decision names the model to run. A routing decision now returns the provider and the reference model id behind the chosen target, so a caller that executes elsewhere can hand the choice straight to its own client and report the outcome back.
- Release notes reach you. New releases are mailed as a clean digest to everyone who takes product news, the dashboard shows a What's new card once per release, and the API publishes structured release notes with the version the deployment actually runs.
- Public downloads. A downloads page serves every self-hosting artifact of the current release - the Compose bundle, the Helm chart, the marketplace package and checksums - with stable short links and a machine-readable manifest.
- Browser extension: store-ready packages, guided install and a product page. One package per store - Chrome, Edge, Firefox (signed, installs on click) and Safari - is published behind a manifest the product page reads: it detects your browser, leads with the right install button, shows a guided developer-mode path while a listing is not live yet, and switches to the store buttons the moment they are. The page's hero is the real advisor card, live: every number is a real quote, and typing in the demo composer re-quotes your own draft.
- A writing score and API meter in the browser. The extension observes what drafts on the chat sites would cost, meters LLM API calls from the DevTools panel with exact usage and lets you replay any call through the router side by side; opt-in sharing uploads call shapes (never text) to the workspace's AI spend report.
- Learned token counting and a neural routing head (optional extra). An optional TensorFlow extra learns the gap between the token estimate and what providers actually bill, so quotes count the way the bill does; a neural routing head can join the ensemble and serve as an embedder for the routing model.
- Blog covers and one story, one post. Posts without a usable image get a generated cover, a publisher's site logo never counts as a lead image, and the same article delivered by two feeds becomes one post, on every poll.
- Documented backup and recovery targets. The platform guide states what protects the hosted database, the recovery point and time objectives, and how restores are drilled.
- Public status page.
/statusshows the live readiness checks and what the router did across every workspace, so a visitor can check the platform is up before creating an account. - Event webhooks. Channels can subscribe to request, outcome, hand-off, key, member, plan, support and governance events with signed deliveries, per-family selection, delivery history and retries.
- Native Anthropic support. Routing to Claude no longer needs a gateway: the platform speaks the Messages API natively - tools, images, streaming and extended thinking translated both ways - and picks the dialect automatically for Anthropic endpoints.
- Conversation state without extra infrastructure. The Responses API keeps
previous_response_idstate in the platform database, so a follow-up turn on another replica or after a restart continues the conversation. - Financial control plane. Every metered request carries both sides of its price - provider cost and customer charge - under a versioned price book with markup, tier, promo and minimum-charge rules; workspaces pay by subscription, prepaid wallet or invoice; operators get provider finance (reconciliation, settlement), margin analytics, a Finance console page and two new operator roles for money and providers. Wallet settlement is idempotent, and intentional zero charges stay zero.
- Marketplace installs are routing candidates, and they run. Everything a workspace installs joins its routing pool; agents and tools with a public endpoint execute for real, installed model cards run once mapped to a provider, and plans run sequentially or in parallel on request. Other workspaces never see a workspace's installs.
- An owner can delete an organization. From the workspace page, members, keys, tenants, usage and the subscription end at once, every member's session moves to their personal workspace, and the deletion is audited.
- Lifecycle e-mail, done politely. Trial-ending notices, one upgrade offer to free workspaces the product has already worked for, and release news - each sent at most once per workspace, opt-outs honoured, recipients always people who signed up here.
- Activation is measured and acted on. Operators see the signup-to-value funnel per acquisition source and the workspaces stuck before their first request, and can send a one-time getting-started reminder, manually or automatically a day after signup.
Changed
- The home page shows the products as they really are. A Products section presents the browser extension (live, quoting real drafts), the desktop command bar, the playground, dashboard and traces, the MCP server, the SDKs and the marketplace, every figure read live from the deployment; nothing is a mock-up. The hero, code sections and industry examples were rebuilt to fit every screen without sideways scroll.
- Vendors' own marks everywhere. Install buttons and browser cards use the browsers' official logos, chat-site chips carry their marks, and the Linux tab shows Tux.
- The brand mark follows the surface. Every surface - site, dashboard, extension, documents - draws the positive or reverse mark according to what it stands on, in both themes, and the favicon keeps an edge on dark tab strips.
- Key figures show their movement. Stat cards across the dashboard and console carry sparklines and period-over-period trends computed the same way everywhere; nothing on the web app renders below the readable floor, and long description lines are capped at a readable measure.
- Browser extension: one design system. Every surface shares the same tokens, icons and controls; the popup is a status dashboard; Settings is a real settings app with sticky sections; signed out, the card shows the on-device checks and a Connect prompt instead of a model list you do not own.
- Every version shown on the site comes from the running platform. A cached page can no longer show a stale version.
Fixed
- A provider connected seconds ago answers the first chat. The OpenAI-compatible endpoints re-check the workspace's providers before answering "no provider is configured", so a freshly connected provider works immediately.
- Requests with no recognisable verb route correctly. "Convert 5 miles to kilometers" reaches the calculator and "my account is locked" the support agent instead of a general model; measured routing accuracy on the labelled example set rose from 0.879 to 0.970, and the bundled routing model was retrained on the corrected data.
- Browser extension: no spinner that never ends. Every analysis request times out and clears the "Reading your draft…" placeholder, and the widget finds the field that already had focus when the page loaded.
- TypeScript SDK works in browsers and workers. Calls from a page, service worker or extension no longer fail with
Illegal invocation. - The platform's own writers route with a crew. The blog and growth writers compose a persona, skills and the model per assignment, grade every run so the learners see the platform's own traffic, and salvage an article a small model cut short instead of falling back to an excerpt.
- Metering is exactly-once and bounds are real. Every usage row is idempotent, so a replay after a failure is one financial effect, never two; the output allowance a request is priced at is enforced on the provider call itself; per-call priced targets reserve their real price; and a paid-for request whose usage row cannot be written immediately is journalled and replayed, so the customer always gets the answer and the books always get the row.
- Spending admission is a bound, not a guess. Before a costed call runs, the dearest admissible quote is held against budgets and wallet; a one-cent wallet no longer admits a two-dollar call, concurrent requests cannot jointly overspend, and long streams renew their hold while they run. Repricing honours the tariff that was in force at the time of the request.
- Learning is consistent across replicas. With shared state configured, every replica learns into the shared learner state and adopts what the others learned, so feedback given anywhere changes routing everywhere.
- Empty answers no longer count as successes. A model that spends its whole budget thinking and returns no text is recorded as a failure and the next candidate takes the request; a fallback re-route keeps the plan (persona and skills) of the original decision; and agent results that report only a token total are metered by it.
- Streaming holds nothing back it should not. The output guard's streaming mode screens tokens with bounded memory and delay, so a key split across chunks never leaves while long answers flow freely.
- Faster under concurrency. Writes no longer queue behind a process-wide lock; under concurrent load the routing endpoint's p95 dropped from 1.8 s to 0.5 s at 2.6× the throughput.
- Yearly plans with overage check out correctly. The pricing page's annual choice survives signup, and the billing portal works out of the box.
- Event-driven requests route. A request with an event or workflow context and no prompt text is routable, as the SDK always allowed.
- Reasoning is visible, not lost. Thinking models' reasoning is kept on the response, so an answer cut short by its token budget is explainable.
osr/auto:*presets work on the hosted platform. They behave exactly as on the self-hosted server.
Security
- The operator console session is no longer readable by scripts. It moved into an HttpOnly cookie scoped to the admin API, closing a browser-credential risk.
1.3.0 - 2026-09-13
Added
- Terms of service and privacy notice acceptance. Every published version of the terms and the privacy notice is recorded with its effective date. Sign-up asks for agreement; people arriving through SSO or an invitation are asked on first sign-in and again when a new version takes effect; Account › Agreements shows what was accepted and when. Operators publish a version with a summary and a notice period, and publishing notifies every user.
- A trained routing model ships inside the package. Load it with
RouterSLM.bundled(), or passbundledanywhere a model file is accepted, and an on-prem or air-gapped install routes with a calibrated, pre-trained model before it has seen a single request. Self-improvement starts warm from it, fine-tuning on your own rows is one command, and the served model's status is always reportable. - Anthropic Messages API on both proxies.
POST /v1/messagesspeaks the surface of the Anthropic SDKs and the agent frameworks built on them - blocks, tools, streaming events and token counting included - over the same routed path, metering and fallbacks as chat completions. - Moderation endpoint.
POST /v1/moderationsscreens prompts with the router's own guards - prompt injection, steering, personal data, oversize - in the OpenAI moderation shape, without any provider call. - Per-target and per-key limits. A catalogue target may declare its own rate limit, budget and circuit breaker; an exhausted target is skipped before scoring and traffic spills to the next candidate. On the platform, API keys accept daily and monthly budgets, a per-minute rate and a target allow list.
- Output guard. Every model and agent answer can be screened for leaked secrets, personal data and instruction injection, then flagged in the trace, redacted or blocked, as the deployment setting says.
- Weighted spread across interchangeable deployments. Candidates that share a family split load in a declared ratio, so two regions or two provider keys share traffic while health checks keep removing saturated members.
- Compliance posture and evidence report. Governance grades the workspace's posture - guards, audit, budgets, key hygiene, SSO, retention - most severe first, with the page that fixes each finding, and offers a downloadable evidence bundle for reviewers.
- Trace tooling.
osr trace <request_id>prints the span tree of one request. The dashboard trace gained a "what crossed the boundary" stage, a JSON download and a shareable link. - Growth on autopilot. The platform writes documentation-grounded guides for uncovered search terms through its own router, submits new pages for indexing, tracks signups per source, and can create and pace search campaigns under a daily budget. All of it can be inspected and controlled from the console.
- Self-hosted server hardening without Python. Every production control - guard, PII redaction, health breakers, audit chain, origin policy, resource limits, external learner state - is a serve flag with an environment-variable twin, so the container and the Helm chart run hardened by configuration alone.
- OpenAI Responses API on both proxies. Requests are translated to the routed chat path, with typed streaming events.
- Speech, transcription and image generation on the self-hosted server. One OpenAI-compatible endpoint serves them next to chat.
- MCP client parity. Remote MCP servers connect over Streamable HTTP; a server's resources become read-only tools and its prompts become skills.
- SSO group-to-role mapping. Organization connections can map directory groups to workspace roles, applied at every sign-in, so promotions and demotions follow the directory.
- The TypeScript SDK covers the whole platform surface. It is typed from the API's OpenAPI document and includes Responses, audio and images.
- Scoped, expiring API keys. A key can be limited to the read, route, execute, feedback and manage scopes and given an expiry; a call outside the key's scopes is refused before anything is metered.
- Support, sales and service levels, end to end. Every plan states a measured service level - support first-answer time, and uptime on Enterprise - that the platform reports against your own records. Talk to sales is a tracked inquiry with a reference; support tickets, the assistant and live ticket updates round out the loop.
- Every marketplace listing kind has an automated public source. From agent and prompt conventions across public repositories to model cards and generated routing stacks, each listing is attributed to its source with licence and provenance.
- E-mail, end to end. Microsoft 365 joins the transports; every template is branded, with a plain-text alternative; each person has e-mail preferences with one-click unsubscribe on every optional message; daily usage digests arrive; and operators can inspect categories, opt-outs and each person's mail.
- Operator visibility. Billing administration (subscriptions, overage, webhook events, per-workspace sync), personal-to-organization conversion in place, tenant budgets with bars, plan entitlements as a feature-by-feature list, and custom quotas and retention per enterprise workspace.
Changed
- The documentation site got a design pass. A wider shell, icons in the sidebar, meta rows with reading time, card-style tables and dark code panes in both themes; LaTeX and Mermaid render properly everywhere.
- A read-only server token cannot spend. Execution paths on the self-hosted server refuse read-only tokens.
- Plan features are enforced consistently. That includes custom plan overrides that drop a feature.
Fixed
- The routing model trains faster and reports fairly. The attention encoder trains an order of magnitude faster and its accuracy caught up on real corpora. The ensemble hears the model at its calibrated probability, gated by how familiar the prompt is, so a model trained mostly on synthetic rows no longer overrules the ensemble on prompts it has never seen.
- The hosted routing model learns from real traffic. Routed prompts and their outcomes survive deploys, decisions themselves become training evidence, and per-workspace models train on their own workspace's traffic only.
- Feedback cannot be forged. An outcome must reference a request the same workspace actually routed.
- Dark theme, everywhere. The mark, vendor logos, charts and the remaining light-only surfaces follow the theme; the favicon is the brand mark and keeps its edge on a dark tab strip.
- When every candidate fails, you see the real outage. The answer is a 503, or a 429 with
Retry-After, instead of whichever low-ranked candidate happened to fail last. - The daily marketplace harvest is resilient. An interrupted run resumes promptly and publishes as it goes, and a stale lease can no longer stall it for days.
- Kafka-backed deployments start in any order. A broker that is not up yet no longer crash-loops the services; events are dropped and the connection retried instead.
- Blank prompts are refused. An empty prompt is rejected instead of being routed.
- Revoked keys and edition gates answer with the right status. Revoked keys answer 404 on revocation, and edition gates answer 403 with the edition named, so clients can tell "not included" from "wrong URL".
1.2.0 - 2026-09-10
Added
- A four-tier pricing ladder with monthly quotas, overage, trials and annual billing. Free includes feedback and bring-your-own-keys; Pro and Team add quota, seats, tenants and statistics; Enterprise comes through sales. Quota state is visible everywhere -
GET /api/v1/quota, the dashboard, and warning alerts at 80% - and requests beyond the quota keep flowing on a live subscription as metered overage. - Prompt compaction before every model call. Whitespace, zero-width characters and repeated lines are collapsed (code blocks are kept byte-for-byte), conversation history is trimmed to a budget, and the saving is reported per request.
- Plans recommend tools next to the model. A plan carries the tools that fit the request; the model receives them as function specs, the platform runs the calls, and every called tool is credited with its own outcome.
- The router follows the marketplace by itself. Followed listings are kept in sync into the registry on a schedule, on the self-hosted server and through the local MCP server, so an IDE can find a skill and route to it in one conversation.
- The self-improvement loop reads articles. Vendor blogs and research feeds inform each improvement cycle: mentioned models are looked up, new cards join the candidates, and the evidence still decides.
- Region pinning. Workspaces are pinned to the stack that created them and refused elsewhere with a clear error; every authenticated response names the region.
- Public leaderboards by task type and kind. Ranked by verified outcomes with provisional rows marked, plus a marketplace leaderboard, all aggregated and anonymised.
- Implicit feedback. When a handler reports no quality, the answer is judged against the request - refusals, empty or truncated answers, a coding request answered without code - and the next turn of a session (a complaint, a retry, thanks) becomes feedback on the previous one.
- Managed-services deployment option. Self-hosters can run the platform against managed PostgreSQL, Redis and an Event Hubs-compatible broker instead of the bundled containers, with authenticated brokers supported throughout.
- TypeScript client SDK.
@opensmartroute/sdkis zero-dependency and typed, with streaming chat. - A stronger evaluation harness. Paired held-out baseline comparisons now come with confidence intervals.
Fixed
- Token estimates match the bill. The estimator over-counted prose by up to 78%. Recalibrated against billed provider tokens across twelve text types, it now lands within a few percent on average, so quotes and savings are real-sized numbers.
- Every page fits a phone. Sixty-seven pages were measured at six widths and every sideways scroll fixed; a check keeps it that way.
- Pages stop waiting on the API. Navigation paints immediately with progress and skeletons, public reads are served stale-while-revalidate and shared between replicas, and heavy pages send a fraction of the data - a cold catalogue page went from seconds to instant.
- No more leaked database connections. Idle and orphaned connections are closed promptly, so a busy day can no longer exhaust the database's connection slots.
Security
- The analytics tag no longer receives copied text or URL secrets. Copy events report only a kind, page views use a sanitised location, and the tag is off in the dashboard and console. If you copied an API key from the site before this change, rotate it.
1.1.0 - 2026-09-07
Added
- Bring your own model providers, per workspace. Connect your own Azure OpenAI, Bedrock, Vertex, OpenAI, Anthropic, Mistral, Groq, xAI, Cohere, OpenRouter, Ollama, vLLM or any OpenAI-compatible endpoint; check it; map catalogue targets to its models. Your requests then execute on your endpoint with your key. Keys are encrypted at rest and never returned, and every change is audited.
- Self-hosted open models on the platform deployment. The deployment can run its own model server with a curated set of small open weights for the private and specialist targets, on CPU or GPU; the same set is available to the compose stacks.
- OpenAI-compatible parity on the self-hosted server. True token-by-token streaming, tool calling, structured output, multi-part content, embeddings, candidate lists with automatic fallback, async handlers and read-only or expiring access tokens.
- Routing to humans executes for real. A decision that lands on a human target queues a ticket, the dashboard's Human queue lets a teammate answer it, and the resolution feeds the learners - deferral itself is learned.
- Traces explain themselves. The ranking records every strategy's vote and rationale for the top candidates, and the trace and the playground tell the decision in plain language: who was allowed, how candidates ranked, why the winner won, what it cost and what was saved.
- The model leaderboard refreshes from public benchmark sources. It is refreshed several times a day and merged into the model catalogue, with rank movement over time.
- A blog written through the router. Curated feeds become posts written by the platform's own routed models, with a daily digest for confirmed readers and a full archive; every post carries the routing decision that wrote it.
- The platform observes itself. Spans and events persist in the platform's own store. Traffic series, latency percentiles and alert rules - budgets, failures, readiness, drift - are evaluated in-process and delivered to e-mail, webhook, Slack and Teams channels, with severity filters and delivery history.
- Operator console, grown up. Deployment analytics, activity across workspaces, global search, settings with every effective value, health with breaker states, marketplace moderation, plans, leads, directory administration with bulk actions and CSV exports, audit filters and outbox administration. Operators can also open any workspace's dashboard in an audited, time-boxed session.
- Quotes and recommendations before you spend.
osr estimateandPOST /api/v1/estimateprice every candidate for a request - recommended, cheapest, best quality, fastest - and an MCP server exposes route, estimate, recommend, explain and feedback to IDEs and agent hosts. - Marketplace and declarative stacks. One YAML document holds targets, rules, settings and imports; the hosted marketplace serves templates, agents, skills, personas, tools and prompts with versions, reviews, installs and moderation.
- Documentation as a real site. The docs render as a static site with search, a generated REST API reference, task-shaped quickstarts and a version menu, with machine-readable Markdown for every page.
- Sign in your way. Password accounts with recovery and e-mail confirmation, SSO presets, organization SSO with domain discovery, CLI sign-in via device grant and native installers for the CLI - plus self-service account deletion, key rotation and full data export.
Fixed
- Split deployments report one truth. The audit chain verifies across services, every service persists its spans, and the human hand-off queue is reachable behind the gateway.
- Mail is delivered at least once, with bounded retries. A malformed transport configuration disables mail and shows the reason instead of crashing the platform, and delivery state is visible to operators.
- The rate limiter and event pipeline degrade gracefully. A hiccup in shared infrastructure costs moments, not requests.
- Streaming is real streaming. The first token arrives when the provider sends it, not when the answer is complete.
Security
- Client addresses cannot be spoofed. Rate limits and audit records now use the first untrusted hop of the forwarding chain, not a header any client could write.
1.0.0 - 2026-09-07
1.0 freezes the public API: every exported name is stable from here, and removals go through a deprecation for at least one minor release first.
Added
- Operator accounts. Operators sign in with username and password, superadmins manage operators, and every operator action is audited. Workspace users can also sign in with e-mail and password.
- Self-hosted cluster topology. The platform runs on PostgreSQL with shared rate limits and learner state and an event broker between replicas. A single Compose file runs the whole platform - API, web, database, cache, broker and an optional local model server - on any Docker host.
- The routing model runs as its own service. It trains on the platform's feedback on a schedule and promotes only challengers that beat the champion; replicas pick up promotions automatically.
- A development stack with live reload. Self-hosters and contributors can run the platform with live reload.
Changed
- Marketing and documentation honesty pass. The editions matrix, showcase figures and operator pages say only what the code does.
0.5.0 - 2026-09-06
Added
- Published benchmark results and the recipe to reproduce them. Alongside them, an external security review pack with system boundaries, threat model and evidence.
- The marketplace imports the public skills ecosystem. Published skills, agent cards and MCP servers arrive with provenance, licences and source links, refreshed on a schedule, and browsing stays fast at 100k+ listings. Imported content is screened: credential-shaped strings are redacted and attack corpora are rejected.
- Effort routing and agentic task routing, measured. Think-versus-no-think routing spends 62% of the always-think tokens at equal quality; progress-guided task routing beats the best single agent at less than half its latency. Both are reproducible from the shipped evaluation harness.
- Account lifecycle end to end. Signup with recovery, e-mail confirmation, invitations by mail, self-service deletion, an account audit trail and outbound e-mail with an operator-visible outbox.
- CLI installers and platform sign-in. One-line installers for every OS, device-grant sign-in, profiles for several deployments, and token-protected self-hosted servers.
- Quotes, MCP and the estimate page. Price a request before sending it, from the CLI, the API, the MCP server or the site.
- Declarative stacks and the hosted marketplace. The marketplace comes with publishing, moderation, reviews and installs.
- Tracing and observability throughout the SDK. Every stage of a request reports to a tracer with bounded, text-free attributes; metrics export in Prometheus format; traces and events are browsable in the dashboard with a span waterfall and a plain-language routing story.
- Governance. Workspace policy with budgets, per-tenant constraints and spend attribution, a one-payload governance posture, and retention sweeps.
- Routing SLM, autopilot and datasets. Train a compact routing model on public preference datasets or your own feedback, let the autopilot retrain and promote it on drift, and load it anywhere with one flag.
- Web analytics with consent. Consent Mode v2, denied by default, plus canonical SEO metadata, generated social cards, vendor hubs, comparison pages and machine-readable exports for AI assistants.
Changed
- The site got its editorial redesign. Light and typographic, with live data everywhere and restrained motion that honours reduced-motion preferences.
0.4.0 - 2026-09-04
Added
- Execution and plans.
Router.run()routes and executes: skills pre-process, persona and skill instructions compose into the system prompt, the primary answers, and every participant's outcome is learned from. Targets gained instructions, effort variants and families; requests gained profiles and history. - Learning depth. Task tables with confidence intervals, learning-to-defer to humans, think-versus-no-think effort decisions, progress-guided multi-round execution, cascade planning, task-level credit assignment, calibration (temperature, isotonic, conformal candidate sets) and forgetting in the preference models.
- Catalogue interop at scale. Retrieve-then-rank for large catalogues; MCP tools with signed manifests; A2A agent cards; LangGraph, Agent Framework and OpenAI function-calling adapters; personas from Markdown and editor conventions; agent harnesses (callable, HTTP, subprocess); SKILL.md loading; and an OpenAI-compatible proxy on the built-in server.
- Evaluation. Baselines with an oracle and noise floor, robustness (paraphrase, repeat-flip, fairness), cost-quality frontiers with ablations, off-policy estimates, dataset presets and a minimum-accuracy gate for your own build.
- Enterprise stores and operations. Redis, SQL, versioned, encrypted and batched state stores; shadow routing and A/B tests with sequential verdicts; fair-share scheduling; queue-aware routing.
- Security. A learned gadget detector, injection risk scoring, per-task resource limits, tool-parameter provenance, and a red-team routing suite with a gate you can run from the CLI.
- A frozen public API surface. The exported API is snapshotted, so adding or removing a public name is always a deliberate, reviewed act - the foundation of the 1.0 stability promise.
Fixed
- Files always read as UTF-8. Windows locales no longer fail on the shipped examples.
0.3.0 - 2026-09-04
Added
- Provider adapters. A dependency-free OpenAI-compatible client with retries and typed errors, with glue for judges, embedders and chat handlers.
- Typed configuration loading. Every error names the file, the entry and the reason.
- The brand identity and a reproducible latency benchmark. Both ship with this release.
Fixed
- Health checks no longer consume rate-limit tokens for every candidate. Only the chosen target reserves one.
- HTTP feedback carries complexity. The ability model can now learn from it.
0.2.0 - 2026-09-04
Added
- The mathematical core. Bandits (Thompson, UCB, LinUCB), item-response ability, Bradley-Terry and Elo preferences, Markov decision models, drift detection, confidence intervals, Pareto / TOPSIS and queueing estimates - all dependency-free.
- Learning strategies and auto-learning. With drift detection and atomic persistence.
- Real-time protection. Circuit breakers, rate limits, rolling budgets and health-aware scoring.
- The enterprise builder. Middleware (cache, tenant, timeout), telemetry, state stores and a hash-chained audit sink.
- Security primitives. Input guard, PII redactor, prompt sanitisation and secret loading.
- Async support, typed errors, pinned rules and plan-only targets. All four arrive in this release.
Changed
- Whole-word lexicon matching. No more
sqlinsideaustralia; cost and latency normalisation is log-scaled, and no-route errors say more.
0.1.0 - 2026-09-04
Added
- Initial release. Core types, registry, signals, policy, the rules / capability / similarity / bandit / judge / cascade strategies, the router with plans, feedback, the evaluation harness, the CLI and the HTTP server.
Something wrong or out of date on this page? Tell us - the page is named for you, so a one-line note is enough.
osr-security-hardening
Harden OpenSmartRoute deployments against prompt injection, gadget/steering attacks, PII leakage, runaway agents and untrusted tool arguments.
Versions and channels
One version for every artifact, stable releases and developer previews, and how to read the build a deployment runs.