@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
304 lines (303 loc) • 13.5 kB
JavaScript
import { PROVIDER_MAX_TOKENS } from "../core/constants.js";
import { getCatalogJsonEntries, getDecideCatalogEntries, } from "../providers/catalog/loader.js";
import { anthropicManifest } from "./manifests/anthropic.js";
import { openaiManifest } from "./manifests/openai.js";
import { azureManifest } from "./manifests/azure.js";
import { bedrockManifest } from "./manifests/bedrock.js";
import { ollamaManifest } from "./manifests/ollama.js";
import { mistralManifest } from "./manifests/mistral.js";
import { googleAiManifest } from "./manifests/google-ai.js";
import { openaiCompatibleManifest } from "./manifests/openai-compatible.js";
import { openrouterManifest } from "./manifests/openrouter.js";
import { vertexManifest } from "./manifests/vertex.js";
import { huggingfaceManifest } from "./manifests/huggingface.js";
import { litellmManifest } from "./manifests/litellm.js";
import { sagemakerManifest } from "./manifests/sagemaker.js";
import { deepseekManifest } from "./manifests/deepseek.js";
import { nvidiaNimManifest } from "./manifests/nvidia-nim.js";
import { lmStudioManifest } from "./manifests/lm-studio.js";
import { llamacppManifest } from "./manifests/llamacpp.js";
import { xaiManifest } from "./manifests/xai.js";
import { groqManifest } from "./manifests/groq.js";
import { typesafeManifest } from "./manifests/typesafe.js";
import { perplexityDeciderManifest } from "./manifests/perplexityDecider.js";
import { cloudflareClefManifest } from "./manifests/cloudflareClef.js";
import { cohereManifest } from "./manifests/cohere.js";
import { togetherAiManifest } from "./manifests/together-ai.js";
import { fireworksManifest } from "./manifests/fireworks.js";
import { perplexityManifest } from "./manifests/perplexity.js";
import { cloudflareManifest } from "./manifests/cloudflare.js";
import { replicateManifest } from "./manifests/replicate.js";
import { voyageManifest } from "./manifests/voyage.js";
import { jinaManifest } from "./manifests/jina.js";
import { stabilityManifest } from "./manifests/stability.js";
import { ideogramManifest } from "./manifests/ideogram.js";
import { recraftManifest } from "./manifests/recraft.js";
/**
* Builds a manifest for a JSON-catalog provider from its catalog entry.
*
* Only used for cerebras and sambanova (see MANIFEST_REGISTRY below) — the
* catalog JSON carries no per-model `maxOutputTokens`, only a provider-wide
* `models.defaultMaxOutputTokens`, so every derived entry uses that ceiling.
* For cerebras/sambanova this is 8192, identical to their old hand-written
* manifests' `maxOutputTokens`. The other 7 catalog providers' hand
* manifests carry higher documented ceilings — 64000 for groq, xai,
* together-ai, fireworks and perplexity, 8192 for mistral and cloudflare —
* that the JSON's `defaultMaxOutputTokens` (a generic 4096 placeholder for
* all 7) would silently regress, so they stay hand-written, untouched.
*
* `contextWindow` falls back to `models.defaultContextWindow` when a model
* spec omits its own (matches resolveManifestEntry's synthesized-`_default`
* fallback pattern above). `aliases` is always `[]` — CatalogModelSpec has
* no alias field.
*/
function buildCatalogManifest(entry) {
// capabilities.tools is "model-dependent" for huggingface, but
// huggingface uses its own hand-written manifest (see MANIFEST_REGISTRY
// below), never this generic path — cerebras/sambanova, the only two
// providers actually routed through buildCatalogManifest() today, both
// have a plain boolean here. Narrowed rather than widening
// ProviderModelManifestEntry.functionCalling itself: a provider entering
// this generic (non-hand-curated) path with "model-dependent" tools gets
// the conservative false, not an unearned optimistic true.
const functionCalling = entry.capabilities.tools === true;
const namedModels = Object.fromEntries(Object.entries(entry.models.catalog).map(([modelId, spec]) => [
modelId,
{
aliases: [],
contextWindow: spec.contextWindow ?? entry.models.defaultContextWindow,
maxOutputTokens: entry.models.defaultMaxOutputTokens,
vision: spec.vision,
functionCalling,
},
]));
return {
defaultContextWindow: entry.models.defaultContextWindow,
models: {
_default: {
aliases: [],
contextWindow: entry.models.defaultContextWindow,
maxOutputTokens: entry.models.defaultMaxOutputTokens,
vision: false,
functionCalling,
},
...namedModels,
},
};
}
const catalogManifest = (id) => {
const entry = getCatalogJsonEntries().find((e) => e.id === id);
if (!entry) {
throw new Error(`No catalog JSON entry found for provider "${id}"`);
}
return buildCatalogManifest(entry);
};
/**
* Builds a manifest for a decide catalog provider from its catalog entry.
*
* A decide model emits no text, but the manifest type requires a
* `maxOutputTokens`, so the figure a decide entry declares is carried over
* as is. A model that omits `contextWindow` or `maxOutputTokens` takes the
* default model's, and `_default` is the default model's own row.
* `functionCalling` is always false: a decide model has no tool calling.
* No row gets a `displayName`: the decide catalog has no field for one and
* no reader shows a decide model's manifest name.
*/
function buildDecideManifest(entry) {
const base = entry.models.catalog[entry.models.default];
if (base === undefined ||
base.contextWindow === undefined ||
base.maxOutputTokens === undefined) {
throw new Error(`Decide catalog entry "${entry.id}": models.default needs contextWindow and maxOutputTokens for its manifest`);
}
const baseWindow = base.contextWindow;
const baseMaxOutput = base.maxOutputTokens;
const toEntry = (spec) => ({
aliases: [],
contextWindow: spec.contextWindow ?? baseWindow,
maxOutputTokens: spec.maxOutputTokens ?? baseMaxOutput,
vision: spec.vision,
functionCalling: false,
});
return {
defaultContextWindow: baseWindow,
models: {
_default: toEntry(base),
...Object.fromEntries(Object.entries(entry.models.catalog).map(([modelId, spec]) => [
modelId,
toEntry(spec),
])),
},
};
}
/**
* Every provider's model manifest, keyed by the exact AIProviderName enum
* value (kebab-case) — e.g. "google-ai", "nvidia-nim". Manifests are pure
* data with zero heavy dependencies, so they are imported statically here
* (Critical Rule 1's dynamic-import mandate targets providerRegistry.ts's
* *provider* factories, which pull in real SDK clients — not this).
*/
export const MANIFEST_REGISTRY = {
anthropic: anthropicManifest,
openai: openaiManifest,
azure: azureManifest,
bedrock: bedrockManifest,
ollama: ollamaManifest,
mistral: mistralManifest,
"google-ai": googleAiManifest,
"openai-compatible": openaiCompatibleManifest,
openrouter: openrouterManifest,
vertex: vertexManifest,
huggingface: huggingfaceManifest,
litellm: litellmManifest,
sagemaker: sagemakerManifest,
deepseek: deepseekManifest,
"nvidia-nim": nvidiaNimManifest,
"lm-studio": lmStudioManifest,
llamacpp: llamacppManifest,
xai: xaiManifest,
groq: groqManifest,
typesafe: typesafeManifest,
...Object.fromEntries(getDecideCatalogEntries().map((e) => [e.id, buildDecideManifest(e)])),
"perplexity-decider": perplexityDeciderManifest,
"cloudflare-clef": cloudflareClefManifest,
cerebras: catalogManifest("cerebras"),
sambanova: catalogManifest("sambanova"),
cohere: cohereManifest,
"together-ai": togetherAiManifest,
fireworks: fireworksManifest,
perplexity: perplexityManifest,
cloudflare: cloudflareManifest,
replicate: replicateManifest,
voyage: voyageManifest,
jina: jinaManifest,
stability: stabilityManifest,
ideogram: ideogramManifest,
recraft: recraftManifest,
};
export function getManifestForProvider(provider) {
return MANIFEST_REGISTRY[provider];
}
export function getAllManifestProviders() {
return Object.keys(MANIFEST_REGISTRY);
}
/**
* Apply every matching family rule's patch, in declaration order, on top of
* a base entry. Later rules win on overlapping fields (last patch applied
* wins), matching the "later registrations overwrite earlier ones" idiom
* used elsewhere in this subsystem (see registerRuntimeContextWindow's
* docblock, src/lib/constants/contextWindows.ts).
*/
function applyFamilyRules(manifest, model, base) {
if (!manifest.familyRules) {
return base;
}
let result = base;
for (const rule of manifest.familyRules) {
if (rule.pattern.test(model)) {
result = { ...result, ...rule.patch };
}
}
return result;
}
/**
* Resolve a model against a provider's manifest WITHOUT ever falling back to
* the provider's `_default` entry. Used by callers that need to insert their
* own special-case fallback (cross-provider pricing, proxy pass-through)
* between "no real match" and "give up" — see resolveManifestEntry's
* docblock for why the split exists.
*
* Resolution order: exact canonical id, then a declared alias, then
* longest-prefix match (for tagged/gateway-shaped ids like Ollama's
* "llama3.2:latest" or OpenRouter's "openai/gpt-4o"), then undefined.
* Family rules are applied on top of whichever entry matched.
*/
/**
* Like resolveManifestEntryExact but WITHOUT the longest-prefix fallback:
* exact canonical id or declared alias only. For consumers where a prefix
* hit can steal precedence from a more-specific legacy row — boolean
* capability checks above all (a manifest "gpt-4" prefix match must never
* shadow the legacy table's explicit "gpt-4-vision-preview" vision row).
* Family rules still apply to a real match.
*/
export function resolveManifestEntryStrict(provider, model) {
const manifest = MANIFEST_REGISTRY[provider];
if (!manifest) {
return undefined;
}
const exact = manifest.models[model];
if (exact) {
return applyFamilyRules(manifest, model, exact);
}
const aliasMatch = Object.entries(manifest.models).find(([canonicalId, entry]) => canonicalId !== "_default" && entry.aliases.includes(model));
if (aliasMatch) {
return applyFamilyRules(manifest, model, aliasMatch[1]);
}
return undefined;
}
export function resolveManifestEntryExact(provider, model) {
const manifest = MANIFEST_REGISTRY[provider];
if (!manifest) {
return undefined;
}
const exact = manifest.models[model];
if (exact) {
return applyFamilyRules(manifest, model, exact);
}
const aliasMatch = Object.entries(manifest.models).find(([canonicalId, entry]) => canonicalId !== "_default" && entry.aliases.includes(model));
if (aliasMatch) {
return applyFamilyRules(manifest, model, aliasMatch[1]);
}
const sortedKeys = Object.keys(manifest.models)
.filter((k) => k !== "_default")
.sort((a, b) => b.length - a.length);
const prefixKey = sortedKeys.find((k) => model.startsWith(k));
if (prefixKey) {
return applyFamilyRules(manifest, model, manifest.models[prefixKey]);
}
return undefined;
}
/**
* Provider-specific output-token ceiling used to synthesize a `_default`
* entry when a manifest declares no explicit one (currently every
* MODEL_REGISTRY-generated manifest — azure, bedrock, ollama, mistral,
* google-ai — since `generateFullManifest` only emits real model ids).
* Mirrors the same table + fallback chain the minimal-manifest generator
* already uses (scripts/generate-remaining-manifests.ts), so a provider
* with no PROVIDER_MAX_TOKENS entry still gets an honest ceiling instead of
* `undefined`. Clamped against the manifest's own `defaultContextWindow` —
* an output ceiling can never legitimately exceed total context.
*/
function defaultMaxOutputTokens(provider, defaultContextWindow) {
const providerLimits = PROVIDER_MAX_TOKENS[provider];
const rawMax = typeof providerLimits === "number"
? providerLimits
: (providerLimits?.default ?? PROVIDER_MAX_TOKENS.default);
return Math.min(rawMax, defaultContextWindow);
}
/**
* Resolve a model against a provider's manifest, falling back to the
* provider's `_default` entry (synthesized from `PROVIDER_MAX_TOKENS`,
* clamped to `defaultContextWindow`, when no explicit `_default` model
* entry exists) when no real model matches. Family rules are tested
* against the ORIGINAL model string even on the `_default` path, so an
* unmatched gateway-shaped id still gets patched.
*/
export function resolveManifestEntry(provider, model) {
const exact = resolveManifestEntryExact(provider, model);
if (exact) {
return exact;
}
const manifest = MANIFEST_REGISTRY[provider];
if (!manifest) {
return undefined;
}
const defaultEntry = manifest.models._default ?? {
aliases: [],
contextWindow: manifest.defaultContextWindow,
maxOutputTokens: defaultMaxOutputTokens(provider, manifest.defaultContextWindow),
vision: false,
functionCalling: false,
};
return applyFamilyRules(manifest, model, defaultEntry);
}