/** * Tier 2 LLMObs Summarizer * * Extracts operational metrics from LLMObs spans for Tier 2 export. * CRITICAL: This emits metrics WITHOUT any sensitive content. * * Tier 2 metrics include: * - LLM latency by provider/model * - Token usage (input, output, cached, reasoning) * - Success/failure rates by error category * - Cost aggregates * * EXPLICITLY EXCLUDED: * - Prompts, code, tool IO * - File paths, stack traces * - User identifiers */ import type { ReadableSpan } from "@opentelemetry/sdk-trace-base"; /** * Error categories aligned with tier2-metrics.v0.1.0.json contract. */ export type LLMErrorCategory = "none" | "rate_limit" | "context_length" | "content_filter" | "quota" | "network" | "timeout" | "auth_error" | "api_error" | "validation_error" | "aborted" | "unknown"; /** * Finish reason aligned with tier2-metrics.v0.2.0.json contract. */ export type LLMFinishReason = "stop" | "length" | "content_filter" | "tool_calls" | "error"; /** * Operation name aligned with OTEL gen_ai.operation.name semantic convention. * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-metrics/ */ export type GenAIOperationName = "chat" | "text_completion" | "embeddings" | "execute_tool" | "invoke_agent" | "generate_content"; /** * Tool error categories aligned with tier2-metrics.v0.2.0.json contract. */ export type ToolErrorCategory = "none" | "timeout" | "execution_error" | "validation_error" | "permission_denied" | "not_found" | "unknown"; /** * Provider names aligned with tier2-metrics.v0.1.0.json contract. */ export type LLMProvider = "openai" | "anthropic" | "azure" | "bedrock" | "google" | "cohere" | "mistral"; /** * Metric labels for LLM requests. * These are the ONLY labels allowed per tier2-metrics.v0.1.0.json. */ export interface LLMRequestMetricLabels { provider: LLMProvider; model: string; status: "success" | "error"; error_category?: LLMErrorCategory; finish_reason?: LLMFinishReason; } /** * Token metric labels. */ export interface TokenMetricLabels { provider: LLMProvider; model: string; token_type: "input" | "output" | "reasoning" | "cached"; } /** * Tool call metric labels. */ export interface ToolCallMetricLabels { tool_name: string; status: "success" | "error"; } /** * Summary of an LLM span extracted for Tier 2 metrics. * Contains NO sensitive data. */ export interface LLMSpanSummary { provider: LLMProvider; /** OTEL canonical provider name (e.g., aws.bedrock, azure.ai.openai) */ providerOtel: string; model: string; /** Response model if different from request model */ responseModel?: string; status: "success" | "error"; durationMs: number; inputTokens: number; outputTokens: number; totalTokens: number; reasoningTokens: number; cachedTokens: number; errorCategory: LLMErrorCategory; finishReason?: LLMFinishReason; estimatedCost: number; /** OTEL operation name (chat, text_completion, etc.) */ operationName: GenAIOperationName; /** Time to first token in milliseconds (streaming only) */ timeToFirstTokenMs?: number; } /** * Tool span summary for metrics. */ export interface ToolSpanSummary { toolName: string; status: "success" | "error"; durationMs: number; /** Error category for tool failures (added in v0.2.0) */ errorCategory: ToolErrorCategory; } /** * Metrics client interface for emitting Tier 2 metrics. * Matches OTEL Metrics API patterns. */ export interface Tier2MetricsClient { recordHistogram(name: string, value: number, labels: Record): void; incrementCounter(name: string, value: number, labels: Record): void; } /** * LLMObs Tier 2 Summarizer. * * Processes Tier 1 LLMObs spans and emits Tier 2 metrics. * CRITICAL: Ensures NO prompts, code, tool IO appear in metrics. * * @example * ```typescript * const summarizer = new LLMObsTier2Summarizer(metricsClient); * * // Process each LLMObs span * for (const span of llmobsSpans) { * summarizer.summarize(span); * } * ``` */ export declare class LLMObsTier2Summarizer { private readonly metricsClient; private readonly pricing; /** * Create a Tier 2 summarizer. * * @param metricsClient - Client for emitting metrics * @param customPricing - Optional custom pricing per model */ constructor(metricsClient: Tier2MetricsClient, customPricing?: Map); /** * Process a Tier 1 LLMObs span and emit Tier 2 metrics. * * @param span - The span to summarize */ summarize(span: ReadableSpan): void; /** * Extract a summary from an LLM span (for testing/debugging). * Contains NO sensitive data. * * @param span - The span to extract from * @returns Summary with safe metrics only */ extractLLMSummary(span: ReadableSpan): LLMSpanSummary; /** * Extract a summary from a tool span. * * @param span - The span to extract from * @returns Tool summary with safe metrics only */ extractToolSummary(span: ReadableSpan): ToolSpanSummary; /** * Emit LLM span metrics. * Emits BOTH legacy (llm_*) and OTEL-aligned (gen_ai.*) metrics for migration. */ private summarizeLLMSpan; /** * Emit tool span metrics. * Uses OTEL-aligned naming with gen_ai.operation.name = "execute_tool". */ private summarizeToolSpan; /** * Check if span is an LLM span by name pattern. */ private isLLMSpan; /** * Check if span is a tool span by name pattern. */ private isToolSpan; /** * Extract span status. */ private extractStatus; /** * Categorize error from span attributes. * CRITICAL: Does NOT expose error messages or stack traces. */ private categorizeError; /** * Extract finish reason. * Handles gen_ai.response.finish_reasons as array per OTEL semantic conventions. */ private extractFinishReason; /** * Normalize provider name to allowed values. * Defensive: handles non-string inputs gracefully. */ private normalizeProvider; /** * Normalize provider to OTEL canonical names. * Maps legacy names to OTEL gen_ai.provider.name values. * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-metrics/ */ private normalizeProviderOtel; /** * Extract operation name from span attributes. * Maps span kind and attributes to OTEL gen_ai.operation.name values. */ private extractOperationName; /** * Extract time to first token from span attributes. * Checks multiple attribute names for compatibility. * Returns value in MILLISECONDS for consistent internal handling. * * IMPORTANT: Different attributes use different units: * - gen_ai.client.time_to_first_token: SECONDS (OTEL spec) * - llm.time_to_first_token_ms: MILLISECONDS * - llmobs.metrics.time_to_first_token_ms: MILLISECONDS * - timeToFirstTokenMs: MILLISECONDS */ private extractTimeToFirstToken; /** * Categorize tool errors. * CRITICAL: Does NOT expose error messages or stack traces. */ private categorizeToolError; /** * Validate operation name is in the allowed enum. */ private isValidOperationName; /** * Validate tool error category is in the allowed enum. */ private isValidToolErrorCategory; /** * Normalize model name with strict sanitization. * SECURITY: Only allows alphanumeric, dots, hyphens to prevent data injection. * Attacker-controlled model names could otherwise leak sensitive data to Tier 2. */ private normalizeModel; /** * Normalize tool name with strict sanitization. * SECURITY: Only allows alphanumeric, underscores, hyphens to prevent data injection. * Attacker-controlled tool names could otherwise leak sensitive data to Tier 2. */ private normalizeToolName; /** * Get span duration in milliseconds, clamped to non-negative. * Handles clock skew or corrupted data gracefully. */ private getDurationMs; /** * Validate error category is in the allowed enum. */ private isValidErrorCategory; /** * Validate finish reason is in the allowed enum. */ private isValidFinishReason; /** * Estimate cost based on model and token counts. * Uses rough estimates - actual costs should be calculated server-side. */ private estimateCost; /** * Get default pricing per 1000 tokens (in USD). */ private getDefaultPricing; } //# sourceMappingURL=tier2-summarizer.d.ts.map