{"version":3,"file":"instrumentation.js","sources":["../../../../../src/integrations/tracing/vercelai/instrumentation.ts"],"sourcesContent":["import type { InstrumentationConfig, InstrumentationModuleDefinition } from '@opentelemetry/instrumentation';\nimport { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';\nimport {\n _INTERNAL_cleanupToolCallSpanContext,\n _INTERNAL_getSpanContextForToolCallId,\n addNonEnumerableProperty,\n captureException,\n getActiveSpan,\n getClient,\n handleCallbackErrors,\n SDK_VERSION,\n withScope,\n} from '@sentry/core';\nimport { INTEGRATION_NAME } from './constants';\nimport type { TelemetrySettings, VercelAiIntegration } from './types';\n\nconst SUPPORTED_VERSIONS = ['>=3.0.0 <7'];\n\n// List of patched methods\n// From: https://sdk.vercel.ai/docs/ai-sdk-core/telemetry#collected-data\nconst INSTRUMENTED_METHODS = [\n 'generateText',\n 'streamText',\n 'generateObject',\n 'streamObject',\n 'embed',\n 'embedMany',\n 'rerank',\n] as const;\n\ninterface MethodFirstArg extends Record {\n experimental_telemetry?: TelemetrySettings;\n}\n\ntype MethodArgs = [MethodFirstArg, ...unknown[]];\n\ntype PatchedModuleExports = Record<(typeof INSTRUMENTED_METHODS)[number], (...args: MethodArgs) => unknown> &\n Record;\n\ninterface RecordingOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n}\n\ninterface ToolError {\n type: 'tool-error' | 'tool-result' | 'tool-call';\n toolCallId: string;\n toolName: string;\n input?: {\n [key: string]: unknown;\n };\n error: Error;\n dynamic?: boolean;\n}\n\nfunction isToolError(obj: unknown): obj is ToolError {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n\n const candidate = obj as Record;\n return (\n 'type' in candidate &&\n 'error' in candidate &&\n 'toolName' in candidate &&\n 'toolCallId' in candidate &&\n candidate.type === 'tool-error' &&\n candidate.error instanceof Error\n );\n}\n\n/**\n * Process tool call results: capture tool errors and clean up span context mappings.\n *\n * Error checking runs first (needs span context for linking), then cleanup removes all entries.\n * Tool errors are not rejected in Vercel AI V5 — they appear as metadata in the result content.\n */\nexport function processToolCallResults(result: unknown): void {\n if (typeof result !== 'object' || result === null || !('content' in result)) {\n return;\n }\n\n const resultObj = result as { content: Array };\n if (!Array.isArray(resultObj.content)) {\n return;\n }\n\n captureToolErrors(resultObj.content);\n cleanupToolCallSpanContexts(resultObj.content);\n}\n\nfunction captureToolErrors(content: Array): void {\n for (const item of content) {\n if (!isToolError(item)) {\n continue;\n }\n\n // Try to get the span context associated with this tool call ID\n const spanContext = _INTERNAL_getSpanContextForToolCallId(item.toolCallId);\n\n if (spanContext) {\n // We have the span context, so link the error using span and trace IDs\n withScope(scope => {\n scope.setContext('trace', {\n trace_id: spanContext.traceId,\n span_id: spanContext.spanId,\n });\n\n scope.setTag('vercel.ai.tool.name', item.toolName);\n scope.setTag('vercel.ai.tool.callId', item.toolCallId);\n scope.setLevel('error');\n\n captureException(item.error, {\n mechanism: {\n type: 'auto.vercelai.otel',\n handled: false,\n },\n });\n });\n } else {\n // Fallback: capture without span linking\n withScope(scope => {\n scope.setTag('vercel.ai.tool.name', item.toolName);\n scope.setTag('vercel.ai.tool.callId', item.toolCallId);\n scope.setLevel('error');\n\n captureException(item.error, {\n mechanism: {\n type: 'auto.vercelai.otel',\n handled: false,\n },\n });\n });\n }\n }\n}\n\n/**\n * Remove span context entries for all completed tool calls in the content array.\n */\nexport function cleanupToolCallSpanContexts(content: Array): void {\n for (const item of content) {\n if (\n typeof item === 'object' &&\n item !== null &&\n 'toolCallId' in item &&\n typeof (item as Record).toolCallId === 'string'\n ) {\n _INTERNAL_cleanupToolCallSpanContext((item as Record).toolCallId as string);\n }\n }\n}\n\n/**\n * Determines whether to record inputs and outputs for Vercel AI telemetry based on the configuration hierarchy.\n *\n * The order of precedence is:\n * 1. The vercel ai integration options\n * 2. The experimental_telemetry options in the vercel ai method calls\n * 3. When telemetry is explicitly enabled (isEnabled: true), default to recording\n * 4. Otherwise, use the dataCollection.genAI settings from client options\n */\nexport function determineRecordingSettings(\n integrationRecordingOptions: RecordingOptions | undefined,\n methodTelemetryOptions: RecordingOptions,\n telemetryExplicitlyEnabled: boolean | undefined,\n defaultInputsEnabled: boolean,\n defaultOutputsEnabled: boolean,\n): { recordInputs: boolean; recordOutputs: boolean } {\n const recordInputs =\n integrationRecordingOptions?.recordInputs !== undefined\n ? integrationRecordingOptions.recordInputs\n : methodTelemetryOptions.recordInputs !== undefined\n ? methodTelemetryOptions.recordInputs\n : telemetryExplicitlyEnabled === true\n ? true // When telemetry is explicitly enabled, default to recording inputs\n : defaultInputsEnabled;\n\n const recordOutputs =\n integrationRecordingOptions?.recordOutputs !== undefined\n ? integrationRecordingOptions.recordOutputs\n : methodTelemetryOptions.recordOutputs !== undefined\n ? methodTelemetryOptions.recordOutputs\n : telemetryExplicitlyEnabled === true\n ? true // When telemetry is explicitly enabled, default to recording outputs\n : defaultOutputsEnabled;\n\n return { recordInputs, recordOutputs };\n}\n\n/**\n * This detects is added by the Sentry Vercel AI Integration to detect if the integration should\n * be enabled.\n *\n * It also patches the `ai` module to enable Vercel AI telemetry automatically for all methods.\n */\nexport class SentryVercelAiInstrumentation extends InstrumentationBase {\n private _isPatched = false;\n private _callbacks: (() => void)[] = [];\n\n public constructor(config: InstrumentationConfig = {}) {\n super('@sentry/instrumentation-vercel-ai', SDK_VERSION, config);\n }\n\n /**\n * Initializes the instrumentation by defining the modules to be patched.\n */\n public init(): InstrumentationModuleDefinition {\n const module = new InstrumentationNodeModuleDefinition('ai', SUPPORTED_VERSIONS, this._patch.bind(this));\n return module;\n }\n\n /**\n * Call the provided callback when the module is patched.\n * If it has already been patched, the callback will be called immediately.\n */\n public callWhenPatched(callback: () => void): void {\n if (this._isPatched) {\n callback();\n } else {\n this._callbacks.push(callback);\n }\n }\n\n /**\n * Patches module exports to enable Vercel AI telemetry.\n */\n private _patch(moduleExports: PatchedModuleExports): unknown {\n this._isPatched = true;\n\n this._callbacks.forEach(callback => callback());\n this._callbacks = [];\n\n const generatePatch = unknown>(originalMethod: T): T => {\n return new Proxy(originalMethod, {\n apply: (target, thisArg, args: MethodArgs) => {\n const existingExperimentalTelemetry = args[0].experimental_telemetry || {};\n const isEnabled = existingExperimentalTelemetry.isEnabled;\n\n const client = getClient();\n const integration = client?.getIntegrationByName(INTEGRATION_NAME);\n const integrationOptions = integration?.options;\n const genAI = integration ? client?.getDataCollectionOptions().genAI : undefined;\n\n const { recordInputs, recordOutputs } = determineRecordingSettings(\n integrationOptions,\n existingExperimentalTelemetry,\n isEnabled,\n Boolean(genAI?.inputs),\n Boolean(genAI?.outputs),\n );\n\n args[0].experimental_telemetry = {\n ...existingExperimentalTelemetry,\n isEnabled: isEnabled !== undefined ? isEnabled : true,\n recordInputs,\n recordOutputs,\n };\n\n return handleCallbackErrors(\n () => Reflect.apply(target, thisArg, args),\n error => {\n // This error bubbles up to unhandledrejection handler (if not handled before),\n // where we do not know the active span anymore\n // So to circumvent this, we set the active span on the error object\n // which is picked up by the unhandledrejection handler\n if (error && typeof error === 'object') {\n addNonEnumerableProperty(error, '_sentry_active_span', getActiveSpan());\n }\n },\n () => {},\n result => {\n processToolCallResults(result);\n },\n );\n },\n });\n };\n\n // Is this an ESM module?\n // https://tc39.es/ecma262/#sec-module-namespace-objects\n if (Object.prototype.toString.call(moduleExports) === '[object Module]') {\n // In ESM we take the usual route and just replace the exports we want to instrument\n for (const method of INSTRUMENTED_METHODS) {\n // Skip methods that don't exist in this version of the AI SDK (e.g., rerank was added in v6)\n if (moduleExports[method] != null) {\n moduleExports[method] = generatePatch(moduleExports[method]);\n }\n }\n\n return moduleExports;\n } else {\n // In CJS we can't replace the exports in the original module because they\n // don't have setters, so we create a new object with the same properties\n const patchedModuleExports = INSTRUMENTED_METHODS.reduce((acc, curr) => {\n // Skip methods that don't exist in this version of the AI SDK (e.g., rerank was added in v6)\n if (moduleExports[curr] != null) {\n acc[curr] = generatePatch(moduleExports[curr]);\n }\n return acc;\n }, {} as PatchedModuleExports);\n\n return { ...moduleExports, ...patchedModuleExports };\n }\n }\n}\n"],"names":["_INTERNAL_getSpanContextForToolCallId","withScope","captureException","_INTERNAL_cleanupToolCallSpanContext","InstrumentationBase","SDK_VERSION","InstrumentationNodeModuleDefinition","getClient","INTEGRATION_NAME","handleCallbackErrors","addNonEnumerableProperty","getActiveSpan"],"mappings":"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"}