/**
 * OpenTelemetry Instrumentation for Langfuse v4
 *
 * Configures OpenTelemetry TracerProvider with LangfuseSpanProcessor to capture
 * traces from Vercel AI SDK's experimental_telemetry feature.
 *
 * Flow: Vercel AI SDK → OpenTelemetry Spans → LangfuseSpanProcessor → Langfuse Platform
 */
import { trace } from "@opentelemetry/api";
import { LoggerProvider } from "@opentelemetry/sdk-logs";
import { type SpanProcessor } from "@opentelemetry/sdk-trace-base";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import type { LangfuseConfig, LangfuseContext } from "../../../../types/index.js";
/**
 * True when a span is an internal NeuroLink wrapper that should NOT be sent to
 * Langfuse. Internal wrappers carry the `langfuse.internal: true` attribute.
 *
 * Exposed so host apps that bring their own `LangfuseSpanProcessor` (e.g.
 * `skipLangfuseSpanProcessor: true`, or manual registration on an existing
 * TracerProvider) can apply the same filter and avoid duplicate observations.
 */
export declare function isLangfuseInternalSpan(span: {
    attributes?: Record<string, unknown>;
}): boolean;
/**
 * Drop-in `shouldExportSpan` predicate for a `LangfuseSpanProcessor` that
 * filters out NeuroLink internal wrapper spans.
 *
 * Usage in host apps:
 * ```ts
 * import { langfuseShouldExportSpan } from "@juspay/neurolink";
 * new LangfuseSpanProcessor({ ..., shouldExportSpan: langfuseShouldExportSpan });
 * ```
 */
export declare function langfuseShouldExportSpan({ otelSpan, }: {
    otelSpan: {
        attributes?: Record<string, unknown>;
    };
}): boolean;
/**
 * Initialize OpenTelemetry with Langfuse span processor
 *
 * This connects Vercel AI SDK's experimental_telemetry to Langfuse by:
 * 1. Creating LangfuseSpanProcessor with Langfuse credentials
 * 2. Creating a NodeTracerProvider with service metadata and span processor
 * 3. Registering the provider globally for AI SDK to use
 *
 * NEW: If useExternalTracerProvider is true or autoDetectExternalProvider detects
 * an existing provider, steps 2 and 3 are skipped. The span processors are still
 * created and can be retrieved via getSpanProcessors().
 *
 * @param config - Langfuse configuration passed from parent application
 */
export declare function initializeOpenTelemetry(config: LangfuseConfig): Promise<void>;
/**
 * Flush all pending spans to Langfuse
 */
export declare function flushOpenTelemetry(): Promise<void>;
/**
 * Shutdown OpenTelemetry and Langfuse span processor
 */
export declare function shutdownOpenTelemetry(): Promise<void>;
/**
 * Get the Langfuse span processor
 */
export declare function getLangfuseSpanProcessor(): SpanProcessor | null;
/**
 * Get the tracer provider
 */
export declare function getTracerProvider(): NodeTracerProvider | null;
/**
 * Get the logger provider for emitting OTLP log records.
 * Returns null if OTLP is not configured or LoggerProvider was not created.
 */
export declare function getLoggerProvider(): LoggerProvider | null;
/**
 * Check if OpenTelemetry is initialized
 */
export declare function isOpenTelemetryInitialized(): boolean;
/**
 * Get health status for Langfuse observability
 *
 * @returns Health status object with initialization and configuration details
 */
export declare function getLangfuseHealthStatus(): {
    isHealthy: boolean;
    initialized: boolean;
    credentialsValid: boolean;
    enabled: boolean;
    hasProcessor: boolean;
    usingExternalProvider: boolean;
    config?: {
        baseUrl: string;
        environment: string;
        release: string;
    };
};
/**
 * Set user and session context for Langfuse spans in the current async context
 *
 * Merges the provided context with existing AsyncLocalStorage context. If a callback is provided,
 * the context is scoped to that callback execution and returns the callback's result.
 * Without a callback, the context applies to the current execution context and its children.
 *
 * Uses AsyncLocalStorage to properly scope context per request, avoiding race conditions
 * in concurrent scenarios.
 *
 * @param context - Object containing context fields to merge with existing context
 * @param callback - Optional callback to run within the context scope. If omitted, context applies to current execution
 * @returns The callback's return value if provided, otherwise void
 *
 * @example
 * // With callback - returns the result
 * const result = await setLangfuseContext({ userId: "user123" }, async () => {
 *   return await generateText({ model: "gpt-4", prompt: "Hello" });
 * });
 *
 * @example
 * // Without callback - sets context for current execution
 * await setLangfuseContext({ sessionId: "session456", traceName: "chat-completion" });
 */
