Configuration
Configuration
Section titled “Configuration”UPP provides flexible configuration options for provider infrastructure.
ProviderConfig
Section titled “ProviderConfig”All providers share a common configuration interface:
interface ProviderConfig { /** * API key - string, async function, or key strategy * @example 'sk-xxx' * @example () => fetchKeyFromVault() * @example roundRobinKeys(['sk-1', 'sk-2']) */ apiKey?: string | (() => string | Promise<string>) | KeyStrategy;
/** Override the base API URL (for proxies, local models) */ baseUrl?: string;
/** Request timeout in milliseconds */ timeout?: number;
/** Custom fetch implementation (for logging, caching, custom TLS) */ fetch?: typeof fetch;
/** API version override */ apiVersion?: string;
/** Retry strategy factory for handling failures and rate limits */ retryStrategy?: RetryStrategyFactory;
/** Custom HTTP headers to include in API requests */ headers?: Record<string, string>;}Provider-Specific Options
Section titled “Provider-Specific Options”Some providers accept additional options for vendor-specific operational choices. These are passed to the provider factory function, not to ProviderConfig:
interface OpenAIProviderOptions { /** * Which API to use: * - 'responses': Modern Responses API (default, recommended) * - 'completions': Legacy Chat Completions API */ api?: 'responses' | 'completions';}
// Use the modern Responses API (default)const gpt = llm({ model: openai('gpt-4o'),});
// Explicitly use the legacy Completions APIconst gptLegacy = llm({ model: openai('gpt-4o', { api: 'completions' }),});API Key Configuration
Section titled “API Key Configuration”const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { apiKey: 'sk-ant-xxx', },});const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { apiKey: process.env.ANTHROPIC_API_KEY, },});const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { apiKey: async () => { const secret = await fetchFromVault('anthropic-key'); return secret.value; }, },});Key Strategies
Section titled “Key Strategies”UPP provides built-in key strategies for API key management:
roundRobinKeys
Section titled “roundRobinKeys”Cycles through a list of API keys:
import { roundRobinKeys } from '@providerprotocol/ai';
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { apiKey: roundRobinKeys([ process.env.ANTHROPIC_KEY_1!, process.env.ANTHROPIC_KEY_2!, process.env.ANTHROPIC_KEY_3!, ]), },});weightedKeys
Section titled “weightedKeys”Selects keys based on weight (useful for tiered pricing or rate limits):
import { weightedKeys } from '@providerprotocol/ai';
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { apiKey: weightedKeys([ { key: process.env.PRIMARY_KEY!, weight: 0.7 }, { key: process.env.SECONDARY_KEY!, weight: 0.3 }, ]), },});dynamicKey
Section titled “dynamicKey”Custom key selection logic:
import { dynamicKey } from '@providerprotocol/ai';
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { apiKey: dynamicKey(async () => { // Custom logic to select key const keys = await fetchActiveKeys(); return selectLeastUsedKey(keys); }), },});Retry Strategies
Section titled “Retry Strategies”UPP provides pluggable retry strategies:
interface RetryStrategy { /** * Called when a request fails with a retryable error. * @returns Delay in ms before retrying, or null to stop retrying */ onRetry(error: UPPError, attempt: number): number | null | Promise<number | null>;
/** * Called before each request. Can be used for pre-emptive delays. */ beforeRequest?(): number | Promise<number>;
/** * Reset the strategy state (e.g., after a successful request) */ reset?(): void;
readonly maxAttempts?: number;
setRetryAfter?(seconds: number): void;}Provider configs accept a RetryStrategyFactory — a function that returns a fresh RetryStrategy per request, ensuring complete isolation between concurrent requests.
Built-in Strategies
Section titled “Built-in Strategies”import { exponentialBackoff, linearBackoff, noRetry, retryAfterStrategy,} from '@providerprotocol/ai';
// Exponential backoff (recommended)const strategy1 = exponentialBackoff({ maxAttempts: 3, baseDelay: 1000, maxDelay: 30000,});
// Linear backoffconst strategy2 = linearBackoff({ maxAttempts: 5, delay: 2000,});
// No retriesconst strategy3 = noRetry();Custom Strategy
Section titled “Custom Strategy”const myCustomStrategy: RetryStrategyFactory = () => ({ onRetry(error: UPPError, attempt: number): number | null { if (attempt >= 5) return null; if (error.code === 'RATE_LIMITED') return 5000; return 1000; }});
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { retryStrategy: myCustomStrategy, },});Base URL Override
Section titled “Base URL Override”Override the API endpoint for proxies or local models:
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { baseUrl: 'https://my-proxy.example.com', },});Custom Fetch
Section titled “Custom Fetch”Provide a custom fetch implementation for logging, caching, or custom TLS:
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { fetch: async (url, init) => { console.log('Request:', url); const response = await fetch(url, init); console.log('Response:', response.status); return response; }, },});Timeout Configuration
Section titled “Timeout Configuration”Set request timeout in milliseconds:
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { timeout: 30000, // 30 seconds },});Custom Headers
Section titled “Custom Headers”Add custom HTTP headers to API requests:
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { headers: { 'anthropic-beta': 'extended-cache-ttl-2025-04-11', }, },});Custom headers allow you to:
- Enable provider beta features (e.g., Anthropic’s
anthropic-betaheader) - Pass organization/project identifiers (e.g., OpenAI’s
OpenAI-Organization) - Provide attribution metadata (e.g., OpenRouter’s
HTTP-RefererandX-Title) - Configure proxy authentication (e.g., Cloudflare Access headers for Ollama)
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { apiKey: process.env.ANTHROPIC_API_KEY, headers: { 'anthropic-beta': 'extended-cache-ttl-2025-04-11', }, },});const model = llm({ model: openrouter('anthropic/claude-sonnet-4'), config: { apiKey: process.env.OPENROUTER_API_KEY, headers: { 'HTTP-Referer': 'https://myapp.example.com', 'X-Title': 'My Application', }, },});const gpt = llm({ model: openai('gpt-4o'), config: { apiKey: process.env.OPENAI_API_KEY, headers: { 'OpenAI-Organization': 'org-xxx', }, },});Full Configuration Example
Section titled “Full Configuration Example”import { llm } from '@providerprotocol/ai';import { anthropic } from '@providerprotocol/ai/anthropic';import type { AnthropicLLMParams } from '@providerprotocol/ai/anthropic';import { roundRobinKeys, exponentialBackoff } from '@providerprotocol/ai';
const claude = llm({ model: anthropic('claude-sonnet-4-20250514'), config: { apiKey: roundRobinKeys([ process.env.ANTHROPIC_KEY_1!, process.env.ANTHROPIC_KEY_2!, ]), baseUrl: 'https://my-proxy.example.com', timeout: 30000, retryStrategy: exponentialBackoff({ maxAttempts: 3 }), }, params: { max_tokens: 4096, temperature: 0.7, } as AnthropicLLMParams, system: 'You are a helpful assistant.',});