feat(providers): add g4f.space no-key gateway (groq/gemini/pollinations/ollama/nvidia) (#6650) (#7647)

Validated in local merge-train @ 8f27177d1 (full parity suite green: typecheck+file-size+complexity+cognitive+changelog+unit shards 1&2+vitest)
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-07-17 22:09:37 -03:00
committed by GitHub
parent 9a71113583
commit 8bf2e6929f
16 changed files with 453 additions and 24 deletions

View File

@@ -3,12 +3,12 @@
## Project
Unified AI proxy/router — route any LLM through one endpoint. Multi-provider support
with **259 provider entries** (OpenAI, Anthropic, Gemini, DeepSeek, Groq, xAI, Mistral, Fireworks,
with **264 provider entries** (OpenAI, Anthropic, Gemini, DeepSeek, Groq, xAI, Mistral, Fireworks,
Cohere, NVIDIA, Cerebras, Pollinations, Puter, Cloudflare AI, HuggingFace, DeepInfra,
SambaNova, Meta Llama API, Moonshot AI, AI21 Labs, Databricks, Snowflake, and many more)
with **MCP Server** (94 tools), **A2A v0.3 Protocol**, and **Electron desktop app**.
> **Live counts (v3.8.49)**: providers 259 · MCP tools 94 · MCP scopes 30 · A2A skills 6 ·
> **Live counts (v3.8.49)**: providers 264 · MCP tools 94 · MCP scopes 30 · A2A skills 6 ·
> open-sse services 134 · routing strategies 17 · auto-combo scoring factors 12 ·
> DB modules 95 · DB migrations 110 · base tables 17 · search providers 11 ·
> i18n locales 42. **Refresh with `npm run check:docs-all`.**

View File

@@ -35,7 +35,7 @@ For full test matrix, see `CONTRIBUTING.md` → "Running Tests". For deep archit
## Project at a Glance
**OmniRoute** — unified AI proxy/router. One endpoint, 259 LLM providers, auto-fallback.
**OmniRoute** — unified AI proxy/router. One endpoint, 264 LLM providers, auto-fallback.
| Layer | Location | Purpose |
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |

View File

@@ -6,7 +6,7 @@
# 🚀 OmniRoute — The Free AI Gateway
### Never stop coding. Connect every AI tool to **259 providers** — **90+ free** — through one endpoint.
### Never stop coding. Connect every AI tool to **264 providers** — **90+ free** — through one endpoint.
**Plug Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini. Auto-fallback.**
<br/>
@@ -149,11 +149,11 @@
</div>
> One endpoint. **259 providers.** Never stop building — and let OmniRoute pick the cheapest one that works.
> One endpoint. **264 providers.** Never stop building — and let OmniRoute pick the cheapest one that works.
<table>
<tr>
<td width="33%" valign="top"><b>🚫 Never hit limits</b><br/><sub>Auto-fallback across 259 providers in milliseconds. Quota out? Next provider takes over — zero downtime.</sub></td>
<td width="33%" valign="top"><b>🚫 Never hit limits</b><br/><sub>Auto-fallback across 264 providers in milliseconds. Quota out? Next provider takes over — zero downtime.</sub></td>
<td width="33%" valign="top"><b>💸 Save up to 95% tokens</b><br/><sub>RTK + Caveman stacked compression cuts 1595% of eligible tokens (~89% avg on tool-heavy sessions).</sub></td>
<td width="33%" valign="top"><b>🆓 $0 to start</b><br/><sub>90+ providers with a free tier, 11 free <i>forever</i> (Kiro, Qoder, Pollinations, LongCat…). No card needed.</sub></td>
</tr>
@@ -368,7 +368,7 @@ All **18** strategies — mix & match per combo step:
</div>
> The most complete catalog of any open-source router: **259 providers**, **90+ with a free tier**, **11 free forever**.
> The most complete catalog of any open-source router: **264 providers**, **90+ with a free tier**, **11 free forever**.
<div align="center">
@@ -874,7 +874,7 @@ Compression: aggressive (~50%) → double your free quota · Cost: $0/mo
**Will I be charged by OmniRoute?** No — it's free, open-source software on your machine. You only pay paid providers directly. OmniRoute has no billing system.
**Are FREE providers really unlimited?** Mostly — Qoder, Pollinations, LongCat, and Cloudflare are free with no per-account credit cap. Kiro is free too but capped at ~50 credits/month per account. Stack multiple free providers in a combo and auto-fallback keeps you serving for $0.
**Will compression hurt quality?** No — it only compresses the **input**; code, URLs, JSON are always protected.
**Does it work where AI is blocked?** Yes — 3-level proxy + 1proxy marketplace reach all 259 providers.
**Does it work where AI is blocked?** Yes — 3-level proxy + 1proxy marketplace reach all 264 providers.
📖 [User Guide](docs/guides/USER_GUIDE.md) · [API Reference](docs/reference/API_REFERENCE.md) · [Environment Config](docs/reference/ENVIRONMENT.md)

View File

@@ -0,0 +1 @@
- feat(sse): add 5 no-key g4f.space gateway providers — `g4f-groq`, `g4f-gemini`, `g4f-pollinations`, `g4f-ollama`, `g4f-nvidia` — a free, no-signup reverse proxy (gpt4free project) fronting Groq, Gemini, Pollinations, Ollama, and NVIDIA NIM, rate-limited to 5 req/min per IP (#6650 — thanks @chirag127).

View File

@@ -10,7 +10,7 @@ lastUpdated: 2026-07-17
> Regenerate with: `npm run gen:provider-reference`
> **Last generated:** 2026-07-17
Total providers: **259**. See category breakdown below.
Total providers: **264**. See category breakdown below.
## Categories
@@ -90,7 +90,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `zai-web` | `zw` | Z.ai Web (Free) | Web cookie | [link](https://chat.z.ai) | Paste the full Cookie header from chat.z.ai (must include the token=<JWT> cookie) |
| `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) (172)
## API Key Providers (paid / paid-with-free-credits) (177)
| ID | Alias | Name | Tags | Website | Notes |
|----|-------|------|------|---------|-------|
@@ -149,6 +149,11 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `freepik` | `fpk` | Freepik (Mystic) | API key, image | [link](https://freepik.com) | Get API key at freepik.com/developers (Mystic image endpoint) |
| `freetheai` | `fta` | FreeTheAi | API key, aggregator | [link](https://freetheai.xyz) | Join the FreeTheAi Discord to get your free API key. |
| `friendliai` | `friendli` | FriendliAI | API key | [link](https://friendli.ai) | Free tier for serverless inference — no credit card required |
| `g4f-gemini` | `g4fgem` | g4f.space — Gemini | API key, aggregator | [link](https://g4f.space) | No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits. |
| `g4f-groq` | `g4fgroq` | g4f.space — Groq | API key, aggregator | [link](https://g4f.space) | No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits. |
| `g4f-nvidia` | `g4fnv` | g4f.space — NVIDIA | API key, aggregator | [link](https://g4f.space) | No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits. |
| `g4f-ollama` | `g4foll` | g4f.space — Ollama | API key, aggregator | [link](https://g4f.space) | No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits. |
| `g4f-pollinations` | `g4fpol` | g4f.space — Pollinations | API key, aggregator | [link](https://g4f.space) | No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits. |
| `galadriel` | `galadriel` | Galadriel | API key | [link](https://galadriel.com) | ⚠️ **DEPRECATED.** api.galadriel.ai no longer resolves (sweep 2026-06-19); the inference API appears discontinued. |
| `gemini` | `gemini` | Gemini (Google AI Studio) | API key | [link](https://aistudio.google.com) | Free forever: 1,500 req/day for Gemini 2.5 Flash — no credit card, get key at aistudio.google.com |
| `getgoapi` | `ggo` | GoAPI | API key, aggregator | [link](https://api.getgoapi.com) | — |

View File

@@ -66,6 +66,11 @@ import { cursorProvider } from "./registry/cursor/index.ts";
import { volcengineProvider } from "./registry/volcengine/index.ts";
import { hackclubProvider } from "./registry/hackclub/index.ts";
import { freetheaiProvider } from "./registry/freetheai/index.ts";
import { g4f_groqProvider } from "./registry/g4f-groq/index.ts";
import { g4f_geminiProvider } from "./registry/g4f-gemini/index.ts";
import { g4f_pollinationsProvider } from "./registry/g4f-pollinations/index.ts";
import { g4f_ollamaProvider } from "./registry/g4f-ollama/index.ts";
import { g4f_nvidiaProvider } from "./registry/g4f-nvidia/index.ts";
import { tencentProvider } from "./registry/tencent/index.ts";
import { cozeProvider } from "./registry/coze/index.ts";
import { ai21Provider } from "./registry/ai21/index.ts";
@@ -256,6 +261,11 @@ export const REGISTRY: Record<string, RegistryEntry> = {
volcengine: volcengineProvider,
hackclub: hackclubProvider,
freetheai: freetheaiProvider,
"g4f-groq": g4f_groqProvider,
"g4f-gemini": g4f_geminiProvider,
"g4f-pollinations": g4f_pollinationsProvider,
"g4f-ollama": g4f_ollamaProvider,
"g4f-nvidia": g4f_nvidiaProvider,
tencent: tencentProvider,
coze: cozeProvider,
ai21: ai21Provider,

View File

@@ -0,0 +1,20 @@
import type { RegistryEntry } from "../../shared.ts";
// g4f.space/api/gemini — no-key reverse proxy to Gemini (gpt4free project, issue #6650).
// Distinct auth mechanism from the existing gemini-web (browser cookie): this is a
// plain no-key HTTP proxy. Same OpenAI-compatible shape as the other no-key gateways.
export const g4f_geminiProvider: RegistryEntry = {
id: "g4f-gemini",
alias: "g4fgem",
format: "openai",
executor: "default",
baseUrl: "https://g4f.space/api/gemini/v1/chat/completions",
modelsUrl: "https://g4f.space/api/gemini/v1/models",
authType: "optional",
authHeader: "bearer",
passthroughModels: true,
models: [
{ id: "models/gemini-2.5-flash", name: "Gemini 2.5 Flash (g4f)" },
{ id: "models/gemini-2.5-pro", name: "Gemini 2.5 Pro (g4f)" },
],
};

View File

@@ -0,0 +1,20 @@
import type { RegistryEntry } from "../../shared.ts";
// g4f.space/api/groq — no-key reverse proxy to Groq (gpt4free project, issue #6650).
// Same OpenAI-compatible shape as the other no-key gateways (hackclub, uncloseai):
// standard chat/completions + /v1/models discovery, no custom executor/translator.
export const g4f_groqProvider: RegistryEntry = {
id: "g4f-groq",
alias: "g4fgroq",
format: "openai",
executor: "default",
baseUrl: "https://g4f.space/api/groq/v1/chat/completions",
modelsUrl: "https://g4f.space/api/groq/v1/models",
authType: "optional",
authHeader: "bearer",
passthroughModels: true,
models: [
{ id: "llama-3.3-70b-versatile", name: "Llama 3.3 70B (g4f/Groq)" },
{ id: "llama-3.1-8b-instant", name: "Llama 3.1 8B Instant (g4f/Groq)" },
],
};

View File

@@ -0,0 +1,22 @@
import type { RegistryEntry } from "../../shared.ts";
// g4f.space/api/nvidia — no-key reverse proxy to NVIDIA NIM (gpt4free project,
// issue #6650). The existing `nvidia` entry requires signup; this is the genuine
// no-key gap the reporter flagged. Free tier is rate-limited to 5 req/min
// (confirmed live via 429 upsell to g4f.dev/members.html).
export const g4f_nvidiaProvider: RegistryEntry = {
id: "g4f-nvidia",
alias: "g4fnv",
format: "openai",
executor: "default",
baseUrl: "https://g4f.space/api/nvidia/v1/chat/completions",
modelsUrl: "https://g4f.space/api/nvidia/v1/models",
authType: "optional",
authHeader: "bearer",
passthroughModels: true,
models: [
{ id: "nvidia/nemotron-3-nano-30b-a3b", name: "Nemotron 3 Nano 30B (g4f/NVIDIA)" },
{ id: "z-ai/glm-5.2", name: "GLM 5.2 (g4f/NVIDIA)" },
{ id: "minimaxai/minimax-m2.7", name: "MiniMax M2.7 (g4f/NVIDIA)" },
],
};

View File

@@ -0,0 +1,18 @@
import type { RegistryEntry } from "../../shared.ts";
// g4f.space/api/ollama — no-key hosted Ollama gateway (gpt4free project, issue #6650).
// Fills a niche none of the existing ollama-* entries cover (local/cloud/search) —
// this is a no-key *hosted* Ollama proxy. Same OpenAI-compatible shape as the other
// no-key gateways.
export const g4f_ollamaProvider: RegistryEntry = {
id: "g4f-ollama",
alias: "g4foll",
format: "openai",
executor: "default",
baseUrl: "https://g4f.space/api/ollama/v1/chat/completions",
modelsUrl: "https://g4f.space/api/ollama/v1/models",
authType: "optional",
authHeader: "bearer",
passthroughModels: true,
models: [{ id: "gemma3:4b", name: "Gemma 3 4B (g4f/Ollama)" }],
};

View File

@@ -0,0 +1,20 @@
import type { RegistryEntry } from "../../shared.ts";
// g4f.space/api/pollinations — no-key reverse proxy to Pollinations (gpt4free project,
// issue #6650). Separate route from the existing direct pollinations.ai entry; same
// OpenAI-compatible shape as the other no-key gateways.
export const g4f_pollinationsProvider: RegistryEntry = {
id: "g4f-pollinations",
alias: "g4fpol",
format: "openai",
executor: "default",
baseUrl: "https://g4f.space/api/pollinations/v1/chat/completions",
modelsUrl: "https://g4f.space/api/pollinations/v1/models",
authType: "optional",
authHeader: "bearer",
passthroughModels: true,
models: [
{ id: "openai", name: "OpenAI (g4f/Pollinations)" },
{ id: "openai-fast", name: "OpenAI Fast (g4f/Pollinations)" },
],
};

View File

@@ -80,6 +80,11 @@ export const AGGREGATOR_PROVIDER_IDS = new Set([
"chutes",
"hackclub",
"freetheai",
"g4f-groq",
"g4f-gemini",
"g4f-pollinations",
"g4f-ollama",
"g4f-nvidia",
]);
export const ENTERPRISE_CLOUD_PROVIDER_IDS = new Set([
@@ -165,17 +170,30 @@ export function isSelfHostedChatProvider(providerId: unknown): boolean {
return typeof providerId === "string" && SELF_HOSTED_CHAT_PROVIDER_IDS.has(providerId);
}
// Providers with heterogeneous/no-key auth that don't fit the NOAUTH_PROVIDERS
// registry (e.g. free-tier gateways where a key is accepted but not required).
// Kept as a Set (not an || chain) to keep providerAllowsOptionalApiKey's
// cyclomatic complexity flat as this list grows — see g4f.space (#6650).
const EXPLICIT_OPTIONAL_APIKEY_PROVIDER_IDS = new Set([
"searxng-search",
"pollinations",
"copilot-web",
"hackclub",
"g4f-groq",
"g4f-gemini",
"g4f-pollinations",
"g4f-ollama",
"g4f-nvidia",
"huggingchat",
"gitlawb",
"gitlawb-gmi",
]);
export function providerAllowsOptionalApiKey(providerId: unknown): boolean {
return (
// ponytail: any noAuth provider auto-qualifies — no per-provider maintenance
(typeof providerId === "string" && providerId in NOAUTH_PROVIDERS) ||
providerId === "searxng-search" ||
providerId === "pollinations" ||
providerId === "copilot-web" ||
providerId === "hackclub" ||
providerId === "huggingchat" ||
providerId === "gitlawb" ||
providerId === "gitlawb-gmi" ||
(typeof providerId === "string" && EXPLICIT_OPTIONAL_APIKEY_PROVIDER_IDS.has(providerId)) ||
isLocalProvider(providerId) ||
isSelfHostedChatProvider(providerId) ||
isOpenAICompatibleProvider(providerId) ||

View File

@@ -251,6 +251,81 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
passthroughModels: true,
authHint: "Join the FreeTheAi Discord to get your free API key.",
},
"g4f-groq": {
id: "g4f-groq",
alias: "g4fgroq",
name: "g4f.space — Groq",
icon: "bolt",
color: "#F97316",
textIcon: "G4F",
website: "https://g4f.space",
hasFree: true,
freeNote:
"Free no-key reverse proxy to Groq (gpt4free project) — rate-limited to 5 req/min.",
passthroughModels: true,
authHint:
"No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits.",
},
"g4f-gemini": {
id: "g4f-gemini",
alias: "g4fgem",
name: "g4f.space — Gemini",
icon: "bolt",
color: "#F97316",
textIcon: "G4F",
website: "https://g4f.space",
hasFree: true,
freeNote:
"Free no-key reverse proxy to Gemini (gpt4free project) — rate-limited to 5 req/min.",
passthroughModels: true,
authHint:
"No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits.",
},
"g4f-pollinations": {
id: "g4f-pollinations",
alias: "g4fpol",
name: "g4f.space — Pollinations",
icon: "bolt",
color: "#F97316",
textIcon: "G4F",
website: "https://g4f.space",
hasFree: true,
freeNote:
"Free no-key reverse proxy to Pollinations (gpt4free project) — rate-limited to 5 req/min.",
passthroughModels: true,
authHint:
"No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits.",
},
"g4f-ollama": {
id: "g4f-ollama",
alias: "g4foll",
name: "g4f.space — Ollama",
icon: "bolt",
color: "#F97316",
textIcon: "G4F",
website: "https://g4f.space",
hasFree: true,
freeNote:
"Free no-key hosted Ollama gateway (gpt4free project) — rate-limited to 5 req/min.",
passthroughModels: true,
authHint:
"No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits.",
},
"g4f-nvidia": {
id: "g4f-nvidia",
alias: "g4fnv",
name: "g4f.space — NVIDIA",
icon: "bolt",
color: "#F97316",
textIcon: "G4F",
website: "https://g4f.space",
hasFree: true,
freeNote:
"Free no-key reverse proxy to NVIDIA NIM (gpt4free project) — rate-limited to 5 req/min.",
passthroughModels: true,
authHint:
"No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits.",
},
"vercel-ai-gateway": {
id: "vercel-ai-gateway",
alias: "vag",

View File

@@ -1646,6 +1646,121 @@
"stream": "https://api.friendli.ai/serverless/v1/chat/completions"
}
},
"g4f-gemini": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://g4f.space/api/gemini/v1/chat/completions",
"stream": "https://g4f.space/api/gemini/v1/chat/completions"
}
},
"g4f-groq": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://g4f.space/api/groq/v1/chat/completions",
"stream": "https://g4f.space/api/groq/v1/chat/completions"
}
},
"g4f-nvidia": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://g4f.space/api/nvidia/v1/chat/completions",
"stream": "https://g4f.space/api/nvidia/v1/chat/completions"
}
},
"g4f-ollama": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://g4f.space/api/ollama/v1/chat/completions",
"stream": "https://g4f.space/api/ollama/v1/chat/completions"
}
},
"g4f-pollinations": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://g4f.space/api/pollinations/v1/chat/completions",
"stream": "https://g4f.space/api/pollinations/v1/chat/completions"
}
},
"galadriel": {
"format": "openai",
"headers": {

View File

@@ -0,0 +1,103 @@
/**
* Issue #6650 — Add g4f.space no-key gateway (Groq/Ollama/Pollinations/NVIDIA/Gemini
* via gpt4free).
*
* Live-verified reachability (triage, not re-verified in CI — see plan-file):
* GET https://g4f.space/api/nvidia/models → 200, real model list
* GET https://g4f.space/api/ollama/v1/models → 200, real model list
* GET https://g4f.space/api/pollinations/v1/models → 200, real model list
* GET https://g4f.space/api/gemini/v1/models → 200, real model list
* GET https://g4f.space/api/groq/... → live Groq backend
*
* Verifies each of the 5 sub-path providers is wired end-to-end the same way as
* the other no-key gateway providers (hackclub, uncloseai):
* - present in the executor REGISTRY with a no-key OpenAI-compatible shape
* - resolvable through getExecutor() (falls through to DefaultExecutor)
* - listed in AGGREGATOR_PROVIDER_IDS so it shows up in the aggregator
* category on the dashboard
* - allowed to skip API key validation (providerAllowsOptionalApiKey)
* - has provider metadata (name/website/free-tier note) in the apikey
* gateway catalog
*/
import test from "node:test";
import assert from "node:assert/strict";
interface RegistryEntryShape {
format?: string;
executor?: string;
baseUrl?: string;
modelsUrl?: string;
authType?: string;
authHeader?: string;
passthroughModels?: boolean;
models?: unknown[];
}
interface ApikeyMetaShape {
id?: string;
name?: string;
website?: string;
hasFree?: boolean;
freeNote?: string;
}
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
const { getExecutor, DefaultExecutor } = await import("../../open-sse/executors/index.ts");
const { AGGREGATOR_PROVIDER_IDS, providerAllowsOptionalApiKey } = await import(
"../../src/shared/constants/providers.ts"
);
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers/apikey/index.ts");
const SUB_PATHS: Record<string, string> = {
"g4f-groq": "groq",
"g4f-gemini": "gemini",
"g4f-pollinations": "pollinations",
"g4f-ollama": "ollama",
"g4f-nvidia": "nvidia",
};
for (const [id, subPath] of Object.entries(SUB_PATHS)) {
test(`#6650 ${id} is registered in the executor registry with a no-key OpenAI-compatible shape`, () => {
const entry = (REGISTRY as Record<string, RegistryEntryShape>)[id];
assert.ok(entry, `${id} should be present in the executor registry`);
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.baseUrl, `https://g4f.space/api/${subPath}/v1/chat/completions`);
assert.equal(entry.modelsUrl, `https://g4f.space/api/${subPath}/v1/models`);
assert.equal(entry.authType, "optional");
assert.equal(entry.passthroughModels, true);
assert.ok(
Array.isArray(entry.models) && entry.models.length > 0,
`${id} must seed a fallback model list`
);
});
test(`#6650 ${id} resolves through getExecutor() as a DefaultExecutor instance`, () => {
const executor = getExecutor(id);
assert.ok(
executor instanceof DefaultExecutor,
`${id} has no custom executor — must fall through to DefaultExecutor`
);
});
test(`#6650 ${id} is classified as an aggregator/gateway provider`, () => {
assert.ok(
AGGREGATOR_PROVIDER_IDS.has(id),
`${id} must be listed in AGGREGATOR_PROVIDER_IDS alongside hackclub/uncloseai`
);
});
test(`#6650 ${id} allows optional (no-key) API key validation`, () => {
assert.equal(providerAllowsOptionalApiKey(id), true);
});
test(`#6650 ${id} has provider metadata with free-tier info`, () => {
const meta = (APIKEY_PROVIDERS as Record<string, ApikeyMetaShape>)[id];
assert.ok(meta, `${id} should have an APIKEY_PROVIDERS metadata entry`);
assert.equal(meta.id, id);
assert.equal(meta.website, "https://g4f.space");
assert.equal(meta.hasFree, true);
assert.equal(typeof meta.freeNote, "string");
assert.ok((meta.freeNote as string).length > 0);
});
}

