diff --git a/AGENTS.md b/AGENTS.md
index 0c8d27008a..47fa7028eb 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -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`.**
diff --git a/CLAUDE.md b/CLAUDE.md
index 82e30fb40d..51f08a8c8d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -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 |
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
diff --git a/README.md b/README.md
index ab17737df5..c6c656b921 100644
--- a/README.md
+++ b/README.md
@@ -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.**
@@ -149,11 +149,11 @@
-> 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.
- 🚫 Never hit limits Auto-fallback across 259 providers in milliseconds. Quota out? Next provider takes over — zero downtime. |
+ 🚫 Never hit limits Auto-fallback across 264 providers in milliseconds. Quota out? Next provider takes over — zero downtime. |
💸 Save up to 95% tokens RTK + Caveman stacked compression cuts 15–95% of eligible tokens (~89% avg on tool-heavy sessions). |
🆓 $0 to start 90+ providers with a free tier, 11 free forever (Kiro, Qoder, Pollinations, LongCat…). No card needed. |
@@ -368,7 +368,7 @@ All **18** strategies — mix & match per combo step:
-> 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**.
@@ -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)
diff --git a/changelog.d/features/6650-g4f-space-gateway.md b/changelog.d/features/6650-g4f-space-gateway.md
new file mode 100644
index 0000000000..b3c8089f0d
--- /dev/null
+++ b/changelog.d/features/6650-g4f-space-gateway.md
@@ -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).
diff --git a/docs/reference/PROVIDER_REFERENCE.md b/docs/reference/PROVIDER_REFERENCE.md
index 9eb0df2d0c..74298874cc 100644
--- a/docs/reference/PROVIDER_REFERENCE.md
+++ b/docs/reference/PROVIDER_REFERENCE.md
@@ -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= 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) | — |
diff --git a/open-sse/config/providers/index.ts b/open-sse/config/providers/index.ts
index c3943a95e6..ecdd7a82b5 100644
--- a/open-sse/config/providers/index.ts
+++ b/open-sse/config/providers/index.ts
@@ -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 = {
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,
diff --git a/open-sse/config/providers/registry/g4f-gemini/index.ts b/open-sse/config/providers/registry/g4f-gemini/index.ts
new file mode 100644
index 0000000000..1c977b90b7
--- /dev/null
+++ b/open-sse/config/providers/registry/g4f-gemini/index.ts
@@ -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)" },
+ ],
+};
diff --git a/open-sse/config/providers/registry/g4f-groq/index.ts b/open-sse/config/providers/registry/g4f-groq/index.ts
new file mode 100644
index 0000000000..665b79732c
--- /dev/null
+++ b/open-sse/config/providers/registry/g4f-groq/index.ts
@@ -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)" },
+ ],
+};
diff --git a/open-sse/config/providers/registry/g4f-nvidia/index.ts b/open-sse/config/providers/registry/g4f-nvidia/index.ts
new file mode 100644
index 0000000000..a270130d53
--- /dev/null
+++ b/open-sse/config/providers/registry/g4f-nvidia/index.ts
@@ -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)" },
+ ],
+};
diff --git a/open-sse/config/providers/registry/g4f-ollama/index.ts b/open-sse/config/providers/registry/g4f-ollama/index.ts
new file mode 100644
index 0000000000..588f1d96f7
--- /dev/null
+++ b/open-sse/config/providers/registry/g4f-ollama/index.ts
@@ -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)" }],
+};
diff --git a/open-sse/config/providers/registry/g4f-pollinations/index.ts b/open-sse/config/providers/registry/g4f-pollinations/index.ts
new file mode 100644
index 0000000000..9aaeb03d1b
--- /dev/null
+++ b/open-sse/config/providers/registry/g4f-pollinations/index.ts
@@ -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)" },
+ ],
+};
diff --git a/src/shared/constants/providers.ts b/src/shared/constants/providers.ts
index 65aa041144..93c7cc4ef8 100644
--- a/src/shared/constants/providers.ts
+++ b/src/shared/constants/providers.ts
@@ -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) ||
diff --git a/src/shared/constants/providers/apikey/gateways.ts b/src/shared/constants/providers/apikey/gateways.ts
index 0e16497fbc..3e08899728 100644
--- a/src/shared/constants/providers/apikey/gateways.ts
+++ b/src/shared/constants/providers/apikey/gateways.ts
@@ -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",
diff --git a/tests/snapshots/provider/translate-path.json b/tests/snapshots/provider/translate-path.json
index 1242dc13d5..f386d3a883 100644
--- a/tests/snapshots/provider/translate-path.json
+++ b/tests/snapshots/provider/translate-path.json
@@ -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 ",
+ "Content-Type": "application/json"
+ },
+ "nonStream": {
+ "Authorization": "Bearer ",
+ "Content-Type": "application/json"
+ },
+ "oauth": {
+ "Accept": "text/event-stream",
+ "Authorization": "Bearer ",
+ "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 ",
+ "Content-Type": "application/json"
+ },
+ "nonStream": {
+ "Authorization": "Bearer ",
+ "Content-Type": "application/json"
+ },
+ "oauth": {
+ "Accept": "text/event-stream",
+ "Authorization": "Bearer ",
+ "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 ",
+ "Content-Type": "application/json"
+ },
+ "nonStream": {
+ "Authorization": "Bearer ",
+ "Content-Type": "application/json"
+ },
+ "oauth": {
+ "Accept": "text/event-stream",
+ "Authorization": "Bearer ",
+ "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 ",
+ "Content-Type": "application/json"
+ },
+ "nonStream": {
+ "Authorization": "Bearer ",
+ "Content-Type": "application/json"
+ },
+ "oauth": {
+ "Accept": "text/event-stream",
+ "Authorization": "Bearer ",
+ "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 ",
+ "Content-Type": "application/json"
+ },
+ "nonStream": {
+ "Authorization": "Bearer ",
+ "Content-Type": "application/json"
+ },
+ "oauth": {
+ "Accept": "text/event-stream",
+ "Authorization": "Bearer ",
+ "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": {
diff --git a/tests/unit/g4f-space-gateway-6650.test.ts b/tests/unit/g4f-space-gateway-6650.test.ts
new file mode 100644
index 0000000000..8f1aadc2bc
--- /dev/null
+++ b/tests/unit/g4f-space-gateway-6650.test.ts
@@ -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 = {
+ "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)[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)[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);
+ });
+}
diff --git a/tests/unit/providers-constants-split.test.ts b/tests/unit/providers-constants-split.test.ts
index 779834e0f1..546145468e 100644
--- a/tests/unit/providers-constants-split.test.ts
+++ b/tests/unit/providers-constants-split.test.ts
@@ -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/.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).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", () => {