Skip to content

Commit a199896

Browse files
committed
refactor: narrow live free economics to discovery metadata
1 parent d389311 commit a199896

25 files changed

Lines changed: 149 additions & 670 deletions
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
- Keep Antigravity Gemini usable when the same connection's Claude weekly quota is empty; generic quota cache stays per-connection for every other provider.
1+
Keep Antigravity Gemini usable when the same connection's Claude weekly quota is empty; generic quota cache stays per-connection for every other provider.

docs/routing/STRICT_ZERO_COST.md

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "STRICT_ZERO_COST"
3-
version: 3.8.51
4-
lastUpdated: 2026-09-04
3+
version: 3.8.50
4+
lastUpdated: 2026-08-20
55
---
66

77
# STRICT_ZERO_COST
@@ -13,9 +13,9 @@ lastUpdated: 2026-09-04
1313
1414
## Why this exists, and why `hidePaidModels` alone isn't enough
1515

16-
`hidePaidModels` answers "is this candidate classified free?" using the shared free-model
17-
classifier plus connection-scoped discovery evidence and explicit local tier policy. It is still
18-
a classification filter, not a current-spend proof, and says nothing about two real risks:
16+
`hidePaidModels` answers "is this model classified free in `FREE_MODEL_BUDGETS` right now?" —
17+
a point-in-time catalog fact, checked via `isFreeModel()`/`providerHasFreeModels()`
18+
(`src/shared/utils/freeModels.ts`). It says nothing about two real risks:
1919

2020
1. A `recurring-*`/`one-time-initial` free tier's allowance can be **exhausted** — the catalog
2121
still lists the model as free, but the account behind it has no headroom left.
@@ -32,29 +32,20 @@ dispatch — never after a request has already gone out.
3232
For every candidate in the pool (`open-sse/services/autoCombo/virtualFactory.ts::buildPreparedPool`,
3333
right after `filterPaidOnlyCandidates`):
3434