View File

@@ -1,14 +1,16 @@
// Characterization of the providers.ts catalog split (god-file decomposition): the host became a
// barrel that re-exports 10 data catalogs now living under constants/providers/*, and APIKEY is
// merged from 6 semantic family files (apikey/<family>.ts). Locks: the public surface (every catalog
// + helpers still exported), the spread-merge integrity (168 APIKEY entries, no loss/dup), and that
// + helpers still exported), the spread-merge integrity (177 APIKEY entries, no loss/dup), and that
// load-time Zod validation still runs. Pure-data move → behavior must be identical.
// Count was 171 before obsolete provider removals (PR #6675: glhf/kluster/cablyai/inclusionai etc.,
// 171->167) plus #6126 (ClinePass dual-auth): the API-key-only APIKEY_PROVIDERS_GATEWAYS entry was
// removed as a duplicate now that clinepass is OAuth-primary (OAUTH_PROVIDERS.clinepass) with its
// BYOK path admitted through the DUAL_AUTH_APIKEY_PROVIDER_IDS gate instead (167->166), then the
// OpenVecta inference-gateway addition brought it back to 167, then #7246 (Chenzk API gateway)
// brought it to 168.
// brought it to 168, then more additions brought it to 172, then #6650 (g4f.space no-key gateway:
// 5 new sub-path entries — g4f-groq/g4f-gemini/g4f-pollinations/g4f-ollama/g4f-nvidia) brought it
// to 177.
import { test } from "node:test";
import assert from "node:assert/strict";
@@ -37,12 +39,12 @@ test("barrel still exports every catalog + key helpers", () => {
}
});
test("APIKEY_PROVIDERS merges the 6 family files into 172 entries (no loss / no dup)", async () => {
test("APIKEY_PROVIDERS merges the 6 family files into 177 entries (no loss / no dup)", async () => {
const keys = Object.keys((P as Record<string, object>).APIKEY_PROVIDERS);
assert.equal(keys.length, 172);
assert.equal(new Set(keys).size, 172, "duplicate keys after spread-merge");
assert.equal(keys.length, 177);
assert.equal(new Set(keys).size, 177, "duplicate keys after spread-merge");
// the merged object's entry-count equals the sum of the 6 semantic family files; families are a
// strict partition (every provider in exactly one), so the sum must be exactly 172.
// strict partition (every provider in exactly one), so the sum must be exactly 177.
const families: [string, string][] = [
["gateways", "APIKEY_PROVIDERS_GATEWAYS"],
["frontier-labs", "APIKEY_PROVIDERS_FRONTIER"],
@@ -62,7 +64,7 @@ test("APIKEY_PROVIDERS merges the 6 family files into 172 entries (no loss / no
seen.add(k);
}
}
assert.equal(famTotal, 172, "families must partition all 172 providers");
assert.equal(famTotal, 177, "families must partition all 177 providers");
});
test("AI_PROVIDERS Proxy aggregates all sections; lookups resolve", () => {