/** * Model resolution, scoping, and initial selection */ import type { ThinkingLevel } from "@earendil-works/pi-agent-core"; import { type Api, type AuthOperationOptions, type KnownProvider, type Model } from "@earendil-works/pi-ai"; import type { ModelRuntime } from "./model-runtime.ts"; /** Default chat model IDs for providers with built-in chat models. */ export declare const defaultModelPerProvider: Partial>; export interface ScopedModel { model: Model; /** Thinking level if explicitly specified in pattern (e.g., "model:high"), undefined otherwise */ thinkingLevel?: ThinkingLevel; } export interface ModelReferenceRequest { /** Bare model id or `provider/id`, optionally followed by `:`. */ text: string; /** Only consider models from this provider. */ provider?: string; /** * A trailing `:` is only considered when the full text matches no model, since ids such as * OpenRouter's `qwen/qwen3-coder:exacto` contain colons. * - `none`: the suffix stays part of the id * - `strict`: a valid thinking level is parsed; any other suffix stays part of the id * - `lenient`: like `strict`, but an invalid suffix is dropped with a warning */ thinkingSuffix: "none" | "strict" | "lenient"; /** Match id and name substrings when no exact match exists. */ fuzzy: boolean; } export type ModelReferenceResult = { status: "resolved"; model: Model; thinkingLevel?: ThinkingLevel; warning?: string; } | { status: "ambiguous"; candidates: Model[]; usableCount: number; thinkingLevel?: ThinkingLevel; warning?: string; } | { status: "not-found"; /** Set when a provider is explicit or named by a `provider/` prefix, for building a custom model id. */ target?: ModelReferenceTarget; }; export interface ModelReferenceTarget { provider: string; providerModels: [Model, ...Model[]]; /** Text after the provider prefix as typed, including any `:`. */ modelText: string; /** `modelText` without a valid thinking suffix (unless `thinkingSuffix` is `none`). */ modelId: string; thinkingLevel?: ThinkingLevel; } /** * `usable` only breaks ties between providers, so a unique match resolves even without credentials * (`--api-key` first-time setup). */ export declare function resolveModelReference(request: ModelReferenceRequest, models: readonly Model[], usable: (provider: string) => boolean): ModelReferenceResult; /** Exact `provider/id` or bare id lookup without thinking suffixes or fuzzy matching. */ export declare function findExactModelReferenceMatch(modelReference: string, models: readonly Model[]): Model | undefined; export interface ModelScopeDiagnostic { type: "warning"; code: "no-match" | "invalid-thinking-level" | "ambiguous"; message: string; pattern: string; } export interface ResolveModelScopeResult { scopedModels: ScopedModel[]; diagnostics: ModelScopeDiagnostic[]; } /** * Resolve scope patterns (`--models`, `enabledModels`) to models with optional thinking levels. * * Every model in `models` is usable, so credentials cannot choose between providers offering the same * id. All of them are added, with a warning so the user can pick one with `provider/id`. */ export declare function resolveModelScopeFromModels(patterns: string[], models: readonly Model[]): ResolveModelScopeResult; export declare function resolveModelScopeWithDiagnostics(patterns: string[], modelRuntime: ModelRuntime, options?: AuthOperationOptions): Promise; export declare function resolveModelScope(patterns: string[], modelRuntime: ModelRuntime, options?: AuthOperationOptions): Promise; export interface ResolveCliModelResult { model: Model | undefined; thinkingLevel?: ThinkingLevel; warning: string | undefined; /** * Error message suitable for CLI display. * When set, model will be undefined. */ error: string | undefined; } /** * Resolve a single model from CLI flags. * * Supports: * - --provider --model * - --model / * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name) * * Note: This does not apply the thinking level by itself, but it may *parse* and * return a thinking level from ":" so the caller can apply it. */ export declare function resolveCliModel(options: { cliProvider?: string; cliModel?: string; cliThinking?: ThinkingLevel; /** `--api-key` was supplied for the selected provider. */ inlineApiKey?: boolean; modelRuntime: ModelRuntime; }): ResolveCliModelResult; export interface InitialModelResult { model: Model | undefined; thinkingLevel: ThinkingLevel; fallbackMessage: string | undefined; } /** * Find the initial model to use based on priority: * 1. First model from scoped models (if not continuing/resuming) * 2. Saved default from settings * 3. First available model with valid API key */ export declare function findInitialModel(options: { scopedModels: ScopedModel[]; isContinuing: boolean; defaultProvider?: string; defaultModelId?: string; defaultThinkingLevel?: ThinkingLevel; modelThinkingLevels?: Record; modelRuntime: ModelRuntime; }): Promise; /** * Restore model from session, with fallback to available models */ export declare function restoreModelFromSession(savedProvider: string, savedModelId: string, currentModel: Model | undefined, shouldPrintMessages: boolean, modelRuntime: ModelRuntime): Promise<{ model: Model | undefined; fallbackMessage: string | undefined; }>;