feat(node): Add eveConversationHook() to link eve sessions as Sentry conversations - #24247
Open
mydea wants to merge 4 commits into
Open
feat(node): Add eveConversationHook() to link eve sessions as Sentry conversations#24247mydea wants to merge 4 commits into
eveConversationHook() to link eve sessions as Sentry conversations#24247mydea wants to merge 4 commits into
Conversation
…y conversations
Adds `Sentry.eveConversationHook()`, used as the default export of an eve
`agent/hooks/sentry.ts`:
export default defineHook(Sentry.eveConversationHook());
It tags every turn of an eve session with the durable session id as the Sentry
conversation id, so the session's AI spans — which land in separate traces
(each eve turn is its own durable workflow) — group into one conversation in
the Agents "Conversations" view.
The id is set on the isolation scope rather than on the AI call: eve's session
id never reaches the AI SDK's telemetry diagnostics channel, so the only way to
attach it is via the scope, where the always-on `conversationIdIntegration`
picks it up and stamps `gen_ai.conversation.id` onto the gen_ai spans.
Subscribes to both `turn.started` and `step.started`. Each turn is a fresh
request with its own isolation scope, and a turn that parks and resumes
(approvals, compaction) resumes in another request where `turn.started` won't
re-fire — `step.started` runs before every model call, so together they cover
each request that produces spans. Re-setting the same id is idempotent.
The eve hook context is typed structurally (not imported from `eve`) so
`@sentry/node` keeps no dependency on the framework; the shape is checked at the
`defineHook(...)` call site instead.
The node-eve e2e app uses the hook and asserts `gen_ai.conversation.id` on each
gen_ai span equals the eve session id.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
size-limit report 📦
|
mydea
added this pull request to stack #24250
September 9, 2026 13:29
…e-export from every runtime SDK The helper only needs `setConversationId` from core, so `@sentry/server-utils` is its natural home — a framework-agnostic shared layer already re-exported by the runtime SDKs — rather than living in `@sentry/node`. - `@sentry/node` now re-exports it from `@sentry/server-utils` (like the other shared server helpers), so every node-based SDK that does `export * from '@sentry/node'` (astro, nitro — eve's own base —, nestjs, hono, effect) surfaces it automatically. - Added to the explicit `@sentry/node` re-export blocks of `@sentry/bun`, `@sentry/aws-serverless` and `@sentry/google-cloud-serverless`. - Added to the `@sentry/server-utils` re-export blocks of `@sentry/deno` and `@sentry/cloudflare`, which build on server-utils rather than node. The unit test moves alongside the implementation into `@sentry/server-utils`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
It is a single-field options bag callers pass as an inline object literal, so exporting the type name added public API surface across every runtime SDK for no benefit. It stays declared (unexported) alongside the function, so the signature is unaffected and callers still pass options structurally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mydea
marked this pull request as ready for review
September 9, 2026 14:43
mydea
requested review from
JPeer264 and
isaacs
and removed request for
a team
September 9, 2026 14:43
6 tasks
Astro's runtime entry curates its `@sentry/node` re-exports (it can't `export *`), so the helper has to be listed explicitly like the other SDKs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mydea
requested review from
nicohrubec and
s1gr1d
and removed request for
a team
September 9, 2026 14:51
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #24228 (base branch
feat/e2e-eve-agent).Adds
eveConversationHook(), used as the default export of an eveagent/hooks/sentry.ts:It tags every turn of an eve session with the durable session id (
ctx.session.id) as the Sentry conversation id, so the session's AI spans — which land in separate traces, since each eve turn is its own durable workflow — group into one conversation in the Agents "Conversations" view.Root cause / why this shape:
recordInputs/recordOutputs/functionId;runtimeContext/metadata go to eve's own OTel integration, which Sentry bypasses). So the id can only be attached via the isolation scope, where the always-onconversationIdIntegrationpicks it up and stampsgen_ai.conversation.idonto the gen_ai spans.turn.startedandstep.started. Each turn is a fresh request with its own isolation scope, and a turn that parks and resumes (approvals, compaction) resumes in another request whereturn.startedwon't re-fire.step.startedruns before every model call, so together they cover every request that produces spans. Re-setting the same id is idempotent.@sentry/server-utils. The helper only needssetConversationIdfrom core, so it belongs in the framework-agnostic shared layer, not@sentry/node.@sentry/nodere-exports it (so everyexport * from '@sentry/node'SDK — astro, nitro (eve's own base), nestjs, hono, effect — surfaces it automatically); it is added explicitly to the node-based@sentry/bun,@sentry/aws-serverless,@sentry/google-cloud-serverless, and to the server-utils-based@sentry/denoand@sentry/cloudflare.eve, so the SDK keeps no dependency on the framework; the shape is checked at thedefineHook(...)call site. An optionalgetConversationIdlets users override the default (e.g. to use a root/parent session id for subagents).The
node-evee2e app now uses the hook and assertsgen_ai.conversation.idon each gen_ai span equals the eve session id returned by the session endpoint.🤖 Generated with Claude Code