🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@sentry/server-utils

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sentry/server-utils - npm Package Compare versions

Comparing version
10.61.0
to
10.62.0
+21
build/cjs/vercel-ai/index.js
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const core = require('@sentry/core');
const vercelAiDcSubscriber = require('./vercel-ai-dc-subscriber.js');
const dc = require('node:diagnostics_channel');
const _vercelAiIntegration = ((options = {}) => {
return {
name: "VercelAI",
setupOnce() {
if (!dc.tracingChannel) {
return;
}
void Promise.resolve().then(() => vercelAiDcSubscriber.subscribeVercelAiTracingChannel(dc.tracingChannel, options));
}
};
});
const vercelAiIntegration = core.defineIntegration(_vercelAiIntegration);
exports.vercelAiIntegration = vercelAiIntegration;
//# sourceMappingURL=index.js.map
{"version":3,"file":"index.js","sources":["../../../src/vercel-ai/index.ts"],"sourcesContent":["import { defineIntegration, type IntegrationFn } from '@sentry/core';\nimport { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber';\nimport * as dc from 'node:diagnostics_channel';\n\ntype VercelAiOptions = {\n /**\n * Enable or disable input recording. Enabled if `dataCollection.genAI.inputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordInputs?: boolean;\n\n /**\n * Enable or disable output recording. Enabled if `dataCollection.genAI.outputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordOutputs?: boolean;\n\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n};\n\nconst _vercelAiIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: 'VercelAI' as const,\n setupOnce() {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n // Subscribe to the `ai` SDK's native telemetry tracing channel (ai >= 7).\n // This is a no-op on versions that don't publish to the channel, so it is always safe to call.\n // The factory needs the Sentry OTel context manager, which `initOpenTelemetry()` registers after `setupOnce`, so defer a tick.\n // Options are passed in here rather than read back off the integration per event.\n void Promise.resolve().then(() => subscribeVercelAiTracingChannel(dc.tracingChannel, options));\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7).\n */\nexport const vercelAiIntegration = defineIntegration(_vercelAiIntegration);\n"],"names":["subscribeVercelAiTracingChannel","defineIntegration"],"mappings":";;;;;;AA0BA,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAAC,GAAG,cAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAMA,MAAA,KAAK,OAAA,CAAQ,SAAQ,CAAE,IAAA,CAAK,MAAMA,oDAAA,CAAgC,EAAA,CAAG,cAAA,EAAgB,OAAO,CAAC,CAAA;AAAA,IAC/F;AAAA,GACF;AACF,CAAA,CAAA;AAKO,MAAM,mBAAA,GAAsBC,uBAAkB,oBAAoB;;;;"}
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const attributes = require('@sentry/conventions/attributes');
const op = require('@sentry/conventions/op');
const core = require('@sentry/core');
const tracingChannel = require('../tracing-channel.js');
const AI_SDK_TELEMETRY_TRACING_CHANNEL = "ai:telemetry";
const ORIGIN = "auto.vercelai.channel";
const GEN_AI_TOOL_CALL_ID_ATTRIBUTE = "gen_ai.tool.call.id";
const GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = "gen_ai.tool.description";
const GEN_AI_EMBEDDINGS_OPERATION = "embeddings";
const GEN_AI_RERANK_OPERATION = "rerank";
const GEN_AI_GENERATE_CONTENT_OPERATION = "generate_content";
const VERCEL_AI_OPERATION_ID_ATTRIBUTE = "vercel.ai.operationId";
const VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE = "vercel.ai.model.provider";
const VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE = "vercel.ai.settings.maxRetries";
const operationIdByCallId = /* @__PURE__ */ new Map();
const toolDescriptionsByCallId = /* @__PURE__ */ new Map();
const ROOT_OPERATION_TYPES = /* @__PURE__ */ new Set(["generateText", "streamText", "embed", "rerank"]);
function clearOperationId(data) {
if (!ROOT_OPERATION_TYPES.has(data.type)) {
return;
}
const callId = asString(data.event.callId);
if (callId) {
operationIdByCallId.delete(callId);
toolDescriptionsByCallId.delete(callId);
}
}
function recordToolDescriptions(callId, tools) {
if (!callId || !Array.isArray(tools)) {
return;
}
let descriptions = toolDescriptionsByCallId.get(callId);
for (const tool of tools) {
if (isRecord(tool) && typeof tool.name === "string" && typeof tool.description === "string") {
descriptions = descriptions ?? /* @__PURE__ */ new Map();
if (!descriptions.has(tool.name)) {
descriptions.set(tool.name, tool.description);
}
}
}
if (descriptions) {
toolDescriptionsByCallId.set(callId, descriptions);
}
}
function resolveToolDescription(callId, toolName, tools) {
const fromMap = callId ? toolDescriptionsByCallId.get(callId)?.get(toolName) : void 0;
if (fromMap) {
return fromMap;
}
if (Array.isArray(tools)) {
const match = tools.find((tool) => isRecord(tool) && tool.name === toolName);
return isRecord(match) ? asString(match.description) : void 0;
}
if (isRecord(tools)) {
const tool = tools[toolName];
return isRecord(tool) ? asString(tool.description) : void 0;
}
return void 0;
}
let subscribed = false;
function subscribeVercelAiTracingChannel(tracingChannel$1, options = {}) {
if (subscribed) {
return;
}
subscribed = true;
tracingChannel.bindTracingChannelToSpan(
tracingChannel$1(AI_SDK_TELEMETRY_TRACING_CHANNEL),
(data) => createSpanFromMessage(data, options),
{
// The helper ends the span; we enrich it from the settled result first (tokens, output messages,
// finish reasons, response model/id, provider metadata) and drop the per-operation `callId` maps.
beforeSpanEnd: (span, data) => {
enrichSpanOnEnd(span, data, options);
clearOperationId(data);
}
}
);
}
function createSpanFromMessage(data, channelOptions) {
const { type, event } = data;
if (type === "step" || !event || typeof event !== "object") {
return void 0;
}
const { recordInputs, enableTruncation } = getRecordingOptions(event, channelOptions);
const provider = asString(event.provider);
const modelId = asString(event.modelId);
const callId = asString(event.callId);
const maxRetries = asNumber(event.maxRetries);
if (recordInputs) {
recordToolDescriptions(callId, event.tools);
}
const baseAttributes = {
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
...provider ? { [attributes.GEN_AI_SYSTEM]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {},
...modelId ? { [attributes.GEN_AI_REQUEST_MODEL]: modelId } : {},
...maxRetries !== void 0 ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}
};
switch (type) {
case "generateText":
case "streamText":
return buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, type === "streamText");
case "languageModelCall":
return buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId);
case "executeTool":
return buildToolSpan(event, recordInputs);
case "embed":
return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, {
...baseAttributes,
...recordInputs && event.value !== void 0 ? { [attributes.GEN_AI_EMBEDDINGS_INPUT]: safeStringify(event.value) } : {}
});
case "rerank":
return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes);
default:
return void 0;
}
}
function startGenAiSpan(operation, suffix, attributes$1) {
return core.startInactiveSpan({
name: suffix ? `${operation} ${suffix}` : operation,
op: `gen_ai.${operation}`,
attributes: { [attributes.GEN_AI_OPERATION_NAME]: operation, ...attributes$1 }
});
}
function buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, isStream) {
const functionId = asString(event.functionId);
const operationId = asString(event.operationId) ?? (isStream ? "ai.streamText" : "ai.generateText");
if (callId) {
operationIdByCallId.set(callId, { operationId, isStream });
}
return startGenAiSpan(op.GEN_AI_INVOKE_AGENT_SPAN_OP, functionId, {
...baseAttributes,
[VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,
[attributes.GEN_AI_RESPONSE_STREAMING]: isStream,
...functionId ? { [attributes.GEN_AI_FUNCTION_ID]: functionId } : {},
...recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}
});
}
function buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId) {
const parent = callId ? operationIdByCallId.get(callId) : void 0;
const operationId = parent ? `${parent.operationId}.${parent.isStream ? "doStream" : "doGenerate"}` : "ai.generateText.doGenerate";
return startGenAiSpan(GEN_AI_GENERATE_CONTENT_OPERATION, modelId, {
...baseAttributes,
[VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,
...recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {},
...recordInputs && Array.isArray(event.tools) ? { [attributes.GEN_AI_REQUEST_AVAILABLE_TOOLS]: safeStringify(event.tools) } : {}
});
}
function buildToolSpan(event, recordInputs) {
const toolCall = isRecord(event.toolCall) ? event.toolCall : {};
const toolName = asString(toolCall.toolName);
const toolCallId = asString(event.toolCallId) ?? asString(toolCall.toolCallId);
const toolInput = toolCall.input ?? toolCall.args;
const description = recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : void 0;
return startGenAiSpan(op.GEN_AI_EXECUTE_TOOL_SPAN_OP, toolName, {
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
[attributes.GEN_AI_TOOL_TYPE]: "function",
...toolName ? { [attributes.GEN_AI_TOOL_NAME]: toolName } : {},
...toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {},
...description ? { [GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE]: description } : {},
...recordInputs && toolInput !== void 0 ? { [attributes.GEN_AI_TOOL_INPUT]: safeStringify(toolInput) } : {}
});
}
function enrichSpanOnEnd(span, data, channelOptions) {
const { type, result } = data;
if (!isRecord(result)) {
return;
}
const { recordOutputs } = getRecordingOptions(data.event, channelOptions);
if (type === "executeTool") {
if (recordOutputs) {
span.setAttribute(attributes.GEN_AI_TOOL_OUTPUT, safeStringify(result.output ?? result));
}
const output = isRecord(result.output) ? result.output : void 0;
if (output?.type === "tool-error") {
captureToolError(span, data, output.error);
}
return;
}
const usage = isRecord(result.usage) ? result.usage : void 0;
if (usage) {
const inputTokens = tokenCount(usage.inputTokens) ?? tokenCount(usage.tokens);
const outputTokens = tokenCount(usage.outputTokens);
const totalTokens = tokenCount(usage.totalTokens) ?? sum(inputTokens, outputTokens);
if (inputTokens !== void 0) {
span.setAttribute(attributes.GEN_AI_USAGE_INPUT_TOKENS, inputTokens);
}
if (outputTokens !== void 0) {
span.setAttribute(attributes.GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);
}
if (totalTokens !== void 0) {
span.setAttribute(attributes.GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);
}
}
const finishReason = getFinishReason(result);
if (finishReason && type === "languageModelCall") {
span.setAttribute(attributes.GEN_AI_RESPONSE_FINISH_REASONS, safeStringify([finishReason]));
}
const response = isRecord(result.response) ? result.response : void 0;
const responseId = asString(response?.id) ?? asString(result.responseId);
if (responseId) {
span.setAttribute(attributes.GEN_AI_RESPONSE_ID, responseId);
}
const responseModel = asString(response?.modelId) ?? asString(data.event.modelId);
if (responseModel) {
span.setAttribute(attributes.GEN_AI_RESPONSE_MODEL, responseModel);
}
const providerMetadata = result.providerMetadata;
const providerAttributes = core.getProviderMetadataAttributes(providerMetadata);
if (core.GEN_AI_CONVERSATION_ID_ATTRIBUTE in providerAttributes && core.spanToJSON(span).data[core.GEN_AI_CONVERSATION_ID_ATTRIBUTE]) {
delete providerAttributes[core.GEN_AI_CONVERSATION_ID_ATTRIBUTE];
}
span.setAttributes(providerAttributes);
if (recordOutputs) {
const parts = type === "languageModelCall" && Array.isArray(result.content) ? partsFromContent(result.content) : partsFromTextAndToolCalls(result.text, result.toolCalls);
const outputMessages = buildOutputMessages(parts, finishReason);
if (outputMessages) {
span.setAttribute(attributes.GEN_AI_OUTPUT_MESSAGES, outputMessages);
}
}
}
function normalizeFinishReason(finishReason) {
return finishReason === "tool-calls" ? "tool_call" : finishReason ?? "stop";
}
function getFinishReason(result) {
const finishReason = result.finishReason;
if (typeof finishReason === "string") {
return finishReason;
}
return isRecord(finishReason) ? asString(finishReason.unified) : void 0;
}
function tokenCount(value) {
return asNumber(value) ?? (isRecord(value) ? asNumber(value.total) : void 0);
}
function buildOutputMessages(parts, finishReason) {
if (!parts.length) {
return void 0;
}
return safeStringify([{ role: "assistant", parts, finish_reason: normalizeFinishReason(finishReason) }]);
}
function toolCallPart(toolCall) {
const args = toolCall.input ?? toolCall.args;
return {
type: "tool_call",
id: asString(toolCall.toolCallId),
name: asString(toolCall.toolName),
arguments: typeof args === "string" ? args : safeStringify(args ?? {})
};
}
function partsFromContent(content) {
const parts = [];
for (const item of content) {
if (!isRecord(item)) {
continue;
}
if (item.type === "text" && typeof item.text === "string") {
parts.push({ type: "text", content: item.text });
} else if (item.type === "tool-call") {
parts.push(toolCallPart(item));
}
}
return parts;
}
function partsFromTextAndToolCalls(text, toolCalls) {
const parts = [];
if (typeof text === "string" && text.length) {
parts.push({ type: "text", content: text });
}
if (Array.isArray(toolCalls)) {
for (const toolCall of toolCalls) {
if (isRecord(toolCall)) {
parts.push(toolCallPart(toolCall));
}
}
}
return parts;
}
function captureToolError(span, data, error) {
span.setStatus({
code: core.SPAN_STATUS_ERROR,
message: error instanceof Error ? error.message : "tool_error"
});
const toolCall = isRecord(data.event.toolCall) ? data.event.toolCall : {};
const toolName = asString(toolCall.toolName);
const toolCallId = asString(data.event.toolCallId) ?? asString(toolCall.toolCallId);
core.withScope((scope) => {
scope.setContext("trace", core.spanToTraceContext(span));
if (toolName) {
scope.setTag("vercel.ai.tool.name", toolName);
}
if (toolCallId) {
scope.setTag("vercel.ai.tool.callId", toolCallId);
}
scope.setLevel("error");
core.captureException(
error instanceof Error ? error : new Error(typeof error === "string" ? error : "Tool execution failed"),
{
mechanism: { type: "auto.vercelai.channel", handled: false }
}
);
});
}
function getRecordingOptions(event, channelOptions) {
const genAI = core.getClient()?.getDataCollectionOptions().genAI;
return {
recordInputs: resolveRecording(channelOptions.recordInputs, event.recordInputs, genAI?.inputs),
recordOutputs: resolveRecording(channelOptions.recordOutputs, event.recordOutputs, genAI?.outputs),
enableTruncation: core.shouldEnableTruncation(channelOptions.enableTruncation)
};
}
function resolveRecording(integrationOption, perCallOption, globalDefault) {
if (typeof integrationOption === "boolean") {
return integrationOption;
}
if (typeof perCallOption === "boolean") {
return perCallOption;
}
return globalDefault === true;
}
function buildInputMessageAttributes(event, enableTruncation) {
const attributes$1 = {};
const instructions = asString(event.instructions);
if (instructions) {
attributes$1[core.GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE] = safeStringify([{ type: "text", content: instructions }]);
}
const messages = event.messages ?? event.prompt;
if (messages !== void 0) {
attributes$1[attributes.GEN_AI_INPUT_MESSAGES] = enableTruncation ? core.getTruncatedJsonString(messages) : safeStringify(messages);
attributes$1[core.GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE] = Array.isArray(messages) ? messages.length : 1;
}
return attributes$1;
}
function asString(value) {
return typeof value === "string" ? value : void 0;
}
function asNumber(value) {
return typeof value === "number" && !isNaN(value) ? value : void 0;
}
function sum(a, b) {
return a === void 0 && b === void 0 ? void 0 : (a ?? 0) + (b ?? 0);
}
function isRecord(value) {
return typeof value === "object" && value !== null;
}
function safeStringify(value) {
if (typeof value === "string") {
return value;
}
try {
return JSON.stringify(value);
} catch {
return "[unserializable]";
}
}
exports.clearOperationId = clearOperationId;
exports.createSpanFromMessage = createSpanFromMessage;
exports.enrichSpanOnEnd = enrichSpanOnEnd;
exports.subscribeVercelAiTracingChannel = subscribeVercelAiTracingChannel;
//# sourceMappingURL=vercel-ai-dc-subscriber.js.map
{"version":3,"file":"vercel-ai-dc-subscriber.js","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"sourcesContent":["/* eslint-disable max-lines */\n// `@sentry/conventions` marks several gen_ai attributes (e.g. `GEN_AI_SYSTEM`, `GEN_AI_TOOL_*`,\n// `GEN_AI_REQUEST_AVAILABLE_TOOLS`) as deprecated in favour of newer semconv names. We intentionally\n// keep emitting the current names so these spans match the OTel-based (v6) integration and what the\n// Sentry product consumes today; migrating to the new names is a separate, coordinated change.\n/* eslint-disable typescript-eslint/no-deprecated */\nimport {\n GEN_AI_EMBEDDINGS_INPUT,\n GEN_AI_FUNCTION_ID,\n GEN_AI_INPUT_MESSAGES,\n GEN_AI_OPERATION_NAME,\n GEN_AI_OUTPUT_MESSAGES,\n GEN_AI_REQUEST_AVAILABLE_TOOLS,\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_FINISH_REASONS,\n GEN_AI_RESPONSE_ID,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_RESPONSE_STREAMING,\n GEN_AI_SYSTEM,\n GEN_AI_TOOL_INPUT,\n GEN_AI_TOOL_NAME,\n GEN_AI_TOOL_OUTPUT,\n GEN_AI_TOOL_TYPE,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n GEN_AI_USAGE_TOTAL_TOKENS,\n} from '@sentry/conventions/attributes';\nimport { GEN_AI_EXECUTE_TOOL_SPAN_OP, GEN_AI_INVOKE_AGENT_SPAN_OP } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n getClient,\n getProviderMetadataAttributes,\n getTruncatedJsonString,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n SPAN_STATUS_ERROR,\n spanToJSON,\n spanToTraceContext,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport type { TracingChannel } from 'node:diagnostics_channel';\nimport { bindTracingChannelToSpan } from '../tracing-channel';\n\n/**\n * The single tracing channel the `ai` package (>= 7) publishes all telemetry lifecycle events to\n * via `node:diagnostics_channel`. Events are discriminated by their `type` field.\n * @see https://github.com/vercel/ai/pull/15660\n */\nconst AI_SDK_TELEMETRY_TRACING_CHANNEL = 'ai:telemetry';\n\nconst ORIGIN = 'auto.vercelai.channel';\n\n// `@sentry/conventions` does not expose these yet, so we keep the literals here.\nconst GEN_AI_TOOL_CALL_ID_ATTRIBUTE = 'gen_ai.tool.call.id';\nconst GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = 'gen_ai.tool.description';\nconst GEN_AI_EMBEDDINGS_OPERATION = 'embeddings';\nconst GEN_AI_RERANK_OPERATION = 'rerank';\n// The model-call op matches the Vercel AI OTel integration (`gen_ai.generate_content`) rather than\n// the generic `gen_ai.chat`, so v6 (OTel) and v7 (channel) produce the same spans.\nconst GEN_AI_GENERATE_CONTENT_OPERATION = 'generate_content';\n\n// Subset of the `vercel.ai.*` passthrough attributes the OTel integration emits that we reproduce.\nconst VERCEL_AI_OPERATION_ID_ATTRIBUTE = 'vercel.ai.operationId';\nconst VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE = 'vercel.ai.model.provider';\nconst VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE = 'vercel.ai.settings.maxRetries';\n\n// Tracks the top-level operationId (and whether it streams) per `callId` so a model-call span can\n// name its `doGenerate`/`doStream` operation the same way the OTel integration does. `isStream` is\n// the authoritative event-type signal rather than a substring check on the (possibly custom)\n// operationId. Cleared when the top-level span ends.\nconst operationIdByCallId = new Map<string, { operationId: string; isStream: boolean }>();\n\n// Per-operation map of tool name → description, harvested from a model-call /\n// top-level event's `tools` (keyed by the shared `callId`). The AI SDK's\n// `executeTool` event doesn't carry the tool's description, so we backfill it\n// onto the tool span here — without relying on the OTel `vercelAiEventProcessor`\n// (which isn't registered in channel/orchestrion mode). Cleared with the\n// operation. Only populated when inputs are recorded, matching the OTel path\n// (which sources descriptions from the recorded `available_tools`).\nconst toolDescriptionsByCallId = new Map<string, Map<string, string>>();\n\n// Only top-level operations own the `callId` → operationId mapping; `step`/`languageModelCall`/\n// `executeTool` share the parent's `callId`, so they must not clear it.\nconst ROOT_OPERATION_TYPES = new Set<ChannelEventType>(['generateText', 'streamText', 'embed', 'rerank']);\n\n/** Drop the per-operation `callId` maps once the owning top-level operation settles (success or error). */\nexport function clearOperationId(data: VercelAiChannelMessage): void {\n if (!ROOT_OPERATION_TYPES.has(data.type)) {\n return;\n }\n const callId = asString(data.event.callId);\n if (callId) {\n operationIdByCallId.delete(callId);\n toolDescriptionsByCallId.delete(callId);\n }\n}\n\n/** Record tool name → description from an event's `tools`, so tool spans can backfill the description. */\nfunction recordToolDescriptions(callId: string | undefined, tools: unknown): void {\n if (!callId || !Array.isArray(tools)) {\n return;\n }\n let descriptions = toolDescriptionsByCallId.get(callId);\n for (const tool of tools) {\n if (isRecord(tool) && typeof tool.name === 'string' && typeof tool.description === 'string') {\n descriptions = descriptions ?? new Map();\n if (!descriptions.has(tool.name)) {\n descriptions.set(tool.name, tool.description);\n }\n }\n }\n if (descriptions) {\n toolDescriptionsByCallId.set(callId, descriptions);\n }\n}\n\n/**\n * Resolve a tool's description, preferring the per-operation map (populated from the model-call /\n * top-level event's `tools`, v7) and falling back to a `tools` collection on the event itself —\n * which may be an array of `{ name, description }` or a record keyed by tool name (v6).\n */\nfunction resolveToolDescription(callId: string | undefined, toolName: string, tools: unknown): string | undefined {\n const fromMap = callId ? toolDescriptionsByCallId.get(callId)?.get(toolName) : undefined;\n if (fromMap) {\n return fromMap;\n }\n if (Array.isArray(tools)) {\n const match = tools.find(tool => isRecord(tool) && tool.name === toolName);\n return isRecord(match) ? asString(match.description) : undefined;\n }\n if (isRecord(tools)) {\n const tool = tools[toolName];\n return isRecord(tool) ? asString(tool.description) : undefined;\n }\n return undefined;\n}\n\n/** The lifecycle event types the `ai:telemetry` channel can carry. */\nexport type ChannelEventType =\n | 'generateText'\n | 'streamText'\n | 'step'\n | 'languageModelCall'\n | 'executeTool'\n | 'embed'\n | 'rerank';\n\n/**\n * The context object the AI SDK passes through one tracing-channel call. It is the same object\n * identity across `start`/`end`/`asyncEnd`/`error`, and Node's `tracingChannel` attaches\n * `result`/`error` to it as the traced promise settles.\n */\nexport interface VercelAiChannelMessage {\n type: ChannelEventType;\n event: Record<string, unknown>;\n result?: unknown;\n error?: unknown;\n}\n\n/**\n * Platform-provided factory that returns a tracing channel for the given channel name. The factory\n * is responsible for, when `start` fires, calling `transformStart(data)` and storing the returned\n * span on `data._sentrySpan` so the subscriber's `asyncEnd`/`error` handlers can read it.\n *\n * Node passes `@sentry/opentelemetry/tracing-channel`, which uses `bindStore` to additionally make\n * the span the active OTel context for the duration of the traced operation. That is what makes\n * nested AI SDK operations (model calls, tool calls) become children of the enclosing span without\n * any manual parent bookkeeping here.\n */\ntype VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;\n\n/** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */\ninterface VercelAiChannelOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n enableTruncation?: boolean;\n}\n\nlet subscribed = false;\n\n/**\n * Subscribe Sentry span handlers to the `ai` SDK's native telemetry tracing channel (`ai:telemetry`,\n * available in `ai` >= 7) and emit fully-formed `gen_ai.*` spans directly — no OpenTelemetry span\n * post-processing involved.\n *\n * The integration passes its options in directly (rather than us looking the integration up on every\n * event); the global `dataCollection.genAI` default is still read from the client per event.\n *\n * Safe to always call: on `ai` versions that don't publish to the channel (e.g. < 7) nothing is\n * ever emitted and this is inert, so there is no double-instrumentation against the OTel-based\n * patcher. Idempotent.\n */\nexport function subscribeVercelAiTracingChannel(\n tracingChannel: VercelAiTracingChannelFactory,\n options: VercelAiChannelOptions = {},\n): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n bindTracingChannelToSpan(\n tracingChannel<VercelAiChannelMessage>(AI_SDK_TELEMETRY_TRACING_CHANNEL),\n data => createSpanFromMessage(data, options),\n {\n // The helper ends the span; we enrich it from the settled result first (tokens, output messages,\n // finish reasons, response model/id, provider metadata) and drop the per-operation `callId` maps.\n beforeSpanEnd: (span, data) => {\n enrichSpanOnEnd(span, data, options);\n clearOperationId(data);\n },\n },\n );\n}\n\n/**\n * Transform a channel `start` payload into the span that should be active for the operation. For\n * `step` we deliberately don't open a span (model calls and tool calls are siblings under the\n * invoke_agent span, matching the OTel-based output), so we reuse the active span and mark the\n * payload to skip ending it.\n */\nexport function createSpanFromMessage(\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): Span | undefined {\n const { type, event } = data;\n\n if (type === 'step' || !event || typeof event !== 'object') {\n // Opt out: returning `undefined` leaves the enclosing `invoke_agent` span as the active context\n // (model-call and tool-call events nest under it) without opening — or ending — a span of its own.\n return undefined;\n }\n\n const { recordInputs, enableTruncation } = getRecordingOptions(event, channelOptions);\n const provider = asString(event.provider);\n const modelId = asString(event.modelId);\n const callId = asString(event.callId);\n const maxRetries = asNumber(event.maxRetries);\n\n // Harvest tool descriptions from the operation/model-call `tools` so tool spans can backfill them.\n // Gated on `recordInputs` to match the OTel path, which only records `available_tools` then.\n if (recordInputs) {\n recordToolDescriptions(callId, event.tools);\n }\n\n const baseAttributes: Record<string, string | number | boolean> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n ...(provider ? { [GEN_AI_SYSTEM]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {}),\n ...(modelId ? { [GEN_AI_REQUEST_MODEL]: modelId } : {}),\n ...(maxRetries !== undefined ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}),\n };\n\n switch (type) {\n case 'generateText':\n case 'streamText':\n return buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, type === 'streamText');\n case 'languageModelCall':\n return buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId);\n case 'executeTool':\n return buildToolSpan(event, recordInputs);\n case 'embed':\n return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, {\n ...baseAttributes,\n ...(recordInputs && event.value !== undefined ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(event.value) } : {}),\n });\n case 'rerank':\n return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes);\n default:\n // Unknown event type: opt out rather than open a span we can't shape correctly.\n return undefined;\n }\n}\n\ntype Attributes = Record<string, string | number | boolean>;\n\n/** Start a `gen_ai.<operation>` span named `<operation> <suffix>` (or just `<operation>` when no suffix). */\nfunction startGenAiSpan(operation: string, suffix: string | undefined, attributes: Attributes): Span {\n return startInactiveSpan({\n name: suffix ? `${operation} ${suffix}` : operation,\n op: `gen_ai.${operation}`,\n attributes: { [GEN_AI_OPERATION_NAME]: operation, ...attributes },\n });\n}\n\nfunction buildInvokeAgentSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n isStream: boolean,\n): Span {\n const functionId = asString(event.functionId);\n const operationId = asString(event.operationId) ?? (isStream ? 'ai.streamText' : 'ai.generateText');\n if (callId) {\n operationIdByCallId.set(callId, { operationId, isStream });\n }\n return startGenAiSpan(GEN_AI_INVOKE_AGENT_SPAN_OP, functionId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n [GEN_AI_RESPONSE_STREAMING]: isStream,\n ...(functionId ? { [GEN_AI_FUNCTION_ID]: functionId } : {}),\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n });\n}\n\nfunction buildModelCallSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n modelId: string | undefined,\n): Span {\n const parent = callId ? operationIdByCallId.get(callId) : undefined;\n const operationId = parent\n ? `${parent.operationId}.${parent.isStream ? 'doStream' : 'doGenerate'}`\n : 'ai.generateText.doGenerate';\n return startGenAiSpan(GEN_AI_GENERATE_CONTENT_OPERATION, modelId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n ...(recordInputs && Array.isArray(event.tools)\n ? { [GEN_AI_REQUEST_AVAILABLE_TOOLS]: safeStringify(event.tools) }\n : {}),\n });\n}\n\nfunction buildToolSpan(event: Record<string, unknown>, recordInputs: boolean): Span {\n const toolCall = isRecord(event.toolCall) ? event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(event.toolCallId) ?? asString(toolCall.toolCallId);\n const toolInput = toolCall.input ?? toolCall.args;\n // The `executeTool` event has no description; backfill it from the operation's recorded tools.\n // Gated on `recordInputs` to match the OTel path (descriptions come from the recorded tools list).\n const description =\n recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : undefined;\n return startGenAiSpan(GEN_AI_EXECUTE_TOOL_SPAN_OP, toolName, {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [GEN_AI_TOOL_TYPE]: 'function',\n ...(toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {}),\n ...(toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {}),\n ...(description ? { [GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE]: description } : {}),\n ...(recordInputs && toolInput !== undefined ? { [GEN_AI_TOOL_INPUT]: safeStringify(toolInput) } : {}),\n });\n}\n\n/**\n * Best-effort enrichment from the resolved value the AI SDK attaches to the channel context.\n * Everything here is guarded: when a field is missing or the shape differs across `ai` versions,\n * we simply don't set the attribute rather than emit a malformed span.\n */\nexport function enrichSpanOnEnd(\n span: Span,\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): void {\n const { type, result } = data;\n if (!isRecord(result)) {\n return;\n }\n\n const { recordOutputs } = getRecordingOptions(data.event, channelOptions);\n\n if (type === 'executeTool') {\n if (recordOutputs) {\n span.setAttribute(GEN_AI_TOOL_OUTPUT, safeStringify(result.output ?? result));\n }\n // From V5 on, tool errors are not rejected (so the `error` channel verb never fires) — they\n // surface as `tool-error` content on the resolved result. Mirror the OTel path by marking the\n // span and capturing the error.\n const output = isRecord(result.output) ? result.output : undefined;\n if (output?.type === 'tool-error') {\n captureToolError(span, data, output.error);\n }\n return;\n }\n\n // `languageModelCall` results report usage as `{ total }` objects; top-level/step results report\n // flat numbers. `tokenCount` handles both.\n const usage = isRecord(result.usage) ? result.usage : undefined;\n if (usage) {\n const inputTokens = tokenCount(usage.inputTokens) ?? tokenCount(usage.tokens);\n const outputTokens = tokenCount(usage.outputTokens);\n const totalTokens = tokenCount(usage.totalTokens) ?? sum(inputTokens, outputTokens);\n if (inputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, inputTokens);\n }\n if (outputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);\n }\n if (totalTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);\n }\n }\n\n // Match the OTel integration: finish reasons live on the model-call (`generate_content`) span, not\n // on the top-level `invoke_agent` span.\n const finishReason = getFinishReason(result);\n if (finishReason && type === 'languageModelCall') {\n span.setAttribute(GEN_AI_RESPONSE_FINISH_REASONS, safeStringify([finishReason]));\n }\n\n const response = isRecord(result.response) ? result.response : undefined;\n const responseId = asString(response?.id) ?? asString(result.responseId);\n if (responseId) {\n span.setAttribute(GEN_AI_RESPONSE_ID, responseId);\n }\n const responseModel = asString(response?.modelId) ?? asString(data.event.modelId);\n if (responseModel) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL, responseModel);\n }\n\n // Provider-specific cache/reasoning/prediction token breakdowns and `gen_ai.conversation.id`.\n // The channel exposes `providerMetadata` as an object (the OTel path parses it from a string);\n // both share `getProviderMetadataAttributes` so the emitted shape is identical.\n const providerMetadata = (result as { providerMetadata?: unknown }).providerMetadata;\n const providerAttributes = getProviderMetadataAttributes(providerMetadata);\n // Don't overwrite a conversation id already set on span start (e.g. by `conversationIdIntegration`\n // from a user-set scope value); the provider-derived id is only a fallback. Matches the OTel path.\n if (\n GEN_AI_CONVERSATION_ID_ATTRIBUTE in providerAttributes &&\n spanToJSON(span).data[GEN_AI_CONVERSATION_ID_ATTRIBUTE]\n ) {\n // oxlint-disable-next-line typescript/no-dynamic-delete\n delete providerAttributes[GEN_AI_CONVERSATION_ID_ATTRIBUTE];\n }\n span.setAttributes(providerAttributes);\n\n if (recordOutputs) {\n // `languageModelCall` exposes the response as a `content` parts array; top-level results expose\n // `text` + `toolCalls`. Both normalize into the OTel `gen_ai.output.messages` assistant message.\n const parts =\n type === 'languageModelCall' && Array.isArray(result.content)\n ? partsFromContent(result.content)\n : partsFromTextAndToolCalls(result.text, result.toolCalls);\n const outputMessages = buildOutputMessages(parts, finishReason);\n if (outputMessages) {\n span.setAttribute(GEN_AI_OUTPUT_MESSAGES, outputMessages);\n }\n }\n}\n\n/** Maps a Vercel AI finish reason to the OTel `gen_ai.output.messages` form (`tool-calls` → `tool_call`). */\nfunction normalizeFinishReason(finishReason: string | undefined): string {\n return finishReason === 'tool-calls' ? 'tool_call' : (finishReason ?? 'stop');\n}\n\n/** Reads the finish reason from a result — a string on top-level results, `{ unified }` on model calls. */\nfunction getFinishReason(result: Record<string, unknown>): string | undefined {\n const finishReason = result.finishReason;\n if (typeof finishReason === 'string') {\n return finishReason;\n }\n return isRecord(finishReason) ? asString(finishReason.unified) : undefined;\n}\n\n/** Reads a token count that may be a plain number or a `{ total }` object (model-call usage). */\nfunction tokenCount(value: unknown): number | undefined {\n return asNumber(value) ?? (isRecord(value) ? asNumber(value.total) : undefined);\n}\n\nfunction buildOutputMessages(\n parts: Array<Record<string, unknown>>,\n finishReason: string | undefined,\n): string | undefined {\n if (!parts.length) {\n return undefined;\n }\n return safeStringify([{ role: 'assistant', parts, finish_reason: normalizeFinishReason(finishReason) }]);\n}\n\nfunction toolCallPart(toolCall: Record<string, unknown>): Record<string, unknown> {\n const args = toolCall.input ?? toolCall.args;\n return {\n type: 'tool_call',\n id: asString(toolCall.toolCallId),\n name: asString(toolCall.toolName),\n arguments: typeof args === 'string' ? args : safeStringify(args ?? {}),\n };\n}\n\nfunction partsFromContent(content: unknown[]): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n for (const item of content) {\n if (!isRecord(item)) {\n continue;\n }\n if (item.type === 'text' && typeof item.text === 'string') {\n parts.push({ type: 'text', content: item.text });\n } else if (item.type === 'tool-call') {\n parts.push(toolCallPart(item));\n }\n }\n return parts;\n}\n\nfunction partsFromTextAndToolCalls(text: unknown, toolCalls: unknown): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n if (typeof text === 'string' && text.length) {\n parts.push({ type: 'text', content: text });\n }\n if (Array.isArray(toolCalls)) {\n for (const toolCall of toolCalls) {\n if (isRecord(toolCall)) {\n parts.push(toolCallPart(toolCall));\n }\n }\n }\n return parts;\n}\n\nfunction captureToolError(span: Span, data: VercelAiChannelMessage, error: unknown): void {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error instanceof Error ? error.message : 'tool_error',\n });\n\n const toolCall = isRecord(data.event.toolCall) ? data.event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(data.event.toolCallId) ?? asString(toolCall.toolCallId);\n\n withScope(scope => {\n scope.setContext('trace', spanToTraceContext(span));\n if (toolName) {\n scope.setTag('vercel.ai.tool.name', toolName);\n }\n if (toolCallId) {\n scope.setTag('vercel.ai.tool.callId', toolCallId);\n }\n scope.setLevel('error');\n captureException(\n error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Tool execution failed'),\n {\n mechanism: { type: 'auto.vercelai.channel', handled: false },\n },\n );\n });\n}\n\nfunction getRecordingOptions(\n event: Record<string, unknown>,\n channelOptions: VercelAiChannelOptions,\n): {\n recordInputs: boolean;\n recordOutputs: boolean;\n enableTruncation: boolean;\n} {\n const genAI = getClient()?.getDataCollectionOptions().genAI;\n\n return {\n recordInputs: resolveRecording(channelOptions.recordInputs, event.recordInputs, genAI?.inputs),\n recordOutputs: resolveRecording(channelOptions.recordOutputs, event.recordOutputs, genAI?.outputs),\n enableTruncation: shouldEnableTruncation(channelOptions.enableTruncation),\n };\n}\n\n/**\n * Mirrors the OTel integration's `determineRecordingSettings` precedence: an integration-level option\n * wins, then the per-call `experimental_telemetry.recordInputs/recordOutputs` flag the AI SDK forwards\n * on the channel event, then the global `dataCollection.genAI` default.\n *\n * NOTE: the OTel integration also defaults recording to `true` for a call with\n * `experimental_telemetry: { isEnabled: true }`. The `ai:telemetry` channel does not expose `isEnabled`\n * (nor a resolved recording flag), so that per-call default cannot be reproduced here — v7 users who\n * want inputs/outputs recorded must enable `dataCollection.genAI` or set `recordInputs`/`recordOutputs`.\n */\nfunction resolveRecording(integrationOption: unknown, perCallOption: unknown, globalDefault: unknown): boolean {\n if (typeof integrationOption === 'boolean') {\n return integrationOption;\n }\n if (typeof perCallOption === 'boolean') {\n return perCallOption;\n }\n return globalDefault === true;\n}\n\nfunction buildInputMessageAttributes(\n event: Record<string, unknown>,\n enableTruncation: boolean,\n): Record<string, string | number> {\n const attributes: Record<string, string | number> = {};\n\n // `ai` >= 7 forbids system messages in `messages`/`prompt` and exposes the system prompt as a\n // separate `instructions` field. The OTel path lifts the system message out of the prompt into\n // `gen_ai.system_instructions` as `[{ type: 'text', content }]`; mirror that shape here.\n const instructions = asString(event.instructions);\n if (instructions) {\n attributes[GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE] = safeStringify([{ type: 'text', content: instructions }]);\n }\n\n // The AI SDK start events extend `StandardizedPrompt`; messages live on `messages`, otherwise the\n // simpler `prompt` field is used.\n const messages = event.messages ?? event.prompt;\n if (messages !== undefined) {\n attributes[GEN_AI_INPUT_MESSAGES] = enableTruncation ? getTruncatedJsonString(messages) : safeStringify(messages);\n // The original (pre-truncation) message count, so the product can show how many were dropped.\n attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE] = Array.isArray(messages) ? messages.length : 1;\n }\n\n return attributes;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && !isNaN(value) ? value : undefined;\n}\n\nfunction sum(a: number | undefined, b: number | undefined): number | undefined {\n return a === undefined && b === undefined ? undefined : (a ?? 0) + (b ?? 0);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '[unserializable]';\n }\n}\n"],"names":["tracingChannel","bindTracingChannelToSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","GEN_AI_SYSTEM","GEN_AI_REQUEST_MODEL","GEN_AI_EMBEDDINGS_INPUT","attributes","startInactiveSpan","GEN_AI_OPERATION_NAME","GEN_AI_INVOKE_AGENT_SPAN_OP","GEN_AI_RESPONSE_STREAMING","GEN_AI_FUNCTION_ID","GEN_AI_REQUEST_AVAILABLE_TOOLS","GEN_AI_EXECUTE_TOOL_SPAN_OP","GEN_AI_TOOL_TYPE","GEN_AI_TOOL_NAME","GEN_AI_TOOL_INPUT","GEN_AI_TOOL_OUTPUT","GEN_AI_USAGE_INPUT_TOKENS","GEN_AI_USAGE_OUTPUT_TOKENS","GEN_AI_USAGE_TOTAL_TOKENS","GEN_AI_RESPONSE_FINISH_REASONS","GEN_AI_RESPONSE_ID","GEN_AI_RESPONSE_MODEL","getProviderMetadataAttributes","GEN_AI_CONVERSATION_ID_ATTRIBUTE","spanToJSON","GEN_AI_OUTPUT_MESSAGES","SPAN_STATUS_ERROR","withScope","spanToTraceContext","captureException","getClient","shouldEnableTruncation","GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE","GEN_AI_INPUT_MESSAGES","getTruncatedJsonString","GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE"],"mappings":";;;;;;;AAqDA,MAAM,gCAAA,GAAmC,cAAA;AAEzC,MAAM,MAAA,GAAS,uBAAA;AAGf,MAAM,6BAAA,GAAgC,qBAAA;AACtC,MAAM,iCAAA,GAAoC,yBAAA;AAC1C,MAAM,2BAAA,GAA8B,YAAA;AACpC,MAAM,uBAAA,GAA0B,QAAA;AAGhC,MAAM,iCAAA,GAAoC,kBAAA;AAG1C,MAAM,gCAAA,GAAmC,uBAAA;AACzC,MAAM,kCAAA,GAAqC,0BAAA;AAC3C,MAAM,wCAAA,GAA2C,+BAAA;AAMjD,MAAM,mBAAA,uBAA0B,GAAA,EAAwD;AASxF,MAAM,wBAAA,uBAA+B,GAAA,EAAiC;AAItE,MAAM,oBAAA,uBAA2B,GAAA,CAAsB,CAAC,gBAAgB,YAAA,EAAc,OAAA,EAAS,QAAQ,CAAC,CAAA;AAGjG,SAAS,iBAAiB,IAAA,EAAoC;AACnE,EAAA,IAAI,CAAC,oBAAA,CAAqB,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AACxC,IAAA;AAAA,EACF;AACA,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AACzC,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,mBAAA,CAAoB,OAAO,MAAM,CAAA;AACjC,IAAA,wBAAA,CAAyB,OAAO,MAAM,CAAA;AAAA,EACxC;AACF;AAGA,SAAS,sBAAA,CAAuB,QAA4B,KAAA,EAAsB;AAChF,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACpC,IAAA;AAAA,EACF;AACA,EAAA,IAAI,YAAA,GAAe,wBAAA,CAAyB,GAAA,CAAI,MAAM,CAAA;AACtD,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,IAAI,QAAA,CAAS,IAAI,CAAA,IAAK,OAAO,IAAA,CAAK,SAAS,QAAA,IAAY,OAAO,IAAA,CAAK,WAAA,KAAgB,QAAA,EAAU;AAC3F,MAAA,YAAA,GAAe,YAAA,wBAAoB,GAAA,EAAI;AACvC,MAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AAChC,QAAA,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,IAAA,CAAK,WAAW,CAAA;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AACA,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,wBAAA,CAAyB,GAAA,CAAI,QAAQ,YAAY,CAAA;AAAA,EACnD;AACF;AAOA,SAAS,sBAAA,CAAuB,MAAA,EAA4B,QAAA,EAAkB,KAAA,EAAoC;AAChH,EAAA,MAAM,OAAA,GAAU,SAAS,wBAAA,CAAyB,GAAA,CAAI,MAAM,CAAA,EAAG,GAAA,CAAI,QAAQ,CAAA,GAAI,MAAA;AAC/E,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,OAAO,OAAA;AAAA,EACT;AACA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,CAAA,IAAA,KAAQ,SAAS,IAAI,CAAA,IAAK,IAAA,CAAK,IAAA,KAAS,QAAQ,CAAA;AACzE,IAAA,OAAO,SAAS,KAAK,CAAA,GAAI,QAAA,CAAS,KAAA,CAAM,WAAW,CAAA,GAAI,MAAA;AAAA,EACzD;AACA,EAAA,IAAI,QAAA,CAAS,KAAK,CAAA,EAAG;AACnB,IAAA,MAAM,IAAA,GAAO,MAAM,QAAQ,CAAA;AAC3B,IAAA,OAAO,SAAS,IAAI,CAAA,GAAI,QAAA,CAAS,IAAA,CAAK,WAAW,CAAA,GAAI,MAAA;AAAA,EACvD;AACA,EAAA,OAAO,MAAA;AACT;AA2CA,IAAI,UAAA,GAAa,KAAA;AAcV,SAAS,+BAAA,CACdA,gBAAA,EACA,OAAA,GAAkC,EAAC,EAC7B;AACN,EAAA,IAAI,UAAA,EAAY;AACd,IAAA;AAAA,EACF;AACA,EAAA,UAAA,GAAa,IAAA;AAEb,EAAAC,uCAAA;AAAA,IACED,iBAAuC,gCAAgC,CAAA;AAAA,IACvE,CAAA,IAAA,KAAQ,qBAAA,CAAsB,IAAA,EAAM,OAAO,CAAA;AAAA,IAC3C;AAAA;AAAA;AAAA,MAGE,aAAA,EAAe,CAAC,IAAA,EAAM,IAAA,KAAS;AAC7B,QAAA,eAAA,CAAgB,IAAA,EAAM,MAAM,OAAO,CAAA;AACnC,QAAA,gBAAA,CAAiB,IAAI,CAAA;AAAA,MACvB;AAAA;AACF,GACF;AACF;AAQO,SAAS,qBAAA,CACd,MACA,cAAA,EACkB;AAClB,EAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,IAAA;AAExB,EAAA,IAAI,SAAS,MAAA,IAAU,CAAC,KAAA,IAAS,OAAO,UAAU,QAAA,EAAU;AAG1D,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,EAAE,YAAA,EAAc,gBAAA,EAAiB,GAAI,mBAAA,CAAoB,OAAO,cAAc,CAAA;AACpF,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,KAAA,CAAM,QAAQ,CAAA;AACxC,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,KAAA,CAAM,OAAO,CAAA;AACtC,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,CAAM,MAAM,CAAA;AACpC,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,KAAA,CAAM,UAAU,CAAA;AAI5C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,sBAAA,CAAuB,MAAA,EAAQ,MAAM,KAAK,CAAA;AAAA,EAC5C;AAEA,EAAA,MAAM,cAAA,GAA4D;AAAA,IAChE,CAACE,qCAAgC,GAAG,MAAA;AAAA,IACpC,GAAI,QAAA,GAAW,EAAE,CAACC,wBAAa,GAAG,QAAA,EAAU,CAAC,kCAAkC,GAAG,QAAA,EAAS,GAAI,EAAC;AAAA,IAChG,GAAI,UAAU,EAAE,CAACC,+BAAoB,GAAG,OAAA,KAAY,EAAC;AAAA,IACrD,GAAI,eAAe,MAAA,GAAY,EAAE,CAAC,wCAAwC,GAAG,UAAA,EAAW,GAAI;AAAC,GAC/F;AAEA,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,cAAA;AAAA,IACL,KAAK,YAAA;AACH,MAAA,OAAO,qBAAqB,KAAA,EAAO,cAAA,EAAgB,cAAc,gBAAA,EAAkB,MAAA,EAAQ,SAAS,YAAY,CAAA;AAAA,IAClH,KAAK,mBAAA;AACH,MAAA,OAAO,mBAAmB,KAAA,EAAO,cAAA,EAAgB,YAAA,EAAc,gBAAA,EAAkB,QAAQ,OAAO,CAAA;AAAA,IAClG,KAAK,aAAA;AACH,MAAA,OAAO,aAAA,CAAc,OAAO,YAAY,CAAA;AAAA,IAC1C,KAAK,OAAA;AACH,MAAA,OAAO,cAAA,CAAe,6BAA6B,OAAA,EAAS;AAAA,QAC1D,GAAG,cAAA;AAAA,QACH,GAAI,YAAA,IAAgB,KAAA,CAAM,KAAA,KAAU,SAAY,EAAE,CAACC,kCAAuB,GAAG,aAAA,CAAc,KAAA,CAAM,KAAK,CAAA,KAAM;AAAC,OAC9G,CAAA;AAAA,IACH,KAAK,QAAA;AACH,MAAA,OAAO,cAAA,CAAe,uBAAA,EAAyB,OAAA,EAAS,cAAc,CAAA;AAAA,IACxE;AAEE,MAAA,OAAO,MAAA;AAAA;AAEb;AAKA,SAAS,cAAA,CAAe,SAAA,EAAmB,MAAA,EAA4BC,YAAA,EAA8B;AACnG,EAAA,OAAOC,sBAAA,CAAkB;AAAA,IACvB,MAAM,MAAA,GAAS,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA,GAAK,SAAA;AAAA,IAC1C,EAAA,EAAI,UAAU,SAAS,CAAA,CAAA;AAAA,IACvB,YAAY,EAAE,CAACC,gCAAqB,GAAG,SAAA,EAAW,GAAGF,YAAA;AAAW,GACjE,CAAA;AACH;AAEA,SAAS,qBACP,KAAA,EACA,cAAA,EACA,YAAA,EACA,gBAAA,EACA,QACA,QAAA,EACM;AACN,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,KAAA,CAAM,UAAU,CAAA;AAC5C,EAAA,MAAM,cAAc,QAAA,CAAS,KAAA,CAAM,WAAW,CAAA,KAAM,WAAW,eAAA,GAAkB,iBAAA,CAAA;AACjF,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,mBAAA,CAAoB,GAAA,CAAI,MAAA,EAAQ,EAAE,WAAA,EAAa,UAAU,CAAA;AAAA,EAC3D;AACA,EAAA,OAAO,cAAA,CAAeG,gCAA6B,UAAA,EAAY;AAAA,IAC7D,GAAG,cAAA;AAAA,IACH,CAAC,gCAAgC,GAAG,WAAA;AAAA,IACpC,CAACC,oCAAyB,GAAG,QAAA;AAAA,IAC7B,GAAI,aAAa,EAAE,CAACC,6BAAkB,GAAG,UAAA,KAAe,EAAC;AAAA,IACzD,GAAI,YAAA,GAAe,2BAAA,CAA4B,KAAA,EAAO,gBAAgB,IAAI;AAAC,GAC5E,CAAA;AACH;AAEA,SAAS,mBACP,KAAA,EACA,cAAA,EACA,YAAA,EACA,gBAAA,EACA,QACA,OAAA,EACM;AACN,EAAA,MAAM,MAAA,GAAS,MAAA,GAAS,mBAAA,CAAoB,GAAA,CAAI,MAAM,CAAA,GAAI,MAAA;AAC1D,EAAA,MAAM,WAAA,GAAc,MAAA,GAChB,CAAA,EAAG,MAAA,CAAO,WAAW,IAAI,MAAA,CAAO,QAAA,GAAW,UAAA,GAAa,YAAY,CAAA,CAAA,GACpE,4BAAA;AACJ,EAAA,OAAO,cAAA,CAAe,mCAAmC,OAAA,EAAS;AAAA,IAChE,GAAG,cAAA;AAAA,IACH,CAAC,gCAAgC,GAAG,WAAA;AAAA,IACpC,GAAI,YAAA,GAAe,2BAAA,CAA4B,KAAA,EAAO,gBAAgB,IAAI,EAAC;AAAA,IAC3E,GAAI,YAAA,IAAgB,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,GACzC,EAAE,CAACC,yCAA8B,GAAG,aAAA,CAAc,KAAA,CAAM,KAAK,CAAA,KAC7D;AAAC,GACN,CAAA;AACH;AAEA,SAAS,aAAA,CAAc,OAAgC,YAAA,EAA6B;AAClF,EAAA,MAAM,WAAW,QAAA,CAAS,KAAA,CAAM,QAAQ,CAAA,GAAI,KAAA,CAAM,WAAW,EAAC;AAC9D,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,QAAA,CAAS,QAAQ,CAAA;AAC3C,EAAA,MAAM,aAAa,QAAA,CAAS,KAAA,CAAM,UAAU,CAAA,IAAK,QAAA,CAAS,SAAS,UAAU,CAAA;AAC7E,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,KAAA,IAAS,QAAA,CAAS,IAAA;AAG7C,EAAA,MAAM,WAAA,GACJ,YAAA,IAAgB,QAAA,GAAW,sBAAA,CAAuB,QAAA,CAAS,KAAA,CAAM,MAAM,CAAA,EAAG,QAAA,EAAU,KAAA,CAAM,KAAK,CAAA,GAAI,MAAA;AACrG,EAAA,OAAO,cAAA,CAAeC,gCAA6B,QAAA,EAAU;AAAA,IAC3D,CAACX,qCAAgC,GAAG,MAAA;AAAA,IACpC,CAACY,2BAAgB,GAAG,UAAA;AAAA,IACpB,GAAI,WAAW,EAAE,CAACC,2BAAgB,GAAG,QAAA,KAAa,EAAC;AAAA,IACnD,GAAI,aAAa,EAAE,CAAC,6BAA6B,GAAG,UAAA,KAAe,EAAC;AAAA,IACpE,GAAI,cAAc,EAAE,CAAC,iCAAiC,GAAG,WAAA,KAAgB,EAAC;AAAA,IAC1E,GAAI,YAAA,IAAgB,SAAA,KAAc,MAAA,GAAY,EAAE,CAACC,4BAAiB,GAAG,aAAA,CAAc,SAAS,CAAA,EAAE,GAAI;AAAC,GACpG,CAAA;AACH;AAOO,SAAS,eAAA,CACd,IAAA,EACA,IAAA,EACA,cAAA,EACM;AACN,EAAA,MAAM,EAAE,IAAA,EAAM,MAAA,EAAO,GAAI,IAAA;AACzB,EAAA,IAAI,CAAC,QAAA,CAAS,MAAM,CAAA,EAAG;AACrB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,EAAE,aAAA,EAAc,GAAI,mBAAA,CAAoB,IAAA,CAAK,OAAO,cAAc,CAAA;AAExE,EAAA,IAAI,SAAS,aAAA,EAAe;AAC1B,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,IAAA,CAAK,aAAaC,6BAAA,EAAoB,aAAA,CAAc,MAAA,CAAO,MAAA,IAAU,MAAM,CAAC,CAAA;AAAA,IAC9E;AAIA,IAAA,MAAM,SAAS,QAAA,CAAS,MAAA,CAAO,MAAM,CAAA,GAAI,OAAO,MAAA,GAAS,MAAA;AACzD,IAAA,IAAI,MAAA,EAAQ,SAAS,YAAA,EAAc;AACjC,MAAA,gBAAA,CAAiB,IAAA,EAAM,IAAA,EAAM,MAAA,CAAO,KAAK,CAAA;AAAA,IAC3C;AACA,IAAA;AAAA,EACF;AAIA,EAAA,MAAM,QAAQ,QAAA,CAAS,MAAA,CAAO,KAAK,CAAA,GAAI,OAAO,KAAA,GAAQ,MAAA;AACtD,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAM,cAAc,UAAA,CAAW,KAAA,CAAM,WAAW,CAAA,IAAK,UAAA,CAAW,MAAM,MAAM,CAAA;AAC5E,IAAA,MAAM,YAAA,GAAe,UAAA,CAAW,KAAA,CAAM,YAAY,CAAA;AAClD,IAAA,MAAM,cAAc,UAAA,CAAW,KAAA,CAAM,WAAW,CAAA,IAAK,GAAA,CAAI,aAAa,YAAY,CAAA;AAClF,IAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,MAAA,IAAA,CAAK,YAAA,CAAaC,sCAA2B,WAAW,CAAA;AAAA,IAC1D;AACA,IAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,MAAA,IAAA,CAAK,YAAA,CAAaC,uCAA4B,YAAY,CAAA;AAAA,IAC5D;AACA,IAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,MAAA,IAAA,CAAK,YAAA,CAAaC,sCAA2B,WAAW,CAAA;AAAA,IAC1D;AAAA,EACF;AAIA,EAAA,MAAM,YAAA,GAAe,gBAAgB,MAAM,CAAA;AAC3C,EAAA,IAAI,YAAA,IAAgB,SAAS,mBAAA,EAAqB;AAChD,IAAA,IAAA,CAAK,aAAaC,yCAAA,EAAgC,aAAA,CAAc,CAAC,YAAY,CAAC,CAAC,CAAA;AAAA,EACjF;AAEA,EAAA,MAAM,WAAW,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA,GAAI,OAAO,QAAA,GAAW,MAAA;AAC/D,EAAA,MAAM,aAAa,QAAA,CAAS,QAAA,EAAU,EAAE,CAAA,IAAK,QAAA,CAAS,OAAO,UAAU,CAAA;AACvE,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,IAAA,CAAK,YAAA,CAAaC,+BAAoB,UAAU,CAAA;AAAA,EAClD;AACA,EAAA,MAAM,aAAA,GAAgB,SAAS,QAAA,EAAU,OAAO,KAAK,QAAA,CAAS,IAAA,CAAK,MAAM,OAAO,CAAA;AAChF,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,IAAA,CAAK,YAAA,CAAaC,kCAAuB,aAAa,CAAA;AAAA,EACxD;AAKA,EAAA,MAAM,mBAAoB,MAAA,CAA0C,gBAAA;AACpE,EAAA,MAAM,kBAAA,GAAqBC,mCAA8B,gBAAgB,CAAA;AAGzE,EAAA,IACEC,yCAAoC,kBAAA,IACpCC,eAAA,CAAW,IAAI,CAAA,CAAE,IAAA,CAAKD,qCAAgC,CAAA,EACtD;AAEA,IAAA,OAAO,mBAAmBA,qCAAgC,CAAA;AAAA,EAC5D;AACA,EAAA,IAAA,CAAK,cAAc,kBAAkB,CAAA;AAErC,EAAA,IAAI,aAAA,EAAe;AAGjB,IAAA,MAAM,QACJ,IAAA,KAAS,mBAAA,IAAuB,KAAA,CAAM,OAAA,CAAQ,OAAO,OAAO,CAAA,GACxD,gBAAA,CAAiB,MAAA,CAAO,OAAO,CAAA,GAC/B,yBAAA,CAA0B,MAAA,CAAO,IAAA,EAAM,OAAO,SAAS,CAAA;AAC7D,IAAA,MAAM,cAAA,GAAiB,mBAAA,CAAoB,KAAA,EAAO,YAAY,CAAA;AAC9D,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,IAAA,CAAK,YAAA,CAAaE,mCAAwB,cAAc,CAAA;AAAA,IAC1D;AAAA,EACF;AACF;AAGA,SAAS,sBAAsB,YAAA,EAA0C;AACvE,EAAA,OAAO,YAAA,KAAiB,YAAA,GAAe,WAAA,GAAe,YAAA,IAAgB,MAAA;AACxE;AAGA,SAAS,gBAAgB,MAAA,EAAqD;AAC5E,EAAA,MAAM,eAAe,MAAA,CAAO,YAAA;AAC5B,EAAA,IAAI,OAAO,iBAAiB,QAAA,EAAU;AACpC,IAAA,OAAO,YAAA;AAAA,EACT;AACA,EAAA,OAAO,SAAS,YAAY,CAAA,GAAI,QAAA,CAAS,YAAA,CAAa,OAAO,CAAA,GAAI,MAAA;AACnE;AAGA,SAAS,WAAW,KAAA,EAAoC;AACtD,EAAA,OAAO,QAAA,CAAS,KAAK,CAAA,KAAM,QAAA,CAAS,KAAK,CAAA,GAAI,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA,GAAI,MAAA,CAAA;AACvE;AAEA,SAAS,mBAAA,CACP,OACA,YAAA,EACoB;AACpB,EAAA,IAAI,CAAC,MAAM,MAAA,EAAQ;AACjB,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,aAAA,CAAc,CAAC,EAAE,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,aAAA,EAAe,qBAAA,CAAsB,YAAY,CAAA,EAAG,CAAC,CAAA;AACzG;AAEA,SAAS,aAAa,QAAA,EAA4D;AAChF,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,KAAA,IAAS,QAAA,CAAS,IAAA;AACxC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,WAAA;AAAA,IACN,EAAA,EAAI,QAAA,CAAS,QAAA,CAAS,UAAU,CAAA;AAAA,IAChC,IAAA,EAAM,QAAA,CAAS,QAAA,CAAS,QAAQ,CAAA;AAAA,IAChC,SAAA,EAAW,OAAO,IAAA,KAAS,QAAA,GAAW,OAAO,aAAA,CAAc,IAAA,IAAQ,EAAE;AAAA,GACvE;AACF;AAEA,SAAS,iBAAiB,OAAA,EAAoD;AAC5E,EAAA,MAAM,QAAwC,EAAC;AAC/C,EAAA,KAAA,MAAW,QAAQ,OAAA,EAAS;AAC1B,IAAA,IAAI,CAAC,QAAA,CAAS,IAAI,CAAA,EAAG;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,KAAK,IAAA,KAAS,MAAA,IAAU,OAAO,IAAA,CAAK,SAAS,QAAA,EAAU;AACzD,MAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,QAAQ,OAAA,EAAS,IAAA,CAAK,MAAM,CAAA;AAAA,IACjD,CAAA,MAAA,IAAW,IAAA,CAAK,IAAA,KAAS,WAAA,EAAa;AACpC,MAAA,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,IAAI,CAAC,CAAA;AAAA,IAC/B;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,yBAAA,CAA0B,MAAe,SAAA,EAAoD;AACpG,EAAA,MAAM,QAAwC,EAAC;AAC/C,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,CAAK,MAAA,EAAQ;AAC3C,IAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,MAAM,CAAA;AAAA,EAC5C;AACA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,SAAS,CAAA,EAAG;AAC5B,IAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,MAAA,IAAI,QAAA,CAAS,QAAQ,CAAA,EAAG;AACtB,QAAA,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,QAAQ,CAAC,CAAA;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,gBAAA,CAAiB,IAAA,EAAY,IAAA,EAA8B,KAAA,EAAsB;AACxF,EAAA,IAAA,CAAK,SAAA,CAAU;AAAA,IACb,IAAA,EAAMC,sBAAA;AAAA,IACN,OAAA,EAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA,GACnD,CAAA;AAED,EAAA,MAAM,QAAA,GAAW,SAAS,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,QAAA,GAAW,EAAC;AACxE,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,QAAA,CAAS,QAAQ,CAAA;AAC3C,EAAA,MAAM,UAAA,GAAa,SAAS,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA,IAAK,QAAA,CAAS,SAAS,UAAU,CAAA;AAElF,EAAAC,cAAA,CAAU,CAAA,KAAA,KAAS;AACjB,IAAA,KAAA,CAAM,UAAA,CAAW,OAAA,EAASC,uBAAA,CAAmB,IAAI,CAAC,CAAA;AAClD,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,KAAA,CAAM,MAAA,CAAO,uBAAuB,QAAQ,CAAA;AAAA,IAC9C;AACA,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,KAAA,CAAM,MAAA,CAAO,yBAAyB,UAAU,CAAA;AAAA,IAClD;AACA,IAAA,KAAA,CAAM,SAAS,OAAO,CAAA;AACtB,IAAAC,qBAAA;AAAA,MACE,KAAA,YAAiB,QAAQ,KAAA,GAAQ,IAAI,MAAM,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,uBAAuB,CAAA;AAAA,MACtG;AAAA,QACE,SAAA,EAAW,EAAE,IAAA,EAAM,uBAAA,EAAyB,SAAS,KAAA;AAAM;AAC7D,KACF;AAAA,EACF,CAAC,CAAA;AACH;AAEA,SAAS,mBAAA,CACP,OACA,cAAA,EAKA;AACA,EAAA,MAAM,KAAA,GAAQC,cAAA,EAAU,EAAG,wBAAA,EAAyB,CAAE,KAAA;AAEtD,EAAA,OAAO;AAAA,IACL,cAAc,gBAAA,CAAiB,cAAA,CAAe,cAAc,KAAA,CAAM,YAAA,EAAc,OAAO,MAAM,CAAA;AAAA,IAC7F,eAAe,gBAAA,CAAiB,cAAA,CAAe,eAAe,KAAA,CAAM,aAAA,EAAe,OAAO,OAAO,CAAA;AAAA,IACjG,gBAAA,EAAkBC,2BAAA,CAAuB,cAAA,CAAe,gBAAgB;AAAA,GAC1E;AACF;AAYA,SAAS,gBAAA,CAAiB,iBAAA,EAA4B,aAAA,EAAwB,aAAA,EAAiC;AAC7G,EAAA,IAAI,OAAO,sBAAsB,SAAA,EAAW;AAC1C,IAAA,OAAO,iBAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAO,kBAAkB,SAAA,EAAW;AACtC,IAAA,OAAO,aAAA;AAAA,EACT;AACA,EAAA,OAAO,aAAA,KAAkB,IAAA;AAC3B;AAEA,SAAS,2BAAA,CACP,OACA,gBAAA,EACiC;AACjC,EAAA,MAAM3B,eAA8C,EAAC;AAKrD,EAAA,MAAM,YAAA,GAAe,QAAA,CAAS,KAAA,CAAM,YAAY,CAAA;AAChD,EAAA,IAAI,YAAA,EAAc;AAChB,IAAAA,YAAA,CAAW4B,yCAAoC,CAAA,GAAI,aAAA,CAAc,CAAC,EAAE,MAAM,MAAA,EAAQ,OAAA,EAAS,YAAA,EAAc,CAAC,CAAA;AAAA,EAC5G;AAIA,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,IAAY,KAAA,CAAM,MAAA;AACzC,EAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,IAAA5B,YAAA,CAAW6B,gCAAqB,CAAA,GAAI,gBAAA,GAAmBC,4BAAuB,QAAQ,CAAA,GAAI,cAAc,QAAQ,CAAA;AAEhH,IAAA9B,YAAA,CAAW+B,oDAA+C,CAAA,GAAI,KAAA,CAAM,QAAQ,QAAQ,CAAA,GAAI,SAAS,MAAA,GAAS,CAAA;AAAA,EAC5G;AAEA,EAAA,OAAO/B,YAAA;AACT;AAEA,SAAS,SAAS,KAAA,EAAoC;AACpD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,MAAA;AAC7C;AAEA,SAAS,SAAS,KAAA,EAAoC;AACpD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,KAAA,CAAM,KAAK,IAAI,KAAA,GAAQ,MAAA;AAC9D;AAEA,SAAS,GAAA,CAAI,GAAuB,CAAA,EAA2C;AAC7E,EAAA,OAAO,MAAM,MAAA,IAAa,CAAA,KAAM,SAAY,MAAA,GAAA,CAAa,CAAA,IAAK,MAAM,CAAA,IAAK,CAAA,CAAA;AAC3E;AAEA,SAAS,SAAS,KAAA,EAAkD;AAClE,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA;AAChD;AAEA,SAAS,cAAc,KAAA,EAAwB;AAC7C,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,kBAAA;AAAA,EACT;AACF;;;;;;;"}
import { defineIntegration } from '@sentry/core';
import { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber.js';
import * as dc from 'node:diagnostics_channel';
const _vercelAiIntegration = ((options = {}) => {
return {
name: "VercelAI",
setupOnce() {
if (!dc.tracingChannel) {
return;
}
void Promise.resolve().then(() => subscribeVercelAiTracingChannel(dc.tracingChannel, options));
}
};
});
const vercelAiIntegration = defineIntegration(_vercelAiIntegration);
export { vercelAiIntegration };
//# sourceMappingURL=index.js.map
{"version":3,"file":"index.js","sources":["../../../src/vercel-ai/index.ts"],"sourcesContent":["import { defineIntegration, type IntegrationFn } from '@sentry/core';\nimport { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber';\nimport * as dc from 'node:diagnostics_channel';\n\ntype VercelAiOptions = {\n /**\n * Enable or disable input recording. Enabled if `dataCollection.genAI.inputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordInputs?: boolean;\n\n /**\n * Enable or disable output recording. Enabled if `dataCollection.genAI.outputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordOutputs?: boolean;\n\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n};\n\nconst _vercelAiIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: 'VercelAI' as const,\n setupOnce() {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n // Subscribe to the `ai` SDK's native telemetry tracing channel (ai >= 7).\n // This is a no-op on versions that don't publish to the channel, so it is always safe to call.\n // The factory needs the Sentry OTel context manager, which `initOpenTelemetry()` registers after `setupOnce`, so defer a tick.\n // Options are passed in here rather than read back off the integration per event.\n void Promise.resolve().then(() => subscribeVercelAiTracingChannel(dc.tracingChannel, options));\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7).\n */\nexport const vercelAiIntegration = defineIntegration(_vercelAiIntegration);\n"],"names":[],"mappings":";;;;AA0BA,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAAC,GAAG,cAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAMA,MAAA,KAAK,OAAA,CAAQ,SAAQ,CAAE,IAAA,CAAK,MAAM,+BAAA,CAAgC,EAAA,CAAG,cAAA,EAAgB,OAAO,CAAC,CAAA;AAAA,IAC/F;AAAA,GACF;AACF,CAAA,CAAA;AAKO,MAAM,mBAAA,GAAsB,kBAAkB,oBAAoB;;;;"}
import { GEN_AI_EMBEDDINGS_INPUT, GEN_AI_OPERATION_NAME, GEN_AI_FUNCTION_ID, GEN_AI_RESPONSE_STREAMING, GEN_AI_REQUEST_AVAILABLE_TOOLS, GEN_AI_TOOL_INPUT, GEN_AI_TOOL_NAME, GEN_AI_TOOL_TYPE, GEN_AI_TOOL_OUTPUT, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, GEN_AI_RESPONSE_FINISH_REASONS, GEN_AI_RESPONSE_ID, GEN_AI_RESPONSE_MODEL, GEN_AI_OUTPUT_MESSAGES, GEN_AI_INPUT_MESSAGES, GEN_AI_REQUEST_MODEL, GEN_AI_SYSTEM } from '@sentry/conventions/attributes';
import { GEN_AI_INVOKE_AGENT_SPAN_OP, GEN_AI_EXECUTE_TOOL_SPAN_OP } from '@sentry/conventions/op';
import { startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getProviderMetadataAttributes, GEN_AI_CONVERSATION_ID_ATTRIBUTE, spanToJSON, SPAN_STATUS_ERROR, withScope, spanToTraceContext, captureException, getClient, shouldEnableTruncation, getTruncatedJsonString, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '@sentry/core';
import { bindTracingChannelToSpan } from '../tracing-channel.js';
const AI_SDK_TELEMETRY_TRACING_CHANNEL = "ai:telemetry";
const ORIGIN = "auto.vercelai.channel";
const GEN_AI_TOOL_CALL_ID_ATTRIBUTE = "gen_ai.tool.call.id";
const GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = "gen_ai.tool.description";
const GEN_AI_EMBEDDINGS_OPERATION = "embeddings";
const GEN_AI_RERANK_OPERATION = "rerank";
const GEN_AI_GENERATE_CONTENT_OPERATION = "generate_content";
const VERCEL_AI_OPERATION_ID_ATTRIBUTE = "vercel.ai.operationId";
const VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE = "vercel.ai.model.provider";
const VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE = "vercel.ai.settings.maxRetries";
const operationIdByCallId = /* @__PURE__ */ new Map();
const toolDescriptionsByCallId = /* @__PURE__ */ new Map();
const ROOT_OPERATION_TYPES = /* @__PURE__ */ new Set(["generateText", "streamText", "embed", "rerank"]);
function clearOperationId(data) {
if (!ROOT_OPERATION_TYPES.has(data.type)) {
return;
}
const callId = asString(data.event.callId);
if (callId) {
operationIdByCallId.delete(callId);
toolDescriptionsByCallId.delete(callId);
}
}
function recordToolDescriptions(callId, tools) {
if (!callId || !Array.isArray(tools)) {
return;
}
let descriptions = toolDescriptionsByCallId.get(callId);
for (const tool of tools) {
if (isRecord(tool) && typeof tool.name === "string" && typeof tool.description === "string") {
descriptions = descriptions ?? /* @__PURE__ */ new Map();
if (!descriptions.has(tool.name)) {
descriptions.set(tool.name, tool.description);
}
}
}
if (descriptions) {
toolDescriptionsByCallId.set(callId, descriptions);
}
}
function resolveToolDescription(callId, toolName, tools) {
const fromMap = callId ? toolDescriptionsByCallId.get(callId)?.get(toolName) : void 0;
if (fromMap) {
return fromMap;
}
if (Array.isArray(tools)) {
const match = tools.find((tool) => isRecord(tool) && tool.name === toolName);
return isRecord(match) ? asString(match.description) : void 0;
}
if (isRecord(tools)) {
const tool = tools[toolName];
return isRecord(tool) ? asString(tool.description) : void 0;
}
return void 0;
}
let subscribed = false;
function subscribeVercelAiTracingChannel(tracingChannel, options = {}) {
if (subscribed) {
return;
}
subscribed = true;
bindTracingChannelToSpan(
tracingChannel(AI_SDK_TELEMETRY_TRACING_CHANNEL),
(data) => createSpanFromMessage(data, options),
{
// The helper ends the span; we enrich it from the settled result first (tokens, output messages,
// finish reasons, response model/id, provider metadata) and drop the per-operation `callId` maps.
beforeSpanEnd: (span, data) => {
enrichSpanOnEnd(span, data, options);
clearOperationId(data);
}
}
);
}
function createSpanFromMessage(data, channelOptions) {
const { type, event } = data;
if (type === "step" || !event || typeof event !== "object") {
return void 0;
}
const { recordInputs, enableTruncation } = getRecordingOptions(event, channelOptions);
const provider = asString(event.provider);
const modelId = asString(event.modelId);
const callId = asString(event.callId);
const maxRetries = asNumber(event.maxRetries);
if (recordInputs) {
recordToolDescriptions(callId, event.tools);
}
const baseAttributes = {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
...provider ? { [GEN_AI_SYSTEM]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {},
...modelId ? { [GEN_AI_REQUEST_MODEL]: modelId } : {},
...maxRetries !== void 0 ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}
};
switch (type) {
case "generateText":
case "streamText":
return buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, type === "streamText");
case "languageModelCall":
return buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId);
case "executeTool":
return buildToolSpan(event, recordInputs);
case "embed":
return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, {
...baseAttributes,
...recordInputs && event.value !== void 0 ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(event.value) } : {}
});
case "rerank":
return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes);
default:
return void 0;
}
}
function startGenAiSpan(operation, suffix, attributes) {
return startInactiveSpan({
name: suffix ? `${operation} ${suffix}` : operation,
op: `gen_ai.${operation}`,
attributes: { [GEN_AI_OPERATION_NAME]: operation, ...attributes }
});
}
function buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, isStream) {
const functionId = asString(event.functionId);
const operationId = asString(event.operationId) ?? (isStream ? "ai.streamText" : "ai.generateText");
if (callId) {
operationIdByCallId.set(callId, { operationId, isStream });
}
return startGenAiSpan(GEN_AI_INVOKE_AGENT_SPAN_OP, functionId, {
...baseAttributes,
[VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,
[GEN_AI_RESPONSE_STREAMING]: isStream,
...functionId ? { [GEN_AI_FUNCTION_ID]: functionId } : {},
...recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}
});
}
function buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId) {
const parent = callId ? operationIdByCallId.get(callId) : void 0;
const operationId = parent ? `${parent.operationId}.${parent.isStream ? "doStream" : "doGenerate"}` : "ai.generateText.doGenerate";
return startGenAiSpan(GEN_AI_GENERATE_CONTENT_OPERATION, modelId, {
...baseAttributes,
[VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,
...recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {},
...recordInputs && Array.isArray(event.tools) ? { [GEN_AI_REQUEST_AVAILABLE_TOOLS]: safeStringify(event.tools) } : {}
});
}
function buildToolSpan(event, recordInputs) {
const toolCall = isRecord(event.toolCall) ? event.toolCall : {};
const toolName = asString(toolCall.toolName);
const toolCallId = asString(event.toolCallId) ?? asString(toolCall.toolCallId);
const toolInput = toolCall.input ?? toolCall.args;
const description = recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : void 0;
return startGenAiSpan(GEN_AI_EXECUTE_TOOL_SPAN_OP, toolName, {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
[GEN_AI_TOOL_TYPE]: "function",
...toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {},
...toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {},
...description ? { [GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE]: description } : {},
...recordInputs && toolInput !== void 0 ? { [GEN_AI_TOOL_INPUT]: safeStringify(toolInput) } : {}
});
}
function enrichSpanOnEnd(span, data, channelOptions) {
const { type, result } = data;
if (!isRecord(result)) {
return;
}
const { recordOutputs } = getRecordingOptions(data.event, channelOptions);
if (type === "executeTool") {
if (recordOutputs) {
span.setAttribute(GEN_AI_TOOL_OUTPUT, safeStringify(result.output ?? result));
}
const output = isRecord(result.output) ? result.output : void 0;
if (output?.type === "tool-error") {
captureToolError(span, data, output.error);
}
return;
}
const usage = isRecord(result.usage) ? result.usage : void 0;
if (usage) {
const inputTokens = tokenCount(usage.inputTokens) ?? tokenCount(usage.tokens);
const outputTokens = tokenCount(usage.outputTokens);
const totalTokens = tokenCount(usage.totalTokens) ?? sum(inputTokens, outputTokens);
if (inputTokens !== void 0) {
span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, inputTokens);
}
if (outputTokens !== void 0) {
span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);
}
if (totalTokens !== void 0) {
span.setAttribute(GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);
}
}
const finishReason = getFinishReason(result);
if (finishReason && type === "languageModelCall") {
span.setAttribute(GEN_AI_RESPONSE_FINISH_REASONS, safeStringify([finishReason]));
}
const response = isRecord(result.response) ? result.response : void 0;
const responseId = asString(response?.id) ?? asString(result.responseId);
if (responseId) {
span.setAttribute(GEN_AI_RESPONSE_ID, responseId);
}
const responseModel = asString(response?.modelId) ?? asString(data.event.modelId);
if (responseModel) {
span.setAttribute(GEN_AI_RESPONSE_MODEL, responseModel);
}
const providerMetadata = result.providerMetadata;
const providerAttributes = getProviderMetadataAttributes(providerMetadata);
if (GEN_AI_CONVERSATION_ID_ATTRIBUTE in providerAttributes && spanToJSON(span).data[GEN_AI_CONVERSATION_ID_ATTRIBUTE]) {
delete providerAttributes[GEN_AI_CONVERSATION_ID_ATTRIBUTE];
}
span.setAttributes(providerAttributes);
if (recordOutputs) {
const parts = type === "languageModelCall" && Array.isArray(result.content) ? partsFromContent(result.content) : partsFromTextAndToolCalls(result.text, result.toolCalls);
const outputMessages = buildOutputMessages(parts, finishReason);
if (outputMessages) {
span.setAttribute(GEN_AI_OUTPUT_MESSAGES, outputMessages);
}
}
}
function normalizeFinishReason(finishReason) {
return finishReason === "tool-calls" ? "tool_call" : finishReason ?? "stop";
}
function getFinishReason(result) {
const finishReason = result.finishReason;
if (typeof finishReason === "string") {
return finishReason;
}
return isRecord(finishReason) ? asString(finishReason.unified) : void 0;
}
function tokenCount(value) {
return asNumber(value) ?? (isRecord(value) ? asNumber(value.total) : void 0);
}
function buildOutputMessages(parts, finishReason) {
if (!parts.length) {
return void 0;
}
return safeStringify([{ role: "assistant", parts, finish_reason: normalizeFinishReason(finishReason) }]);
}
function toolCallPart(toolCall) {
const args = toolCall.input ?? toolCall.args;
return {
type: "tool_call",
id: asString(toolCall.toolCallId),
name: asString(toolCall.toolName),
arguments: typeof args === "string" ? args : safeStringify(args ?? {})
};
}
function partsFromContent(content) {
const parts = [];
for (const item of content) {
if (!isRecord(item)) {
continue;
}
if (item.type === "text" && typeof item.text === "string") {
parts.push({ type: "text", content: item.text });
} else if (item.type === "tool-call") {
parts.push(toolCallPart(item));
}
}
return parts;
}
function partsFromTextAndToolCalls(text, toolCalls) {
const parts = [];
if (typeof text === "string" && text.length) {
parts.push({ type: "text", content: text });
}
if (Array.isArray(toolCalls)) {
for (const toolCall of toolCalls) {
if (isRecord(toolCall)) {
parts.push(toolCallPart(toolCall));
}
}
}
return parts;
}
function captureToolError(span, data, error) {
span.setStatus({
code: SPAN_STATUS_ERROR,
message: error instanceof Error ? error.message : "tool_error"
});
const toolCall = isRecord(data.event.toolCall) ? data.event.toolCall : {};
const toolName = asString(toolCall.toolName);
const toolCallId = asString(data.event.toolCallId) ?? asString(toolCall.toolCallId);
withScope((scope) => {
scope.setContext("trace", spanToTraceContext(span));
if (toolName) {
scope.setTag("vercel.ai.tool.name", toolName);
}
if (toolCallId) {
scope.setTag("vercel.ai.tool.callId", toolCallId);
}
scope.setLevel("error");
captureException(
error instanceof Error ? error : new Error(typeof error === "string" ? error : "Tool execution failed"),
{
mechanism: { type: "auto.vercelai.channel", handled: false }
}
);
});
}
function getRecordingOptions(event, channelOptions) {
const genAI = getClient()?.getDataCollectionOptions().genAI;
return {
recordInputs: resolveRecording(channelOptions.recordInputs, event.recordInputs, genAI?.inputs),
recordOutputs: resolveRecording(channelOptions.recordOutputs, event.recordOutputs, genAI?.outputs),
enableTruncation: shouldEnableTruncation(channelOptions.enableTruncation)
};
}
function resolveRecording(integrationOption, perCallOption, globalDefault) {
if (typeof integrationOption === "boolean") {
return integrationOption;
}
if (typeof perCallOption === "boolean") {
return perCallOption;
}
return globalDefault === true;
}
function buildInputMessageAttributes(event, enableTruncation) {
const attributes = {};
const instructions = asString(event.instructions);
if (instructions) {
attributes[GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE] = safeStringify([{ type: "text", content: instructions }]);
}
const messages = event.messages ?? event.prompt;
if (messages !== void 0) {
attributes[GEN_AI_INPUT_MESSAGES] = enableTruncation ? getTruncatedJsonString(messages) : safeStringify(messages);
attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE] = Array.isArray(messages) ? messages.length : 1;
}
return attributes;
}
function asString(value) {
return typeof value === "string" ? value : void 0;
}
function asNumber(value) {
return typeof value === "number" && !isNaN(value) ? value : void 0;
}
function sum(a, b) {
return a === void 0 && b === void 0 ? void 0 : (a ?? 0) + (b ?? 0);
}
function isRecord(value) {
return typeof value === "object" && value !== null;
}
function safeStringify(value) {
if (typeof value === "string") {
return value;
}
try {
return JSON.stringify(value);
} catch {
return "[unserializable]";
}
}
export { clearOperationId, createSpanFromMessage, enrichSpanOnEnd, subscribeVercelAiTracingChannel };
//# sourceMappingURL=vercel-ai-dc-subscriber.js.map
{"version":3,"file":"vercel-ai-dc-subscriber.js","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"sourcesContent":["/* eslint-disable max-lines */\n// `@sentry/conventions` marks several gen_ai attributes (e.g. `GEN_AI_SYSTEM`, `GEN_AI_TOOL_*`,\n// `GEN_AI_REQUEST_AVAILABLE_TOOLS`) as deprecated in favour of newer semconv names. We intentionally\n// keep emitting the current names so these spans match the OTel-based (v6) integration and what the\n// Sentry product consumes today; migrating to the new names is a separate, coordinated change.\n/* eslint-disable typescript-eslint/no-deprecated */\nimport {\n GEN_AI_EMBEDDINGS_INPUT,\n GEN_AI_FUNCTION_ID,\n GEN_AI_INPUT_MESSAGES,\n GEN_AI_OPERATION_NAME,\n GEN_AI_OUTPUT_MESSAGES,\n GEN_AI_REQUEST_AVAILABLE_TOOLS,\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_FINISH_REASONS,\n GEN_AI_RESPONSE_ID,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_RESPONSE_STREAMING,\n GEN_AI_SYSTEM,\n GEN_AI_TOOL_INPUT,\n GEN_AI_TOOL_NAME,\n GEN_AI_TOOL_OUTPUT,\n GEN_AI_TOOL_TYPE,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n GEN_AI_USAGE_TOTAL_TOKENS,\n} from '@sentry/conventions/attributes';\nimport { GEN_AI_EXECUTE_TOOL_SPAN_OP, GEN_AI_INVOKE_AGENT_SPAN_OP } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n getClient,\n getProviderMetadataAttributes,\n getTruncatedJsonString,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n SPAN_STATUS_ERROR,\n spanToJSON,\n spanToTraceContext,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport type { TracingChannel } from 'node:diagnostics_channel';\nimport { bindTracingChannelToSpan } from '../tracing-channel';\n\n/**\n * The single tracing channel the `ai` package (>= 7) publishes all telemetry lifecycle events to\n * via `node:diagnostics_channel`. Events are discriminated by their `type` field.\n * @see https://github.com/vercel/ai/pull/15660\n */\nconst AI_SDK_TELEMETRY_TRACING_CHANNEL = 'ai:telemetry';\n\nconst ORIGIN = 'auto.vercelai.channel';\n\n// `@sentry/conventions` does not expose these yet, so we keep the literals here.\nconst GEN_AI_TOOL_CALL_ID_ATTRIBUTE = 'gen_ai.tool.call.id';\nconst GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = 'gen_ai.tool.description';\nconst GEN_AI_EMBEDDINGS_OPERATION = 'embeddings';\nconst GEN_AI_RERANK_OPERATION = 'rerank';\n// The model-call op matches the Vercel AI OTel integration (`gen_ai.generate_content`) rather than\n// the generic `gen_ai.chat`, so v6 (OTel) and v7 (channel) produce the same spans.\nconst GEN_AI_GENERATE_CONTENT_OPERATION = 'generate_content';\n\n// Subset of the `vercel.ai.*` passthrough attributes the OTel integration emits that we reproduce.\nconst VERCEL_AI_OPERATION_ID_ATTRIBUTE = 'vercel.ai.operationId';\nconst VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE = 'vercel.ai.model.provider';\nconst VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE = 'vercel.ai.settings.maxRetries';\n\n// Tracks the top-level operationId (and whether it streams) per `callId` so a model-call span can\n// name its `doGenerate`/`doStream` operation the same way the OTel integration does. `isStream` is\n// the authoritative event-type signal rather than a substring check on the (possibly custom)\n// operationId. Cleared when the top-level span ends.\nconst operationIdByCallId = new Map<string, { operationId: string; isStream: boolean }>();\n\n// Per-operation map of tool name → description, harvested from a model-call /\n// top-level event's `tools` (keyed by the shared `callId`). The AI SDK's\n// `executeTool` event doesn't carry the tool's description, so we backfill it\n// onto the tool span here — without relying on the OTel `vercelAiEventProcessor`\n// (which isn't registered in channel/orchestrion mode). Cleared with the\n// operation. Only populated when inputs are recorded, matching the OTel path\n// (which sources descriptions from the recorded `available_tools`).\nconst toolDescriptionsByCallId = new Map<string, Map<string, string>>();\n\n// Only top-level operations own the `callId` → operationId mapping; `step`/`languageModelCall`/\n// `executeTool` share the parent's `callId`, so they must not clear it.\nconst ROOT_OPERATION_TYPES = new Set<ChannelEventType>(['generateText', 'streamText', 'embed', 'rerank']);\n\n/** Drop the per-operation `callId` maps once the owning top-level operation settles (success or error). */\nexport function clearOperationId(data: VercelAiChannelMessage): void {\n if (!ROOT_OPERATION_TYPES.has(data.type)) {\n return;\n }\n const callId = asString(data.event.callId);\n if (callId) {\n operationIdByCallId.delete(callId);\n toolDescriptionsByCallId.delete(callId);\n }\n}\n\n/** Record tool name → description from an event's `tools`, so tool spans can backfill the description. */\nfunction recordToolDescriptions(callId: string | undefined, tools: unknown): void {\n if (!callId || !Array.isArray(tools)) {\n return;\n }\n let descriptions = toolDescriptionsByCallId.get(callId);\n for (const tool of tools) {\n if (isRecord(tool) && typeof tool.name === 'string' && typeof tool.description === 'string') {\n descriptions = descriptions ?? new Map();\n if (!descriptions.has(tool.name)) {\n descriptions.set(tool.name, tool.description);\n }\n }\n }\n if (descriptions) {\n toolDescriptionsByCallId.set(callId, descriptions);\n }\n}\n\n/**\n * Resolve a tool's description, preferring the per-operation map (populated from the model-call /\n * top-level event's `tools`, v7) and falling back to a `tools` collection on the event itself —\n * which may be an array of `{ name, description }` or a record keyed by tool name (v6).\n */\nfunction resolveToolDescription(callId: string | undefined, toolName: string, tools: unknown): string | undefined {\n const fromMap = callId ? toolDescriptionsByCallId.get(callId)?.get(toolName) : undefined;\n if (fromMap) {\n return fromMap;\n }\n if (Array.isArray(tools)) {\n const match = tools.find(tool => isRecord(tool) && tool.name === toolName);\n return isRecord(match) ? asString(match.description) : undefined;\n }\n if (isRecord(tools)) {\n const tool = tools[toolName];\n return isRecord(tool) ? asString(tool.description) : undefined;\n }\n return undefined;\n}\n\n/** The lifecycle event types the `ai:telemetry` channel can carry. */\nexport type ChannelEventType =\n | 'generateText'\n | 'streamText'\n | 'step'\n | 'languageModelCall'\n | 'executeTool'\n | 'embed'\n | 'rerank';\n\n/**\n * The context object the AI SDK passes through one tracing-channel call. It is the same object\n * identity across `start`/`end`/`asyncEnd`/`error`, and Node's `tracingChannel` attaches\n * `result`/`error` to it as the traced promise settles.\n */\nexport interface VercelAiChannelMessage {\n type: ChannelEventType;\n event: Record<string, unknown>;\n result?: unknown;\n error?: unknown;\n}\n\n/**\n * Platform-provided factory that returns a tracing channel for the given channel name. The factory\n * is responsible for, when `start` fires, calling `transformStart(data)` and storing the returned\n * span on `data._sentrySpan` so the subscriber's `asyncEnd`/`error` handlers can read it.\n *\n * Node passes `@sentry/opentelemetry/tracing-channel`, which uses `bindStore` to additionally make\n * the span the active OTel context for the duration of the traced operation. That is what makes\n * nested AI SDK operations (model calls, tool calls) become children of the enclosing span without\n * any manual parent bookkeeping here.\n */\ntype VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;\n\n/** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */\ninterface VercelAiChannelOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n enableTruncation?: boolean;\n}\n\nlet subscribed = false;\n\n/**\n * Subscribe Sentry span handlers to the `ai` SDK's native telemetry tracing channel (`ai:telemetry`,\n * available in `ai` >= 7) and emit fully-formed `gen_ai.*` spans directly — no OpenTelemetry span\n * post-processing involved.\n *\n * The integration passes its options in directly (rather than us looking the integration up on every\n * event); the global `dataCollection.genAI` default is still read from the client per event.\n *\n * Safe to always call: on `ai` versions that don't publish to the channel (e.g. < 7) nothing is\n * ever emitted and this is inert, so there is no double-instrumentation against the OTel-based\n * patcher. Idempotent.\n */\nexport function subscribeVercelAiTracingChannel(\n tracingChannel: VercelAiTracingChannelFactory,\n options: VercelAiChannelOptions = {},\n): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n bindTracingChannelToSpan(\n tracingChannel<VercelAiChannelMessage>(AI_SDK_TELEMETRY_TRACING_CHANNEL),\n data => createSpanFromMessage(data, options),\n {\n // The helper ends the span; we enrich it from the settled result first (tokens, output messages,\n // finish reasons, response model/id, provider metadata) and drop the per-operation `callId` maps.\n beforeSpanEnd: (span, data) => {\n enrichSpanOnEnd(span, data, options);\n clearOperationId(data);\n },\n },\n );\n}\n\n/**\n * Transform a channel `start` payload into the span that should be active for the operation. For\n * `step` we deliberately don't open a span (model calls and tool calls are siblings under the\n * invoke_agent span, matching the OTel-based output), so we reuse the active span and mark the\n * payload to skip ending it.\n */\nexport function createSpanFromMessage(\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): Span | undefined {\n const { type, event } = data;\n\n if (type === 'step' || !event || typeof event !== 'object') {\n // Opt out: returning `undefined` leaves the enclosing `invoke_agent` span as the active context\n // (model-call and tool-call events nest under it) without opening — or ending — a span of its own.\n return undefined;\n }\n\n const { recordInputs, enableTruncation } = getRecordingOptions(event, channelOptions);\n const provider = asString(event.provider);\n const modelId = asString(event.modelId);\n const callId = asString(event.callId);\n const maxRetries = asNumber(event.maxRetries);\n\n // Harvest tool descriptions from the operation/model-call `tools` so tool spans can backfill them.\n // Gated on `recordInputs` to match the OTel path, which only records `available_tools` then.\n if (recordInputs) {\n recordToolDescriptions(callId, event.tools);\n }\n\n const baseAttributes: Record<string, string | number | boolean> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n ...(provider ? { [GEN_AI_SYSTEM]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {}),\n ...(modelId ? { [GEN_AI_REQUEST_MODEL]: modelId } : {}),\n ...(maxRetries !== undefined ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}),\n };\n\n switch (type) {\n case 'generateText':\n case 'streamText':\n return buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, type === 'streamText');\n case 'languageModelCall':\n return buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId);\n case 'executeTool':\n return buildToolSpan(event, recordInputs);\n case 'embed':\n return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, {\n ...baseAttributes,\n ...(recordInputs && event.value !== undefined ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(event.value) } : {}),\n });\n case 'rerank':\n return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes);\n default:\n // Unknown event type: opt out rather than open a span we can't shape correctly.\n return undefined;\n }\n}\n\ntype Attributes = Record<string, string | number | boolean>;\n\n/** Start a `gen_ai.<operation>` span named `<operation> <suffix>` (or just `<operation>` when no suffix). */\nfunction startGenAiSpan(operation: string, suffix: string | undefined, attributes: Attributes): Span {\n return startInactiveSpan({\n name: suffix ? `${operation} ${suffix}` : operation,\n op: `gen_ai.${operation}`,\n attributes: { [GEN_AI_OPERATION_NAME]: operation, ...attributes },\n });\n}\n\nfunction buildInvokeAgentSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n isStream: boolean,\n): Span {\n const functionId = asString(event.functionId);\n const operationId = asString(event.operationId) ?? (isStream ? 'ai.streamText' : 'ai.generateText');\n if (callId) {\n operationIdByCallId.set(callId, { operationId, isStream });\n }\n return startGenAiSpan(GEN_AI_INVOKE_AGENT_SPAN_OP, functionId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n [GEN_AI_RESPONSE_STREAMING]: isStream,\n ...(functionId ? { [GEN_AI_FUNCTION_ID]: functionId } : {}),\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n });\n}\n\nfunction buildModelCallSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n modelId: string | undefined,\n): Span {\n const parent = callId ? operationIdByCallId.get(callId) : undefined;\n const operationId = parent\n ? `${parent.operationId}.${parent.isStream ? 'doStream' : 'doGenerate'}`\n : 'ai.generateText.doGenerate';\n return startGenAiSpan(GEN_AI_GENERATE_CONTENT_OPERATION, modelId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n ...(recordInputs && Array.isArray(event.tools)\n ? { [GEN_AI_REQUEST_AVAILABLE_TOOLS]: safeStringify(event.tools) }\n : {}),\n });\n}\n\nfunction buildToolSpan(event: Record<string, unknown>, recordInputs: boolean): Span {\n const toolCall = isRecord(event.toolCall) ? event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(event.toolCallId) ?? asString(toolCall.toolCallId);\n const toolInput = toolCall.input ?? toolCall.args;\n // The `executeTool` event has no description; backfill it from the operation's recorded tools.\n // Gated on `recordInputs` to match the OTel path (descriptions come from the recorded tools list).\n const description =\n recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : undefined;\n return startGenAiSpan(GEN_AI_EXECUTE_TOOL_SPAN_OP, toolName, {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [GEN_AI_TOOL_TYPE]: 'function',\n ...(toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {}),\n ...(toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {}),\n ...(description ? { [GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE]: description } : {}),\n ...(recordInputs && toolInput !== undefined ? { [GEN_AI_TOOL_INPUT]: safeStringify(toolInput) } : {}),\n });\n}\n\n/**\n * Best-effort enrichment from the resolved value the AI SDK attaches to the channel context.\n * Everything here is guarded: when a field is missing or the shape differs across `ai` versions,\n * we simply don't set the attribute rather than emit a malformed span.\n */\nexport function enrichSpanOnEnd(\n span: Span,\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): void {\n const { type, result } = data;\n if (!isRecord(result)) {\n return;\n }\n\n const { recordOutputs } = getRecordingOptions(data.event, channelOptions);\n\n if (type === 'executeTool') {\n if (recordOutputs) {\n span.setAttribute(GEN_AI_TOOL_OUTPUT, safeStringify(result.output ?? result));\n }\n // From V5 on, tool errors are not rejected (so the `error` channel verb never fires) — they\n // surface as `tool-error` content on the resolved result. Mirror the OTel path by marking the\n // span and capturing the error.\n const output = isRecord(result.output) ? result.output : undefined;\n if (output?.type === 'tool-error') {\n captureToolError(span, data, output.error);\n }\n return;\n }\n\n // `languageModelCall` results report usage as `{ total }` objects; top-level/step results report\n // flat numbers. `tokenCount` handles both.\n const usage = isRecord(result.usage) ? result.usage : undefined;\n if (usage) {\n const inputTokens = tokenCount(usage.inputTokens) ?? tokenCount(usage.tokens);\n const outputTokens = tokenCount(usage.outputTokens);\n const totalTokens = tokenCount(usage.totalTokens) ?? sum(inputTokens, outputTokens);\n if (inputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, inputTokens);\n }\n if (outputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);\n }\n if (totalTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);\n }\n }\n\n // Match the OTel integration: finish reasons live on the model-call (`generate_content`) span, not\n // on the top-level `invoke_agent` span.\n const finishReason = getFinishReason(result);\n if (finishReason && type === 'languageModelCall') {\n span.setAttribute(GEN_AI_RESPONSE_FINISH_REASONS, safeStringify([finishReason]));\n }\n\n const response = isRecord(result.response) ? result.response : undefined;\n const responseId = asString(response?.id) ?? asString(result.responseId);\n if (responseId) {\n span.setAttribute(GEN_AI_RESPONSE_ID, responseId);\n }\n const responseModel = asString(response?.modelId) ?? asString(data.event.modelId);\n if (responseModel) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL, responseModel);\n }\n\n // Provider-specific cache/reasoning/prediction token breakdowns and `gen_ai.conversation.id`.\n // The channel exposes `providerMetadata` as an object (the OTel path parses it from a string);\n // both share `getProviderMetadataAttributes` so the emitted shape is identical.\n const providerMetadata = (result as { providerMetadata?: unknown }).providerMetadata;\n const providerAttributes = getProviderMetadataAttributes(providerMetadata);\n // Don't overwrite a conversation id already set on span start (e.g. by `conversationIdIntegration`\n // from a user-set scope value); the provider-derived id is only a fallback. Matches the OTel path.\n if (\n GEN_AI_CONVERSATION_ID_ATTRIBUTE in providerAttributes &&\n spanToJSON(span).data[GEN_AI_CONVERSATION_ID_ATTRIBUTE]\n ) {\n // oxlint-disable-next-line typescript/no-dynamic-delete\n delete providerAttributes[GEN_AI_CONVERSATION_ID_ATTRIBUTE];\n }\n span.setAttributes(providerAttributes);\n\n if (recordOutputs) {\n // `languageModelCall` exposes the response as a `content` parts array; top-level results expose\n // `text` + `toolCalls`. Both normalize into the OTel `gen_ai.output.messages` assistant message.\n const parts =\n type === 'languageModelCall' && Array.isArray(result.content)\n ? partsFromContent(result.content)\n : partsFromTextAndToolCalls(result.text, result.toolCalls);\n const outputMessages = buildOutputMessages(parts, finishReason);\n if (outputMessages) {\n span.setAttribute(GEN_AI_OUTPUT_MESSAGES, outputMessages);\n }\n }\n}\n\n/** Maps a Vercel AI finish reason to the OTel `gen_ai.output.messages` form (`tool-calls` → `tool_call`). */\nfunction normalizeFinishReason(finishReason: string | undefined): string {\n return finishReason === 'tool-calls' ? 'tool_call' : (finishReason ?? 'stop');\n}\n\n/** Reads the finish reason from a result — a string on top-level results, `{ unified }` on model calls. */\nfunction getFinishReason(result: Record<string, unknown>): string | undefined {\n const finishReason = result.finishReason;\n if (typeof finishReason === 'string') {\n return finishReason;\n }\n return isRecord(finishReason) ? asString(finishReason.unified) : undefined;\n}\n\n/** Reads a token count that may be a plain number or a `{ total }` object (model-call usage). */\nfunction tokenCount(value: unknown): number | undefined {\n return asNumber(value) ?? (isRecord(value) ? asNumber(value.total) : undefined);\n}\n\nfunction buildOutputMessages(\n parts: Array<Record<string, unknown>>,\n finishReason: string | undefined,\n): string | undefined {\n if (!parts.length) {\n return undefined;\n }\n return safeStringify([{ role: 'assistant', parts, finish_reason: normalizeFinishReason(finishReason) }]);\n}\n\nfunction toolCallPart(toolCall: Record<string, unknown>): Record<string, unknown> {\n const args = toolCall.input ?? toolCall.args;\n return {\n type: 'tool_call',\n id: asString(toolCall.toolCallId),\n name: asString(toolCall.toolName),\n arguments: typeof args === 'string' ? args : safeStringify(args ?? {}),\n };\n}\n\nfunction partsFromContent(content: unknown[]): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n for (const item of content) {\n if (!isRecord(item)) {\n continue;\n }\n if (item.type === 'text' && typeof item.text === 'string') {\n parts.push({ type: 'text', content: item.text });\n } else if (item.type === 'tool-call') {\n parts.push(toolCallPart(item));\n }\n }\n return parts;\n}\n\nfunction partsFromTextAndToolCalls(text: unknown, toolCalls: unknown): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n if (typeof text === 'string' && text.length) {\n parts.push({ type: 'text', content: text });\n }\n if (Array.isArray(toolCalls)) {\n for (const toolCall of toolCalls) {\n if (isRecord(toolCall)) {\n parts.push(toolCallPart(toolCall));\n }\n }\n }\n return parts;\n}\n\nfunction captureToolError(span: Span, data: VercelAiChannelMessage, error: unknown): void {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error instanceof Error ? error.message : 'tool_error',\n });\n\n const toolCall = isRecord(data.event.toolCall) ? data.event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(data.event.toolCallId) ?? asString(toolCall.toolCallId);\n\n withScope(scope => {\n scope.setContext('trace', spanToTraceContext(span));\n if (toolName) {\n scope.setTag('vercel.ai.tool.name', toolName);\n }\n if (toolCallId) {\n scope.setTag('vercel.ai.tool.callId', toolCallId);\n }\n scope.setLevel('error');\n captureException(\n error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Tool execution failed'),\n {\n mechanism: { type: 'auto.vercelai.channel', handled: false },\n },\n );\n });\n}\n\nfunction getRecordingOptions(\n event: Record<string, unknown>,\n channelOptions: VercelAiChannelOptions,\n): {\n recordInputs: boolean;\n recordOutputs: boolean;\n enableTruncation: boolean;\n} {\n const genAI = getClient()?.getDataCollectionOptions().genAI;\n\n return {\n recordInputs: resolveRecording(channelOptions.recordInputs, event.recordInputs, genAI?.inputs),\n recordOutputs: resolveRecording(channelOptions.recordOutputs, event.recordOutputs, genAI?.outputs),\n enableTruncation: shouldEnableTruncation(channelOptions.enableTruncation),\n };\n}\n\n/**\n * Mirrors the OTel integration's `determineRecordingSettings` precedence: an integration-level option\n * wins, then the per-call `experimental_telemetry.recordInputs/recordOutputs` flag the AI SDK forwards\n * on the channel event, then the global `dataCollection.genAI` default.\n *\n * NOTE: the OTel integration also defaults recording to `true` for a call with\n * `experimental_telemetry: { isEnabled: true }`. The `ai:telemetry` channel does not expose `isEnabled`\n * (nor a resolved recording flag), so that per-call default cannot be reproduced here — v7 users who\n * want inputs/outputs recorded must enable `dataCollection.genAI` or set `recordInputs`/`recordOutputs`.\n */\nfunction resolveRecording(integrationOption: unknown, perCallOption: unknown, globalDefault: unknown): boolean {\n if (typeof integrationOption === 'boolean') {\n return integrationOption;\n }\n if (typeof perCallOption === 'boolean') {\n return perCallOption;\n }\n return globalDefault === true;\n}\n\nfunction buildInputMessageAttributes(\n event: Record<string, unknown>,\n enableTruncation: boolean,\n): Record<string, string | number> {\n const attributes: Record<string, string | number> = {};\n\n // `ai` >= 7 forbids system messages in `messages`/`prompt` and exposes the system prompt as a\n // separate `instructions` field. The OTel path lifts the system message out of the prompt into\n // `gen_ai.system_instructions` as `[{ type: 'text', content }]`; mirror that shape here.\n const instructions = asString(event.instructions);\n if (instructions) {\n attributes[GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE] = safeStringify([{ type: 'text', content: instructions }]);\n }\n\n // The AI SDK start events extend `StandardizedPrompt`; messages live on `messages`, otherwise the\n // simpler `prompt` field is used.\n const messages = event.messages ?? event.prompt;\n if (messages !== undefined) {\n attributes[GEN_AI_INPUT_MESSAGES] = enableTruncation ? getTruncatedJsonString(messages) : safeStringify(messages);\n // The original (pre-truncation) message count, so the product can show how many were dropped.\n attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE] = Array.isArray(messages) ? messages.length : 1;\n }\n\n return attributes;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && !isNaN(value) ? value : undefined;\n}\n\nfunction sum(a: number | undefined, b: number | undefined): number | undefined {\n return a === undefined && b === undefined ? undefined : (a ?? 0) + (b ?? 0);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '[unserializable]';\n }\n}\n"],"names":[],"mappings":"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"}
type VercelAiOptions = {
/**
* Enable or disable input recording. Enabled if `dataCollection.genAI.inputs` (or the deprecated `sendDefaultPii` option) is `true`
* or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.
* Integration-level options take precedence over global `dataCollection` config.
*/
recordInputs?: boolean;
/**
* Enable or disable output recording. Enabled if `dataCollection.genAI.outputs` (or the deprecated `sendDefaultPii` option) is `true`
* or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.
* Integration-level options take precedence over global `dataCollection` config.
*/
recordOutputs?: boolean;
/**
* Enable or disable truncation of recorded input messages.
* Defaults to `true`.
*/
enableTruncation?: boolean;
};
/**
* Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7).
*/
export declare const vercelAiIntegration: (options?: VercelAiOptions | undefined) => import("@sentry/core").Integration;
export {};
//# sourceMappingURL=index.d.ts.map
import { Span } from '@sentry/core';
import { TracingChannel } from 'node:diagnostics_channel';
/** Drop the per-operation `callId` maps once the owning top-level operation settles (success or error). */
export declare function clearOperationId(data: VercelAiChannelMessage): void;
/** The lifecycle event types the `ai:telemetry` channel can carry. */
export type ChannelEventType = 'generateText' | 'streamText' | 'step' | 'languageModelCall' | 'executeTool' | 'embed' | 'rerank';
/**
* The context object the AI SDK passes through one tracing-channel call. It is the same object
* identity across `start`/`end`/`asyncEnd`/`error`, and Node's `tracingChannel` attaches
* `result`/`error` to it as the traced promise settles.
*/
export interface VercelAiChannelMessage {
type: ChannelEventType;
event: Record<string, unknown>;
result?: unknown;
error?: unknown;
}
/**
* Platform-provided factory that returns a tracing channel for the given channel name. The factory
* is responsible for, when `start` fires, calling `transformStart(data)` and storing the returned
* span on `data._sentrySpan` so the subscriber's `asyncEnd`/`error` handlers can read it.
*
* Node passes `@sentry/opentelemetry/tracing-channel`, which uses `bindStore` to additionally make
* the span the active OTel context for the duration of the traced operation. That is what makes
* nested AI SDK operations (model calls, tool calls) become children of the enclosing span without
* any manual parent bookkeeping here.
*/
type VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;
/** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */
interface VercelAiChannelOptions {
recordInputs?: boolean;
recordOutputs?: boolean;
enableTruncation?: boolean;
}
/**
* Subscribe Sentry span handlers to the `ai` SDK's native telemetry tracing channel (`ai:telemetry`,
* available in `ai` >= 7) and emit fully-formed `gen_ai.*` spans directly — no OpenTelemetry span
* post-processing involved.
*
* The integration passes its options in directly (rather than us looking the integration up on every
* event); the global `dataCollection.genAI` default is still read from the client per event.
*
* Safe to always call: on `ai` versions that don't publish to the channel (e.g. < 7) nothing is
* ever emitted and this is inert, so there is no double-instrumentation against the OTel-based
* patcher. Idempotent.
*/
export declare function subscribeVercelAiTracingChannel(tracingChannel: VercelAiTracingChannelFactory, options?: VercelAiChannelOptions): void;
/**
* Transform a channel `start` payload into the span that should be active for the operation. For
* `step` we deliberately don't open a span (model calls and tool calls are siblings under the
* invoke_agent span, matching the OTel-based output), so we reuse the active span and mark the
* payload to skip ending it.
*/
export declare function createSpanFromMessage(data: VercelAiChannelMessage, channelOptions: VercelAiChannelOptions): Span | undefined;
/**
* Best-effort enrichment from the resolved value the AI SDK attaches to the channel context.
* Everything here is guarded: when a field is missing or the shape differs across `ai` versions,
* we simply don't set the attribute rather than emit a malformed span.
*/
export declare function enrichSpanOnEnd(span: Span, data: VercelAiChannelMessage, channelOptions: VercelAiChannelOptions): void;
export {};
//# sourceMappingURL=vercel-ai-dc-subscriber.d.ts.map
type VercelAiOptions = {
/**
* Enable or disable input recording. Enabled if `dataCollection.genAI.inputs` (or the deprecated `sendDefaultPii` option) is `true`
* or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.
* Integration-level options take precedence over global `dataCollection` config.
*/
recordInputs?: boolean;
/**
* Enable or disable output recording. Enabled if `dataCollection.genAI.outputs` (or the deprecated `sendDefaultPii` option) is `true`
* or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.
* Integration-level options take precedence over global `dataCollection` config.
*/
recordOutputs?: boolean;
/**
* Enable or disable truncation of recorded input messages.
* Defaults to `true`.
*/
enableTruncation?: boolean;
};
/**
* Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7).
*/
export declare const vercelAiIntegration: (options?: VercelAiOptions | undefined) => import("@sentry/core").Integration;
export {};
//# sourceMappingURL=index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vercel-ai/index.ts"],"names":[],"mappings":"AAIA,KAAK,eAAe,GAAG;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAoBF;;GAEG;AACH,eAAO,MAAM,mBAAmB,+EAA0C,CAAC"}
import type { Span } from '@sentry/core';
import type { TracingChannel } from 'node:diagnostics_channel';
/** Drop the per-operation `callId` maps once the owning top-level operation settles (success or error). */
export declare function clearOperationId(data: VercelAiChannelMessage): void;
/** The lifecycle event types the `ai:telemetry` channel can carry. */
export type ChannelEventType = 'generateText' | 'streamText' | 'step' | 'languageModelCall' | 'executeTool' | 'embed' | 'rerank';
/**
* The context object the AI SDK passes through one tracing-channel call. It is the same object
* identity across `start`/`end`/`asyncEnd`/`error`, and Node's `tracingChannel` attaches
* `result`/`error` to it as the traced promise settles.
*/
export interface VercelAiChannelMessage {
type: ChannelEventType;
event: Record<string, unknown>;
result?: unknown;
error?: unknown;
}
/**
* Platform-provided factory that returns a tracing channel for the given channel name. The factory
* is responsible for, when `start` fires, calling `transformStart(data)` and storing the returned
* span on `data._sentrySpan` so the subscriber's `asyncEnd`/`error` handlers can read it.
*
* Node passes `@sentry/opentelemetry/tracing-channel`, which uses `bindStore` to additionally make
* the span the active OTel context for the duration of the traced operation. That is what makes
* nested AI SDK operations (model calls, tool calls) become children of the enclosing span without
* any manual parent bookkeeping here.
*/
type VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;
/** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */
interface VercelAiChannelOptions {
recordInputs?: boolean;
recordOutputs?: boolean;
enableTruncation?: boolean;
}
/**
* Subscribe Sentry span handlers to the `ai` SDK's native telemetry tracing channel (`ai:telemetry`,
* available in `ai` >= 7) and emit fully-formed `gen_ai.*` spans directly — no OpenTelemetry span
* post-processing involved.
*
* The integration passes its options in directly (rather than us looking the integration up on every
* event); the global `dataCollection.genAI` default is still read from the client per event.
*
* Safe to always call: on `ai` versions that don't publish to the channel (e.g. < 7) nothing is
* ever emitted and this is inert, so there is no double-instrumentation against the OTel-based
* patcher. Idempotent.
*/
export declare function subscribeVercelAiTracingChannel(tracingChannel: VercelAiTracingChannelFactory, options?: VercelAiChannelOptions): void;
/**
* Transform a channel `start` payload into the span that should be active for the operation. For
* `step` we deliberately don't open a span (model calls and tool calls are siblings under the
* invoke_agent span, matching the OTel-based output), so we reuse the active span and mark the
* payload to skip ending it.
*/
export declare function createSpanFromMessage(data: VercelAiChannelMessage, channelOptions: VercelAiChannelOptions): Span | undefined;
/**
* Best-effort enrichment from the resolved value the AI SDK attaches to the channel context.
* Everything here is guarded: when a field is missing or the shape differs across `ai` versions,
* we simply don't set the attribute rather than emit a malformed span.
*/
export declare function enrichSpanOnEnd(span: Span, data: VercelAiChannelMessage, channelOptions: VercelAiChannelOptions): void;
export {};
//# sourceMappingURL=vercel-ai-dc-subscriber.d.ts.map
{"version":3,"file":"vercel-ai-dc-subscriber.d.ts","sourceRoot":"","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAiBzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AA6C/D,2GAA2G;AAC3G,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI,CASnE;AA0CD,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,YAAY,GACZ,MAAM,GACN,mBAAmB,GACnB,aAAa,GACb,OAAO,GACP,QAAQ,CAAC;AAEb;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,KAAK,6BAA6B,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE9F,mHAAmH;AACnH,UAAU,sBAAsB;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAC7C,cAAc,EAAE,6BAA6B,EAC7C,OAAO,GAAE,sBAA2B,GACnC,IAAI,CAkBN;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,sBAAsB,EAC5B,cAAc,EAAE,sBAAsB,GACrC,IAAI,GAAG,SAAS,CA+ClB;AA4ED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,sBAAsB,EAC5B,cAAc,EAAE,sBAAsB,GACrC,IAAI,CAqFN"}
+2
-0

@@ -5,2 +5,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

const tracingChannel = require('./tracing-channel.js');
const index = require('./vercel-ai/index.js');

@@ -16,2 +17,3 @@

exports.bindTracingChannelToSpan = tracingChannel.bindTracingChannelToSpan;
exports.vercelAiIntegration = index.vercelAiIntegration;
//# sourceMappingURL=index.js.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const diagnosticsChannel = require('node:diagnostics_channel');
const dc = require('node:diagnostics_channel');
const core = require('@sentry/core');

@@ -21,3 +21,3 @@ const debugBuild = require('../../debug-build.js');

debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion:mysql] subscribing to channel "${channels.CHANNELS.MYSQL_QUERY}"`);
const queryCh = diagnosticsChannel.tracingChannel(channels.CHANNELS.MYSQL_QUERY);
const queryCh = dc.tracingChannel(channels.CHANNELS.MYSQL_QUERY);
const spans = /* @__PURE__ */ new WeakMap();

@@ -24,0 +24,0 @@ const parentScopes = /* @__PURE__ */ new WeakMap();

@@ -1,1 +0,1 @@

{"version":3,"file":"mysql.js","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope, Span } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, OTel 'Mysql' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Mysql';\n\n// OpenTelemetry \"OLD\" db/net semantic-conventions. We inline them rather than\n// importing `@opentelemetry/semantic-conventions` to keep this integration's\n// dependency surface free of OTel — orchestrion's whole point is to step away\n// from the OTel auto-instrumentation stack.\n//\n// We emit the OLD conventions to match `@opentelemetry/instrumentation-mysql`'s\n// default (it only emits the stable `db.system.name` / `db.query.text` set when\n// `OTEL_SEMCONV_STABILITY_OPT_IN=database` is opted into) and the rest of the\n// Sentry JS SDK, whose `inferDbSpanData` processor renames spans based on\n// `db.statement`.\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\n\n/**\n * The shape orchestrion's wrapCallback transform attaches to the tracing-channel\n * `context` object. Documented here rather than imported because orchestrion's\n * runtime doesn't export it — see `node_modules/@apm-js-collab/code-transformer/lib/transforms.js`.\n *\n * `arguments` is the *live* args array passed to the wrapped function: orchestrion\n * splices the user's callback out and inserts its own wrapper at the same index\n * before publishing `start`. The `start` hook re-wraps that entry to restore the\n * caller's scope across mysql's async callback dispatch (see below).\n */\ninterface MysqlQueryChannelContext {\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\n}\n\ninterface MysqlConnectionConfig {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n // Pool connections nest the real config one level deeper.\n connectionConfig?: MysqlConnectionConfig;\n}\n\ninterface MysqlConnection {\n config?: MysqlConnectionConfig;\n}\n\nconst _mysqlChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n const queryCh = diagnosticsChannel.tracingChannel(CHANNELS.MYSQL_QUERY);\n\n // Orchestrion creates one `context` object per call, shared across all\n // lifecycle hooks. We key both maps off that identity; `WeakMap` so an\n // unfinished path can't leak its entries.\n const spans = new WeakMap<object, Span>();\n // The scope active when the query was issued, consumed in `end` to bind\n // the streamed `Query` emitter's listeners to it.\n const parentScopes = new WeakMap<object, Scope>();\n\n // `subscribe()` requires all five lifecycle hooks. The orchestrion\n // `wrapAuto` transform fires events in one of four orders depending on\n // call shape:\n // - sync throw : start → error → end\n // (NO asyncEnd)\n // - async-callback error : start → end → error →\n // asyncStart → asyncEnd\n // - async-callback success : start → end → asyncStart →\n // asyncEnd\n // - no-callback (streamable Query) : start → end\n // (ctx.result is the Query\n // emitter, no async events)\n //\n // Where the span closes depends on the path: `asyncEnd` for callbacks (so\n // it spans the full round-trip + callback), or `end` for the sync-throw\n // and streamable paths. The `end` hook tells those apart via `ctx.error`\n // / `ctx.result` — see there.\n queryCh.subscribe({\n start(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const sql = extractSql(ctx.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(ctx.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n const span = startInactiveSpan({\n name: sql ?? 'mysql.query',\n op: 'db',\n attributes: {\n [ATTR_DB_SYSTEM]: 'mysql',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.orchestrion.mysql',\n [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database),\n ...(database ? { [ATTR_DB_NAME]: database } : {}),\n ...(user ? { [ATTR_DB_USER]: user } : {}),\n ...(sql ? { [ATTR_DB_STATEMENT]: sql } : {}),\n ...(host ? { [ATTR_NET_PEER_NAME]: host } : {}),\n ...(portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {}),\n },\n });\n spans.set(rawCtx, span);\n\n // Capture the scope while we're still synchronously inside the\n // caller's `connection.query` call. mysql v2 drains callbacks and\n // emits streamed-query events from its socket data handler, where the\n // AsyncLocalStorage store backing the active span no longer reflects\n // the caller's context — and `asyncStart`/`asyncEnd` fire from that\n // same lost context, so capturing has to happen now.\n const scope = getCurrentScope();\n parentScopes.set(rawCtx, scope);\n\n // Callback path: orchestrion has spliced the user's callback out of\n // `ctx.arguments` and put its own wrapper (`__apm$wrappedCb`) at the\n // same index. Re-wrap it so the callback — and any nested\n // `connection.query(...)` — runs with the captured scope active.\n if (ctx.arguments.length > 0) {\n const cbIdx = ctx.arguments.length - 1;\n const orchestrionWrappedCb = ctx.arguments[cbIdx];\n if (typeof orchestrionWrappedCb === 'function') {\n const wrapped = orchestrionWrappedCb as (...a: unknown[]) => unknown;\n ctx.arguments[cbIdx] = function (this: unknown, ...args: unknown[]): unknown {\n return withScope(scope, () => wrapped.apply(this, args));\n };\n }\n }\n },\n\n end(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n\n // Sync throw: `end` fires AFTER `error` (both inside the wrapper's\n // `try/catch/finally`), so `ctx.error` is already set. Close the\n // span now since no `asyncEnd` will fire.\n if (ctx.error !== undefined) {\n finishSpan(rawCtx);\n return;\n }\n\n // No-callback (streamable Query) path: orchestrion's `wrapPromise`\n // stores the synchronous return value on `ctx.result` and never\n // fires `asyncStart`/`asyncEnd`. The returned `Query` is an\n // `EventEmitter` that emits `'end'` on success and `'error'` on\n // failure — hook those to close the span.\n // Note: a streamed span never finishes if the connection is destroyed\n // mid-flight — mysql then emits neither `'end'` nor `'error'`, so the\n // span is dropped (the `WeakMap` still prevents a leak). Closing this\n // needs connection-level hooks the per-query context doesn't expose.\n const result = ctx.result;\n if (result && typeof result === 'object' && hasOnMethod(result)) {\n const span = spans.get(rawCtx);\n if (!span) return;\n\n // Bind the captured scope to the streamed `Query` emitter: its\n // `'end'`/`'error'`/`'fields'`/… events fire from mysql's socket\n // handler with the caller's context lost, so without this a span\n // started in a user's stream listener would begin a fresh root trace\n // instead of nesting under the parent. `bindScopeToEmitter` patches\n // `on`/`addListener`/… so listeners added after `query()` returns\n // inherit the scope (like OTel's `context.bind`).\n const parentScope = parentScopes.get(rawCtx);\n if (parentScope) {\n bindScopeToEmitter(result, parentScope);\n }\n\n result.on('error', err => {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: err instanceof Error ? err.message : 'unknown_error',\n });\n // Defensive: end the span here too in case `'end'` never fires\n // (e.g. abrupt socket destruction). `finishSpan` is idempotent —\n // `spans.delete` makes the subsequent `'end'` listener a no-op.\n finishSpan(rawCtx);\n });\n result.on('end', () => finishSpan(rawCtx));\n return;\n }\n\n // Callback path: `asyncEnd` will close the span. Nothing to do here.\n },\n\n error(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const span = spans.get(rawCtx);\n if (!span) return;\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: ctx.error instanceof Error ? ctx.error.message : 'unknown_error',\n });\n },\n\n asyncStart() {\n // No-op: we end on `asyncEnd` so the span covers the full callback duration.\n },\n\n asyncEnd(rawCtx) {\n finishSpan(rawCtx);\n },\n });\n\n function finishSpan(rawCtx: object): void {\n const span = spans.get(rawCtx);\n if (!span) return;\n span.end();\n spans.delete(rawCtx);\n parentScopes.delete(rawCtx);\n }\n },\n };\n}) satisfies IntegrationFn;\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\nfunction extractSql(firstArg: unknown): string | undefined {\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n if (firstArg && typeof firstArg === 'object' && 'sql' in firstArg) {\n const sql = (firstArg as { sql?: unknown }).sql;\n return typeof sql === 'string' ? sql : undefined;\n }\n return undefined;\n}\n\nfunction getConnectionConfig(connection: MysqlConnection | undefined): {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n} {\n // Pool connections nest the real config under `.connectionConfig`; single\n // connections expose it directly. Matches `@opentelemetry/instrumentation-mysql`.\n const config = connection?.config?.connectionConfig ?? connection?.config ?? {};\n return {\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n };\n}\n\nfunction getJDBCString(host: string | undefined, port: number | undefined, database: string | undefined): string {\n let s = `jdbc:mysql://${host || 'localhost'}`;\n if (typeof port === 'number') {\n s += `:${port}`;\n }\n if (database) {\n s += `/${database}`;\n }\n return s;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven mysql integration.\n *\n * Subscribes to the `orchestrion:mysql:query` diagnostics_channel that the\n * orchestrion code transform injects into `mysql/lib/Connection.js`'s\n * `Connection.prototype.query`. Requires the orchestrion runtime hook or\n * bundler plugin to be active — wire that up via `_experimentalSetupOrchestrion`.\n */\nexport const mysqlChannelIntegration = defineIntegration(_mysqlChannelIntegration);\n"],"names":["DEBUG_BUILD","debug","CHANNELS","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","getCurrentScope","withScope","bindScopeToEmitter","SPAN_STATUS_ERROR","defineIntegration"],"mappings":"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"}
{"version":3,"file":"mysql.js","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope, Span } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, OTel 'Mysql' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Mysql';\n\n// OpenTelemetry \"OLD\" db/net semantic-conventions. We inline them rather than\n// importing `@opentelemetry/semantic-conventions` to keep this integration's\n// dependency surface free of OTel — orchestrion's whole point is to step away\n// from the OTel auto-instrumentation stack.\n//\n// We emit the OLD conventions to match `@opentelemetry/instrumentation-mysql`'s\n// default (it only emits the stable `db.system.name` / `db.query.text` set when\n// `OTEL_SEMCONV_STABILITY_OPT_IN=database` is opted into) and the rest of the\n// Sentry JS SDK, whose `inferDbSpanData` processor renames spans based on\n// `db.statement`.\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\n\n/**\n * The shape orchestrion's wrapCallback transform attaches to the tracing-channel\n * `context` object. Documented here rather than imported because orchestrion's\n * runtime doesn't export it — see `node_modules/@apm-js-collab/code-transformer/lib/transforms.js`.\n *\n * `arguments` is the *live* args array passed to the wrapped function: orchestrion\n * splices the user's callback out and inserts its own wrapper at the same index\n * before publishing `start`. The `start` hook re-wraps that entry to restore the\n * caller's scope across mysql's async callback dispatch (see below).\n */\ninterface MysqlQueryChannelContext {\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\n}\n\ninterface MysqlConnectionConfig {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n // Pool connections nest the real config one level deeper.\n connectionConfig?: MysqlConnectionConfig;\n}\n\ninterface MysqlConnection {\n config?: MysqlConnectionConfig;\n}\n\nconst _mysqlChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n const queryCh = diagnosticsChannel.tracingChannel(CHANNELS.MYSQL_QUERY);\n\n // Orchestrion creates one `context` object per call, shared across all\n // lifecycle hooks. We key both maps off that identity; `WeakMap` so an\n // unfinished path can't leak its entries.\n const spans = new WeakMap<object, Span>();\n // The scope active when the query was issued, consumed in `end` to bind\n // the streamed `Query` emitter's listeners to it.\n const parentScopes = new WeakMap<object, Scope>();\n\n // `subscribe()` requires all five lifecycle hooks. The orchestrion\n // `wrapAuto` transform fires events in one of four orders depending on\n // call shape:\n // - sync throw : start → error → end\n // (NO asyncEnd)\n // - async-callback error : start → end → error →\n // asyncStart → asyncEnd\n // - async-callback success : start → end → asyncStart →\n // asyncEnd\n // - no-callback (streamable Query) : start → end\n // (ctx.result is the Query\n // emitter, no async events)\n //\n // Where the span closes depends on the path: `asyncEnd` for callbacks (so\n // it spans the full round-trip + callback), or `end` for the sync-throw\n // and streamable paths. The `end` hook tells those apart via `ctx.error`\n // / `ctx.result` — see there.\n queryCh.subscribe({\n start(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const sql = extractSql(ctx.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(ctx.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n const span = startInactiveSpan({\n name: sql ?? 'mysql.query',\n op: 'db',\n attributes: {\n [ATTR_DB_SYSTEM]: 'mysql',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.orchestrion.mysql',\n [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database),\n ...(database ? { [ATTR_DB_NAME]: database } : {}),\n ...(user ? { [ATTR_DB_USER]: user } : {}),\n ...(sql ? { [ATTR_DB_STATEMENT]: sql } : {}),\n ...(host ? { [ATTR_NET_PEER_NAME]: host } : {}),\n ...(portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {}),\n },\n });\n spans.set(rawCtx, span);\n\n // Capture the scope while we're still synchronously inside the\n // caller's `connection.query` call. mysql v2 drains callbacks and\n // emits streamed-query events from its socket data handler, where the\n // AsyncLocalStorage store backing the active span no longer reflects\n // the caller's context — and `asyncStart`/`asyncEnd` fire from that\n // same lost context, so capturing has to happen now.\n const scope = getCurrentScope();\n parentScopes.set(rawCtx, scope);\n\n // Callback path: orchestrion has spliced the user's callback out of\n // `ctx.arguments` and put its own wrapper (`__apm$wrappedCb`) at the\n // same index. Re-wrap it so the callback — and any nested\n // `connection.query(...)` — runs with the captured scope active.\n if (ctx.arguments.length > 0) {\n const cbIdx = ctx.arguments.length - 1;\n const orchestrionWrappedCb = ctx.arguments[cbIdx];\n if (typeof orchestrionWrappedCb === 'function') {\n const wrapped = orchestrionWrappedCb as (...a: unknown[]) => unknown;\n ctx.arguments[cbIdx] = function (this: unknown, ...args: unknown[]): unknown {\n return withScope(scope, () => wrapped.apply(this, args));\n };\n }\n }\n },\n\n end(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n\n // Sync throw: `end` fires AFTER `error` (both inside the wrapper's\n // `try/catch/finally`), so `ctx.error` is already set. Close the\n // span now since no `asyncEnd` will fire.\n if (ctx.error !== undefined) {\n finishSpan(rawCtx);\n return;\n }\n\n // No-callback (streamable Query) path: orchestrion's `wrapPromise`\n // stores the synchronous return value on `ctx.result` and never\n // fires `asyncStart`/`asyncEnd`. The returned `Query` is an\n // `EventEmitter` that emits `'end'` on success and `'error'` on\n // failure — hook those to close the span.\n // Note: a streamed span never finishes if the connection is destroyed\n // mid-flight — mysql then emits neither `'end'` nor `'error'`, so the\n // span is dropped (the `WeakMap` still prevents a leak). Closing this\n // needs connection-level hooks the per-query context doesn't expose.\n const result = ctx.result;\n if (result && typeof result === 'object' && hasOnMethod(result)) {\n const span = spans.get(rawCtx);\n if (!span) return;\n\n // Bind the captured scope to the streamed `Query` emitter: its\n // `'end'`/`'error'`/`'fields'`/… events fire from mysql's socket\n // handler with the caller's context lost, so without this a span\n // started in a user's stream listener would begin a fresh root trace\n // instead of nesting under the parent. `bindScopeToEmitter` patches\n // `on`/`addListener`/… so listeners added after `query()` returns\n // inherit the scope (like OTel's `context.bind`).\n const parentScope = parentScopes.get(rawCtx);\n if (parentScope) {\n bindScopeToEmitter(result, parentScope);\n }\n\n result.on('error', err => {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: err instanceof Error ? err.message : 'unknown_error',\n });\n // Defensive: end the span here too in case `'end'` never fires\n // (e.g. abrupt socket destruction). `finishSpan` is idempotent —\n // `spans.delete` makes the subsequent `'end'` listener a no-op.\n finishSpan(rawCtx);\n });\n result.on('end', () => finishSpan(rawCtx));\n return;\n }\n\n // Callback path: `asyncEnd` will close the span. Nothing to do here.\n },\n\n error(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const span = spans.get(rawCtx);\n if (!span) return;\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: ctx.error instanceof Error ? ctx.error.message : 'unknown_error',\n });\n },\n\n asyncStart() {\n // No-op: we end on `asyncEnd` so the span covers the full callback duration.\n },\n\n asyncEnd(rawCtx) {\n finishSpan(rawCtx);\n },\n });\n\n function finishSpan(rawCtx: object): void {\n const span = spans.get(rawCtx);\n if (!span) return;\n span.end();\n spans.delete(rawCtx);\n parentScopes.delete(rawCtx);\n }\n },\n };\n}) satisfies IntegrationFn;\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\nfunction extractSql(firstArg: unknown): string | undefined {\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n if (firstArg && typeof firstArg === 'object' && 'sql' in firstArg) {\n const sql = (firstArg as { sql?: unknown }).sql;\n return typeof sql === 'string' ? sql : undefined;\n }\n return undefined;\n}\n\nfunction getConnectionConfig(connection: MysqlConnection | undefined): {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n} {\n // Pool connections nest the real config under `.connectionConfig`; single\n // connections expose it directly. Matches `@opentelemetry/instrumentation-mysql`.\n const config = connection?.config?.connectionConfig ?? connection?.config ?? {};\n return {\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n };\n}\n\nfunction getJDBCString(host: string | undefined, port: number | undefined, database: string | undefined): string {\n let s = `jdbc:mysql://${host || 'localhost'}`;\n if (typeof port === 'number') {\n s += `:${port}`;\n }\n if (database) {\n s += `/${database}`;\n }\n return s;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven mysql integration.\n *\n * Subscribes to the `orchestrion:mysql:query` diagnostics_channel that the\n * orchestrion code transform injects into `mysql/lib/Connection.js`'s\n * `Connection.prototype.query`. Requires the orchestrion runtime hook or\n * bundler plugin to be active — wire that up via `_experimentalSetupOrchestrion`.\n */\nexport const mysqlChannelIntegration = defineIntegration(_mysqlChannelIntegration);\n"],"names":["DEBUG_BUILD","debug","CHANNELS","diagnosticsChannel","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","getCurrentScope","withScope","bindScopeToEmitter","SPAN_STATUS_ERROR","defineIntegration"],"mappings":"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"}
export { IOREDIS_DC_CHANNEL_COMMAND, IOREDIS_DC_CHANNEL_CONNECT, REDIS_DC_CHANNEL_BATCH, REDIS_DC_CHANNEL_COMMAND, REDIS_DC_CHANNEL_CONNECT, subscribeRedisDiagnosticChannels } from './redis/redis-dc-subscriber.js';
export { bindTracingChannelToSpan } from './tracing-channel.js';
export { vercelAiIntegration } from './vercel-ai/index.js';
//# sourceMappingURL=index.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}

