Skip to content

vercelAIIntegration: span op stays 'default' instead of 'gen_ai.invoke_agent' - AI Agents dashboard shows no data #18448

@jam3gw

Description

@jam3gw

Is there an existing issue for this?

How do you use Sentry?

Sentry SaaS (sentry.io)

Which SDK are you using?

@sentry/nextjs

SDK Version

10.29.0

Framework Version

Next.js 15.4.1

Link to Sentry event

https://pedestalai.sentry.io/explore/traces/?query=span.description%3A*ai.generateText*&project=4510505607364608

Reproduction Example/SDK Setup

sentry.server.config.ts:

import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: "...",
  tracesSampleRate: 1,
  integrations: [
    Sentry.vercelAIIntegration({
      recordInputs: true,
      recordOutputs: true,
    }),
  ],
  sendDefaultPii: true,
});

AI SDK call with telemetry:

const result = await generateText({
  model: google("gemini-2.5-flash"),
  prompt: "...",
  experimental_telemetry: {
    isEnabled: true,
    functionId: "generate-title",
    recordInputs: true,
    recordOutputs: true,
  },
});

Steps to Reproduce

  1. Configure vercelAIIntegration() in Sentry.init()
  2. Make AI SDK calls with experimental_telemetry: { isEnabled: true }
  3. Check spans in Trace Explorer - they appear with span.op: default
  4. Check AI Agents dashboard at /insights/ai-agents/ - no data appears

Expected Result

Spans should have:

  • span.op: gen_ai.invoke_agent (for ai.generateText, ai.streamText)
  • span.op: gen_ai.generate_text (for ai.generateText.doGenerate)

This would make them appear in the AI Agents dashboard.

Actual Result

Spans have:

  • span.op: default
  • span.description: ai.generateText
  • All other gen_ai.* attributes are correctly set ✅

The common attributes (gen_ai.system, gen_ai.request.model, gen_ai.usage.*, etc.) are populated correctly, but the op transformation never happens.

Root Cause Analysis

The issue is in packages/core/src/tracing/vercel-ai/index.ts:

function onVercelAiSpanStart(span: Span): void {
  const { data: attributes, description: name } = spanToJSON(span);
  // ...
  
  // THE BUG: These attributes don't exist yet when the span STARTS
  const aiModelId = attributes[AI_MODEL_ID_ATTRIBUTE];
  const aiModelProvider = attributes[AI_MODEL_PROVIDER_ATTRIBUTE];
  
  // This check FAILS because attributes are undefined at span start
  if (typeof aiModelId !== 'string' || typeof aiModelProvider !== 'string' || !aiModelId || !aiModelProvider) {
    return;  // ← Exits early, never sets the op!
  }

  processGenerateSpan(span, name, attributes);  // ← Never reached
}

The AI SDK adds ai.model.id and ai.model.provider attributes after the span starts (when the LLM response completes), not at span creation time.

The vercelAiEventProcessor (which runs after spans end when attributes ARE available) only renames attributes but does NOT set the op.

Suggested Fix

Add op transformation logic to processEndedVercelAiSpan:

function processEndedVercelAiSpan(span: SpanJSON): void {
  const { data: attributes, origin, description: name } = span;

  if (origin !== 'auto.vercelai.otel') {
    return;
  }

  // FIX: Set op based on span name (attributes are now available)
  if (name === 'ai.generateText' || name === 'ai.streamText' || name === 'ai.generateObject') {
    span.op = 'gen_ai.invoke_agent';
  } else if (name === 'ai.generateText.doGenerate') {
    span.op = 'gen_ai.generate_text';
  } else if (name === 'ai.streamText.doStream') {
    span.op = 'gen_ai.stream_text';
  }
  // ... handle other cases

  // existing attribute renaming logic...
}

Related

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Status

Waiting for: Product Owner

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions