import { type LLMCostsResult } from '../../LLMService.typedefs'; /** * Trace/observation metadata. Values are coerced to strings before they reach * the SDK, so callers may pass scalars. */ export type LLMTraceMetadata = Record; export interface LLMTraceContext { /** Overrides the trace name (defaults to the wrapping operation name). */ name?: string; userId?: string; sessionId?: string; tags?: string[]; metadata?: LLMTraceMetadata; } /** * Structural reference to the managed prompt a generation was produced from. * SDK-free by design: the gateway only carries `name`/`version`/`isFallback`, * and the tracer implementation turns it into a prompt link (a fallback * prompt intentionally produces no link). */ export interface LLMTracedPrompt { name: string; version: number; isFallback?: boolean; } /** * Escape-hatch update applied to the active trace of a single tracer. `name`, * `input` and `output` replace the previous values; `metadata` merges. Outside * an active scope the call is a safe no-op. * * `output` is the only way a trace gets one: the root never harvests the * wrapped operation's return value, so a feature that wants a meaningful trace * output states it here, in whatever trimmed shape is worth reading. */ export interface LLMActiveTraceUpdate { name?: string; input?: unknown; output?: unknown; metadata?: LLMTraceMetadata; } export declare enum LLMObservationLevel { Default = "DEFAULT", Debug = "DEBUG", Warning = "WARNING", Error = "ERROR" } export declare enum LLMToolObservationType { Tool = "tool", Retriever = "retriever" } export interface LLMAgentObservationOptions { onError?: (error: unknown) => unknown; } export interface LLMToolObservationOptions extends LLMAgentObservationOptions { type?: LLMToolObservationType; level?: LLMObservationLevel; } /** * Per-call generation capture passed from a provider service to the base * service's success/error metric points. The observation name defaults to the * service method when no prompt name is threaded through. */ export interface LLMGenerationTrace { name: string; input?: unknown; output?: unknown; modelParameters?: Record; metadata?: LLMTraceMetadata; /** * The managed prompt this generation used. Threaded through so the tracer can * link the observation to its prompt version. */ prompt?: LLMTracedPrompt; /** * The user this call was made for. A typed trace attribute, never a metadata * key: the tracer promotes it to the trace's own user field, which is what * Langfuse filters and groups on. */ userId?: string; /** * Groups every trace of one conversation, review, or agent run under a single * Langfuse session. Typed trace attribute, never a metadata key. */ sessionId?: string; /** Langfuse trace tags. Typed trace attribute, never a metadata key. */ tags?: string[]; /** Epoch milliseconds captured immediately before the provider call. */ startedAt: number; } /** * Full per-call generation record passed to `recordGeneration`. Extracted from * `LLMGenerationTrace` so the gateway and `@mate-academy/llm-tracer` share the * exact same recorded shape. */ export interface LLMGenerationTraceRecord extends LLMGenerationTrace { /** Epoch milliseconds stamped when the generation is handed to the tracer. */ endedAt: number; model: string | null; usageDetails?: Record; costDetails?: Record; isError?: boolean; } export interface LLMGenerationAccounting { tokens: { input: number; output: number; total: number; lastRequestInput?: number; }; costs: LLMCostsResult; usageDetails: Record; costDetails: Record; } /** * The tracing surface the gateway depends on. Any implementation (the no-op, * or a real tracer from `@mate-academy/llm-tracer`) satisfies it, so * consumers hold a single type regardless of whether tracing is configured. */ export interface LLMGatewayTracer { readonly isEnabled: boolean; withTrace(name: string, context: LLMTraceContext, fn: () => Promise): Promise; recordGeneration(generation: LLMGenerationTraceRecord): void; withToolObservation(name: string, input: unknown, fn: () => Promise, options?: LLMToolObservationOptions): Promise; withAgentObservation(name: string, input: unknown, fn: () => Promise, options?: LLMAgentObservationOptions): Promise; /** * Updates the active trace of this tracer only (name/input replace, metadata * merges). A no-op outside an active scope. Isolated per tracer so it can * never touch another project's trace. */ updateActiveTrace(update: LLMActiveTraceUpdate): void; /** * The context the active scope was opened with, or `undefined` outside a * scope. It is what lets a consumer resolve what the surrounding operation * declared (its user, session, tags) without the application threading that * context through every call. */ getActiveTraceContext(): LLMTraceContext | undefined; flush(): Promise; /** * Tears down the tracer's provider/exporter. Optional so a 7.8 minor does not * break external structural implementations that predate the method. */ shutdown?(): Promise; } export interface LLMFallbackMetricDimensions { feature?: string; promptName?: string; reason?: string; } /** * Emits a single fallback-served data point. Consumers inject a real CloudWatch * implementation when they build the gateway; the default is a no-op so the * gateway carries no AWS dependency and tracing stays fire-and-forget. */ export type LLMFallbackMetricEmitter = (dimensions: LLMFallbackMetricDimensions) => void;