export declare function setLangfuseContext<T = void>(context: {
    userId?: string | null;
    sessionId?: string | null;
    conversationId?: string | null;
    requestId?: string | null;
    traceName?: string | null;
    metadata?: Record<string, unknown> | null;
    /** Explicit operation name (overrides auto-detection) */
    operationName?: string | null;
    /** Override global autoDetectOperationName for this context */
    autoDetectOperationName?: boolean;
    /** Custom attributes to set on all spans within this context */
    customAttributes?: Record<string, string | number | boolean>;
}, callback?: () => T | Promise<T>): Promise<T | void>;
/**
 * Get the current Langfuse context from AsyncLocalStorage
 *
 * Returns the current context including userId, sessionId, conversationId,
 * requestId, traceName, and metadata. Returns undefined if no context is set.
 *
 * @returns The current LangfuseContext or undefined
 *
 * @example
 * const context = getLangfuseContext();
 * console.log(context?.userId, context?.sessionId);
 */
export declare function getLangfuseContext(): LangfuseContext | undefined;
/**
 * Capture the current Langfuse AsyncLocalStorage context and return a wrapper
 * that re-enters that context when executing the provided callback.
 *
 * This is essential for preserving trace context across async boundaries that
 * break the automatic ALS propagation chain, such as `setImmediate()`,
 * `setTimeout()`, or event-emitter callbacks. Without this, spans created
 * inside those callbacks become orphaned traces in Langfuse.
 *
 * **How it works:**
 * 1. Captures the current ALS store at call time (synchronously).
 * 2. Returns an async function that, when invoked, re-enters the captured
 *    context via `contextStorage.run()` before executing the callback.
 * 3. If no context exists at capture time, the callback runs without
 *    ALS wrapping (no-op passthrough).
 *
 * @param fn - The async function to execute within the captured context
 * @returns A new async function that preserves the Langfuse ALS context
 *
 * @example
 * // Before (broken — setImmediate loses ALS context):
 * setImmediate(async () => {
 *   await this.checkAndSummarize(session, threshold);
 * });
 *
 * // After (fixed — context is captured and re-entered):
 * const wrappedFn = runWithCurrentLangfuseContext(async () => {
 *   await this.checkAndSummarize(session, threshold);
 * });
 * setImmediate(wrappedFn);
 */
export declare function runWithCurrentLangfuseContext<T>(fn: () => Promise<T>): () => Promise<T>;
/**
 * Get an OpenTelemetry Tracer for creating custom spans
 *
 * This allows applications to create their own spans that will be
 * processed by the same span processors (ContextEnricher + LangfuseSpanProcessor).
 *
 * @param name - Tracer name, defaults to "neurolink"
 * @param version - Tracer version, optional
 * @returns OpenTelemetry Tracer instance
 *
 * @example
 * const tracer = getTracer("my-app");
 * const span = tracer.startSpan("custom-operation");
 * try {
 *   // ... do work
 * } finally {
 *   span.end();
 * }
 */
export declare function getTracer(name?: string, version?: string): ReturnType<typeof trace.getTracer>;
/**
 * Create a new ContextEnricher span processor
 * Use this when useExternalTracerProvider is true to add to your own TracerProvider
 *
 * @returns A new ContextEnricher instance
 */
export declare function createContextEnricher(): SpanProcessor;
/**
 * Get all span processors that NeuroLink would use
 * Convenience function that returns [ContextEnricher, LangfuseSpanProcessor]
 *
 * @returns Array of span processors, or empty array if not initialized
 */
export declare function getSpanProcessors(): SpanProcessor[];
/**
 * Check if using external TracerProvider mode
 *
 * @returns true if operating in external TracerProvider mode
 */
export declare function isUsingExternalTracerProvider(): boolean;
