mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 07:42:13 +03:00
Registers Cheaper Inference (api.cheaperinference.com) as an OSS-sponsor gateway provider. - Canonical provider `cheaperinference` (alias `cinf`) + routing registry with 39 measured text models - Dedicated executor: forces `store:false` on the native /v1/responses endpoint (the shared strip in chatCore.ts deletes `store` for every provider != openai, so without this every Responses request 400'd) and resolves chat-vs-responses URL from the per-model targetFormat - 3 image models (grok-imagine, nano-banana-pro, nano-banana-2), prefix-only: the two nano-banana ids already belong to adobe-firefly, which keeps the bare-id routing - Resale pricing measured from GET /v1/models (30% off list); sponsor rail Kimi 1st / Cheaper Inference 2nd via an explicit rank map; supporter badge in 43 locales; README row No quota card: the gateway exposes no balance API (/v1/wallet and /v1/balance both 404). Validated live end-to-end through OmniRoute: chat, native Responses, streaming and image generation all 200 with real content; the Firefly collision guard verified at runtime.
70 lines
3.0 KiB
TypeScript
70 lines
3.0 KiB
TypeScript
import { BaseExecutor, type ProviderCredentials } from "./base.ts";
|
|
import { PROVIDERS } from "../config/constants.ts";
|
|
import { getModelTargetFormat, PROVIDER_ID_TO_ALIAS } from "../config/providerModels.ts";
|
|
|
|
/**
|
|
* CheaperInferenceExecutor — api.cheaperinference.com.
|
|
*
|
|
* The gateway is OpenAI-compatible on both surfaces, so everything else comes from
|
|
* BaseExecutor. Two provider-specific facts need handling (both measured against the
|
|
* live API on 2026-07-31, not inferred from docs):
|
|
*
|
|
* 1. `/v1/responses` is STATELESS and REQUIRES `store:false`. Omitting it returns
|
|
* HTTP 400 ("This Responses-compatible endpoint is stateless. Send store=false…").
|
|
* chatCore.ts deletes `store` for every provider except "openai" — a strip shared
|
|
* by ~290 providers that must not be special-cased — so we re-add it here, after
|
|
* that strip has run. A client-supplied `store:true` is overwritten rather than
|
|
* forwarded: the endpoint cannot honour it, and forwarding would 400.
|
|
*
|
|
* 2. Chat and Responses live at DIFFERENT URLs (unlike providers that switch on a
|
|
* path suffix). The per-model `targetFormat` registry tag is the single source of
|
|
* truth for which surface a model uses — the same tag chatCore reads to translate
|
|
* the body — so resolving the URL from it keeps URL and payload in lockstep.
|
|
* Same pattern as executors/xai.ts (9router#2439).
|
|
*/
|
|
export class CheaperInferenceExecutor extends BaseExecutor {
|
|
constructor(provider = "cheaperinference") {
|
|
super(provider, PROVIDERS[provider]);
|
|
}
|
|
|
|
/**
|
|
* True when this model is served by the native /v1/responses endpoint.
|
|
*
|
|
* PROVIDER_MODELS is keyed by provider ALIAS ("cinf"), while PROVIDERS is keyed by
|
|
* provider ID ("cheaperinference") — so `this.provider` cannot be passed straight
|
|
* through the way executors/xai.ts does (there the alias equals the id, which hides
|
|
* the distinction). Resolve the alias first or every lookup silently returns null
|
|
* and every Responses request 400s upstream.
|
|
*/
|
|
private usesResponsesEndpoint(model: string): boolean {
|
|
const alias = PROVIDER_ID_TO_ALIAS[this.provider] || this.provider;
|
|
return getModelTargetFormat(alias, model) === "openai-responses";
|
|
}
|
|
|
|
buildUrl(model: string, _stream: boolean, _urlIndex = 0): string {
|
|
if (this.usesResponsesEndpoint(model)) {
|
|
return this.config.responsesBaseUrl || this.config.baseUrl;
|
|
}
|
|
return this.config.baseUrl;
|
|
}
|
|
|
|
transformRequest(
|
|
model: string,
|
|
body: unknown,
|
|
stream: boolean,
|
|
credentials: ProviderCredentials
|
|
): unknown {
|
|
const cleanedBody = super.transformRequest(model, body, stream, credentials);
|
|
if (!cleanedBody || typeof cleanedBody !== "object" || Array.isArray(cleanedBody)) {
|
|
return cleanedBody;
|
|
}
|
|
if (!this.usesResponsesEndpoint(model)) {
|
|
// Chat Completions rejects unknown params — never add `store` on that surface.
|
|
return cleanedBody;
|
|
}
|
|
return { ...(cleanedBody as Record<string, unknown>), store: false };
|
|
}
|
|
}
|
|
|
|
export default CheaperInferenceExecutor;
|