/** * @license * Copyright 2025 Vybestack LLC * SPDX-License-Identifier: Apache-2.0 */ import { type IProvider, type GenerateChatOptions, type ProviderToolset } from './IProvider.js'; import { type IModel } from './IModel.js'; import { type IContent } from '../services/history/IContent.js'; import { AuthPrecedenceResolver, type OAuthManager } from '../auth/precedence.js'; import type { Config } from '../config/config.js'; import { type IProviderConfig } from './types/IProviderConfig.js'; import type { ProviderRuntimeContext } from '../runtime/providerRuntimeContext.js'; import { type RuntimeInvocationContext } from '../runtime/RuntimeInvocationContext.js'; import { SettingsService } from '../settings/SettingsService.js'; import type { ProviderTelemetryContext, ResolvedAuthToken, UserMemoryInput } from './types/providerRuntime.js'; export interface BaseProviderConfig { name: string; apiKey?: string; baseURL?: string; envKeyNames?: string[]; isOAuthEnabled?: boolean; oauthProvider?: string; oauthManager?: OAuthManager; supportsOAuth?: boolean; } export interface NormalizedGenerateChatOptions extends GenerateChatOptions { settings: SettingsService; config?: Config; userMemory?: UserMemoryInput; runtime?: ProviderRuntimeContext; invocation: RuntimeInvocationContext; tools?: ProviderToolset; metadata: Record; resolved: { model: string; baseURL?: string; authToken: ResolvedAuthToken; telemetry?: ProviderTelemetryContext; temperature?: number; maxTokens?: number; streaming?: boolean; }; } /** * Abstract base provider class that implements authentication precedence logic * This class provides lazy OAuth triggering and proper authentication precedence */ export declare abstract class BaseProvider implements IProvider { readonly name: string; protected authResolver: AuthPrecedenceResolver; protected baseProviderConfig: BaseProviderConfig; protected providerConfig?: IProviderConfig; /** * @plan PLAN-20250218-STATELESSPROVIDER.P05 * @requirement REQ-SP-001 * @pseudocode provider-invocation.md lines 8-15 */ private defaultSettingsService; private defaultConfig?; private readonly activeCallContext; protected throttleTracker?: (waitTimeMs: number) => void; protected get globalConfig(): Config | undefined; protected set globalConfig(config: Config | undefined); constructor(config: BaseProviderConfig, providerConfig?: IProviderConfig, globalConfig?: Config, settingsService?: SettingsService); /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @plan:PLAN-20251018-STATELESSPROVIDER2.P06 * @requirement REQ-SP2-001 * @pseudocode base-provider-call-contract.md lines 1-2 */ setRuntimeSettingsService(settingsService: SettingsService | null | undefined): void; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @plan:PLAN-20251023-STATELESS-HARDENING.P05 * @requirement REQ-SP2-001 * @requirement:REQ-SP4-001 * @pseudocode base-provider-call-contract.md lines 1-3 */ protected resolveSettingsService(): SettingsService; /** * Set throttle tracking callback (used by LoggingProviderWrapper) */ setThrottleTracker(tracker: (waitTimeMs: number) => void): void; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @requirement REQ-SP2-001 * @pseudocode base-provider-call-contract.md lines 2-3 * Gets the base URL with proper precedence: * 1. Ephemeral settings (highest priority - from /baseurl or profile) * 2. Provider-specific settings in SettingsService * 3. Provider config (from IProviderConfig) * 4. Base provider config (initial constructor value) * 5. undefined (use provider default) */ protected getBaseURL(): string | undefined; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @requirement REQ-SP2-001 * @pseudocode base-provider-call-contract.md lines 2-3 * Gets the current model with proper precedence: * 1. Ephemeral settings (highest priority) * 2. Provider-specific settings in SettingsService * 3. Provider config * 4. Default model */ protected getModel(): string; private computeBaseURL; private computeModel; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @requirement REQ-SP2-001 * @pseudocode base-provider-call-contract.md lines 1-3 * Gets authentication token using the precedence chain * This method implements lazy OAuth triggering - only triggers OAuth when actually making API calls * Returns empty string if no auth is available (for local/self-hosted endpoints) */ protected getAuthToken(): Promise; /** * Get auth token for prompt send - CAN trigger OAuth if needed * Use this method ONLY when actually sending a prompt to the API */ protected getAuthTokenForPrompt(): Promise; /** * Checks if OAuth is enabled for this provider */ protected isOAuthEnabled(): boolean; /** * Abstract method to determine if this provider supports OAuth * Must be implemented by concrete providers */ protected abstract supportsOAuth(): boolean; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @requirement REQ-SP2-001 * @pseudocode base-provider-call-contract.md lines 1-3 * Checks if authentication is available without triggering OAuth */ hasNonOAuthAuthentication(): Promise; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @requirement REQ-SP2-001 * @pseudocode base-provider-call-contract.md lines 1-3 * Checks if OAuth is the only available authentication method */ isOAuthOnlyAvailable(): Promise; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @requirement REQ-SP2-001 * @pseudocode base-provider-call-contract.md lines 1-3 * Gets the current authentication method name for debugging */ getAuthMethodName(): Promise; /** * Clears authentication (used when removing keys/keyfiles) */ clearAuth?(): void; /** * Updates OAuth configuration */ protected updateOAuthConfig(isEnabled: boolean, provider?: string, manager?: OAuthManager): void; /** * Clears the authentication token cache. * This ensures that after logout, fresh tokens are fetched on the next * authentication attempt without requiring a provider switch. * * @plan PLAN-20251023-STATELESS-HARDENING * @requirement Issue #975 - OAuth logout cache invalidation */ clearAuthCache(): void; /** * Checks if the provider is authenticated using any available method */ isAuthenticated(): Promise; abstract getModels(): Promise; abstract getDefaultModel(): string; /** * @plan PLAN-20250218-STATELESSPROVIDER.P04 * @requirement REQ-SP-001 * @pseudocode base-provider.md lines 4-15 */ generateChatCompletion(options: GenerateChatOptions): AsyncIterableIterator; generateChatCompletion(contents: IContent[], tools?: ProviderToolset): AsyncIterableIterator; /** * @plan PLAN-20250218-STATELESSPROVIDER.P04 * @requirement REQ-SP-001 * @pseudocode base-provider.md lines 7-15 */ protected abstract generateChatCompletionWithOptions(options: NormalizedGenerateChatOptions): AsyncIterableIterator; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @requirement REQ-SP2-001 * @pseudocode base-provider-call-contract.md lines 3-5 */ private invokeWithNormalizedOptions; /** * @plan PLAN-20251018-STATELESSPROVIDER2.P06 * @plan:PLAN-20251023-STATELESS-HARDENING.P05 * @requirement REQ-SP2-001 * @requirement:REQ-SP4-001 * @pseudocode base-provider-call-contract.md lines 1-3 */ private normalizeGenerateChatOptions; private buildEphemeralsSnapshot; /** * @plan:PLAN-20251023-STATELESS-HARDENING.P05 * @requirement:REQ-SP4-001 * @pseudocode base-provider-fallback-removal.md lines 11-14 */ protected assertRuntimeContext(input: { providerKey: string; settings?: SettingsService | null; config?: Config | null; runtime?: ProviderRuntimeContext; metadata?: Record; resolved?: NormalizedGenerateChatOptions['resolved']; stage: string; }): { runtime: ProviderRuntimeContext; metadata: Record; }; getCurrentModel?(): string; getToolFormat?(): string; isPaidMode?(): boolean; clearState?(): void; setConfig?(config: unknown): void; getServerTools(): string[]; invokeServerTool(toolName: string, _params: unknown, _config?: unknown, _signal?: AbortSignal): Promise; getModelParams?(): Record | undefined; /** * Get setting value from SettingsService */ protected getProviderSetting(key: keyof ProviderSettings, fallback?: T): Promise; /** * Set setting value in SettingsService */ protected setProviderSetting(key: keyof ProviderSettings, value: T): Promise; /** * Get API key from SettingsService if available */ protected getApiKeyFromSettings(): Promise; /** * Set API key in SettingsService if available */ protected setApiKeyInSettings(apiKey: string): Promise; /** * Get model from SettingsService if available */ protected getModelFromSettings(): Promise; /** * Set model in SettingsService if available */ protected setModelInSettings(model: string): Promise; /** * Get base URL from SettingsService if available */ protected getBaseUrlFromSettings(): Promise; /** * Set base URL in SettingsService if available */ protected setBaseUrlInSettings(baseUrl?: string): Promise; /** * Get model parameters from SettingsService */ protected getModelParamsFromSettings(): Promise | undefined>; /** * Set model parameters in SettingsService */ protected setModelParamsInSettings(params: Record | undefined): Promise; /** * Get custom headers from provider configuration and ephemeral settings. * * This merges: * - Provider config `customHeaders` * - Ephemeral `custom-headers` * - Ephemeral `user-agent` (mapped into a `User-Agent` header) * - Invocation `customHeaders` (from separated settings) */ protected getCustomHeaders(options?: NormalizedGenerateChatOptions): Record | undefined; } interface ProviderSettings { enabled: boolean; apiKey?: string; baseUrl?: string; model?: string; maxTokens?: number; temperature?: number; [key: string]: unknown; } export {};