/**
 * 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;
