UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

221 lines (220 loc) 8.62 kB
/** * 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;