diff --git a/open-sse/config/providers/index.ts b/open-sse/config/providers/index.ts index 506eaeed13..837328e071 100644 --- a/open-sse/config/providers/index.ts +++ b/open-sse/config/providers/index.ts @@ -256,6 +256,8 @@ import { nagaAiProvider } from "./registry/naga-ai/index.ts"; import { chatOripeProvider } from "./registry/chat-oripe/index.ts"; import { freeinferenceProvider } from "./registry/freeinference/index.ts"; import { freeAiProvider } from "./registry/free-ai/index.ts"; +import { voidAiProvider } from "./registry/void-ai/index.ts"; +import { helixmindProvider } from "./registry/helixmind/index.ts"; export const REGISTRY: Record = { aimlapi: aimlapiProvider, @@ -513,4 +515,6 @@ export const REGISTRY: Record = { "chat-oripe": chatOripeProvider, freeinference: freeinferenceProvider, "free-ai": freeAiProvider, + "void-ai": voidAiProvider, + helixmind: helixmindProvider, }; diff --git a/open-sse/config/providers/registry/helixmind/index.ts b/open-sse/config/providers/registry/helixmind/index.ts new file mode 100644 index 0000000000..c8f4d3a529 --- /dev/null +++ b/open-sse/config/providers/registry/helixmind/index.ts @@ -0,0 +1,26 @@ +import type { RegistryEntry } from "../../shared.ts"; +import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts"; + +export const helixmindProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({ + id: "helixmind", + alias: "helixmind", + baseUrl: "https://helixmind.online/v1/chat/completions", + modelsUrl: "https://helixmind.online/v1/models", + responsesBaseUrl: "https://helixmind.online/v1/responses", + models: [], + passthroughModels: true, + alternateFormats: [ + { + format: "claude", + baseUrl: "https://helixmind.online/v1/messages", + authHeader: "x-api-key", + label: "Anthropic-compatible", + }, + { + format: "openai-responses", + baseUrl: "https://helixmind.online/v1/responses", + authHeader: "bearer", + label: "OpenAI Responses", + }, + ], +}); diff --git a/open-sse/config/providers/registry/void-ai/index.ts b/open-sse/config/providers/registry/void-ai/index.ts new file mode 100644 index 0000000000..95a4e8fff9 --- /dev/null +++ b/open-sse/config/providers/registry/void-ai/index.ts @@ -0,0 +1,12 @@ +import type { RegistryEntry } from "../../shared.ts"; +import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts"; + +export const voidAiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({ + id: "void-ai", + alias: "void-ai", + baseUrl: "https://api.voidai.app/v1/chat/completions", + modelsUrl: "https://api.voidai.app/v1/models", + responsesBaseUrl: "https://api.voidai.app/v1/responses", + models: [], + passthroughModels: true, +}); diff --git a/src/shared/constants/config.ts b/src/shared/constants/config.ts index 35b3be51d1..0ec376305a 100644 --- a/src/shared/constants/config.ts +++ b/src/shared/constants/config.ts @@ -34,6 +34,8 @@ export const PROVIDER_ENDPOINTS = { "chat-oripe": "https://api.oriper.com/v1/chat/completions", freeinference: "https://freeinference.org/v1/chat/completions", "free-ai": "https://api.free.ai/v1/chat/", + "void-ai": "https://api.voidai.app/v1/chat/completions", + helixmind: "https://helixmind.online/v1/chat/completions", glm: "https://api.z.ai/api/anthropic/v1/messages", glmt: "https://api.z.ai/api/anthropic/v1/messages", "bailian-coding-plan": "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1/messages", diff --git a/src/shared/constants/providers.ts b/src/shared/constants/providers.ts index 93150eab7b..522a7e0bdd 100644 --- a/src/shared/constants/providers.ts +++ b/src/shared/constants/providers.ts @@ -119,6 +119,8 @@ export const AGGREGATOR_PROVIDER_IDS = new Set([ "chat-oripe", "freeinference", "free-ai", + "void-ai", + "helixmind", ]); export const ENTERPRISE_CLOUD_PROVIDER_IDS = new Set([ diff --git a/src/shared/constants/providers/apikey/audited-free-gateways.ts b/src/shared/constants/providers/apikey/audited-free-gateways.ts index 301614fcc7..c3505b5e02 100644 --- a/src/shared/constants/providers/apikey/audited-free-gateways.ts +++ b/src/shared/constants/providers/apikey/audited-free-gateways.ts @@ -392,4 +392,34 @@ export const APIKEY_PROVIDERS_AUDITED_FREE = { apiHint: "Create an sk-free- key, then use the nonstandard but OpenAI-shaped https://api.free.ai/v1/chat/ endpoint. Select a self-hosted zero-price model to stay within the free pool.", }, + "void-ai": { + id: "void-ai", + alias: "void-ai", + name: "Void AI", + icon: "science", + color: "#111827", + textIcon: "VA", + passthroughModels: true, + website: "https://voidai.app", + hasFree: true, + freeNote: + "The public model catalog marks some models with a free plan requirement, but access is conditional and no numeric quota is confirmed.", + apiHint: + "Use https://api.voidai.app/v1 only after confirming authentication, account eligibility and terms. Treat this integration as experimental until the blocked documentation becomes public.", + }, + helixmind: { + id: "helixmind", + alias: "helixmind", + name: "HelixMind", + icon: "hub", + color: "#4F46E5", + textIcon: "HM", + passthroughModels: true, + website: "https://helixmind.online", + hasFree: false, + freeNote: + "Previously circulated 3 RPM/50 RPD and no-card claims were not confirmed during the 2026-08-02 audit; current quota and billing require account verification.", + apiHint: + "Create a helix- key and use https://helixmind.online/v1. OpenAI requests use Bearer authentication; the Anthropic-compatible messages endpoint accepts x-api-key.", + }, }; diff --git a/tests/unit/free-tier-providers-wave5-integration.test.ts b/tests/unit/free-tier-providers-wave5-integration.test.ts new file mode 100644 index 0000000000..48d24c2081 --- /dev/null +++ b/tests/unit/free-tier-providers-wave5-integration.test.ts @@ -0,0 +1,101 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { deriveConfigFromRegistryModelsUrl } from "../../src/app/api/providers/[id]/models/discoveryConfig.ts"; + +const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts"); +const { DefaultExecutor, getExecutor, hasSpecializedExecutor } = + await import("../../open-sse/executors/index.ts"); +const { PROVIDER_ENDPOINTS } = await import("../../src/shared/constants/config.ts"); +const { isValidModel } = await import("../../src/shared/constants/models.ts"); +const { AGGREGATOR_PROVIDER_IDS } = await import("../../src/shared/constants/providers.ts"); +const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers/apikey/index.ts"); + +const providers = [ + { + id: "void-ai", + endpoint: "https://api.voidai.app/v1/chat/completions", + modelsUrl: "https://api.voidai.app/v1/models", + hasFree: true, + }, + { + id: "helixmind", + endpoint: "https://helixmind.online/v1/chat/completions", + modelsUrl: "https://helixmind.online/v1/models", + hasFree: false, + }, +] as const; + +for (const { id, endpoint, modelsUrl, hasFree } of providers) { + test(`${id} is fully wired through the public provider interfaces`, () => { + const registry = REGISTRY[id]; + const metadata = APIKEY_PROVIDERS[id]; + + assert.ok(registry); + assert.ok(metadata); + assert.equal(registry.id, id); + assert.equal(registry.alias, id); + assert.equal(registry.format, "openai"); + assert.equal(registry.executor, "default"); + assert.equal(registry.authType, "apikey"); + assert.equal(registry.authHeader, "bearer"); + assert.equal(registry.baseUrl, endpoint); + assert.equal(registry.modelsUrl, modelsUrl); + assert.equal(registry.passthroughModels, true); + assert.deepEqual(registry.models, []); + + assert.equal(PROVIDER_ENDPOINTS[id], endpoint); + assert.equal(metadata.id, id); + assert.equal(metadata.alias, id); + assert.equal(metadata.hasFree, hasFree); + assert.equal(metadata.passthroughModels, true); + assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true); + assert.equal(hasSpecializedExecutor(id), false); + + const executor = getExecutor(id); + assert.ok(executor instanceof DefaultExecutor); + assert.equal(executor.buildUrl("live-model", false), endpoint); + assert.equal(isValidModel(id, "future/live-catalog-model"), true); + + const discovery = deriveConfigFromRegistryModelsUrl(id); + assert.ok(discovery); + assert.equal(discovery.url, modelsUrl); + assert.deepEqual(discovery.parseResponse({ object: "list", data: [{ id: "live-model" }] }), [ + { id: "live-model" }, + ]); + }); +} + +test("Void AI metadata keeps the free-plan signal conditional", () => { + const metadata = APIKEY_PROVIDERS["void-ai"]; + + assert.match(metadata.freeNote ?? "", /free plan/i); + assert.match(metadata.freeNote ?? "", /conditional/i); + assert.match(metadata.freeNote ?? "", /no numeric quota/i); + assert.match(metadata.apiHint ?? "", /authentication.*account.*terms/i); +}); + +test("HelixMind exposes its verified alternate API surfaces without reviving old quota claims", () => { + const registry = REGISTRY.helixmind; + const metadata = APIKEY_PROVIDERS.helixmind; + + assert.equal(registry.responsesBaseUrl, "https://helixmind.online/v1/responses"); + assert.deepEqual(registry.alternateFormats, [ + { + format: "claude", + baseUrl: "https://helixmind.online/v1/messages", + authHeader: "x-api-key", + label: "Anthropic-compatible", + }, + { + format: "openai-responses", + baseUrl: "https://helixmind.online/v1/responses", + authHeader: "bearer", + label: "OpenAI Responses", + }, + ]); + assert.match(metadata.freeNote ?? "", /3 RPM\/50 RPD/i); + assert.match(metadata.freeNote ?? "", /no-card/i); + assert.match(metadata.freeNote ?? "", /not confirmed/i); + assert.doesNotMatch(metadata.freeNote ?? "", /free forever|unlimited/i); +});