import { z } from 'zod'; import { Stream } from '@aid-on/nagare'; /** * @aid-on/unilmp - Type definitions * * Edge-native types for LLM providers: Groq, Gemini, Cloudflare Workers AI * * Key concept: ModelSpec = "provider:model" (e.g., "groq:llama-3.1-8b-instant") */ type ProviderType = "groq" | "gemini" | "cloudflare" | "openai" | "anthropic"; /** Anthropic supported models (verified 2025-12-26) */ type AnthropicModel = "claude-opus-4-5-20251101" | "claude-haiku-4-5-20251001" | "claude-sonnet-4-5-20250929" | "claude-opus-4-1-20250805" | "claude-opus-4-20250514" | "claude-sonnet-4-20250514" | "claude-3-5-haiku-20241022" | "claude-3-haiku-20240307"; /** OpenAI supported models (verified 2025-12-26) */ type OpenAIModel = "gpt-4o" | "gpt-4o-mini" | "gpt-4o-2024-11-20" | "gpt-4o-2024-08-06" | "gpt-4o-2024-05-13" | "gpt-4o-mini-2024-07-18" | "gpt-4-turbo" | "gpt-4-turbo-preview" | "gpt-4-turbo-2024-04-09" | "gpt-4-0125-preview" | "gpt-4-1106-preview" | "gpt-4" | "gpt-4-0613" | "gpt-4-0314" | "gpt-3.5-turbo" | "gpt-3.5-turbo-0125" | "gpt-3.5-turbo-1106"; /** Groq supported models (verified 2025-01-15) */ type GroqModel = "llama-3.1-8b-instant" | "llama-3.3-70b-versatile" | "meta-llama/llama-guard-4-12b" | "openai/gpt-oss-120b" | "openai/gpt-oss-20b" | "groq/compound" | "groq/compound-mini"; /** Gemini supported models (verified 2025-01-15) */ type GeminiModel = "gemini-3-pro-preview" | "gemini-3-flash-preview" | "gemini-3-pro-image-preview" | "gemini-2.5-pro" | "gemini-2.5-flash" | "gemini-2.5-flash-lite" | "gemini-2.5-flash-image" | "gemini-2.0-flash" | "gemini-2.0-flash-lite" | "gemini-2.0-flash-001" | "gemini-2.0-pro-exp-02-05" | "gemini-1.5-pro-002" | "gemini-1.5-flash-002" | "gemini-1.5-flash-8b-001" | "gemini-1.5-pro-latest" | "gemini-1.5-flash-latest" | "gemini-exp-1121" | "gemini-exp-1114"; /** Cloudflare Workers AI supported models (verified 2025-01-15) */ type CloudflareModel = "@cf/openai/gpt-oss-120b" | "@cf/openai/gpt-oss-20b" | "@cf/meta/llama-4-scout-17b-16e-instruct" | "@cf/meta/llama-3.3-70b-instruct-fp8-fast" | "@cf/meta/llama-3.1-70b-instruct" | "@cf/meta/llama-3.1-8b-instruct-fast" | "@cf/meta/llama-3.1-8b-instruct" | "@cf/ibm/granite-4.0-h-micro" | "@cf/mistralai/mistral-small-3.1-24b-instruct" | "@cf/mistralai/mistral-7b-instruct-v0.2" | "@cf/google/gemma-3-12b-it" | "@cf/qwen/qwq-32b" | "@cf/qwen/qwen2.5-coder-32b-instruct" | "@cf/qwen/qwen3-30b-a3b-fp8"; /** All model types */ type AnyModel = AnthropicModel | OpenAIModel | GroqModel | GeminiModel | CloudflareModel; /** * ModelSpec: "provider:model" format string * * Examples: * - "anthropic:claude-3-5-sonnet-latest" * - "openai:gpt-4o" * - "groq:llama-3.1-8b-instant" * - "gemini:gemini-2.0-flash" * - "cloudflare:@cf/meta/llama-3.3-70b-instruct-fp8-fast" */ type ModelSpec = `anthropic:${AnthropicModel}` | `openai:${OpenAIModel}` | `groq:${GroqModel}` | `gemini:${GeminiModel}` | `cloudflare:${CloudflareModel}`; /** * Parsed ModelSpec */ interface ParsedModelSpec { provider: ProviderType; model: string; spec: ModelSpec; } interface Credentials { anthropicApiKey?: string; openaiApiKey?: string; groqApiKey?: string; geminiApiKey?: string; /** Cloudflare API credentials (for REST API) */ cloudflareApiKey?: string; cloudflareEmail?: string; cloudflareAccountId?: string; } interface ModelInfo { /** Full spec: "provider:model" */ spec: ModelSpec; /** Provider type */ provider: ProviderType; /** Model ID (without provider prefix) */ model: string; /** Display name */ name: string; /** Context window size */ contextWindow: number; /** Speed rating */ speed: "fast" | "medium" | "slow"; /** Cost rating */ cost: "free" | "low" | "medium" | "high"; } interface CheckResult { /** Full spec: "provider:model" */ spec: string; provider: ProviderType; model: string; success: boolean; responseTime: number; response?: string; error?: string; request: { model: string; messages: Array<{ role: string; content: string; }>; temperature?: number; }; rawResponse?: unknown; } interface CheckOptions { stream?: boolean; tools?: boolean; json?: boolean; verbose?: boolean; } interface GenerateOptions { temperature?: number; maxTokens?: number; stream?: boolean; } interface GenerateResult { text: string; usage?: { promptTokens: number; completionTokens: number; }; } /** * Cloudflare Workers AI REST API * * Edge-native implementation for Cloudflare Workers AI via REST API. * Supports both standard and streaming responses. */ interface CloudflareRestResponse { result: { response: string; output?: Array<{ type: string; role: string; content?: Array<{ text?: string; }>; }>; usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number; }; }; success: boolean; errors: unknown[]; messages: unknown[]; } /** * Call Cloudflare Workers AI via REST API */ declare function callCloudflareRest(model: string, messages: Array<{ role: string; content: string; }>, credentials: Credentials): Promise; /** * Call Cloudflare Workers AI via REST API with streaming */ declare function callCloudflareRestStream(model: string, messages: Array<{ role: string; content: string; }>, credentials: Credentials): AsyncGenerator; /** * Provider-Specific Factory Functions * * Edge-native implementations for each LLM provider's API. * Each function uses pure fetch API with no external dependencies. */ interface ProviderResponse { text: string; usage?: { promptTokens: number; completionTokens: number; }; } declare function generateWithAnthropic(model: string, messages: Array<{ role: string; content: string; }>, apiKey: string, options?: { temperature?: number; maxTokens?: number; }): Promise; declare function generateWithOpenAI(model: string, messages: Array<{ role: string; content: string; }>, apiKey: string, options?: { temperature?: number; maxTokens?: number; }): Promise; declare function generateWithGroq(model: string, messages: Array<{ role: string; content: string; }>, apiKey: string, options?: { temperature?: number; maxTokens?: number; }): Promise; declare function generateWithGemini(model: string, messages: Array<{ role: string; content: string; }>, apiKey: string, options?: { temperature?: number; maxTokens?: number; }): Promise; /** * Edge-Native Provider Factory * * Core factory function and utilities for routing to provider-specific * implementations. Pure fetch API - no external dependencies. */ /** * Parse a ModelSpec string into its components */ declare function parseModelSpec(spec: string): ParsedModelSpec; /** * Create a model spec string */ declare function createModelSpec(provider: ProviderType, model: string): ModelSpec; /** * Generate text using any supported provider (edge-native) */ declare function generate(spec: ModelSpec | string, messages: Array<{ role: string; content: string; }>, credentials: Credentials, options?: { temperature?: number; maxTokens?: number; }): Promise<{ text: string; usage?: { promptTokens: number; completionTokens: number; }; }>; /** * Check if credentials are available for a provider */ declare function hasCredentials(provider: ProviderType, credentials: Credentials): boolean; /** * Get credentials from environment variables */ declare function getCredentialsFromEnv(): Credentials; /** * Model Registry and Utilities * * Aggregates model data from provider-specific files and provides * lookup, filtering, and query functions. */ /** * All available models with metadata */ declare const MODELS: ModelInfo[]; /** * Model lookup by spec */ declare const MODEL_BY_SPEC: Record; /** * Get model info by spec */ declare function getModelInfo(spec: ModelSpec | string): ModelInfo | undefined; /** * Get models by provider */ declare function getModelsByProvider(provider: ProviderType): ModelInfo[]; /** * Get all model specs */ declare function getAllSpecs(): ModelSpec[]; /** * Get recommended models (fast + low/free cost) */ declare function getRecommendedModels(): ModelInfo[]; /** * Default model specs for each provider */ declare const DEFAULT_SPECS: Record; /** * Check if a spec is valid */ declare function isValidSpec(spec: string): spec is ModelSpec; /** * Get available providers based on credentials */ declare function getAvailableProviders(credentials: Credentials): ProviderType[]; /** * Get available models based on credentials */ declare function getAvailableModels(credentials: Credentials): ModelInfo[]; /** * Error Types for LLM Provider * * Unified error handling across all providers (Groq, Gemini, Cloudflare) */ /** * Error codes for categorization */ type LLMErrorCode = "RATE_LIMIT" | "AUTH" | "TIMEOUT" | "INVALID_RESPONSE" | "NETWORK" | "SERVER_ERROR" | "VALIDATION" | "UNKNOWN"; /** * Main error class for LLM provider errors */ declare class LLMProviderError extends Error { readonly code: LLMErrorCode; readonly provider: ProviderType | "unknown"; readonly retryable: boolean; readonly statusCode?: number; readonly cause?: Error; constructor(options: { message: string; code: LLMErrorCode; provider?: ProviderType; statusCode?: number; retryable?: boolean; cause?: Error; }); /** * Create a user-friendly error message */ toUserMessage(): string; } /** * Determine if an error code is retryable by default */ declare function isRetryableCode(code: LLMErrorCode): boolean; /** * Parse an HTTP status code to an error code */ declare function statusToErrorCode(status: number): LLMErrorCode; /** * Wrap any error into an LLMProviderError */ declare function wrapError(error: unknown, provider?: ProviderType, context?: string): LLMProviderError; /** * Check if an error is an LLMProviderError with a specific code */ declare function isLLMError(error: unknown, code?: LLMErrorCode): error is LLMProviderError; /** * Check if an error is retryable */ declare function isRetryable(error: unknown): boolean; /** * Retry Logic for LLM Provider * * Exponential backoff with jitter for handling transient errors */ /** * Configuration for retry behavior */ interface RetryConfig { /** Maximum number of retry attempts (default: 3) */ maxRetries?: number; /** Base delay in milliseconds (default: 100) */ baseDelay?: number; /** Maximum delay in milliseconds (default: 10000) */ maxDelay?: number; /** Error codes to retry on (default: all retryable codes) */ retryOn?: LLMErrorCode[]; /** Callback when a retry occurs */ onRetry?: (attempt: number, error: LLMProviderError, delay: number) => void; /** Custom delay calculator (overrides exponential backoff) */ delayFn?: (attempt: number, baseDelay: number) => number; } /** * Default retry configuration */ declare const DEFAULT_RETRY_CONFIG: Required>; /** * Default retryable error codes */ declare const DEFAULT_RETRYABLE_CODES: LLMErrorCode[]; /** * Calculate delay with exponential backoff and jitter * * @param attempt - Current attempt number (0-indexed) * @param baseDelay - Base delay in milliseconds * @param maxDelay - Maximum delay cap * @returns Delay in milliseconds */ declare function calculateDelay(attempt: number, baseDelay: number, maxDelay: number): number; /** * Sleep for a specified duration */ declare function sleep(ms: number): Promise; /** * Execute a function with retry logic * * @example * ```typescript * const result = await withRetry( * () => generateText({ model, prompt }), * { * maxRetries: 3, * baseDelay: 100, * retryOn: ['RATE_LIMIT', 'TIMEOUT'], * onRetry: (attempt, error) => console.log(`Retry ${attempt}...`), * } * ); * ``` */ declare function withRetry(fn: () => Promise, config?: RetryConfig): Promise; /** * Result of withRetryResult - includes metadata about retries */ interface RetryResult { /** The successful result */ result: T; /** Number of attempts made */ attempts: number; /** Total time spent including retries (ms) */ totalTime: number; /** Whether any retries occurred */ retried: boolean; } /** * Execute a function with retry logic, returning metadata about the retries * * @example * ```typescript * const { result, attempts, totalTime } = await withRetryResult( * () => generateText({ model, prompt }), * { maxRetries: 3 } * ); * console.log(`Success after ${attempts} attempts in ${totalTime}ms`); * ``` */ declare function withRetryResult(fn: () => Promise, config?: RetryConfig): Promise>; /** * Create a retry wrapper with pre-configured options * * @example * ```typescript * const retryWithBackoff = createRetryWrapper({ * maxRetries: 5, * baseDelay: 200, * onRetry: (attempt) => console.log(`Retry ${attempt}...`), * }); * * // Use later * const result = await retryWithBackoff(() => generateText({ model, prompt })); * ``` */ declare function createRetryWrapper(defaultConfig: RetryConfig): (fn: () => Promise, overrideConfig?: RetryConfig) => Promise; /** * Structured Output Functions (Edge-Native) * * Pure implementation without AI SDK dependencies * Uses JSON extraction from text responses with Zod validation */ interface GenerateObjectOptions { /** Model specification (e.g., "groq:llama-3.1-8b-instant") */ model: ModelSpec | string; /** API credentials */ credentials: Credentials; /** Zod schema for the expected output */ schema: T; /** User prompt */ prompt: string; /** Optional system prompt */ system?: string; /** Temperature (0-1) */ temperature?: number; /** Max tokens */ maxTokens?: number; } interface GenerateObjectResult { /** Parsed and validated object */ object: T; /** Raw text response */ rawText: string; /** Token usage */ usage?: { promptTokens: number; completionTokens: number; }; } /** * Generate a structured object using edge-native implementation * * @example * ```typescript * const result = await generateObject({ * model: "groq:llama-3.1-8b-instant", * credentials: { groqApiKey: process.env.GROQ_API_KEY }, * schema: z.object({ name: z.string(), age: z.number() }), * prompt: "Generate a person", * }); * ``` */ declare function generateObject(options: GenerateObjectOptions): Promise>>; /** * Extract JSON from text response (edge-native) * * @example * ```typescript * const response = "Here's the data: {\"name\": \"test\", \"value\": 42}"; * const schema = z.object({ name: z.string(), value: z.number() }); * const result = extractJSON(response, schema); * // => { name: "test", value: 42 } * ``` */ declare function extractJSON(text: string, schema?: T): T extends z.ZodType ? z.infer : unknown; /** * Edge-native streaming utilities using Web Streams API * * Provides WebStreams-compatible streaming for edge computing environments * like Cloudflare Workers, Vercel Edge Functions, etc. */ interface CloudflareStreamChunk { response: string; finished?: boolean; } declare function createCloudflareStream(model: string, messages: Array<{ role: string; content: string; }>, credentials: Credentials): ReadableStream; /** * Convert a CloudflareStreamChunk stream to text chunks * Useful for integrating with other streaming APIs * * @example * ```typescript * const cloudflareStream = createCloudflareStream(model, messages, credentials); * const textStream = cloudflareStreamToText(cloudflareStream); * * const reader = textStream.getReader(); * while (true) { * const { done, value } = await reader.read(); * if (done) break; * process.stdout.write(value); // string * } * ``` */ declare function cloudflareStreamToText(stream: ReadableStream): ReadableStream; /** * Convert a ReadableStream to Response object * Useful for returning streaming responses in edge functions * * @example * ```typescript * export async function POST(request: Request) { * const stream = createCloudflareStream(model, messages, credentials); * const textStream = cloudflareStreamToText(stream); * * return streamToResponse(textStream, { * headers: { "Content-Type": "text/plain; charset=utf-8" } * }); * } * ``` */ declare function streamToResponse(stream: ReadableStream, init?: ResponseInit): Response; /** * Convert ReadableStream to AsyncIterator for easier consumption * * @example * ```typescript * const stream = createCloudflareStream(model, messages, credentials); * * for await (const chunk of streamToAsyncIterator(stream)) { * console.log(chunk.response); * } * ``` */ declare function streamToAsyncIterator(stream: ReadableStream): AsyncIterableIterator; /** * Memory optimization utilities for edge computing environments * * Edge environments like Cloudflare Workers have strict memory limits. * These utilities help optimize memory usage when working with LLMs. */ interface OptimizedMessage { role: "system" | "user" | "assistant"; content: string; tokens?: number; } /** * Truncate message history to stay within token limits * Useful for edge environments with memory constraints * * @example * ```typescript * const messages = [ * { role: "system", content: "You are a helpful assistant." }, * { role: "user", content: "Hello" }, * { role: "assistant", content: "Hi there!" }, * // ... many more messages * ]; * * // Keep only recent messages within token limit * const optimized = truncateMessages(messages, 2000); * ``` */ declare function truncateMessages(messages: Array<{ role: string; content: string; }>, maxTokens: number, tokensPerChar?: number): OptimizedMessage[]; /** * Compress long messages by removing unnecessary whitespace and newlines */ declare function compressMessage(content: string): string; /** * Memory-efficient buffer for streaming responses * Automatically flushes when buffer gets too large */ declare class StreamingBuffer { private buffer; private maxSize; private onFlush?; constructor(maxSize?: number, onFlush?: (content: string) => void); append(chunk: string): void; flush(): string; getContent(): string; getTotalLength(): number; clear(): void; } /** * Simple LRU cache for edge environments * Useful for caching model responses or credentials */ declare class EdgeCache { private cache; private maxSize; private ttl; constructor(maxSize?: number, ttl?: number); get(key: string): T | undefined; set(key: string, value: T): void; has(key: string): boolean; delete(key: string): boolean; clear(): void; size(): number; cleanup(): number; } /** * Get rough memory usage estimate * Note: This is a rough approximation as JS doesn't expose precise memory info */ declare function getMemoryEstimate(): { heapUsed?: number; heapTotal?: number; external?: number; }; /** * Create a memory-aware credentials cache * Automatically cleans up when memory gets low */ declare function createCredentialsCache(maxSize?: number, ttl?: number): EdgeCache; /** * Anthropic-specific builder shortcuts with streaming support */ declare const anthropic: { /** Claude 4.5 Sonnet - Latest 2025, most capable */ sonnet: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; /** Claude 3.5 Haiku - Fast and cheap */ haiku: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; }; /** * OpenAI-specific builder shortcuts with streaming support */ declare const openai: { /** GPT-4o - Latest and fastest */ gpt4o: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; /** GPT-4o Mini - Cost-effective */ mini: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; /** GPT-4 Turbo - High capability */ turbo: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; /** GPT-3.5 Turbo - Fast and cheap */ gpt35: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; }; /** * Groq-specific builder shortcuts with streaming support */ declare const groq: { /** Fastest model - 560 tokens/sec */ instant: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; /** Balanced model - 280 tokens/sec */ versatile: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; /** OpenAI OSS models */ gpt120b: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; gpt20b: (apiKey: string) => UnillmBuilder & { stream: (prompt: string) => Promise>; }; /** Specialized models */ guard: (apiKey: string) => UnillmBuilder; compound: (apiKey: string) => UnillmBuilder; compoundMini: (apiKey: string) => UnillmBuilder; }; /** * Gemini-specific builder shortcuts */ declare const gemini: { /** Latest Gemini 3 series */ pro3: (apiKey: string) => UnillmBuilder; flash3: (apiKey: string) => UnillmBuilder; /** Gemini 2.5 series */ pro25: (apiKey: string) => UnillmBuilder; flash25: (apiKey: string) => UnillmBuilder; /** Gemini 2.0 series (recommended) */ flash: (apiKey: string) => UnillmBuilder; lite: (apiKey: string) => UnillmBuilder; /** Stable 1.5 series */ pro: (apiKey: string) => UnillmBuilder; flash15: (apiKey: string) => UnillmBuilder; }; /** * Cloudflare-specific builder shortcuts */ declare const cloudflare: { /** GPT-OSS 120B - Production use */ gpt120b: (creds: { apiKey: string; email: string; accountId: string; }) => UnillmBuilder; /** GPT-OSS 20B - Lower latency */ gpt20b: (creds: { apiKey: string; email: string; accountId: string; }) => UnillmBuilder; /** Llama 4 Scout - Multimodal */ llama4: (creds: { apiKey: string; email: string; accountId: string; }) => UnillmBuilder; /** Llama 3.3 70B - Fast quantized */ llama70b: (creds: { apiKey: string; email: string; accountId: string; }) => UnillmBuilder; /** Llama 3.1 8B - Lightweight */ llama8b: (creds: { apiKey: string; email: string; accountId: string; }) => UnillmBuilder; /** QwQ 32B - Reasoning specialist */ reasoning: (creds: { apiKey: string; email: string; accountId: string; }) => UnillmBuilder; /** Qwen 2.5 Coder - Code specialist */ coder: (creds: { apiKey: string; email: string; accountId: string; }) => UnillmBuilder; /** IBM Granite - Enterprise */ granite: (creds: { apiKey: string; email: string; accountId: string; }) => UnillmBuilder; }; /** * Fluent Builder API for unillm * * Modern, type-safe, chainable interface for LLM operations * Inspired by Prisma, Playwright, and modern TypeScript patterns */ interface FluentState { model?: ModelSpec | string; credentials?: Credentials; messages?: Array<{ role: string; content: string; }>; system?: string; temperature?: number; maxTokens?: number; retryConfig?: RetryConfig; schema?: z.ZodType; } declare class UnillmBuilder { private state; constructor(initialState?: Partial); model(spec: ModelSpec | string): UnillmBuilder; credentials(creds: Credentials): UnillmBuilder; /** Alias for credentials */ creds(creds: Credentials): UnillmBuilder; temperature(temp: number): UnillmBuilder; /** Alias for temperature */ temp(temp: number): UnillmBuilder; maxTokens(tokens: number): UnillmBuilder; /** Alias for maxTokens */ tokens(tokens: number): UnillmBuilder; system(prompt: string): UnillmBuilder; messages(msgs: Array<{ role: string; content: string; }>): UnillmBuilder; user(content: string): UnillmBuilder; assistant(content: string): UnillmBuilder; schema(schema: T): UnillmStructuredBuilder; retry(config: RetryConfig): UnillmBuilder; retries(count: number, baseDelay?: number): UnillmBuilder; optimize(maxTokens?: number): UnillmBuilder; compress(): UnillmBuilder; generate(prompt?: string): Promise; stream(prompt?: string): Promise>; private prepareMessages; private validateRequired; } declare class UnillmStructuredBuilder { private state; constructor(state: FluentState & { schema: T; }); generate(prompt: string): Promise<{ object: z.infer; rawText: string; usage?: Record; }>; extract(text: string): z.infer; } declare function unillm(initialState?: Partial): UnillmBuilder; declare function quick(model: ModelSpec | string, credentials: Credentials): UnillmBuilder; export { type AnyModel, type CheckOptions, type CheckResult, type CloudflareModel, type CloudflareRestResponse, type CloudflareStreamChunk, type Credentials, DEFAULT_RETRYABLE_CODES, DEFAULT_RETRY_CONFIG, DEFAULT_SPECS, EdgeCache, type GeminiModel, type GenerateObjectOptions, type GenerateObjectResult, type GenerateOptions, type GenerateResult, type GroqModel, type LLMErrorCode, LLMProviderError, MODELS, MODEL_BY_SPEC, type ModelInfo, type ModelSpec, type OptimizedMessage, type ParsedModelSpec, type ProviderType, type RetryConfig, type RetryResult, StreamingBuffer, UnillmBuilder, UnillmStructuredBuilder, anthropic, calculateDelay, callCloudflareRest, callCloudflareRestStream, cloudflare, cloudflareStreamToText, compressMessage, createCloudflareStream, createCredentialsCache, createModelSpec, createRetryWrapper, extractJSON, gemini, generate, generateObject, generateWithAnthropic, generateWithGemini, generateWithGroq, generateWithOpenAI, getAllSpecs, getAvailableModels, getAvailableProviders, getCredentialsFromEnv, getMemoryEstimate, getModelInfo, getModelsByProvider, getRecommendedModels, groq, hasCredentials, isLLMError, isRetryable, isRetryableCode, isValidSpec, openai, parseModelSpec, quick, sleep, statusToErrorCode, streamToAsyncIterator, streamToResponse, truncateMessages, unillm, withRetry, withRetryResult, wrapError };