@@ -1,2 +0,2 @@

import * as diagnosticsChannel from 'node:diagnostics_channel';
import * as dc from 'node:diagnostics_channel';
import { defineIntegration, debug, SPAN_STATUS_ERROR, bindScopeToEmitter, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getCurrentScope, withScope } from '@sentry/core';

@@ -19,3 +19,3 @@ import { DEBUG_BUILD } from '../../debug-build.js';

DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel "${CHANNELS.MYSQL_QUERY}"`);
const queryCh = diagnosticsChannel.tracingChannel(CHANNELS.MYSQL_QUERY);
const queryCh = dc.tracingChannel(CHANNELS.MYSQL_QUERY);
const spans = /* @__PURE__ */ new WeakMap();

@@ -22,0 +22,0 @@ const parentScopes = /* @__PURE__ */ new WeakMap();

@@ -1,1 +0,1 @@

{"version":3,"file":"mysql.js","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope, Span } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, OTel 'Mysql' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Mysql';\n\n// OpenTelemetry \"OLD\" db/net semantic-conventions. We inline them rather than\n// importing `@opentelemetry/semantic-conventions` to keep this integration's\n// dependency surface free of OTel — orchestrion's whole point is to step away\n// from the OTel auto-instrumentation stack.\n//\n// We emit the OLD conventions to match `@opentelemetry/instrumentation-mysql`'s\n// default (it only emits the stable `db.system.name` / `db.query.text` set when\n// `OTEL_SEMCONV_STABILITY_OPT_IN=database` is opted into) and the rest of the\n// Sentry JS SDK, whose `inferDbSpanData` processor renames spans based on\n// `db.statement`.\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\n\n/**\n * The shape orchestrion's wrapCallback transform attaches to the tracing-channel\n * `context` object. Documented here rather than imported because orchestrion's\n * runtime doesn't export it — see `node_modules/@apm-js-collab/code-transformer/lib/transforms.js`.\n *\n * `arguments` is the *live* args array passed to the wrapped function: orchestrion\n * splices the user's callback out and inserts its own wrapper at the same index\n * before publishing `start`. The `start` hook re-wraps that entry to restore the\n * caller's scope across mysql's async callback dispatch (see below).\n */\ninterface MysqlQueryChannelContext {\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\n}\n\ninterface MysqlConnectionConfig {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n // Pool connections nest the real config one level deeper.\n connectionConfig?: MysqlConnectionConfig;\n}\n\ninterface MysqlConnection {\n config?: MysqlConnectionConfig;\n}\n\nconst _mysqlChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n const queryCh = diagnosticsChannel.tracingChannel(CHANNELS.MYSQL_QUERY);\n\n // Orchestrion creates one `context` object per call, shared across all\n // lifecycle hooks. We key both maps off that identity; `WeakMap` so an\n // unfinished path can't leak its entries.\n const spans = new WeakMap<object, Span>();\n // The scope active when the query was issued, consumed in `end` to bind\n // the streamed `Query` emitter's listeners to it.\n const parentScopes = new WeakMap<object, Scope>();\n\n // `subscribe()` requires all five lifecycle hooks. The orchestrion\n // `wrapAuto` transform fires events in one of four orders depending on\n // call shape:\n // - sync throw : start → error → end\n // (NO asyncEnd)\n // - async-callback error : start → end → error →\n // asyncStart → asyncEnd\n // - async-callback success : start → end → asyncStart →\n // asyncEnd\n // - no-callback (streamable Query) : start → end\n // (ctx.result is the Query\n // emitter, no async events)\n //\n // Where the span closes depends on the path: `asyncEnd` for callbacks (so\n // it spans the full round-trip + callback), or `end` for the sync-throw\n // and streamable paths. The `end` hook tells those apart via `ctx.error`\n // / `ctx.result` — see there.\n queryCh.subscribe({\n start(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const sql = extractSql(ctx.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(ctx.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n const span = startInactiveSpan({\n name: sql ?? 'mysql.query',\n op: 'db',\n attributes: {\n [ATTR_DB_SYSTEM]: 'mysql',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.orchestrion.mysql',\n [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database),\n ...(database ? { [ATTR_DB_NAME]: database } : {}),\n ...(user ? { [ATTR_DB_USER]: user } : {}),\n ...(sql ? { [ATTR_DB_STATEMENT]: sql } : {}),\n ...(host ? { [ATTR_NET_PEER_NAME]: host } : {}),\n ...(portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {}),\n },\n });\n spans.set(rawCtx, span);\n\n // Capture the scope while we're still synchronously inside the\n // caller's `connection.query` call. mysql v2 drains callbacks and\n // emits streamed-query events from its socket data handler, where the\n // AsyncLocalStorage store backing the active span no longer reflects\n // the caller's context — and `asyncStart`/`asyncEnd` fire from that\n // same lost context, so capturing has to happen now.\n const scope = getCurrentScope();\n parentScopes.set(rawCtx, scope);\n\n // Callback path: orchestrion has spliced the user's callback out of\n // `ctx.arguments` and put its own wrapper (`__apm$wrappedCb`) at the\n // same index. Re-wrap it so the callback — and any nested\n // `connection.query(...)` — runs with the captured scope active.\n if (ctx.arguments.length > 0) {\n const cbIdx = ctx.arguments.length - 1;\n const orchestrionWrappedCb = ctx.arguments[cbIdx];\n if (typeof orchestrionWrappedCb === 'function') {\n const wrapped = orchestrionWrappedCb as (...a: unknown[]) => unknown;\n ctx.arguments[cbIdx] = function (this: unknown, ...args: unknown[]): unknown {\n return withScope(scope, () => wrapped.apply(this, args));\n };\n }\n }\n },\n\n end(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n\n // Sync throw: `end` fires AFTER `error` (both inside the wrapper's\n // `try/catch/finally`), so `ctx.error` is already set. Close the\n // span now since no `asyncEnd` will fire.\n if (ctx.error !== undefined) {\n finishSpan(rawCtx);\n return;\n }\n\n // No-callback (streamable Query) path: orchestrion's `wrapPromise`\n // stores the synchronous return value on `ctx.result` and never\n // fires `asyncStart`/`asyncEnd`. The returned `Query` is an\n // `EventEmitter` that emits `'end'` on success and `'error'` on\n // failure — hook those to close the span.\n // Note: a streamed span never finishes if the connection is destroyed\n // mid-flight — mysql then emits neither `'end'` nor `'error'`, so the\n // span is dropped (the `WeakMap` still prevents a leak). Closing this\n // needs connection-level hooks the per-query context doesn't expose.\n const result = ctx.result;\n if (result && typeof result === 'object' && hasOnMethod(result)) {\n const span = spans.get(rawCtx);\n if (!span) return;\n\n // Bind the captured scope to the streamed `Query` emitter: its\n // `'end'`/`'error'`/`'fields'`/… events fire from mysql's socket\n // handler with the caller's context lost, so without this a span\n // started in a user's stream listener would begin a fresh root trace\n // instead of nesting under the parent. `bindScopeToEmitter` patches\n // `on`/`addListener`/… so listeners added after `query()` returns\n // inherit the scope (like OTel's `context.bind`).\n const parentScope = parentScopes.get(rawCtx);\n if (parentScope) {\n bindScopeToEmitter(result, parentScope);\n }\n\n result.on('error', err => {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: err instanceof Error ? err.message : 'unknown_error',\n });\n // Defensive: end the span here too in case `'end'` never fires\n // (e.g. abrupt socket destruction). `finishSpan` is idempotent —\n // `spans.delete` makes the subsequent `'end'` listener a no-op.\n finishSpan(rawCtx);\n });\n result.on('end', () => finishSpan(rawCtx));\n return;\n }\n\n // Callback path: `asyncEnd` will close the span. Nothing to do here.\n },\n\n error(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const span = spans.get(rawCtx);\n if (!span) return;\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: ctx.error instanceof Error ? ctx.error.message : 'unknown_error',\n });\n },\n\n asyncStart() {\n // No-op: we end on `asyncEnd` so the span covers the full callback duration.\n },\n\n asyncEnd(rawCtx) {\n finishSpan(rawCtx);\n },\n });\n\n function finishSpan(rawCtx: object): void {\n const span = spans.get(rawCtx);\n if (!span) return;\n span.end();\n spans.delete(rawCtx);\n parentScopes.delete(rawCtx);\n }\n },\n };\n}) satisfies IntegrationFn;\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\nfunction extractSql(firstArg: unknown): string | undefined {\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n if (firstArg && typeof firstArg === 'object' && 'sql' in firstArg) {\n const sql = (firstArg as { sql?: unknown }).sql;\n return typeof sql === 'string' ? sql : undefined;\n }\n return undefined;\n}\n\nfunction getConnectionConfig(connection: MysqlConnection | undefined): {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n} {\n // Pool connections nest the real config under `.connectionConfig`; single\n // connections expose it directly. Matches `@opentelemetry/instrumentation-mysql`.\n const config = connection?.config?.connectionConfig ?? connection?.config ?? {};\n return {\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n };\n}\n\nfunction getJDBCString(host: string | undefined, port: number | undefined, database: string | undefined): string {\n let s = `jdbc:mysql://${host || 'localhost'}`;\n if (typeof port === 'number') {\n s += `:${port}`;\n }\n if (database) {\n s += `/${database}`;\n }\n return s;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven mysql integration.\n *\n * Subscribes to the `orchestrion:mysql:query` diagnostics_channel that the\n * orchestrion code transform injects into `mysql/lib/Connection.js`'s\n * `Connection.prototype.query`. Requires the orchestrion runtime hook or\n * bundler plugin to be active — wire that up via `_experimentalSetupOrchestrion`.\n */\nexport const mysqlChannelIntegration = defineIntegration(_mysqlChannelIntegration);\n"],"names":[],"mappings":"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"}
{"version":3,"file":"mysql.js","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope, Span } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, OTel 'Mysql' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Mysql';\n\n// OpenTelemetry \"OLD\" db/net semantic-conventions. We inline them rather than\n// importing `@opentelemetry/semantic-conventions` to keep this integration's\n// dependency surface free of OTel — orchestrion's whole point is to step away\n// from the OTel auto-instrumentation stack.\n//\n// We emit the OLD conventions to match `@opentelemetry/instrumentation-mysql`'s\n// default (it only emits the stable `db.system.name` / `db.query.text` set when\n// `OTEL_SEMCONV_STABILITY_OPT_IN=database` is opted into) and the rest of the\n// Sentry JS SDK, whose `inferDbSpanData` processor renames spans based on\n// `db.statement`.\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\n\n/**\n * The shape orchestrion's wrapCallback transform attaches to the tracing-channel\n * `context` object. Documented here rather than imported because orchestrion's\n * runtime doesn't export it — see `node_modules/@apm-js-collab/code-transformer/lib/transforms.js`.\n *\n * `arguments` is the *live* args array passed to the wrapped function: orchestrion\n * splices the user's callback out and inserts its own wrapper at the same index\n * before publishing `start`. The `start` hook re-wraps that entry to restore the\n * caller's scope across mysql's async callback dispatch (see below).\n */\ninterface MysqlQueryChannelContext {\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\n}\n\ninterface MysqlConnectionConfig {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n // Pool connections nest the real config one level deeper.\n connectionConfig?: MysqlConnectionConfig;\n}\n\ninterface MysqlConnection {\n config?: MysqlConnectionConfig;\n}\n\nconst _mysqlChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n const queryCh = diagnosticsChannel.tracingChannel(CHANNELS.MYSQL_QUERY);\n\n // Orchestrion creates one `context` object per call, shared across all\n // lifecycle hooks. We key both maps off that identity; `WeakMap` so an\n // unfinished path can't leak its entries.\n const spans = new WeakMap<object, Span>();\n // The scope active when the query was issued, consumed in `end` to bind\n // the streamed `Query` emitter's listeners to it.\n const parentScopes = new WeakMap<object, Scope>();\n\n // `subscribe()` requires all five lifecycle hooks. The orchestrion\n // `wrapAuto` transform fires events in one of four orders depending on\n // call shape:\n // - sync throw : start → error → end\n // (NO asyncEnd)\n // - async-callback error : start → end → error →\n // asyncStart → asyncEnd\n // - async-callback success : start → end → asyncStart →\n // asyncEnd\n // - no-callback (streamable Query) : start → end\n // (ctx.result is the Query\n // emitter, no async events)\n //\n // Where the span closes depends on the path: `asyncEnd` for callbacks (so\n // it spans the full round-trip + callback), or `end` for the sync-throw\n // and streamable paths. The `end` hook tells those apart via `ctx.error`\n // / `ctx.result` — see there.\n queryCh.subscribe({\n start(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const sql = extractSql(ctx.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(ctx.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n const span = startInactiveSpan({\n name: sql ?? 'mysql.query',\n op: 'db',\n attributes: {\n [ATTR_DB_SYSTEM]: 'mysql',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.orchestrion.mysql',\n [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database),\n ...(database ? { [ATTR_DB_NAME]: database } : {}),\n ...(user ? { [ATTR_DB_USER]: user } : {}),\n ...(sql ? { [ATTR_DB_STATEMENT]: sql } : {}),\n ...(host ? { [ATTR_NET_PEER_NAME]: host } : {}),\n ...(portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {}),\n },\n });\n spans.set(rawCtx, span);\n\n // Capture the scope while we're still synchronously inside the\n // caller's `connection.query` call. mysql v2 drains callbacks and\n // emits streamed-query events from its socket data handler, where the\n // AsyncLocalStorage store backing the active span no longer reflects\n // the caller's context — and `asyncStart`/`asyncEnd` fire from that\n // same lost context, so capturing has to happen now.\n const scope = getCurrentScope();\n parentScopes.set(rawCtx, scope);\n\n // Callback path: orchestrion has spliced the user's callback out of\n // `ctx.arguments` and put its own wrapper (`__apm$wrappedCb`) at the\n // same index. Re-wrap it so the callback — and any nested\n // `connection.query(...)` — runs with the captured scope active.\n if (ctx.arguments.length > 0) {\n const cbIdx = ctx.arguments.length - 1;\n const orchestrionWrappedCb = ctx.arguments[cbIdx];\n if (typeof orchestrionWrappedCb === 'function') {\n const wrapped = orchestrionWrappedCb as (...a: unknown[]) => unknown;\n ctx.arguments[cbIdx] = function (this: unknown, ...args: unknown[]): unknown {\n return withScope(scope, () => wrapped.apply(this, args));\n };\n }\n }\n },\n\n end(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n\n // Sync throw: `end` fires AFTER `error` (both inside the wrapper's\n // `try/catch/finally`), so `ctx.error` is already set. Close the\n // span now since no `asyncEnd` will fire.\n if (ctx.error !== undefined) {\n finishSpan(rawCtx);\n return;\n }\n\n // No-callback (streamable Query) path: orchestrion's `wrapPromise`\n // stores the synchronous return value on `ctx.result` and never\n // fires `asyncStart`/`asyncEnd`. The returned `Query` is an\n // `EventEmitter` that emits `'end'` on success and `'error'` on\n // failure — hook those to close the span.\n // Note: a streamed span never finishes if the connection is destroyed\n // mid-flight — mysql then emits neither `'end'` nor `'error'`, so the\n // span is dropped (the `WeakMap` still prevents a leak). Closing this\n // needs connection-level hooks the per-query context doesn't expose.\n const result = ctx.result;\n if (result && typeof result === 'object' && hasOnMethod(result)) {\n const span = spans.get(rawCtx);\n if (!span) return;\n\n // Bind the captured scope to the streamed `Query` emitter: its\n // `'end'`/`'error'`/`'fields'`/… events fire from mysql's socket\n // handler with the caller's context lost, so without this a span\n // started in a user's stream listener would begin a fresh root trace\n // instead of nesting under the parent. `bindScopeToEmitter` patches\n // `on`/`addListener`/… so listeners added after `query()` returns\n // inherit the scope (like OTel's `context.bind`).\n const parentScope = parentScopes.get(rawCtx);\n if (parentScope) {\n bindScopeToEmitter(result, parentScope);\n }\n\n result.on('error', err => {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: err instanceof Error ? err.message : 'unknown_error',\n });\n // Defensive: end the span here too in case `'end'` never fires\n // (e.g. abrupt socket destruction). `finishSpan` is idempotent —\n // `spans.delete` makes the subsequent `'end'` listener a no-op.\n finishSpan(rawCtx);\n });\n result.on('end', () => finishSpan(rawCtx));\n return;\n }\n\n // Callback path: `asyncEnd` will close the span. Nothing to do here.\n },\n\n error(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const span = spans.get(rawCtx);\n if (!span) return;\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: ctx.error instanceof Error ? ctx.error.message : 'unknown_error',\n });\n },\n\n asyncStart() {\n // No-op: we end on `asyncEnd` so the span covers the full callback duration.\n },\n\n asyncEnd(rawCtx) {\n finishSpan(rawCtx);\n },\n });\n\n function finishSpan(rawCtx: object): void {\n const span = spans.get(rawCtx);\n if (!span) return;\n span.end();\n spans.delete(rawCtx);\n parentScopes.delete(rawCtx);\n }\n },\n };\n}) satisfies IntegrationFn;\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\nfunction extractSql(firstArg: unknown): string | undefined {\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n if (firstArg && typeof firstArg === 'object' && 'sql' in firstArg) {\n const sql = (firstArg as { sql?: unknown }).sql;\n return typeof sql === 'string' ? sql : undefined;\n }\n return undefined;\n}\n\nfunction getConnectionConfig(connection: MysqlConnection | undefined): {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n} {\n // Pool connections nest the real config under `.connectionConfig`; single\n // connections expose it directly. Matches `@opentelemetry/instrumentation-mysql`.\n const config = connection?.config?.connectionConfig ?? connection?.config ?? {};\n return {\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n };\n}\n\nfunction getJDBCString(host: string | undefined, port: number | undefined, database: string | undefined): string {\n let s = `jdbc:mysql://${host || 'localhost'}`;\n if (typeof port === 'number') {\n s += `:${port}`;\n }\n if (database) {\n s += `/${database}`;\n }\n return s;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven mysql integration.\n *\n * Subscribes to the `orchestrion:mysql:query` diagnostics_channel that the\n * orchestrion code transform injects into `mysql/lib/Connection.js`'s\n * `Connection.prototype.query`. Requires the orchestrion runtime hook or\n * bundler plugin to be active — wire that up via `_experimentalSetupOrchestrion`.\n */\nexport const mysqlChannelIntegration = defineIntegration(_mysqlChannelIntegration);\n"],"names":["diagnosticsChannel"],"mappings":"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"}

