import { type ApiKeyResolver, type ResolvedApiKey } from "../auth-retry.js"; import type { SessionAffinity } from "./affinity.js"; import type { CredentialPool } from "./pool.js"; import type { CredentialSelector } from "./select.js"; import type { AuthApiKeyOptions, AuthCredential, AuthSource, AuthSourceOptions, KeysApi, LimitsApi, OAuthRequestIdentity } from "./types.js"; /** Runtime (--api-key) and config (models.yml) key overrides plus the config-value resolver. */ export declare class KeyOverrides { #private; constructor(resolver?: (config: string) => Promise); has(provider: string): boolean; runtimeKey(provider: string): string | undefined; configKey(provider: string): string | undefined; /** Config value consulted only after stored OAuth/login credentials. */ fallbackKey(provider: string): string | undefined; /** Resolve a config value (env var name, "!command", literal) to the secret. */ resolve(config: string): Promise; /** * Set a runtime API key override (not persisted to disk). * Used for CLI --api-key flag. */ setRuntime(provider: string, apiKey: string): void; /** * Remove a runtime API key override. */ removeRuntime(provider: string): void; /** * Register a per-provider API key sourced from user configuration * (e.g. `models.yml` `providers..apiKey`). Higher priority than * stored credentials and OAuth tokens — when the user pins a key in * config, that key is what authenticates outbound requests, regardless * of whatever the broker happens to have loaded for that provider. * * Lower priority than {@link KeyOverrides.setRuntime} so a CLI `--api-key` * still wins for the duration of a single invocation. * * `fallback: true` instead ranks the value below stored OAuth and `/login` * credentials (at the env-var tier). Providers that own a `/login` flow use * this so their default key reference (e.g. an unset env-var name, which * resolves to its literal text) cannot shadow the key the user logged in with. */ setConfig(provider: string, apiKeyConfig: string, options?: { fallback?: boolean; }): void; /** * Remove a single config-sourced API key (override or fallback). */ removeConfig(provider: string): void; /** * Drop every config-sourced API key. Called by `ModelRegistry` before * re-parsing `models.yml` so removed entries actually disappear. */ clearConfig(): void; /** * Install the host's async config-value resolver. Coding-agent uses this so * every stored/config credential reference shares command caching, * failure backoff, and process hardening even when AuthStorage was created * independently and later attached to a registry. */ setResolver(resolver: (config: string) => Promise): void; } /** Dependencies of the provider key precedence cascade. */ export interface KeyCascadeDeps { pool: CredentialPool; overrides: KeyOverrides; selector: CredentialSelector; affinity: SessionAffinity; /** LimitsApi.rotate, injected to avoid a cascade↔rotation import cycle. */ rotate: LimitsApi["rotate"]; sourceLabel?: string; } /** The provider auth precedence cascade (runtime → config → OAuth → login key → env → stored key). */ export declare class KeyCascade implements KeysApi { #private; constructor(deps: KeyCascadeDeps); /** * True when a stored credential is the provider's KDL `empty-fallback` * keyless-mode marker — what an empty paste at an "Optional: paste API key" * login prompt stores (e.g. `lm-studio-local` for lm-studio). The wire layer * never sends these as a bearer (`isDiscoveryBearerApiKey` strips them), so * auth-status surfaces must not count them either; otherwise the model hub * and `/login` report the provider as authenticated while every request * goes out bare (issue #12281). The credential itself stays stored: `/logout` * can still remove it, and availability treats the provider as keyless. */ isKeylessFallback(provider: string, credential: AuthCredential): boolean; /** * True when the provider has stored credentials but none of them carries * auth — i.e. its only credential is the KDL `empty-fallback` keyless-mode * marker (an empty paste at an optional-key login prompt). Such a provider * is configured-but-keyless: model availability treats it like an * `auth: none` endpoint instead of locking it out (issue #12281). */ keyless(provider: string): boolean; /** * Classify where a provider's auth comes from, following the same precedence * as {@link KeyCascade.get}: runtime override → config override → * stored OAuth → login-stored api_key → config fallback → env var → stored api_key. * Returns undefined when no auth is configured. * * Compact, structured counterpart to {@link KeyCascade.describe}; `env` * selects dedicated-only, alias-aware, or no environment fallback. */ source(provider: string, { env }?: AuthSourceOptions): AuthSource | undefined; /** * Peek at API key for a provider without refreshing OAuth tokens. * Used for model discovery where we only need to know if credentials exist * and get a best-effort token. GitHub Copilot's peek must preserve * enterprise routing metadata because discovery needs a structured * credential to reach the correct host. */ peek(provider: string): Promise; /** Resolve a bearer together with the stored row that supplied it. */ getWithCredential(provider: string, sessionId?: string, options?: AuthApiKeyOptions): Promise; /** * Get API key for a provider. * Priority (first match wins): runtime override, config override, OAuth, * login API key, environment variable, then another stored API key. */ get(provider: string, sessionId?: string, options?: AuthApiKeyOptions, onCredentialId?: (id: number, identity?: OAuthRequestIdentity) => void): Promise; /** * Build an {@link ApiKeyResolver} backed by this storage, implementing the * central a/b/c auth-retry policy: * * - initial (`error: undefined`) → resolve the session credential. * - step (b) `!lastChance` → force-refresh the SAME session-sticky credential. * - step (c) `lastChance` → rotate to a sibling and re-resolve, unless quota exhaustion has no sibling. * * Used by web-search providers and other consumers that hold a KeyCascade * directly (no ModelRegistry in scope). */ resolver(provider: string, options?: { sessionId?: string; baseUrl?: string; modelId?: string; }): ApiKeyResolver; /** * Describe where the active credential for a provider came from. * * Mirrors {@link KeyCascade.get} precedence, highest first: * 1. Runtime override (`--api-key`). * 2. Config override (`models.yml` `providers..apiKey`). * 3. Stored OAuth credential. * 4. API key persisted by a successful `/login`. * 5. Env var — overrides a stored static api_key (e.g. a stale broker copy). * 6. Stored api_key credential. * * The string is purely informational; consumers must not parse it. */ describe(provider: string, sessionId?: string): string | undefined; setRuntime(provider: string, apiKey: string): void; removeRuntime(provider: string): void; setConfig(provider: string, apiKeyConfig: string, options?: { fallback?: boolean; }): void; removeConfig(provider: string): void; clearConfig(): void; setResolver(resolver: (config: string) => Promise): void; }