{"version":3,"sources":["../src/index.ts","../src/LangfuseVercelAiSdkIntegration.ts","../src/utils.ts"],"sourcesContent":["export { LangfuseVercelAiSdkIntegration } from \"./LangfuseVercelAiSdkIntegration.js\";\n\nexport type {\n  LangfusePrompt,\n  LangfuseVercelAiSdkIntegrationOptions,\n} from \"./types.js\";\n","import { OpenTelemetry } from \"@ai-sdk/otel\";\nimport type {\n  EmbedEndEvent,\n  EmbedStartEvent,\n  EmbeddingModelCallEndEvent,\n  EmbeddingModelCallStartEvent,\n  GenerateObjectEndEvent,\n  GenerateObjectStartEvent,\n  GenerateObjectStepEndEvent,\n  GenerateObjectStepStartEvent,\n  GenerateTextAbortEvent,\n  GenerateTextEndEvent,\n  GenerateTextStartEvent,\n  GenerateTextStepEndEvent,\n  GenerateTextStepStartEvent,\n  LanguageModelCallEndEvent,\n  LanguageModelCallStartEvent,\n  RerankEndEvent,\n  RerankStartEvent,\n  RerankingModelCallEndEvent,\n  RerankingModelCallStartEvent,\n  Telemetry,\n  ToolExecutionEndEvent,\n  ToolExecutionStartEvent,\n  ToolSet,\n} from \"ai\";\n\nimport type { LangfuseVercelAiSdkIntegrationOptions } from \"./types.js\";\nimport { createLangfuseObservationAttributes } from \"./utils.js\";\n\n/**\n * Langfuse telemetry integration for Vercel AI SDK v7 (`ai@7`).\n *\n * Register this once at application startup (or pass it per-call via\n * `telemetry.integrations`) and every AI SDK call — `generateText`,\n * `streamText`, `generateObject`, `embed`, tool executions — is traced as\n * Langfuse observations. Requires the `LangfuseSpanProcessor` from\n * `@langfuse/otel` to be registered with your OpenTelemetry setup; this\n * integration only creates spans, the processor exports them to Langfuse.\n *\n * For AI SDK versions ≤6, do not use this class — enable\n * `experimental_telemetry: { isEnabled: true }` on each call instead; the\n * `LangfuseSpanProcessor` picks those spans up without an integration.\n *\n * Trace-level attributes (userId, sessionId, tags, traceName, metadata)\n * should be set with `propagateAttributes` from `@langfuse/tracing` around\n * the AI SDK call. Runtime context keys included via the AI SDK `telemetry`\n * option become Langfuse observation metadata; the special key\n * `langfusePrompt` links a Langfuse prompt version to model-call\n * observations instead.\n *\n * @example\n * ```typescript\n * // instrumentation.ts — run once at startup\n * import { registerTelemetry } from \"ai\";\n * import { LangfuseSpanProcessor } from \"@langfuse/otel\";\n * import { LangfuseVercelAiSdkIntegration } from \"@langfuse/vercel-ai-sdk\";\n * import { NodeSDK } from \"@opentelemetry/sdk-node\";\n *\n * const sdk = new NodeSDK({ spanProcessors: [new LangfuseSpanProcessor()] });\n * sdk.start();\n * registerTelemetry(new LangfuseVercelAiSdkIntegration());\n *\n * // app code\n * import { generateText } from \"ai\";\n * import { propagateAttributes } from \"@langfuse/tracing\";\n *\n * const { text } = await propagateAttributes(\n *   { userId: \"user-123\", sessionId: \"session-456\" },\n *   () =>\n *     generateText({\n *       model,\n *       prompt: \"Explain RAG in one paragraph\",\n *       telemetry: { functionId: \"chat-assistant\" },\n *     }),\n * );\n * ```\n *\n * @see https://langfuse.com/integrations/frameworks/vercel-ai-sdk for the full guide incl. Next.js setup\n * @see https://langfuse.com/docs/observability/sdk/overview\n *\n * @public\n */\nexport class LangfuseVercelAiSdkIntegration implements Telemetry {\n  private readonly delegate: OpenTelemetry;\n\n  constructor(options: LangfuseVercelAiSdkIntegrationOptions = {}) {\n    const openTelemetryOptions: ConstructorParameters<typeof OpenTelemetry>[0] =\n      {\n        tracer: options.tracer,\n        enrichSpan: ({ spanType, runtimeContext }) =>\n          createLangfuseObservationAttributes({\n            spanType,\n            runtimeContext,\n          }),\n      };\n\n    this.delegate = new OpenTelemetry(openTelemetryOptions);\n  }\n\n  executeTool<T>(params: {\n    callId: string;\n    toolCallId: string;\n    execute: () => PromiseLike<T>;\n  }): PromiseLike<T> {\n    return this.delegate.executeTool(params);\n  }\n\n  executeLanguageModelCall<T>(params: {\n    callId: string;\n    execute: () => PromiseLike<T>;\n  }): PromiseLike<T> {\n    return this.delegate.executeLanguageModelCall(params);\n  }\n\n  onStart(\n    event:\n      | GenerateTextStartEvent\n      | GenerateObjectStartEvent\n      | EmbedStartEvent\n      | RerankStartEvent,\n  ): void {\n    this.delegate.onStart(event);\n  }\n\n  onStepStart(event: GenerateTextStepStartEvent): void {\n    this.delegate.onStepStart(event);\n  }\n\n  onLanguageModelCallStart(event: LanguageModelCallStartEvent): void {\n    this.delegate.onLanguageModelCallStart(event);\n  }\n\n  onLanguageModelCallEnd(event: LanguageModelCallEndEvent<ToolSet>): void {\n    this.delegate.onLanguageModelCallEnd(event);\n  }\n\n  onToolExecutionStart(event: ToolExecutionStartEvent<ToolSet>): void {\n    this.delegate.onToolExecutionStart(event);\n  }\n\n  onToolExecutionEnd(event: ToolExecutionEndEvent<ToolSet>): void {\n    this.delegate.onToolExecutionEnd(event);\n  }\n\n  onStepEnd(event: GenerateTextStepEndEvent<ToolSet>): void {\n    this.delegate.onStepEnd(event);\n  }\n\n  /** @deprecated AI SDK v7 still emits object generation model spans through this callback. */\n  onObjectStepStart(event: GenerateObjectStepStartEvent): void {\n    this.delegate.onObjectStepStart(event);\n  }\n\n  /** @deprecated AI SDK v7 still emits object generation model spans through this callback. */\n  onObjectStepEnd(event: GenerateObjectStepEndEvent): void {\n    this.delegate.onObjectStepEnd(event);\n  }\n\n  onEmbedStart(event: EmbeddingModelCallStartEvent): void {\n    this.delegate.onEmbedStart(event);\n  }\n\n  onEmbedEnd(event: EmbeddingModelCallEndEvent): void {\n    this.delegate.onEmbedEnd(event);\n  }\n\n  onRerankStart(event: RerankingModelCallStartEvent): void {\n    this.delegate.onRerankStart(event);\n  }\n\n  onRerankEnd(event: RerankingModelCallEndEvent): void {\n    this.delegate.onRerankEnd(event);\n  }\n\n  onEnd(\n    event:\n      | GenerateTextEndEvent<ToolSet>\n      | GenerateObjectEndEvent<unknown>\n      | EmbedEndEvent\n      | RerankEndEvent,\n  ): void {\n    this.delegate.onEnd(event);\n  }\n\n  onAbort(event: GenerateTextAbortEvent<ToolSet>): void {\n    this.delegate.onAbort(event);\n  }\n\n  onError(error: unknown): void {\n    this.delegate.onError(error);\n  }\n}\n","import type { OpenTelemetrySpanType } from \"@ai-sdk/otel\";\nimport { LangfuseOtelSpanAttributes } from \"@langfuse/core\";\nimport type { Attributes } from \"@opentelemetry/api\";\n\nimport type { LangfusePrompt } from \"./types.js\";\n\nconst PROMPT_SPAN_TYPES = new Set<OpenTelemetrySpanType>([\n  \"languageModel\",\n  \"embedding\",\n  \"reranking\",\n]);\n\nexport function createLangfuseObservationAttributes(params: {\n  runtimeContext?: Record<string, unknown>;\n  spanType: OpenTelemetrySpanType;\n}): Attributes {\n  const { runtimeContext, spanType } = params;\n  const attributes: Attributes = {};\n\n  if (!runtimeContext) {\n    return attributes;\n  }\n\n  const { langfusePrompt, ...metadata } = runtimeContext;\n\n  // Handle prompt data\n  const prompt = normalizePrompt(langfusePrompt);\n\n  if (PROMPT_SPAN_TYPES.has(spanType) && prompt && !prompt.isFallback) {\n    attributes[LangfuseOtelSpanAttributes.OBSERVATION_PROMPT_NAME] =\n      prompt.name;\n    attributes[LangfuseOtelSpanAttributes.OBSERVATION_PROMPT_VERSION] =\n      prompt.version;\n  }\n\n  // Handle metadata\n  if (metadata) {\n    for (const [key, value] of Object.entries(metadata)) {\n      const serialized =\n        typeof value === \"string\" ? value : safeSerialize(value);\n\n      if (serialized != null) {\n        attributes[\n          `${LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.${key}`\n        ] = serialized;\n      }\n    }\n  }\n\n  return attributes;\n}\n\nfunction normalizePrompt(value: unknown): LangfusePrompt | undefined {\n  if (!isPlainObject(value)) {\n    return;\n  }\n\n  if (typeof value.name !== \"string\" || typeof value.version !== \"number\") {\n    return;\n  }\n\n  return {\n    name: value.name,\n    version: value.version,\n    isFallback:\n      typeof value.isFallback === \"boolean\" ? value.isFallback : false,\n  };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, any> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction safeSerialize(value: unknown): string | undefined {\n  try {\n    if (value == null) {\n      return;\n    }\n\n    return JSON.stringify(value);\n  } catch {\n    return \"<failed to serialize>\";\n  }\n}\n"],"mappings":"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","names":[]}