@@ -1,1 +0,1 @@

{"type":"module","version":"10.61.0","sideEffects":false}
{"type":"module","version":"10.62.0","sideEffects":false}

@@ -10,2 +10,3 @@ /**

export { SentryTracingChannel, TracingChannelLifeCycleOptions, TracingChannelBindingHandle, TracingChannelPayloadWithSpan, } from './tracing-channel';
export { vercelAiIntegration } from './vercel-ai';
//# sourceMappingURL=index.d.ts.map

@@ -10,2 +10,3 @@ /**

export type { SentryTracingChannel, TracingChannelLifeCycleOptions, TracingChannelBindingHandle, TracingChannelPayloadWithSpan, } from './tracing-channel';
export { vercelAiIntegration } from './vercel-ai';
//# sourceMappingURL=index.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,kCAAkC,EAClC,0BAA0B,GAC3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,kCAAkC,EAClC,0BAA0B,GAC3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
{
"name": "@sentry/server-utils",
"version": "10.61.0",
"version": "10.62.0",
"description": "Server Utilities for all Sentry JavaScript SDKs",

@@ -89,3 +89,3 @@ "repository": "git://github.com/getsentry/sentry-javascript.git",

"@sentry/conventions": "^0.12.0",
"@sentry/core": "10.61.0",
"@sentry/core": "10.62.0",
"magic-string": "~0.30.0"

@@ -92,0 +92,0 @@ },