import { type LLMCallTraceContext, type LLMInstanceOptions, type LLMInstances, type LLMProviders, type LLMRejectedToolCall, type LLMPurposes, type LLMProviderModelsByPurpose, type LLMToolDefinition, type LLMToolResult, type LLMSerializedToolDefinition } from '../LLMService.typedefs'; import { type LLMLoggerInterface } from '../utilities/logger'; import { type LLMReporterInterface, type LLMMetricsWriter } from '../utilities/reporter'; import { type LLMModel } from '../LLMService.typedefs'; import { type LLMGatewayTracer, type LLMGenerationTrace, type LLMModelUsage, type LLMTraceMetadata } from '../utilities'; import { LLMAgentRounds } from './agentRounds'; export declare abstract class LLMBaseService | undefined> { readonly provider: Provider; readonly serviceName: string; readonly purpose: Purpose; logger: LLMLoggerInterface | undefined; reporter: Reporter; options?: LLMInstanceOptions[Provider] | undefined; private static readonly sharedInstanceCache; private tracer; constructor(provider: Provider, serviceName: string, purpose: Purpose, logger: LLMLoggerInterface | undefined, reporter: Reporter, options?: LLMInstanceOptions[Provider] | undefined); /** * Wires the tracer the service reports generations and tool calls to. Called * by `LLMGateway` right after construction; services built through * `LLMServiceFactory` keep the no-op tracer. */ initTracer(tracer: LLMGatewayTracer): void; protected getTracer(): LLMGatewayTracer; protected notifyToolCallRejected(listener: ((call: LLMRejectedToolCall) => void) | undefined, call: LLMRejectedToolCall): void; protected executeTracedTool(params: { tool: LLMToolDefinition; input: Record; }): Promise; protected recordWarningToolResult(params: { name: string; input: unknown; output: Result; }): Promise; protected serializeToolDefinitions(tools: LLMToolDefinition[]): LLMSerializedToolDefinition[]; /** * The LLM instance for the current provider. */ abstract get instance(): LLMInstances[Provider]; /** * Available models for the current provider and purpose. */ get models(): LLMProviderModelsByPurpose[Purpose]; /** * Initialize the logger by creating a child logger with the provider and service name. */ protected initLogger(): void; /** * Inject method names into class methods for better logging and reporting. */ private injectMethodNames; /** * Get the method name from a function. * If the method name is not available, return 'unknown'. */ protected getMethodName(func: Function & { methodName?: string; }): string; /** * Generate a cache key from credentials/options. * Includes provider to ensure cache isolation between different providers. * Note: Different purposes (Completion, Assistance, etc.) for the same provider * share the same underlying client instance. */ protected getCredentialsCacheKey(options: LLMInstanceOptions[Provider] | undefined): string; /** * Get or create cached instance for current credentials. * This method implements LRU caching to bound memory usage across all service types. * @throws {Error} If options are not provided (required for instance creation) */ protected getOrCreateInstance(factory: () => LLMInstances[Provider]): LLMInstances[Provider]; /** * Evict least recently used instance from the shared cache. */ private evictLeastRecentlyUsed; /** * Set new options for the LLM service instance. * The instance will be lazily recreated with new credentials on next access. */ setOptions(options: LLMInstanceOptions[Provider]): void; /** * Get the current options for the LLM service instance. */ getOptions(): LLMInstanceOptions[Provider] | undefined; /** * Clear all cached instances from the shared cache. * Useful for testing and manual resource cleanup. */ clearInstanceCache(): void; protected getDefaultTraceName(method: string): string; /** * Builds the per-call generation trace from the standard method options. * Returns `undefined` when tracing is disabled, so providers skip the work. */ protected buildGenerationTrace(params: { method: string; traceContext?: LLMCallTraceContext; input: unknown; output?: unknown; modelParameters?: Record; metadata?: LLMTraceMetadata; startedAt: number; }): LLMGenerationTrace | undefined; /** * Opens the per-round generation stream of an agent tool loop. Every model * round the loop runs is traced through the returned recorder, so the run * renders as one role-labelled transcript per round instead of a single * generation covering the whole loop. The run's aggregate metrics point is * written separately by `writeSuccessMetrics` and is unaffected. */ protected openAgentRounds(params: { method: string; model: LLMModel | null; traceContext?: LLMCallTraceContext; modelParameters?: Record; onRoundStarted?: () => void; }): LLMAgentRounds; /** * The generation a failed agent run falls back to when it never reached its * first model round: a run that throws while assembling the request would * otherwise trace nothing at all. Once a round has been recorded the * transcript is already there, and no second observation is emitted for it. */ protected buildUnstartedRunTrace(params: { rounds: LLMAgentRounds; method: string; traceContext?: LLMCallTraceContext; input: unknown; modelParameters?: Record; startedAt: number; }): LLMGenerationTrace | undefined; /** * Write success metrics for a specific method, and emit the matching * generation observation when per-call trace context is provided. */ protected writeSuccessMetrics>(params: { method: string; model: TModel | null; usage: LLMModelUsage; lastRequestUsage?: LLMModelUsage; writeMetrics: LLMMetricsWriter | undefined; generationTrace?: LLMGenerationTrace; }): Promise; /** * Token totals and costs of one accounted call, in the shape both the metrics * writer and a generation observation take. */ private buildGenerationAccounting; private static sumInputTokens; /** * Write error metrics for a specific method, and emit the matching generation * observation (level ERROR) when per-call trace context is given. */ protected writeErrorMetrics>(params: { method: string; model: TModel | null; isAborted?: boolean; writeMetrics: LLMMetricsWriter | undefined; generationTrace?: LLMGenerationTrace; error?: unknown; }): Promise; /** * Log a request failure at a severity matching whether it was an * intentional cancellation (isAborted) or a genuine provider/network error. * An aborted request is expected behaviour, not an operational failure, so * it is logged as a warning rather than an error. */ protected logRequestFailure(params: { method: string; message: string; error: unknown; isAborted?: boolean; meta?: Record; }): void; private recordGenerationTrace; private describeError; }