UNPKG

@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

80 lines (79 loc) • 4.57 kB
/** * The model catalogue — turning the registry into a routable pool. * * `ClassifierRouter` has always taken a host-declared `pool`, because the set * of models a host is *willing to be billed for* is not something NeuroLink * can invent. But the registry already knows 64 models across 7 providers * (132 aliases), each carrying a context window, in/out pricing, speed and * quality buckets, capability flags and seven 1–10 use-case scores — and * routing read none of it beyond cost and quality. `maxContextTokens` in * particular was never read anywhere. * * The registry covers 7 of the registered providers, so the catalogue is * an addition to a declared pool, never a replacement: a host routing over * LiteLLM, OpenRouter or a self-hosted model still declares those by hand, * and `enrichCandidate` ranks declared and catalogue members on one scale. * * This module closes that gap for hosts that opt in (`catalog.enabled`): it * builds pool members from the registry, intersected with the credentials * actually present, and renders each as one line for a decision model to rank. * * Two constraints shape everything here: * * 1. **The rendered catalogue is a question, not state.** A decision model's * binding limit is `state + the single longest question`, and the model * choice question's `criteria` map is that question. Rendering has to stay * terse and the count has to stay capped. * 2. **A deterministic ranker must exist first.** Every other decision * consumer falls back to what the code did before, but there was no * "pick from the whole registry" behaviour to fall back to. * {@link rankCatalogue} * is that fallback, and it runs whenever no decision provider is * configured, the call fails, or the verdict is not confident enough. * * @module routing/modelCatalog */ import type { ClassifierCandidate, ClassifierCatalogConfig, ClassifierDifficulty, ClassifierRouterInput, ClassifierRouterPoolMember, ModelInfo } from "../types/index.js"; /** Provider names this host has credentials for AND that generate text. */ export declare function reachableTextProviders(): Set<string>; /** * Rank candidates deterministically for a difficulty. The fallback that makes * the catalogue safe to enable: with no decision provider configured this is * the whole selection, and it never consults the network. * * `requiredCapabilities` filters leniently — a candidate with no recorded * capabilities is kept rather than starving the pool on missing metadata, * matching `ClassifierRouter.filterByCapabilities`. */ export declare function rankCatalogue(candidates: readonly ClassifierCandidate[], difficulty: ClassifierDifficulty, input?: Pick<ClassifierRouterInput, "estimatedInputTokens">, requiredCapabilities?: readonly string[]): ClassifierCandidate[]; /** * Build catalogue pool members from the registry. * * Returns `[]` when the catalogue is disabled or nothing is reachable, which * leaves the declared pool as the only source — the pre-catalogue behaviour. */ export declare function buildModelCatalog(config?: ClassifierCatalogConfig): ClassifierRouterPoolMember[]; /** * Enrich a pool member into a classifier candidate, pulling registry metadata * the member did not declare. * * Works for any pool, catalogue-derived or hand-declared: a host that listed * `{ provider: "openai", model: "gpt-4o" }` gets the same context window and * pricing as a catalogue entry, because both resolve through the registry. * Members the registry does not know (LiteLLM, self-hosted) keep exactly what * the host declared and are still rankable — `tierScore` falls back to * neutral values rather than dropping them. */ export declare function enrichCandidate(id: string, member: ClassifierRouterPoolMember, difficulty: ClassifierDifficulty, registry?: Map<string, ModelInfo>): ClassifierCandidate; /** Index the registry by model id once per build, for `enrichCandidate`. */ export declare function buildRegistryIndex(): Map<string, ModelInfo>; /** * Render one candidate as a single criteria line for the decision model. * * Terse on purpose: this text is multiplied by the candidate count inside a * single question, and that question competes with the request for the * ~33K ceiling. Numbers are rendered in units a reader can compare at a * glance (K tokens, ¢ per 1K) because a decision model reads digits as text * and does better with "128K" than with "131072". */ export declare function renderCandidate(candidate: ClassifierCandidate): string;