/**
 * Model resolution, scoping, and initial selection.
 *
 * Layering:
 * - `matchModel` is the single matching engine. Order: exact `provider/id`
 *   reference (with variant-alias and OpenRouter routed/date fallbacks) →
 *   exact bare id → retired variant alias → provider-scoped fuzzy → substring
 *   with alias-vs-dated pick.
 * - `parseModelPatternWithContext`/`parseModelPattern` layer the selector
 *   grammar on top: trailing `:level` thinking suffixes (`splitThinkingSuffix`)
 *   and `@upstream` provider routing (`splitUpstreamRouting`).
 * - Everything else (`resolveModelFromString`, `resolveModelOverride*`,
 *   `resolveRoleSelection`, `resolveModelScope`, `resolveCliModel`,
 *   `findSmolModel`/`findSlowModel`) adapts inputs — roles, settings patterns,
 *   CLI flags, scope globs — onto that pipeline.
 */
import { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import type { Api, Effort, Model } from "@oh-my-pi/pi-ai";
import { type ConfiguredThinkingLevel } from "../thinking.js";
import { type ModelRegistry } from "./model-registry.js";
import { type ModelRole } from "./model-roles.js";
import type { Settings } from "./settings.js";
/**
 * Pick the first provider-default model in availability order.
 *
 * If multiple providers expose that same default id, rank only that shared-id
 * group by canonical provider priority so native/OAuth transports beat mirrors
 * without changing unrelated provider fallback precedence.
 */
export declare function pickDefaultAvailableModel(availableModels: Model<Api>[]): Model<Api> | undefined;
export interface ScopedModel {
    model: Model<Api>;
    thinkingLevel?: ThinkingLevel;
    explicitThinkingLevel: boolean;
}
interface ThinkingSuffixOptions {
    allowMaxAlias?: boolean;
    allowAutoAlias?: boolean;
}
interface ModelStringParseOptions extends ThinkingSuffixOptions {
    isLiteralModelId?: (provider: string, id: string) => boolean;
}
/**
 * Parse a model string in "provider/modelId" format.
 * Returns undefined if the format is invalid.
 */
export declare function parseModelString(modelStr: string, options?: ModelStringParseOptions): {
    provider: string;
    id: string;
    thinkingLevel?: ConfiguredThinkingLevel;
} | undefined;
/**
 * Format a model as "provider/modelId" string.
 */
export declare function formatModelString(model: Model<Api>): string;
export declare function formatModelStringWithRouting(model: Model<Api>): string;
export declare function formatModelSelectorValue(selector: string, thinkingLevel: ConfiguredThinkingLevel | undefined): string;
/**
 * Split a trailing `@<upstream>` provider-routing selector off a model pattern.
 *
 * `openrouter/z-ai/glm-4.7@cerebras` -> base `openrouter/z-ai/glm-4.7`, upstream
 * `cerebras`. A `:thinking` suffix after the slug is kept on the base
 * (`...@cerebras:high` -> base `...:high`). Returns undefined when there is no
 * `@` or the suffix is not a bare provider slug, so model ids that legitimately
 * contain `@` (`claude-opus-4-8@default`, `workers-ai/@cf/...`) are never split.
 */
export declare function splitUpstreamRouting(pattern: string): {
    base: string;
    upstream: string;
} | undefined;
export declare function resolveProviderModelReference(provider: string, modelId: string, availableModels: readonly Model<Api>[]): Model<Api> | undefined;
export interface ModelMatchPreferences {
    /** Most-recently-used model keys (provider/modelId) to prefer when ambiguous. */
    usageOrder?: string[];
    /** Provider precedence used for ambiguous unqualified model patterns. */
    providerOrder?: readonly string[];
    /** Providers to deprioritize when no recent usage or provider priority is available. */
    deprioritizeProviders?: string[];
}
export type ModelLookupRegistry = Pick<ModelRegistry, "getAvailable">;
type CliModelRegistry = Pick<ModelRegistry, "getAll">;
type InitialModelRegistry = Pick<ModelRegistry, "getAvailable" | "find">;
type RestorableModelRegistry = Pick<ModelRegistry, "getAvailable" | "find" | "getApiKey">;
export declare function getModelMatchPreferences(settings?: Partial<Pick<Settings, "get" | "getStorage">>): ModelMatchPreferences;
export interface ParsedModelResult {
    model: Model<Api> | undefined;
    /** Thinking level if explicitly specified in pattern, undefined otherwise */
    thinkingLevel?: ConfiguredThinkingLevel;
    /** Upstream provider slug from an `@upstream` routing selector, if present. */
    upstream?: string;
    warning: string | undefined;
    explicitThinkingLevel: boolean;
}
export declare function parseModelPattern(pattern: string, availableModels: Model<Api>[], preferences?: ModelMatchPreferences, options?: {
    allowInvalidThinkingSelectorFallback?: boolean;
}): 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<Api> | undefined;
    thinkingLevel?: ConfiguredThinkingLevel;
    explicitThinkingLevel: boolean;
    warning: string | undefined;
}
export declare function resolveModelRoleValue(roleValue: string | undefined, availableModels: Model<Api>[], options?: {
    settings?: Settings;
    matchPreferences?: ModelMatchPreferences;
}): ResolvedModelRoleValue;
interface ExplicitThinkingSelectorOptions {
    isLiteralModelId?: (provider: string, id: string) => boolean;
}
export declare function extractExplicitThinkingSelector(value: string | undefined, settings?: Settings, options?: ExplicitThinkingSelectorOptions): ConfiguredThinkingLevel | undefined;
/**
 * Resolve a model identifier or pattern to a Model instance.
 */
