openvibers/openvibe.ai Commits
Catalogue the providers' free tiers, read on 2026-11-12 (#514)
Changes
@@@ -29,6 +29,9 @@* data_policy what the provider says it does with a prompt, in the facts the house reads (retention,* trains, region, trust) with the terms page and the day it was checked. A fact the* provider did not state is null, never a guess.++ * free_tier what the provider gives away without a paid plan, under the published request/token++ * limits, whether a card is required, whether free prompts are trained on (in the++ * provider's own words), and the page and day it was read (2026-11-12).* provider_access the commercial gate (docs/provider-matrix.md, 2026-11-03): only OWN_DEPLOYMENT and* AUTHORIZED_WHOLESALE may serve managed paid routes. UNVERIFIED and RESTRICTED offers* stay out of the managed pool while the model catalogue is on; the owner raises a@@@ -109,6 +112,135 @@ const traits = (o) => ({checked: o.checked || NEW_CHECKED,});++/**++ * What each provider gives away without a paid plan, read from the provider's own pages on 2026-11-12. The limits are++ * the published numbers, null where the provider prints none; `card_required` and `trains_on_free` are null when the++ * page does not say. `wording` is the provider's own sentence about training, and `source` is the page the free-tier++ * facts came from. A fact nobody published is null, never a guess.++ */++const FREE_TIERS = {++ groq: {++ available: true,++ summary: 'GroqCloud Free plan: the listed production/preview chat models are usable at no charge within per-model free-plan limits; no card is required for the free plan.',++ limits: { rpm: 30, rpd: 1000, tpm: 8000, tpd: 200000 },++ card_required: false,++ trains_on_free: null,++ wording: 'By default, Groq does not retain customer data for inference requests.',++ source: 'https://console.groq.com/docs/rate-limits',++ checked: '2026-11-12',++ },++ cerebras: {++ available: true,++ summary: 'No permanently free tier. A one-time $5 promotional credit is granted after adding a verified payment method; it expires 30 days after activation. API/Playground pause when it expires or is exhausted. The rate-limits page (5 RPM) and the gpt-oss-120b model page (30 RPM) conflict; the lower 5 RPM is kept.',++ limits: { rpm: 5, rpd: null, tpm: 30000, tpd: 1000000 },++ card_required: true,++ trains_on_free: false,++ wording: 'For clarity, the foregoing does not grant Cerebras the right to use Service Content for the purpose of training or fine-tuning models.',++ source: 'https://inference-docs.cerebras.ai/support/rate-limits',++ checked: '2026-11-12',++ },++ sambanova: {++ available: true,++ summary: 'SambaCloud Free Tier applies when no payment method is linked to the account. Free-tier calls are allowed at 20 RPM, 20 requests/day and 200K tokens/day per model.',++ limits: { rpm: 20, rpd: 20, tpm: null, tpd: 200000 },++ card_required: false,++ trains_on_free: null,++ wording: null,++ source: 'https://docs.sambanova.ai/docs/en/models/rate-limits.md',++ checked: '2026-11-12',++ },++ together: {++ available: false,++ summary: 'No free trial and no free credits. Access requires a minimum $15 credit purchase (fully prepaid); one serverless model, Prism-ML/Ternary-Bonsai-27B, is priced Free/Free.',++ limits: { rpm: null, rpd: null, tpm: null, tpd: null },++ card_required: true,++ trains_on_free: false,++ wording: 'Data that we collect, including your Personal Data, will not be used to train the Company\'s models without your explicit opt-in and consent.',++ source: 'https://docs.together.ai/docs/billing-credits.md',++ checked: '2026-11-12',++ },++ fireworks: {++ available: true,++ summary: 'A one-time $1 starter credit on the prepaid account. No free inference model is listed; when the credit is exhausted, usage pauses and the account is suspended until a payment method is added.',++ limits: { rpm: null, rpd: null, tpm: null, tpd: null },++ card_required: false,++ trains_on_free: false,++ wording: 'We do not use your prompts, training data, or API inputs to train or improve our AI models without your explicit opt-in.',++ source: 'https://docs.fireworks.ai/faq-new/billing-pricing/what-happens-when-i-finish-my-1-dollar-credit.md',++ checked: '2026-11-12',++ },++ hyperbolic: {++ available: true,++ summary: 'Personal Free Tier accounts can use inference after verifying a phone number; verification adds a $1 credit. Pro is optional. Requests use the credit balance (must be above zero).',++ limits: { rpm: 300, rpd: null, tpm: null, tpd: null },++ card_required: false,++ trains_on_free: false,++ wording: 'Hyperbolic does not use any of your User Content, including Inputs or Outputs, to train any generative artificial intelligence models.',++ source: 'https://hyperbolic.ai/docs/faq/inference-models.md',++ checked: '2026-11-12',++ },++ nebius: {++ available: false,++ summary: 'No free tier. Creating a Token Factory billing account is mandatory and requires a bank card; only promo codes add free credits.',++ limits: { rpm: null, rpd: null, tpm: null, tpd: null },++ card_required: true,++ trains_on_free: null,++ wording: null,++ source: 'https://docs.tokenfactory.nebius.com/other-capabilities/billing-new.md',++ checked: '2026-11-12',++ },++ chutes: {++ available: false,++ summary: 'No free tier: \'We do not offer a free tier at this time. Top up your account in the app to get started.\'',++ limits: { rpm: null, rpd: null, tpm: null, tpd: null },++ card_required: true,++ trains_on_free: null,++ wording: null,++ source: 'https://chutes.ai/pricing',++ checked: '2026-11-12',++ },++ mistral: {++ available: true,++ summary: 'Free mode (the default) has the lowest API limits and is intended for evaluation/prototyping; pay-as-you-go unlocks Tier 1 and above.',++ limits: { rpm: null, rpd: null, tpm: null, tpd: null },++ card_required: null,++ trains_on_free: true,++ wording: 'In certain cases, your input and output data (such as conversations, documents, and other user-provided content) may be included in Mistral\'s model training programs. ... You may opt out of data training for Mistral Studio and related API services ... Under the Anonymous improvement data section, disable the toggle to prevent API calls and related data from being used to improve Mistral\'s services.',++ source: 'https://docs.mistral.ai/inference/pricing.md',++ checked: '2026-11-12',++ },++ openrouter: {++ available: true,++ summary: 'Free model variants (IDs ending :free) are available at $0; the Free Models Router (openrouter/free) picks one automatically.',++ limits: { rpm: 20, rpd: 50, tpm: null, tpd: null },++ card_required: false,++ trains_on_free: null,++ wording: 'Each provider on OpenRouter has its own data handling policies ... you can set whether you would like to allow routing to providers that may train on your data ... There are separate settings for paid and free models ... Wherever possible, OpenRouter works with providers to ensure that prompts will not be trained on, but there are exceptions.',++ source: 'https://openrouter.ai/docs/api-reference/limits',++ checked: '2026-11-12',++ },++ cohere: {++ available: true,++ summary: 'Trial API keys are free, issued automatically with an account, limited to 1,000 API calls/month at 20 requests/minute; not permitted for production or commercial use. Command A+ and North Mini Code are listed as Free.',++ limits: { rpm: 20, rpd: null, tpm: null, tpd: null },++ card_required: false,++ trains_on_free: null,++ wording: 'YOU GRANT US A NONEXCLUSIVE, WORLDWIDE, ROYALTY-FREE, IRREVOCABLE, SUBLICENSABLE, AND FULLY PAID-UP RIGHT TO ... USE ... CUSTOMER DATA ... TO: ... (III) IMPROVE AND ENHANCE THE COHERE SOLUTION AND OUR OTHER OFFERINGS ... INCLUDING BY SHARING API DATA AND FINETUNING DATA WITH THIRD PARTIES WHO MAY USE THE FINETUNING DATA AND API DATA TO PROVIDE SERVICES TO COHERE AND FOR OTHER PURPOSES PERMITTED UNDER THEIR TERMS AND CONDITIONS.',++ source: 'https://docs.cohere.com/docs/rate-limits',++ checked: '2026-11-12',++ },++ gemini: {++ available: true,++ summary: 'Free tier gives free input and output tokens on supported models (gemini-3.8-flash, gemini-3.6-flash, gemini-3.5-flash-lite were free on the pricing page). Gemini 4 Carbon/Argon/Hydrogen are not available on the Free tier.',++ limits: { rpm: null, rpd: null, tpm: null, tpd: null },++ card_required: false,++ trains_on_free: true,++ wording: 'For unpaid quota on Gemini API, Google uses the content you submit to the Services and any generated responses to provide, improve, and develop Google products and services and machine learning technologies ... To help with quality and improve our products, human reviewers may read, annotate, and process your API input and output.',++ source: 'https://ai.google.dev/gemini-api/docs/pricing',++ checked: '2026-11-12',++ },++};++const PROVIDERS = [{key: 'qwen',@@@ -645,6 +777,7 @@ const PROVIDERS = [provider_access: 'UNVERIFIED',priority: 90,role: 'fallback',++ free_tier: FREE_TIERS.openrouter,privacy: privacy({label: 'anonymized',terms_url: 'https://openrouter.ai/terms',@@@ -694,6 +827,7 @@ const PROVIDERS = [key, display_name, base_url, docs_url, keys_url, credential_default_model, models_dev_id, default_model: model_key, timeout_ms: 60000,capabilities: ['chat', 'generate', 'summarize', 'classify', 'extract', 'enrich', 'json', 'tools'],provider_access, priority: 40, ...(uncensored ? { uncensored: true } : {}),++ ...(FREE_TIERS[key] ? { free_tier: FREE_TIERS[key] } : {}),privacy: privacy({ label: privateTier ? 'private' : 'anonymized', terms_url: privateTier ? source : null,wording: privateTier ? 'Venice states prompts and generations are never stored or logged, and are not used to train future models for this model.' : 'Retention and training commitments were not confirmed on the provider page; unknown.' }),data_policy: policy({ trains: privateTier ? false : null, retention: privateTier ? 'none' : null,@@@ -756,13 +890,16 @@ const PROVIDERS = [docs_url: 'https://platform.openai.com/docs/api-reference/models/list', capabilities: ['chat', 'vision', 'tools', 'image', 'video', 'speech', 'transcribe', 'embed'] },{ key: 'gemini', models_dev_id: 'google', keys_url: 'https://aistudio.google.com/apikey', display_name: 'Google AI Studio (Gemini API)', base_url: 'https://generativelanguage.googleapis.com/v1beta/openai',models_endpoint: 'https://generativelanguage.googleapis.com/v1beta/models',-- api_family: 'google', docs_url: 'https://ai.google.dev/gemini-api/docs/openai', capabilities: ['chat', 'vision', 'tools', 'embed'] },++ api_family: 'google', docs_url: 'https://ai.google.dev/gemini-api/docs/openai', capabilities: ['chat', 'vision', 'tools', 'embed'],++ free_tier: FREE_TIERS.gemini },{ key: 'xai', keys_url: 'https://console.x.ai/', display_name: 'xAI', base_url: 'https://api.x.ai/v1',docs_url: 'https://docs.x.ai/docs/api-reference', capabilities: ['chat', 'vision', 'tools', 'image', 'video'] },{ key: 'mistral', keys_url: 'https://console.mistral.ai/api-keys', display_name: 'Mistral', base_url: 'https://api.mistral.ai/v1',-- docs_url: 'https://docs.mistral.ai/api', capabilities: ['chat', 'vision', 'tools', 'embed', 'transcribe'] },++ docs_url: 'https://docs.mistral.ai/api', capabilities: ['chat', 'vision', 'tools', 'embed', 'transcribe'],++ free_tier: FREE_TIERS.mistral },{ key: 'cohere', display_name: 'Cohere', base_url: 'https://api.cohere.com/compatibility/v1', models_endpoint: 'https://api.cohere.com/v1/models',-- docs_url: 'https://docs.cohere.com/docs/compatibility-api', capabilities: ['chat', 'tools', 'embed', 'rerank'] },++ docs_url: 'https://docs.cohere.com/docs/compatibility-api', capabilities: ['chat', 'tools', 'embed', 'rerank'],++ free_tier: FREE_TIERS.cohere },{ key: 'perplexity', display_name: 'Perplexity', kind: 'responses', base_url: 'https://api.perplexity.ai/v1',docs_url: 'https://docs.perplexity.ai/docs/agent-api/openai-compatibility', capabilities: ['chat', 'web-search'], search_adapters: ['perplexity'] },{ key: 'brave', display_name: 'Brave Search', kind: 'http', base_url: 'https://api.search.brave.com/res/v1',@@@ -37,6 +37,8 @@ function recordOf(p) {data_policy: p.data_policy,// A provider's published request limits, kept by the router (server/providers/rate-gate.js).rate_limits: p.rate_limits || null,++ // What the provider gives away without a paid plan, with the page and day it was read.++ free_tier: p.free_tier || null,// The privacy label of the provider: `private` only where its own terms say it keeps nothing and trains on// nothing, `anonymized` for everyone else. The wording and the page it was read from travel with it.privacy: p.privacy,@@@ -26,21 +26,22 @@ const { ProviderError, insufficientBalance, retryable } = require('../server/proconst t = suite('ai-provider-adapters');--/** The provider's own domain: a price or a policy may only be read from the provider's own pages. */++/** The provider's own domain: a price or a policy may only be read from the provider's own pages. `|` joins its domains. */const DOMAIN = {qwen: 'alibabacloud.com', kimi: 'kimi.ai', glm: 'z.ai', minimax: 'minimax.io', deepinfra: 'deepinfra.com',novita: 'novita.ai', featherless: 'featherless.ai', refuseless: 'refuseless.com', abliteration: 'abliteration.ai',openrouter: 'openrouter.ai', venice: 'venice.ai', abliteratedmodels: 'abliteratedmodels.cc', uplinkswitch: 'uplinkswitch.ai',chutes: 'chutes.ai', siliconflow: 'siliconflow.com', nebius: 'nebius.com', together: 'together.ai',fireworks: 'fireworks.ai', groq: 'groq.com', cerebras: 'cerebras.ai', sambanova: 'sambanova.ai',-- baseten: 'baseten.co', hyperbolic: 'hyperbolic.xyz', parasail: 'parasail.io', 'particle-ai': 'particle.ai',++ baseten: 'baseten.co', hyperbolic: 'hyperbolic.xyz|hyperbolic.ai', parasail: 'parasail.io', 'particle-ai': 'particle.ai','inference-net': 'inference.net', 'atlas-cloud': 'atlascloud.ai', avian: 'avian.io',nanogpt: 'nano-gpt.com', infermatic: 'totalgpt.ai', arliai: 'arliai.com', friendli: 'friendli.ai', scaleway: 'scaleway.com', anthropic: 'claude.com',++ mistral: 'mistral.ai', cohere: 'cohere.com', gemini: 'google.dev',iteracompute: 'iteracompute.com', sable: 'sableapi.com', inception: 'inceptionlabs.ai', dosai: 'dos.ai', 'runpod-vllm': 'runpod.io', meta: 'meta.ai', altare: 'altare.global',};const onItsOwnSite = (url, key) => {const host = new URL(url).hostname;-- return host === DOMAIN[key] || host.endsWith(`.${DOMAIN[key]}`);++ return DOMAIN[key].split('|').some((domain) => host === domain || host.endsWith(`.${domain}`));};const noop = { get: async () => undefined, run: async () => ({}), all: async () => [] };const iso = (n) => new Date(n).toISOString();@@@ -127,6 +128,17 @@ t.test('every price comes from the provider\'s own page, with the day it was reaassert.strictEqual(pool.isUncensored(pool.byKey.get('featherless'), { model_key: 'some/Model-32B-abliterated' }), true);});++t.test('every free tier states availability, its own page and the day it was read', () => {++ const free = pool.PROVIDERS.filter((p) => p.free_tier);++ assert.strictEqual(free.length, 12, 'the twelve providers read on 2026-11-12 carry their free tier');++ for (const p of free) {++ assert.strictEqual(typeof p.free_tier.available, 'boolean', `${p.key} free tier availability`);++ assert.ok(p.free_tier.source && onItsOwnSite(p.free_tier.source, p.key), `${p.key} free tier page is its own`);++ assert.strictEqual(p.free_tier.checked, '2026-11-12', `${p.key} free tier checked`);++ }++ assert.strictEqual(pool.byKey.get('groq').free_tier.limits.rpm, 30, 'Groq free plan is 30 RPM');++});++t.test('the seed writes the privacy label, the quantization and the refusal rate into the registry', async () => {const saved = new Map();const models = new Map();@@@ -143,6 +155,8 @@ t.test('the seed writes the privacy label, the quantization and the refusal rateassert.strictEqual(saved.get('abliteration').secret_ref, 'vault:abliteration');assert.strictEqual(saved.get('deepinfra').metadata.privacy.label, 'private');assert.strictEqual(saved.get('qwen').metadata.privacy.label, 'anonymized');++ assert.strictEqual(saved.get('groq').metadata.free_tier.checked, '2026-11-12');++ assert.strictEqual(saved.get('groq').metadata.free_tier.limits.rpm, 30);assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').metadata.refusal_rate, null);assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').metadata.quantization, null);assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').cost.in_per_mtok, null);
@@ -29,6 +29,9 @@
@@ -29,6 +29,9 @@
* data_policy what the provider says it does with a prompt, in the facts the house reads (retention,
* data_policy what the provider says it does with a prompt, in the facts the house reads (retention,
* trains, region, trust) with the terms page and the day it was checked. A fact the
* trains, region, trust) with the terms page and the day it was checked. A fact the
* provider did not state is null, never a guess.
* provider did not state is null, never a guess.
+ * free_tier what the provider gives away without a paid plan, under the published request/token
+ * limits, whether a card is required, whether free prompts are trained on (in the
+ * provider's own words), and the page and day it was read (2026-11-12).
* provider_access the commercial gate (docs/provider-matrix.md, 2026-11-03): only OWN_DEPLOYMENT and
* provider_access the commercial gate (docs/provider-matrix.md, 2026-11-03): only OWN_DEPLOYMENT and
* AUTHORIZED_WHOLESALE may serve managed paid routes. UNVERIFIED and RESTRICTED offers
* AUTHORIZED_WHOLESALE may serve managed paid routes. UNVERIFIED and RESTRICTED offers
* stay out of the managed pool while the model catalogue is on; the owner raises a
* stay out of the managed pool while the model catalogue is on; the owner raises a
@@ -109,6 +112,135 @@ const traits = (o) => ({
@@ -109,6 +112,135 @@ const traits = (o) => ({
checked: o.checked || NEW_CHECKED,
checked: o.checked || NEW_CHECKED,
});
});
+/**
+ * What each provider gives away without a paid plan, read from the provider's own pages on 2026-11-12. The limits are
+ * the published numbers, null where the provider prints none; `card_required` and `trains_on_free` are null when the
+ * page does not say. `wording` is the provider's own sentence about training, and `source` is the page the free-tier
+ * facts came from. A fact nobody published is null, never a guess.
+ */
+const FREE_TIERS = {
+ groq: {
+ available: true,
+ summary: 'GroqCloud Free plan: the listed production/preview chat models are usable at no charge within per-model free-plan limits; no card is required for the free plan.',
+ limits: { rpm: 30, rpd: 1000, tpm: 8000, tpd: 200000 },
+ card_required: false,
+ trains_on_free: null,
+ wording: 'By default, Groq does not retain customer data for inference requests.',
+ source: 'https://console.groq.com/docs/rate-limits',
+ checked: '2026-11-12',
+ },
+ cerebras: {
+ available: true,
+ summary: 'No permanently free tier. A one-time $5 promotional credit is granted after adding a verified payment method; it expires 30 days after activation. API/Playground pause when it expires or is exhausted. The rate-limits page (5 RPM) and the gpt-oss-120b model page (30 RPM) conflict; the lower 5 RPM is kept.',
+ limits: { rpm: 5, rpd: null, tpm: 30000, tpd: 1000000 },
+ card_required: true,
+ trains_on_free: false,
+ wording: 'For clarity, the foregoing does not grant Cerebras the right to use Service Content for the purpose of training or fine-tuning models.',
+ source: 'https://inference-docs.cerebras.ai/support/rate-limits',
+ checked: '2026-11-12',
+ },
+ sambanova: {
+ available: true,
+ summary: 'SambaCloud Free Tier applies when no payment method is linked to the account. Free-tier calls are allowed at 20 RPM, 20 requests/day and 200K tokens/day per model.',
+ limits: { rpm: 20, rpd: 20, tpm: null, tpd: 200000 },
+ card_required: false,
+ trains_on_free: null,
+ wording: null,
+ source: 'https://docs.sambanova.ai/docs/en/models/rate-limits.md',
+ checked: '2026-11-12',
+ },
+ together: {
+ available: false,
+ summary: 'No free trial and no free credits. Access requires a minimum $15 credit purchase (fully prepaid); one serverless model, Prism-ML/Ternary-Bonsai-27B, is priced Free/Free.',
+ limits: { rpm: null, rpd: null, tpm: null, tpd: null },
+ card_required: true,
+ trains_on_free: false,
+ wording: 'Data that we collect, including your Personal Data, will not be used to train the Company\'s models without your explicit opt-in and consent.',
+ source: 'https://docs.together.ai/docs/billing-credits.md',
+ checked: '2026-11-12',
+ },
+ fireworks: {
+ available: true,
+ summary: 'A one-time $1 starter credit on the prepaid account. No free inference model is listed; when the credit is exhausted, usage pauses and the account is suspended until a payment method is added.',
+ limits: { rpm: null, rpd: null, tpm: null, tpd: null },
+ card_required: false,
+ trains_on_free: false,
+ wording: 'We do not use your prompts, training data, or API inputs to train or improve our AI models without your explicit opt-in.',
+ source: 'https://docs.fireworks.ai/faq-new/billing-pricing/what-happens-when-i-finish-my-1-dollar-credit.md',
+ checked: '2026-11-12',
+ },
+ hyperbolic: {
+ available: true,
+ summary: 'Personal Free Tier accounts can use inference after verifying a phone number; verification adds a $1 credit. Pro is optional. Requests use the credit balance (must be above zero).',
+ limits: { rpm: 300, rpd: null, tpm: null, tpd: null },
+ card_required: false,
+ trains_on_free: false,
+ wording: 'Hyperbolic does not use any of your User Content, including Inputs or Outputs, to train any generative artificial intelligence models.',
+ source: 'https://hyperbolic.ai/docs/faq/inference-models.md',
+ checked: '2026-11-12',
+ },
+ nebius: {
+ available: false,
+ summary: 'No free tier. Creating a Token Factory billing account is mandatory and requires a bank card; only promo codes add free credits.',
+ limits: { rpm: null, rpd: null, tpm: null, tpd: null },
+ card_required: true,
+ trains_on_free: null,
+ wording: null,
+ source: 'https://docs.tokenfactory.nebius.com/other-capabilities/billing-new.md',
+ checked: '2026-11-12',
+ },
+ chutes: {
+ available: false,
+ summary: 'No free tier: \'We do not offer a free tier at this time. Top up your account in the app to get started.\'',
+ limits: { rpm: null, rpd: null, tpm: null, tpd: null },
+ card_required: true,
+ trains_on_free: null,
+ wording: null,
+ source: 'https://chutes.ai/pricing',
+ checked: '2026-11-12',
+ },
+ mistral: {
+ available: true,
+ summary: 'Free mode (the default) has the lowest API limits and is intended for evaluation/prototyping; pay-as-you-go unlocks Tier 1 and above.',
+ limits: { rpm: null, rpd: null, tpm: null, tpd: null },
+ card_required: null,
+ trains_on_free: true,
+ wording: 'In certain cases, your input and output data (such as conversations, documents, and other user-provided content) may be included in Mistral\'s model training programs. ... You may opt out of data training for Mistral Studio and related API services ... Under the Anonymous improvement data section, disable the toggle to prevent API calls and related data from being used to improve Mistral\'s services.',
+ source: 'https://docs.mistral.ai/inference/pricing.md',
+ checked: '2026-11-12',
+ },
+ openrouter: {
+ available: true,
+ summary: 'Free model variants (IDs ending :free) are available at $0; the Free Models Router (openrouter/free) picks one automatically.',
+ limits: { rpm: 20, rpd: 50, tpm: null, tpd: null },
+ card_required: false,
+ trains_on_free: null,
+ wording: 'Each provider on OpenRouter has its own data handling policies ... you can set whether you would like to allow routing to providers that may train on your data ... There are separate settings for paid and free models ... Wherever possible, OpenRouter works with providers to ensure that prompts will not be trained on, but there are exceptions.',
+ source: 'https://openrouter.ai/docs/api-reference/limits',
+ checked: '2026-11-12',
+ },
+ cohere: {
+ available: true,
+ summary: 'Trial API keys are free, issued automatically with an account, limited to 1,000 API calls/month at 20 requests/minute; not permitted for production or commercial use. Command A+ and North Mini Code are listed as Free.',
+ limits: { rpm: 20, rpd: null, tpm: null, tpd: null },
+ card_required: false,
+ trains_on_free: null,
+ wording: 'YOU GRANT US A NONEXCLUSIVE, WORLDWIDE, ROYALTY-FREE, IRREVOCABLE, SUBLICENSABLE, AND FULLY PAID-UP RIGHT TO ... USE ... CUSTOMER DATA ... TO: ... (III) IMPROVE AND ENHANCE THE COHERE SOLUTION AND OUR OTHER OFFERINGS ... INCLUDING BY SHARING API DATA AND FINETUNING DATA WITH THIRD PARTIES WHO MAY USE THE FINETUNING DATA AND API DATA TO PROVIDE SERVICES TO COHERE AND FOR OTHER PURPOSES PERMITTED UNDER THEIR TERMS AND CONDITIONS.',
+ source: 'https://docs.cohere.com/docs/rate-limits',
+ checked: '2026-11-12',
+ },
+ gemini: {
+ available: true,
+ summary: 'Free tier gives free input and output tokens on supported models (gemini-3.8-flash, gemini-3.6-flash, gemini-3.5-flash-lite were free on the pricing page). Gemini 4 Carbon/Argon/Hydrogen are not available on the Free tier.',
+ limits: { rpm: null, rpd: null, tpm: null, tpd: null },
+ card_required: false,
+ trains_on_free: true,
+ wording: 'For unpaid quota on Gemini API, Google uses the content you submit to the Services and any generated responses to provide, improve, and develop Google products and services and machine learning technologies ... To help with quality and improve our products, human reviewers may read, annotate, and process your API input and output.',
+ source: 'https://ai.google.dev/gemini-api/docs/pricing',
+ checked: '2026-11-12',
+ },
+};
+
const PROVIDERS = [
const PROVIDERS = [
{
{
key: 'qwen',
key: 'qwen',
@@ -645,6 +777,7 @@ const PROVIDERS = [
@@ -645,6 +777,7 @@ const PROVIDERS = [
provider_access: 'UNVERIFIED',
provider_access: 'UNVERIFIED',
priority: 90,
priority: 90,
role: 'fallback',
role: 'fallback',
+ free_tier: FREE_TIERS.openrouter,
privacy: privacy({
privacy: privacy({
label: 'anonymized',
label: 'anonymized',
terms_url: 'https://openrouter.ai/terms',
terms_url: 'https://openrouter.ai/terms',
@@ -694,6 +827,7 @@ const PROVIDERS = [
@@ -694,6 +827,7 @@ const PROVIDERS = [
key, display_name, base_url, docs_url, keys_url, credential_default_model, models_dev_id, default_model: model_key, timeout_ms: 60000,
key, display_name, base_url, docs_url, keys_url, credential_default_model, models_dev_id, default_model: model_key, timeout_ms: 60000,
capabilities: ['chat', 'generate', 'summarize', 'classify', 'extract', 'enrich', 'json', 'tools'],
capabilities: ['chat', 'generate', 'summarize', 'classify', 'extract', 'enrich', 'json', 'tools'],
provider_access, priority: 40, ...(uncensored ? { uncensored: true } : {}),
provider_access, priority: 40, ...(uncensored ? { uncensored: true } : {}),
+ ...(FREE_TIERS[key] ? { free_tier: FREE_TIERS[key] } : {}),
privacy: privacy({ label: privateTier ? 'private' : 'anonymized', terms_url: privateTier ? source : null,
privacy: privacy({ label: privateTier ? 'private' : 'anonymized', terms_url: privateTier ? source : null,
wording: privateTier ? 'Venice states prompts and generations are never stored or logged, and are not used to train future models for this model.' : 'Retention and training commitments were not confirmed on the provider page; unknown.' }),
wording: privateTier ? 'Venice states prompts and generations are never stored or logged, and are not used to train future models for this model.' : 'Retention and training commitments were not confirmed on the provider page; unknown.' }),
data_policy: policy({ trains: privateTier ? false : null, retention: privateTier ? 'none' : null,
data_policy: policy({ trains: privateTier ? false : null, retention: privateTier ? 'none' : null,
@@ -756,13 +890,16 @@ const PROVIDERS = [
@@ -756,13 +890,16 @@ const PROVIDERS = [
docs_url: 'https://platform.openai.com/docs/api-reference/models/list', capabilities: ['chat', 'vision', 'tools', 'image', 'video', 'speech', 'transcribe', 'embed'] },
docs_url: 'https://platform.openai.com/docs/api-reference/models/list', capabilities: ['chat', 'vision', 'tools', 'image', 'video', 'speech', 'transcribe', 'embed'] },
{ key: 'gemini', models_dev_id: 'google', keys_url: 'https://aistudio.google.com/apikey', display_name: 'Google AI Studio (Gemini API)', base_url: 'https://generativelanguage.googleapis.com/v1beta/openai',
{ key: 'gemini', models_dev_id: 'google', keys_url: 'https://aistudio.google.com/apikey', display_name: 'Google AI Studio (Gemini API)', base_url: 'https://generativelanguage.googleapis.com/v1beta/openai',
models_endpoint: 'https://generativelanguage.googleapis.com/v1beta/models',
models_endpoint: 'https://generativelanguage.googleapis.com/v1beta/models',
- api_family: 'google', docs_url: 'https://ai.google.dev/gemini-api/docs/openai', capabilities: ['chat', 'vision', 'tools', 'embed'] },
+ api_family: 'google', docs_url: 'https://ai.google.dev/gemini-api/docs/openai', capabilities: ['chat', 'vision', 'tools', 'embed'],
+ free_tier: FREE_TIERS.gemini },
{ key: 'xai', keys_url: 'https://console.x.ai/', display_name: 'xAI', base_url: 'https://api.x.ai/v1',
{ key: 'xai', keys_url: 'https://console.x.ai/', display_name: 'xAI', base_url: 'https://api.x.ai/v1',
docs_url: 'https://docs.x.ai/docs/api-reference', capabilities: ['chat', 'vision', 'tools', 'image', 'video'] },
docs_url: 'https://docs.x.ai/docs/api-reference', capabilities: ['chat', 'vision', 'tools', 'image', 'video'] },
{ key: 'mistral', keys_url: 'https://console.mistral.ai/api-keys', display_name: 'Mistral', base_url: 'https://api.mistral.ai/v1',
{ key: 'mistral', keys_url: 'https://console.mistral.ai/api-keys', display_name: 'Mistral', base_url: 'https://api.mistral.ai/v1',
- docs_url: 'https://docs.mistral.ai/api', capabilities: ['chat', 'vision', 'tools', 'embed', 'transcribe'] },
+ docs_url: 'https://docs.mistral.ai/api', capabilities: ['chat', 'vision', 'tools', 'embed', 'transcribe'],
+ free_tier: FREE_TIERS.mistral },
{ key: 'cohere', display_name: 'Cohere', base_url: 'https://api.cohere.com/compatibility/v1', models_endpoint: 'https://api.cohere.com/v1/models',
{ key: 'cohere', display_name: 'Cohere', base_url: 'https://api.cohere.com/compatibility/v1', models_endpoint: 'https://api.cohere.com/v1/models',
- docs_url: 'https://docs.cohere.com/docs/compatibility-api', capabilities: ['chat', 'tools', 'embed', 'rerank'] },
+ docs_url: 'https://docs.cohere.com/docs/compatibility-api', capabilities: ['chat', 'tools', 'embed', 'rerank'],
+ free_tier: FREE_TIERS.cohere },
{ key: 'perplexity', display_name: 'Perplexity', kind: 'responses', base_url: 'https://api.perplexity.ai/v1',
{ key: 'perplexity', display_name: 'Perplexity', kind: 'responses', base_url: 'https://api.perplexity.ai/v1',
docs_url: 'https://docs.perplexity.ai/docs/agent-api/openai-compatibility', capabilities: ['chat', 'web-search'], search_adapters: ['perplexity'] },
docs_url: 'https://docs.perplexity.ai/docs/agent-api/openai-compatibility', capabilities: ['chat', 'web-search'], search_adapters: ['perplexity'] },
{ key: 'brave', display_name: 'Brave Search', kind: 'http', base_url: 'https://api.search.brave.com/res/v1',
{ key: 'brave', display_name: 'Brave Search', kind: 'http', base_url: 'https://api.search.brave.com/res/v1',
@@ -37,6 +37,8 @@ function recordOf(p) {
@@ -37,6 +37,8 @@ function recordOf(p) {
data_policy: p.data_policy,
data_policy: p.data_policy,
// A provider's published request limits, kept by the router (server/providers/rate-gate.js).
// A provider's published request limits, kept by the router (server/providers/rate-gate.js).
rate_limits: p.rate_limits || null,
rate_limits: p.rate_limits || null,
+ // What the provider gives away without a paid plan, with the page and day it was read.
+ free_tier: p.free_tier || null,
// The privacy label of the provider: `private` only where its own terms say it keeps nothing and trains on
// The privacy label of the provider: `private` only where its own terms say it keeps nothing and trains on
// nothing, `anonymized` for everyone else. The wording and the page it was read from travel with it.
// nothing, `anonymized` for everyone else. The wording and the page it was read from travel with it.
privacy: p.privacy,
privacy: p.privacy,
@@ -26,21 +26,22 @@ const { ProviderError, insufficientBalance, retryable } = require('../server/pro
@@ -26,21 +26,22 @@ const { ProviderError, insufficientBalance, retryable } = require('../server/pro
const t = suite('ai-provider-adapters');
const t = suite('ai-provider-adapters');
-/** The provider's own domain: a price or a policy may only be read from the provider's own pages. */
+/** The provider's own domain: a price or a policy may only be read from the provider's own pages. `|` joins its domains. */
const DOMAIN = {
const DOMAIN = {
qwen: 'alibabacloud.com', kimi: 'kimi.ai', glm: 'z.ai', minimax: 'minimax.io', deepinfra: 'deepinfra.com',
qwen: 'alibabacloud.com', kimi: 'kimi.ai', glm: 'z.ai', minimax: 'minimax.io', deepinfra: 'deepinfra.com',
novita: 'novita.ai', featherless: 'featherless.ai', refuseless: 'refuseless.com', abliteration: 'abliteration.ai',
novita: 'novita.ai', featherless: 'featherless.ai', refuseless: 'refuseless.com', abliteration: 'abliteration.ai',
openrouter: 'openrouter.ai', venice: 'venice.ai', abliteratedmodels: 'abliteratedmodels.cc', uplinkswitch: 'uplinkswitch.ai',
openrouter: 'openrouter.ai', venice: 'venice.ai', abliteratedmodels: 'abliteratedmodels.cc', uplinkswitch: 'uplinkswitch.ai',
chutes: 'chutes.ai', siliconflow: 'siliconflow.com', nebius: 'nebius.com', together: 'together.ai',
chutes: 'chutes.ai', siliconflow: 'siliconflow.com', nebius: 'nebius.com', together: 'together.ai',
fireworks: 'fireworks.ai', groq: 'groq.com', cerebras: 'cerebras.ai', sambanova: 'sambanova.ai',
fireworks: 'fireworks.ai', groq: 'groq.com', cerebras: 'cerebras.ai', sambanova: 'sambanova.ai',
- baseten: 'baseten.co', hyperbolic: 'hyperbolic.xyz', parasail: 'parasail.io', 'particle-ai': 'particle.ai',
+ baseten: 'baseten.co', hyperbolic: 'hyperbolic.xyz|hyperbolic.ai', parasail: 'parasail.io', 'particle-ai': 'particle.ai',
'inference-net': 'inference.net', 'atlas-cloud': 'atlascloud.ai', avian: 'avian.io',
'inference-net': 'inference.net', 'atlas-cloud': 'atlascloud.ai', avian: 'avian.io',
nanogpt: 'nano-gpt.com', infermatic: 'totalgpt.ai', arliai: 'arliai.com', friendli: 'friendli.ai', scaleway: 'scaleway.com', anthropic: 'claude.com',
nanogpt: 'nano-gpt.com', infermatic: 'totalgpt.ai', arliai: 'arliai.com', friendli: 'friendli.ai', scaleway: 'scaleway.com', anthropic: 'claude.com',
+ mistral: 'mistral.ai', cohere: 'cohere.com', gemini: 'google.dev',
iteracompute: 'iteracompute.com', sable: 'sableapi.com', inception: 'inceptionlabs.ai', dosai: 'dos.ai', 'runpod-vllm': 'runpod.io', meta: 'meta.ai', altare: 'altare.global',
iteracompute: 'iteracompute.com', sable: 'sableapi.com', inception: 'inceptionlabs.ai', dosai: 'dos.ai', 'runpod-vllm': 'runpod.io', meta: 'meta.ai', altare: 'altare.global',
};
};
const onItsOwnSite = (url, key) => {
const onItsOwnSite = (url, key) => {
const host = new URL(url).hostname;
const host = new URL(url).hostname;
- return host === DOMAIN[key] || host.endsWith(`.${DOMAIN[key]}`);
+ return DOMAIN[key].split('|').some((domain) => host === domain || host.endsWith(`.${domain}`));
};
};
const noop = { get: async () => undefined, run: async () => ({}), all: async () => [] };
const noop = { get: async () => undefined, run: async () => ({}), all: async () => [] };
const iso = (n) => new Date(n).toISOString();
const iso = (n) => new Date(n).toISOString();
@@ -127,6 +128,17 @@ t.test('every price comes from the provider\'s own page, with the day it was rea
@@ -127,6 +128,17 @@ t.test('every price comes from the provider\'s own page, with the day it was rea
assert.strictEqual(pool.isUncensored(pool.byKey.get('featherless'), { model_key: 'some/Model-32B-abliterated' }), true);
assert.strictEqual(pool.isUncensored(pool.byKey.get('featherless'), { model_key: 'some/Model-32B-abliterated' }), true);
});
});
+t.test('every free tier states availability, its own page and the day it was read', () => {
+ const free = pool.PROVIDERS.filter((p) => p.free_tier);
+ assert.strictEqual(free.length, 12, 'the twelve providers read on 2026-11-12 carry their free tier');
+ for (const p of free) {
+ assert.strictEqual(typeof p.free_tier.available, 'boolean', `${p.key} free tier availability`);
+ assert.ok(p.free_tier.source && onItsOwnSite(p.free_tier.source, p.key), `${p.key} free tier page is its own`);
+ assert.strictEqual(p.free_tier.checked, '2026-11-12', `${p.key} free tier checked`);
+ }
+ assert.strictEqual(pool.byKey.get('groq').free_tier.limits.rpm, 30, 'Groq free plan is 30 RPM');
+});
+
t.test('the seed writes the privacy label, the quantization and the refusal rate into the registry', async () => {
t.test('the seed writes the privacy label, the quantization and the refusal rate into the registry', async () => {
const saved = new Map();
const saved = new Map();
const models = new Map();
const models = new Map();
@@ -143,6 +155,8 @@ t.test('the seed writes the privacy label, the quantization and the refusal rate
@@ -143,6 +155,8 @@ t.test('the seed writes the privacy label, the quantization and the refusal rate
assert.strictEqual(saved.get('abliteration').secret_ref, 'vault:abliteration');
assert.strictEqual(saved.get('abliteration').secret_ref, 'vault:abliteration');
assert.strictEqual(saved.get('deepinfra').metadata.privacy.label, 'private');
assert.strictEqual(saved.get('deepinfra').metadata.privacy.label, 'private');
assert.strictEqual(saved.get('qwen').metadata.privacy.label, 'anonymized');
assert.strictEqual(saved.get('qwen').metadata.privacy.label, 'anonymized');
+ assert.strictEqual(saved.get('groq').metadata.free_tier.checked, '2026-11-12');
+ assert.strictEqual(saved.get('groq').metadata.free_tier.limits.rpm, 30);
assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').metadata.refusal_rate, null);
assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').metadata.refusal_rate, null);
assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').metadata.quantization, null);
assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').metadata.quantization, null);
assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').cost.in_per_mtok, null);
assert.strictEqual(models.get('refuseless/deepseek-v4.1-flash-abliterated').cost.in_per_mtok, null);