Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
fb23cfc
docs(docker): clarify latest tracks published stable SemVer
RaviTharuma Aug 20, 2026
a352c23
fix(chatgpt-web): refresh current model catalog (#10637)
backryun Aug 20, 2026
5e50814
perf(electron): defer hidden-start renderer creation (#10327)
backryun Aug 20, 2026
8122f6b
perf(electron): optionally unload renderer on close (4/8) (#10328)
backryun Aug 20, 2026
80a59c0
fix(images): route bare dall-e-3 to OpenAI (#10847)
RaviTharuma Aug 20, 2026
84d7e33
feat(resilience): warn on slow /healthz event-loop lag (#10827)
RaviTharuma Aug 20, 2026
7ac6bbb
docs(backend): document memory/skills/token-refresh event-loop cost (…
RaviTharuma Aug 20, 2026
6767f27
docs(db): document throttled pre-write SQLite backups (#10824)
RaviTharuma Aug 20, 2026
8b52596
docs(auth): distinguish access tokens, API keys, and management crede…
RaviTharuma Aug 20, 2026
6f08a08
feat(speech): accept response_format=ogg as an opus alias (#10822)
RaviTharuma Aug 20, 2026
77d7502
fix(opencode-plugin): keep bare combo ids unprefixed (#10821)
RaviTharuma Aug 20, 2026
2f73158
fix(auto): log empty auto-family pools once per process (#10820)
RaviTharuma Aug 20, 2026
56b9d00
fix(docker): warn when OMNIROUTE_MEMORY_MB disagrees with NODE_OPTION…
RaviTharuma Aug 20, 2026
7c6bf32
docs(docker): document SQLite single-replica HA limits (#10817)
RaviTharuma Aug 20, 2026
9eddaff
fix(admission): reserve Responses and Messages bodies before clone (#…
RaviTharuma Aug 20, 2026
9d2240e
fix(search): name /v1/search 502 provider and cause (#10756)
RaviTharuma Aug 20, 2026
2acafd9
feat(api): add GET /livez as a process-alive probe (#10819)
RaviTharuma Aug 20, 2026
0918829
Merge commit 'refs/pull/10816/head' of https://github.com/diegosouzap…
hartmark Aug 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions @omniroute/opencode-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1294,10 +1294,15 @@ export function mapRawModelToModelV2(
// `(providerID, modelID)`. If the raw id is already provider-prefixed
// (e.g. `cc/claude-opus-4-7` from the `cc` Claude Code alias, or
// `nvidia/llama-3-70b` from a provider that ships prefixed ids), leave
// it as-is — double-prefixing breaks OC's lookup. Otherwise prefix with
// the resolved `providerId` so a bare key like `claude-opus-4` parses as
// `(omniroute, claude-opus-4)` and the credentials resolve correctly.
id: raw.id.includes("/") ? raw.id : `${ctx.providerId}/${raw.id}`,
// it as-is — double-prefixing breaks OC's lookup. Bare **combo** ids
// (`owned_by: "combo"`, e.g. `gpt-5.6-sol`) must also stay unprefixed:
// OpenCode looks up `-m <plugin>/<combo>` as model id `<combo>` under
// the plugin provider (#10345). Other bare ids still prefix with
// `providerId` so credentials resolve as `(omniroute, model)`.
id:
raw.id.includes("/") || raw.owned_by === "combo"
? raw.id
: `${ctx.providerId}/${raw.id}`,
/**
* Display name. Falls back to raw.id when no enrichment is available;
* the caller (`createOmniRouteProviderHook`) overlays
Expand Down
34 changes: 34 additions & 0 deletions @omniroute/opencode-plugin/tests/bare-combo-ids-10345.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import test from "node:test";
import assert from "node:assert/strict";

import { mapRawModelToModelV2 } from "../src/index.ts";

test("mapRawModelToModelV2: bare combo ids stay unprefixed (#10345)", () => {
const combo = mapRawModelToModelV2(
{
id: "gpt-5.6-sol",
owned_by: "combo",
context_length: 272000,
max_output_tokens: 8192,
},
{ providerId: "omniroute", baseURL: "https://or.example.com/v1" }
);
assert.equal(combo.id, "gpt-5.6-sol");
assert.equal(combo.providerID, "omniroute");

const slashed = mapRawModelToModelV2(
{
id: "cx/gpt-5.6-sol",
owned_by: "combo",
context_length: 272000,
},
{ providerId: "omniroute", baseURL: "https://or.example.com/v1" }
);
assert.equal(slashed.id, "cx/gpt-5.6-sol");

const ordinary = mapRawModelToModelV2(
{ id: "claude-primary", context_length: 200000 },
{ providerId: "omniroute", baseURL: "https://or.example.com/v1" }
);
assert.equal(ordinary.id, "omniroute/claude-primary");
});
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,8 @@ docker run -d --name omniroute --restart unless-stopped --stop-timeout 40 \
-p 127.0.0.1:20128:20128 -v omniroute-data:/app/data diegosouzapw/omniroute:latest
```

`:latest` follows the highest **published** stable SemVer. It does not track git `main`. Pin `:X.Y.Z` for GitOps. See [Docker Release Channels](docs/guides/DOCKER_GUIDE.md#release-channels).

> **Pre-release Docker channel:** `diegosouzapw/omniroute:next` and
> `diegosouzapw/omniroute:next-web` follow the current default `release/v*`
> branch. These mutable tags are intended only for testing unreleased fixes and
Expand Down
1 change: 1 addition & 0 deletions changelog.d/features/10303-healthz-event-loop-lag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **feat(resilience):** warn when `/healthz` is served under event-loop lag ≥200ms so a slow 200 is visible as sick, not healthy ([#10303](https://github.com/diegosouzapw/OmniRoute/issues/10303))
1 change: 1 addition & 0 deletions changelog.d/features/10316-livez-endpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **feat(docker):** add `GET`/`HEAD` `/livez` as a process-alive probe, distinct from `/healthz` readiness ([#10316](https://github.com/diegosouzapw/OmniRoute/issues/10316))
1 change: 1 addition & 0 deletions changelog.d/features/10587-ogg-speech-alias.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **feat(providers):** accept `response_format=ogg` on `/v1/audio/speech` as an alias for the existing Opus/Ogg encoder ([#10587](https://github.com/diegosouzapw/OmniRoute/issues/10587))
1 change: 1 addition & 0 deletions changelog.d/fixes/10345-bare-combo-opencode-ids.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(opencode-plugin):** publish bare combo model ids without the plugin provider prefix so OpenCode can select them ([#10345](https://github.com/diegosouzapw/OmniRoute/issues/10345))
1 change: 1 addition & 0 deletions changelog.d/fixes/10346-empty-pool-warn-once.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(backend):** log `auto/<family> matched no connected models` once per process per label instead of every minute ([#10346](https://github.com/diegosouzapw/OmniRoute/issues/10346))
1 change: 1 addition & 0 deletions changelog.d/fixes/10353-memory-heap-conflict-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(docker):** warn at boot when `OMNIROUTE_MEMORY_MB` disagrees with `NODE_OPTIONS --max-old-space-size`, and document that the standalone/Docker launcher appends `OMNIROUTE_MEMORY_MB` last ([#10353](https://github.com/diegosouzapw/OmniRoute/issues/10353))
1 change: 1 addition & 0 deletions changelog.d/fixes/10735-search-provider-named-errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(search):** name `/v1/search` 502s with provider id and sanitized Node cause code, without hostnames ([#10735](https://github.com/diegosouzapw/OmniRoute/issues/10735))
1 change: 1 addition & 0 deletions changelog.d/fixes/10832-unprefixed-dalle3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(images):** register OpenAI `dall-e-3` in the image registry so unprefixed `dall-e-3` (and `openai/dall-e-3`) route to OpenAI Images instead of Microsoft Designer Web, and so the chat catalog no longer lists `openai/dall-e-3` as a 128k chat model ([#10832](https://github.com/diegosouzapw/OmniRoute/issues/10832))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **docs(docker):** spell out that `:latest` tracks the highest **published** stable SemVer (not git `main`), and that GitOps should pin `X.Y.Z` ([#10317](https://github.com/diegosouzapw/OmniRoute/issues/10317))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **docs(backend):** document that memory extraction, skills injection, and token refresh share the request event loop, plus dashboard kill switches ([#10349](https://github.com/diegosouzapw/OmniRoute/issues/10349))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **docs(docker):** document default SQLite as single-replica / HA-unsupported, including Recreate and HEALTHCHECK session blast radius ([#10350](https://github.com/diegosouzapw/OmniRoute/issues/10350))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **docs(backend):** document that pre-write SQLite backups (including models.dev pricing) are throttled to once per 60 minutes and can be disabled with `DISABLE_SQLITE_AUTO_BACKUP` ([#10351](https://github.com/diegosouzapw/OmniRoute/issues/10351))
1 change: 1 addition & 0 deletions changelog.d/maintenance/7786-management-auth-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **docs(auth):** distinguish dashboard sessions, `oma_live_…` Access Tokens, manage-scoped API keys, and inference keys ([#7786](https://github.com/diegosouzapw/OmniRoute/issues/7786))
2 changes: 2 additions & 0 deletions docs/getting-started/QUICK-START.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ npm install -g omniroute
docker run -d --name omniroute -p 20128:20128 diegosouzapw/omniroute:latest
```

`:latest` is the highest **published** stable SemVer. It does **not** track git `main`. Pin `diegosouzapw/omniroute:X.Y.Z` for GitOps. See [Image Tags / Release Channels](../guides/DOCKER_GUIDE.md#release-channels).

### Option C: From Source

```bash
Expand Down
48 changes: 41 additions & 7 deletions docs/guides/DOCKER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ lastUpdated: 2026-06-28
- [Docker Compose with Caddy (HTTPS)](#docker-compose-with-caddy-https-auto-tls)
- [Cloudflare Quick Tunnel](#cloudflare-quick-tunnel)
- [Image Tags](#image-tags)
- [Availability: default SQLite is single-replica](#availability-default-sqlite-is-single-replica)
- [Important Notes](#important-notes)

---
Expand Down Expand Up @@ -341,13 +342,15 @@ For orchestrators (Kubernetes, Nomad, etc.):

| Probe | Prefer | Avoid |
| --- | --- | --- |
| Liveness | TCP on the main port (`PORT`, default `20128`), or soft HTTP `/healthz` | `/api/monitoring/health` as liveness |
| Liveness | HTTP `GET /livez`, or TCP on the main port (`PORT`, default `20128`) | `/api/monitoring/health` as liveness |
| Readiness | HTTP `GET /healthz` | Tight timeouts that treat event-loop busy as dead |
| Deep / blackbox | `/api/monitoring/health` | — |

`/healthz` only reports process lifecycle (`ok` / `starting` / `stopping`). It still
runs on the same Node event loop as request handling, so CPU-bound catalog or
compression work can delay it — busy ≠ dead. Full probe guidance:
`/healthz` reports process lifecycle (`ok` / `starting` / `stopping`). `/livez` is
process-alive only (200 whenever the handler can run; it does not wait for
readiness). Both still run on the same Node event loop as request handling, so
CPU-bound catalog or compression work can delay them — busy ≠ dead. Prefer TCP
liveness if HTTP probes time out. Full probe guidance:
[Monitoring guide — Kubernetes probe recommendations](../ops/MONITORING_GUIDE.md#kubernetes-probe-recommendations).

## Docker Compose with Caddy (HTTPS Auto-TLS)
Expand Down Expand Up @@ -409,8 +412,8 @@ Endpoint tunnel panels (Cloudflare, Tailscale, ngrok) can be shown or hidden fro

| Image | Tag | Size | Description |
| ------------------------ | -------- | ------ | --------------------- |
| `diegosouzapw/omniroute` | `latest` | ~250MB | Latest stable release |
| `diegosouzapw/omniroute` | `3.8.0` | ~250MB | Current version |
| `diegosouzapw/omniroute` | `latest` | ~250MB | Highest **published** stable SemVer (not git `main`) |
| `diegosouzapw/omniroute` | `3.8.0` | ~250MB | Pin this class of tag for GitOps |

Multi-platform manifest: `linux/amd64` + `linux/arm64` native (Apple Silicon, AWS Graviton, Raspberry Pi). Docker selects the matching architecture automatically; pass `--platform linux/amd64` if you need to force AMD64 emulation on ARM hosts.

Expand All @@ -421,7 +424,7 @@ OmniRoute publishes separate Docker channels for stable releases, active release
| Channel | Source | Mutability | Recommended use |
| ------------------------------- | ----------------------------------- | --------------------------- | ----------------------------------------------------------------------------------------------- |
| `:<version>` / `:<version>-web` | Signed/versioned release | Immutable | Production deployments that pin an exact release |
| `:latest` / `:latest-web` | Highest stable release | Mutable stable pointer | Production deployments that intentionally follow stable releases |
| `:latest` / `:latest-web` | Highest **published** stable SemVer | Mutable stable pointer | Follows stable releases **after** a SemVer publish job — does **not** track `main` or unreleased `release/v*` commits |
| `:next` / `:next-web` | Current default `release/v*` branch | Mutable pre-release pointer | Testing fixes that have landed on the active release branch but are not yet in a stable release |
| `:main` / `:main-web` | `main` branch | Mutable development pointer | Development and integration testing only |

Expand Down Expand Up @@ -465,6 +468,37 @@ docker compose up -d

A release-branch build can never move `latest`; only an eligible stable semantic version may promote the stable pointer. The `next` images retain the release image inspection and blocking CRITICAL-vulnerability gate.

**`latest` is not a currency guarantee for git.** Merged fixes on `main` or on the active `release/v*` branch are **not** in `:latest` until a stable SemVer image is published and the publish job promotes `:latest` (same digest as that SemVer). If `latest` looks frozen while GitHub already shows the fix, pull `:next` to test the release branch or wait for the SemVer tag.

| You want | Use |
| --- | --- |
| GitOps / production that must not drift | Pin `:X.Y.Z` (or the image digest) |
| Follow published stables and accept a recreate on each release | `:latest` |
| Test unreleased `release/v*` commits | `:next` (not production) |
| Test `main` | `:main` (not production) |

## Availability: default SQLite is single-replica

Stock Docker / Kubernetes OmniRoute is **one Node process + one SQLite writer**. High availability is **not supported** on that topology.

| Constraint | Consequence |
| --- | --- |
| Single writer | Do **not** run multiple replicas against the same SQLite file. That corrupts the DB. |
| Recreate / restart / HEALTHCHECK kill | **Full outage** of in-flight SSE, dashboard sessions, and in-memory state. Every connected client drops. |
| Same event loop as `/healthz` | A busy catalog or compression tick can delay probes; a short timeout then restarts the **only** replica. |

**Probe matrix** (see also [Kubernetes probe recommendations](../ops/MONITORING_GUIDE.md#kubernetes-probe-recommendations)):

| Probe | Target | Do not use |
| --- | --- | --- |
| Liveness | TCP on `PORT` (default `20128`), or soft HTTP `/healthz` | `/api/monitoring/health` |
| Readiness | HTTP `GET /healthz` | Tight timeouts that treat event-loop busy as dead |
| Deep / humans | `/api/monitoring/health` | Automated kubelet liveness |

**Upgrades:** expect every session to drop. Drain clients if you can; there is no rolling update on default SQLite. Compose `restart: unless-stopped` plus Docker `HEALTHCHECK` will also replace the only process when the container is Unhealthy — same blast radius.

External Postgres / multi-writer HA is **not** a documented stock path. If you need HA, keep a single replica or run a topology the project has tested and documented separately.

## Important Notes

- **SQLite WAL Mode:** `docker stop` should be allowed to finish so OmniRoute can checkpoint the latest changes back into `storage.sqlite`. The bundled Compose files already set a 40s stop grace period. If you run the image directly, keep `--stop-timeout 40`.
Expand Down
Loading
Loading