Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const core = require('@sentry/core'); const instrument = require('../../../otel/instrument.js'); const addOriginToSpan = require('../../../utils/addOriginToSpan.js'); const instrumentation = require('./instrumentation.js'); const INTEGRATION_NAME = 'VercelAI'; const instrumentVercelAi = instrument.generateInstrumentOnce(INTEGRATION_NAME, () => new instrumentation.SentryVercelAiInstrumentation({})); const _vercelAIIntegration = (() => { let instrumentation; return { name: INTEGRATION_NAME, setupOnce() { instrumentation = instrumentVercelAi(); }, setup(client) { instrumentation?.callWhenPatched(() => { client.on('spanStart', span => { const { data: attributes, description: name } = core.spanToJSON(span); if (!name) { return; } // The id of the model const aiModelId = attributes['ai.model.id']; // the provider of the model const aiModelProvider = attributes['ai.model.provider']; // both of these must be defined for the integration to work if (typeof aiModelId !== 'string' || typeof aiModelProvider !== 'string' || !aiModelId || !aiModelProvider) { return; } let isPipelineSpan = false; switch (name) { case 'ai.generateText': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.pipeline.generateText'); isPipelineSpan = true; break; } case 'ai.generateText.doGenerate': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run.doGenerate'); break; } case 'ai.streamText': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.pipeline.streamText'); isPipelineSpan = true; break; } case 'ai.streamText.doStream': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run.doStream'); break; } case 'ai.generateObject': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.pipeline.generateObject'); isPipelineSpan = true; break; } case 'ai.generateObject.doGenerate': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run.doGenerate'); break; } case 'ai.streamObject': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.pipeline.streamObject'); isPipelineSpan = true; break; } case 'ai.streamObject.doStream': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run.doStream'); break; } case 'ai.embed': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.pipeline.embed'); isPipelineSpan = true; break; } case 'ai.embed.doEmbed': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.embeddings'); break; } case 'ai.embedMany': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.pipeline.embedMany'); isPipelineSpan = true; break; } case 'ai.embedMany.doEmbed': { span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.embeddings'); break; } case 'ai.toolCall': case 'ai.stream.firstChunk': case 'ai.stream.finish': span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run'); break; } addOriginToSpan.addOriginToSpan(span, 'auto.vercelai.otel'); const nameWthoutAi = name.replace('ai.', ''); span.setAttribute('ai.pipeline.name', nameWthoutAi); span.updateName(nameWthoutAi); // If a Telemetry name is set and it is a pipeline span, use that as the operation name const functionId = attributes['ai.telemetry.functionId']; if (functionId && typeof functionId === 'string' && isPipelineSpan) { span.updateName(functionId); span.setAttribute('ai.pipeline.name', functionId); } if (attributes['ai.prompt']) { span.setAttribute('ai.input_messages', attributes['ai.prompt']); } if (attributes['ai.model.id']) { span.setAttribute('ai.model_id', attributes['ai.model.id']); } span.setAttribute('ai.streaming', name.includes('stream')); }); client.addEventProcessor(event => { if (event.type === 'transaction' && event.spans?.length) { for (const span of event.spans) { const { data: attributes, description: name } = span; if (!name || span.origin !== 'auto.vercelai.otel') { continue; } if (attributes['ai.usage.completionTokens'] != undefined) { attributes['ai.completion_tokens.used'] = attributes['ai.usage.completionTokens']; } if (attributes['ai.usage.promptTokens'] != undefined) { attributes['ai.prompt_tokens.used'] = attributes['ai.usage.promptTokens']; } if ( typeof attributes['ai.usage.completionTokens'] == 'number' && typeof attributes['ai.usage.promptTokens'] == 'number' ) { attributes['ai.total_tokens.used'] = attributes['ai.usage.completionTokens'] + attributes['ai.usage.promptTokens']; } } } return event; }); }); }, }; }) ; /** * Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library. * * For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry). * * @example * ```javascript * const Sentry = require('@sentry/node'); * * Sentry.init({ * integrations: [Sentry.vercelAIIntegration()], * }); * ``` * * By default this integration adds tracing support to all `ai` function calls. If you need to disable * collecting spans for a specific call, you can do so by setting `experimental_telemetry.isEnabled` to * `false` in the first argument of the function call. * * ```javascript * const result = await generateText({ * model: openai('gpt-4-turbo'), * experimental_telemetry: { isEnabled: false }, * }); * ``` * * If you want to collect inputs and outputs for a specific call, you must specifically opt-in to each * function call by setting `experimental_telemetry.recordInputs` and `experimental_telemetry.recordOutputs` * to `true`. * * ```javascript * const result = await generateText({ * model: openai('gpt-4-turbo'), * experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true }, * }); */ const vercelAIIntegration = core.defineIntegration(_vercelAIIntegration); exports.instrumentVercelAi = instrumentVercelAi; exports.vercelAIIntegration = vercelAIIntegration; //# sourceMappingURL=index.js.map