Skip to content

Conversation

@jam3gw
Copy link

@jam3gw jam3gw commented Dec 18, 2025

Summary

  • Sets span.op for Vercel AI spans during ended-span processing when it is missing or still default.
  • This is a fallback for cases where onVercelAiSpanStart returns early (for example, AI SDK attributes required for op mapping are not present at span start).

Context

Fixes #18448.

PR #18471 relaxed the spanStart guard to require only ai.model.id, but this can still be insufficient if the attributes needed for op mapping aren't reliably present at span start. Since processEndedVercelAiSpan already normalizes AI attributes on ended spans, it's a good place to also ensure span.op is set.

FAQ

Q: Why aren't these spans getting a gen_ai.* op at span start? Is the user setup wrong?

A: Usually nothing is wrong with the user setup. The integration sets span.op in the spanStart hook, but it gates that work on AI SDK attributes being present at span start (for example ai.model.id). In practice, the AI SDK / OpenTelemetry instrumentation may attach some of those attributes after the span has started (for example once the provider response/usage is known). In that case onVercelAiSpanStart can return early and the span remains op=default. The ended-span event processor already runs after those attributes exist (it renames them to gen_ai.*), so setting the op there provides the needed fallback for the AI Agents UI.

Test plan

  • Verify in Trace Explorer that ai.* spans no longer have op=default and are classified as gen_ai.* (and appear in AI Agents).

Copy link
Member

@chargome chargome left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @jam3gw, thanks for opening a PR!

The code will need some refinement and also some tests before we can merge this in.

We're happy to take this over if you want, please let us know.

Comment on lines +121 to +144
if (name && (span.op === 'default' || !span.op)) {
if (
name === 'ai.generateText' ||
name === 'ai.streamText' ||
name === 'ai.generateObject' ||
name === 'ai.streamObject' ||
name === 'ai.embed' ||
name === 'ai.embedMany'
) {
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';
} else if (name === 'ai.generateObject.doGenerate') {
span.op = 'gen_ai.generate_object';
} else if (name === 'ai.streamObject.doStream') {
span.op = 'gen_ai.stream_object';
} else if (name === 'ai.embed.doEmbed') {
span.op = 'gen_ai.embed';
} else if (name === 'ai.embedMany.doEmbed') {
span.op = 'gen_ai.embed_many';
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a cleaner approach would be to determine the name with a map here.

name === 'ai.embed' ||
name === 'ai.embedMany'
) {
span.op = 'gen_ai.invoke_agent';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're generally using constants for these attributes, you'll find other occurrences in this file.

) {
span.op = 'gen_ai.invoke_agent';
} else if (name === 'ai.generateText.doGenerate') {
span.op = 'gen_ai.generate_text';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

op should be updated like this:

span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, YOUR_AI_ATTRIBUTE);

@chargome chargome changed the title fix(tracing): set op on ended Vercel AI spans fix(core): Set op on ended Vercel AI spans Dec 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants