/** * Smart model routing for automatic tier-based model selection. * * Analyzes conversation signals after each turn and selects the optimal model * tier (fast/balanced/powerful) for the next turn based on task complexity. */ import type { AgentMessage, ThinkingLevel } from "@elyracode/agent-core"; import type { Api, Model } from "@elyracode/ai"; export interface SmartRouterConfig { enabled: boolean; /** Available models the router can pick from. Must have at least one. */ availableModels: Model[]; /** The user's preferred/current model -- used as the Tier 2 default and fallback. */ preferredModel: Model; /** * User-pinned models per tier (from settings). When set, a pin wins over * the heuristic ranking for its tier — the router decides the tier, the * user decides the model. Pins are still subject to the modality filter. */ pinnedModels?: Partial>>; /** * During a budgeted /goal loop, swap the routed model for its half-price * `:batch` sibling on the same provider when one exists. Unattended goal * work tolerates batch latency; interactive turns are never swapped * (the swap only applies while a goal budget is active). */ preferBatchDuringGoal?: boolean; } export interface TurnAnalysis { /** The messages in the conversation so far. */ messages: readonly AgentMessage[]; /** Current thinking level. */ thinkingLevel: ThinkingLevel; /** * Fraction (0..1+) of an active goal budget already spent, when a * budgeted /goal is running. Used to cap the tier as funds run low. */ budgetUsedFraction?: number; } export type ComplexityTier = "fast" | "balanced" | "powerful"; export interface SmartRouterResult { model: Model; tier: ComplexityTier; reason: string; /** False when the selected model is the one already in use. */ changed: boolean; /** * Thinking level for this turn, when routing lowers it below the session * setting. Undefined means keep the session level. Routing only ever * reduces effort - the user's chosen level is a ceiling, never a floor. */ thinkingLevel?: ThinkingLevel; } /** True when any user message in the conversation contains an image. */ export declare function conversationHasImages(messages: readonly AgentMessage[]): boolean; /** Bucket an output cost ($/million tokens) into a complexity tier. */ export declare function tierForOutputCost(outputCostPerMillion: number): ComplexityTier; /** Classify the complexity tier for the next turn. */ export declare function classifyComplexity(analysis: TurnAnalysis, previousTier?: ComplexityTier): { tier: ComplexityTier; reason: string; }; /** * Budget-aware tier capping: as an active goal budget depletes, cap the * tier so the loop spends the expensive turns early and rations later * instead of hitting the wall at full price. */ export declare function applyBudgetCap(result: { tier: ComplexityTier; reason: string; }, budgetUsedFraction: number | undefined): { tier: ComplexityTier; reason: string; }; /** * Select the best model for a given complexity tier from available models. * A user-pinned model for the tier wins over the heuristic ranking. * When the conversation contains images, only vision-capable models are * considered so routing can never break a multimodal session. */ export declare function selectModelForTier(tier: ComplexityTier, config: SmartRouterConfig, requiresImageInput?: boolean): Model; /** * Find a model's half-price `:batch` sibling on the same provider, if the * registry has one. Batch variants are ordinary streaming models with * relaxed latency and roughly half the price — a fit for unattended work. */ export declare function findBatchSibling(model: Model, availableModels: readonly Model[]): Model | undefined; /** * Pick the thinking level for a turn: the lower of the session level and the * tier's ceiling. Returns undefined when the session level already fits (no * change needed) or the model cannot reason at all. */ export declare function thinkingLevelForTier(tier: ComplexityTier, sessionLevel: ThinkingLevel, model: Model): ThinkingLevel | undefined; export declare function routeNextTurn(analysis: TurnAnalysis, config: SmartRouterConfig, previousTier?: ComplexityTier): SmartRouterResult | undefined; //# sourceMappingURL=smart-router.d.ts.map