Trace integration
Send Eve traces to Langfuse with prompt attribution, session grouping, and Gateway metadata.
The Quick start uses two provider files: one enables complete trace content and one sends Eve's native trace model to Langfuse.
import { otel } from "eve/instrumentation/otel";
export default otel({
tracePolicy: () => ({
emit: true,
recordInputs: true,
recordOutputs: true,
}),
});import { defineLangfuseInstrumentation } from "@vantezzen/langfuse-eve/instrumentation";
export default defineLangfuseInstrumentation();The root agent must enable experimental.instrumentationProviders in agent/agent.ts.
No shared instrumentation.ts file or manual OpenTelemetry registration is needed.
What appears in Langfuse
The integration maps Eve data into Langfuse fields that can be searched and filtered:
| Eve activity | Langfuse result |
|---|---|
| Model call | Generation with model, tokens, latency, and usage |
| Langfuse-backed instructions | Prompt name and version on the generation |
| Root agent or declared subagent | Agent observation with parent lineage |
| Tool or skill action | Tool observation |
| Step and workflow | Chain observation |
| Memory lookup | Retriever observation |
| Vercel AI Gateway response | Generation ID and cost metadata |
Every root and child session keeps its own prompt attribution. Child spans include their parent call, session, and turn IDs, while Langfuse groups the conversation under the root Eve session by default.
| Langfuse field | Default value |
|---|---|
session.id | Root Eve session ID |
user.id | Initiating principal ID, when available |
| Trace metadata | Root/local session, turn, step, channel, and parent lineage |
| Observation prompt | Current agent's selected non-fallback prompt |
| Prompt trace metadata | All Langfuse prompts resolved for the current agent |
Add product context
Use context to add fields your team filters by in Langfuse:
import { defineLangfuseInstrumentation } from "@vantezzen/langfuse-eve/instrumentation";
export default defineLangfuseInstrumentation({
context: ({ channel, session }) => ({
metadata: {
channel: channel.kind,
plan: session.auth.current?.attributes.plan?.toString() ?? "unknown",
workspaceId:
session.auth.current?.attributes.workspaceId?.toString() ?? "unknown",
},
tags: ["support", process.env.VERCEL_ENV ?? "development"],
traceName: "support-agent",
}),
});Return null for userId or sessionId to suppress the inferred value. Set a custom
sessionId when your product already has a durable conversation identifier.
Control captured content
Eve's default OpenTelemetry policy records inputs and outputs for public conversations and for development. Non-public conversations outside development emit trace metadata but omit model and tool content.
The Quick start overrides that default so Langfuse traces include model and tool content:
import { otel } from "eve/instrumentation/otel";
export default otel({
tracePolicy: () => ({
emit: true,
recordInputs: true,
recordOutputs: true,
}),
});Review this policy before deployment
Inputs can contain prompts, user messages, documents, and tool arguments. Outputs can contain model responses, reasoning, tool results, and error details.
Restrict the policy when only public or development conversations may send content:
import { otel } from "eve/instrumentation/otel";
export default otel({
tracePolicy: ({ audience, environment }) => ({
emit: true,
recordInputs: audience === "public" || environment === "development",
recordOutputs: audience === "public" || environment === "development",
}),
});Remove otel.ts entirely to use Eve's default capture policy. You can also use the file to
set process-wide OpenTelemetry resource, sampler, or propagator options.
The otel() policy is shared by every OpenTelemetry destination. A destination cannot
restore content removed by that policy.
Configure Langfuse export
Pass official LangfuseSpanProcessor options through langfuse:
export default defineLangfuseInstrumentation({
langfuse: {
environment: process.env.VERCEL_ENV ?? "development",
release: process.env.VERCEL_GIT_COMMIT_SHA,
mask: ({ data }) => redactSecrets(data),
},
});shouldExportSpan replaces the default filter. If you provide it, include the Eve spans
you want Langfuse to receive.
Add Langfuse-only span fields
enrichSpan adds attributes to the copy sent to Langfuse. Other destinations still
receive the original span.
export default defineLangfuseInstrumentation({
enrichSpan: (span) => ({
"langfuse.observation.metadata.billing_region":
regionFor(span.attributes["cloud.region"]),
}),
});Add another trace destination
Add another file beside langfuse.ts. Eve owns the shared OpenTelemetry pipeline and
loads each destination independently, so no composition helper is required.