export declare function resolveModelFromString(value: string, available: Model<Api>[], matchPreferences?: ModelMatchPreferences): Model<Api> | undefined;
/**
 * Resolve a model from configured roles, honoring order and overrides.
 */
export declare function resolveModelFromSettings(options: {
    settings: Settings;
    availableModels: Model<Api>[];
    matchPreferences?: ModelMatchPreferences;
    roleOrder?: readonly ModelRole[];
}): Model<Api> | undefined;
/**
 * Resolve a list of override patterns to the first matching model.
 */
export declare function resolveModelOverride(modelPatterns: string[], modelRegistry: ModelLookupRegistry, settings?: Settings): {
    model?: Model<Api>;
    thinkingLevel?: ConfiguredThinkingLevel;
    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<ModelRegistry, "getApiKey">, settings?: Settings): Promise<{
    model?: Model<Api>;
    thinkingLevel?: ConfiguredThinkingLevel;
    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<Api>[]): {
    model: Model<Api>;
    thinkingLevel?: ConfiguredThinkingLevel;
} | undefined;
/**
 * Resolve the model for the `advisor` role. A configured `modelRoles.advisor`
 * wins outright (a bad override surfaces as no model rather than silently
 * running something else); when unset it falls back to the `slow` priority
 * chain via {@link ROLE_PRIORITY_ALIAS} — a strong reasoning model that, unlike
 * the `slow` role itself, never inherits the primary's model. Returns undefined
 * only when no candidate in the resolved chain is available.
 */
export declare function resolveAdvisorRoleSelection(settings: Settings, availableModels: Model<Api>[]): {
    model: Model<Api>;
    thinkingLevel?: ConfiguredThinkingLevel;
} | 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<ModelRegistry, "getAvailable">, preferences?: ModelMatchPreferences): Promise<ScopedModel[]>;
/**
 * 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 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<ModelRegistry, "getAvailable">, settings: Settings | undefined, preferences?: ModelMatchPreferences): Promise<Model<Api>[]>;
/**
 * Synchronous subset of {@link resolveAllowedModels} for contexts where async is unavailable
 * (e.g. `getAvailableModels()` which is called from the ACP model-list advertisement, RPC
 * `get_available_models`, and the `/model` slash command). Uses the same effective
 * `enabledModels` scope semantics as startup resolution:
 *
 * - Glob selectors match `provider/modelId` and bare model id
 * - Exact `provider/modelId`, bare ids, provider-scoped fuzzy, and substring selectors
 *   resolve through the shared model-pattern matcher
 * - Optional `:thinkingLevel` suffixes are stripped only when valid
 *
 * When no pattern resolves to any model (misconfiguration / typo) an empty list is returned,
 * consistent with the empty-list contract of {@link resolveAllowedModels}. Callers that render
 * a UI picker should treat an empty list as "hide the picker entry", matching how the SDK
 * surfaces the same misconfiguration during session initialization.
 */
export declare function filterAvailableModelsByEnabledPatterns(available: Model<Api>[], patterns: readonly string[]): Model<Api>[];
export interface ResolveCliModelResult {
    model: Model<Api> | undefined;
    selector?: string;
    thinkingLevel?: ConfiguredThinkingLevel;
    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<Api> | 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<InitialModelResult>;
/**
 * Restore model from session, with fallback to available models
 */
export declare function restoreModelFromSession(savedProvider: string, savedModelId: string, currentModel: Model<Api> | undefined, shouldPrintMessages: boolean, modelRegistry: RestorableModelRegistry): Promise<{
    model: Model<Api> | 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<Model<Api> | 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<Model<Api> | undefined>;
export {};
