{"version":3,"file":"instrumentation.js","sources":["../../../../../src/integrations/tracing/langchain/instrumentation.ts"],"sourcesContent":["import {\n InstrumentationBase,\n type InstrumentationConfig,\n type InstrumentationModuleDefinition,\n InstrumentationNodeModuleDefinition,\n} from '@opentelemetry/instrumentation';\nimport { InstrumentationNodeModuleFile } from '../InstrumentationNodeModuleFile';\nimport type { LangChainOptions } from '@sentry/core';\nimport {\n _INTERNAL_mergeLangChainCallbackHandler,\n _INTERNAL_skipAiProviderWrapping,\n ANTHROPIC_AI_INTEGRATION_NAME,\n createLangChainCallbackHandler,\n GOOGLE_GENAI_INTEGRATION_NAME,\n instrumentLangChainEmbeddings,\n OPENAI_INTEGRATION_NAME,\n SDK_VERSION,\n} from '@sentry/core';\n\nconst supportedVersions = ['>=0.1.0 <2.0.0'];\n\ntype LangChainInstrumentationOptions = InstrumentationConfig & LangChainOptions;\n\n/**\n * Represents the patched shape of LangChain provider package exports\n */\ninterface PatchedLangChainExports {\n [key: string]: unknown;\n}\n\n/**\n * Wraps Runnable methods (invoke, stream, batch) to inject Sentry callbacks at request time\n * Uses a Proxy to intercept method calls and augment the options.callbacks\n */\nfunction wrapRunnableMethod(\n originalMethod: (...args: unknown[]) => unknown,\n sentryHandler: unknown,\n _methodName: string,\n): (...args: unknown[]) => unknown {\n return new Proxy(originalMethod, {\n apply(target, thisArg, args: unknown[]): unknown {\n // LangChain Runnable method signatures:\n // invoke(input, options?) - options contains callbacks\n // stream(input, options?) - options contains callbacks\n // batch(inputs, options?) - options contains callbacks\n\n // Options is typically the second argument\n const optionsIndex = 1;\n let options = args[optionsIndex] as Record | undefined;\n\n // If options don't exist or aren't an object, create them\n if (!options || typeof options !== 'object' || Array.isArray(options)) {\n options = {};\n args[optionsIndex] = options;\n }\n\n // Inject our callback handler into options.callbacks (request time callbacks)\n options.callbacks = _INTERNAL_mergeLangChainCallbackHandler(options.callbacks, sentryHandler);\n\n // Call original method with augmented options\n return Reflect.apply(target, thisArg, args);\n },\n }) as (...args: unknown[]) => unknown;\n}\n\n/**\n * Sentry LangChain instrumentation using OpenTelemetry.\n */\nexport class SentryLangChainInstrumentation extends InstrumentationBase {\n public constructor(config: LangChainInstrumentationOptions = {}) {\n super('@sentry/instrumentation-langchain', SDK_VERSION, config);\n }\n\n /**\n * Initializes the instrumentation by defining the modules to be patched.\n * We patch the BaseChatModel class methods to inject callbacks\n *\n * We hook into provider packages (@langchain/anthropic, @langchain/openai, etc.)\n * because @langchain/core is often bundled and not loaded as a separate module\n */\n public init(): InstrumentationModuleDefinition | InstrumentationModuleDefinition[] {\n const modules: InstrumentationModuleDefinition[] = [];\n\n // Hook into common LangChain provider packages\n const providerPackages = [\n '@langchain/anthropic',\n '@langchain/openai',\n '@langchain/google-genai',\n '@langchain/mistralai',\n '@langchain/google-vertexai',\n '@langchain/groq',\n ];\n\n for (const packageName of providerPackages) {\n // In CJS, LangChain packages re-export from dist/index.cjs files.\n // Patching only the root module sometimes misses the real implementation or\n // gets overwritten when that file is loaded. We add a file-level patch so that\n // _patch runs again on the concrete implementation\n modules.push(\n new InstrumentationNodeModuleDefinition(\n packageName,\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n [\n new InstrumentationNodeModuleFile(\n `${packageName}/dist/index.cjs`,\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n ),\n ],\n ),\n );\n }\n\n // Hook into main 'langchain' package to catch initChatModel (v1+)\n modules.push(\n new InstrumentationNodeModuleDefinition(\n 'langchain',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n [\n // To catch the CJS build that contains ConfigurableModel / initChatModel for v1\n new InstrumentationNodeModuleFile(\n 'langchain/dist/chat_models/universal.cjs',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n ),\n ],\n ),\n );\n\n return modules;\n }\n\n /**\n * Core patch logic - patches chat model and embedding methods\n * This is called when a LangChain provider package is loaded\n */\n private _patch(exports: PatchedLangChainExports): PatchedLangChainExports | void {\n // Skip AI provider wrapping now that LangChain is actually being used\n // This prevents duplicate spans from Anthropic/OpenAI/GoogleGenAI standalone integrations\n _INTERNAL_skipAiProviderWrapping([\n OPENAI_INTEGRATION_NAME,\n ANTHROPIC_AI_INTEGRATION_NAME,\n GOOGLE_GENAI_INTEGRATION_NAME,\n ]);\n\n const config = this.getConfig();\n\n // Create a shared handler instance for chat model callbacks\n const sentryHandler = createLangChainCallbackHandler(config);\n\n // Patch Runnable methods to inject callbacks at request time\n // This directly manipulates options.callbacks that LangChain uses\n this._patchRunnableMethods(exports, sentryHandler);\n\n // Patch embedding methods to create spans directly\n // Embeddings don't use the callback system, so we wrap the methods themselves\n this._patchEmbeddingsMethods(exports, config);\n\n return exports;\n }\n\n /**\n * Patches chat model methods (invoke, stream, batch) to inject Sentry callbacks\n * Finds a chat model class from the provider package exports and patches its prototype methods\n */\n private _patchRunnableMethods(exports: PatchedLangChainExports, sentryHandler: unknown): void {\n // Known chat model class names for each provider\n const knownChatModelNames = [\n 'ChatAnthropic',\n 'ChatOpenAI',\n 'ChatGoogleGenerativeAI',\n 'ChatMistralAI',\n 'ChatVertexAI',\n 'ChatGroq',\n 'ConfigurableModel',\n ];\n\n const exportsToPatch = (exports.universal_exports ?? exports) as Record;\n\n const chatModelClass = Object.values(exportsToPatch).find(exp => {\n return typeof exp === 'function' && knownChatModelNames.includes(exp.name);\n }) as { prototype: unknown; name: string } | undefined;\n\n if (!chatModelClass) {\n return;\n }\n\n // Patch directly on chatModelClass.prototype\n const targetProto = chatModelClass.prototype as Record;\n\n // Skip if already patched (both file-level and module-level hooks resolve to the same prototype)\n if (targetProto.__sentry_patched__) {\n return;\n }\n targetProto.__sentry_patched__ = true;\n\n // Patch the methods (invoke, stream, batch)\n // All chat model instances will inherit these patched methods\n const methodsToPatch = ['invoke', 'stream', 'batch'] as const;\n\n for (const methodName of methodsToPatch) {\n const method = targetProto[methodName];\n if (typeof method === 'function') {\n targetProto[methodName] = wrapRunnableMethod(\n method as (...args: unknown[]) => unknown,\n sentryHandler,\n methodName,\n );\n }\n }\n }\n\n /**\n * Patches embedding class methods (embedQuery, embedDocuments) to create Sentry spans.\n *\n * Unlike chat models which use LangChain's callback system, the Embeddings base class\n * has no callback support. We wrap the methods directly on the prototype.\n *\n * Instruments any exported class whose prototype has both embedQuery and embedDocuments as functions.\n */\n private _patchEmbeddingsMethods(exports: PatchedLangChainExports, options: LangChainOptions): void {\n const exportsToPatch = (exports.universal_exports ?? exports) as Record;\n\n for (const exp of Object.values(exportsToPatch)) {\n if (typeof exp !== 'function' || !exp.prototype) {\n continue;\n }\n const proto = exp.prototype as Record;\n if (typeof proto.embedQuery !== 'function' || typeof proto.embedDocuments !== 'function') {\n continue;\n }\n if (proto.__sentry_patched__) {\n continue;\n }\n proto.__sentry_patched__ = true;\n\n instrumentLangChainEmbeddings(proto, options);\n }\n }\n}\n"],"names":["_INTERNAL_mergeLangChainCallbackHandler","InstrumentationBase","SDK_VERSION","InstrumentationNodeModuleDefinition","InstrumentationNodeModuleFile","_INTERNAL_skipAiProviderWrapping","OPENAI_INTEGRATION_NAME","ANTHROPIC_AI_INTEGRATION_NAME","GOOGLE_GENAI_INTEGRATION_NAME","createLangChainCallbackHandler","instrumentLangChainEmbeddings"],"mappings":"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"}