Skip to content

feat(node): Add eveConversationHook() to link eve sessions as Sentry conversations - #24247

Merged
mydea merged 6 commits into
developfrom
feat/eve-conversation-hook
Sep 14, 2026
Merged

mydea merged 6 commits into
developfrom
feat/eve-conversation-hook

Conversation

@mydea

@mydea mydea commented Sep 9, 2026 •

Copy link
Copy Markdown
Member

Stacked on #24228 (base branch feat/e2e-eve-agent).

Adds eveConversationHook(), used as the default export of an eve agent/hooks/sentry.ts:

import * as Sentry from '@sentry/node';
import { defineHook } from 'eve/hooks';

export default defineHook(Sentry.eveConversationHook());

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:

  • Scope, not the AI call. eve's session id never reaches the AI SDK's telemetry diagnostics channel (the channel event only carries 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-on conversationIdIntegration picks it up and stamps gen_ai.conversation.id onto the gen_ai spans.
  • 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 every request that produces spans. Re-setting the same id is idempotent.
  • Lives in @sentry/server-utils. The helper only needs setConversationId from core, so it belongs in the framework-agnostic shared layer, not @sentry/node. @sentry/node re-exports it (so every export * 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/deno and @sentry/cloudflare.
  • Structural typing. The eve hook context is typed structurally rather than imported from eve, so the SDK keeps no dependency on the framework; the shape is checked at the defineHook(...) call site. An optional getConversationId lets users override the default (e.g. to use a root/parent session id for subagents).

The node-eve e2e app now uses the hook and asserts gen_ai.conversation.id on each gen_ai span equals the eve session id returned by the session endpoint.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️ Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

Path Size % Change Change
@sentry/browser 28.92 kB - -
@sentry/browser - with treeshaking flags 27.21 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.11 kB - -
@sentry/browser (incl. Tracing) 50.42 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 50.43 kB - -
@sentry/browser (incl. Tracing, Profiling) 53.41 kB - -
@sentry/browser (incl. Tracing, Replay) 89.93 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 79.05 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 94.64 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 107.65 kB - -
@sentry/browser (incl. Feedback) 46.41 kB - -
@sentry/browser (incl. sendFeedback) 33.97 kB - -
@sentry/browser (incl. FeedbackAsync) 39.08 kB - -
@sentry/browser (incl. Metrics) 29.93 kB - -
@sentry/browser (incl. Logs) 30.2 kB - -
@sentry/browser (incl. Metrics & Logs) 30.87 kB - -
@sentry/react 30.67 kB - -
@sentry/react (incl. Tracing) 52.73 kB - -
@sentry/vue 36.16 kB - -
@sentry/vue (incl. Tracing) 52.66 kB - -
@sentry/svelte 28.93 kB - -
CDN Bundle 30.66 kB - -
CDN Bundle (incl. Tracing) 50.93 kB - -
CDN Bundle (incl. Logs, Metrics) 32.93 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 52.91 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.62 kB - -
CDN Bundle (incl. Tracing, Replay) 88.48 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 90.43 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 94.55 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 96.55 kB - -
CDN Bundle - uncompressed 90.73 kB - -
CDN Bundle (incl. Tracing) - uncompressed 152.17 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.31 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 158.13 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 226.72 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 271.74 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 277.69 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 285.44 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 291.38 kB - -
@sentry/nextjs (client) 55.05 kB - -
@sentry/sveltekit (client) 50.83 kB - -
@sentry/core/server 37.08 kB - -
@sentry/core/browser 13.66 kB - -
@sentry/node 129.77 kB +0.02% +20 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 81.83 kB - -
@sentry/node - without tracing 89.57 kB +0.04% +30 B 🔺
@sentry/node - without channel injection 108.65 kB +0.03% +22 B 🔺
@sentry/aws-serverless 97.79 kB +0.02% +19 B 🔺
@sentry/cloudflare (withSentry) - minified 203.02 kB - -
@sentry/cloudflare (withSentry) 505.43 kB - -

View base workflow run

@mydea
mydea added this pull request to stack #24250 September 9, 2026 13:29
@mydea
mydea marked this pull request as ready for review September 9, 2026 14:43
@mydea
mydea requested review from a team as code owners September 9, 2026 14:43
@mydea
mydea requested review from JPeer264 and isaacs and removed request for a team September 9, 2026 14:43
@mydea
mydea requested a review from a team as a code owner September 9, 2026 14:51
@mydea
mydea requested review from nicohrubec and s1gr1d and removed request for a team September 9, 2026 14:51
@chargome
chargome self-requested a review September 10, 2026 09:40

@RulaKhaled RulaKhaled left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

left two comments, otherwise lgtm

Comment thread packages/server-utils/src/eve.ts Outdated

const setConversationIdFromContext: EveHookHandler = (_event, context) => {
const conversationId = resolveConversationId(context);
if (conversationId) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

does this mean a resolver returning undefined cannot unset the conversation id? setConversationId's documentsnull | undefined

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

oops, yeah, should not be that way, I refactored this to just use the value as-is and set it!

Comment thread packages/deno/src/index.ts
*
* ```ts
* // agent/hooks/sentry.ts
* import * as Sentry from '@sentry/node';

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.

nit: I guess this can also come from non-node packages?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

jup, theoretically, but eve is mostly just documented for node, so I think it's fine to keep this as example/docs here?

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.

I agree to keep it for node only for now. I don't think Eve would be optimized too much for other runtimes - if we stay with Node for now we have the minimal setup working it's a great start

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4bf7875. Configure here.

Comment thread packages/server-utils/src/eve.ts
Comment thread packages/server-utils/src/eve.ts

@JPeer264 JPeer264 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.

LGTM. Great points were already raised before.

@mydea
mydea force-pushed the feat/eve-conversation-hook branch from 6110680 to 796048f Compare September 11, 2026 08:03
Base automatically changed from feat/e2e-eve-agent to develop September 11, 2026 10:40
mydea and others added 6 commits September 11, 2026 12:41
…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>
…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>
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
mydea force-pushed the feat/eve-conversation-hook branch from 796048f to af51063 Compare September 11, 2026 10:41
@mydea
mydea merged commit 1e9d407 into develop Sep 14, 2026
234 of 235 checks passed
@mydea
mydea deleted the feat/eve-conversation-hook branch September 14, 2026 07:44
mydea added a commit that referenced this pull request Sep 14, 2026
Stacked on #24247 (base branch `feat/eve-conversation-hook`).

Exposes `getInstrumentedModuleNames()` — the package names Sentry
instruments through the orchestrion module transform (its
diagnostics-channel injection).

```ts
import { getInstrumentedModuleNames } from '@sentry/node';

// eve agent.ts — keep every Sentry-instrumented package external so the
// transform can hook it, instead of hardcoding the list:
build: { externalDependencies: getInstrumentedModuleNames() }
```

_Why:_

- A framework with no Sentry bundler plugin (eve, via
`build.externalDependencies`) otherwise has to hardcode which packages
to keep external. An inlined dependency never reaches the transform's
`onLoad`, so it's silently never instrumented — this hands the app the
authoritative set.
- It returns the plain `module.name` set, deliberately **without** the
bundler-only additions in the internal `INSTRUMENTED_MODULE_NAMES` (e.g.
`@remix-run/node`), which exist to force a helper package to be
*bundled* — the opposite of keeping it external.

_Export surface:_ lives in `@sentry/server-utils` (home of the
orchestrion config). Re-exported from `@sentry/node`, so `export *`
consumers — **nitro** (eve's base), astro, nestjs, hono, effect —
surface it automatically; and added explicitly to `@sentry/bun`,
`@sentry/aws-serverless`, `@sentry/google-cloud-serverless` (from node)
and `@sentry/deno`, `@sentry/cloudflare` (from server-utils), i.e.
everywhere a server bundle is configured — the same footprint as
`eveConversationHook`.

_node-eve e2e:_ the orchestrion variant's `build.externalDependencies`
now uses `getInstrumentedModuleNames()` instead of a hardcoded
`['dataloader']`. The app only uses `dataloader` of that set, so the
others are no-ops; `ai` v7 stays correct when externalized (native
`ai:telemetry` channel, and registration-only under the transform, so no
double instrumentation). The existing `dataloader` assertion continues
to prove the transform still runs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mydea added a commit to getsentry/sentry-docs that referenced this pull request Sep 16, 2026
## DESCRIBE YOUR PR

Adds a standalone **Eve** JavaScript guide and lifts the old Eve Agent
Tracing page into it. Based on
[getsentry/sentry-javascript#24228](getsentry/sentry-javascript#24228),
[#24247](getsentry/sentry-javascript#24247), and
[#24254](getsentry/sentry-javascript#24254).

- New guide at `/platforms/javascript/guides/eve/` that **extends the
Node guide** (`fallbackGuide: javascript.node`) with Error Monitoring /
Tracing / Profiling onboarding toggles. Documents the `@sentry/node`
SDK-based setup (replacing the old OTLP approach),
`Sentry.eveConversationHook()` for linking session turns into
Conversations, and `getInstrumentedModuleNames()` for orchestrion
`externalDependencies`.
- Removes the old OTLP-based `common/agent-tracing/eve.mdx`, redirects
the old route to the new guide, and keeps the Eve card in the Node Agent
Tracing grid (which now redirects to the guide).
- Adds `javascript.eve` to every `notSupported` **and** `supported` list
in JS common content wherever `javascript.node` appears.
`PlatformSection` doesn't resolve a guide's `fallbackGuide`, so Eve must
be enumerated alongside Node in both directions — otherwise browser-only
content leaks into the Eve guide and inherited Node sections/pages
render empty.
- Registers the Eve sidebar/dropdown icon (`javascript-eve`).

## IS YOUR CHANGE URGENT?

Help us prioritize incoming PRs by letting us know when the change needs
to go live.
Select exactly one option. For deadlines, replace `YYYY-MM-DD` with the
due date. You can update this information later by editing the PR
description.

- [ ] Urgent deadline (GA date, etc.): YYYY-MM-DD
- [ ] Other deadline: YYYY-MM-DD
- [x] No deadline: Not urgent, can wait up to 1 week+ (blocked on the
next `@sentry/node` beta release — see above)

## SLA

- Teamwork makes the dream work, so please add a reviewer to your PRs.
- Please give the docs team up to 1 week to review your PR unless you've
supplied a deadline.

Thanks in advance for your help!

## PRE-MERGE CHECKLIST

_Make sure you've checked the following before merging your changes:_

- [ ] Checked Vercel preview for correctness, including links
- [ ] PR was reviewed and approved by any necessary SMEs (subject matter
experts)
- [ ] PR was reviewed and approved by a member of the [Sentry docs
team](https://github.com/orgs/getsentry/teams/docs)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01RaYGdTstWVZKU9X4NjtYV1

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
inventarSarah pushed a commit to getsentry/sentry-docs that referenced this pull request Sep 29, 2026
## DESCRIBE YOUR PR

Adds a standalone **Eve** JavaScript guide and lifts the old Eve Agent
Tracing page into it. Based on
[getsentry/sentry-javascript#24228](getsentry/sentry-javascript#24228),
[#24247](getsentry/sentry-javascript#24247), and
[#24254](getsentry/sentry-javascript#24254).

- New guide at `/platforms/javascript/guides/eve/` that **extends the
Node guide** (`fallbackGuide: javascript.node`) with Error Monitoring /
Tracing / Profiling onboarding toggles. Documents the `@sentry/node`
SDK-based setup (replacing the old OTLP approach),
`Sentry.eveConversationHook()` for linking session turns into
Conversations, and `getInstrumentedModuleNames()` for orchestrion
`externalDependencies`.
- Removes the old OTLP-based `common/agent-tracing/eve.mdx`, redirects
the old route to the new guide, and keeps the Eve card in the Node Agent
Tracing grid (which now redirects to the guide).
- Adds `javascript.eve` to every `notSupported` **and** `supported` list
in JS common content wherever `javascript.node` appears.
`PlatformSection` doesn't resolve a guide's `fallbackGuide`, so Eve must
be enumerated alongside Node in both directions — otherwise browser-only
content leaks into the Eve guide and inherited Node sections/pages
render empty.
- Registers the Eve sidebar/dropdown icon (`javascript-eve`).

## IS YOUR CHANGE URGENT?

Help us prioritize incoming PRs by letting us know when the change needs
to go live.
Select exactly one option. For deadlines, replace `YYYY-MM-DD` with the
due date. You can update this information later by editing the PR
description.

- [ ] Urgent deadline (GA date, etc.): YYYY-MM-DD
- [ ] Other deadline: YYYY-MM-DD
- [x] No deadline: Not urgent, can wait up to 1 week+ (blocked on the
next `@sentry/node` beta release — see above)

## SLA

- Teamwork makes the dream work, so please add a reviewer to your PRs.
- Please give the docs team up to 1 week to review your PR unless you've
supplied a deadline.

Thanks in advance for your help!

## PRE-MERGE CHECKLIST

_Make sure you've checked the following before merging your changes:_

- [ ] Checked Vercel preview for correctness, including links
- [ ] PR was reviewed and approved by any necessary SMEs (subject matter
experts)
- [ ] PR was reviewed and approved by a member of the [Sentry docs
team](https://github.com/orgs/getsentry/teams/docs)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01RaYGdTstWVZKU9X4NjtYV1

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

4 participants