Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
0a44295
fix(reasoning): preserve plaintext from mixed reasoning items (#10949)
jackjinke Aug 21, 2026
b8e4e88
fix(reasoning): drop incompatible continuation by default (#10959)
jackjinke Aug 21, 2026
2ab16d3
fix(cli): scoping android instrumentation-hook diagnosis to real plat…
diegosouzapw Aug 21, 2026
484cb6e
fix: add static model catalog for v0-vercel-web web-cookie provider (…
diegosouzapw Aug 21, 2026
861ac69
fix(providers): validate Dify keys against native /v1/chat-messages e…
diegosouzapw Aug 21, 2026
d61eec6
fix(dashboard): treat UncloseAI as a no-auth provider so the connect …
diegosouzapw Aug 21, 2026
a928fad
fix(command-code): surface reasoning-only output as content when no t…
diegosouzapw Aug 21, 2026
4e3e53e
fix(ssrf): honor local-first provider URL flag in outbound guard (#91…
diegosouzapw Aug 21, 2026
99111f3
fix(services): isolate probeBeforeSpawn adoption tests on distinct po…
diegosouzapw Aug 21, 2026
eb4fd74
fix(security): close remaining v3.8.50 advisories (batch 2 — 11 findi…
diegosouzapw Aug 21, 2026
9349af2
fix(quality): rebaseline file-size baseline for modelCapabilities.ts …
hartmark Aug 21, 2026
d01a4ae
fix(release): drain v3.8.50 base-reds — build-breaking import, stale …
diegosouzapw Aug 21, 2026
ae2de45
fix(sse): resolve OpencodeExecutor target format through the provider…
maxmad64bis Aug 21, 2026
02a6c3d
fix(sse): split concatenated tool_call arguments from same-name index…
maxmad64bis Aug 21, 2026
1c920eb
fix(webhooks): remove 3 declared-but-never-emitted ghost events (#11050)
maxmad64bis Aug 21, 2026
666e4aa
fix(providers): route Muse Spark to the Responses API on opencode-zen…
maxmad64bis Aug 21, 2026
c977536
refactor(providers): dedupe identical opencode-zen/opencode-go model …
maxmad64bis Aug 21, 2026
f968496
fix(gamification): validate leaderboard limit/offset before the SQLit…
pacocartones Aug 21, 2026
0ff0490
test(db): assert resetDbInstance swaps the singleton, WAL mode, and s…
pacocartones Aug 22, 2026
9b801b7
fix(dashboard): compute unique connection names from array to avoid o…
rqzbeh Aug 22, 2026
7e48be8
feat(dashboard): trigger key validation on Enter in AddApiKeyModal (#…
rqzbeh Aug 22, 2026
8643e0f
fix(cli): default limit.context to 128k when unknown in OpenCode conf…
rqzbeh Aug 22, 2026
7c39e95
fix(providers): update hailuo-web domain to chat.minimax.io (#11000) …
rqzbeh Aug 22, 2026
7ffa3ef
fix(quality): move #11050 changelog fragment to valid fixes/ section …
hartmark Aug 22, 2026
7ddbaf6
feat(cli): add native Bun backend support and Dockerfile.bun (#11039)
rqzbeh Aug 22, 2026
5a60a46
fix: deprecate blackbox provider since api.blackbox.ai returns 404 (#…
diegosouzapw Aug 22, 2026
e06f8b7
feat(api): flag a pinned account on /v1/combos steps without leaking …
ntdatt812 Aug 22, 2026
b6412c6
fix(command-code): use the documented /provider/v1 chat endpoint (#10…
diegosouzapw Aug 22, 2026
6cd4d38
fix(m365): BizChat invocation shape drift + HAR-import UX + Antigravi…
eenggar-svg Aug 22, 2026
0d86693
docs(reasoning): clarify mixed-state replay contract
jackjinke Aug 22, 2026
742ccb9
fix(ci): register oauth-autoimport-local-only test in stryker tap.tes…
hartmark Aug 22, 2026
9629693
fix(providers): filter Perplexity model import to the Sonar family (#…
diegosouzapw Aug 22, 2026
d91238b
fix(install): make ONNX chain optional for Android/Termux installs (#…
diegosouzapw Aug 22, 2026
da490a7
fix(sse): resume stream recovery after a completed tool call (#11109)
maxmad64bis Aug 22, 2026
d9b3ce2
test(stream): direct coverage + comment for splitConcatenatedToolCall…
maxmad64bis Aug 22, 2026
02a078e
fix(sse): default summary on freshly-built Chat->Responses reasoning …
maxmad64bis Aug 22, 2026
b44f22a
fix(webhooks): followup ghost-event dispatcher tests + vi i18n (#1105…
maxmad64bis Aug 22, 2026
efc7134
fix(registry): restore models[0] default + guards; note muse-spark ov…
maxmad64bis Aug 22, 2026
78b4082
fix(autopilot): show real suggestion count and link dashboard (#11102)
maxmad64bis Aug 22, 2026
d021423
fix(sse): default summary + strip malformed id on kept Responses inpu…
maxmad64bis Aug 22, 2026
f3b190b
fix(providers): reject silent validation degradation with 400 and rej…
maxmad64bis Aug 22, 2026
84c9dfd
fix(config-audit): persist config audit log to SQLite with retention …
maxmad64bis Aug 22, 2026
c89fc6b
feat(providers): let operators add per-provider error rules via setti…
maxmad64bis Aug 22, 2026
1dd0173
fix(sse): assign a stable index/id to parallel function_call items in…
maxmad64bis Aug 22, 2026
5631e91
fix(providers): learn reasoning_effort capability from upstream 4xx i…
maxmad64bis Aug 22, 2026
dae3a72
fix(i18n): translate providers.harImport* keys into Vietnamese (#1106…
hartmark Aug 22, 2026
a51b8ba
fix(cline): use valid modelType/model format for Cline provider model…
rqzbeh Aug 22, 2026
3157e8a
fix(providers): require API key for Pollinations and fix optional key…
rqzbeh Aug 22, 2026
9a67185
fix(cli): support OpenCode V2 config format in setup-opencode (#11070…
rqzbeh Aug 22, 2026
50fc0d7
fix(resilience): keep Ollama model-not-found failures scoped to conne…
rqzbeh Aug 22, 2026
4220c81
fix(resilience): include RFC1918, CGNAT, and mDNS hosts in isLocalPro…
rqzbeh Aug 22, 2026
367ae2f
fix(search): enforce blockedProviders setting on search endpoint (#11…
rqzbeh Aug 22, 2026
b2509bc
fix(release): drain v3.8.50 base-reds — getTokenLimit contract, vi i1…
diegosouzapw Aug 22, 2026
aa12873
fix(providers): remove Hack Club AI provider (#11118) (#11123)
rqzbeh Aug 22, 2026
56540f2
fix(api): save call logs and add endpoint fallback for local rerank p…
AndrianBalanescu Aug 22, 2026
80d931a
fix(logs): apply filter predicates to merged in-memory call-log rows …
AndrianBalanescu Aug 22, 2026
e15af18
fix(kimi): point kimi-web to international www.kimi.ai (#11045)
MeRezaRezaei Aug 22, 2026
7360ca4
feat(redis): add configurable key namespace prefix (#11042)
MeRezaRezaei Aug 22, 2026
445121f
docs: DEFAULT_RATE_LIMIT_PER_DAY unset is unlimited (#11031)
Prajeeth-12 Aug 22, 2026
c19c73f
fix(claude): restore canonical tool names so Claude Code accepts tool…
linhdmn Aug 22, 2026
5818cfb
docs(cli): update opencode.ts JSDoc to reflect 128k context fallback …
rqzbeh Aug 22, 2026
64b7389
fix(tests): update translate-path golden snapshot and docs for hailuo…
rqzbeh Aug 22, 2026
d3ac1a6
refactor(dashboard): mirror check button disable state in AddApiKeyMo…
rqzbeh Aug 22, 2026
ec6010f
fix(cli): resolve blank device code and undefined verification URL in…
rqzbeh Aug 22, 2026
805252a
feat(mcp): implement dynamic runtime tool schema plumbing for blocked…
rqzbeh Aug 22, 2026
7246e5a
fix(bun): update Dockerfile.bun entrypoint and native bun:sqlite inst…
rqzbeh Aug 22, 2026
de5e237
feat(ci): publish Bun container images (-bun and -web-bun) in Docker …
rqzbeh Aug 22, 2026
2edb7a1
fix(dashboard): keep the provider registry out of node:net (#11122) (…
yourspraveen Aug 22, 2026
ce66d31
fix(quality): drain v3.8.50 base-reds — doc counts + orphan uncloseai…
yourspraveen Aug 22, 2026
92ef3c7
fix(resilience): honor shared-registry passthrough providers (#11071)…
yourspraveen Aug 22, 2026
f387575
fix(memory): treat TokenRouter as system-must-be-first (live HTTP 400…
ggdayup Aug 23, 2026
b384455
fix(api): refuse creating a routing combo without any model (#11162)
maxmad64bis Aug 23, 2026
1058426
fix(executors): rotate on upstream 400 empty-body rejections (opencod…
maxmad64bis Aug 23, 2026
60f25ef
fix(sse): merge purify_history compression notice into the leading sy…
ggdayup Aug 23, 2026
80b8d2a
fix(sse): resume stream recovery after a clean stop with reasoning-on…
maxmad64bis Aug 23, 2026
62ab93d
fix(sse): reject a low-overlap stream-recovery continuation instead o…
maxmad64bis Aug 23, 2026
eb9fa33
feat(api): structured ?format=json for the self-service usage endpoin…
diegosouzapw Aug 23, 2026
3ef54fc
feat(api): return every connection's snapshot under providers[] in om…
diegosouzapw Aug 23, 2026
eb57973
feat(dashboard): add CheaperInference sponsor banner and route banner…
diegosouzapw Aug 23, 2026
d888f1a
fix(combo): accept SSE comment lines (e.g. OpenRouter keep-alives) in…
asorourx Aug 23, 2026
e73ab00
fix(codex): make remote compaction V2 complete reliably (#11041)
jackjinke Aug 23, 2026
2300171
fix(resilience): drain heavyweight SSE on SIGTERM (#11020)
RaviTharuma Aug 23, 2026
e52d2db
fix(compression): CCR must not strand prompts for callers without the…
HouMinXi Aug 23, 2026
c018bb4
fix(catalog): declare GLM reasoning effort tiers (#10963)
xz-dev Aug 23, 2026
0a031d5
board #10961
hartmark Aug 23, 2026
976154f
test(reasoning): propagate #11110/#11129 summary defaults in chatcore…
hartmark Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 6 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ DISABLE_SQLITE_AUTO_BACKUP=false
# Used by: src/shared/utils/rateLimiter.ts
# Example: redis://localhost:6379 (or redis://redis:6379 in Docker)
# REDIS_URL=redis://localhost:6379
# Namespace prefix for ALL OmniRoute Redis keys (rate limiter + auth cache +
# quota store). Prevents key collisions when OmniRoute shares a Redis instance
# with other apps (e.g. on 127.0.0.1:6379). Default when unset: omniroute:
# REDIS_KEY_PREFIX=omniroute:
# Host interface docker-compose publishes the Redis sidecar on.
# Default: 127.0.0.1 (loopback only). The compose Redis runs WITHOUT
# `requirepass`, and app containers reach it over the compose network
Expand Down Expand Up @@ -372,9 +376,8 @@ ALLOW_API_KEY_REVEAL=false
# NO_LOG_API_KEY_IDS=key_abc123,key_def456

# Fallback per-day request budget applied to API keys whose `rate_limits`
# column is null. Default (unset/empty/malformed) preserves the legacy
# 1000/day, 5000/week, 20000/month windows so existing deployments do not
# silently lose rate limiting on upgrade.
# column is null. Default (unset/empty) is unlimited (no implicit caps).
# Malformed values preserve the legacy 1000/day, 5000/week, 20000/month windows.
# Set explicitly to "0" to opt out entirely (unlimited fallback). Any
# positive integer N enables N/day, 5N/week, 20N/month.
# Used by: src/shared/utils/apiKeyPolicy.ts — checkRateLimit() fallback.
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/dast-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
env:
PORT: "20128"
INJECTION_GUARD_MODE: block
REQUIRE_API_KEY: "false"
run: |
node dist/server.js > server.log 2>&1 &
echo $! > server.pid
Expand All @@ -64,16 +65,20 @@ jobs:
# those 302s as "the API accepted a schema-violating request" and the configured-off
# 400 as "rejected a schema-compliant request". Documenting the flow in the spec is
# still right (operators need it); fuzzing it is not what this smoke is for.
# /api/auth/login has brute-force rate limiting: repeated failed logins return 429,
# which Schemathesis flags as rejection of schema-compliant requests.
schemathesis run docs/openapi.yaml --url http://localhost:20128 \
--include-path-regex '^/v1/(chat/completions|models)$|^/api/(auth|keys)' \
--exclude-path-regex '^/api/auth/oidc/' \
--exclude-path-regex '^/api/auth/(oidc/|login)' \
--max-examples 8 --workers 4 --checks all --max-response-time 30 \
--request-timeout 20 --suppress-health-check all --no-color
- name: Install promptfoo
run: npm install -g promptfoo@0.122.0
- name: promptfoo injection-guard (blocking)
env:
OMNIROUTE_URL: http://localhost:20128
OMNIROUTE_API_KEY: not-needed-blocked-before-upstream
run: npx --yes promptfoo@latest eval -c promptfooconfig.yaml --no-cache
run: promptfoo eval -c promptfooconfig.yaml --no-cache
- name: Stop server
if: always()
run: kill "$(cat server.pid)" || true
Expand Down
76 changes: 75 additions & 1 deletion .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,55 @@ jobs:
env:
DOCKER_BUILDKIT_INLINE_CACHE: 1

- name: Build and push BUN base platform image by digest
id: build-bun-base
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
with:
context: .
file: Dockerfile.bun
target: runner-base
platforms: ${{ matrix.platform }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
${{ env.GHCR_IMAGE_NAME }}
cache-from: type=gha,scope=docker-bun-base-${{ matrix.arch }}
cache-to: type=gha,scope=docker-bun-base-${{ matrix.arch }},mode=max
no-cache: false
env:
DOCKER_BUILDKIT_INLINE_CACHE: 1

- name: Build and push BUN web platform image by digest
id: build-bun-web
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
with:
context: .
file: Dockerfile.bun
target: runner-web
platforms: ${{ matrix.platform }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
${{ env.GHCR_IMAGE_NAME }}
cache-from: type=gha,scope=docker-bun-web-${{ matrix.arch }}
cache-to: type=gha,scope=docker-bun-web-${{ matrix.arch }},mode=max
no-cache: false
env:
DOCKER_BUILDKIT_INLINE_CACHE: 1

- name: Export digests
env:
DIGEST_BASE: ${{ steps.build.outputs.digest }}
DIGEST_WEB: ${{ steps.build-web.outputs.digest }}
DIGEST_BUN_BASE: ${{ steps.build-bun-base.outputs.digest }}
DIGEST_BUN_WEB: ${{ steps.build-bun-web.outputs.digest }}
run: |
set -euo pipefail
mkdir -p /tmp/digests/base /tmp/digests/web
mkdir -p /tmp/digests/base /tmp/digests/web /tmp/digests/bun-base /tmp/digests/bun-web
touch "/tmp/digests/base/${DIGEST_BASE#sha256:}"
touch "/tmp/digests/web/${DIGEST_WEB#sha256:}"
touch "/tmp/digests/bun-base/${DIGEST_BUN_BASE#sha256:}"
touch "/tmp/digests/bun-web/${DIGEST_BUN_WEB#sha256:}"

- name: Upload base digests
uses: actions/upload-artifact@v7
Expand All @@ -209,6 +249,22 @@ jobs:
if-no-files-found: error
retention-days: 1

- name: Upload bun-base digests
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: digests-bun-base-${{ matrix.arch }}
path: /tmp/digests/bun-base/*
if-no-files-found: error
retention-days: 1

- name: Upload bun-web digests
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: digests-bun-web-${{ matrix.arch }}
path: /tmp/digests/bun-web/*
if-no-files-found: error
retention-days: 1

merge:
name: Publish multi-arch manifests
needs:
Expand Down Expand Up @@ -263,6 +319,20 @@ jobs:
path: /tmp/digests/web
merge-multiple: true

- name: Download bun-base digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: digests-bun-base-*
path: /tmp/digests/bun-base
merge-multiple: true

- name: Download bun-web digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: digests-bun-web-*
path: /tmp/digests/bun-web
merge-multiple: true

- name: Create Docker Hub manifest
run: |
set -euo pipefail
Expand All @@ -286,6 +356,8 @@ jobs:

create_manifest "${IMAGE_NAME}" "" /tmp/digests/base
create_manifest "${IMAGE_NAME}" "-web" /tmp/digests/web
create_manifest "${IMAGE_NAME}" "-bun" /tmp/digests/bun-base
create_manifest "${IMAGE_NAME}" "-web-bun" /tmp/digests/bun-web

- name: Create GHCR manifest
run: |
Expand All @@ -310,6 +382,8 @@ jobs:

create_manifest "${GHCR_IMAGE_NAME}" "" /tmp/digests/base
create_manifest "${GHCR_IMAGE_NAME}" "-web" /tmp/digests/web
create_manifest "${GHCR_IMAGE_NAME}" "-bun" /tmp/digests/bun-base
create_manifest "${GHCR_IMAGE_NAME}" "-web-bun" /tmp/digests/bun-web

- name: Inspect image
if: needs.prepare.outputs.version != 'main'
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Repository map and Reference Documentation sections below.
| Translators | `open-sse/translator/` | Format conversion (OpenAI↔Claude↔Gemini) |
| Transformer | `open-sse/transformer/` | Responses API ↔ Chat Completions |
| Services | `open-sse/services/` | Combo routing, rate limits, caching, etc |
| Database | `src/lib/db/` | SQLite domain modules (157 migrations) |
| Database | `src/lib/db/` | SQLite domain modules (159 migrations) |
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
| MCP Server | `open-sse/mcp-server/` | 110 tools (44 canonical + memory/skill/GitHub/pool/gamification/plugin/Notion/Obsidian/local-corpus/RTK modules), 3 transports (stdio / SSE / Streamable HTTP), 33 scopes |
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |
Expand Down
146 changes: 146 additions & 0 deletions Dockerfile.bun
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# ── Multi-stage Dockerfile for Native Bun Runtime (web-latest-bun) ───────────
FROM oven/bun:1.3.14-slim AS base
WORKDIR /app

RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
build-essential \
python3 \
python-is-python3 \
make \
g++ \
libsecret-1-0 \
ca-certificates \
curl \
&& rm -rf /var/lib/apt/lists/*

# ── Builder stage (100% Bun Native Install & Build) ─────────────────────────
FROM base AS builder
WORKDIR /app

COPY . .

# Fast Bun native package install
RUN bun install --include=optional --quiet

# Compile native better-sqlite3 Node-API addon under Bun
RUN if [ -d "node_modules/better-sqlite3" ]; then \
(cd node_modules/better-sqlite3 && bunx node-gyp rebuild); \
fi

# Fetch tls-client-node native binary if script exists
RUN if [ -f "node_modules/tls-client-node/scripts/postinstall.js" ]; then \
bun node_modules/tls-client-node/scripts/postinstall.js || true; \
fi

# Disable Turbopack for Bun builder stage (Turbopack V8 internal worker bindings require Node)
ENV OMNIROUTE_USE_TURBOPACK=0

ARG OMNIROUTE_BASE_PATH=""
ENV OMNIROUTE_BASE_PATH=$OMNIROUTE_BASE_PATH

ARG DASHBOARD_ALLOW_EMBED=""
ENV DASHBOARD_ALLOW_EMBED=$DASHBOARD_ALLOW_EMBED

ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production

# Bun native Next.js build execution
RUN bun run --quiet build

# ── Runner Base stage (100% Bun Native Production Runtime) ──────────────────
FROM oven/bun:1.3.14-slim AS runner-base

LABEL org.opencontainers.image.title="omniroute" \
org.opencontainers.image.description="Unified AI proxy — route any LLM through one endpoint (Bun Native)" \
org.opencontainers.image.url="https://omniroute.online" \
org.opencontainers.image.source="https://github.com/diegosouzapw/OmniRoute" \
org.opencontainers.image.licenses="MIT"

WORKDIR /app

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
libsecret-1-0 \
ca-certificates \
curl \
&& rm -rf /var/lib/apt/lists/*

ENV NODE_ENV=production
ENV PORT=20128
ENV HOSTNAME=0.0.0.0
ENV OMNIROUTE_MEMORY_MB=1024

ENV DATA_DIR=/app/data
RUN mkdir -p /app/data

COPY --from=builder /app/.build/next/standalone ./
COPY --from=builder /app/node_modules/better-sqlite3 ./node_modules/better-sqlite3
ENV OMNIROUTE_MIGRATIONS_DIR=/app/migrations

COPY --from=builder /app/scripts/dev/healthcheck.mjs ./healthcheck.mjs

EXPOSE 20128

HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD bun healthcheck.mjs || exit 1

ENTRYPOINT ["bun", "dev/run-standalone.mjs"]

# ── Runner Web stage (Bun Native + Chromium/Playwright for Web providers) ───
FROM runner-base AS runner-web

USER root

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
chromium \
chromium-driver \
fonts-liberation \
libasound2t64 \
gconf-service \
libatk-bridge2.0-0 \
libatk1.0-0 \
libc6 \
libcairo2 \
libcups2 \
libdbus-1-3 \
libexpat1 \
libfontconfig1 \
libgbm1 \
libgcc-s1 \
libglib2.0-0 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libpango-1.0-0 \
pangocairo-1.0-0 \
stdc++6 \
libx11-6 \
libx11-xcb1 \
libxcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxi6 \
libxrandr2 \
libxrender1 \
libxss1 \
libxtst6 \
ca-certificates \
fonts-gargi \
fonts-ipafont-gothic \
fonts-kacst \
fonts-thai-tlwg \
fonts-wqy-zenhei \
&& rm -rf /var/lib/apt/lists/*

ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium

# Return to the base image non-root user after the apt install (mirrors the
# Node Dockerfile runner-web stage, which re-asserts USER node).
USER bun
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ curl http://localhost:20128/v1/chat/completions \

</div>

<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint. 348 providers. Never stop building — OmniRoute picks the cheapest one that works. Six pillars: Never hit limits (auto-fallback across 348 providers in milliseconds, zero downtime) · Save up to 95% tokens (RTK + Caveman stacked compression cuts 15–95%, ~89% avg on tool-heavy sessions) · $0 to start (90+ free tiers, 57 free forever — no card needed) · Every tool works (33 coding agents through one config) · One endpoint (OpenAI ↔ Claude ↔ Gemini ↔ Responses API at /v1) · Production-grade (circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals — 25,000+ tests)."/>
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint. 348 providers. Never stop building — OmniRoute picks the cheapest one that works. Six pillars: Never hit limits (auto-fallback across 348 providers in milliseconds, zero downtime) · Save up to 95% tokens (RTK + Caveman stacked compression cuts 15–95%, ~89% avg on tool-heavy sessions) · $0 to start (90+ free tiers, 56 free forever — no card needed) · Every tool works (33 coding agents through one config) · One endpoint (OpenAI ↔ Claude ↔ Gemini ↔ Responses API at /v1) · Production-grade (circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals — 25,000+ tests)."/>

<br/>
<br/>
Expand Down Expand Up @@ -646,7 +646,7 @@ of your shell history. → [CLI Integrations](docs/guides/CLI-INTEGRATIONS.md)

</div>

> The most complete catalog of any open-source router: **348 providers**, **90+ with a free tier**, **57 free forever**.
> The most complete catalog of any open-source router: **348 providers**, **90+ with a free tier**, **56 free forever**.

<div align="center">

Expand Down Expand Up @@ -1009,6 +1009,19 @@ Full table: [Docker Guide — runtime RAM](docs/guides/DOCKER_GUIDE.md#runtime-r
> are **not supported for production**. See
> [Docker Release Channels](docs/guides/DOCKER_GUIDE.md#release-channels).

**🥟 Bun**

Standard `bun install` and global installation (`bun install -g omniroute`) are supported via Bun runtime detection:
- **Built-in `bun:sqlite`**: OmniRoute uses Bun's built-in `bun:sqlite` driver when running under Bun, falling back to `better-sqlite3` on Node.js or `sql.js`.
- **Automatic Webpack bundler selection**: Development (`bun run dev`) and production builds (`bun run build`) automatically detect Bun and disable Turbopack in favor of Webpack to prevent native V8 binding incompatibilities.
- **Dedicated Bun Dockerfile**: Multi-stage `Dockerfile.bun` for native Bun production deployments (`docker build -f Dockerfile.bun -t omniroute:bun .`).

```bash
# Install and run with Bun
bun install
bun run dev
```

**🛠️ From source**

```bash
Expand Down Expand Up @@ -1187,7 +1200,7 @@ Métricas de validação: 1002 vídeos rastreados · 7,069,190 visualizações c
<tr><td nowrap><b>Runtime</b></td><td>Node.js 22.x / 24.x LTS — <code>&gt;=22.22.2 &lt;23 || &gt;=24.0.0 &lt;27</code></td></tr>
<tr><td nowrap><b>Language</b></td><td>TypeScript 6.0 — <b>100% TypeScript</b> across <code>src/</code> and <code>open-sse/</code> (zero <code>any</code> in core since v2.0)</td></tr>
<tr><td nowrap><b>Framework</b></td><td>Next.js 16 + React 19 + Tailwind CSS 4</td></tr>
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 120 domain modules, 157 migrations</td></tr>
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 120 domain modules, 159 migrations</td></tr>
<tr><td nowrap><b>Memory</b></td><td>SQLite FTS5 full-text + int8-quantized vector embeddings, typed decay</td></tr>
<tr><td nowrap><b>Schemas</b></td><td>Zod 4 — MCP tool I/O validation + API contracts</td></tr>
<tr><td nowrap><b>Protocols</b></td><td>MCP (stdio / HTTP / SSE) + A2A v0.3 (JSON-RPC 2.0 + SSE)</td></tr>
Expand Down
6 changes: 6 additions & 0 deletions bin/cli/commands/combo.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,12 @@ export async function runComboCreateCommand(name, strategy = "priority", opts =
}

const models = Array.isArray(opts.models) ? opts.models : [];
if (!models.length) {
console.error(
"combo create requires at least one target. Pass --models <provider/model,...> and/or repeat --model <provider/model>."
);
return 1;
}

try {
return await withRuntime(async ({ kind, api, db }) => {
Expand Down
Loading
Loading