@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
688 lines (687 loc) • 26.7 kB
JavaScript
/**
* Centralized model choices for CLI commands
* Derives choices from model enums to ensure consistency
*/
import { AIProviderName, OpenAIModels, AnthropicModels, GoogleAIModels, BedrockModels, VertexModels, OllamaModels, AzureOpenAIModels, LiteLLMModels, SageMakerModels, OpenRouterModels, NvidiaNimModels, CohereModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, TypeSafeModels, LayaModels, XorModels, PerplexityDeciderModels, CloudflareClefModels, ReplicateModels, } from "../constants/enums.js";
import { getCatalogJsonEntries } from "../providers/catalog/loader.js";
/**
* Looks up the JSON catalog entry for a provider, if it is one of the 11
* JSON-catalog providers. Used to short-circuit the hand tables below so a
* catalog provider's models are always sourced from its catalog JSON, never
* from stale hand-written duplicates.
*/
function catalogEntryFor(provider) {
return getCatalogJsonEntries().find((entry) => entry.id === provider);
}
/**
* Derives CLI-prompt entries for a catalog provider. Uses the curated
* `models.topModels` ordering when the JSON provides one (mapping each id to
* its own `models.catalog[id].description`); falls back to the full
* `models.catalog` in file key-order when `topModels` is absent, matching
* the loader's documented fallback contract.
*/
function catalogTopModels(entry) {
if (entry.models.topModels) {
return entry.models.topModels.map((model) => ({
model,
description: entry.models.catalog[model].description,
}));
}
return Object.entries(entry.models.catalog).map(([model, spec]) => ({
model,
description: spec.description,
}));
}
/**
* Top models per provider with descriptions for CLI prompts
* These are curated lists of the most commonly used/recommended models
*
* Covers every provider EXCEPT the JSON-catalog providers (see
* `CatalogProviderName`) — their entries are derived from
* `models.catalog[*].description` by `catalogTopModels()` and merged in at
* the accessor-function level below, never hand-duplicated here.
*/
const TOP_MODELS_CONFIG = {
[]: [
{
model: OpenAIModels.GPT_4O,
description: "Recommended - Latest multimodal model",
},
{ model: OpenAIModels.GPT_4O_MINI, description: "Cost-effective, fast" },
{
model: OpenAIModels.GPT_5_2,
description: "Latest flagship with deep reasoning",
},
{ model: OpenAIModels.O3, description: "Advanced reasoning model" },
{ model: OpenAIModels.GPT_4_TURBO, description: "Previous generation" },
{
model: OpenAIModels.GPT_3_5_TURBO,
description: "Legacy, most cost-effective",
},
],
[]: [
{
model: AnthropicModels.CLAUDE_SONNET_4_5,
description: "Recommended - Latest and most capable",
},
{
model: AnthropicModels.CLAUDE_4_5_HAIKU,
description: "Fast and cost-effective",
},
{
model: AnthropicModels.CLAUDE_OPUS_4_5,
description: "Most powerful for complex tasks",
},
{
model: AnthropicModels.CLAUDE_3_5_SONNET,
description: "Excellent reasoning and coding",
},
{
model: AnthropicModels.CLAUDE_3_5_HAIKU,
description: "Fast and economical",
},
{
model: AnthropicModels.CLAUDE_3_OPUS,
description: "Previous gen, powerful",
},
],
[]: [
{
model: GoogleAIModels.GEMINI_2_5_FLASH,
description: "Recommended - Fast and efficient",
},
{
model: GoogleAIModels.GEMINI_2_5_PRO,
description: "Most capable, large context",
},
{
model: GoogleAIModels.GEMINI_2_0_FLASH,
description: "Stable production model",
},
{
model: GoogleAIModels.GEMINI_3_PRO_PREVIEW,
description: "Latest preview",
},
],
[]: [
{
model: VertexModels.GEMINI_2_5_FLASH,
description: "Recommended - Fast and efficient",
},
{
model: VertexModels.GEMINI_2_5_PRO,
description: "Most capable, large context",
},
{ model: VertexModels.CLAUDE_4_5_SONNET, description: "Claude on Vertex" },
{
model: VertexModels.GEMINI_2_0_FLASH,
description: "Stable production model",
},
{
model: VertexModels.CLAUDE_3_5_SONNET,
description: "Claude 3.5 on Vertex",
},
],
[]: [
{
model: BedrockModels.CLAUDE_4_5_SONNET,
description: "Recommended - Latest Claude",
},
{ model: BedrockModels.NOVA_PRO, description: "Amazon Nova balanced" },
{ model: BedrockModels.NOVA_LITE, description: "Fast and cost-effective" },
{ model: BedrockModels.CLAUDE_3_5_SONNET, description: "Excellent coding" },
{ model: BedrockModels.LLAMA_4_MAVERICK_17B, description: "Meta Llama 4" },
{ model: BedrockModels.MISTRAL_LARGE_3, description: "Mistral flagship" },
],
[]: [
{
model: AzureOpenAIModels.GPT_4O,
description: "Recommended - Latest multimodal",
},
{
model: AzureOpenAIModels.GPT_4O_MINI,
description: "Cost-effective, fast",
},
{ model: AzureOpenAIModels.GPT_5_1, description: "Latest flagship" },
{ model: AzureOpenAIModels.O3, description: "Advanced reasoning" },
{
model: AzureOpenAIModels.GPT_4_TURBO,
description: "Previous generation",
},
{ model: AzureOpenAIModels.GPT_3_5_TURBO, description: "Legacy model" },
],
[]: [
{
model: OllamaModels.LLAMA4_LATEST,
description: "Recommended - Latest Llama 4",
},
{
model: OllamaModels.LLAMA3_3_LATEST,
description: "High-performance local",
},
{ model: OllamaModels.DEEPSEEK_R1_70B, description: "Advanced reasoning" },
{ model: OllamaModels.QWEN3_72B, description: "Multilingual reasoning" },
{ model: OllamaModels.MISTRAL_LARGE_LATEST, description: "Mistral local" },
{
model: OllamaModels.LLAMA3_2_LATEST,
description: "Efficient local model",
},
],
[]: [
{ model: LiteLLMModels.OPENAI_GPT_4O, description: "OpenAI via LiteLLM" },
{
model: LiteLLMModels.ANTHROPIC_CLAUDE_SONNET_4_5,
description: "Anthropic via LiteLLM",
},
{ model: LiteLLMModels.GEMINI_2_5_PRO, description: "Google via LiteLLM" },
{
model: LiteLLMModels.GROQ_LLAMA_3_1_70B_VERSATILE,
description: "Groq via LiteLLM",
},
{ model: LiteLLMModels.MISTRAL_LARGE, description: "Mistral via LiteLLM" },
{
model: LiteLLMModels.VERTEX_GEMINI_2_5_PRO,
description: "Vertex via LiteLLM",
},
],
[]: [
{
model: SageMakerModels.LLAMA_4_MAVERICK_17B_128E,
description: "Recommended - Llama 4",
},
{ model: SageMakerModels.LLAMA_3_70B, description: "Meta Llama 3 70B" },
{ model: SageMakerModels.MISTRAL_SMALL_24B, description: "Mistral Small" },
{ model: SageMakerModels.MIXTRAL_8X7B, description: "Mixtral MoE" },
{ model: SageMakerModels.FALCON_3_10B, description: "Falcon 3" },
{ model: SageMakerModels.CODE_LLAMA_34B, description: "Code Llama" },
],
[]: [
{
model: OpenRouterModels.CLAUDE_SONNET_4_5,
description: "Anthropic via OpenRouter",
},
{ model: OpenRouterModels.GPT_4O, description: "OpenAI via OpenRouter" },
{
model: OpenRouterModels.GEMINI_2_0_FLASH,
description: "Google via OpenRouter",
},
{ model: OpenRouterModels.LLAMA_3_1_70B, description: "Meta Llama" },
{
model: OpenRouterModels.MISTRAL_LARGE,
description: "Mistral via OpenRouter",
},
{ model: OpenRouterModels.MIXTRAL_8X7B, description: "Mixtral MoE" },
],
[]: [
{ model: "gpt-4o", description: "OpenAI-compatible model" },
{ model: "gpt-4o-mini", description: "Fast compatible model" },
{ model: "gpt-4-turbo", description: "Turbo compatible model" },
{ model: "gpt-3.5-turbo", description: "Legacy compatible model" },
],
[]: [
{
model: "meta/llama-3.3-70b-instruct",
description: "Recommended - Llama 3.3 70B",
},
{
model: "nvidia/llama-3.3-nemotron-super-49b-v1",
description: "Nemotron Super (reasoning)",
},
{
model: "deepseek-ai/deepseek-r1",
description: "DeepSeek-R1 hosted on NIM",
},
{
model: "meta/llama-3.2-90b-vision-instruct",
description: "Llama 3.2 vision",
},
{
model: "mistralai/mixtral-8x22b-instruct-v0.1",
description: "Mixtral 8x22B",
},
],
[]: [
{
model: "",
description: "Auto-discover loaded model from /v1/models",
},
],
[]: [
{
model: "",
description: "Use whatever model llama-server has loaded",
},
],
[]: [
{
model: CohereModels.COMMAND_R_PLUS,
description: "Recommended - Flagship RAG-tuned chat",
},
{ model: CohereModels.COMMAND_R, description: "Smaller RAG-tuned chat" },
{ model: CohereModels.COMMAND_R7B, description: "Most compact" },
],
[]: [
{
model: "meta/meta-llama-3-70b-instruct",
description: "Recommended - Llama 3 70B Instruct (stable)",
},
{
model: "meta/meta-llama-3.1-405b-instruct",
description: "Llama 3.1 405B (flagship)",
},
{
model: "mistralai/mixtral-8x7b-instruct-v0.1",
description: "Mixtral 8x7B v0.1",
},
{
model: "black-forest-labs/flux-1.1-pro",
description: "FLUX 1.1 Pro (image-gen)",
},
{
model: "stability-ai/stable-diffusion-3.5-large",
description: "SD 3.5 Large (image-gen)",
},
],
[]: [
{
model: VoyageModels.VOYAGE_3_5,
description: "Recommended - General-purpose embeddings",
},
{
model: VoyageModels.VOYAGE_3_LARGE,
description: "Flagship — highest accuracy",
},
{
model: VoyageModels.VOYAGE_CODE_3,
description: "Code-tuned embeddings",
},
{
model: VoyageModels.VOYAGE_MULTILINGUAL_2,
description: "Multilingual embeddings",
},
{
model: VoyageModels.VOYAGE_3_5_LITE,
description: "Smaller / cheaper",
},
],
[]: [
{
model: JinaModels.JINA_EMBEDDINGS_V3,
description: "Recommended - Multilingual flagship",
},
{
model: JinaModels.JINA_EMBEDDINGS_V2_BASE_EN,
description: "v2 base English",
},
{
model: JinaModels.JINA_EMBEDDINGS_V2_BASE_CODE,
description: "v2 base code",
},
{
model: JinaModels.JINA_RERANKER_V2_BASE_MULTILINGUAL,
description: "Reranker (multilingual)",
},
{
model: JinaModels.JINA_COLBERT_V2,
description: "Late-interaction retrieval",
},
],
[]: [
{
model: StabilityModels.STABLE_IMAGE_ULTRA,
description: "Recommended - Flagship quality",
},
{
model: StabilityModels.STABLE_IMAGE_CORE,
description: "Fast tier",
},
{ model: StabilityModels.SD_3_5_LARGE, description: "SD 3.5 Large" },
{
model: StabilityModels.SD_3_5_LARGE_TURBO,
description: "SD 3.5 Large Turbo",
},
{ model: StabilityModels.SD_3_5_MEDIUM, description: "SD 3.5 Medium" },
],
[]: [
{ model: IdeogramModels.IDEOGRAM_V3, description: "Recommended - V3" },
{ model: IdeogramModels.IDEOGRAM_V2, description: "V2" },
{ model: IdeogramModels.IDEOGRAM_V2_TURBO, description: "V2 Turbo (fast)" },
{ model: IdeogramModels.IDEOGRAM_V1, description: "V1" },
],
[]: [
{
model: RecraftModels.RECRAFT_V3,
description: "Recommended - Raster V3",
},
{
model: RecraftModels.RECRAFT_V3_SVG,
description: "Vector / SVG output",
},
{ model: RecraftModels.RECRAFT_V2, description: "V2" },
],
[]: [
{
model: TypeSafeModels.JEV_LATEST,
description: "Recommended - Jev (decisions, not text)",
},
{
model: TypeSafeModels.JEV_PREVIEW,
description: "Preview build of Jev",
},
],
[]: [
{
model: LayaModels.TYPED_DECISIONS,
description: "Recommended - Laya fine-tuned for typed decisions",
},
{
model: LayaModels.MULTILINGUAL,
description: "Laya, 100+ languages",
},
{
model: LayaModels.ENGLISH,
description: "Laya, English base checkpoint (512-token window)",
},
{
model: LayaModels.AUTO,
description: "Let Laya pick a checkpoint by language",
},
],
[]: [
{
model: XorModels.XOR_1_1,
description: "Recommended - XOR 1.1, decision model that also reads images and video",
},
],
[]: [
{
model: PerplexityDeciderModels.PPLX_DECIDER_V1_27B,
description: "Recommended - Perplexity decision model that also reads images",
},
],
[]: [
{
model: CloudflareClefModels.CLEF,
description: "Recommended - Cloudflare Clef 27B decision model that also reads images (state limited to ~2,000 tokens)",
},
{
model: CloudflareClefModels.CLEF_FLASH,
description: "Clef-flash 9B - the faster, cheaper Cloudflare decision model (same ~2,000-token state limit)",
},
],
[]: [],
};
/**
* Default models per provider (first choice/recommended).
*
* Covers every provider EXCEPT the JSON-catalog providers (see
* `CatalogProviderName`) — those default models come from `models.default`
* in the catalog JSON, read directly by `getDefaultModel()` below. (cerebras,
* sambanova — never had a hand entry here at all; `getDefaultModel()` now
* resolves them too.)
*
* AUTO is also excluded — it never had an entry here either (matches
* pre-existing behavior: `getDefaultModel(AUTO)` returns `undefined`).
*/
export const DEFAULT_MODELS = {
[]: OpenAIModels.GPT_4O,
[]: AnthropicModels.CLAUDE_SONNET_4_5,
[]: GoogleAIModels.GEMINI_2_5_FLASH,
[]: VertexModels.GEMINI_2_5_FLASH,
[]: BedrockModels.CLAUDE_4_5_SONNET,
[]: AzureOpenAIModels.GPT_4O,
[]: OllamaModels.LLAMA4_LATEST,
[]: LiteLLMModels.OPENAI_GPT_4O,
[]: SageMakerModels.LLAMA_4_MAVERICK_17B_128E,
[]: OpenRouterModels.CLAUDE_SONNET_4_5,
[]: "gpt-4o",
[]: NvidiaNimModels.GPT_OSS_20B,
// LM Studio + llama.cpp auto-discover their loaded model from /v1/models;
// an empty default is the documented signal to use that path.
[]: "",
[]: "",
[]: CohereModels.COMMAND_R_PLUS,
[]: "meta/meta-llama-3-70b-instruct",
[]: VoyageModels.VOYAGE_3_5,
[]: JinaModels.JINA_EMBEDDINGS_V3,
[]: StabilityModels.STABLE_IMAGE_ULTRA,
[]: IdeogramModels.IDEOGRAM_V3,
[]: RecraftModels.RECRAFT_V3,
[]: TypeSafeModels.JEV_LATEST,
[]: LayaModels.TYPED_DECISIONS,
[]: XorModels.XOR_1_1,
[]: PerplexityDeciderModels.PPLX_DECIDER_V1_27B,
[]: CloudflareClefModels.CLEF,
};
/**
* Model enum mappings for getAllModels.
*
* Covers every provider EXCEPT the JSON-catalog providers (see
* `CatalogProviderName`) — those model lists come from
* `Object.keys(models.catalog)` in the catalog JSON, read directly by
* `getAllModels()` below.
*/
const MODEL_ENUMS = {
[]: OpenAIModels,
[]: AnthropicModels,
[]: GoogleAIModels,
[]: VertexModels,
[]: BedrockModels,
[]: AzureOpenAIModels,
[]: OllamaModels,
[]: LiteLLMModels,
[]: SageMakerModels,
[]: OpenRouterModels,
[]: null,
[]: NvidiaNimModels,
[]: null,
[]: null,
[]: CohereModels,
[]: ReplicateModels,
[]: VoyageModels,
[]: JinaModels,
[]: StabilityModels,
[]: IdeogramModels,
[]: RecraftModels,
[]: TypeSafeModels,
[]: LayaModels,
[]: XorModels,
[]: PerplexityDeciderModels,
[]: CloudflareClefModels,
[]: null,
};
/**
* Get top model choices for a provider (for CLI prompts)
* Returns models formatted for inquirer list prompts
*
* @param provider - The AI provider to get models for
* @param limit - Maximum number of models to return (default: 5)
* @returns Array of ModelChoice objects for CLI prompts
*/
export function getTopModelChoices(provider, limit = 5) {
const catalogEntry = catalogEntryFor(provider);
const config = catalogEntry
? catalogTopModels(catalogEntry)
: TOP_MODELS_CONFIG[provider];
if (!config || config.length === 0) {
return [];
}
const choices = config.slice(0, limit).map((item) => ({
// Empty-string entries are auto-discovery sentinels for LM Studio /
// llama.cpp. Surface them with a friendly label so the CLI doesn't show a
// blank row, but keep `value: ""` so it matches `DEFAULT_MODELS` (which
// also uses `""`) and any caller that preselects the active choice via
// the default model still resolves to this entry.
name: item.model.length > 0
? `${item.model} (${item.description})`
: `Auto-discover loaded model (${item.description})`,
value: item.model,
description: item.description,
}));
// Always add custom option at the end
choices.push({
name: "Custom model (enter manually)",
value: "custom",
description: "Enter a custom model name",
});
return choices;
}
/**
* Get all available models for a provider
* Returns all values from the provider's model enum
*
* For a JSON-catalog provider, excludes retired ids. The `catalog` map keeps
* retired entries as raw table keys (they still resolve for a caller who
* pins that id explicitly — see `isValidModel`'s dedicated retired-id
* allowance below), but a listing/selection surface should not offer them.
* Mirrors the `selectableModels` filter in catalog/schema.ts.
*
* @param provider - The AI provider to get models for
* @returns Array of model identifier strings
*/
export function getAllModels(provider) {
const catalogEntry = catalogEntryFor(provider);
if (catalogEntry) {
return Object.entries(catalogEntry.models.catalog)
.filter(([, spec]) => spec.status !== "retired")
.map(([model]) => model);
}
const modelEnum = MODEL_ENUMS[provider];
if (!modelEnum) {
return [];
}
return Object.values(modelEnum);
}
/**
* Get available provider choices for CLI
* Returns all provider names except AUTO
*
* @returns Array of provider name strings
*/
export function getProviderChoices() {
return Object.values(AIProviderName).filter((p) => p !== AIProviderName.AUTO);
}
/**
* Get all provider choices including AUTO
*
* @returns Array of all provider name strings
*/
export function getAllProviderChoices() {
return Object.values(AIProviderName);
}
/**
* Get the default model for a provider
*
* @param provider - The AI provider
* @returns Default model string for the provider
*/
export function getDefaultModel(provider) {
const catalogEntry = catalogEntryFor(provider);
if (catalogEntry) {
return catalogEntry.models.default;
}
return DEFAULT_MODELS[provider];
}
/**
* Check if a model is valid for a given provider
*
* `getAllModels` excludes retired catalog ids (it is a listing/selection
* surface), but a caller who pins a retired id explicitly must not have
* that pin start failing validation just because it dropped out of the
* listing — so this falls back to the full catalog (all statuses) before
* rejecting a JSON-catalog provider's model.
*
* The empty-listing case is checked against catalog membership, not
* accepted outright: a catalog provider whose every entry happens to be
* retired still has a real catalog to validate against, and a fabricated
* id must not slip through just because the *selectable* listing is empty.
* Only a provider with no catalog entry at all (openai-compatible,
* lm-studio, llamacpp — providers without a strict model list) keeps the
* permissive "allow any model" behavior.
*
* @param provider - The AI provider
* @param model - The model identifier to check
* @returns true if the model exists in the provider's model enum
*/
export function isValidModel(provider, model) {
const models = getAllModels(provider);
if (models.includes(model)) {
return true;
}
const catalogEntry = catalogEntryFor(provider);
if (catalogEntry) {
// Falls back to the FULL catalog (all statuses) so an explicitly pinned
// retired id still validates, and — critically — so an all-retired
// catalog (getAllModels() === []) is checked against real membership
// instead of accepting any string. Object.hasOwn (not `in`) so an
// inherited Object.prototype member name (e.g. "toString") is never
// mistaken for a real catalog key.
return Object.hasOwn(catalogEntry.models.catalog, model);
}
// No JSON catalog and no strict MODEL_ENUMS entry (openai-compatible,
// lm-studio, llamacpp): keep the permissive "allow any model" behavior.
return models.length === 0;
}
/**
* Get model choices formatted for inquirer prompts with a specific default
*
* @param provider - The AI provider
* @param currentModel - Current/existing model to mark as default
* @param limit - Maximum number of models to return
* @returns Array of ModelChoice objects with the current model marked
*/
export function getModelChoicesWithDefault(provider, currentModel, limit = 5) {
const choices = getTopModelChoices(provider, limit);
if (currentModel && !choices.some((c) => c.value === currentModel)) {
// Insert current model at the top if not already in the list
choices.unshift({
name: `${currentModel} (current)`,
value: currentModel,
description: "Currently configured model",
});
}
else if (currentModel) {
// Mark the current model in the list
const idx = choices.findIndex((c) => c.value === currentModel);
if (idx !== -1) {
choices[idx].name = `${choices[idx].name.replace(/\)$/, ", current)")}`;
}
}
return choices;
}
/**
* Get a flat list of popular models across all providers
* Useful for model suggestions and auto-complete
*
* @returns Array of { provider, model, description } objects
*/
export function getPopularModelsAcrossProviders() {
const popularModels = [];
// Take top 2 from each provider, ignoring blank auto-discovery sentinels.
// (Auto-discovery is surfaced separately by `getTopModelChoices` for
// LM Studio / llama.cpp; we don't want it to appear in the cross-
// provider popular-models list as an empty value.)
const pushTop2 = (provider, config) => {
config
.filter((item) => item.model.length > 0)
.slice(0, 2)
.forEach((item) => {
popularModels.push({
provider,
model: item.model,
description: item.description,
});
});
};
for (const [provider, config] of Object.entries(TOP_MODELS_CONFIG)) {
if (config && config.length > 0) {
pushTop2(provider, config);
}
}
// JSON-catalog providers are excluded from TOP_MODELS_CONFIG above; merge
// their models in here, derived the same way getTopModelChoices() does.
for (const entry of getCatalogJsonEntries()) {
pushTop2(entry.id, catalogTopModels(entry));
}
return popularModels;
}