/** * Model resolution, scoping, and initial selection */ import { ThinkingLevel } from "@oh-my-pi/pi-agent-core"; import { type Api, type Effort, type KnownProvider, type Model } from "@oh-my-pi/pi-ai"; import { type ModelRegistry, type ModelRole } from "./model-registry"; import type { Settings } from "./settings"; /** Default model IDs for each known provider */ export declare const defaultModelPerProvider: Record; export interface ScopedModel { model: Model; thinkingLevel?: ThinkingLevel; explicitThinkingLevel: boolean; } /** * Parse a model string in "provider/modelId" format. * Returns undefined if the format is invalid. */ export declare function parseModelString(modelStr: string): { provider: string; id: string; thinkingLevel?: ThinkingLevel; } | undefined; /** * Format a model as "provider/modelId" string. */ export declare function formatModelString(model: Model): string; export declare function formatModelSelectorValue(selector: string, thinkingLevel: ThinkingLevel | undefined): string; export declare function resolveProviderModelReference(provider: string, modelId: string, availableModels: readonly Model[]): Model | undefined; export interface ModelMatchPreferences { /** Most-recently-used model keys (provider/modelId) to prefer when ambiguous. */ usageOrder?: string[]; /** Providers to deprioritize when no recent usage is available. */ deprioritizeProviders?: string[]; } export type CanonicalModelRegistry = Partial>; export type ModelLookupRegistry = Pick & Partial; type CliModelRegistry = Pick & Partial; type InitialModelRegistry = Pick; type RestorableModelRegistry = Pick; /** * Find an exact explicit provider/model match. * Bare model ids are handled separately so canonical ids can coalesce variants. */ export declare function findExactModelReferenceMatch(modelReference: string, availableModels: Model[]): Model | undefined; export interface ParsedModelResult { model: Model | undefined; /** Thinking level if explicitly specified in pattern, undefined otherwise */ thinkingLevel?: ThinkingLevel; warning: string | undefined; explicitThinkingLevel: boolean; } export declare function parseModelPattern(pattern: string, availableModels: Model[], preferences?: ModelMatchPreferences, options?: { allowInvalidThinkingSelectorFallback?: boolean; modelRegistry?: CanonicalModelRegistry; }): ParsedModelResult; /** * Expand a role alias like "pi/smol" to the configured model string. */ export declare function expandRoleAlias(value: string, settings?: Settings): string; export declare function resolveConfiguredModelPatterns(value: string | string[] | undefined, settings?: Settings): string[]; export interface AgentModelPatternResolutionOptions { settingsOverride?: string | string[]; agentModel?: string | string[]; settings?: Settings; activeModelPattern?: string; fallbackModelPattern?: string; } export declare function resolveAgentModelPatterns(options: AgentModelPatternResolutionOptions): string[]; /** * Resolve a model role value into a concrete model and thinking metadata. */ export interface ResolvedModelRoleValue { model: Model | undefined; thinkingLevel?: ThinkingLevel; explicitThinkingLevel: boolean; warning: string | undefined; } export declare function resolveModelRoleValue(roleValue: string | undefined, availableModels: Model[], options?: { settings?: Settings; matchPreferences?: ModelMatchPreferences; modelRegistry?: CanonicalModelRegistry; }): ResolvedModelRoleValue; export declare function extractExplicitThinkingSelector(value: string | undefined, settings?: Settings): ThinkingLevel | undefined; /** * Resolve a model identifier or pattern to a Model instance. */ export declare function resolveModelFromString(value: string, available: Model[], matchPreferences?: ModelMatchPreferences, modelRegistry?: CanonicalModelRegistry): Model | undefined; /** * Resolve a model from configured roles, honoring order and overrides. */ export declare function resolveModelFromSettings(options: { settings: Settings; availableModels: Model[]; matchPreferences?: ModelMatchPreferences; roleOrder?: readonly ModelRole[]; modelRegistry?: CanonicalModelRegistry; }): Model | undefined; /** * Resolve a list of override patterns to the first matching model. */ export declare function resolveModelOverride(modelPatterns: string[], modelRegistry: ModelLookupRegistry, settings?: Settings): { model?: Model; thinkingLevel?: ThinkingLevel; explicitThinkingLevel: boolean; }; /** * Resolve a list of override patterns to the first matching model, with an * auth-aware fallback to the parent session's active model. * * If the resolved subagent model has no working credentials (provider has no * usable auth), and the parent's active model resolves with working auth, * use the parent's model instead. This prevents subagent dispatch from * silently routing to a provider the user can't actually call (e.g. * `modelRoles.task` pointing at an unqualified id whose only available * provider variant has no configured credentials — see #985). * * Keyless-by-design providers (llama.cpp, ollama, lm-studio) advertise the * `kNoAuth` sentinel from `getApiKey` to signal that they do not require * credentials. Those are treated as authenticated here so an explicitly * configured local model is never silently rerouted to the parent's remote * provider (see #1008). * * If neither the subagent nor the parent has working auth, returns the * primary resolution unchanged so the existing error path still surfaces * a meaningful failure downstream. */ export declare function resolveModelOverrideWithAuthFallback(modelPatterns: string[], parentActiveModelPattern: string | undefined, modelRegistry: ModelLookupRegistry & Pick, settings?: Settings): Promise<{ model?: Model; thinkingLevel?: ThinkingLevel; explicitThinkingLevel: boolean; authFallbackUsed: boolean; }>; /** * Resolve a list of role patterns to the first matching model. */ export declare function resolveRoleSelection(roles: readonly string[], settings: Settings, availableModels: Model[], modelRegistry?: CanonicalModelRegistry): { model: Model; thinkingLevel?: ThinkingLevel; } | undefined; /** * Resolve model patterns to actual Model objects with optional thinking levels * Format: "pattern:level" where :level is optional * For each pattern, finds all matching models and picks the best version: * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929) * 2. If no alias, pick the latest dated version * * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto). * The algorithm tries to match the full pattern first, then progressively * strips colon-suffixes to find a match. */ export declare function resolveModelScope(patterns: string[], modelRegistry: Pick, preferences?: ModelMatchPreferences): Promise; /** * Resolve the set of models a session is allowed to use, given the active * settings. Starts from `modelRegistry.getAvailable()` (so disabled providers * and providers without credentials are already filtered out) and, when * `enabledModels` is configured for the current path scope, further restricts * the result to models matching those patterns. * * Returns the unfiltered available list when `enabledModels` is empty. * Returns an empty list when `enabledModels` is configured but no available * model matches any pattern — callers MUST treat this as "no usable model" * rather than falling back to the global default (see issue #1022). */ export declare function resolveAllowedModels(modelRegistry: Pick, settings: Settings | undefined, preferences?: ModelMatchPreferences): Promise[]>; export interface ResolveCliModelResult { model: Model | undefined; selector?: string; thinkingLevel?: ThinkingLevel; warning: string | undefined; error: string | undefined; } /** * Resolve a single model from CLI flags. */ export declare function resolveCliModel(options: { cliProvider?: string; cliModel?: string; modelRegistry: CliModelRegistry; preferences?: ModelMatchPreferences; }): ResolveCliModelResult; export interface InitialModelResult { model: Model | undefined; thinkingLevel?: ThinkingLevel; fallbackMessage: string | undefined; } /** * Find the initial model to use based on priority: * 1. CLI args (provider + model) * 2. First model from scoped models (if not continuing/resuming) * 3. Restored from session (if continuing/resuming) * 4. Saved default from settings * 5. First available model with valid API key */ export declare function findInitialModel(options: { cliProvider?: string; cliModel?: string; scopedModels: ScopedModel[]; isContinuing: boolean; defaultProvider?: string; defaultModelId?: string; defaultThinkingSelector?: Effort; modelRegistry: InitialModelRegistry; }): Promise; /** * Restore model from session, with fallback to available models */ export declare function restoreModelFromSession(savedProvider: string, savedModelId: string, currentModel: Model | undefined, shouldPrintMessages: boolean, modelRegistry: RestorableModelRegistry): Promise<{ model: Model | undefined; fallbackMessage: string | undefined; }>; /** * Find a smol/fast model using the priority chain. * Tries exact matches first, then fuzzy matches. * * @param modelRegistry The model registry to search * @param savedModel Optional saved model string from settings (provider/modelId) * @returns The best available smol model, or undefined if none found */ export declare function findSmolModel(modelRegistry: ModelLookupRegistry, savedModel?: string): Promise | undefined>; /** * Find a slow/comprehensive model using the priority chain. * Prioritizes reasoning and codex models for thorough analysis. * * @param modelRegistry The model registry to search * @param savedModel Optional saved model string from settings (provider/modelId) * @returns The best available slow model, or undefined if none found */ export declare function findSlowModel(modelRegistry: ModelLookupRegistry, savedModel?: string): Promise | undefined>; export {};