35-
1. **Explicit local tier policy** is highest precedence. `free` admits the real connection set;
36-
`cheap`/`premium` excludes even when lower-precedence catalog or discovery evidence says free.
37-
2. **Fresh connection-scoped discovery evidence** (`isFree`, a `:free` id, or exact zero pricing
38-
observed in that provider response) admits only the connections that reported it free. The
39-
successful discovery must be newer than `autoRefreshProviderQuotaInterval`; after restart or
40-
expiry it becomes `state-unknown`, while the ordinary non-strict router may still use the LKG.
41-
3. **Nous Portal `:free` variants** are provider-owned no-cost variants and may pass without a
42-
static catalog row. Other Nous models do not get this shortcut; Portal recommendations/pricing
43-
determine their tier dynamically.
44-
4. **Not in `FREE_MODEL_BUDGETS` after those higher-precedence checks** → excluded. This covers
45-
genuinely paid models and candidates OmniRoute still cannot prove zero-cost.
46-
5. **`freeType: "keyless"`** → passes immediately, **but only for a candidate that genuinely
35+
1. **Not in `FREE_MODEL_BUDGETS` at all** → excluded. This covers genuinely paid models and any
36+
provider/model OmniRoute hasn't classified yet — new candidates start excluded, not included.
37+
2. **`freeType: "keyless"`** → passes immediately, **but only for a candidate that genuinely
4738
arrived via the no-auth path** (`connectionId === SYNTHETIC_NOAUTH_CONNECTION_ID`,
4839
`open-sse/services/autoCombo/resilienceCandidateFilter.ts`). No credential exists for that
4940
candidate, so no request against it can ever be billed — no runtime check is needed or
5041
possible. The same catalogued `keyless` provider/model reached through a **real** DB
5142
connection (`connectionId` is an actual connection id, or the candidate carries
5243
`allowedConnectionIds`) does **not** get this shortcut — `keyless` metadata describes the
5344
no-auth path specifically, not the provider in general, and never authorizes a real,
54-
credentialed account. Such a candidate falls through to check 6 like any other, where it is
45+
credentialed account. Such a candidate falls through to check 3 like any other, where it is
5546
excluded unless the catalog entry separately carries `hardStopGuaranteed: true` (real
5647
`keyless` entries never do — the shortcut was their only path to safety).
57-
6. **Any other `freeType`** (`recurring-daily`, `recurring-monthly`, `recurring-credit`,
48+
3. **Any other `freeType`** (`recurring-daily`, `recurring-monthly`, `recurring-credit`,
5849
`recurring-uncapped`, `one-time-initial`, and any future type this module doesn't
5950
special-case) → passes only if **all** of the following hold:
6051
- `hardStopGuaranteed: true` is set on the catalog entry (`FreeModelBudget.hardStopGuaranteed`,
@@ -69,7 +60,7 @@ right after `filterPaidOnlyCandidates`):
6960
evaluated** is `status: "SAFE"`, was checked within
7061
`settings.autoRefreshProviderQuotaInterval` (default 180s — the existing setting, not a new
7162
number), and reports `remainingFreeAllowance` above a small safety margin.
72-
7. **`freeType: "discontinued"`** → always excluded.
63+
4. **`freeType: "discontinued"`** → always excluded.
7364

7465
## Connection safety (per-connection verification, never per-candidate)
7566

@@ -134,18 +125,17 @@ leaves the field `null` everywhere and costs nothing.
134125

135126
| `freeAccessExclusion` | What it means | What to do about it |
136127
| :--------------------- | :------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------- |
137-
| `operator-non-free` | Local tier policy explicitly marks this provider/model `cheap` or `premium`. | Change/remove the local override only if that policy is no longer intended. |
138-
| `not-in-catalog` | No higher-precedence free proof exists and the pair is absent from `FREE_MODEL_BUDGETS`. | Add a curated entry or obtain live/explicit zero-cost evidence; unknown pairs fail closed. |
128+
| `not-in-catalog` | The provider/model pair is absent from `FREE_MODEL_BUDGETS`. | Add a curated entry, or accept that new pairs start excluded — that is the design. |
139129
| `regime-not-free` | Catalogued, but its `freeType` is not one that grants free access (a discontinued tier, for instance). | Nothing to fix. The model costs money. |
140130
| `no-hard-stop` | Free regime, but `hardStopGuaranteed` is not `true`, so exceeding the allowance might silently start billing. | Verify the provider's terms and set the flag with the source in a comment — never to grow the catalog. |
141131
| `contradictory-noauth` | A no-auth candidate whose catalog entry is not `keyless`. Fail-closed on inconsistent metadata. | Fix the catalog entry; the two facts disagree. |
142132
| `exhausted` | A fresh reading says the allowance is used up. | Wait for the reset. This one resolves itself. |
143-
| `state-unknown` | No fresh quota or live-discovery proof exists for this account. | Refresh discovery/quota state; missing adapters or expired process-local evidence stay fail-closed. |
133+
| `state-unknown` | No quota reading, or one too old to trust. | Go look: the provider may have no usage adapter registered, or the quota fetch is failing. |
144134
| `no-connection` | The candidate carries no account to check at all. | Not a quota problem: the candidate was built without a connection, so nothing was ever looked up. Check how the pool was assembled. |
145135

146-
The `exhausted` / `state-unknown` pair is worth separating. An exhausted allowance resets on its
147-
own; a reading that never arrives or live-discovery proof that expires means current safety is
148-
unknown, and until now both looked identical from outside — the candidate simply vanished.
136+
The last two are the pair worth separating. An exhausted allowance resets on its own; a reading
137+
that never arrives means the lookup itself is broken, and until now both looked identical from
138+
outside — the candidate simply vanished.
149139

150140
**One gap remains, and it is deliberate.** `excludeTosAvoid` still removes candidates before the
151141
listing is built, so a model curated `tos: "avoid"` is absent with no reason given — the same

open-sse/executors/glm.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ export function translateSseResponse(
223223
suppressThinkClose: boolean = false
224224
): Response {
225225
if (!response.body) return response;
226-
// Translate GLM's Anthropic-compatible stream through the shared SSE transformer.
226+
// GLM is a high-throughput provider — use a larger stream buffer (64KB) to
227+
// keep provider → client pacing ahead of the model's token emission rate.
227228
const transform = createSSETransformStreamWithLogger(
228229
FORMATS.CLAUDE,
229230
FORMATS.OPENAI,
@@ -239,7 +240,8 @@ export function translateSseResponse(
239240
false,
240241
suppressThinkClose,
241242
undefined,
242-
undefined
243+
undefined,
244+
65536
243245
);
244246
const headers = cloneHeaders(response.headers);
245247
headers.set("content-type", "text/event-stream");

open-sse/services/__tests__/tierResolver.test.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,6 @@ describe("TierResolver", () => {
125125
expect(result.reason.includes("override")).toBe(true);
126126
});
127127

128-
it("lets an explicit non-free override beat default free-provider classification", () => {
129-
setTierConfig({ providerOverrides: [{ provider: "groq", tier: "premium" }] });
130-
const result = classifyTier("groq", "openai/gpt-oss-120b");
131-
expect(result.tier).toBe(PROVIDER_TIER.PREMIUM);
132-
expect(result.hasFreeTier).toBe(false);
133-
});
134-
135128
it("respects model-level glob pattern override", () => {
136129
setTierConfig({
137130
modelOverrides: [{ provider: "openai", modelPattern: "gpt-4o-mini*", tier: "cheap" }],

open-sse/services/autoCombo/freeAccessQuota.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {
2020
type UsageFetcherProvider,
2121
} from "./../usage.ts";
2222
import { getCachedProviderConnections } from "@/lib/db/readCache";
23-
import { invalidateProviderModelDiscoveryFreshness } from "@/lib/providerModels/discoveryFreshness";
2423
import { defaultLogger as log } from "@omniroute/open-sse/utils/logger";
2524
import type { FreeAccessState } from "./strictZeroCostFilter";
2625
import { isStateStaleForReset } from "./subscriptionLadder";
@@ -212,7 +211,6 @@ export function resolveFreeAccessState(
212211
* build reads a clean cache miss (UNKNOWN) rather than a stale SAFE. */
213212
export function invalidateFreeAccessState(provider: string, connectionId: string): void {
214213
cache.delete(cacheKey(provider, connectionId));
215-
invalidateProviderModelDiscoveryFreshness(provider, connectionId);
216214
}
217215

218216
export const __testing = { cache, extractRemainingAllowance, sweepIfDue };

open-sse/services/autoCombo/freeCandidateEconomics.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

open-sse/services/autoCombo/paidModelFilter.ts

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,52 +11,34 @@
1111
* Kept as a pure, dependency-light function so the filter is unit-testable in
1212
* isolation without seeding the DB-backed virtual factory.
1313
*/
14-
import { isFreeModel } from "@/shared/utils/freeModels";
14+
import { isFreeModel, providerHasFreeModels } from "@/shared/utils/freeModels";
1515

1616
interface PaidFilterCandidate {
1717
provider: string;
1818
model: string;
19-
allowedConnectionIds?: string[];
20-
freeConnectionIds?: string[];
19+
}
20+
21+
/** A candidate is kept only when its provider has documented free models AND the
22+
* selected model itself qualifies as free — mirrors `shouldHidePaid` in
23+
* `src/app/api/v1/models/catalog.ts`. */
24+
function isFreeCandidate(candidate: PaidFilterCandidate): boolean {
25+
return (
26+
providerHasFreeModels(candidate.provider) &&
27+
isFreeModel(candidate.provider, { id: candidate.model })
28+
);
2129
}
2230

2331
/**
2432
* Return the candidate pool filtered to free-only backends when
2533
* `hidePaidModels` is on; otherwise return the pool unchanged (identity — the
26-
* default, opt-in-off path). Connection-scoped discovery is honored without
27-
* widening it: when only some credentials reported this model free, the
28-
* candidate's dispatch allowlist is narrowed to exactly those connections.
34+
* default, opt-in-off path). If every candidate is paid the result is empty, and
35+
* the caller's existing graceful empty-pool path handles it (consistent with the
36+
* opt-in intent — the operator asked not to route to paid models).
2937
*/
3038
export function filterPaidOnlyCandidates<T extends PaidFilterCandidate>(
3139
pool: T[],
32-
hidePaidModels: boolean,
33-
resolveOperatorTier: (
34-
provider: string,
35-
model: string
36-
) => "free" | "cheap" | "premium" | undefined = () => undefined
40+
hidePaidModels: boolean
3741
): T[] {
3842
if (!hidePaidModels) return pool;
39-
40-
const kept: T[] = [];
41-
for (const candidate of pool) {
42-
const override = resolveOperatorTier(candidate.provider, candidate.model);
43-
if (override !== undefined) {
44-
if (override === "free") kept.push(candidate);
45-
continue;
46-
}
47-
if (isFreeModel(candidate.provider, { id: candidate.model })) {
48-
kept.push(candidate);
49-
continue;
50-
}
51-
52-
const freeConnections = candidate.freeConnectionIds ?? [];
53-
if (freeConnections.length === 0) continue;
54-
const allowed = candidate.allowedConnectionIds ?? [];
55-
const narrowed = freeConnections.filter((id) => allowed.includes(id));
56-
if (narrowed.length === 0) continue;
57-
const same =
58-
allowed.length === narrowed.length && narrowed.every((id) => allowed.includes(id));
59-
kept.push(same ? candidate : ({ ...candidate, allowedConnectionIds: narrowed } as T));
60-
}
61-
return kept;
43+
return pool.filter(isFreeCandidate);
6244
}

0 commit comments

Comments
 (0)