Compare commits
78 Commits
fix/11526-
...
security/v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45dbe13620 | ||
|
|
52670c1bf6 | ||
|
|
60dd135d62 | ||
|
|
0b18b2dc27 | ||
|
|
4fee959ad2 | ||
|
|
d62ecb5d98 | ||
|
|
ab60b95e31 | ||
|
|
6d209a9128 | ||
|
|
62b1835bb5 | ||
|
|
23832ba1e9 | ||
|
|
11e501f099 | ||
|
|
747ae10e62 | ||
|
|
64b78df100 | ||
|
|
ff70ea7633 | ||
|
|
6b36696d95 | ||
|
|
d62c0f2688 | ||
|
|
b945e3c80e | ||
|
|
132ad5f16d | ||
|
|
6475be13c7 | ||
|
|
f47f63df83 | ||
|
|
2acbfc6fa6 | ||
|
|
ad3e293f9f | ||
|
|
c467c3232b | ||
|
|
c9f11d86b5 | ||
|
|
21ed68d8ac | ||
|
|
d35b3f9779 | ||
|
|
9587e07b69 | ||
|
|
12cc6ca834 | ||
|
|
4f11b2ae3d | ||
|
|
b4e76a7ed9 | ||
|
|
4d519c406a | ||
|
|
b85d0abb0b | ||
|
|
1325047d56 | ||
|
|
6fee356aa2 | ||
|
|
e77b386619 | ||
|
|
8893816d0c | ||
|
|
71765435fb | ||
|
|
e385778bcf | ||
|
|
fb8897e926 | ||
|
|
a9f98fcb48 | ||
|
|
6dab0df038 | ||
|
|
2ac715aa9c | ||
|
|
86e48e3c9a | ||
|
|
5fbf218139 | ||
|
|
0095f3b38f | ||
|
|
2e8326d531 | ||
|
|
7133585d1d | ||
|
|
bcda889f84 | ||
|
|
91ecb6be9c | ||
|
|
e02f11984f | ||
|
|
ca4df9bef8 | ||
|
|
0ce2b83005 | ||
|
|
124f4cf761 | ||
|
|
dabf8dd580 | ||
|
|
d92088c5dc | ||
|
|
20bd2c067c | ||
|
|
1ed8f4ad4a | ||
|
|
f2f2fab636 | ||
|
|
b76aa02875 | ||
|
|
4977f1adcf | ||
|
|
99044ed044 | ||
|
|
68aa69bc21 | ||
|
|
14278e301c | ||
|
|
38bc925187 | ||
|
|
8946ce71eb | ||
|
|
c8f3bc888e | ||
|
|
955c7bbf42 | ||
|
|
ff25849530 | ||
|
|
756b47fdd7 | ||
|
|
e69f2109aa | ||
|
|
bda83c1d39 | ||
|
|
67f4e5201d | ||
|
|
e95a25512d | ||
|
|
146897d9bd | ||
|
|
f75bd75389 | ||
|
|
42a13fedef | ||
|
|
242c451298 | ||
|
|
6e62aad32e |
@@ -23,7 +23,7 @@
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"clean": "rm -rf dist",
|
||||
"test": "node --import tsx/esm --test tests/scaffold.test.ts tests/auth.test.ts tests/options-schema.test.ts tests/multi-instance.test.ts tests/fetch-interceptor.test.ts tests/provider.test.ts tests/gemini-sanitize.test.ts tests/combos.test.ts tests/config-shim.test.ts tests/features.test.ts tests/feature-defaults.test.ts tests/usable-combo.test.ts tests/disk-snapshot-perms.test.ts tests/fork-features.test.ts tests/auto-combo-context.test.ts tests/provider-id-routing.test.ts tests/management-read-token.test.ts tests/auto-sync.test.ts tests/model-allowlist.test.ts tests/log-level.test.ts tests/effort-tier-variants.test.ts",
|
||||
"test": "node --import tsx/esm --test tests/scaffold.test.ts tests/auth.test.ts tests/options-schema.test.ts tests/multi-instance.test.ts tests/fetch-interceptor.test.ts tests/provider.test.ts tests/gemini-sanitize.test.ts tests/combos.test.ts tests/config-shim.test.ts tests/features.test.ts tests/feature-defaults.test.ts tests/usable-combo.test.ts tests/disk-snapshot-perms.test.ts tests/fork-features.test.ts tests/auto-combo-context.test.ts tests/provider-id-routing.test.ts tests/management-read-token.test.ts tests/auto-sync.test.ts tests/model-allowlist.test.ts tests/log-level.test.ts tests/effort-tier-variants.test.ts tests/naming.test.ts tests/free-budget-magnitude.test.ts",
|
||||
"prepublishOnly": "npm run clean && npm run build && npm test"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
@@ -23,27 +23,11 @@ const ALIAS_UPPER_MAX_CHARS = 5;
|
||||
|
||||
// ── Auto Combo Types ─────────────────────────────────────────────────────
|
||||
|
||||
export type AutoVariant =
|
||||
| "coding"
|
||||
| "fast"
|
||||
| "cheap"
|
||||
| "offline"
|
||||
| "smart"
|
||||
| "lkgp";
|
||||
export type AutoVariant = "coding" | "fast" | "cheap" | "offline" | "smart" | "lkgp";
|
||||
|
||||
export const AUTO_VARIANTS: AutoVariant[] = [
|
||||
"coding",
|
||||
"fast",
|
||||
"cheap",
|
||||
"offline",
|
||||
"smart",
|
||||
"lkgp",
|
||||
];
|
||||
export const AUTO_VARIANTS: AutoVariant[] = ["coding", "fast", "cheap", "offline", "smart", "lkgp"];
|
||||
|
||||
export const AUTO_VARIANT_DESCRIPTIONS: Record<
|
||||
AutoVariant | "default",
|
||||
string
|
||||
> = {
|
||||
export const AUTO_VARIANT_DESCRIPTIONS: Record<AutoVariant | "default", string> = {
|
||||
default: "Best provider via scoring",
|
||||
coding: "Quality-first for code tasks",
|
||||
fast: "Latency-optimized routing",
|
||||
@@ -83,24 +67,15 @@ function titleCaseAlias(alias: string): string {
|
||||
* 3. Neither → undefined.
|
||||
*/
|
||||
export function shortProviderLabel(
|
||||
enrichment:
|
||||
| { providerDisplayName?: string; providerAlias?: string }
|
||||
| undefined,
|
||||
enrichment: { providerDisplayName?: string; providerAlias?: string } | undefined
|
||||
): string | undefined {
|
||||
if (!enrichment) return undefined;
|
||||
const raw =
|
||||
typeof enrichment.providerDisplayName === "string"
|
||||
? enrichment.providerDisplayName.trim()
|
||||
: "";
|
||||
typeof enrichment.providerDisplayName === "string" ? enrichment.providerDisplayName.trim() : "";
|
||||
if (raw.length > 0 && raw.length <= PROVIDER_LABEL_MAX_CHARS) return raw;
|
||||
const alias =
|
||||
typeof enrichment.providerAlias === "string"
|
||||
? enrichment.providerAlias.trim()
|
||||
: "";
|
||||
const alias = typeof enrichment.providerAlias === "string" ? enrichment.providerAlias.trim() : "";
|
||||
if (alias.length > 0) {
|
||||
return alias.length <= ALIAS_UPPER_MAX_CHARS
|
||||
? alias.toUpperCase()
|
||||
: titleCaseAlias(alias);
|
||||
return alias.length <= ALIAS_UPPER_MAX_CHARS ? alias.toUpperCase() : titleCaseAlias(alias);
|
||||
}
|
||||
// Long displayName with no alias to fall back on: keep the long label
|
||||
// rather than dropping the provider prefix entirely.
|
||||
@@ -131,10 +106,33 @@ export function normaliseFreeLabel(name: string): string {
|
||||
|
||||
// ── Free Budget Formatting ────────────────────────────────────────────────
|
||||
|
||||
/** Scales, largest first, so the unit is chosen by descending magnitude. */
|
||||
const TOKEN_UNITS = [
|
||||
[1e9, "B"],
|
||||
[1e6, "M"],
|
||||
[1e3, "K"],
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* Format a token count as a short magnitude string: `25M`, `1.5K`, `999`.
|
||||
*
|
||||
* The unit has to be picked from the value that will actually be *printed*,
|
||||
* not from the raw input. `toFixed(1)` rounds to the nearest tenth, so at the
|
||||
* K scale 999_950 and above render as `1000.0` — and by then the M branch has
|
||||
* already been skipped, producing `1000K` for a number that is `1M`. The same
|
||||
* carry turns just under a billion into `1000M`. When the rounded value reaches
|
||||
* the next scale, re-render at that scale instead.
|
||||
*/
|
||||
function fmtTokens(n: number): string {
|
||||
if (n >= 1e9) return (n / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
|
||||
if (n >= 1e6) return (n / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
|
||||
if (n >= 1e3) return (n / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
|
||||
for (let i = 0; i < TOKEN_UNITS.length; i++) {
|
||||
const [scale, suffix] = TOKEN_UNITS[i]!;
|
||||
if (n < scale) continue;
|
||||
const value = Number((n / scale).toFixed(1));
|
||||
// `Number()` also drops a trailing `.0`, which the previous regex did.
|
||||
if (value < 1000 || i === 0) return `${value}${suffix}`;
|
||||
const [nextScale, nextSuffix] = TOKEN_UNITS[i - 1]!;
|
||||
return `${Number((n / nextScale).toFixed(1))}${nextSuffix}`;
|
||||
}
|
||||
return String(n);
|
||||
}
|
||||
|
||||
@@ -184,15 +182,11 @@ export function formatFreeBudget(params: {
|
||||
*/
|
||||
export function formatAutoComboName(
|
||||
variant: AutoVariant | undefined,
|
||||
candidateCount?: number,
|
||||
candidateCount?: number
|
||||
): string {
|
||||
const label = variant
|
||||
? variant.charAt(0).toUpperCase() + variant.slice(1)
|
||||
: "Default";
|
||||
const label = variant ? variant.charAt(0).toUpperCase() + variant.slice(1) : "Default";
|
||||
const count =
|
||||
typeof candidateCount === "number" && candidateCount > 0
|
||||
? ` (${candidateCount}p)`
|
||||
: "";
|
||||
typeof candidateCount === "number" && candidateCount > 0 ? ` (${candidateCount}p)` : "";
|
||||
return `Auto: ${label}${count}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Magnitude-crossover regression for the free-budget suffix
|
||||
* (`formatFreeBudget` -> `fmtTokens` in @omniroute/opencode-plugin/src/naming.ts).
|
||||
*
|
||||
* `fmtTokens` picked its unit from the raw input and then rounded with
|
||||
* `toFixed(1)`. Rounding can carry a value into the next magnitude *after* that
|
||||
* branch has been skipped, so 999_950..999_999 rendered as "1000K" rather than
|
||||
* "1M", and just under a billion rendered as "1000M" rather than "1B".
|
||||
*
|
||||
* These budgets are not always round numbers: `monthlyTokens` is derived from the
|
||||
* remote Radar feed (`tokensPerMonth`) and can be replaced wholesale by a
|
||||
* user-local override, so the crossover band is reachable with real data.
|
||||
*
|
||||
* Kept in its own file rather than added to naming.test.ts so this does not
|
||||
* collide with the coverage being added for `formatFreeBudget` in #11660.
|
||||
*/
|
||||
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { formatFreeBudget } from "../src/naming.js";
|
||||
|
||||
/** `recurring-daily` is the shortest path from a token count to a rendered suffix. */
|
||||
const daily = (monthlyTokens: number) =>
|
||||
formatFreeBudget({ freeType: "recurring-daily", monthlyTokens }).replace(" tokens/day", "");
|
||||
|
||||
test("fmtTokens: a rounded K value that reaches 1000 is promoted to M", () => {
|
||||
// 999_950 is the true boundary, not 999_999: toFixed(1) rounds to the nearest
|
||||
// tenth, so 999.95K is the first value that carries to "1000.0".
|
||||
assert.equal(daily(999_950), "1M");
|
||||
assert.equal(daily(999_999), "1M");
|
||||
});
|
||||
|
||||
test("fmtTokens: a rounded M value that reaches 1000 is promoted to B", () => {
|
||||
assert.equal(daily(999_950_000), "1B");
|
||||
assert.equal(daily(999_999_999), "1B");
|
||||
});
|
||||
|
||||
test("fmtTokens: values just below the rounding boundary keep their own unit", () => {
|
||||
// The promotion must not fire early — 999.9K still rounds to 999.9, not 1000.
|
||||
assert.equal(daily(999_949), "999.9K");
|
||||
assert.equal(daily(999_499), "999.5K");
|
||||
assert.equal(daily(999_499_999), "999.5M");
|
||||
});
|
||||
|
||||
test("fmtTokens: ordinary magnitudes are unchanged", () => {
|
||||
assert.equal(daily(0), "0");
|
||||
assert.equal(daily(999), "999");
|
||||
assert.equal(daily(1_000), "1K");
|
||||
assert.equal(daily(1_500), "1.5K");
|
||||
assert.equal(daily(1_000_000), "1M");
|
||||
assert.equal(daily(1_500_000), "1.5M");
|
||||
assert.equal(daily(25_000_000), "25M");
|
||||
assert.equal(daily(1_234_567), "1.2M");
|
||||
assert.equal(daily(1_000_000_000), "1B");
|
||||
assert.equal(daily(2_500_000_000), "2.5B");
|
||||
});
|
||||
|
||||
test("fmtTokens: B is the top unit, so a carry there has nowhere to go", () => {
|
||||
// Deliberately pinned: promoting past B would need a unit that does not exist,
|
||||
// so "1000B" is the intended output rather than an oversight.
|
||||
assert.equal(daily(999_999_999_999), "1000B");
|
||||
});
|
||||
|
||||
test("formatFreeBudget: the promotion applies to every token-bearing branch", () => {
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "recurring-monthly", monthlyTokens: 999_999 }),
|
||||
"1M tokens/month"
|
||||
);
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "recurring-credit", creditTokens: 999_999 }),
|
||||
"1M credits"
|
||||
);
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "one-time-initial", creditTokens: 999_999 }),
|
||||
"1M credits (one-time)"
|
||||
);
|
||||
});
|
||||
81
@omniroute/opencode-plugin/tests/naming.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Tests for `formatFreeBudget` (@omniroute/opencode-plugin/src/naming.ts):
|
||||
* formats a free-tier model's budget info into a short human-readable
|
||||
* suffix, branching on `freeType`.
|
||||
*/
|
||||
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { formatFreeBudget, type FreeModelFreeType } from "../src/naming.js";
|
||||
|
||||
test("formatFreeBudget: recurring-daily formats tokens/day", () => {
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "recurring-daily", monthlyTokens: 25_000_000 }),
|
||||
"25M tokens/day"
|
||||
);
|
||||
});
|
||||
|
||||
test("formatFreeBudget: recurring-monthly formats tokens/month", () => {
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "recurring-monthly", monthlyTokens: 1_000_000 }),
|
||||
"1M tokens/month"
|
||||
);
|
||||
});
|
||||
|
||||
test("formatFreeBudget: recurring-credit formats credits", () => {
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "recurring-credit", creditTokens: 10_000_000 }),
|
||||
"10M credits"
|
||||
);
|
||||
});
|
||||
|
||||
test("formatFreeBudget: one-time-initial formats credits with (one-time) suffix", () => {
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "one-time-initial", creditTokens: 1_000_000 }),
|
||||
"1M credits (one-time)"
|
||||
);
|
||||
});
|
||||
|
||||
test("formatFreeBudget: keyless has no token/credit args", () => {
|
||||
assert.equal(formatFreeBudget({ freeType: "keyless" }), "(keyless)");
|
||||
});
|
||||
|
||||
test("formatFreeBudget: discontinued has no token/credit args", () => {
|
||||
assert.equal(formatFreeBudget({ freeType: "discontinued" }), "(discontinued)");
|
||||
});
|
||||
|
||||
test("formatFreeBudget: missing token/credit counts default to 0", () => {
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "recurring-daily" }),
|
||||
"0 tokens/day"
|
||||
);
|
||||
});
|
||||
|
||||
test("formatFreeBudget: unrecognised freeType falls through to the default branch", () => {
|
||||
// `freeType` is populated from catalog data at runtime, so a value the
|
||||
// build doesn't know about is reachable even though TypeScript treats the
|
||||
// `default:` arm as dead code for a well-typed caller.
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "some-future-type" as FreeModelFreeType }),
|
||||
""
|
||||
);
|
||||
});
|
||||
|
||||
test("formatFreeBudget: sub-1K token count is not abbreviated", () => {
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "recurring-daily", monthlyTokens: 500 }),
|
||||
"500 tokens/day"
|
||||
);
|
||||
});
|
||||
|
||||
test("formatFreeBudget: the 999_999 rounding wart is fixed — promotes to 1M", () => {
|
||||
// `toFixed(1)` rounds 999999/1e3 up to "1000.0" before the `>= 1e6` threshold
|
||||
// check has a chance to apply. fmtTokens now promotes a rounded-up "1000" in
|
||||
// any unit to the next unit up, so this correctly reads "1M" instead of the
|
||||
// old "1000K" wart.
|
||||
assert.equal(
|
||||
formatFreeBudget({ freeType: "recurring-daily", monthlyTokens: 999_999 }),
|
||||
"1M tokens/day"
|
||||
);
|
||||
});
|
||||
@@ -46,7 +46,7 @@ Repository map and Reference Documentation sections below.
|
||||
|
||||
## Project at a Glance
|
||||
|
||||
**OmniRoute** — unified AI proxy/router. One endpoint, 354 LLM providers, auto-fallback.
|
||||
**OmniRoute** — unified AI proxy/router. One endpoint, 357 LLM providers, auto-fallback.
|
||||
|
||||
| Layer | Location | Purpose |
|
||||
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
36
Dockerfile
@@ -184,19 +184,29 @@ ENV NODE_OPTIONS="--max-old-space-size=${OMNIROUTE_BUILD_MEMORY_MB}"
|
||||
# silently leaving no standalone bundle. Next derives the worker count from
|
||||
# CIRCLE_NODE_TOTAL (workers = N-1). (#10060)
|
||||
#
|
||||
# Lowered 8 → 3 (7 workers → 2). Every page-data worker inherits NODE_OPTIONS
|
||||
# above, so the ceiling is per PROCESS, not per build: 7 workers on a 16 GB
|
||||
# GitHub runner (ubuntu-24.04 / ubuntu-24.04-arm, 4 vCPU) exhausted the host and
|
||||
# buildkit failed the whole step with `ResourceExhausted: ... cannot allocate
|
||||
# memory`. The compile phase always finished ("✓ Compiled successfully in
|
||||
# 4.2min"); the kernel killed the build right after "Collecting page data using
|
||||
# 7 workers". It was intermittent for a while and went 100% on 2026-08-22, which
|
||||
# is what a threshold being crossed by ordinary codebase growth looks like.
|
||||
# tests/unit/docker-build-memory-budget.test.ts does the arithmetic and fails if
|
||||
# either knob is raised past what a 16 GB runner holds. 2 workers also stops
|
||||
# oversubscribing the runner's 4 vCPU, which 7 did. Override for a big builder:
|
||||
# `--build-arg OMNIROUTE_BUILD_WORKERS=8`.
|
||||
ARG OMNIROUTE_BUILD_WORKERS=3
|
||||
# Lowered 8 → 3 (7 workers → 2) in #11419, then 3 → 2 (2 workers → 1) in #7518.
|
||||
# Every page-data worker inherits NODE_OPTIONS above, so the ceiling is per
|
||||
# PROCESS, not per build: 7 workers on a 16 GB GitHub runner (ubuntu-24.04 /
|
||||
# ubuntu-24.04-arm, 4 vCPU) exhausted the host and buildkit failed the whole
|
||||
# step with `ResourceExhausted: ... cannot allocate memory`. The compile phase
|
||||
# always finished ("✓ Compiled successfully in 4.2min"); the kernel killed the
|
||||
# build right after "Collecting page data using N workers".
|
||||
#
|
||||
# #11419's first fix (8 → 3) modeled the per-worker peak as an INFERENCE
|
||||
# (2560 MB, guessed from "7 workers didn't fit") and assumed the parent
|
||||
# process's RSS tracked the V8 heap ceiling. Both assumptions were wrong: a
|
||||
# live VPS reproduction (issue #7518, dmesg OOM-killer report) measured the
|
||||
# real per-process RSS directly at ~4.5 GB, independent of the NODE_OPTIONS
|
||||
# heap flag (Turbopack itself is native/Rust, outside the V8 heap) — and it
|
||||
# applies to the parent process too, not just workers. 2 workers (3 processes
|
||||
# × 4.5 GB = 13.5 GB) still didn't fit the 12.288 GB (75%) budget on a 16 GB
|
||||
# runner, matching the still-live publish failures after #11419 merged. 1
|
||||
# worker (2 processes × 4.5 GB = 9 GB) fits with headroom to spare.
|
||||
# tests/unit/docker-build-memory-budget.test.ts does the arithmetic against
|
||||
# the measured figure and fails if either knob is raised past what a 16 GB
|
||||
# runner holds. Override for a big builder: `--build-arg
|
||||
# OMNIROUTE_BUILD_WORKERS=8`.
|
||||
ARG OMNIROUTE_BUILD_WORKERS=2
|
||||
ENV CIRCLE_NODE_TOTAL=${OMNIROUTE_BUILD_WORKERS}
|
||||
|
||||
COPY . ./
|
||||
|
||||
10
README.md
@@ -7,7 +7,7 @@
|
||||
|
||||
# 🚀 OmniRoute — The Free AI Gateway
|
||||
|
||||
<img src="./docs/diagrams/readme-hero.svg" width="100%" alt="OmniRoute — Never stop coding. Every AI tool → 353 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 15–95% tokens (~89% avg) — never hit limits. 353 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
|
||||
<img src="./docs/diagrams/readme-hero.svg" width="100%" alt="OmniRoute — Never stop coding. Every AI tool → 357 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 15–95% tokens (~89% avg) — never hit limits. 357 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -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 and 353 providers. Automatic fallback keeps routing while another healthy target is available. Six pillars: resilient fallback across 353 providers · up to 95% token savings on eligible workloads · $0 to start with 90+ free tiers and 56 recurring/keyless free-forever providers · 35 CLI/agent integrations through one config · OpenAI, Claude, Gemini and Responses API compatibility at /v1 · production controls including circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals and 39,000+ static test declarations across 5,100+ tracked test files."/>
|
||||
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint and 357 providers. Automatic fallback keeps routing while another healthy target is available. Six pillars: resilient fallback across 357 providers · up to 95% token savings on eligible workloads · $0 to start with 90+ free tiers and 56 recurring/keyless free-forever providers · 35 CLI/agent integrations through one config · OpenAI, Claude, Gemini and Responses API compatibility at /v1 · production controls including circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals and 39,000+ static test declarations across 5,100+ tracked test files."/>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
@@ -461,7 +461,7 @@ All **19** strategies — mix & match per combo step:
|
||||
|
||||
</div>
|
||||
|
||||
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 353 providers, 90+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 43 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
|
||||
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 357 providers, 90+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 43 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
|
||||
|
||||
<sub>📊 Full methodology & per-feature detail vs 9router, OpenRouter, CLIProxyAPI & LiteLLM → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md)</sub>
|
||||
|
||||
@@ -559,7 +559,7 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute
|
||||
- **🖼️ New endpoints** — `/v1/ocr` (Mistral OCR) and `/v1/audio/translations` (Whisper-style) round out the media surface. → [API Reference](docs/reference/API_REFERENCE.md)
|
||||
- **🎨 Image / video / audio generation** — one API for media: xAI Grok Imagine & Novita AI video, ComfyUI, Freepik, Adobe Firefly, Microsoft Designer, Segmind, EdgeTTS. → [API Reference](docs/reference/API_REFERENCE.md)
|
||||
- **🌍 Deployment & ops** — reverse-proxy `basePath`, browser-language auto-detect, per-key device tracking, root-less MITM trust, zh-TW localization. → [Environment](docs/reference/ENVIRONMENT.md)
|
||||
- **🤝 More providers & agents** — Cursor Cloud Agent, Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **353-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md)
|
||||
- **🤝 More providers & agents** — Cursor Cloud Agent, Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **357-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md)
|
||||
- **📡 Routing transparency** — every response carries an `X-OmniRoute-Decision` header naming the strategy/provider/latency that served it, a new `cache-optimized` combo strategy + Auto-Combo `cacheAffinity` factor route repeat requests back to the connection holding the cached prefix, and a read-only `/v1/auto-combo/{channel}/candidates` endpoint exposes an `auto/*` channel's live candidate pool. → [Auto-Combo](docs/routing/AUTO-COMBO.md)
|
||||
- **⚡ Local performance & infra** — one-click local Redis, Cloudflare Workers / Deno Deploy relay deployers, Bifrost & Mux as supervised embedded services. → [Embedded Services](docs/frameworks/EMBEDDED-SERVICES.md)
|
||||
|
||||
@@ -642,7 +642,7 @@ of your shell history. → [CLI Integrations](docs/guides/CLI-INTEGRATIONS.md)
|
||||
|
||||
<div align="center">
|
||||
|
||||
## 🌐 353 AI Providers — 154 Catalog-Marked Free
|
||||
## 🌐 357 AI Providers — 154 Catalog-Marked Free
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
1
changelog.d/features/anysearch-search-provider.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(search):** Add AnySearch free web search + URL extract (webFetch) with typed results, credential validation, REST routing, and MCP selection - fallback-only
|
||||
1
changelog.d/fixes/11296-kie-market-model-id-sweep.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(kie):** correct 12 more KIE Market catalog ids that were sent to `createTask` unchanged but diverge from KIE's documented upstream `model` values — GPT Image 2 T2I/I2I (drops the `gpt/` prefix), GPT Image 1.5 T2I/I2I (`gpt-image/` namespace), Seedream 5.0 Lite T2I/I2I (drops the `.0`), all 4 Flux 2 variants (`flux-2/` namespace, generic variant renamed `flex`), and Wan 2.7 Image / Image Pro (dash instead of dot) — each verified individually against the literal example request published on docs.kie.ai. `#11326`'s "everything else already matches" claim was wrong a second time (#11296); `z-image/4.0-*`/`z-image/4.5-*` and `flux/kontext` remain open, documented as unresolved in `KIE_MARKET_UPSTREAM_MODEL_IDS`'s comment pending further verification.
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(dashboard):** `useApiKeySave.handleSaveApiKey` no longer forces a full upstream `/models` catalog sync on every non-curated provider connection save — callers can now pass `skipModelSync: true` to opt out, so a workflow that only wants to add one manual model no longer floods the provider's available-models list with hundreds/thousands of synced entries. The flag is a client-side intent signal only and is stripped before the connection payload is POSTed to `/api/providers`; default behavior (full sync on save) is unchanged when the flag is omitted (#11324)
|
||||
1
changelog.d/fixes/11433-opencode-alias-collision.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(combos):** the combo builder's precision-select, global-model-search, and manual-entry flows now serialize a model step's `model` string using the provider's already-computed routing-alias prefix (e.g. `oc/`) instead of rebuilding it from the raw canonical `providerId`, fixing the no-auth "OpenCode Free" provider (`opencode`) being routed to the unrelated paid "OpenCode Zen" provider (`opencode-zen`) because `opencode` doubles as a manual routing-prefix override ([#11433](https://github.com/diegosouzapw/OmniRoute/issues/11433)).
|
||||
1
changelog.d/fixes/11449-anysearch-icon-fallback.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(ui): let AnySearch use the normal provider-icon fallback when LobeHub has no matching icon (#11449)
|
||||
1
changelog.d/fixes/11462-roundrobin-combo-diagnostics.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(combo):** attach the same combo-diagnostics trace (`poolSize`/`attemptOrder`/`excluded`/`terminalReason`, plus `x-omniroute-combo-*` headers) to the round-robin strategy's and the nested pipeline/fusion runtime-unit loop's "Maximum combo retry limit reached" 503 that the priority-strategy path already attaches for the identical terminal condition — previously those two paths returned a bare, contextless 503 ([#11462](https://github.com/diegosouzapw/OmniRoute/issues/11462)).
|
||||
1
changelog.d/fixes/11500-decrypt-log-dedup.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(db):** dedupe the raw `[Encryption] Decryption failed...` log line emitted by the lazy-decrypt views (`createLazyRowProxy`/`createLazyConnectionView`), which power `getProviderConnections()` and were re-triggering that line on every CredentialHealth/model-sync cycle for the same corrupt or stale-key credential — a fresh Proxy over a fresh row on every cycle meant the per-proxy memoization never suppressed it, unlike the dedup `decryptConnectionFields()` already had since [#9927](https://github.com/diegosouzapw/OmniRoute/issues/9927). Now shares that dedupe tracking so the line logs at most once per credential ([#11500](https://github.com/diegosouzapw/OmniRoute/issues/11500)).
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(sse):** stop dropping resolved `thoughtSignature` values on parallel (multi tool-call) turns sent to Gemini 3.x — the claude→gemini and openai→gemini translators previously kept the signature only on the *first* function call of a message, causing Gemini to reject subsequent calls in the same turn with HTTP 400 "Function call is missing a thought_signature"; each function call now keeps its own resolved signature ([#11510](https://github.com/diegosouzapw/OmniRoute/issues/11510)).
|
||||
1
changelog.d/fixes/11556-client-abort-guard-mjs-import.md
Normal file
@@ -0,0 +1 @@
|
||||
- **sse:** fix LiveWS/embed-WS servers crashing at startup under the Node/tsx runtime — `liveServer.ts`, `embedWsProxy.ts` and `apiBridgeServer.ts` imported `@/shared/utils/httpClientAbortGuard` without the `.mjs` extension, so the client-abort crash guard added by [#11556](https://github.com/diegosouzapw/OmniRoute/pull/11556) was unreachable and every dependent test failed with `ERR_MODULE_NOT_FOUND` ([#11556](https://github.com/diegosouzapw/OmniRoute/pull/11556)).
|
||||
@@ -0,0 +1 @@
|
||||
- **resilience:** restore the expired-connection retry-budget probe in the token-health sweep — the `!isGitHubAccessTokenOnlyConnection` carve-out reintroduced by #11608 contradicted the boundary pinned by #11592, so a GitHub connection parked at `expired` with retry budget remaining was never probed and could never self-heal ([#11592](https://github.com/diegosouzapw/OmniRoute/pull/11592)).
|
||||
1
changelog.d/fixes/11604-aggregate-profile-level-pin.md
Normal file
@@ -0,0 +1 @@
|
||||
- **test(gamification):** pin the aggregate profile level to the XP-derived semantics of #11604 — `getAggregateXp()` now derives `currentLevel` from the summed XP (`calculateLevel(sum)`), not `MAX(stored current_level)`, and the #3484 fixture levels are aligned with the XP curve ([#11604](https://github.com/diegosouzapw/OmniRoute/pull/11604)).
|
||||
1
changelog.d/fixes/11626-retired-model-test-updates.md
Normal file
@@ -0,0 +1 @@
|
||||
- **test(chatcore):** move Codex/Claude combo fixtures off models the lifecycle guard now rejects — `gpt-5.1-codex`/`gpt-5-codex` are vendor-retired (snapshot, #11626) and `claude-3-5-sonnet-20241022` is shut down, so native-passthrough and combo-fallback tests switched to `gpt-5.6-sol` and `claude-sonnet-4.6` ([#11626](https://github.com/diegosouzapw/OmniRoute/pull/11626)).
|
||||
@@ -0,0 +1 @@
|
||||
- **fix(security):** Video Bridge transcript text is now omitted from OmniRoute-owned retained request, response, usage, error, stream, continuation, handoff, and Memory surfaces while the live bridge request remains intact. Server-generated descriptions are matched by bounded SHA-256/length identities emitted only by a successful Video Bridge rewrite; ordinary fields named `transcript` and caller-forged description prose remain untouched. Traversal is cycle-safe and bounded, and hostile getters, proxies, or budget overflow fail closed to a constant omission marker instead of leaking content or breaking the request. Custom plugins and guardrails remain privileged processors of the live payload and must secure any sinks they create themselves. ([#11658](https://github.com/diegosouzapw/OmniRoute/issues/11658))
|
||||
@@ -0,0 +1 @@
|
||||
- fix(opencode-plugin): stop a free-tier budget that rounds up across a magnitude from rendering as `1000K`/`1000M` in the model picker — `fmtTokens` chose its unit from the raw token count and then rounded with `toFixed(1)`, so 999,950–999,999 printed as `1000K` rather than `1M` and just under a billion printed as `1000M` rather than `1B` ([#11684](https://github.com/diegosouzapw/OmniRoute/pull/11684))
|
||||
1
changelog.d/fixes/7518-docker-build-memory-budget.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(docker):** re-derive the Docker build's worker-pool memory budget from the MEASURED ~4.5 GB per-process RSS (the issue owner's own VPS dmesg OOM-killer reproduction) instead of the stale 2560 MB/worker inference #11419 shipped, and lower `OMNIROUTE_BUILD_WORKERS` 3 → 2 so 1 parent + 1 page-data worker (2 processes × 4.5 GB = 9 GB) fits the 12.288 GB (75%) budget on a 16 GB GitHub Actions runner — the previous default (1 parent + 2 workers = 13.5 GB) still overcommitted the runner and kept "Publish to Docker Hub" failing with `cannot allocate memory` after #11419 merged (#7518).
|
||||
@@ -0,0 +1 @@
|
||||
- **docs:** sync the canonical provider count 354 → 356 across `README.md`, `AGENTS.md`, `llm.txt` (+ 42 i18n mirrors), the four README SVG diagrams, `docs/reference/PROVIDER_REFERENCE.md` (regenerated) and the `package.json` description after Opper (#11629) and 1min.ai (#11631) boarded the catalog — closes the `check:docs-counts-sync` strict drifts that kept `release/v3.8.51` red ([#11449](https://github.com/diegosouzapw/OmniRoute/issues/11449)).
|
||||
@@ -0,0 +1 @@
|
||||
- **test(providers):** update count-derived assertions after the v3.8.51 provider additions — `APIKEY_PROVIDERS` 233 → 235 (Opper #11629 + 1min.ai #11631), reserved-prefix REGISTRY walk 395 → 398, `WEB_FETCH_PROVIDERS` now includes `nimble-search` (#11620), and the provider translate-path golden snapshot regenerated ([#11449](https://github.com/diegosouzapw/OmniRoute/issues/11449)).
|
||||
@@ -0,0 +1 @@
|
||||
- **test(sse):** bump the hard-lease connection-query inventory for `src/lib/tokenHealthCheck.ts` to 2 — the verify-only web-cookie sweep added by #11495 split the single `getProviderConnections` call into oauth + cookie variants, which the frozen inventory had not tracked ([#11495](https://github.com/diegosouzapw/OmniRoute/pull/11495)).
|
||||
@@ -0,0 +1 @@
|
||||
- **test(opencode-plugin):** add unit test coverage for `formatFreeBudget()` naming helper ([#11660](https://github.com/diegosouzapw/OmniRoute/pull/11660)) — thanks @f9td56dbgh-hub
|
||||
@@ -2790,11 +2790,6 @@
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"src/mitm/dns/dnsConfig.ts": {
|
||||
"@typescript-eslint/no-unused-vars": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/mitm/dns/provision.ts": {
|
||||
"@typescript-eslint/no-unused-vars": {
|
||||
"count": 1
|
||||
@@ -2926,11 +2921,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/shared/middleware/chatBodyAdmission.ts": {
|
||||
"@typescript-eslint/no-unused-vars": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/shared/services/apiKeyResolver.ts": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
@@ -3440,10 +3430,10 @@
|
||||
},
|
||||
"tests/integration/skills-pipeline.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 14
|
||||
"count": 15
|
||||
},
|
||||
"@typescript-eslint/no-unused-vars": {
|
||||
"count": 2
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"tests/integration/traffic-inspector-error-sanitization.test.ts": {
|
||||
@@ -3690,11 +3680,6 @@
|
||||
"count": 15
|
||||
}
|
||||
},
|
||||
"tests/unit/authz/probe-9033-repro.test.ts": {
|
||||
"@typescript-eslint/no-unused-vars": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"tests/unit/autoCombo/tieredRotation.test.ts": {
|
||||
"@typescript-eslint/no-unused-vars": {
|
||||
"count": 3
|
||||
|
||||
@@ -229,7 +229,8 @@
|
||||
"tests/unit/vscode-token-routes.test.ts": 1633,
|
||||
"tests/unit/executor-antigravity.test.ts": 1427,
|
||||
"tests/unit/guardrails/videoBridgeResultCache.test.ts": 1040,
|
||||
"_rebaseline_2026_08_24_video_bridge_fu01_fu03_fu04_result_cache_tests": "PRs #11362 (FU-01 cache hardening) + #11382 (FU-03 visual dedup policy identity) + #11383 (FU-04 focused analysis mode) own test growth: videoBridgeResultCache.test.ts <1000->1040, +40 (sum of three stacked PRs boarded together in the same merge-batch, each adding its own cache-identity assertions on the shared result-cache seam). Owner pre-authorized rebaseline for legitimate PR growth (2026-08-19 directive)."
|
||||
"_rebaseline_2026_08_24_video_bridge_fu01_fu03_fu04_result_cache_tests": "PRs #11362 (FU-01 cache hardening) + #11382 (FU-03 visual dedup policy identity) + #11383 (FU-04 focused analysis mode) own test growth: videoBridgeResultCache.test.ts <1000->1040, +40 (sum of three stacked PRs boarded together in the same merge-batch, each adding its own cache-identity assertions on the shared result-cache seam). Owner pre-authorized rebaseline for legitimate PR growth (2026-08-19 directive).",
|
||||
"tests/integration/skills-pipeline.test.ts": 1010
|
||||
},
|
||||
"_rebaseline_2026_06_09": "Re-baseline consciente pre-release v3.8.19: 9 arquivos cresceram durante o ciclo (features mergeadas: RequestLoggerV2 +281 request-logger rework, stream +101, combo +73, chatCore +45, catalog +32 fable-5/catalog-flag, callLogs +4, accountFallback +2, usageHistory novo 840) + core.ts +7 (fix resetAllDbModuleState, PR 3536). A catraca segue valendo destes valores — proximo crescimento falha. Decisao: encolher (esp. RequestLoggerV2/chatCore) e a issue #3501 ficam para o ciclo seguinte.",
|
||||
"_rebaseline_2026_06_11_phase1f": "Phase 1f (#3501): ProviderDetailPageClient.tsx 4948→4062 (-886 LOC); 3 novos hooks extraídos. useProviderConnections.ts=954 acima do cap=800 — justificado: extração direta do god-component (zero lógica nova), própria redução do cliente supera o custo. useProviderSettings.ts=263 e useProviderModels.ts=154 já abaixo do cap.",
|
||||
@@ -652,5 +653,6 @@
|
||||
"_rebaseline_2026_08_20_imageregistry_1034": "imageRegistry.ts 1033->1034: +1 line drift between #10842 (cursor image provider, froze at 1033) and its actual merged state on release (measured 1034) — trivial rebaseline, not a new feature.",
|
||||
"_rebaseline_2026_08_25_11146_subscription_first_auto": "PR #11146 (@yourspraveen, subscription-first auto groupings auto/subscription+auto/thrifty): open-sse/services/autoCombo/virtualFactory.ts is a NEW file in this PR landing at 1128 lines (+2 margin) — two opt-in flat auto ids built on the established auto/best-free pattern (connectionBillingCatalog + subscriptionLadder pure functions). Frozen at merge size per owner-authorized rebaseline directive (2026-08-19, merge-batch Step 4); no further growth without split rationale.",
|
||||
"_rebaseline_2026_08_26_mergebatch_v3851_batch1": "/merge-batch 2026-08-26 (v3.8.51): three legitimate growths from this batch. #11448 src/app/api/providers/[id]/test/route.ts 1237->1262 (auto-test-on-create wiring). #11495 src/sse/services/auth.ts 3346->3376 (web-cookie health-sweep verify-only path). #11561 src/lib/cloudflaredTunnel.ts new named-tunnel mode, lands at 1078 (+78 over the 1000 new-file cap) for the CLOUDFLARED_CONFIG named-tunnel flow (login->create->route dns config parsing + readiness detection). Owner-authorized rebaseline per merge-batch Step 4 (2026-08-19 directive); no further growth without split rationale.",
|
||||
"_rebaseline_2026_08_26_mergebatch_v3851_batch2": "/merge-batch 2026-08-26 (v3.8.51) batch 2: three legitimate growths. #11083 src/shared/components/RequestLoggerDetail.tsx new-file cap, lands at 1018 (+18 over 1000) — copy-all button for request detail modal. #11631 src/shared/constants/providers/apikey/gateways.ts 1321->1330 (1min.ai gateway entry). #11628 src/sse/services/auth.ts 3376->3432 (credential-health isolation from model failures). Owner-authorized rebaseline per merge-batch Step 4 (2026-08-19 directive); no further growth without split rationale."
|
||||
"_rebaseline_2026_08_26_mergebatch_v3851_batch2": "/merge-batch 2026-08-26 (v3.8.51) batch 2: three legitimate growths. #11083 src/shared/components/RequestLoggerDetail.tsx new-file cap, lands at 1018 (+18 over 1000) — copy-all button for request detail modal. #11631 src/shared/constants/providers/apikey/gateways.ts 1321->1330 (1min.ai gateway entry). #11628 src/sse/services/auth.ts 3376->3432 (credential-health isolation from model failures). Owner-authorized rebaseline per merge-batch Step 4 (2026-08-19 directive); no further growth without split rationale.",
|
||||
"_rebaseline_2026_08_26_mergebatch_v3851_batch5": "/merge-batch 2026-08-26 (v3.8.51) batch 5: #11642 tests/integration/skills-pipeline.test.ts new regression test for the configured-provider-over-fallback search selection (#11524), lands at 1010 lines (+10 over the 1000 new-file testCap). Owner-authorized rebaseline per merge-batch Step 4 (2026-08-19 directive); no further growth without split rationale."
|
||||
}
|
||||
|
||||
@@ -188,14 +188,15 @@
|
||||
"dedicatedGate": true
|
||||
},
|
||||
"bundleSize": {
|
||||
"value": 8461,
|
||||
"value": 8653,
|
||||
"direction": "down",
|
||||
"dedicatedGate": true,
|
||||
"_rebaseline_2026_07_07_v3846_release_close": "5601->6534 (+933). v3.8.46 release close: gzip of the 4 bin/*.mjs entrypoints (size-limit + @size-limit/file) grew from this cycle's feature/fix merges pulled transitively into the CLI entrypoints (new providers, combo pipeline strategy #6396, effort/thinking standardization #6241, catalog cache-invalidation #6408). Measured 6534 locally via `check:bundle-size --ratchet` (deterministic gzip, matches CI). Legitimate cycle growth; shrink is separate debt.",
|
||||
"_rebaseline_2026_07_19_7808_codeql_alias_resolver_hook": "6534->6762 (+228). PR #7808 (CodeQL js/incomplete-url-substring-sanitization fix): the ESM loader hook source moved out of the inline `HOOK_SOURCE` template literal in bin/aliasResolver.mjs into a real file bin/aliasResolverHook.mjs, loaded via pathToFileURL() instead of a dynamically-built `data:text/javascript,...` URL. The new file is now counted by size-limit as a 5th bin/*.mjs entrypoint. Net +228 = the hook's gzip size (previously hidden inside aliasResolver.mjs because the template literal was compressed away). Security-driven; no shrink opportunity.",
|
||||
"_rebaseline_2026_07_28_v3849_release_preflight": "6762 -> 7666 (+904). Fechamento do ciclo v3.8.49: gzip dos entrypoints bin/*.mjs (size-limit + @size-limit/file) cresceu com o que os merges do ciclo puxam transitivamente para o CLI (novos provedores — 271->290, seletor de protocolo por conexão #8861, catálogos de busca #8814, resiliência). Crescimento legítimo de ciclo, medido localmente com `npm run check:bundle-size` = 7666 (gzip determinístico, bate com o CI). Encolher é dívida separada.",
|
||||
"_rebaseline_2026_08_09_v3850_release_close": "7666 -> 8045 (+379 gzip bytes, +4.9%). Release v3.8.50 close reconciliation measured twice with the real size-limit + @size-limit/file path on tip e0ce95c592. Per-entry measurements remain below their absolute budgets: omniroute.mjs 4380/15000, mcp-server.mjs 1195/5000, nodeRuntimeSupport.mjs 887/8000, reset-password.mjs 1583/6000. The growth accumulated through legitimate CLI/runtime work in this cycle, including global-install ESM alias resolution, Termux cache preparation, and MCP stdio startup hardening; no entrypoint is near its absolute ceiling. The direction:down ratchet stays blocking from this exact measured tip.",
|
||||
"_rebaseline_2026_08_24_ci_green_gates_f95b03d7": "8045 -> 8461 (+416 gzip bytes, +5.2%). CI run 32786966560 (release PR #8875, tip f95b03d7) measured bundleSize=8461 via check:bundle-size --ratchet, above the 8045 baseline left at the v3.8.50 close. The growth comes from the post-freeze back-merge cycle landing in the CLI entrypoints (Synthetic + Kilo Gateway providers, kilo-gateway routing surface). Re-baseline per the gate's own instruction (legitimate cycle growth); shrinking the entrypoints remains separate debt; direction:down ratchet stays blocking from this measured tip."
|
||||
"_rebaseline_2026_08_24_ci_green_gates_f95b03d7": "8045 -> 8461 (+416 gzip bytes, +5.2%). CI run 32786966560 (release PR #8875, tip f95b03d7) measured bundleSize=8461 via check:bundle-size --ratchet, above the 8045 baseline left at the v3.8.50 close. The growth comes from the post-freeze back-merge cycle landing in the CLI entrypoints (Synthetic + Kilo Gateway providers, kilo-gateway routing surface). Re-baseline per the gate's own instruction (legitimate cycle growth); shrinking the entrypoints remains separate debt; direction:down ratchet stays blocking from this measured tip.",
|
||||
"_rebaseline_2026_08_27_v3851_volatile_env_warning_11437": "8461 -> 8653 (+192 gzip bytes, +2.3%). Exact paired size-limit measurements on the VPS compared f95b03d709 with release/v3.8.51: only bin/omniroute.mjs changed, 4700 -> 4892; the other three entries remained 1195/983/1583. The growth originates in 943b9aaa84 (#11437), which warns users before a package-local .env is lost on the next global install. The CLI entry remains 4892/15000 bytes (32.6% of its absolute budget). Legitimate bug-fix growth; shrinking stays separate debt and direction:down remains blocking from this measured tip."
|
||||
},
|
||||
"openapiBreaking": {
|
||||
"value": 4,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 350" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Animated terminal demoing the OmniRoute CLI: omniroute providers list (354 providers registered, anthropic, codex, glm, kimi shown active), omniroute combo list (always-on priority, cost-saver, fusion-panel, context-relay) and omniroute health (healthy, 18412 requests in 24h, p95 412ms, circuit breakers 24 closed, 1 half-open, 0 open), cycling over 85 top-level commands: providers, oauth, keys, combo, nodes, models, cache, compression, cost, usage, quota, health, resilience, telemetry, logs, audit, mcp, a2a, cloud, memory, skills, eval, doctor, repl, tunnel, backup, sync, webhooks, policy, pricing, translator, simulate and more.">
|
||||
<svg viewBox="0 0 1200 350" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Animated terminal demoing the OmniRoute CLI: omniroute providers list (357 providers registered, anthropic, codex, glm, kimi shown active), omniroute combo list (always-on priority, cost-saver, fusion-panel, context-relay) and omniroute health (healthy, 18412 requests in 24h, p95 412ms, circuit breakers 24 closed, 1 half-open, 0 open), cycling over 85 top-level commands: providers, oauth, keys, combo, nodes, models, cache, compression, cost, usage, quota, health, resilience, telemetry, logs, audit, mcp, a2a, cloud, memory, skills, eval, doctor, repl, tunnel, backup, sync, webhooks, policy, pricing, translator, simulate and more.">
|
||||
<desc>Compact animated terminal cycling three real OmniRoute CLI commands with a typewriter effect and a scrolling subcommand ticker; the first frame shows the completed providers-list screen.</desc>
|
||||
<defs><clipPath id="tickerClip"><rect x="12" y="304" width="1176" height="40"/></clipPath><clipPath id="tw0"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;31;61;92;122;153;184;214;245;245" keyTimes="0;0.012;0.018;0.024;0.030;0.036;0.042;0.048;0.054;1" dur="18s" repeatCount="indefinite"/></rect></clipPath><clipPath id="tw1"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;26;51;76;102;128;153;178;204;204" keyTimes="0;0.348;0.351;0.357;0.363;0.369;0.375;0.381;0.387;1" dur="18s" repeatCount="indefinite"/></rect></clipPath><clipPath id="tw2"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;20;41;61;82;102;122;143;163;163" keyTimes="0;0.678;0.684;0.690;0.696;0.702;0.708;0.714;0.720;1" dur="18s" repeatCount="indefinite"/></rect></clipPath></defs>
|
||||
<rect width="1200" height="350" fill="#0d1117"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 780" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Comparison table: OmniRoute versus 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute is the only one with the full set: 354 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 110 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 43 UI locales and 100% MIT self-hosted. 9router has free providers, RTK compression and translation but no MCP, A2A, memory, guardrails, cloud agents or stealth. OpenRouter is a hosted SaaS with 400+ models, guardrails and a hosted MCP but is not self-hosted and lacks A2A, memory, cloud agents and stealth. CLIProxyAPI is a light OAuth proxy with two routing strategies. LiteLLM has 100+ providers, A2A and extensive guardrails but no memory, compression, free tier, stealth or cloud agents.">
|
||||
<svg viewBox="0 0 1200 780" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Comparison table: OmniRoute versus 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute is the only one with the full set: 357 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 110 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 43 UI locales and 100% MIT self-hosted. 9router has free providers, RTK compression and translation but no MCP, A2A, memory, guardrails, cloud agents or stealth. OpenRouter is a hosted SaaS with 400+ models, guardrails and a hosted MCP but is not self-hosted and lacks A2A, memory, cloud agents and stealth. CLIProxyAPI is a light OAuth proxy with two routing strategies. LiteLLM has 100+ providers, A2A and extensive guardrails but no memory, compression, free tier, stealth or cloud agents.">
|
||||
<desc>Static-header comparison table where each capability row fades in top to bottom; the OmniRoute column is highlighted and shows a check or a leading value in every row, while competitors show a mix of checks, partials and crosses.</desc>
|
||||
<defs>
|
||||
<pattern id="gC" width="32" height="32" patternUnits="userSpaceOnUse"><path d="M 32 0 L 0 0 0 32" fill="none" stroke="#ffffff" stroke-opacity="0.05" stroke-width="1"/></pattern>
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint and 354 providers. Six pillars. Resilient fallback: automatic routing continues while another healthy target is available. Save up to 95 percent of eligible tokens: RTK plus Caveman stacked compression averages about 89 percent on tool-heavy sessions. Zero dollars to start: 90+ providers with a free tier and 56 recurring or keyless free-forever providers. Every tool works: 35 CLI and agent integration records, including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity, through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation at /v1. Production controls: circuit breakers, TLS stealth, MCP with 110 tools, A2A, memory, guardrails, evals, and 39,000+ static test declarations across 5,100+ tracked test files.">
|
||||
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint and 357 providers. Six pillars. Resilient fallback: automatic routing continues while another healthy target is available. Save up to 95 percent of eligible tokens: RTK plus Caveman stacked compression averages about 89 percent on tool-heavy sessions. Zero dollars to start: 90+ providers with a free tier and 56 recurring or keyless free-forever providers. Every tool works: 35 CLI and agent integration records, including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity, through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation at /v1. Production controls: circuit breakers, TLS stealth, MCP with 110 tools, A2A, memory, guardrails, evals, and 39,000+ static test declarations across 5,100+ tracked test files.">
|
||||
<desc>Animated promise card: six pillar tiles fade in in reading order, then a soft colored border highlight sweeps from tile to tile in a continuous cycle.</desc>
|
||||
<defs>
|
||||
<pattern id="gridPaperP" width="32" height="32" patternUnits="userSpaceOnUse">
|
||||
@@ -21,7 +21,7 @@
|
||||
<line x1="150" y1="53" x2="1160" y2="53" stroke="#232b38" stroke-width="1.5"/>
|
||||
</g>
|
||||
<g>
|
||||
<text x="40" y="100" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="23" font-weight="600" fill="#c9d1d9">One endpoint. <tspan fill="#a78bfa" font-weight="800">354 providers.</tspan> Never stop building — OmniRoute picks <tspan fill="#7ee787" font-weight="700">the cheapest one that works</tspan>.</text>
|
||||
<text x="40" y="100" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="23" font-weight="600" fill="#c9d1d9">One endpoint. <tspan fill="#a78bfa" font-weight="800">357 providers.</tspan> Never stop building — OmniRoute picks <tspan fill="#7ee787" font-weight="700">the cheapest one that works</tspan>.</text>
|
||||
</g>
|
||||
|
||||
<g font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif">
|
||||
@@ -38,7 +38,7 @@
|
||||
<line x1="3.9" y1="3.9" x2="18.1" y2="18.1"/>
|
||||
</g>
|
||||
<text x="102" y="170" font-size="18" font-weight="800" fill="#74b9ff">Never hit limits</text>
|
||||
<text x="66" y="204" font-size="13.5" fill="#a1a1aa">Auto-fallback across 354 providers in</text>
|
||||
<text x="66" y="204" font-size="13.5" fill="#a1a1aa">Auto-fallback across 357 providers in</text>
|
||||
<text x="66" y="226" font-size="13.5" fill="#a1a1aa">milliseconds. Quota out? The next provider</text>
|
||||
<text x="66" y="248" font-size="13.5" fill="#a1a1aa">takes over while a healthy target remains.</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 548" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OmniRoute hero: Never stop coding. Every AI tool to 354 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot and Antigravity into free Claude, GPT and Gemini with auto-fallback. RTK + Caveman stacked compression saves 15 to 95 percent of tokens — about 89 percent average on tool-heavy sessions — so you never hit limits. Stats: 354 AI providers, 90+ free tiers, about 1.51B free tokens per month, 15 to 95 percent token savings, 19 routing strategies, zero dollars to start.">
|
||||
<svg viewBox="0 0 1200 548" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OmniRoute hero: Never stop coding. Every AI tool to 357 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot and Antigravity into free Claude, GPT and Gemini with auto-fallback. RTK + Caveman stacked compression saves 15 to 95 percent of tokens — about 89 percent average on tool-heavy sessions — so you never hit limits. Stats: 357 AI providers, 90+ free tiers, about 1.51B free tokens per month, 15 to 95 percent token savings, 19 routing strategies, zero dollars to start.">
|
||||
<desc>Animated hero card: a pulse travels the divider line and a compression bar demo repeatedly shrinks a prompt by up to 95 percent; all headline content is static and readable on the first frame.</desc>
|
||||
<defs>
|
||||
<pattern id="gridPaperH" width="32" height="32" patternUnits="userSpaceOnUse">
|
||||
@@ -28,7 +28,7 @@
|
||||
<text x="48" y="138" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="60" font-weight="800" fill="#e9edf3">Never stop coding<tspan fill="#a855f7">.</tspan></text>
|
||||
|
||||
<!-- subheadline -->
|
||||
<text x="48" y="184" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="25" font-weight="600" fill="#c9d1d9">Every AI tool → <tspan fill="#a78bfa" font-weight="800">354 providers</tspan> — <tspan fill="#7ee787" font-weight="800">90+ free</tspan> — through one endpoint.</text>
|
||||
<text x="48" y="184" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="25" font-weight="600" fill="#c9d1d9">Every AI tool → <tspan fill="#a78bfa" font-weight="800">357 providers</tspan> — <tspan fill="#7ee787" font-weight="800">90+ free</tspan> — through one endpoint.</text>
|
||||
|
||||
<!-- plug line -->
|
||||
<text x="48" y="222" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="16.5" fill="#a1a1aa">Claude Code · Codex · Cursor · Cline · Copilot · Antigravity  →  <tspan fill="#7ee787" font-weight="700">FREE</tspan> Claude / GPT / Gemini · auto-fallback</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
@@ -57,7 +57,7 @@ New tab for extracting content from a URL via `POST /v1/web/fetch` (created in p
|
||||
- Submit → fetch → render `ScrapeResult.tsx`.
|
||||
- `ScrapeResult` renders markdown preview + raw toggle.
|
||||
- Cap: if response body > **256 KB**, UI shows `(truncated, view raw)` and opens raw in a Monaco modal (D21).
|
||||
- Metadata panel: provider (firecrawl/jina-reader/tavily-search/tinyfish/nimble-search), latency, cost, response size, links count.
|
||||
- Metadata panel: provider (firecrawl/jina-reader/tavily-search/tinyfish/nimble-search/anysearch-search), latency, cost, response size, links count.
|
||||
- Uses `useScrapeFetch.ts` hook.
|
||||
|
||||
### Compare Tab
|
||||
@@ -105,15 +105,7 @@ Runs the same query/URL across up to **4 providers in parallel** (D22):
|
||||
`ProviderCatalog.tsx` exposes the full provider list from `GET /api/search/providers`
|
||||
(extended in F4 to include fetch providers):
|
||||
|
||||
| Field | Source |
|
||||
| ------------------------------ | ------------------------------------------------------------------------------------------ |
|
||||
| `id`, `name` | `searchRegistry.ts` |
|
||||
| `kind` | `"search"` or `"fetch"` (firecrawl, jina-reader, tavily-search, tinyfish, nimble-search) |
|
||||
| `costPerQuery` | Registry data |
|
||||
| `freeMonthlyQuota` | Registry data |
|
||||
| `searchTypes` / `fetchFormats` | Registry data |
|
||||
| `status` | `"configured"` / `"missing"` / `"rate_limited"` — derived at runtime from credential store |
|
||||
| `configureHref` | `/dashboard/providers` |
|
||||
| `kind` | `"search"` (20 providers) or `"fetch"` (firecrawl, jina-reader, tavily-search, tinyfish, nimble-search, anysearch-search) |
|
||||
|
||||
The status is **derived at request time** by checking whether credentials exist and whether
|
||||
all keys are currently in cooldown.
|
||||
@@ -136,7 +128,7 @@ Only one backend change was needed for this feature:
|
||||
|
||||
`src/app/api/search/providers/route.ts` was extended to:
|
||||
|
||||
- Include every fetch provider (`firecrawl`, `jina-reader`, `tavily-search`, `tinyfish`, `nimble-search`) in the array.
|
||||
- Include all 6 fetch providers (`firecrawl`, `jina-reader`, `tavily-search`, `tinyfish`, `nimble-search`, `anysearch-search`) in the array.
|
||||
- Add `kind: "search" | "fetch"` to every item.
|
||||
- Add `status: "configured" | "missing" | "rate_limited"` derived from live credential state.
|
||||
- Maintain backward compatibility — existing fields (`id`, `name`, etc.) unchanged.
|
||||
|
||||
@@ -226,16 +226,21 @@ Three build args control what the `builder` stage costs. They are build-time onl
|
||||
| --------------------------- | ------- | ----------------------------------------------------------------------------------- |
|
||||
| `OMNIROUTE_USE_TURBOPACK` | `1` | `0` builds with webpack instead. Lower peak memory, slower. |
|
||||
| `OMNIROUTE_BUILD_MEMORY_MB` | `6144` | V8 heap ceiling (`--max-old-space-size`) for the spawned `next build`. |
|
||||
| `OMNIROUTE_BUILD_WORKERS` | `3` | Feeds `CIRCLE_NODE_TOTAL`; Next derives `workers = N - 1` for page-data collection. |
|
||||
| `OMNIROUTE_BUILD_WORKERS` | `2` | Feeds `CIRCLE_NODE_TOTAL`; Next derives `workers = N - 1` for page-data collection. |
|
||||
|
||||
`OMNIROUTE_BUILD_WORKERS` is the one to raise on a big builder and the one to
|
||||
suspect when a constrained build dies **after** `✓ Compiled successfully`. Each
|
||||
page-data worker is its own process and inherits `NODE_OPTIONS`, so the heap
|
||||
ceiling is per process, not per build: the default of `3` (→ 2 workers) is sized
|
||||
for the 16 GB / 4 vCPU GitHub-hosted runners the publish pipeline uses. At `8`
|
||||
(→ 7 workers) that runner ran out of memory and buildkit failed the step with
|
||||
`ResourceExhausted: ... cannot allocate memory`. `tests/unit/docker-build-memory-budget.test.ts`
|
||||
does the arithmetic and fails if either knob outgrows the runner.
|
||||
page-data worker is its own process, and so is the parent `next build` itself;
|
||||
a live VPS reproduction (issue #7518) measured each process's peak RSS at
|
||||
~4.5 GB independent of the `NODE_OPTIONS` heap flag (Turbopack compiles in
|
||||
native/Rust memory outside the V8 heap). The default of `2` (→ 1 worker, 2
|
||||
processes total) is sized for the 16 GB / 4 vCPU GitHub-hosted runners the
|
||||
publish pipeline uses. At `8` (→ 7 workers) that runner ran out of memory and
|
||||
buildkit failed the step with `ResourceExhausted: ... cannot allocate memory`;
|
||||
`3` (→ 2 workers) still didn't fit once the per-process RSS was measured
|
||||
directly instead of inferred. `tests/unit/docker-build-memory-budget.test.ts`
|
||||
does the arithmetic against the measured figure and fails if either knob
|
||||
outgrows the runner.
|
||||
|
||||
Turbopack compiles in native Rust memory that lives **outside** the V8 heap, so
|
||||
`OMNIROUTE_BUILD_MEMORY_MB` does not bound it. On a host with a memory ceiling the
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -1199,6 +1199,8 @@ paths:
|
||||
Searches the web, news, or X through a configured provider. Set `provider`
|
||||
to `xquik-search` to use Xquik for X search. The aliases `xquik` and
|
||||
`xquik_search` resolve to the same provider.
|
||||
AnySearch (`anysearch-search`, aliases `anysearch` / `anysearch_search`)
|
||||
provides free fallback-only web search.
|
||||
security:
|
||||
- BearerAuth: []
|
||||
requestBody:
|
||||
|
||||
45
docs/plans/11690-anysearch-provider-integration.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# AnySearch provider integration (PR #11690)
|
||||
|
||||
Template: xquik #11370 (merged in release/v3.8.51). Posture: `fallbackOnly`.
|
||||
Upstream proposal: issue diegosouzapw/OmniRoute#11637.
|
||||
|
||||
## 1. Service ground truth (official docs, cross-checked)
|
||||
|
||||
- Base URL: `https://api.anysearch.com` (REST) + `POST /mcp` (MCP, JSON-RPC 2.0).
|
||||
- `POST /v1/search` - params: `query` (required), `max_results` (1-10, default 10), `tag` (`{domain}.{sub_domain}` vertical routing), `zone` (cn/intl), `language`, `params` (structured vertical fields), `format` (json/markdown).
|
||||
- `GET /v1/sub-domains?domain=...` - capability catalog, does NOT count against quota.
|
||||
- `POST /v1/extract` - fetch/extract `{url, title, content}`; strict JSON body, 16 KiB cap.
|
||||
- `POST /v1/auth/email/register` - single-call registration, returns one-time plaintext key `as_sk_...`.
|
||||
- Auth: optional `Authorization: Bearer <as_sk_...>`; anonymous degrades to per-IP limits consuming the daily free quota; invalid key returns 401/403 with NO silent anonymous fallback.
|
||||
- Free tier: 1000 requests/day, 20 QPS per key. Paid tier: unpriced (Coming Soon).
|
||||
- Response envelope: success `{code: 0, message: "success", request_id, data}`; failure `{code: -1, message}`. Auth/quota errors carry no structured `error_code` (the message text is the signal); extract-specific errors do carry `error_code` (`invalid_extract_url`, `extract_failed`). No `Retry-After` header on 429.
|
||||
|
||||
## 2. Touch set (~10 layers, mirrors the xquik footprint)
|
||||
|
||||
| Layer | File | Change |
|
||||
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| Registry entry | `open-sse/config/searchRegistry.ts` | `anysearch-search` entry + aliases `anysearch`, `anysearch_search` |
|
||||
| Executor | `open-sse/handlers/search/anysearchSearch.ts` | `buildAnysearchSearchRequest`, `normalizeAnysearchSearchResponse`, `AnysearchSearchEnvelopeError` |
|
||||
| Dispatch maps | `open-sse/handlers/search.ts` + `searchProxy.ts` | request-builder map + response-normalizer map; envelope error -> 402 (quota) / 502 (other) |
|
||||
| Fetch executor | `open-sse/executors/anysearch-fetch.ts` + `open-sse/handlers/webFetch.ts` | `POST /v1/extract`; union + `WEB_FETCH_PROVIDERS` + dispatch case; quota envelope -> 402 |
|
||||
| UI catalog | `src/shared/constants/providers/search.ts` | metadata entry (`serviceKinds: ["webSearch", "webFetch"]`); authHint documents the 1000/day free tier |
|
||||
| Credential validation | `src/lib/providers/validation/searchProviders.ts` | `SEARCH_VALIDATOR_CONFIGS["anysearch-search"]` (Bearer probe) |
|
||||
| MCP | `open-sse/mcp-server/schemas/tools.ts` | fetch enum + web_search description |
|
||||
| API schema | `src/shared/validation/schemas/apiV1.ts`, `docs/openapi.yaml` | alias canonicalization + provider enum |
|
||||
| Docs | `docs/reference/PROVIDER_REFERENCE.md`, `docs/frameworks/SEARCH_TOOLS_STUDIO.md`, `changelog.d/features/anysearch-search-provider.md` | consistency copies |
|
||||
| Tests | `tests/unit/anysearch-search-provider.test.ts` (8 cases), `tests/unit/executor-anysearch-fetch.test.ts` (2 cases), `search-registry.test.ts`, `search-route.test.ts`, `tests/integration/search-providers-catalog.test.ts`, `tests/snapshots/executors/dispatch-rules.json` | mirror xquik suite; catalog counts 20 search / 6 fetch (coexisting with nimble-search) |
|
||||
|
||||
## 3. Decisions (all reached 2026-08-26)
|
||||
|
||||
1. **Routing posture: `fallbackOnly`.** Rationale: a cost-0 free provider must never dominate automatic cost routing; explicit selection and failover return are unaffected. Precedent: merged xquik entry.
|
||||
2. **Scope: webSearch + webFetch via `POST /v1/extract` in v1.** Aligned with the tavily/exa dual-capability mental model. Vertical surfaces (`tag`, `sub-domains`, `batch_search`) stay out of scope — there is no IR for vertical params today.
|
||||
3. **Quota display: `freeMonthlyQuota: 0`** (xquik-style conservative display). The real allowance (1000 req/day, daily reset) is carried in the UI catalog `authHint` copy instead. Rationale: quota display must match reset semantics; converting a daily cap to a monthly-equivalent (30000) is a false promise the UI cannot honor.
|
||||
4. **searchTypes: `["web"]` only.** No public evidence of a news/images vertical in the AnySearch API; gateways integrating APIs without a documented vertical (e.g. Google Custom Search) expose web only rather than silently mapping news -> web.
|
||||
5. **Key posture:** keyless works; an invalid key returns 401/403 and is never silently downgraded to anonymous (mirrors the upstream contract).
|
||||
6. **Deliberate exclusions:** `FETCH_BACKEND_TO_PROVIDER` / `FetchInterceptionBackend` (chat interception stays firecrawl/jina/tavily); `ANONYMOUS_CAPABLE_WEB_FETCH_PROVIDERS` (anonymous remote endpoints share one IP-limited pool per egress IP, so keyless extract is opt-in, not an auto-routing candidate); `QUOTA_STATUS_PROVIDERS` (AnySearch signals quota via 429/envelope, not 402/403 status).
|
||||
|
||||
## 4. References
|
||||
|
||||
- xquik template: commit a0ceccc, PR #11370 (in-tree at release/v3.8.51).
|
||||
- AnySearch official docs: https://anysearch.com/docs, https://anysearch.com/pricing; MCP catalog mcpservers.org/servers/anysearch-ai/anysearch-mcp-server; skill repo github.com/anysearch-ai/anysearch-skill.
|
||||
- Industry mental model: LiteLLM search docs (registry + unified search() + Perplexity-spec IR), open-webui web search (built-in providers, search_web/fetch_url dual tools), Dify tool plugin pattern; cost-fallback ladder: self-hosted -> free quota -> paid.
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
title: "Provider Reference"
|
||||
version: 3.8.51
|
||||
lastUpdated: 2026-08-26
|
||||
lastUpdated: 2026-08-27
|
||||
---
|
||||
|
||||
# Provider Reference
|
||||
|
||||
> **Auto-generated** from `src/shared/constants/providers.ts` — do not edit by hand.
|
||||
> Regenerate with: `npm run gen:provider-reference`
|
||||
> **Last generated:** 2026-08-26
|
||||
> **Last generated:** 2026-08-27
|
||||
|
||||
Total providers: **354**. See category breakdown below.
|
||||
Total providers: **357**. See category breakdown below.
|
||||
|
||||
## Categories
|
||||
|
||||
@@ -122,7 +122,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
| `zai-web` | `zw` | Z.ai Web | Web cookie | [link](https://chat.z.ai) | Copy the "token" value from chat.z.ai → DevTools → Application → Local Storage. Do not copy cookies; OmniRoute handles the per-request CAPTCHA through its browser transport. | — |
|
||||
| `zenmux-free` | `zmf` | ZenMux Free (Web) | Web cookie | [link](https://zenmux.ai) | Login at zenmux.ai, then export all cookies using EditThisCookie or Cookie-Editor and paste the full Cookie header string here. Refresh every ~30 days. | — |
|
||||
|
||||
## API Key Providers (paid / paid-with-free-credits) (234)
|
||||
## API Key Providers (paid / paid-with-free-credits) (235)
|
||||
|
||||
| ID | Alias | Name | Tags | Website | Notes |
|
||||
|----|-------|------|------|---------|-------|
|
||||
@@ -277,6 +277,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
| `oci` | `oci` | OCI Generative AI | API key, enterprise | [link](https://www.oracle.com/artificial-intelligence/generative-ai) | Use your OCI Generative AI API key or IAM bearer token. Base URL can be https://inference.generativeai.<region>.oci.oraclecloud.com/openai/v1/. |
|
||||
| `ofoxai` | `ofoxai` | OfoxAI | API key, aggregator | [link](https://ofox.ai) | The current catalog advertises 10+ free models without a public numeric quota; review upstream provenance, retention and training terms before production use. |
|
||||
| `ollama-cloud` | `ollamacloud` | Ollama Cloud | API key | [link](https://ollama.com/settings/keys) | — |
|
||||
| `oneminai` | `1min` | 1min.AI | API key | [link](https://1min.ai) | Create an API key at https://docs.1min.ai/docs/api/create-api-key, then paste it here. |
|
||||
| `openadapter` | `oad` | OpenAdapter | API key | [link](https://openadapter.dev) | Use your OpenAdapter API key in Authorization: Bearer sk-cv-<key>. Fully OpenAI-compatible. API base URL: https://api.openadapter.in/v1. |
|
||||
| `openai` | `openai` | OpenAI | API key | [link](https://platform.openai.com) | — |
|
||||
| `opencode-go` | `opencode-go` | OpenCode Go | API key | [link](https://opencode.ai/go) | — |
|
||||
@@ -380,10 +381,11 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
| `vllm` | `vllm` | vLLM | Local, self-hosted | [link](https://github.com/vllm-project/vllm) | API key optional. Configure the local vLLM OpenAI-compatible base URL (default: http://localhost:8000/v1). |
|
||||
| `xinference` | `xinference` | XInference | Local, self-hosted | [link](https://inference.readthedocs.io) | API key optional. Configure the local XInference OpenAI-compatible base URL (default: http://localhost:9997/v1). |
|
||||
|
||||
## Search Providers (16)
|
||||
## Search Providers (17)
|
||||
|
||||
| ID | Alias | Name | Tags | Website | Notes |
|
||||
|----|-------|------|------|---------|-------|
|
||||
| `anysearch-search` | `anysearch` | AnySearch | Search | [link](https://anysearch.com) | Optional API key from anysearch.com (as_sk_...) - free 1000/day; keyless tier has lower limits |
|
||||
| `brave-search` | `brave-search` | Brave Search | Search | [link](https://brave.com/search/api) | Subscription token from Brave Search API dashboard |
|
||||
| `context7` | `context7` | Context7 (library docs) | Search | [link](https://context7.com) | API key optional (ctx7sk-...) — anonymous tier works without a key; a key raises the rate limit |
|
||||
| `exa-search` | `exa-search` | Exa Search | Search | [link](https://exa.ai) | API key from dashboard.exa.ai |
|
||||
@@ -443,7 +445,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
|
||||
- Catalog: [`src/shared/constants/providers.ts`](../../src/shared/constants/providers.ts)
|
||||
- Registry (per-model details): [`open-sse/config/providerRegistry.ts`](../../open-sse/config/providerRegistry.ts)
|
||||
- Executors: [`open-sse/executors/`](../../open-sse/executors/) (110 implementations)
|
||||
- Executors: [`open-sse/executors/`](../../open-sse/executors/) (112 implementations)
|
||||
- Translators: [`open-sse/translator/`](../../open-sse/translator/)
|
||||
|
||||
## See Also
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
title: "Guardrails"
|
||||
version: 3.8.50
|
||||
lastUpdated: 2026-08-24
|
||||
version: 3.8.51
|
||||
lastUpdated: 2026-08-27
|
||||
---
|
||||
|
||||
# Guardrails
|
||||
|
||||
> **Source of truth:** `src/lib/guardrails/`
|
||||
> **Last updated:** 2026-08-24 — v3.8.50 (Video Bridge visual dedup hardening + focused captions)
|
||||
> **Last updated:** 2026-08-27 — v3.8.51 (Video Bridge transcript-retention boundary)
|
||||
|
||||
Guardrails enforce safety, policy, and content transformations at the boundary
|
||||
between OmniRoute and upstream providers. Each guardrail can inspect (and
|
||||
@@ -439,6 +439,69 @@ are rendered as untrusted observations alongside the frame captions. Invalid,
|
||||
out-of-range, or provenance-free text is rejected rather than mixed into the
|
||||
caption stream.
|
||||
|
||||
#### Transcript retention boundary
|
||||
|
||||
Transcript text remains available to the live bridge and upstream request, but it is not retained
|
||||
by OmniRoute's logging and memory surfaces. `videoTranscriptLogRedaction.ts` recognizes
|
||||
`transcript` and `audioTranscript` only inside supported video carriers. A field with either name
|
||||
in an ordinary tool argument or application object is preserved, and delimiter-shaped caller
|
||||
prose is not trusted as a bridge result.
|
||||
|
||||
When the Video Bridge produces a description containing validated cues, it emits only a
|
||||
SHA-256/length identity in guardrail metadata. The request pipeline accepts those identities only
|
||||
from a successful, payload-modifying `video-bridge` result and uses them to omit the exact generated
|
||||
description segment after translation or concatenation. Raw transcript text is never placed in the
|
||||
metadata.
|
||||
|
||||
The retention policy covers raw, converted, and provider request logs; provider and client response
|
||||
bodies; detailed pipeline artifacts; call logs, active/pending usage, rejected requests, proxy/error
|
||||
diagnostics, SSE chunks, and Memory extraction. Response bodies and stream chunks for a sensitive
|
||||
request are omitted because an upstream may echo request text. Safe operational metadata such as
|
||||
status, timing, provider, model, headers-presence, token counts, and the fact that redaction occurred
|
||||
remains available. The constant retained marker is `[omitted: video transcript]`.
|
||||
|
||||
Sensitivity is resolved before the guardrail chain from the original client body and resolved again
|
||||
after the chain from the original body, processed body, and trusted description identities. A
|
||||
guardrail that removes or replaces the raw carrier therefore cannot clear the request-scoped bit.
|
||||
Explicit video parts remain sensitive when malformed, and nested carrier objects are inspected under
|
||||
the same bounds. Rejected-request persistence also inspects the body itself, so forgetting to pass the
|
||||
bit at one caller does not expose a raw carrier.
|
||||
|
||||
The request-scoped bit protects OmniRoute-owned application paths in addition to structured payload
|
||||
clones. Native priority, round-robin, pinned, and fusion diagnostics; quality-rejection and live-event
|
||||
logs; terminal combo errors; proxy fast-fail logs; guardrail-registry logs; plugin-dispatcher failure
|
||||
logs; and stream lifecycle callbacks retain only the constant marker when their detail could echo the
|
||||
request. A request-scoped executor logger keeps the diagnostic tag but replaces arbitrary executor
|
||||
messages with the marker and drops attached metadata before those values reach the application
|
||||
logger. Context Relay and Universal Handoff summaries are still generated from a sanitized clone:
|
||||
safe adjacent conversation context remains available while recognized carriers and trusted generated
|
||||
descriptions are omitted. Memory may likewise extract safe request-derived text from the sanitized
|
||||
copy, but response-derived Memory extraction is skipped because an upstream response may echo the
|
||||
transcript. Daily-quota classification still inspects the original upstream error, while sensitive
|
||||
requests use the server-resolved model as the retained lockout key instead of promoting a model token
|
||||
parsed from that diagnostic. These rules affect retained copies, not the live provider request or the
|
||||
functional response returned to the same client.
|
||||
|
||||
Inspection is bounded by depth, aggregate entries, trusted identities, description-prefix
|
||||
occurrences, candidate hashes, and total hashed text. Cycles and binary views are handled without
|
||||
retaining their contents. If a bound is exceeded, or an enumerable getter/proxy throws during
|
||||
inspection, the retained copy fails closed to the omission marker; the live request is not changed.
|
||||
|
||||
Privacy-redacted Responses artifacts cannot reconstruct the omitted transcript portion of
|
||||
`previous_response_id` history. `responsesContinuationStore.ts` therefore reuses only valid,
|
||||
non-truncated retained `input` and `output` arrays, including the explicit omission marker, and never
|
||||
attempts to restore raw transcript text from the pipeline marker. This preserves continuation for the
|
||||
safe portions of the turn while making the missing private segment visible; a client that needs that
|
||||
context again must submit it as part of a new live request.
|
||||
|
||||
Custom guardrails and plugins are privileged, in-process processors: they intentionally receive the
|
||||
live payload so they can inspect, transform, or block it. OmniRoute supplies the server-owned
|
||||
`videoTranscriptSensitive` bit, wraps `GuardrailContext.log`, and protects errors emitted by its native
|
||||
plugin dispatcher. It cannot control a third-party processor that independently writes the live body
|
||||
to `console`, a file, a database, or the network. Operators must audit such code and treat its own
|
||||
sinks as outside the OmniRoute-owned retention boundary; clearing or ignoring the bit does not make
|
||||
the transcript safe to persist.
|
||||
|
||||
An advanced caller may provide an already-authorized `audioTranscript` track
|
||||
for the same video. The fusion seam runs visual and audio observations under
|
||||
one deadline and abort signal, orders them on a common timeline, collapses
|
||||
|
||||
6
llm.txt
@@ -1,6 +1,6 @@
|
||||
# OmniRoute
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 354 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 357 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -277,7 +277,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **354 AI providers** with automatic format translation
|
||||
- **357 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -475,7 +475,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **354-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **357-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -370,6 +370,26 @@ export const SEARCH_PROVIDERS: Record<string, SearchProviderConfig> = {
|
||||
cacheTTLMs: 5 * 60 * 1000,
|
||||
fallbackOnly: true,
|
||||
},
|
||||
|
||||
// Free public web search for AI agents (https://anysearch.com). fallback-only:
|
||||
// a cost-0 provider never overrides configured paid providers in automatic
|
||||
// selection. max_results is capped at 10 upstream.
|
||||
"anysearch-search": {
|
||||
id: "anysearch-search",
|
||||
name: "AnySearch",
|
||||
baseUrl: "https://api.anysearch.com/v1/search",
|
||||
method: "POST",
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
costPerQuery: 0,
|
||||
freeMonthlyQuota: 0, // free tier is 1000 req/day (daily reset, not monthly) — 0 matches the xquik convention; the daily figure lives in the UI catalog authHint
|
||||
searchTypes: ["web"],
|
||||
defaultMaxResults: 5,
|
||||
maxMaxResults: 10,
|
||||
timeoutMs: 10_000,
|
||||
cacheTTLMs: 5 * 60 * 1000,
|
||||
fallbackOnly: true,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -419,6 +439,8 @@ export const SEARCH_PROVIDER_ALIASES: Record<string, string> = {
|
||||
x: "x-search",
|
||||
xquik: "xquik-search",
|
||||
xquik_search: "xquik-search",
|
||||
anysearch: "anysearch-search",
|
||||
anysearch_search: "anysearch-search",
|
||||
};
|
||||
|
||||
export function resolveSearchProviderId(providerId: string): string {
|
||||
|
||||
109
open-sse/executors/anysearch-fetch.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* AnySearch Web Fetch Executor
|
||||
*
|
||||
* Fetches readable content from a URL using the AnySearch Extract API.
|
||||
* POST https://api.anysearch.com/v1/extract
|
||||
*
|
||||
* Free tier: 1000 requests/day per key, shared with /v1/search. Bearer auth
|
||||
* is optional upstream - keyless calls use the lower anonymous tier. Routing
|
||||
* stays key-gated; anonymity only applies at call time.
|
||||
* Docs: https://anysearch.com/docs
|
||||
*/
|
||||
|
||||
import { sanitizeErrorMessage, buildErrorBody } from "../utils/error.ts";
|
||||
import type { WebFetchResult, WebFetchFormat, WebFetchCredentials } from "../handlers/webFetch.ts";
|
||||
|
||||
const ANYSEARCH_EXTRACT_URL = "https://api.anysearch.com/v1/extract";
|
||||
const ANYSEARCH_TIMEOUT_MS = 30_000;
|
||||
|
||||
interface AnysearchFetchOptions {
|
||||
url: string;
|
||||
format: WebFetchFormat;
|
||||
includeMetadata: boolean;
|
||||
credentials: WebFetchCredentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an AnySearch extract request.
|
||||
* The upstream contract is strict JSON: a single { url } object with no
|
||||
* unknown fields, capped at 16 KiB - do not add request fields here.
|
||||
*/
|
||||
export async function anysearchFetch(opts: AnysearchFetchOptions): Promise<WebFetchResult> {
|
||||
// format is accepted but unused: AnySearch extract always returns markdown-ish text
|
||||
// (mirroring the context7 pattern of accepting the field without rejecting).
|
||||
const { url, includeMetadata, credentials } = opts;
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => {
|
||||
const err = new Error(`anysearch-fetch timeout after ${ANYSEARCH_TIMEOUT_MS}ms`);
|
||||
err.name = "TimeoutError";
|
||||
controller.abort(err);
|
||||
}, ANYSEARCH_TIMEOUT_MS);
|
||||
|
||||
try {
|
||||
const response = await fetch(ANYSEARCH_EXTRACT_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(credentials.apiKey ? { Authorization: `Bearer ${credentials.apiKey}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({ url }),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const rawError = await response.text().catch(() => `HTTP ${response.status}`);
|
||||
const msg = sanitizeErrorMessage(`AnySearch error ${response.status}: ${rawError}`);
|
||||
const body = buildErrorBody(response.status, msg);
|
||||
return { success: false, status: response.status, error: body.error.message };
|
||||
}
|
||||
|
||||
const data = (await response.json()) as Record<string, unknown>;
|
||||
|
||||
// Envelope: { code, message, data: { url, title, content } } - tolerate the
|
||||
// enveloped and flat shapes before giving up.
|
||||
const envelope =
|
||||
data.data && typeof data.data === "object" && !Array.isArray(data.data)
|
||||
? (data.data as Record<string, unknown>)
|
||||
: data;
|
||||
const code = typeof data.code === "number" ? data.code : 0;
|
||||
if (code !== 0) {
|
||||
const errorMsg = String(data.error_code ?? data.message ?? code);
|
||||
// Quota-shaped envelope errors map to 402 (failover-eligible), mirroring
|
||||
// the search-side AnysearchSearchEnvelopeError → 402 pattern in anysearchSearch.ts.
|
||||
const isQuota = /quota|exceed|limit|balance|credit|exhaust/i.test(errorMsg);
|
||||
const status = isQuota ? 402 : 422;
|
||||
const msg = sanitizeErrorMessage(`AnySearch extract failed: ${errorMsg}`);
|
||||
const body = buildErrorBody(status, msg);
|
||||
return { success: false, status, error: body.error.message };
|
||||
}
|
||||
|
||||
const content = String(envelope.content ?? "");
|
||||
const title = envelope.title != null ? String(envelope.title) : null;
|
||||
|
||||
const metadata = includeMetadata ? { title, description: null } : null;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
provider: "anysearch-search",
|
||||
url,
|
||||
content,
|
||||
links: [],
|
||||
metadata,
|
||||
screenshot_url: null,
|
||||
},
|
||||
};
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof Error && err.name === "AbortError") {
|
||||
const body = buildErrorBody(504, "AnySearch request timed out");
|
||||
return { success: false, status: 504, error: body.error.message };
|
||||
}
|
||||
const msg =
|
||||
err instanceof Error ? sanitizeErrorMessage(err.message) : sanitizeErrorMessage(String(err));
|
||||
const body = buildErrorBody(502, msg);
|
||||
return { success: false, status: 502, error: body.error.message };
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
@@ -179,10 +179,10 @@ export type ProviderCredentials = {
|
||||
};
|
||||
|
||||
export type ExecutorLog = {
|
||||
debug?: (tag: string, message: string) => void;
|
||||
info?: (tag: string, message: string) => void;
|
||||
warn?: (tag: string, message: string) => void;
|
||||
error?: (tag: string, message: string) => void;
|
||||
debug?: (tag: string, message: string, data?: Record<string, unknown> | null) => void;
|
||||
info?: (tag: string, message: string, data?: Record<string, unknown> | null) => void;
|
||||
warn?: (tag: string, message: string, data?: Record<string, unknown> | null) => void;
|
||||
error?: (tag: string, message: string, data?: Record<string, unknown> | null) => void;
|
||||
};
|
||||
|
||||
export type ExecuteInput = {
|
||||
@@ -202,6 +202,10 @@ export type ExecuteInput = {
|
||||
* this to apply client-format-aware policies such as `</think>` close-marker
|
||||
* suppression. */
|
||||
clientResponseFormat?: string | null;
|
||||
/** True when upstream diagnostics may echo a video transcript. Executors must
|
||||
* preserve operational responses/errors while omitting those echoes from
|
||||
* retained logs. */
|
||||
videoTranscriptSensitive?: boolean;
|
||||
/** Callback to persist tokens that are proactively refreshed during execution.
|
||||
* Accepts a partial credentials patch (e.g. `{ accessToken, refreshToken }` or
|
||||
* `{ testStatus: "expired", isActive: false }`); the caller merges into the
|
||||
|
||||
@@ -16,6 +16,7 @@ import { prepareToolMessages, buildToolAwareResult } from "../translator/webTool
|
||||
import type { Session } from "../services/sessionPool/session.ts";
|
||||
import { tryBackedChat } from "../services/browserBackedChat.ts";
|
||||
import { sanitizeErrorMessage } from "../utils/error.ts";
|
||||
import { normalizeSystemRole } from "../services/roleNormalizer.ts";
|
||||
|
||||
// Issue #6999: Lightweight circuit breaker for the DuckDuckGo executor.
|
||||
// After CB_THRESHOLD consecutive failures (429, 5xx, or network errors),
|
||||
@@ -559,8 +560,17 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
// #ddgw defense-in-depth: duckchat/v1/chat accepts only user/assistant roles.
|
||||
// Normalize after catalog resolution so the effective upstream model is used.
|
||||
// This also shields the system tool prompt injected by prepareToolMessages.
|
||||
const normalizedMessages = normalizeSystemRole(
|
||||
messages,
|
||||
"duckduckgo-web",
|
||||
upstreamModel
|
||||
) as typeof messages;
|
||||
|
||||
const sendChat = async (vqdHeaders: DuckDuckGoAuthHeaders): Promise<Response> => {
|
||||
const payload = buildDuckDuckGoPayload(upstreamModel, messages);
|
||||
const payload = buildDuckDuckGoPayload(upstreamModel, normalizedMessages);
|
||||
const response = await fetch(CHAT_URL, {
|
||||
method: "POST",
|
||||
headers: mergeHeadersCaseInsensitive(
|
||||
@@ -786,10 +796,7 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
|
||||
try {
|
||||
return {
|
||||
vqd4: retry.vqd4,
|
||||
vqdHash1: await solveDuckDuckGoChallenge(
|
||||
retry.vqdHash1,
|
||||
FAKE_HEADERS["User-Agent"]
|
||||
),
|
||||
vqdHash1: await solveDuckDuckGoChallenge(retry.vqdHash1, FAKE_HEADERS["User-Agent"]),
|
||||
status: retry.status,
|
||||
retryAfter: retry.retryAfter,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { redactVideoTranscriptSensitiveText } from "../../src/lib/guardrails/videoTranscriptLogRedaction.ts";
|
||||
import type { KeyHealth } from "../services/apiKeyRotator.ts";
|
||||
|
||||
import { DefaultExecutor } from "./default.ts";
|
||||
@@ -45,6 +46,11 @@ function asRecord(value: unknown): JsonRecord | null {
|
||||
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : null;
|
||||
}
|
||||
|
||||
function retainGlmDiagnostic(error: unknown, input: ExecuteInput): string {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
return redactVideoTranscriptSensitiveText(message, input.videoTranscriptSensitive === true);
|
||||
}
|
||||
|
||||
function getEffectiveKey(credentials: ProviderCredentials): string {
|
||||
const extraKeys = (credentials.providerSpecificData?.extraApiKeys as string[] | undefined) ?? [];
|
||||
if (credentials.apiKey && credentials.connectionId && extraKeys.length > 0) {
|
||||
@@ -465,6 +471,7 @@ export class GlmExecutor extends DefaultExecutor {
|
||||
timeoutMs: STREAM_READINESS_TIMEOUT_MS,
|
||||
provider: this.provider,
|
||||
model: input.model,
|
||||
redactUpstreamDiagnosticForLog: input.videoTranscriptSensitive === true,
|
||||
log: input.log,
|
||||
});
|
||||
response = readiness.response;
|
||||
@@ -559,7 +566,7 @@ export class GlmExecutor extends DefaultExecutor {
|
||||
if (!isRetryableGlmFallbackError(error)) throw error;
|
||||
input.log?.debug?.(
|
||||
"GLM_FALLBACK",
|
||||
`${primaryTransport} error (${error instanceof Error ? error.message : String(error)}); trying ${fallbackTransport}`
|
||||
`${primaryTransport} error (${retainGlmDiagnostic(error, input)}); trying ${fallbackTransport}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -572,7 +579,7 @@ export class GlmExecutor extends DefaultExecutor {
|
||||
if (!primaryResult) throw error;
|
||||
input.log?.debug?.(
|
||||
"GLM_FALLBACK",
|
||||
`${fallbackTransport} fallback failed (${error instanceof Error ? error.message : String(error)}); returning primary response`
|
||||
`${fallbackTransport} fallback failed (${retainGlmDiagnostic(error, input)}); returning primary response`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,11 @@ import {
|
||||
runWithCasGuard,
|
||||
} from "../services/tokenRefresh.ts";
|
||||
import { createRequestLogger } from "../utils/requestLogger.ts";
|
||||
import {
|
||||
redactVideoTranscriptSensitiveText,
|
||||
resolveVideoTranscriptLogSensitivity,
|
||||
} from "@/lib/guardrails/videoTranscriptLogRedaction";
|
||||
import { createExecutorRetentionLog } from "./chatCore/executorRetentionLog.ts";
|
||||
import { createPreparedRequestLogger, runWithCapture } from "../utils/providerRequestLogging.ts";
|
||||
import { summarizeToolSources } from "../utils/toolSources.ts";
|
||||
import { applyResponsesPreviousResponseIdPolicy } from "../utils/responsesStatePolicy.ts";
|
||||
@@ -524,7 +529,22 @@ export async function handleChatCore({
|
||||
skipResourcePressureGuard = false,
|
||||
reasoningTransportFallback = "drop",
|
||||
managedLease = null,
|
||||
videoTranscriptSensitive = false,
|
||||
videoTranscriptDescriptionFingerprints = [],
|
||||
}) {
|
||||
videoTranscriptSensitive =
|
||||
videoTranscriptSensitive ||
|
||||
resolveVideoTranscriptLogSensitivity({
|
||||
rawRequestBody: clientRawRequest?.body,
|
||||
processedBody: body,
|
||||
trustedDescriptionFingerprints: videoTranscriptDescriptionFingerprints,
|
||||
});
|
||||
const retainedErrorTextForLog = (error: unknown): string =>
|
||||
redactVideoTranscriptSensitiveText(
|
||||
error instanceof Error ? error.message : String(error),
|
||||
videoTranscriptSensitive
|
||||
);
|
||||
const retainedExecutorLog = createExecutorRetentionLog(log, videoTranscriptSensitive);
|
||||
let { provider, model, extendedContext } = modelInfo;
|
||||
const resilienceSettings = resolveResilienceSettings(cachedSettings);
|
||||
if (!skipResourcePressureGuard) {
|
||||
@@ -637,6 +657,7 @@ export async function handleChatCore({
|
||||
apiKeyInfo,
|
||||
headers: clientRawRequest?.headers,
|
||||
log,
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
if (pluginGate.blocked === true) {
|
||||
return {
|
||||
@@ -721,6 +742,7 @@ export async function handleChatCore({
|
||||
effectiveServiceTier,
|
||||
startTime,
|
||||
log,
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
if (idempotencyHit) {
|
||||
return idempotencyHit;
|
||||
@@ -902,6 +924,8 @@ export async function handleChatCore({
|
||||
stage: "registered",
|
||||
correlationId,
|
||||
sessionTag: conversationId || null,
|
||||
videoTranscriptSensitive,
|
||||
videoTranscriptDescriptionFingerprints,
|
||||
}) || generateRequestId();
|
||||
|
||||
// Initialize rate limit settings from persisted DB (once, lazy)
|
||||
@@ -1034,6 +1058,8 @@ export async function handleChatCore({
|
||||
noLogEnabled,
|
||||
correlationId,
|
||||
modelPinned,
|
||||
videoTranscriptSensitive,
|
||||
videoTranscriptDescriptionFingerprints,
|
||||
// Resolved conversationId (open-sse/services/conversationTracker.ts) wins when
|
||||
// present — it's populated for every request now, not just ones where the
|
||||
// client explicitly sent x-omniroute-session-id. The raw header remains a
|
||||
@@ -1156,8 +1182,17 @@ export async function handleChatCore({
|
||||
model,
|
||||
provider: provider || undefined,
|
||||
connectionId: connectionId || credentials?.connectionId || undefined,
|
||||
videoTranscriptSensitive,
|
||||
videoTranscriptDescriptionFingerprints,
|
||||
});
|
||||
const pendingScope = { id: pendingRequestId, model, provider, connectionId: pendingConnId };
|
||||
const pendingScope = {
|
||||
id: pendingRequestId,
|
||||
model,
|
||||
provider,
|
||||
connectionId: pendingConnId,
|
||||
videoTranscriptSensitive,
|
||||
videoTranscriptDescriptionFingerprints,
|
||||
};
|
||||
const providerRequestCapture = createPreparedRequestLogger(reqLogger, pendingScope);
|
||||
// 0. Log client raw request (before format conversion)
|
||||
if (clientRawRequest) {
|
||||
@@ -1203,6 +1238,7 @@ export async function handleChatCore({
|
||||
apiKeyId: apiKeyInfo?.id ?? undefined,
|
||||
cacheDefaultMode: (apiKeyInfo as { cacheDefaultMode?: "legacy" | "bypass" } | null)
|
||||
?.cacheDefaultMode,
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
if (cacheHit) {
|
||||
return cacheHit;
|
||||
@@ -1482,8 +1518,7 @@ export async function handleChatCore({
|
||||
} catch (err) {
|
||||
log?.debug?.(
|
||||
"COMPRESSION",
|
||||
"Combo compression override lookup skipped: " +
|
||||
(err instanceof Error ? err.message : String(err))
|
||||
"Combo compression override lookup skipped: " + retainedErrorTextForLog(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1492,10 +1527,7 @@ export async function handleChatCore({
|
||||
const { listCompressionCombos } = await import("../../src/lib/db/compressionCombos.ts");
|
||||
namedCombos = buildNamedComboLookup(listCompressionCombos());
|
||||
} catch (err) {
|
||||
log?.debug?.(
|
||||
"COMPRESSION",
|
||||
"Named combos load skipped: " + (err instanceof Error ? err.message : String(err))
|
||||
);
|
||||
log?.debug?.("COMPRESSION", "Named combos load skipped: " + retainedErrorTextForLog(err));
|
||||
}
|
||||
// Phase 3: per-request override. Unknown values fall through in the resolver (never error).
|
||||
const compressionHeader = resolveCompressionHeader(clientRawRequest?.headers ?? null);
|
||||
@@ -1543,8 +1575,7 @@ export async function handleChatCore({
|
||||
} catch (err) {
|
||||
log?.debug?.(
|
||||
"COMPRESSION",
|
||||
"Default compression combo lookup skipped: " +
|
||||
(err instanceof Error ? err.message : String(err))
|
||||
"Default compression combo lookup skipped: " + retainedErrorTextForLog(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1586,10 +1617,7 @@ export async function handleChatCore({
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
log?.debug?.(
|
||||
"COMPRESSION",
|
||||
"Output styles skipped: " + (err instanceof Error ? err.message : String(err))
|
||||
);
|
||||
log?.debug?.("COMPRESSION", "Output styles skipped: " + retainedErrorTextForLog(err));
|
||||
}
|
||||
}
|
||||
const compressionInputBody = body as Record<string, unknown>;
|
||||
@@ -1899,8 +1927,7 @@ export async function handleChatCore({
|
||||
} catch (err) {
|
||||
log?.warn?.(
|
||||
"COMPRESSION",
|
||||
"Compression pipeline error (non-fatal): " +
|
||||
(err instanceof Error ? err.message : String(err))
|
||||
"Compression pipeline error (non-fatal): " + retainedErrorTextForLog(err)
|
||||
);
|
||||
}
|
||||
// --- End Modular Compression Pipeline ---
|
||||
@@ -1954,7 +1981,10 @@ export async function handleChatCore({
|
||||
`Combo context limit: ${resolved.limit} (source=${resolved.source})`
|
||||
);
|
||||
} catch (err) {
|
||||
log?.warn?.("CONTEXT", "Failed to resolve combo limits for compression: " + err);
|
||||
log?.warn?.(
|
||||
"CONTEXT",
|
||||
"Failed to resolve combo limits for compression: " + retainedErrorTextForLog(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2432,13 +2462,21 @@ export async function handleChatCore({
|
||||
try {
|
||||
const { runOnError } = await import("@/lib/plugins/hooks");
|
||||
await runOnError(
|
||||
{ requestId: traceId, body, model, provider, apiKeyInfo, metadata: {} },
|
||||
{
|
||||
requestId: traceId,
|
||||
body,
|
||||
model,
|
||||
provider,
|
||||
apiKeyInfo,
|
||||
metadata: {},
|
||||
videoTranscriptSensitive,
|
||||
},
|
||||
error instanceof Error ? error : new Error(String(error))
|
||||
);
|
||||
} catch (pluginErr) {
|
||||
log?.debug?.(
|
||||
"PLUGIN",
|
||||
`onError hook error (non-fatal): ${pluginErr instanceof Error ? pluginErr.message : String(pluginErr)}`
|
||||
`onError hook error (non-fatal): ${retainedErrorTextForLog(pluginErr)}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2450,7 +2488,13 @@ export async function handleChatCore({
|
||||
const message = error?.message || "Invalid request";
|
||||
const errorType = typeof error?.errorType === "string" ? error.errorType : null;
|
||||
|
||||
log?.warn?.("TRANSLATE", `Request translation failed: ${message}`);
|
||||
log?.warn?.(
|
||||
"TRANSLATE",
|
||||
`Request translation failed: ${redactVideoTranscriptSensitiveText(
|
||||
message,
|
||||
videoTranscriptSensitive
|
||||
)}`
|
||||
);
|
||||
|
||||
if (errorType) {
|
||||
trackPendingRequest(model, provider, connectionId, false);
|
||||
@@ -2544,8 +2588,7 @@ export async function handleChatCore({
|
||||
// must never turn an otherwise valid translated request into a 500.
|
||||
log?.warn?.(
|
||||
"COMPRESSION",
|
||||
"Post-translation OmniGlyph skipped: " +
|
||||
(error instanceof Error ? error.message : String(error))
|
||||
"Post-translation OmniGlyph skipped: " + retainedErrorTextForLog(error)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2839,7 +2882,7 @@ export async function handleChatCore({
|
||||
const resolveExecutorWithProxy = (prov: string) =>
|
||||
resolveExecutorWithProxyFor(
|
||||
prov,
|
||||
log,
|
||||
retainedExecutorLog,
|
||||
(credentials?.providerSpecificData as Record<string, unknown> | null | undefined) ?? null
|
||||
);
|
||||
|
||||
@@ -2861,7 +2904,7 @@ export async function handleChatCore({
|
||||
}).catch((err: unknown): EnforceDecision => {
|
||||
log?.warn?.(
|
||||
"QUOTA_SHARE",
|
||||
`enforceQuotaShare failed; fail-open: ${err instanceof Error ? err.message : String(err)}`
|
||||
`enforceQuotaShare failed; fail-open: ${retainedErrorTextForLog(err)}`
|
||||
);
|
||||
return { kind: "allow" as const };
|
||||
});
|
||||
@@ -2903,7 +2946,7 @@ export async function handleChatCore({
|
||||
// Outer fail-open guard — should not be reached (inner .catch covers it)
|
||||
log?.warn?.(
|
||||
"QUOTA_SHARE",
|
||||
`[quotaShare] enforceQuotaShare unexpected error; fail-open: ${err instanceof Error ? err.message : String(err)}`
|
||||
`[quotaShare] enforceQuotaShare unexpected error; fail-open: ${retainedErrorTextForLog(err)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2915,7 +2958,7 @@ export async function handleChatCore({
|
||||
} catch (err) {
|
||||
log?.warn?.(
|
||||
"QUOTA_SHARE",
|
||||
`[quotaShare] could not set soft penalty on candidate: ${err instanceof Error ? err.message : String(err)}`
|
||||
`[quotaShare] could not set soft penalty on candidate: ${retainedErrorTextForLog(err)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2949,6 +2992,8 @@ export async function handleChatCore({
|
||||
let onPipelineStreamError: streamFailure.PipelineStreamErrorHandler | null = null;
|
||||
let onClientDisconnectFinalize:
|
||||
((event: { reason: string; duration: number }) => boolean) | null = null;
|
||||
const redactStreamDiagnosticsForLog =
|
||||
videoTranscriptSensitive || reqLogger.isVideoTranscriptSensitive();
|
||||
|
||||
// Create stream controller for disconnect detection
|
||||
const streamController = createStreamController({
|
||||
@@ -2980,11 +3025,15 @@ export async function handleChatCore({
|
||||
clientAbortSignal: clientRawRequest?.signal,
|
||||
allowCompletedToolHandoffGrace: isCodexResponsesEcho,
|
||||
clientDisconnectGracePeriodMs: STREAM_DISCONNECT_GRACE_PERIOD_MS,
|
||||
redactStreamDiagnosticsForLog,
|
||||
});
|
||||
|
||||
const dedupRequestBody = { ...translatedBody, model: `${provider}/${model}`, stream };
|
||||
const dedupEnabled = shouldDeduplicate(dedupRequestBody);
|
||||
const dedupHash = dedupEnabled ? computeRequestHash(dedupRequestBody) : null;
|
||||
// Namespaced by the calling API key: dedup hands the SAME response object to
|
||||
// every joiner, so a shared hash across keys is a cross-principal response
|
||||
// leak (GHSA-6c7w-56xp-wpc6).
|
||||
const dedupHash = dedupEnabled ? computeRequestHash(dedupRequestBody, apiKeyInfo?.id) : null;
|
||||
|
||||
const executeProviderRequest = async (modelToCall = effectiveModel, allowDedup = false) => {
|
||||
const execute = async () => {
|
||||
@@ -3109,7 +3158,7 @@ export async function handleChatCore({
|
||||
execCreds?.providerSpecificData
|
||||
),
|
||||
signal: streamController.signal,
|
||||
log,
|
||||
log: retainedExecutorLog,
|
||||
execute: (signal) =>
|
||||
runWithCapture(providerRequestCapture, () =>
|
||||
executor.execute({
|
||||
@@ -3118,7 +3167,7 @@ export async function handleChatCore({
|
||||
stream: upstreamStream,
|
||||
credentials: execCreds,
|
||||
signal,
|
||||
log,
|
||||
log: retainedExecutorLog,
|
||||
extendedContext,
|
||||
upstreamExtraHeaders: buildUpstreamHeadersForExecute(modelToCall),
|
||||
clientHeaders: buildExecutorClientHeaders(
|
||||
@@ -3126,6 +3175,7 @@ export async function handleChatCore({
|
||||
userAgent
|
||||
),
|
||||
clientResponseFormat,
|
||||
videoTranscriptSensitive,
|
||||
onCredentialsRefreshed,
|
||||
skipUpstreamRetry,
|
||||
contextEditing: { enabled: contextEditingEnabled },
|
||||
@@ -3160,7 +3210,7 @@ export async function handleChatCore({
|
||||
invalidateCodexQuotaCache(String(attemptConnectionId));
|
||||
}
|
||||
} catch (err) {
|
||||
const errMessage = err instanceof Error ? err.message : String(err);
|
||||
const errMessage = retainedErrorTextForLog(err);
|
||||
log?.debug?.("CODEX", `Failed to persist codex quota state: ${errMessage}`);
|
||||
}
|
||||
}
|
||||
@@ -3425,7 +3475,7 @@ export async function handleChatCore({
|
||||
execCreds?.providerSpecificData
|
||||
),
|
||||
signal: streamController.signal,
|
||||
log,
|
||||
log: retainedExecutorLog,
|
||||
execute: (signal) =>
|
||||
runWithCapture(providerRequestCapture, () =>
|
||||
executor.execute({
|
||||
@@ -3434,7 +3484,7 @@ export async function handleChatCore({
|
||||
stream: upstreamStream,
|
||||
credentials: execCreds,
|
||||
signal,
|
||||
log,
|
||||
log: retainedExecutorLog,
|
||||
extendedContext,
|
||||
upstreamExtraHeaders: buildUpstreamHeadersForExecute(modelToCall),
|
||||
clientHeaders: buildExecutorClientHeaders(
|
||||
@@ -3442,6 +3492,7 @@ export async function handleChatCore({
|
||||
userAgent
|
||||
),
|
||||
clientResponseFormat,
|
||||
videoTranscriptSensitive,
|
||||
onCredentialsRefreshed,
|
||||
skipUpstreamRetry,
|
||||
contextEditing: { enabled: contextEditingEnabled },
|
||||
@@ -3674,7 +3725,9 @@ export async function handleChatCore({
|
||||
} catch (err) {
|
||||
// Fail-open at Tier 2: Tier 1 already enforced the model/global limit pre-dispatch.
|
||||
// A transient counter read error here must not break an otherwise-valid request.
|
||||
log?.warn?.("TOKEN_LIMIT", "Tier 2 token-limit check failed; allowing request", { err });
|
||||
log?.warn?.("TOKEN_LIMIT", "Tier 2 token-limit check failed; allowing request", {
|
||||
error: retainedErrorTextForLog(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3693,7 +3746,9 @@ export async function handleChatCore({
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
log?.warn?.("GEMINI_RATE_LIMIT", "Pre-dispatch TPM check failed; allowing request", { err });
|
||||
log?.warn?.("GEMINI_RATE_LIMIT", "Pre-dispatch TPM check failed; allowing request", {
|
||||
error: retainedErrorTextForLog(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3843,7 +3898,12 @@ export async function handleChatCore({
|
||||
failureStatus,
|
||||
upstreamErrorCode || (error instanceof Error && error.name ? error.name : "upstream_error")
|
||||
);
|
||||
console.log(`${COLORS.red}[ERROR] ${failureMessage}${COLORS.reset}`);
|
||||
console.log(
|
||||
`${COLORS.red}[ERROR] ${redactVideoTranscriptSensitiveText(
|
||||
failureMessage,
|
||||
videoTranscriptSensitive
|
||||
)}${COLORS.reset}`
|
||||
);
|
||||
if (stream && upstreamErrorCode) {
|
||||
const result = createStreamingErrorResult(
|
||||
failureStatus,
|
||||
@@ -3975,11 +4035,12 @@ export async function handleChatCore({
|
||||
stream: upstreamStream,
|
||||
credentials: getExecutionCredentials(),
|
||||
signal: streamController.signal,
|
||||
log,
|
||||
log: retainedExecutorLog,
|
||||
extendedContext,
|
||||
upstreamExtraHeaders: buildUpstreamHeadersForExecute(retryModelId),
|
||||
clientHeaders: buildExecutorClientHeaders(clientRawRequest?.headers, userAgent),
|
||||
clientResponseFormat,
|
||||
videoTranscriptSensitive,
|
||||
onCredentialsRefreshed,
|
||||
skipUpstreamRetry: isCombo,
|
||||
contextEditing: { enabled: contextEditingEnabled },
|
||||
@@ -4009,9 +4070,13 @@ export async function handleChatCore({
|
||||
// executor throw). Don't swallow — the operator-visible signal "the user
|
||||
// saw 401 even though auth was actually fixed" is much more confusing
|
||||
// than the original 401 alone. Surface at error level with sanitization.
|
||||
const retainedRetryError = redactVideoTranscriptSensitiveText(
|
||||
sanitizeErrorMessage(retryErr),
|
||||
videoTranscriptSensitive
|
||||
);
|
||||
log?.error?.(
|
||||
"TOKEN",
|
||||
`${provider?.toUpperCase()} | retry after refresh failed: ${sanitizeErrorMessage(retryErr)}`
|
||||
`${provider?.toUpperCase()} | retry after refresh failed: ${retainedRetryError}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -4128,6 +4193,11 @@ export async function handleChatCore({
|
||||
|
||||
if (signatureRecovery.succeeded) break providerFailure;
|
||||
|
||||
const retainedProviderMessage = redactVideoTranscriptSensitiveText(
|
||||
message,
|
||||
videoTranscriptSensitive
|
||||
);
|
||||
|
||||
// #10281 — tiny-budget reasoning probes (e.g. Claude Code's `/model` check
|
||||
// sends `max_tokens: 1`): the model burns the whole budget on thinking, and
|
||||
// some upstreams (e.g. api.cline.bot for deepseek-v4-flash) answer the empty
|
||||
@@ -4150,7 +4220,7 @@ export async function handleChatCore({
|
||||
});
|
||||
log?.warn?.(
|
||||
"PROBE",
|
||||
`Reasoning probe (max_tokens < ${REASONING_BUFFER_MIN_TRIGGER}) answered with truncated 200 — upstream reported "${message}"`
|
||||
`Reasoning probe (max_tokens < ${REASONING_BUFFER_MIN_TRIGGER}) answered with truncated 200 — upstream reported "${retainedProviderMessage}"`
|
||||
);
|
||||
break providerFailure;
|
||||
}
|
||||
@@ -4179,7 +4249,7 @@ export async function handleChatCore({
|
||||
{
|
||||
testStatus: "banned",
|
||||
isActive: false,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
lastErrorType: errorType,
|
||||
errorCode: String(statusCode),
|
||||
},
|
||||
@@ -4210,7 +4280,7 @@ export async function handleChatCore({
|
||||
) {
|
||||
await updateProviderConnection(errorConnectionId, {
|
||||
lastErrorType: errorType,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
errorCode: statusCode,
|
||||
});
|
||||
console.warn(
|
||||
@@ -4223,7 +4293,7 @@ export async function handleChatCore({
|
||||
{
|
||||
testStatus: "deactivated",
|
||||
isActive: false,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
lastErrorType: errorType,
|
||||
errorCode: String(statusCode),
|
||||
},
|
||||
@@ -4247,7 +4317,7 @@ export async function handleChatCore({
|
||||
errorConnectionId,
|
||||
{
|
||||
testStatus: "credits_exhausted",
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
lastErrorType: errorType,
|
||||
errorCode: String(statusCode),
|
||||
},
|
||||
@@ -4295,7 +4365,7 @@ export async function handleChatCore({
|
||||
rateLimitedUntil: kimiRateLimitResetAt,
|
||||
backoffLevel: 0,
|
||||
lastErrorType: PROVIDER_ERROR_TYPES.RATE_LIMITED,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
errorCode: statusCode,
|
||||
});
|
||||
console.warn(
|
||||
@@ -4325,7 +4395,7 @@ export async function handleChatCore({
|
||||
errorConnectionId,
|
||||
{
|
||||
testStatus: "credits_exhausted",
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
lastErrorType: errorType,
|
||||
errorCode: String(statusCode),
|
||||
},
|
||||
@@ -4341,14 +4411,14 @@ export async function handleChatCore({
|
||||
// Normal 401 (token/session auth issue): keep account active for refresh/re-auth.
|
||||
await updateProviderConnection(errorConnectionId, {
|
||||
lastErrorType: errorType,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
errorCode: statusCode,
|
||||
});
|
||||
} else if (errorType === PROVIDER_ERROR_TYPES.OAUTH_INVALID_TOKEN) {
|
||||
// OAuth 401 with invalid credentials - token refresh can recover
|
||||
await updateProviderConnection(errorConnectionId, {
|
||||
lastErrorType: errorType,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
errorCode: statusCode,
|
||||
});
|
||||
console.warn(
|
||||
@@ -4358,7 +4428,7 @@ export async function handleChatCore({
|
||||
// Cloud Code 403 with stale project: not a ban, keep account active.
|
||||
await updateProviderConnection(errorConnectionId, {
|
||||
lastErrorType: errorType,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
errorCode: statusCode,
|
||||
});
|
||||
console.warn(
|
||||
@@ -4374,7 +4444,7 @@ export async function handleChatCore({
|
||||
const geoCooldownMs = COOLDOWN_MS.geoBlocked ?? 24 * 60 * 60 * 1000;
|
||||
await updateProviderConnection(errorConnectionId, {
|
||||
lastErrorType: errorType,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
errorCode: statusCode,
|
||||
});
|
||||
// T-PROBE: the 24h exclusion is a routing mutation — a probe must
|
||||
@@ -4399,7 +4469,7 @@ export async function handleChatCore({
|
||||
const byopCooldownMs = COOLDOWN_MS.gcpProjectRequired ?? 24 * 60 * 60 * 1000;
|
||||
await updateProviderConnection(errorConnectionId, {
|
||||
lastErrorType: errorType,
|
||||
lastError: message,
|
||||
lastError: retainedProviderMessage,
|
||||
errorCode: statusCode,
|
||||
});
|
||||
try {
|
||||
@@ -4445,7 +4515,13 @@ export async function handleChatCore({
|
||||
}).catch(() => {});
|
||||
|
||||
const errMsg = formatProviderError(new Error(message), provider, model, statusCode);
|
||||
console.log(`${COLORS.red}[ERROR] ${errMsg}${COLORS.reset}`);
|
||||
const retainedErrMsg = formatProviderError(
|
||||
new Error(retainedProviderMessage),
|
||||
provider,
|
||||
model,
|
||||
statusCode
|
||||
);
|
||||
console.log(`${COLORS.red}[ERROR] ${retainedErrMsg}${COLORS.reset}`);
|
||||
|
||||
// Log Antigravity retry time if available
|
||||
if (retryAfterMs && provider === "antigravity") {
|
||||
@@ -4772,12 +4848,11 @@ export async function handleChatCore({
|
||||
}
|
||||
}
|
||||
} catch (retryErr) {
|
||||
log?.warn?.(
|
||||
"RETRY",
|
||||
`clinepass retry failed: ${
|
||||
retryErr instanceof Error ? retryErr.message : String(retryErr)
|
||||
}`
|
||||
const retainedRetryError = redactVideoTranscriptSensitiveText(
|
||||
retryErr instanceof Error ? retryErr.message : String(retryErr),
|
||||
videoTranscriptSensitive
|
||||
);
|
||||
log?.warn?.("RETRY", `clinepass retry failed: ${retainedRetryError}`);
|
||||
}
|
||||
}
|
||||
if (envError) {
|
||||
@@ -4996,6 +5071,7 @@ export async function handleChatCore({
|
||||
cacheReasoningFromAssistantMessage(msg, provider, model, {
|
||||
scope: reasoningCacheScope,
|
||||
historyMessages: Array.isArray(historyMessages) ? historyMessages : [],
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
@@ -5047,12 +5123,18 @@ export async function handleChatCore({
|
||||
);
|
||||
|
||||
if (memoryOwnerId && memorySettings?.enabled && memorySettings.maxTokens > 0) {
|
||||
const requestMemoryText = extractMemoryTextFromRequestBody(body as Record<string, unknown>);
|
||||
const requestMemoryText = extractMemoryTextFromRequestBody(
|
||||
body as Record<string, unknown>,
|
||||
videoTranscriptSensitive,
|
||||
{ trustedDescriptionFingerprints: videoTranscriptDescriptionFingerprints }
|
||||
);
|
||||
if (requestMemoryText) {
|
||||
extractFacts(requestMemoryText, memoryOwnerId, pipelineSessionId);
|
||||
}
|
||||
|
||||
const memoryText = extractMemoryTextFromResponse(memoryExtractionResponse);
|
||||
const memoryText = videoTranscriptSensitive
|
||||
? ""
|
||||
: extractMemoryTextFromResponse(memoryExtractionResponse);
|
||||
if (memoryText) {
|
||||
extractFacts(memoryText, memoryOwnerId, pipelineSessionId);
|
||||
}
|
||||
@@ -5092,6 +5174,7 @@ export async function handleChatCore({
|
||||
provider,
|
||||
responsePayloadFormat,
|
||||
clientResponseFormat,
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
const postCallGuardrails = await guardrailRegistry.runPostCallHooks(
|
||||
translatedResponse,
|
||||
@@ -5133,7 +5216,10 @@ export async function handleChatCore({
|
||||
}
|
||||
log?.warn?.(
|
||||
"GUARDRAIL",
|
||||
`Response blocked by ${postCallGuardrails.guardrail || "guardrail"}: ${guardrailMessage}`
|
||||
`Response blocked by ${postCallGuardrails.guardrail || "guardrail"}: ${redactVideoTranscriptSensitiveText(
|
||||
guardrailMessage,
|
||||
videoTranscriptSensitive
|
||||
)}`
|
||||
);
|
||||
finalizePendingScope(pendingScope, {
|
||||
providerResponse: responseBody,
|
||||
@@ -5236,6 +5322,7 @@ export async function handleChatCore({
|
||||
apiKeyId: apiKeyInfo?.id ?? undefined,
|
||||
usage,
|
||||
log,
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
|
||||
// ── Phase 9.2: Save for idempotency ──
|
||||
@@ -5315,6 +5402,7 @@ export async function handleChatCore({
|
||||
apiKeyInfo,
|
||||
headers: clientRawRequest?.headers,
|
||||
response: { status: 200, data: translatedResponse },
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
|
||||
// Routing event (feedback foundation) — fire-and-forget, cheap.
|
||||
@@ -5390,6 +5478,7 @@ export async function handleChatCore({
|
||||
provider,
|
||||
model,
|
||||
log,
|
||||
redactUpstreamDiagnosticForLog: videoTranscriptSensitive,
|
||||
});
|
||||
if (streamReadiness.ok === false) {
|
||||
const { response: failureResponse, reason } = streamReadiness;
|
||||
@@ -5521,6 +5610,7 @@ export async function handleChatCore({
|
||||
cacheReasoningFromAssistantMessage(msg, provider, model, {
|
||||
scope: reasoningCacheScope,
|
||||
historyMessages: Array.isArray(historyMessages) ? historyMessages : [],
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
@@ -5553,6 +5643,7 @@ export async function handleChatCore({
|
||||
status: normalizedStreamStatus,
|
||||
error: streamError,
|
||||
errorCode: streamErrorCode,
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
|
||||
// Track cache token metrics for streaming responses
|
||||
@@ -5675,14 +5766,20 @@ export async function handleChatCore({
|
||||
memorySettings.maxTokens > 0 &&
|
||||
streamStatus === 200
|
||||
) {
|
||||
const requestMemoryText = extractMemoryTextFromRequestBody(body as Record<string, unknown>);
|
||||
const requestMemoryText = extractMemoryTextFromRequestBody(
|
||||
body as Record<string, unknown>,
|
||||
videoTranscriptSensitive,
|
||||
{ trustedDescriptionFingerprints: videoTranscriptDescriptionFingerprints }
|
||||
);
|
||||
if (requestMemoryText) {
|
||||
extractFacts(requestMemoryText, memoryOwnerId, pipelineSessionId);
|
||||
}
|
||||
|
||||
const streamedMemoryText = extractMemoryTextFromResponse(
|
||||
(streamResponseBody ?? null) as Record<string, unknown> | null
|
||||
);
|
||||
const streamedMemoryText = videoTranscriptSensitive
|
||||
? ""
|
||||
: extractMemoryTextFromResponse(
|
||||
(streamResponseBody ?? null) as Record<string, unknown> | null
|
||||
);
|
||||
if (streamedMemoryText) {
|
||||
extractFacts(streamedMemoryText, memoryOwnerId, pipelineSessionId);
|
||||
}
|
||||
@@ -5699,6 +5796,7 @@ export async function handleChatCore({
|
||||
apiKeyId: apiKeyInfo?.id ?? undefined,
|
||||
streamUsage,
|
||||
log,
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
|
||||
// Plugin onStreamComplete hook — fire-and-forget, fail-open (#9571)
|
||||
@@ -5767,7 +5865,8 @@ export async function handleChatCore({
|
||||
// openai-responses → openai translation still wants the namespace identity
|
||||
// map for #7936-style round-trip closure when the client also speaks
|
||||
// Responses (Codex CLI).
|
||||
requestToolIdentityMap
|
||||
requestToolIdentityMap,
|
||||
redactStreamDiagnosticsForLog
|
||||
);
|
||||
} else if (needsTranslation(targetFormat, clientResponseFormat)) {
|
||||
// Standard translation for other providers
|
||||
@@ -5797,7 +5896,8 @@ export async function handleChatCore({
|
||||
clientResponseFormat,
|
||||
}),
|
||||
customToolNames,
|
||||
requestToolIdentityMap
|
||||
requestToolIdentityMap,
|
||||
redactStreamDiagnosticsForLog
|
||||
);
|
||||
} else {
|
||||
log?.debug?.("STREAM", `Standard passthrough mode`);
|
||||
@@ -5812,7 +5912,8 @@ export async function handleChatCore({
|
||||
apiKeyInfo,
|
||||
handleStreamFailure,
|
||||
clientResponseFormat,
|
||||
requestToolIdentityMap
|
||||
requestToolIdentityMap,
|
||||
redactStreamDiagnosticsForLog
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5824,6 +5925,7 @@ export async function handleChatCore({
|
||||
clientRawRequestHeaders: clientRawRequest?.headers,
|
||||
clientResponseFormat,
|
||||
echoModel,
|
||||
redactStreamDiagnosticsForLog,
|
||||
responseHeaders,
|
||||
});
|
||||
|
||||
@@ -5839,6 +5941,7 @@ export async function handleChatCore({
|
||||
apiKeyInfo,
|
||||
headers: clientRawRequest?.headers,
|
||||
response: { status: 200, streamed: true },
|
||||
videoTranscriptSensitive,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -15,6 +15,10 @@ import { logAuditEvent } from "@/lib/compliance";
|
||||
import { emit } from "@/lib/events/eventBus";
|
||||
import type { RequestCompletedPayload, RequestFailedPayload } from "@/lib/events/types";
|
||||
import { saveCallLog } from "@/lib/usageDb";
|
||||
import {
|
||||
VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER,
|
||||
VIDEO_TRANSCRIPT_REDACTION_PIPELINE_KEY,
|
||||
} from "@/lib/guardrails/videoTranscriptLogRedaction";
|
||||
import { FORMATS } from "../../translator/formats.ts";
|
||||
import { takeEarlyKeepaliveBytes } from "../../utils/earlyKeepaliveByteBuffer.ts";
|
||||
import { cloneBoundedChatLogPayload, truncateForLog } from "./logTruncation.ts";
|
||||
@@ -68,7 +72,13 @@ export type PersistAttemptLogsContext = {
|
||||
model: string | null | undefined;
|
||||
skillRequestId: string;
|
||||
detailedLoggingEnabled: boolean;
|
||||
reqLogger: { getPipelinePayloads?: () => Record<string, unknown> | undefined } | null | undefined;
|
||||
reqLogger:
|
||||
| {
|
||||
getPipelinePayloads?: () => Record<string, unknown> | undefined;
|
||||
isVideoTranscriptSensitive?: () => boolean;
|
||||
}
|
||||
| null
|
||||
| undefined;
|
||||
pendingRequestId: unknown;
|
||||
clientRawRequest: { endpoint?: string } | null | undefined;
|
||||
requestedModel: unknown;
|
||||
@@ -89,12 +99,34 @@ export type PersistAttemptLogsContext = {
|
||||
* explicitly present (never synthesized from skillRequestId) — persisted as call_logs.session_tag
|
||||
* for per-session cost attribution. */
|
||||
sessionTag?: string | null;
|
||||
/** Trusted request state derived from the Video Bridge guardrail result. */
|
||||
videoTranscriptSensitive?: boolean;
|
||||
/** Exact SHA-256 identities of transcript descriptions generated by the guardrail. */
|
||||
videoTranscriptDescriptionFingerprints?: readonly string[];
|
||||
};
|
||||
|
||||
function toConnectionId(value: unknown): string | null {
|
||||
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
||||
}
|
||||
|
||||
function omitSensitivePipelineResponse(value: unknown): Record<string, unknown> {
|
||||
const record =
|
||||
value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: {};
|
||||
return {
|
||||
...(typeof record.timestamp === "string" ? { timestamp: record.timestamp } : {}),
|
||||
...(typeof record.status === "number" && Number.isFinite(record.status)
|
||||
? { status: record.status }
|
||||
: {}),
|
||||
...(record.headers !== undefined ? { headers: VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER } : {}),
|
||||
...(record.statusText !== undefined
|
||||
? { statusText: VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER }
|
||||
: {}),
|
||||
body: VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER,
|
||||
};
|
||||
}
|
||||
|
||||
function buildAccountRotationMeta(
|
||||
provider: string | null | undefined,
|
||||
initialConnectionId: string | null,
|
||||
@@ -204,6 +236,8 @@ export function persistAttemptLogs(args: PersistAttemptLogsArgs, ctx: PersistAtt
|
||||
correlationId,
|
||||
modelPinned,
|
||||
sessionTag,
|
||||
videoTranscriptSensitive,
|
||||
videoTranscriptDescriptionFingerprints,
|
||||
} = ctx;
|
||||
const initialConnectionId = toConnectionId(connectionId);
|
||||
const finalConnectionId = toConnectionId(credentials?.connectionId) || initialConnectionId;
|
||||
@@ -212,8 +246,21 @@ export function persistAttemptLogs(args: PersistAttemptLogsArgs, ctx: PersistAtt
|
||||
initialConnectionId,
|
||||
finalConnectionId
|
||||
);
|
||||
const transcriptSensitive =
|
||||
videoTranscriptSensitive === true || reqLogger?.isVideoTranscriptSensitive?.() === true;
|
||||
const descriptionLogContext = {
|
||||
trustedDescriptionFingerprints: videoTranscriptDescriptionFingerprints ?? [],
|
||||
};
|
||||
|
||||
const providerWarnings = extractProviderWarnings(providerResponse, clientResponse, responseBody);
|
||||
const detectedProviderWarnings = extractProviderWarnings(
|
||||
providerResponse,
|
||||
clientResponse,
|
||||
responseBody
|
||||
);
|
||||
const providerWarnings =
|
||||
transcriptSensitive && detectedProviderWarnings.length > 0
|
||||
? [VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER]
|
||||
: detectedProviderWarnings;
|
||||
if (providerWarnings.length > 0) {
|
||||
logAuditEvent({
|
||||
action: "provider.warning",
|
||||
@@ -227,6 +274,7 @@ export function persistAttemptLogs(args: PersistAttemptLogsArgs, ctx: PersistAtt
|
||||
model,
|
||||
connectionId: finalConnectionId,
|
||||
httpStatus: status,
|
||||
warningCount: detectedProviderWarnings.length,
|
||||
warnings: providerWarnings,
|
||||
},
|
||||
});
|
||||
@@ -273,8 +321,51 @@ export function persistAttemptLogs(args: PersistAttemptLogsArgs, ctx: PersistAtt
|
||||
};
|
||||
}
|
||||
}
|
||||
if (transcriptSensitive) {
|
||||
pipelinePayloads[VIDEO_TRANSCRIPT_REDACTION_PIPELINE_KEY] = true;
|
||||
for (const requestStage of [
|
||||
"clientRawRequest",
|
||||
"openaiRequest",
|
||||
"providerRequest",
|
||||
] as const) {
|
||||
if (pipelinePayloads[requestStage] !== undefined) {
|
||||
pipelinePayloads[requestStage] = cloneBoundedChatLogPayload(
|
||||
pipelinePayloads[requestStage],
|
||||
0,
|
||||
requestStage !== "clientRawRequest" ? descriptionLogContext : {}
|
||||
) as Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
if (pipelinePayloads.providerResponse !== undefined || providerResponse !== undefined) {
|
||||
pipelinePayloads.providerResponse = omitSensitivePipelineResponse(
|
||||
pipelinePayloads.providerResponse ?? providerResponse
|
||||
);
|
||||
}
|
||||
if (pipelinePayloads.clientResponse !== undefined || clientResponse !== undefined) {
|
||||
pipelinePayloads.clientResponse = omitSensitivePipelineResponse(
|
||||
pipelinePayloads.clientResponse ?? clientResponse
|
||||
);
|
||||
}
|
||||
if (pipelinePayloads.error !== undefined || error) {
|
||||
const errorRecord =
|
||||
pipelinePayloads.error && typeof pipelinePayloads.error === "object"
|
||||
? pipelinePayloads.error
|
||||
: {};
|
||||
pipelinePayloads.error = {
|
||||
...(typeof errorRecord.timestamp === "string"
|
||||
? { timestamp: errorRecord.timestamp }
|
||||
: {}),
|
||||
message: VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER,
|
||||
};
|
||||
}
|
||||
delete pipelinePayloads.streamChunks;
|
||||
}
|
||||
}
|
||||
|
||||
const responseBodyForLog = transcriptSensitive
|
||||
? VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER
|
||||
: responseBody;
|
||||
|
||||
saveCallLog({
|
||||
id: pendingRequestId,
|
||||
method: "POST",
|
||||
@@ -290,10 +381,12 @@ export function persistAttemptLogs(args: PersistAttemptLogsArgs, ctx: PersistAtt
|
||||
attachLogMeta(truncateForLog(body as Record<string, unknown>), {
|
||||
...accountRotationMeta,
|
||||
claudePromptCache: claudeCacheMeta,
|
||||
})
|
||||
}),
|
||||
0,
|
||||
descriptionLogContext
|
||||
),
|
||||
responseBody: cloneBoundedChatLogPayload(
|
||||
attachLogMeta(truncateForLog(responseBody as Record<string, unknown>), {
|
||||
attachLogMeta(truncateForLog(responseBodyForLog as Record<string, unknown>), {
|
||||
...accountRotationMeta,
|
||||
claudePromptCache: claudeCacheMeta
|
||||
? {
|
||||
@@ -305,7 +398,7 @@ export function persistAttemptLogs(args: PersistAttemptLogsArgs, ctx: PersistAtt
|
||||
claudePromptCacheUsage: claudeCacheUsageMeta,
|
||||
})
|
||||
),
|
||||
error: error || null,
|
||||
error: transcriptSensitive && error ? VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER : error || null,
|
||||
sourceFormat,
|
||||
targetFormat,
|
||||
comboName,
|
||||
@@ -332,7 +425,7 @@ export function persistAttemptLogs(args: PersistAttemptLogsArgs, ctx: PersistAtt
|
||||
const lifecycle = resolveRequestLifecycleEvent({
|
||||
traceId,
|
||||
status,
|
||||
error,
|
||||
error: transcriptSensitive && error ? VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER : error,
|
||||
model,
|
||||
provider,
|
||||
comboName,
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
*/
|
||||
|
||||
import { getExecutor } from "../../executors/index.ts";
|
||||
import type { ExecuteInput } from "../../executors/base.ts";
|
||||
import { isCliproxyapiDeepModeEnabled } from "../../executors/cliproxyapi.ts";
|
||||
import { isDarioDeepModeEnabled } from "../../executors/dario.ts";
|
||||
import { redactVideoTranscriptSensitiveText } from "../../../src/lib/guardrails/videoTranscriptLogRedaction.ts";
|
||||
import { getCachedSettings } from "@/lib/db/readCache";
|
||||
import { getUpstreamProxyConfigCached } from "./comboContextCache.ts";
|
||||
import type { FallbackBackend } from "@/lib/db/upstreamProxy";
|
||||
@@ -48,6 +50,11 @@ function parseFallbackCodes(raw: unknown): number[] | null {
|
||||
return parsed.length > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
function retainExecutorDiagnostic(error: unknown, input: ExecuteInput): string {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
return redactVideoTranscriptSensitiveText(message, input.videoTranscriptSensitive === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the CLIProxyAPI-related settings shared by both the direct
|
||||
* `mode: "cliproxyapi"` passthrough leg and the `mode: "fallback"` retry leg:
|
||||
@@ -155,25 +162,20 @@ export async function resolveExecutorWithProxy(
|
||||
const isRetryableStatus = (s: number) => fallbackCodes.includes(s) || s === 0;
|
||||
|
||||
const wrapper = Object.create(nativeExec);
|
||||
wrapper.execute = async (input: {
|
||||
model: string;
|
||||
body: unknown;
|
||||
stream: boolean;
|
||||
credentials: unknown;
|
||||
signal?: AbortSignal | null;
|
||||
log?: unknown;
|
||||
upstreamExtraHeaders?: Record<string, string> | null;
|
||||
}) => {
|
||||
wrapper.execute = async (input: ExecuteInput) => {
|
||||
let result;
|
||||
try {
|
||||
result = await nativeExec.execute(input);
|
||||
} catch (err) {
|
||||
const errMsg = err instanceof Error ? err.message : String(err);
|
||||
log?.info?.("UPSTREAM_PROXY", `${prov} native error (${errMsg}), retrying via ${backendLabel}`);
|
||||
const errMsg = retainExecutorDiagnostic(err, input);
|
||||
log?.info?.(
|
||||
"UPSTREAM_PROXY",
|
||||
`${prov} native error (${errMsg}), retrying via ${backendLabel}`
|
||||
);
|
||||
try {
|
||||
return await proxyExec.execute(input);
|
||||
} catch (proxyErr) {
|
||||
const proxyMsg = proxyErr instanceof Error ? proxyErr.message : String(proxyErr);
|
||||
const proxyMsg = retainExecutorDiagnostic(proxyErr, input);
|
||||
log?.error?.("UPSTREAM_PROXY", `${prov} ${backendLabel} fallback also failed: ${proxyMsg}`);
|
||||
throw proxyErr;
|
||||
}
|
||||
@@ -189,7 +191,7 @@ export async function resolveExecutorWithProxy(
|
||||
try {
|
||||
return await proxyExec.execute(input);
|
||||
} catch (proxyErr) {
|
||||
const proxyMsg = proxyErr instanceof Error ? proxyErr.message : String(proxyErr);
|
||||
const proxyMsg = retainExecutorDiagnostic(proxyErr, input);
|
||||
log?.error?.("UPSTREAM_PROXY", `${prov} ${backendLabel} fallback also failed: ${proxyMsg}`);
|
||||
throw proxyErr;
|
||||
}
|
||||
|
||||
36
open-sse/handlers/chatCore/executorRetentionLog.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER } from "@/lib/guardrails/videoTranscriptLogRedaction";
|
||||
|
||||
import type { ExecutorLog } from "../../executors/base.ts";
|
||||
|
||||
type ExecutorLogMethod = NonNullable<ExecutorLog["debug"]>;
|
||||
|
||||
function retainMethod(
|
||||
owner: ExecutorLog,
|
||||
method: ExecutorLogMethod | undefined
|
||||
): ExecutorLogMethod | undefined {
|
||||
if (!method) return undefined;
|
||||
|
||||
return (tag) => {
|
||||
method.call(owner, tag, VIDEO_TRANSCRIPT_LOG_OMISSION_MARKER);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Executor diagnostics can contain arbitrary provider text, including request echoes.
|
||||
* Keep the original logger for ordinary requests, but give every executor a request-scoped
|
||||
* fail-closed view when the Video Bridge marked the request sensitive. Tags remain useful;
|
||||
* messages and optional structured metadata are replaced/dropped only at the retention seam.
|
||||
*/
|
||||
export function createExecutorRetentionLog(
|
||||
log: ExecutorLog | null | undefined,
|
||||
videoTranscriptSensitive: boolean
|
||||
): ExecutorLog | null | undefined {
|
||||
if (!log || !videoTranscriptSensitive) return log;
|
||||
|
||||
return {
|
||||
debug: retainMethod(log, log.debug),
|
||||
info: retainMethod(log, log.info),
|
||||
warn: retainMethod(log, log.warn),
|
||||
error: retainMethod(log, log.error),
|
||||
};
|
||||
}
|
||||
@@ -124,6 +124,7 @@ export async function checkIdempotencyCache({
|
||||
effectiveServiceTier,
|
||||
startTime,
|
||||
log,
|
||||
videoTranscriptSensitive,
|
||||
}: {
|
||||
clientRawRequest: IdempotencyRequest;
|
||||
provider: string;
|
||||
@@ -132,7 +133,9 @@ export async function checkIdempotencyCache({
|
||||
effectiveServiceTier: EffectiveServiceTier | null | undefined;
|
||||
startTime: number;
|
||||
log: LoggerLike;
|
||||
videoTranscriptSensitive: boolean;
|
||||
}): Promise<{ hit: { success: true; response: Response } | null; idempotencyKey: string | null }> {
|
||||
if (videoTranscriptSensitive) return { hit: null, idempotencyKey: null };
|
||||
// NEXA fusion-idempotency fix: namespace the raw header key (see composeIdempotencyKey).
|
||||
const rawIdempotencyKey = getIdempotencyKey(clientRawRequest?.headers);
|
||||
const idempotencyKey = composeIdempotencyKey({
|
||||
|
||||
@@ -5,6 +5,10 @@ import {
|
||||
getChatLogMaxObjectKeys,
|
||||
getChatLogMaxBodyBytes,
|
||||
} from "@/lib/logEnv";
|
||||
import {
|
||||
omitVideoTranscriptForLog,
|
||||
type VideoTranscriptLogContext,
|
||||
} from "@/lib/guardrails/videoTranscriptLogRedaction";
|
||||
import { estimateSizeFast } from "../../utils/estimateSize.ts";
|
||||
|
||||
export const MEMORY_EXTRACTION_TEXT_LIMIT = 64 * 1024;
|
||||
@@ -22,7 +26,7 @@ export function truncateChatLogText(value: string): string {
|
||||
return `${head}\n[...truncated ${value.length - limit} chars...]\n${tail}`;
|
||||
}
|
||||
|
||||
export function cloneBoundedChatLogPayload(value: unknown, depth = 0): unknown {
|
||||
function cloneBoundedChatLogPayloadValue(value: unknown, depth = 0): unknown {
|
||||
if (value === null || value === undefined) return value;
|
||||
if (typeof value === "string") return truncateChatLogText(value);
|
||||
if (typeof value !== "object") return value;
|
||||
@@ -32,7 +36,7 @@ export function cloneBoundedChatLogPayload(value: unknown, depth = 0): unknown {
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
const retained = value.length > maxTailItems ? value.slice(-maxTailItems) : value;
|
||||
const cloned = retained.map((item) => cloneBoundedChatLogPayload(item, depth + 1));
|
||||
const cloned = retained.map((item) => cloneBoundedChatLogPayloadValue(item, depth + 1));
|
||||
if (value.length > maxTailItems) {
|
||||
return [
|
||||
{
|
||||
@@ -47,10 +51,11 @@ export function cloneBoundedChatLogPayload(value: unknown, depth = 0): unknown {
|
||||
}
|
||||
|
||||
const result: Record<string, unknown> = {};
|
||||
const entries = Object.entries(value as Record<string, unknown>);
|
||||
const record = value as Record<string, unknown>;
|
||||
const entries = Object.entries(record);
|
||||
const maxKeys = getChatLogMaxObjectKeys();
|
||||
for (const [key, item] of maxKeys > 0 ? entries.slice(0, maxKeys) : entries) {
|
||||
result[key] = cloneBoundedChatLogPayload(item, depth + 1);
|
||||
result[key] = cloneBoundedChatLogPayloadValue(item, depth + 1);
|
||||
}
|
||||
if (maxKeys > 0 && entries.length > maxKeys) {
|
||||
result._omniroute_truncated_keys = entries.length - maxKeys;
|
||||
@@ -58,6 +63,16 @@ export function cloneBoundedChatLogPayload(value: unknown, depth = 0): unknown {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function cloneBoundedChatLogPayload(
|
||||
value: unknown,
|
||||
depth = 0,
|
||||
descriptionContext: VideoTranscriptLogContext = {}
|
||||
): unknown {
|
||||
const transcriptSafeValue =
|
||||
depth === 0 ? omitVideoTranscriptForLog(value, descriptionContext) : value;
|
||||
return cloneBoundedChatLogPayloadValue(transcriptSafeValue, depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a large object for logging. If its JSON representation exceeds
|
||||
* getChatLogMaxBodyBytes() (default 1MB; CHAT_LOG_MAX_BODY_KB env override),
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
import {
|
||||
containsVideoTranscriptForLog,
|
||||
omitVideoTranscriptDerivedTextForMemory,
|
||||
type VideoTranscriptLogContext,
|
||||
} from "../../../src/lib/guardrails/videoTranscriptLogRedaction.ts";
|
||||
import { capMemoryExtractionText, MEMORY_EXTRACTION_TEXT_LIMIT } from "./logTruncation.ts";
|
||||
|
||||
function normalizeMemoryInputText(value: unknown, context: VideoTranscriptLogContext = {}): string {
|
||||
if (typeof value !== "string") return "";
|
||||
return omitVideoTranscriptDerivedTextForMemory(value, context).trim();
|
||||
}
|
||||
|
||||
function extractMemoryTextPart(
|
||||
part: Record<string, unknown>,
|
||||
transcriptSensitive: boolean,
|
||||
context: VideoTranscriptLogContext
|
||||
): string {
|
||||
try {
|
||||
const rawText = typeof part?.text === "string" ? part.text : "";
|
||||
if (!rawText) return "";
|
||||
|
||||
const retainedText = normalizeMemoryInputText(rawText, context);
|
||||
if (!retainedText) return "";
|
||||
if (
|
||||
transcriptSensitive &&
|
||||
containsVideoTranscriptForLog(part, context) &&
|
||||
retainedText === rawText.trim()
|
||||
) {
|
||||
return "";
|
||||
}
|
||||
return retainedText;
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export function extractMemoryTextFromResponse(
|
||||
response: Record<string, unknown> | null | undefined
|
||||
): string {
|
||||
@@ -29,9 +63,16 @@ export function extractMemoryTextFromResponse(
|
||||
}
|
||||
|
||||
export function extractMemoryTextFromRequestBody(
|
||||
body: Record<string, unknown> | null | undefined
|
||||
body: Record<string, unknown> | null | undefined,
|
||||
videoTranscriptSensitive = false,
|
||||
context: VideoTranscriptLogContext = {}
|
||||
): string {
|
||||
if (!body || typeof body !== "object") return "";
|
||||
// Re-check the structured body at the sink boundary. The explicit bit covers
|
||||
// processed requests whose raw carrier was already replaced; trusted hashes
|
||||
// identify only descriptions emitted by a modified Video Bridge guardrail.
|
||||
const transcriptSensitive =
|
||||
videoTranscriptSensitive || containsVideoTranscriptForLog(body, context);
|
||||
|
||||
const messages = Array.isArray(body.messages) ? body.messages : null;
|
||||
if (messages && messages.length > 0) {
|
||||
@@ -39,18 +80,16 @@ export function extractMemoryTextFromRequestBody(
|
||||
const msg = messages[i] as Record<string, unknown>;
|
||||
if (msg?.role !== "user") continue;
|
||||
|
||||
if (typeof msg.content === "string" && msg.content.trim().length > 0) {
|
||||
return capMemoryExtractionText(msg.content.trim());
|
||||
const messageText = normalizeMemoryInputText(msg.content, context);
|
||||
if (messageText) {
|
||||
return capMemoryExtractionText(messageText);
|
||||
}
|
||||
|
||||
if (Array.isArray(msg.content)) {
|
||||
const text = msg.content
|
||||
.map((part: Record<string, unknown>) => {
|
||||
if (typeof part?.text === "string") return part.text.trim();
|
||||
if (part?.type === "input_text" && typeof part?.text === "string")
|
||||
return part.text.trim();
|
||||
return "";
|
||||
})
|
||||
.map((part: Record<string, unknown>) =>
|
||||
extractMemoryTextPart(part, transcriptSensitive, context)
|
||||
)
|
||||
.filter(Boolean)
|
||||
.join("\n")
|
||||
.trim();
|
||||
@@ -68,17 +107,15 @@ export function extractMemoryTextFromRequestBody(
|
||||
if (role && role !== "user") continue;
|
||||
if (itemType && itemType !== "message") continue;
|
||||
|
||||
if (typeof item?.content === "string" && item.content.trim()) {
|
||||
return capMemoryExtractionText(item.content.trim());
|
||||
const itemText = normalizeMemoryInputText(item?.content, context);
|
||||
if (itemText) {
|
||||
return capMemoryExtractionText(itemText);
|
||||
}
|
||||
if (Array.isArray(item?.content)) {
|
||||
const text = item.content
|
||||
.map((part: Record<string, unknown>) => {
|
||||
if (typeof part?.text === "string") return part.text.trim();
|
||||
if (part?.type === "input_text" && typeof part?.text === "string")
|
||||
return part.text.trim();
|
||||
return "";
|
||||
})
|
||||
.map((part: Record<string, unknown>) =>
|
||||
extractMemoryTextPart(part, transcriptSensitive, context)
|
||||
)
|
||||
.filter(Boolean)
|
||||
.join("\n")
|
||||
.trim();
|
||||
@@ -96,15 +133,14 @@ export function extractMemoryTextFromRequestBody(
|
||||
if (role && role !== "user") return "";
|
||||
if (itemType && itemType !== "message") return "";
|
||||
|
||||
if (typeof item?.content === "string") return item.content.trim();
|
||||
if (typeof item?.content === "string") {
|
||||
return normalizeMemoryInputText(item.content, context);
|
||||
}
|
||||
if (Array.isArray(item?.content)) {
|
||||
return item.content
|
||||
.map((part: Record<string, unknown>) => {
|
||||
if (typeof part?.text === "string") return part.text.trim();
|
||||
if (part?.type === "input_text" && typeof part?.text === "string")
|
||||
return part.text.trim();
|
||||
return "";
|
||||
})
|
||||
.map((part: Record<string, unknown>) =>
|
||||
extractMemoryTextPart(part, transcriptSensitive, context)
|
||||
)
|
||||
.filter(Boolean)
|
||||
.join("\n")
|
||||
.trim();
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
* byte-identical to the previous inline block.
|
||||
*/
|
||||
|
||||
import { redactVideoTranscriptSensitiveText } from "@/lib/guardrails/videoTranscriptLogRedaction";
|
||||
|
||||
type LoggerLike =
|
||||
{ info?: (...args: unknown[]) => void; debug?: (...args: unknown[]) => void } | null | undefined;
|
||||
|
||||
@@ -25,6 +27,7 @@ export async function runPluginOnRequestHook(args: {
|
||||
apiKeyInfo: unknown;
|
||||
headers?: Record<string, string | string[] | undefined>;
|
||||
log?: LoggerLike;
|
||||
videoTranscriptSensitive?: boolean;
|
||||
}): Promise<PluginOnRequestGate> {
|
||||
try {
|
||||
const { runOnRequest } = await import("@/lib/plugins/hooks");
|
||||
@@ -36,6 +39,7 @@ export async function runPluginOnRequestHook(args: {
|
||||
apiKeyInfo: args.apiKeyInfo,
|
||||
headers: args.headers,
|
||||
metadata: {},
|
||||
videoTranscriptSensitive: args.videoTranscriptSensitive === true,
|
||||
};
|
||||
const pluginResult = await runOnRequest(pluginCtx);
|
||||
if (pluginResult?.blocked) {
|
||||
@@ -55,10 +59,11 @@ export async function runPluginOnRequestHook(args: {
|
||||
}
|
||||
return { blocked: false, body: pluginResult?.body };
|
||||
} catch (pluginErr) {
|
||||
args.log?.debug?.(
|
||||
"PLUGIN",
|
||||
`onRequest hook error (non-fatal): ${pluginErr instanceof Error ? pluginErr.message : String(pluginErr)}`
|
||||
const retainedPluginError = redactVideoTranscriptSensitiveText(
|
||||
pluginErr instanceof Error ? pluginErr.message : String(pluginErr),
|
||||
args.videoTranscriptSensitive === true
|
||||
);
|
||||
args.log?.debug?.("PLUGIN", `onRequest hook error (non-fatal): ${retainedPluginError}`);
|
||||
return { blocked: false };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ export async function runPluginOnResponseHook(args: {
|
||||
apiKeyInfo: unknown;
|
||||
headers?: Record<string, string | string[] | undefined>;
|
||||
response: PluginOnResponsePayload;
|
||||
videoTranscriptSensitive?: boolean;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
const { runOnResponse } = await import("@/lib/plugins/hooks");
|
||||
@@ -38,6 +39,7 @@ export async function runPluginOnResponseHook(args: {
|
||||
apiKeyInfo: args.apiKeyInfo,
|
||||
headers: args.headers,
|
||||
metadata: {},
|
||||
videoTranscriptSensitive: args.videoTranscriptSensitive === true,
|
||||
},
|
||||
args.response
|
||||
).catch(() => {});
|
||||
|
||||
@@ -36,6 +36,7 @@ export function buildPostCallGuardrailContext(
|
||||
provider: string | null | undefined;
|
||||
responsePayloadFormat: unknown;
|
||||
clientResponseFormat: unknown;
|
||||
videoTranscriptSensitive?: boolean;
|
||||
},
|
||||
resolveDisabledGuardrails: typeof defaultResolveDisabled = defaultResolveDisabled
|
||||
): GuardrailContext {
|
||||
@@ -57,5 +58,6 @@ export function buildPostCallGuardrailContext(
|
||||
sourceFormat: optionalString(args.responsePayloadFormat),
|
||||
stream: false,
|
||||
targetFormat: optionalString(args.clientResponseFormat),
|
||||
videoTranscriptSensitive: args.videoTranscriptSensitive === true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
generateSignature,
|
||||
getCachedResponse,
|
||||
isCacheableForRead,
|
||||
} from "@/lib/semanticCache";
|
||||
import { generateSignature, getCachedResponse, isCacheableForRead } from "@/lib/semanticCache";
|
||||
import { calculateCost } from "@/lib/usage/costCalculator";
|
||||
import { trackPendingRequest } from "@/lib/usageDb";
|
||||
import { synthesizeOpenAiSseFromJson } from "../../utils/jsonToSse.ts";
|
||||
@@ -25,6 +21,7 @@ export async function checkSemanticCache({
|
||||
persistAttemptLogs,
|
||||
apiKeyId,
|
||||
cacheDefaultMode,
|
||||
videoTranscriptSensitive,
|
||||
}: {
|
||||
semanticCacheEnabled: boolean;
|
||||
// Only the fields this read path actually touches are named; everything else
|
||||
@@ -42,7 +39,9 @@ export async function checkSemanticCache({
|
||||
persistAttemptLogs: (args: unknown) => void;
|
||||
apiKeyId?: string | null;
|
||||
cacheDefaultMode?: "legacy" | "bypass" | null;
|
||||
videoTranscriptSensitive: boolean;
|
||||
}) {
|
||||
if (videoTranscriptSensitive) return null;
|
||||
// Per-key bypass: skip cache lookup entirely when the API key opts out.
|
||||
if (cacheDefaultMode === "bypass") return null;
|
||||
if (semanticCacheEnabled && isCacheableForRead(body, clientRawRequest?.headers)) {
|
||||
|
||||
@@ -50,10 +50,12 @@ export function storeSemanticCacheResponse(
|
||||
apiKeyId?: string;
|
||||
usage?: UsageLike;
|
||||
log?: LoggerLike;
|
||||
videoTranscriptSensitive: boolean;
|
||||
},
|
||||
deps: SemanticCacheStoreDeps = DEFAULT_DEPS
|
||||
): void {
|
||||
if (
|
||||
args.videoTranscriptSensitive ||
|
||||
!args.enabled ||
|
||||
!deps.isCacheableForWrite(args.body, args.headers) ||
|
||||
!deps.isSmallEnoughForSemanticCache(args.translatedResponse)
|
||||
|
||||
@@ -68,6 +68,7 @@ export function assembleStreamingPipeline(
|
||||
clientRawRequestHeaders: HeadersLike;
|
||||
clientResponseFormat: Parameters<typeof defaultShape>[0];
|
||||
echoModel: string | null | undefined;
|
||||
redactStreamDiagnosticsForLog?: boolean;
|
||||
responseHeaders: Record<string, string>;
|
||||
},
|
||||
deps: StreamingPipelineDeps = DEFAULT_DEPS
|
||||
@@ -83,7 +84,8 @@ export function assembleStreamingPipeline(
|
||||
let piiStream = deps.pipeWithDisconnect(
|
||||
args.providerResponse,
|
||||
args.transformStream,
|
||||
args.streamController
|
||||
args.streamController,
|
||||
{ redactStreamDiagnosticsForLog: args.redactStreamDiagnosticsForLog }
|
||||
);
|
||||
if (typeof args.createPiiTransform === "function") {
|
||||
piiStream = piiStream.pipeThrough((args.createPiiTransform as () => TransformStream)());
|
||||
|
||||