/** * Smart Router for Franklin * * Two routing modes: * 1. Learned — uses Elo scores from 2M+ gateway requests (router-weights.json) * 2. Classic — 15-dimension keyword scoring (fallback when no weights) * * The learned router detects request category (coding, trading, reasoning, etc.) * and picks the model with the best quality-to-cost ratio for that category. * Local Elo adjustments personalize routing per user over time. */ import { type TaskType } from '@blockrun/router-core'; import { type Category } from './categories.js'; export { isVisionModel, messageNeedsVision, messagesNeedVision, pickVisionSibling } from './vision.js'; export type Tier = 'SIMPLE' | 'MEDIUM' | 'COMPLEX' | 'REASONING'; export type RoutingProfile = 'auto' | 'free'; export interface RoutingResult { model: string; tier: Tier; confidence: number; signals: string[]; savings: number; category?: Category; /** Ordered capability-eligible recovery chain. The selected model is first. */ candidates?: string[]; /** Explainable task class produced by the shared Router core. */ taskType?: TaskType; /** Shared Router implementation that made this decision. */ routerVersion?: 'v2-rules' | 'v3-portfolio' | 'franklin-legacy'; reasoning?: string; } /** Request capabilities known by the Franklin host at routing time. */ export interface RoutingContext { needsVision?: boolean; maxOutputTokens?: number; hasTools?: boolean; toolNames?: readonly string[]; requiresTools?: boolean; requiresStructuredOutput?: boolean; systemPrompt?: string; } export type TierClassifier = (prompt: string) => Promise; /** * Default LLM classifier — lazy-imports the ModelClient to avoid a hard * cycle with agent/llm.ts (which itself imports routing helpers for virtual * profile resolution). Callers can substitute their own classifier for * tests by passing one to `routeRequestAsync`. */ export declare function llmClassifyRequest(prompt: string): Promise; /** * Compatibility async router. Production Auto routing is local and delegates * directly to the shared Router core, so it adds no classifier round trip. * Tests and third-party integrations may still inject an explicit classifier; * that legacy path remains available during the migration window. */ export declare function routeRequestAsync(prompt: string, profile?: RoutingProfile, classify?: TierClassifier, context?: boolean | RoutingContext): Promise; /** * Map a pre-classified tier to a concrete model + savings using the profile's * tier table. No classifier call — assumes the caller already decided the * tier (typically via the turn-analyzer, which rolls tier classification in * with intent / pushback / planning decisions in one LLM call). * * Use this when you have a tier already. Use `routeRequestAsync` when you * need the classifier to produce the tier. */ export declare function resolveTierToModel(tier: Tier, profile?: RoutingProfile, needsVision?: boolean): RoutingResult; export declare function routeRequest(prompt: string, profile?: RoutingProfile, context?: boolean | RoutingContext): RoutingResult; /** * Get fallback models for a tier */ export declare function getFallbackChain(tier: Tier, profile?: RoutingProfile): string[]; /** * Pick the next free model to try given the question category and which * free models have already failed this turn. Returns undefined when every * candidate has been exhausted (caller should surface an error to user). */ export declare function pickFreeFallback(category: string, alreadyFailed: Set): string | undefined; /** * Parse routing profile from model string */ export declare function parseRoutingProfile(model: string): RoutingProfile | null;