From 31fce91fbdc32babf1783097875bd4f8819eae75 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Tue, 11 Aug 2026 07:23:31 -0300 Subject: [PATCH] feat(providers): add Naga.ac and ChatAnywhere aggregator providers (#6674) (#9421) Co-authored-by: diegosouzapw --- .../6674-gpt4free-batch-3-providers.md | 1 + open-sse/config/providers/index.ts | 4 + .../providers/registry/chatanywhere/index.ts | 17 +++ .../providers/registry/naga-ac/index.ts | 17 +++ src/shared/constants/providers.ts | 3 + .../constants/providers/apikey/gateways.ts | 30 ++++++ tests/unit/providers-g4f-batch3.test.ts | 102 ++++++++++++++++++ 7 files changed, 174 insertions(+) create mode 100644 changelog.d/features/6674-gpt4free-batch-3-providers.md create mode 100644 open-sse/config/providers/registry/chatanywhere/index.ts create mode 100644 open-sse/config/providers/registry/naga-ac/index.ts create mode 100644 tests/unit/providers-g4f-batch3.test.ts diff --git a/changelog.d/features/6674-gpt4free-batch-3-providers.md b/changelog.d/features/6674-gpt4free-batch-3-providers.md new file mode 100644 index 0000000000..bafe537872 --- /dev/null +++ b/changelog.d/features/6674-gpt4free-batch-3-providers.md @@ -0,0 +1 @@ +- **feat(providers):** add Naga.ac and ChatAnywhere aggregator gateway providers (#6674 — thanks @chirag127) \ No newline at end of file diff --git a/open-sse/config/providers/index.ts b/open-sse/config/providers/index.ts index d22a3a9af9..f1c556b3f0 100644 --- a/open-sse/config/providers/index.ts +++ b/open-sse/config/providers/index.ts @@ -229,6 +229,8 @@ import { hcnsecProvider } from "./registry/hcnsec/index.ts"; import { promptqlProvider } from "./registry/promptql/index.ts"; import { hyperagentProvider } from "./registry/hyperagent/index.ts"; import { muse_codeProvider } from "./registry/muse-code/index.ts"; +import { naga_acProvider } from "./registry/naga-ac/index.ts"; +import { chatanywhereProvider } from "./registry/chatanywhere/index.ts"; export const REGISTRY: Record = { aimlapi: aimlapiProvider, @@ -460,4 +462,6 @@ export const REGISTRY: Record = { hyperagent: hyperagentProvider, "muse-code": muse_codeProvider, unorouter: unorouterProvider, + "naga-ac": naga_acProvider, + chatanywhere: chatanywhereProvider, }; diff --git a/open-sse/config/providers/registry/chatanywhere/index.ts b/open-sse/config/providers/registry/chatanywhere/index.ts new file mode 100644 index 0000000000..137cef8d05 --- /dev/null +++ b/open-sse/config/providers/registry/chatanywhere/index.ts @@ -0,0 +1,17 @@ +import type { RegistryEntry } from "../../shared.ts"; + +// ChatAnywhere (api.chatanywhere.tech) — OpenAI-compatible gateway from the +// chatanywhere/GPT_API_free project (~38.7k GitHub stars). Requires GitHub-account- +// gated API key. Free tier is for personal non-commercial use only. +export const chatanywhereProvider: RegistryEntry = { + id: "chatanywhere", + alias: "chtany", + format: "openai", + executor: "default", + baseUrl: "https://api.chatanywhere.tech/v1/chat/completions", + modelsUrl: "https://api.chatanywhere.tech/v1/models", + authType: "apikey", + authHeader: "bearer", + passthroughModels: true, + models: [], +}; \ No newline at end of file diff --git a/open-sse/config/providers/registry/naga-ac/index.ts b/open-sse/config/providers/registry/naga-ac/index.ts new file mode 100644 index 0000000000..4627c2b921 --- /dev/null +++ b/open-sse/config/providers/registry/naga-ac/index.ts @@ -0,0 +1,17 @@ +import type { RegistryEntry } from "../../shared.ts"; + +// Naga.ac — OpenAI-compatible aggregator gateway with free models. +// See https://docs.naga.ac for API reference. +// Free models accept an optional API key; authenticated users get higher rate limits. +export const naga_acProvider: RegistryEntry = { + id: "naga-ac", + alias: "naga", + format: "openai", + executor: "default", + baseUrl: "https://api.naga.ac/v1/chat/completions", + modelsUrl: "https://api.naga.ac/v1/models", + authType: "optional", + authHeader: "bearer", + passthroughModels: true, + models: [], +}; \ No newline at end of file diff --git a/src/shared/constants/providers.ts b/src/shared/constants/providers.ts index bdebdc4753..8c20da4471 100644 --- a/src/shared/constants/providers.ts +++ b/src/shared/constants/providers.ts @@ -93,6 +93,8 @@ export const AGGREGATOR_PROVIDER_IDS = new Set([ "g4f-pollinations", "g4f-ollama", "g4f-nvidia", + "naga-ac", + "chatanywhere", ]); export const ENTERPRISE_CLOUD_PROVIDER_IDS = new Set([ @@ -196,6 +198,7 @@ const EXPLICIT_OPTIONAL_APIKEY_PROVIDER_IDS = new Set([ "huggingchat", "gitlawb", "gitlawb-gmi", + "naga-ac", ]); export function providerAllowsOptionalApiKey(providerId: unknown): boolean { diff --git a/src/shared/constants/providers/apikey/gateways.ts b/src/shared/constants/providers/apikey/gateways.ts index 8494de7cf3..f4a7d387ab 100644 --- a/src/shared/constants/providers/apikey/gateways.ts +++ b/src/shared/constants/providers/apikey/gateways.ts @@ -835,5 +835,35 @@ export const APIKEY_PROVIDERS_GATEWAYS = { authHint: "Get your Regolo API key from regolo.ai, then paste it here as a Bearer token.", apiHint: "OpenAI-compatible endpoint at https://api.regolo.ai/v1 with dynamic model discovery (19 models).", + "naga-ac": { + id: "naga-ac", + alias: "naga", + name: "Naga.ac", + icon: "bolt", + color: "#7C3AED", + textIcon: "NA", + website: "https://naga.ac", + docsUrl: "https://docs.naga.ac", + hasFree: true, + freeNote: + "Free models include Nemotron 3 Ultra (free) and Llama 3.3 70B Instruct (Free). Paid models require credits. Google/GitHub/Discord signup.", + passthroughModels: true, + authHint: + "Get API key at naga.ac — Google/GitHub/Discord signup available.", + }, + chatanywhere: { + id: "chatanywhere", + alias: "chtany", + name: "ChatAnywhere", + icon: "chat", + color: "#10B981", + textIcon: "CA", + website: "https://api.chatanywhere.tech", + hasFree: true, + freeNote: + "Free tier: 5 req/day for GPT-5/4o/4.1, 30/day DeepSeek, 200/day gpt-4o-mini. Personal non-commercial use only — see chatanywhere/GPT_API_free. Requires GitHub-account-gated API key.", + passthroughModels: true, + authHint: + "Get free API key at api.chatanywhere.tech — requires GitHub account signup.", }, }; diff --git a/tests/unit/providers-g4f-batch3.test.ts b/tests/unit/providers-g4f-batch3.test.ts new file mode 100644 index 0000000000..c60f6a9843 --- /dev/null +++ b/tests/unit/providers-g4f-batch3.test.ts @@ -0,0 +1,102 @@ +/** + * Issue #6674 — Add Naga.ac and ChatAnywhere as gpt4free-ecosystem aggregator providers. + * + * Verifies both providers are wired end-to-end the same way as the other aggregator + * gateway providers (g4f-groq, freetheai, hackclub): + * - present in the executor REGISTRY with an OpenAI-compatible shape + * - resolvable through getExecutor() (falls through to DefaultExecutor) + * - listed in AGGREGATOR_PROVIDER_IDS so they show up in the aggregator category + * - has provider metadata (name/website/free-tier note) in the apikey gateway catalog + * - Naga.ac allows optional API key (free models); ChatAnywhere requires a key + */ +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; + passthroughModels?: boolean; +} + +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 PROVIDERS: Record = { + "naga-ac": { + id: "naga-ac", + authType: "optional", + baseUrl: "https://api.naga.ac/v1/chat/completions", + website: "https://naga.ac", + }, + chatanywhere: { + id: "chatanywhere", + authType: "apikey", + baseUrl: "https://api.chatanywhere.tech/v1/chat/completions", + website: "https://api.chatanywhere.tech", + }, +}; + +for (const [id, info] of Object.entries(PROVIDERS)) { + test(`#6674 ${id} is registered in the executor registry with an 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, info.baseUrl); + assert.equal(entry.authType, info.authType); + assert.equal(entry.authHeader, "bearer"); + assert.equal(entry.passthroughModels, true); + }); + + test(`#6674 ${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(`#6674 ${id} is classified as an aggregator/gateway provider`, () => { + assert.ok( + AGGREGATOR_PROVIDER_IDS.has(id), + `${id} must be listed in AGGREGATOR_PROVIDER_IDS` + ); + }); + + test(`#6674 ${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, info.website); + assert.equal(meta.hasFree, true); + assert.equal(typeof meta.freeNote, "string"); + assert.ok((meta.freeNote as string).length > 0); + assert.equal(meta.passthroughModels, true); + }); +} + +test("#6674 naga-ac allows optional (no-key) API key validation", () => { + assert.equal(providerAllowsOptionalApiKey("naga-ac"), true); +}); + +test("#6674 chatanywhere requires an API key (not optional)", () => { + assert.equal(providerAllowsOptionalApiKey("chatanywhere"), false); +}); \ No newline at end of file