Skip to content

fix(server-utils): Derive the Vercel AI conversation id from the OpenAI conversation option - #24979

Open
RulaKhaled wants to merge 4 commits into
developfrom
fix/vercel-ai-conversation-id-from-openai-conversation
Open

RulaKhaled wants to merge 4 commits into
developfrom
fix/vercel-ai-conversation-id-from-openai-conversation

Conversation

@RulaKhaled

Copy link
Copy Markdown
Collaborator

The Vercel AI integration filled gen_ai.conversation.id with providerMetadata.openai.responseId. That is the id of the response that just came back, so every call got a different value under a grouping attribute and showed up as its own one-span conversation. The same value is already on gen_ai.response.id. The mapping came in with #16992 and #19903 later had to guard it from overwriting user-set ids.

The id now comes from providerOptions.openai.conversation (or azure), the Conversations API conv_ id, which is the same on every turn. Child model-call and tool spans inherit it from the active operation span. Sentry.setConversationId() still wins, since conversationIdIntegration writes the scope value on spanStart after these start attributes. The v6 adapter forwards providerOptions so ai 4 to 6 behave the same.

Not in this PR: reading the id from runtimeContext / experimental_telemetry.metadata goes with #24706 once #24721 lands.

Part of #24832

🤖 Generated with Claude Code

…AI conversation option

`gen_ai.conversation.id` was filled with `providerMetadata.openai.responseId`,
the id of the response that just came back, so every call got its own value
under a grouping attribute. The id now comes from
`providerOptions.openai.conversation` (or `azure`), the Conversations API id
that is the same on every turn. Child spans inherit it from the active
operation span, and `Sentry.setConversationId()` still wins.

Part of #24832

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@RulaKhaled
RulaKhaled requested a review from a team as a code owner October 2, 2026 10:51
@RulaKhaled
RulaKhaled requested review from andreiborza and isaacs and removed request for a team October 2, 2026 10:51
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 29.44 kB - -
@sentry/browser - with treeshaking flags 27.59 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.48 kB - -
@sentry/browser (incl. Tracing) 51.32 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 51.33 kB - -
@sentry/browser (incl. Tracing, Profiling) 54.31 kB - -
@sentry/browser (incl. Tracing, Replay) 90.95 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 79.93 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 95.65 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 108.65 kB - -
@sentry/browser (incl. Feedback) 46.96 kB - -
@sentry/browser (incl. sendFeedback) 34.5 kB - -
@sentry/browser (incl. FeedbackAsync) 39.6 kB - -
@sentry/browser (incl. Metrics) 30.45 kB - -
@sentry/browser (incl. Logs) 30.74 kB - -
@sentry/browser (incl. Metrics & Logs) 31.39 kB - -
@sentry/react 31.28 kB - -
@sentry/react (incl. Tracing) 53.69 kB - -
@sentry/vue 37.41 kB - -
@sentry/vue (incl. Tracing) 54.23 kB - -
@sentry/svelte 29.47 kB - -
@sentry/remix (Remix 3 client bundle) 55.65 kB - -
CDN Bundle 31.13 kB - -
CDN Bundle (incl. Tracing) 51.87 kB - -
CDN Bundle (incl. Logs, Metrics) 33.37 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 53.81 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 74.1 kB - -
CDN Bundle (incl. Tracing, Replay) 89.45 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 91.42 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 95.63 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 97.59 kB - -
CDN Bundle - uncompressed 91.95 kB - -
CDN Bundle (incl. Tracing) - uncompressed 154.26 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 98.53 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 160.21 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 228.15 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 274.06 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 280 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 287.77 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 293.69 kB - -
@sentry/nextjs (client) 56.18 kB - -
@sentry/sveltekit (client) 51.74 kB - -
@sentry/core/server 40.5 kB - -
@sentry/core/browser 13.51 kB - -
@sentry/node 144.98 kB +0.05% +68 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 83.22 kB - -
@sentry/node - without tracing 93.42 kB +0.02% +12 B 🔺
@sentry/node - without channel injection 123.17 kB +0.06% +63 B 🔺
@sentry/aws-serverless 101.66 kB +0.01% +7 B 🔺
@sentry/cloudflare (withSentry) - minified 208.47 kB - -
@sentry/cloudflare (withSentry) 516.75 kB - -

View base workflow run

@isaacs isaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There are some choices here that we should probably call out and I'd maybe add a follow-up for the openai inconsistency, but this is good overall.

Deferring reading the id from runtimeContext / experimental_telemetry.metadata until #24721 lands is sensible. That should be ready to go once the convention is approved.

Comment thread packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts Outdated
},
});

// Chaining on the previous response names a response, not a thread, so no conversation id.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Definitely out of scope for this PR, but I noticed that the direct OpenAI integration does the reverse of this comment: extractConversationId in packages/server-utils/src/ai/openai/utils.ts line 161 maps previous_response_id to gen_ai.conversation.id. That has the same problem you're fixing in this PR, because the value differs on each turn of a chain. So the same OpenAI conversation now gets different gen_ai.conversation.id values depending on whether the user calls OpenAI directly or through the AI SDK.

I'd suggest naming it in the description here as a todo, and adding a follow-up task to #24832 so we can converge on a single rule.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yah noticed this, adding it to the description as a todo and will put a task on #24830

Comment thread packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts Outdated
Comment thread dev-packages/node-integration-tests/suites/tracing/vercelai/v6_v7/test.ts Outdated
…d spans

A root operation took the conversation id from whatever span was active,
so a generateText inside a tool's execute joined the outer conversation.
Roots now read only their own providerOptions. The azure conversation is
also read when the openai options have none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@RulaKhaled
RulaKhaled enabled auto-merge (squash) October 5, 2026 19:54
@RulaKhaled
RulaKhaled disabled auto-merge October 5, 2026 20:15
# Conflicts:
#	packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts
#	packages/server-utils/src/integrations/vercel-ai/vercel-ai-orchestrion-subscriber.ts

This branch has not been deployed

No deployments
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.

2 participants